Package org.mule.exception

Source Code of org.mule.exception.AbstractExceptionStrategy

/*
* $Id: AbstractExceptionStrategy.java 22050 2011-05-31 17:43:33Z tcarlson $
* --------------------------------------------------------------------------------------
* Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
*
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/

package org.mule.exception;

import org.mule.DefaultMuleEvent;
import org.mule.DefaultMuleMessage;
import org.mule.api.MuleContext;
import org.mule.api.MuleEvent;
import org.mule.api.MuleException;
import org.mule.api.MuleMessage;
import org.mule.api.config.MuleProperties;
import org.mule.api.construct.FlowConstruct;
import org.mule.api.context.notification.ServerNotification;
import org.mule.api.endpoint.EndpointURI;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.processor.MessageProcessor;
import org.mule.api.security.SecurityException;
import org.mule.api.transaction.RollbackMethod;
import org.mule.api.transaction.Transaction;
import org.mule.api.transaction.TransactionException;
import org.mule.api.util.StreamCloserService;
import org.mule.config.ExceptionHelper;
import org.mule.context.notification.ExceptionNotification;
import org.mule.context.notification.SecurityNotification;
import org.mule.management.stats.FlowConstructStatistics;
import org.mule.management.stats.ServiceStatistics;
import org.mule.message.ExceptionMessage;
import org.mule.processor.AbstractMessageProcessorOwner;
import org.mule.routing.filters.WildcardFilter;
import org.mule.routing.outbound.MulticastingRouter;
import org.mule.transaction.TransactionCoordination;
import org.mule.util.CollectionUtils;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* This is the base class for exception strategies which contains several helper methods.  However, you should
* probably inherit from <code>AbstractMessagingExceptionStrategy</code> (if you are creating a Messaging Exception Strategy)
* or <code>AbstractSystemExceptionStrategy</code> (if you are creating a System Exception Strategy) rather than directly from this class.
*/
public abstract class AbstractExceptionStrategy extends AbstractMessageProcessorOwner
{
    protected transient Log logger = LogFactory.getLog(getClass());

    @SuppressWarnings("unchecked")
    protected List<MessageProcessor> messageProcessors = new CopyOnWriteArrayList();

    protected AtomicBoolean initialised = new AtomicBoolean(false);

    protected WildcardFilter rollbackTxFilter;
    protected WildcardFilter commitTxFilter;

    protected boolean enableNotifications = true;

    public AbstractExceptionStrategy(MuleContext muleContext, boolean rollbackByDefault)
    {
        super();
        setMuleContext(muleContext);
        if (rollbackByDefault)
        {
            setRollbackTxFilter(new WildcardFilter("*"));
        }
    }
   
    protected boolean isRollback(Throwable t)
    {
        return (rollbackTxFilter != null && rollbackTxFilter.accept(t.getClass().getName())) ||
            (commitTxFilter != null && !commitTxFilter.accept(t.getClass().getName()));
    }
   
    public List<MessageProcessor> getMessageProcessors()
    {
        return messageProcessors;
    }

    public void setMessageProcessors(List<MessageProcessor> processors)
    {
        if (processors != null)
        {
            this.messageProcessors.clear();
            this.messageProcessors.addAll(processors);
        }
        else
        {
            throw new IllegalArgumentException("List of targets = null");
        }
    }

    public void addEndpoint(MessageProcessor processor)
    {
        if (processor != null)
        {
            messageProcessors.add(processor);
        }
    }

    public boolean removeMessageProcessor(MessageProcessor processor)
    {
        return messageProcessors.remove(processor);
    }

    protected Throwable getExceptionType(Throwable t, Class exceptionType)
    {
        while (t != null)
        {
            if (exceptionType.isAssignableFrom(t.getClass()))
            {
                return t;
            }

            t = t.getCause();
        }

        return null;
    }

    /**
     * The initialise method is call every time the Exception stategy is assigned to
     * a service or connector. This implementation ensures that initialise is called
     * only once. The actual initialisation code is contained in the
     * <code>doInitialise()</code> method.
     *
     * @throws InitialisationException
     */
    public final synchronized void initialise() throws InitialisationException
    {
        super.initialise();
        if (!initialised.get())
        {
            doInitialise(muleContext);
            initialised.set(true);
        }
    }

    protected void doInitialise(MuleContext muleContext) throws InitialisationException
    {
        logger.info("Initialising exception listener: " + toString());
    }

    protected void fireNotification(Exception ex)
    {
        if (enableNotifications)
        {
            if (ex instanceof SecurityException)
            {
                fireNotification(new SecurityNotification((SecurityException) ex, SecurityNotification.SECURITY_AUTHENTICATION_FAILED));
            }
            else
            {
                fireNotification(new ExceptionNotification(ex));
            }
        }
    }

    /**
     * Routes the current exception to an error endpoint such as a Dead Letter Queue
     * (jms) This method is only invoked if there is a MuleMessage available to
     * dispatch. The message dispatched from this method will be an
     * <code>ExceptionMessage</code> which contains the exception thrown the
     * MuleMessage and any context information.
     *
     * @param message the MuleMessage being processed when the exception occurred
     * @param target optional; the endpoint being dispatched or received on
     *            when the error occurred. This is NOT the endpoint that the message
     *            will be disptched on and is only supplied to this method for
     *            logging purposes
     * @param t the exception thrown. This will be sent with the ExceptionMessage
     * @see ExceptionMessage
     */
    protected void routeException(MuleEvent event, Throwable t)
    {
        if (!messageProcessors.isEmpty())
        {
            try
            {
                logger.error("Message being processed is: " + (event.getMessage().getPayloadForLogging()));
                String component = "Unknown";
                if (event.getFlowConstruct() != null)
                {
                    component = event.getFlowConstruct().getName();
                }
                EndpointURI endpointUri = event.getEndpoint().getEndpointURI();

                // Create an ExceptionMessage which contains the original payload, the exception, and some additional context info.
                ExceptionMessage msg = new ExceptionMessage(event, t, component, endpointUri);
                MuleMessage exceptionMessage = new DefaultMuleMessage(msg, event.getMessage(), muleContext);

                // Create an outbound router with all endpoints configured on the exception strategy
                MulticastingRouter router = new MulticastingRouter()
                {
                    @Override
                    protected void setMessageProperties(FlowConstruct session, MuleMessage message, MessageProcessor target)
                    {
                        // No reply-to or correlation for exception targets, at least for now anyway.
                    }
                };
                router.setRoutes(getMessageProcessors());
                router.setMuleContext(muleContext);
               
                // Route the ExceptionMessage to the new router
                router.process(new DefaultMuleEvent(exceptionMessage, event));
            }
            catch (Exception e)
            {
                logFatal(event, e);
            }
        }
       
        List<MessageProcessor> processors = getMessageProcessors();
        FlowConstructStatistics statistics = event.getFlowConstruct().getStatistics();
        if (CollectionUtils.isNotEmpty(processors) && statistics instanceof ServiceStatistics)
        {
            if (statistics.isEnabled())
            {
                for (MessageProcessor endpoint : processors)
                {
                    ((ServiceStatistics) statistics).getOutboundRouterStat().incrementRoutedMessage(endpoint);
                }
            }
        }
    }

    protected void commit()
    {
        Transaction tx = TransactionCoordination.getInstance().getTransaction();
        if (tx != null)
        {
            try
            {
                tx.commit();
            }
            catch (TransactionException e)
            {
                logger.error(e);
            }
        }
    }

    protected void rollback(RollbackMethod rollbackMethod)
    {
        Transaction tx = TransactionCoordination.getInstance().getTransaction();
        if (tx != null)
        {
            try
            {
                tx.rollback();
               
                // TODO The following was in the catch clause of TransactionTemplate previously. 
                // Do we need to do this here?  If so, where can we store these variables (suspendedXATx, joinedExternal)
                // so that they are available to us in the exception handler?
                //
                //if (suspendedXATx != null)
                //{
                //  resumeXATransaction(suspendedXATx);
                //}
                //if (joinedExternal != null)
                //{
                //    TransactionCoordination.getInstance().unbindTransaction(joinedExternal);
                //}
            }
            catch (TransactionException e)
            {
                logger.error(e);
            }
        }
        else if (rollbackMethod != null)
        {
            rollbackMethod.rollback();
        }
    }

    protected void closeStream(MuleMessage message)
    {
        if (muleContext == null || muleContext.isDisposing() || muleContext.isDisposed())
        {
            return;
        }
        if (message != null
            && muleContext.getRegistry().lookupObject(MuleProperties.OBJECT_MULE_STREAM_CLOSER_SERVICE) != null)
        {
            ((StreamCloserService) muleContext.getRegistry().lookupObject(
                    MuleProperties.OBJECT_MULE_STREAM_CLOSER_SERVICE)).closeStream(message.getPayload());
        }
    }

    /**
     * Used to log the error passed into this Exception Listener
     *
     * @param t the exception thrown
     */
    protected void logException(Throwable t)
    {
        MuleException muleException = ExceptionHelper.getRootMuleException(t);
        if (muleException != null)
        {
            logger.error(muleException.getDetailedMessage());
        }
        else
        {
            logger.error("Caught exception in Exception Strategy: " + t.getMessage(), t);
        }
    }

    /**
     * Logs a fatal error message to the logging system. This should be used mostly
     * if an error occurs in the exception listener itself. This implementation logs
     * the the message itself to the logs if it is not null
     *
     * @param message The MuleMessage currently being processed
     * @param t the fatal exception to log
     */
    protected void logFatal(MuleEvent event, Throwable t)
    {
        FlowConstructStatistics statistics = event.getFlowConstruct().getStatistics();
        if (statistics != null && statistics.isEnabled())
        {
            statistics.incFatalError();
        }

        logger.fatal(
            "Failed to dispatch message to error queue after it failed to process.  This may cause message loss."
                            + (event.getMessage() == null ? "" : "Logging Message here: \n" + event.getMessage().toString()), t);
    }

    public boolean isInitialised()
    {
        return initialised.get();
    }

    /**
     * Fires a server notification to all registered
     * {@link org.mule.api.context.notification.ExceptionNotificationListener}
     * eventManager.
     *
     * @param notification the notification to fire.
     */
    protected void fireNotification(ServerNotification notification)
    {
        if (muleContext != null)
        {
            muleContext.fireNotification(notification);
        }
        else if (logger.isWarnEnabled())
        {
            logger.debug("MuleContext is not yet available for firing notifications, ignoring event: "
                         + notification);
        }
    }

    public WildcardFilter getCommitTxFilter()
    {
        return commitTxFilter;
    }

    public void setCommitTxFilter(WildcardFilter commitTxFilter)
    {
        this.commitTxFilter = commitTxFilter;
    }

    public boolean isEnableNotifications()
    {
        return enableNotifications;
    }

    public void setEnableNotifications(boolean enableNotifications)
    {
        this.enableNotifications = enableNotifications;
    }

    public WildcardFilter getRollbackTxFilter()
    {
        return rollbackTxFilter;
    }

    public void setRollbackTxFilter(WildcardFilter rollbackTxFilter)
    {
        this.rollbackTxFilter = rollbackTxFilter;
    }
   
    @Override
    protected List<MessageProcessor> getOwnedMessageProcessors()
    {
        return messageProcessors;
    }
}
TOP

Related Classes of org.mule.exception.AbstractExceptionStrategy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.