/* * 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.runtime.core.exception; import static org.mule.runtime.core.api.Event.getCurrentEvent; import static org.mule.runtime.core.api.Event.setCurrentEvent; import static org.mule.runtime.core.api.context.notification.EnrichedNotificationInfo.createInfo; import static org.mule.runtime.core.context.notification.ErrorHandlerNotification.PROCESS_END; import static org.mule.runtime.core.context.notification.ErrorHandlerNotification.PROCESS_START; import org.mule.runtime.api.exception.MuleException; import org.mule.runtime.api.lifecycle.Lifecycle; import org.mule.runtime.api.lifecycle.Stoppable; import org.mule.runtime.core.api.Event; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.exception.MessagingExceptionHandler; import org.mule.runtime.core.api.message.ExceptionPayload; import org.mule.runtime.core.context.notification.ErrorHandlerNotification; import org.mule.runtime.core.internal.message.DefaultExceptionPayload; import org.mule.runtime.core.internal.message.InternalMessage; import org.mule.runtime.core.management.stats.FlowConstructStatistics; /** * Fire a notification, log exception, increment statistics, route the problematic message to a destination if one is configured * (DLQ pattern), commit or rollback transaction if one exists, close any open streams. */ public abstract class AbstractMessagingExceptionStrategy extends AbstractExceptionListener implements MessagingExceptionHandler { /** * Stop the flow/service when an exception occurs. You will need to restart the flow/service manually after this (e.g, using * JMX). */ private boolean stopMessageProcessing; public AbstractMessagingExceptionStrategy() {} public AbstractMessagingExceptionStrategy(MuleContext muleContext) { setMuleContext(muleContext); } @Override public Event handleException(MessagingException ex, Event event) { try { muleContext.getNotificationManager() .fireNotification(new ErrorHandlerNotification(createInfo(event, ex, null), flowConstruct, PROCESS_START)); // keep legacy notifications fireNotification(ex, event); // Work with the root exception, not anything that wraps it // Throwable t = ExceptionHelper.getRootException(ex); logException(ex, event); event = doHandleException(ex, event); ExceptionPayload exceptionPayload = new DefaultExceptionPayload(ex); if (getCurrentEvent() != null) { Event currentEvent = getCurrentEvent(); currentEvent = Event.builder(currentEvent) .message(InternalMessage.builder(currentEvent.getMessage()).exceptionPayload(exceptionPayload).build()).build(); setCurrentEvent(currentEvent); } return Event.builder(event) .message(InternalMessage.builder(event.getMessage()).nullPayload().exceptionPayload(exceptionPayload).build()).build(); } finally { muleContext.getNotificationManager() .fireNotification(new ErrorHandlerNotification(createInfo(event, ex, null), flowConstruct, PROCESS_END)); } } protected Event doHandleException(Exception ex, Event event) { FlowConstructStatistics statistics = flowConstruct.getStatistics(); if (statistics != null && statistics.isEnabled()) { statistics.incExecutionError(); } // Left this here for backwards-compatibility, remove in the next major version. defaultHandler(ex); Event result; if (isRollback(ex)) { logger.debug("Rolling back transaction"); rollback(ex); logger.debug("Routing exception message"); result = routeException(event, flowConstruct, ex); } else { logger.debug("Routing exception message"); result = routeException(event, flowConstruct, ex); } closeStream(event.getMessage()); if (stopMessageProcessing) { stopFlow(); } return result; } protected void stopFlow() { if (flowConstruct instanceof Stoppable) { logger.info("Stopping flow '" + flowConstruct.getName() + "' due to exception"); try { ((Lifecycle) flowConstruct).stop(); } catch (MuleException e) { logger.error("Unable to stop flow '" + flowConstruct.getName() + "'", e); } } else { logger.warn("Flow is not stoppable"); } } public boolean isStopMessageProcessing() { return stopMessageProcessing; } public void setStopMessageProcessing(boolean stopMessageProcessing) { this.stopMessageProcessing = stopMessageProcessing; } /** * @deprecated Override doHandleException(Exception e, MuleEvent event) instead */ // Left this here for backwards-compatibility, remove in the next major version. @Deprecated protected void defaultHandler(Throwable t) { // empty } }