org.craftercms.studio.exceptions.formatter.impl.AbstractExceptionFormatter.java Source code

Java tutorial

Introduction

Here is the source code for org.craftercms.studio.exceptions.formatter.impl.AbstractExceptionFormatter.java

Source

/*
 * Copyright (C) 2007-2013 Crafter Software Corporation.
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.craftercms.studio.exceptions.formatter.impl;

import java.util.Iterator;

import org.apache.commons.lang.StringUtils;
import org.craftercms.studio.exceptions.formatter.ExceptionFormatter;
import org.craftercms.studio.exceptions.formatter.FormatterRegistry;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;

/**
 * Base class for all Exception message formatter.
 * This class will ensure that all subclasses return
 * the base JSON response that is:
 * <code>
 * {
 * "code":XXX,
 * "message":"Meaningful message"
 * }
 * </code>
 * <b>The meaningful message is call using {@link Exception#getMessage()}</b>
 */
public abstract class AbstractExceptionFormatter implements ExceptionFormatter {
    /**
     * JSON key for code.
     */
    public static final String JSON_CODE_KEY = "code";
    /**
     * JSON key for message.
     */
    public static final String JSON_MESSAGE_KEY = "message";
    /**
     * JSO key for any details.
     */
    public static final String JSON_DETAIL_MESSAGE_KEY = "details";
    /**
     * Response Code that will be send to the client
     * must compliance to http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html .
     */
    private int httpResponseCode;
    private Class<? extends Exception> exceptionClass;
    /**
     * Message Formatter.
     */
    private FormatterRegistry formatterRegistry;
    private Logger log = LoggerFactory.getLogger(AbstractExceptionFormatter.class);

    protected AbstractExceptionFormatter(Class<? extends Exception> exceptionClass) {
        this.exceptionClass = exceptionClass;
    }

    /**
     * Generates the message using base info httpResponseCode and defaultMessage.
     * calls {@link AbstractExceptionFormatter#generateDetailMessage} for get any detail if needed.
     *
     * @return A String representation of a JSON Object to be return.<br/>
     *         or <B>null</B> if the JSON could no be generate due a error.
     */
    @Override
    public String getFormattedMessage(Exception exception) {
        // Checks that all is ok
        validateDefaultMessageParams(exception);
        String returnMsg = null;
        try {
            final JSONObject jsonToReturn = new JSONObject();
            jsonToReturn.put(JSON_CODE_KEY, this.httpResponseCode);
            jsonToReturn.put(JSON_MESSAGE_KEY, exception.getMessage());
            final JSONObject detailsObject = generateDetailMessage(exception);
            if (detailsObject == null) {
                if (this.log.isDebugEnabled()) {
                    this.log.debug("Detail Message is null, ignoring");
                }
            } else if (detailsObject.length() == 0) {
                if (this.log.isDebugEnabled()) {
                    this.log.debug("Detail Message is empty, ignoring");
                }
            } else {
                final Iterator keys = detailsObject.keys();
                while (keys.hasNext()) {
                    final String key = keys.next().toString();
                    if (key.equals(JSON_CODE_KEY) || key.equals(JSON_MESSAGE_KEY)) {
                        if (this.log.isDebugEnabled()) {
                            this.log.debug("Detail message has either {} or {} they are not allow, ignoring them",
                                    JSON_CODE_KEY, JSON_MESSAGE_KEY);
                        }
                    } else {
                        jsonToReturn.put(key, detailsObject.get(key));
                    }
                }
            }
            returnMsg = jsonToReturn.toString();
        } catch (JSONException ex) {
            this.log.error("Unable to format Exception", ex);
        }
        return returnMsg;
    }

    /**
     * Validates that message and http are
     * not null (and >200) and that message is not empty.
     *
     * @throws IllegalStateException if either defaultMessage or httpResponseCode are not valid.
     */
    private void validateDefaultMessageParams(Exception ex) {
        if (StringUtils.isEmpty(ex.getMessage())) {
            throw new IllegalStateException("Default message can't be null or empty");
        }
        try {
            HttpStatus.valueOf(this.httpResponseCode);
        } catch (IllegalArgumentException e) {
            throw new IllegalStateException(
                    String.format("%s is not a valid Http Response Code", this.httpResponseCode));
        }

    }

    /**
     * Generates the any extra information that will be append to the
     * end message.
     * Key of that JSON MUST be call
     *
     * @param ex Exception used to generate detail message.
     * @return A JSONObject that will be append to standard out put.
     *         if contains either "code" or "message" as keys they will be
     *         removed.If return empty or null will be ignore.
     * @throws org.json.JSONException if a error generating the exceptionClass happened.
     */
    protected abstract JSONObject generateDetailMessage(Exception ex) throws JSONException;

    public void register() {
        this.formatterRegistry.registerFormatter(this.exceptionClass, this);
    }

    @Override
    public int getHttpResponseCode() {
        return this.httpResponseCode;
    }

    protected void setHttpResponseCode(int httpResponseCode) {
        this.httpResponseCode = httpResponseCode;
    }

    public void setFormatterRegistry(FormatterRegistryImpl formatterRegistry) {
        this.formatterRegistry = formatterRegistry;
    }
}