/*
* 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.execution;
import static org.mule.runtime.core.util.ClassUtils.withContextClassLoader;
import org.mule.runtime.core.api.exception.SystemExceptionHandler;
import java.util.List;
/**
* This class process a message through a set of {@link org.mule.runtime.core.execution.MessageProcessPhase} using the message
* content and message processing context provided by {@link org.mule.runtime.core.execution.MessageProcessTemplate} and
* {@link org.mule.runtime.core.execution.MessageProcessContext}.
* <p>
* This class will handle any message processing failure by calling the
* {@link org.mule.runtime.core.api.exception.SystemExceptionHandler} defined by the application.
* <p>
* Each {@link org.mule.runtime.core.execution.MessageProcessPhase} can be executed with a different threading mechanism.
* {@link org.mule.runtime.core.execution.MessageProcessPhase} implementation must guarantee that upon phase completion the method
* {@link PhaseResultNotifier#phaseSuccessfully()} is executed, if there was a failure processing the message then the method
* {@link PhaseResultNotifier#phaseFailure(Exception)} must be executed and if the phase consumed the message the method
* {@link org.mule.runtime.core.execution.PhaseResultNotifier#phaseConsumedMessage()} must be executed.
*/
public class PhaseExecutionEngine {
private final List<MessageProcessPhase> phaseList;
private final SystemExceptionHandler exceptionHandler;
private final EndProcessPhase endProcessPhase;
public PhaseExecutionEngine(List<MessageProcessPhase> messageProcessPhaseList, SystemExceptionHandler exceptionHandler,
EndProcessPhase endProcessPhase) {
this.phaseList = messageProcessPhaseList;
this.exceptionHandler = exceptionHandler;
this.endProcessPhase = endProcessPhase;
}
public void process(MessageProcessTemplate messageProcessTemplate, MessageProcessContext messageProcessContext) {
InternalPhaseExecutionEngine internalPhaseExecutionEngine =
new InternalPhaseExecutionEngine(messageProcessTemplate, messageProcessContext);
internalPhaseExecutionEngine.process();
}
public class InternalPhaseExecutionEngine implements PhaseResultNotifier {
private int currentPhase = 0;
private final MessageProcessContext messageProcessContext;
private final MessageProcessTemplate messageProcessTemplate;
private boolean endPhaseProcessed;
public InternalPhaseExecutionEngine(MessageProcessTemplate messageProcessTemplate,
MessageProcessContext messageProcessContext) {
this.messageProcessTemplate = messageProcessTemplate;
this.messageProcessContext = messageProcessContext;
}
@Override
public void phaseSuccessfully() {
currentPhase++;
if (currentPhase < phaseList.size()) {
if (phaseList.get(currentPhase).supportsTemplate(messageProcessTemplate)) {
phaseList.get(currentPhase).runPhase(messageProcessTemplate, messageProcessContext, this);
} else {
phaseSuccessfully();
}
} else {
processEndPhase();
}
}
@Override
public void phaseConsumedMessage() {
processEndPhase();
}
@Override
public void phaseFailure(Exception reason) {
exceptionHandler.handleException(reason);
processEndPhase();
}
private void processEndPhase() {
if (!endPhaseProcessed) {
endPhaseProcessed = true;
if (endProcessPhase.supportsTemplate(messageProcessTemplate)) {
endProcessPhase.runPhase((EndPhaseTemplate) messageProcessTemplate, messageProcessContext, this);
}
}
}
public void process() {
withContextClassLoader(messageProcessContext.getExecutionClassLoader(), () -> {
for (MessageProcessPhase phase : phaseList) {
if (phase.supportsTemplate(messageProcessTemplate)) {
phase.runPhase(messageProcessTemplate, messageProcessContext, this);
return;
}
currentPhase++;
}
});
}
}
}