/*
* 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
}
}