com.qpark.eip.core.failure.BaseFailureHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.qpark.eip.core.failure.BaseFailureHandler.java

Source

/*******************************************************************************
 * Copyright (c) 2013-2017 QPark Consulting  S.a r.l.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0.
 * The Eclipse Public License is available at
 * http://www.eclipse.org/legal/epl-v10.html.
 ******************************************************************************/
package com.qpark.eip.core.failure;

import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.net.ConnectException;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;

import javax.net.ssl.SSLHandshakeException;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import org.slf4j.Logger;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.MessagingException;
import org.springframework.oxm.UnmarshallingFailureException;
import org.springframework.remoting.soap.SoapFaultException;
import org.springframework.ws.client.WebServiceIOException;
import org.springframework.ws.client.WebServiceTransportException;
import org.springframework.ws.soap.client.SoapFaultClientException;

import com.qpark.eip.core.AbstractUnmarschaller;
import com.qpark.eip.core.failure.domain.FailureMessageListType;
import com.qpark.eip.core.failure.domain.FailureMessagePhraseType;
import com.qpark.eip.core.failure.domain.FailureMessagePhraseableType;
import com.qpark.eip.core.failure.domain.FailureMessageSeverity;
import com.qpark.eip.core.failure.domain.FailureMessageType;
import com.springsource.insight.annotation.InsightOperation;

/**
 * Handle failures.
 *
 * @author bhausen
 */
public abstract class BaseFailureHandler {
    /** The default error code if non presented. */
    private static final String DEFAULT = "E_NOT_KNOWN_ERROR";
    /** The default database error code if non presented. */
    private static final String DEFAULT_DATABASE = "E_DATABASE_ERROR";
    /** File name of the base messages. */
    private static final String FAILURE_MESSAGES_XML_BASE = "failure-messages-base.xml";
    /** File name of the messages. */
    public static final String FAILURE_MESSAGES_XML = "failure-messages.xml";
    /**
     * The {@link Unmarshaller} of package com.qpark.eip.core.failure.domain.
     */
    private static AbstractUnmarschaller MARSHALLER = new AbstractUnmarschaller() {
        /**
         * @see com.qpark.eip.core.AbstractUnmarschaller#getContextPath()
         */
        @Override
        protected String getContextPath() {
            return null;
        }

        /**
         * @see com.qpark.eip.core.AbstractUnmarschaller#getContextClasses()
         */
        @Override
        protected Class<?>[] getContextClasses() {
            return new Class<?>[] { FailureMessagePhraseableType.class, FailureMessagePhraseType.class,
                    FailureMessageListType.class, FailureMessageSeverity.class, FailureMessageType.class

            };
        }
    };

    private static String checkUnnumberedBrackets(final String message) {
        String s = message.trim();
        int index = s.indexOf("{}");
        if (index > -1) {
            int number = 0;
            if (s.indexOf("{0}") > 0) {
                number = 0;
            } else if (s.indexOf("{1}") > 0) {
                number = 1;
            } else if (s.indexOf("{2}") > 0) {
                number = 2;
            } else if (s.indexOf("{3}") > 0) {
                number = 3;
            } else if (s.indexOf("{4}") > 0) {
                number = 4;
            } else if (s.indexOf("{5}") > 0) {
                number = 5;
            }
            index = s.indexOf(new StringBuffer().append("{").append(number).append("}").toString());
            while (index > -1) {
                number++;
                index = s.indexOf(new StringBuffer().append("{").append(number).append("}").toString());
            }
            index = s.indexOf("{}");
            while (index > -1) {
                s = s.replaceFirst("\\{\\}", new StringBuffer().append("{").append(number).append("}").toString());
                number++;
                index = s.indexOf("{}");
            }
        }
        return s;
    }

    private static final HashMap<String, FailureMessageType> messages = new HashMap<String, FailureMessageType>();

    private static final HashMap<String, String> phrases = new HashMap<String, String>();

    private static String format(final FailureMessagePhraseableType m, final Object... data) {
        StringBuffer sb = new StringBuffer(1024);
        if (m != null) {
            if (m.getText() != null && m.getText().trim().length() > 0) {
                if (data != null && data.length > 0) {
                    MessageFormat mf = new MessageFormat(checkUnnumberedBrackets(m.getText()));
                    sb.append(mf.format(data));
                } else {
                    sb.append(m.getText());
                }
            }
            if (m.getPhraseKey() != null) {
                for (String key : m.getPhraseKey()) {
                    if (phrases.get(key) != null && phrases.get(key).length() > 0) {
                        if (sb.length() > 0) {
                            sb.append(" ");
                        }
                    }
                    sb.append(phrases.get(key));
                }
            }
        }
        return sb.toString();
    }

    public static FailureDescription getFailure(final String code, final Object... data) {
        return getFailure(code, (Throwable) null, data);
    }

    public static FailureDescription getFailure(final String code, final Throwable t) {
        return getFailure(code, t, (Object[]) null);
    }

    public static FailureDescription getFailure(final String code, final Throwable t, final Object... data) {
        FailureDescription fd = new FailureDescription();
        StringBuffer supportInfo = new StringBuffer(128);
        FailureMessageType fm = null;
        if (code != null) {
            fm = getFailureMessage(code);
            if (fm == null) {
                fm = getFailureMessage(DEFAULT);
                supportInfo.append("No definition found for code ").append(code)
                        .append(" in failure-messages.xml.\n");
            }
        } else {
            fm = getFailureMessage(DEFAULT);
        }
        Object[] datax = data;
        if (datax == null) {
            datax = new Object[] { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
                    "" };
        }

        supportInfo.insert(0, format(fm.getSupportInformation(), datax));

        fd.setWhatHappened(format(fm.getWhatHappened(), datax));
        fd.setWhyHappened(format(fm.getWhyHappened(), datax));
        fd.setWhatToDo(format(fm.getWhatToDo(), datax));
        if (fm.getSeverity() != null && fm.getSeverity().equals(FailureMessageSeverity.WARNING)) {
            fd.setSeverity(FailureMessageSeverity.WARNING);
        } else {
            fd.setSeverity(FailureMessageSeverity.ERROR);
        }

        fd.setErrorCode(code);

        fd.setSupportInformation(supportInfo.toString());

        if (fd.getSeverity().equals(FailureMessageSeverity.ERROR)) {
            if (t != null) {
                showFailureDescription(t.getClass().getSimpleName(), t.getMessage(), fd.getErrorCode(),
                        fd.getSeverity().name(), fd.getWhatHappened(), fd.getWhyHappened(), fd.getWhatToDo());
            } else {
                showFailureDescription("", "", fd.getErrorCode(), fd.getSeverity().name(), fd.getWhatHappened(),
                        fd.getWhyHappened(), fd.getWhatToDo());
            }
        }

        StringBuffer sb = new StringBuffer(256);
        sb.append("Occurred at: ").append(new Date());
        if (t != null) {
            sb.append("\n").append(t.getMessage()).append("\n");
            sb.append(getStackTrace(t));
        }
        fd.setErrorDetails(sb.toString());
        return fd;
    }

    private static FailureMessageType getFailureMessage(final String code) {
        FailureMessageType fm = null;
        if (messages.size() == 0) {
            addBaseMessages();
        }
        fm = messages.get(code);
        return fm;
    }

    private static void addBaseMessages() {
        InputStream is = BaseFailureHandler.class
                .getResourceAsStream(new StringBuffer(32).append("/").append(FAILURE_MESSAGES_XML_BASE).toString());
        if (is != null) {
            try {
                FailureMessageListType failuresMessageList = (FailureMessageListType) MARSHALLER.getValue(is,
                        FailureMessageListType.class);
                addFailureMessageList(failuresMessageList);
            } catch (JAXBException e) {
                e.printStackTrace();
            }
        }
    }

    private static void addFailureMessageList(final FailureMessageListType failuresMessageList) {
        if (failuresMessageList != null) {
            for (FailureMessagePhraseType phr : failuresMessageList.getMessagePhrase()) {
                phrases.put(phr.getKey(), phr.getPhrase());
            }
            for (FailureMessageType msg : failuresMessageList.getMessage()) {
                messages.put(msg.getCode(), msg);
            }
        }
    }

    public static void addFailureMessages(final InputStream is) {
        FailureMessageListType failuresMessageList;
        if (messages.size() == 0) {
            addBaseMessages();
        }
        if (is != null) {
            try {
                failuresMessageList = (FailureMessageListType) MARSHALLER.getValue(is,
                        FailureMessageListType.class);
                addFailureMessageList(failuresMessageList);
            } catch (JAXBException e) {
                e.printStackTrace();
            }
        }
    }

    private static String getStackTrace(final Throwable t) {
        if (t != null) {
            Writer w = new StringWriter();
            PrintWriter pw = new PrintWriter(w);
            t.printStackTrace(pw);
            return w.toString();
        } else {
            return "";
        }
    }

    /**
     * Handles the exception classes:
     * <ul>
     * <li>{@link FailureException}</li>
     * <li>{@link SoapFaultClientException}</li>
     * <li>{@link Exception}</li>
     * </ul>
     *
     * @param e
     * @param rp
     * @param defaultCode
     * @param log
     */
    public static FailureDescription handleException(final Throwable e, final String defaultCode, final Logger log,
            final Object... data) {
        FailureDescription fd = null;
        if (InvocationTargetException.class.isInstance(e)) {
            fd = handleException(((InvocationTargetException) e).getTargetException(), defaultCode, log, data);
        } else if (MessageHandlingException.class.isInstance(e)) {
            fd = handleException(((MessagingException) e).getCause(), defaultCode, log, data);
        } else if (MessagingException.class.isInstance(e)) {
            fd = handleException(((MessagingException) e).getCause(), defaultCode, log, data);
        } else if (SoapFaultClientException.class.isInstance(e)) {
            ArrayList<Object> list = new ArrayList<Object>(data == null ? 1 : data.length + 1);
            if (data != null) {
                list.addAll(Arrays.asList(data));
            }
            if (e.getMessage() != null) {
                list.add(0, e.getMessage());
            }
            fd = getFailure("E_SOAP_FAULT_CLIENT_ERROR", e, list.toArray(new Object[list.size()]));
            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            } else {
                log.error(e.getMessage());
            }
        } else if (WebServiceIOException.class.isInstance(e)) {
            fd = handleWebServiceIOException((WebServiceIOException) e, defaultCode, log, data);
        } else if (SoapFaultException.class.isInstance(e)) {
            ArrayList<Object> list = new ArrayList<Object>(data == null ? 1 : data.length + 1);
            if (data != null) {
                list.addAll(Arrays.asList(data));
            }
            if (e.getMessage() != null) {
                list.add(0, e.getMessage());
            }
            fd = handleSoapFaultException((SoapFaultException) e, defaultCode, log,
                    list.toArray(new Object[list.size()]));
            if (fd == null) {
                fd = getFailure("E_SOAP_MESSAGE_VALIDATION_ERROR", e);
            }
            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            } else {
                log.error(e.getMessage());
            }
        } else if (SQLException.class.isInstance(e)) {
            fd = handleSQLException((SQLException) e, DEFAULT_DATABASE, log, data);
        } else if (e.getCause() != null) {
            fd = handleException(e.getCause(), defaultCode, log, data);
        } else {
            fd = getFailure(defaultCode == null ? DEFAULT : defaultCode, e);
            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            } else {
                log.error(e.getMessage());
            }
        }
        return fd;
    }

    private static FailureDescription handleSoapFaultException(final SoapFaultException e, final String defaultCode,
            final Logger log, final Object... data) {
        FailureDescription fd = null;
        if (e.getCause() != null && WebServiceIOException.class.isInstance(e.getCause())) {
            fd = handleWebServiceIOException((WebServiceIOException) e.getCause(), defaultCode, log, data);
        } else if (e.getCause() != null && WebServiceTransportException.class.isInstance(e.getCause())) {
            fd = getFailure("E_SOAP_FAULT_CREDENTIAL_ERROR", e, data);
        } else if (e.getCause() != null && UnmarshallingFailureException.class.isInstance(e.getCause())) {
            fd = getFailure("E_SOAP_FAULT_MARSHALLING_ERROR", e, data);
        }
        return fd;
    }

    /**
     * @param e
     *            {@link SQLException}
     * @param defaultCode
     * @param log
     * @param data
     * @return
     */
    public static FailureDescription handleSQLException(final SQLException e, final String defaultCode,
            final Logger log, final Object... data) {
        FailureDescription fd = null;
        String code = defaultCode;
        if (code == null) {
            code = DEFAULT_DATABASE;
        }
        fd = getFailure(code, e);
        log.error(e.getMessage(), e);
        return fd;
    }

    private static FailureDescription handleWebServiceIOException(final WebServiceIOException e,
            final String defaultCode, final Logger log, final Object... data) {
        FailureDescription fd = null;
        if (e.getCause() != null && SSLHandshakeException.class.isInstance(e.getCause().getCause())) {
            fd = getFailure("E_SOAP_FAULT_HTTPS_CERTIFICATE_ERROR", e, data);
        } else if (e.getCause() != null && ConnectException.class.isInstance(e.getCause().getCause())) {
            fd = getFailure("E_SOAP_FAULT_SERVICE_NOT_AVAILABLE", e, data);
        } else if (e.getCause() != null && e.getCause().getClass().getPackage().getName().startsWith("java.net")) {
            fd = getFailure("E_SOAP_FAULT_NETWORK_ERROR", e, data);
        } else {
            fd = getFailure("E_SOAP_FAULT_SERVICE_NOT_AVAILABLE", e, data);
        }
        return fd;
    }

    /**
     * Show the {@link FailureDescription} in the insight stack
     *
     * @param fd
     * @param code
     * @param data
     */
    @InsightOperation
    private static void showFailureDescription(final String exception, final String exceptionMessage,
            final String errorCode, final String severity, final String whatHappened, final String whyHappened,
            final String whatToDo) {
        // Only to be shown in insight.
    }

    /**
     * Throws a new {@link FailureException}.
     *
     * @param code
     */
    public static void throwFailureException(final String code) {
        throwFailureException(code, (Throwable) null, (Object[]) null);
    }

    /**
     * Throws a new {@link FailureException}.
     *
     * @param code
     * @param data
     */
    public static void throwFailureException(final String code, final Object... data) {
        throwFailureException(code, (Throwable) null, data);
    }

    /**
     * Throws a new {@link FailureException}.
     *
     * @param code
     * @param cause
     */
    public static void throwFailureException(final String code, final Throwable cause) {
        throwFailureException(code, cause, (Object[]) null);
    }

    /**
     * Throws a new {@link FailureException}.
     *
     * @param code
     * @param cause
     * @param data
     */
    public static void throwFailureException(final String code, final Throwable cause, final Object... data) {
        FailureDescription fd = getFailure(code, cause, data);
        FailureException e;
        if (cause == null) {
            e = new FailureException(fd);
        } else {
            e = new FailureException(fd, cause);
        }
        throw e;
    }
}