Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.ow2.bonita.definition.activity.AbstractActivity Maven / Gradle / Ivy
/**
* Copyright (C) 2007 Bull S. A. S.
* Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation
* version 2.1 of the License.
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301, USA.
*
* Modified by Matthieu Chaffotte, Nicolas Chabanoles, Elias Ricken de Medeiros - BonitaSoft S.A.
**/
package org.ow2.bonita.definition.activity;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hibernate.AssertionFailure;
import org.hibernate.StaleStateException;
import org.hibernate.exception.LockAcquisitionException;
import org.ow2.bonita.definition.MultiInstantiator;
import org.ow2.bonita.definition.MultiInstantiatorDescriptor;
import org.ow2.bonita.env.Authentication;
import org.ow2.bonita.facade.def.InternalActivityDefinition;
import org.ow2.bonita.facade.def.InternalConnectorDefinition;
import org.ow2.bonita.facade.def.element.BoundaryEvent;
import org.ow2.bonita.facade.def.element.DeadlineDefinition;
import org.ow2.bonita.facade.def.element.HookDefinition;
import org.ow2.bonita.facade.def.element.HookDefinition.Event;
import org.ow2.bonita.facade.def.element.MultiInstantiationDefinition;
import org.ow2.bonita.facade.def.element.impl.IterationDescriptor;
import org.ow2.bonita.facade.def.element.impl.MessageBoundaryEventImpl;
import org.ow2.bonita.facade.def.element.impl.SignalBoundaryEventImpl;
import org.ow2.bonita.facade.def.element.impl.TimerBoundaryEventImpl;
import org.ow2.bonita.facade.def.majorElement.ActivityDefinition;
import org.ow2.bonita.facade.def.majorElement.ActivityDefinition.JoinType;
import org.ow2.bonita.facade.def.majorElement.ActivityDefinition.SplitType;
import org.ow2.bonita.facade.def.majorElement.ProcessDefinition;
import org.ow2.bonita.facade.def.majorElement.TransitionDefinition;
import org.ow2.bonita.facade.exception.BonitaWrapperException;
import org.ow2.bonita.facade.exception.MultiInstantiatorInvocationException;
import org.ow2.bonita.facade.exception.UnRollbackableException;
import org.ow2.bonita.facade.runtime.ActivityInstance;
import org.ow2.bonita.facade.runtime.ActivityState;
import org.ow2.bonita.facade.runtime.InstanceState;
import org.ow2.bonita.facade.runtime.impl.InternalActivityInstance;
import org.ow2.bonita.facade.runtime.impl.InternalProcessInstance;
import org.ow2.bonita.facade.runtime.impl.InternalProcessInstance.TransitionState;
import org.ow2.bonita.facade.uuid.ActivityInstanceUUID;
import org.ow2.bonita.facade.uuid.ProcessInstanceUUID;
import org.ow2.bonita.light.LightProcessDefinition.ProcessType;
import org.ow2.bonita.runtime.ExtensionPointsPolicy;
import org.ow2.bonita.runtime.IterationDetectionPolicy;
import org.ow2.bonita.runtime.event.EventConstants;
import org.ow2.bonita.runtime.event.IncomingEventInstance;
import org.ow2.bonita.runtime.event.Job;
import org.ow2.bonita.runtime.event.JobBuilder;
import org.ow2.bonita.runtime.model.Execution;
import org.ow2.bonita.services.EventService;
import org.ow2.bonita.services.Querier;
import org.ow2.bonita.services.Recorder;
import org.ow2.bonita.type.Variable;
import org.ow2.bonita.util.BonitaConstants;
import org.ow2.bonita.util.BonitaRuntimeException;
import org.ow2.bonita.util.EnvTool;
import org.ow2.bonita.util.ExceptionManager;
import org.ow2.bonita.util.GroovyException;
import org.ow2.bonita.util.GroovyExpression;
import org.ow2.bonita.util.GroovyUtil;
import org.ow2.bonita.util.Misc;
import org.ow2.bonita.util.ProcessUtil;
import org.ow2.bonita.util.TransientData;
import org.ow2.bonita.util.VariableUtil;
/**
* @author Marc Blachon, Guillaume Porcher, Charles Souillard, Miguel Valdes, Pierre Vigneras, Pascal Verdage
*/
/**
* Activity life cycle: 1- when an instance is created, activity state is
* {@link ActivityState#INITIAL} 2- when the execution arrives on the node, the
* activity becomes {@link ActivityState#READY} the activity state is recorded
* (before start) 3- if the activity is Manual, a task is created. - when the
* start task is started, the activity state is recorded (after start). 4- the
* activity becomes {@link ActivityState#EXECUTING}. The business logic is
* executed. - the activity state is recorded (before stopped) 5- if the
* activity is Manual, wait for the task to finish. (TODO: change the activity
* state ?) - when the task is finished, the activity state is recorded (after
* stopped). 6- the activity becomes {@link ActivityState#FINISHED}.
*/
public abstract class AbstractActivity implements ExternalActivity {
private static final long serialVersionUID = -2731157748250833266L;
/** LOG */
static final Logger LOG = Logger.getLogger(AbstractActivity.class.getName());
protected long dbid;
protected String activityName;
public static final String BODY_FINISHED = "bodyFinished";
public static final String BODY_SKIPPED = "bodySkipped";
public static final String ACT_INSTANCE_FINISHED = "instFinished";
protected AbstractActivity() {
}
public AbstractActivity(final String activityName) {
this.activityName = activityName;
}
/**
* Return true if the execution can continue
*/
protected abstract boolean executeBusinessLogic(Execution execution);
protected abstract boolean bodyStartAutomatically();
@Override
public void execute(final Execution execution, final boolean checkJoinType) {
final ActivityDefinition activity = execution.getNode();
if (activity.isAsynchronous()) {
Authentication.setUserId(BonitaConstants.SYSTEM_USER);
}
// If instance is ended, don't execute next node.
if (execution.getInstance().getInstanceState().equals(InstanceState.FINISHED)) {
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine("Instance ended : " + execution.getInstance());
}
execution.end();
final Execution parent = execution.getParent();
if (parent != null) {
parent.removeExecution(execution);
}
return;
}
// Execute node.
boolean joinOK = true;
joinOK = ActivityUtil.isJoinOk(execution.getInstance(), execution.getNode());
if (joinOK || !checkJoinType) {
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine("Join for activity " + this + " is OK.");
}
if (activity.getJoinType().equals(JoinType.XOR)) {
cancelJoinXORIncomingTransitions(execution);
}
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine("Creating a new iteration on activity : " + this);
}
ActivityUtil.createNewIteration(execution, activity);
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
final String nodeName = activity.getName();
AbstractActivity.LOG.fine("Executing node: " + nodeName + ", class = " + this.getClass().getSimpleName());
}
final MultiInstantiationDefinition multiInstantiator = activity.getMultiInstantiationDefinition();
final MultiInstantiationDefinition instantiator = activity.getMultipleInstancesInstantiator();
if (multiInstantiator != null || instantiator != null) {
instantiateMultiInstanceActivity(execution);
} else {
if (activity.isInALoop() && activity.evaluateLoopConditionBeforeExecution()) {
if (ActivityUtil.evaluateLoopCondition(activity, execution)) {
final Execution newExecution = execution.createChildExecution(execution.getNode().getName());
initializeActivityInstance(newExecution, null);
startActivityInstance(newExecution);
} else {
terminateInstanceIfNoOutgoingTransitions(execution);
executeSplit(execution, false);
}
} else {
final Execution newExecution = execution.createChildExecution(execution.getNode().getName());
initializeActivityInstance(newExecution, null);
startActivityInstance(newExecution);
}
}
} else {
execution.end();
final Execution parent = execution.getParent();
if (parent != null) {
parent.removeExecution(execution);
}
}
}
private void instantiateMultiInstanceActivity(final Execution execution) {
final ActivityDefinition activity = execution.getNode();
final MultiInstantiationDefinition instantiator = activity.getMultipleInstancesInstantiator();
final Recorder recorder = EnvTool.getRecorder();
RuntimeException caughtException = null;
RuntimeException firstException = null; // the first exception will be
// thrown
final List activitiesToStart = new ArrayList();
if (instantiator != null) {
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine("MultipleActivitiesInstantiation not null on activity " + this);
}
final List> contexts = getContextsFromMultiInstantiator(execution, activity, instantiator);
execution.setWaitingForActivityInstanceNb(contexts.size());
int childId = 0;
for (final Map context : contexts) {
if (execution.getWaitingForActivityInstanceNb() <= 0) {
// maybe this execution is ended
break;
}
final Execution childExec = createChildExecution(execution, childId);
final Set variables = new HashSet();
try {
if (context != null) {
for (final Entry variable : context.entrySet()) {
final Variable multiInstVar = VariableUtil.createVariable(activity.getProcessDefinitionUUID(),
variable.getKey(), variable.getValue());
variables.add(multiInstVar);
}
}
} catch (final RuntimeException e) {
if (LOG.isLoggable(Level.SEVERE)) {
LOG.severe("Error while creating multiInstantiator variables" + e);
}
caughtException = e;
}
try {
initializeActivityInstance(childExec, variables);
activitiesToStart.add(childExec);
} catch (final StaleStateException sse) {
throw sse;
} catch (final AssertionFailure af) {
throw af;
} catch (final LockAcquisitionException lae) {
throw lae;
} catch (final RuntimeException e) {
if (LOG.isLoggable(Level.SEVERE)) {
LOG.severe("Error while initializing multiple instances" + e);
}
caughtException = e;
}
if (caughtException != null) {
if (firstException == null) {
firstException = caughtException;
}
putActivityInFailedStateIfNecessary(recorder, caughtException, childExec);
caughtException = null;
}
childId++;
}
} else {
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine("MultiInstantiation not null on activity " + this);
}
MultiInstantiatorDescriptor actInstDescr = null;
final MultiInstantiationDefinition multiDef = activity.getMultiInstantiationDefinition();
final MultiInstantiator actInstantiator = EnvTool.getClassDataLoader().getInstance(MultiInstantiator.class,
execution.getInstance().getProcessDefinitionUUID(), multiDef);
try {
actInstDescr = ConnectorExecutor.executeMultiInstantiator(execution, activity.getName(), actInstantiator,
multiDef.getParameters());
if (actInstDescr == null) {
final String message = ExceptionManager.getInstance().getFullMessage("be_AA_3", activity.getName());
throw new BonitaRuntimeException(message);
}
} catch (final Exception e) {
throw new BonitaWrapperException(new MultiInstantiatorInvocationException("be_AA_4", activity
.getMultiInstantiationDefinition().getClassName(), e));
}
execution.setWaitingForActivityInstanceNb(actInstDescr.getJoinNumber());
int childId = 0;
for (final Object value : actInstDescr.getVariableValues()) {
if (execution.getWaitingForActivityInstanceNb() <= 0) {
// maybe this execution is ended
break;
}
final Execution childExec = createChildExecution(execution, childId);
Variable multiInstVar = null;
try {
multiInstVar = VariableUtil.createVariable(activity.getProcessDefinitionUUID(), activity
.getMultiInstantiationDefinition().getVariableName(), value);
} catch (final StaleStateException sse) {
throw sse;
} catch (final AssertionFailure af) {
throw af;
} catch (final LockAcquisitionException lae) {
throw lae;
} catch (final RuntimeException e) {
if (LOG.isLoggable(Level.SEVERE)) {
LOG.severe("Error while creating multiInstantiator variable" + e);
}
caughtException = e;
}
final Set variables = new HashSet();
if (multiInstVar != null) {
variables.add(multiInstVar);
}
try {
initializeActivityInstance(childExec, variables);
activitiesToStart.add(childExec);
} catch (final RuntimeException e) {
if (LOG.isLoggable(Level.SEVERE)) {
LOG.severe("Error while initializing multiple instances" + e);
}
caughtException = e;
}
if (caughtException != null) {
if (firstException == null) {
firstException = caughtException;
}
putActivityInFailedStateIfNecessary(recorder, caughtException, childExec);
caughtException = null;
}
childId++;
}
}
final List unrollBackableExceptions = startActivityInstances(activitiesToStart);
if (!unrollBackableExceptions.isEmpty()) {
throw unrollBackableExceptions.get(0);// throw the first exception
}
if (firstException != null
&& ExtensionPointsPolicy.THROW_EXCPTION_ON_FAIL.equals(EnvTool.getExtensionPointsPolicy())) {
if (firstException instanceof UnRollbackableException) {
throw firstException;
}
throw new UnRollbackableException("Error while initializing activity", firstException);
}
}
private void putActivityInFailedStateIfNecessary(final Recorder recorder, final RuntimeException caughtException,
final Execution childExec) {
final InternalActivityInstance activityInstance = childExec.getActivityInstance();
if (activityInstance != null) {
if (!(caughtException instanceof UnRollbackableException)) {
recorder.recordActivityFailed(activityInstance);
}
} else {
throw caughtException;
}
}
private List> getContextsFromMultiInstantiator(final Execution execution,
final ActivityDefinition activity, final MultiInstantiationDefinition instantiator) {
List> contexts;
try {
contexts = ConnectorExecutor.executeMultipleInstancesInstantiatior(instantiator, execution.getInstance()
.getUUID(), activityName, execution.getIterationId());
if (contexts == null) {
final String message = ExceptionManager.getInstance().getFullMessage("be_AA_8", activity.getName());
throw new BonitaRuntimeException(message);
} else if (contexts.isEmpty()) {
final String message = ExceptionManager.getInstance().getFullMessage("be_AA_9", activity.getName());
throw new BonitaRuntimeException(message);
}
} catch (final Exception e) {
throw new BonitaRuntimeException(e.getMessage(), e);
}
return contexts;
}
private Execution createChildExecution(final Execution execution, final int childId) {
final Execution childExec = execution.createChildExecution(execution.getName() + "/" + childId);
childExec.setActivityInstanceId(Integer.toString(childId));
return childExec;
}
private List startActivityInstances(final List activitiesToStart) {
final List unRollbackableExceptions = new ArrayList();
for (final Execution childExec : activitiesToStart) {
if (childExec.isActive()) {
// multi is not yet ended
try {
startActivityInstance(childExec);
} catch (final StaleStateException sse) {
throw sse;
} catch (final AssertionFailure af) {
throw af;
} catch (final LockAcquisitionException lae) {
throw lae;
} catch (final RuntimeException e) {
final InternalActivityInstance activityInstance = childExec.getActivityInstance();
if (activityInstance != null) {
EnvTool.getRecorder().recordActivityFailed(activityInstance);
if (ExtensionPointsPolicy.THROW_EXCPTION_ON_FAIL.equals(EnvTool.getExtensionPointsPolicy())) {
unRollbackableExceptions.add(new UnRollbackableException("Error while executing starting", e));
}
}
// throw e;
}
}
}
return unRollbackableExceptions;
}
private void cancelJoinXORIncomingTransitions(final Execution execution) {
final InternalActivityDefinition currentNode = execution.getNode();
final InternalProcessInstance instance = execution.getInstance();
cancelJoinXORIncomingTransitions(instance, currentNode, new HashSet());
for (final TransitionDefinition t : currentNode.getIncomingTransitions()) {
instance.setTransitionState(t.getName(), TransitionState.ABORTED);
}
}
private void cancelJoinXORIncomingTransitions(final InternalProcessInstance instance,
final InternalActivityDefinition currentNode, final Set checkedNodes) {
final Set incomingTransitions = currentNode.getIncomingTransitions();
final String currentNodeName = currentNode.getName();
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine("Canceling other branches of the join XOR : " + currentNodeName);
}
checkedNodes.add(currentNodeName);
for (final TransitionDefinition incomingTransition : incomingTransitions) {
final String sourceNodeName = incomingTransition.getFrom();
final TransitionState transitionState = instance.getTransitionState(incomingTransition.getName());
if (!checkedNodes.contains(sourceNodeName)
&& (transitionState == null || transitionState.equals(TransitionState.READY))) {
boolean enable = false;
final InternalActivityDefinition sourceNode = instance.getRootExecution().getProcessDefinition()
.getActivity(sourceNodeName);
if (transitionState != null) {
// disable transition
instance.setTransitionState(incomingTransition.getName(), TransitionState.ABORTED);
// check if source node is still enabled
// it is still enabled if it has at least one READY outgoing
// transition (in the
// same cycle if in a cycle)
top: for (final TransitionDefinition tr : sourceNode.getOutgoingTransitions()) {
final TransitionState ts = instance.getTransitionState(tr.getName());
if (ts == null || ts.equals(TransitionState.READY)) {
if (currentNode.isInCycle()) {
final ProcessDefinition process = EnvTool.getJournalQueriers().getProcess(
instance.getProcessDefinitionUUID());
for (final IterationDescriptor itDesc : process.getIterationDescriptors()) {
if (itDesc.containsNode(tr.getTo())) {
// stay in same cycle => do not disable node
enable = true;
break top;
}
}
}
}
}
}
if (!enable) {
// abort sourceNode recursively: sourceNode is not enabled, maybe it
// doesn't have any
// activityInstance. Checks if there is one before
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine(sourceNodeName + " has no more outgoing transitions enabled.");
}
final List execToAbortList = instance.getExecOnNode(sourceNodeName);
for (final Execution execToAbort : execToAbortList) {
destroyEvents(execToAbort);
if (!execToAbort.isActive()) {
execToAbort.unlock();
}
execToAbort.abort();
}
cancelJoinXORIncomingTransitions(instance, sourceNode, checkedNodes);
}
}
}
}
protected void initializeActivityInstance(final Execution internalExecution,
final Set multiInstanceVariables) {
final InternalActivityDefinition activity = internalExecution.getNode();
final ProcessInstanceUUID instanceUUID = internalExecution.getInstance().getUUID();
final Recorder recorder = EnvTool.getRecorder();
Map initialVariables = null;
RuntimeException exception = null;
try {
initialVariables = VariableUtil.createVariables(activity.getDataFields(), instanceUUID, null);
} catch (final StaleStateException sse) {
throw sse;
} catch (final AssertionFailure af) {
throw af;
} catch (final LockAcquisitionException lae) {
throw lae;
} catch (final RuntimeException t) {
if (LOG.isLoggable(Level.SEVERE)) {
LOG.severe("Error while initializingVariables " + t);
}
exception = t;
}
if (multiInstanceVariables != null) {
if (initialVariables == null) {
initialVariables = new HashMap();
}
for (final Variable variable : multiInstanceVariables) {
initialVariables.put(variable.getKey(), variable);
}
}
String loopId = "noLoop";
if (activity.isInALoop()) {
loopId = Misc.getUniqueId("lp");
}
final String iterationId = internalExecution.getIterationId();
final String activityInstanceId = internalExecution.getActivityInstanceId();
final ActivityInstanceUUID activityUUID = new ActivityInstanceUUID(instanceUUID, activity.getName(), iterationId,
activityInstanceId, loopId);
final InternalActivityInstance activityInstance = new InternalActivityInstance(activityUUID, activity,
instanceUUID, internalExecution.getInstance().getRootInstanceUUID(), iterationId, activityInstanceId, loopId);
if (exception == null) {
activityInstance.setActivityState(ActivityState.READY, BonitaConstants.SYSTEM_USER);
activityInstance.setVariables(initialVariables);
// add transient data
TransientData.addTransientVariables(activityUUID,
VariableUtil.createTransientVariables(activity.getDataFields(), instanceUUID));
recorder.recordEnterActivity(activityInstance);
if (activity.getDynamicDescription() != null) {
try {
if (GroovyExpression.isGroovyExpression(activity.getDynamicDescription())) {
final Object dynamicDescription = GroovyUtil.evaluate(activity.getDynamicDescription(), null, activityUUID,
false, false);
if (dynamicDescription != null) {
activityInstance.setDynamicDescription(dynamicDescription.toString());
}
} else {
activityInstance.setDynamicDescription(activity.getDynamicDescription());
}
} catch (final Exception e) {
internalExecution.setActivityInstance(activityInstance);
throw new BonitaWrapperException(new BonitaRuntimeException("Error while evaluating dynamic description: "
+ activity.getDynamicDescription(), e));
}
}
if (activity.getDynamicLabel() != null) {
try {
if (GroovyExpression.isGroovyExpression(activity.getDynamicLabel())) {
final Object dynamicLabel = GroovyUtil.evaluate(activity.getDynamicLabel(), null, activityUUID, false,
false);
if (dynamicLabel != null) {
activityInstance.setDynamicLabel(dynamicLabel.toString());
}
} else {
activityInstance.setDynamicLabel(activity.getDynamicLabel());
}
} catch (final Exception e) {
internalExecution.setActivityInstance(activityInstance);
throw new BonitaWrapperException(new BonitaRuntimeException("Error while evaluating dynamic label: "
+ activity.getDynamicLabel(), e));
}
}
internalExecution.setActivityInstance(activityInstance);
} else {
// recordFailed
if (LOG.isLoggable(Level.SEVERE)) {
LOG.log(Level.SEVERE, exception.getMessage(), exception);
}
recorder.recordEnterActivity(activityInstance);
recorder.recordActivityFailed(activityInstance);
internalExecution.setActivityInstance(activityInstance);
throw exception;
}
}
private void startActivityInstance(final Execution internalExecution) {
final InternalActivityDefinition activity = internalExecution.getNode();
final ActivityInstanceUUID activityUUID = internalExecution.getActivityInstanceUUID();
try {
initializeEvents(internalExecution);
} catch (final GroovyException e) {
final String message = "Error while initializing events: ";
throw new BonitaWrapperException(new BonitaRuntimeException(message, e));
}
if (activity.isAsynchronous()) {
final EventService eventService = EnvTool.getEventService();
String uuid = internalExecution.getEventUUID();
if (uuid == null) {
uuid = UUID.randomUUID().toString();
}
final String eventName = BonitaConstants.ASYNC_EVENT_PREFIX + activityUUID;
internalExecution.setEventUUID(uuid);
internalExecution.lock("async continuation " + eventName);
final Job async = JobBuilder.asyncJob(eventName, internalExecution.getInstance().getRootInstanceUUID(), uuid,
internalExecution.getInstance().getProcessInstanceUUID());
eventService.storeJob(async);
} else {
executeActivityInstance(internalExecution);
}
}
protected void executeActivityInstance(final Execution internalExecution) {
final boolean canContinue = executeBody(internalExecution);
if (canContinue) {
end(internalExecution);
} else {
internalExecution.waitForSignal();
}
}
protected void end(final Execution internalExecution) {
try {
final ActivityDefinition activity = internalExecution.getNode();
if (activity.getDynamicExecutionSummary() != null) {
try {
if (GroovyExpression.isGroovyExpression(activity.getDynamicExecutionSummary())) {
final Object dynamicExecutionSummary = GroovyUtil.evaluate(activity.getDynamicExecutionSummary(), null,
internalExecution.getActivityInstanceUUID(), false, false);
if (dynamicExecutionSummary != null) {
internalExecution.getActivityInstance().setDynamicExecutionSummary(dynamicExecutionSummary.toString());
}
} else {
internalExecution.getActivityInstance().setDynamicExecutionSummary(activity.getDynamicExecutionSummary());
}
} catch (final Exception e) {
throw new BonitaWrapperException(new BonitaRuntimeException(
"Error while evaluating dynamic execution summary: " + activity.getDynamicExecutionSummary(), e));
}
}
EnvTool.getRecorder().recordBodyEnded(internalExecution.getActivityInstance());
if (activity.getMultiInstantiationDefinition() != null || activity.getMultipleInstancesInstantiator() != null) {
endMultiInstantiation(internalExecution);
} else if (activity.isInALoop()) {
endLoop(internalExecution);
} else {
terminateInstanceIfNoOutgoingTransitions(internalExecution);
executeSplit(internalExecution, true);
}
} catch (final StaleStateException sse) {
throw sse;
} catch (final AssertionFailure af) {
throw af;
} catch (final LockAcquisitionException lae) {
throw lae;
} catch (final UnRollbackableException e) {
throw e;
} catch (final RuntimeException e) {
final InternalActivityInstance activityInstance = internalExecution.getActivityInstance();
EnvTool.getRecorder().recordActivityFailed(activityInstance);
if (ExtensionPointsPolicy.THROW_EXCPTION_ON_FAIL.equals(EnvTool.getExtensionPointsPolicy())) {
throw new UnRollbackableException("Error while executing connector taskOnFinish", e);
} else {
if (LOG.isLoggable(Level.SEVERE)) {
LOG.log(Level.SEVERE, e.getMessage(), e);
}
}
} finally {
TransientData.removeTransientData(internalExecution.getActivityInstance().getUUID());
}
}
protected void skip(final Execution internalExecution) {
final ActivityDefinition activity = internalExecution.getNode();
if (activity.getDynamicExecutionSummary() != null) {
try {
if (GroovyExpression.isGroovyExpression(activity.getDynamicExecutionSummary())) {
final Object dynamicExecutionSummary = GroovyUtil.evaluate(activity.getDynamicExecutionSummary(), null,
internalExecution.getActivityInstanceUUID(), false, false);
if (dynamicExecutionSummary != null) {
internalExecution.getActivityInstance().setDynamicExecutionSummary(dynamicExecutionSummary.toString());
}
} else {
internalExecution.getActivityInstance().setDynamicExecutionSummary(activity.getDynamicExecutionSummary());
}
} catch (final Exception e) {
throw new BonitaWrapperException(new BonitaRuntimeException("Error while ending execution: "
+ activity.getDynamicExecutionSummary(), e));
}
}
if (activity.getMultiInstantiationDefinition() != null || activity.getMultipleInstancesInstantiator() != null) {
removeChildrenActivityInstances(internalExecution);
terminateInstanceIfNoOutgoingTransitions(internalExecution);
executeSplit(internalExecution, false);
} else {
terminateInstanceIfNoOutgoingTransitions(internalExecution);
executeSplit(internalExecution, true);
}
}
protected void endMultiInstantiation(final Execution internalExecution) {
final ActivityDefinition activity = internalExecution.getNode();
final Execution parent = internalExecution.getParent();
boolean cleanActiveExecutions = false;
if (parent.getWaitingForActivityInstanceNb() > 1) {
final MultiInstantiationDefinition joinChecker = activity.getMultipleInstancesJoinChecker();
if (joinChecker != null) {
boolean join = false;
try {
join = ConnectorExecutor.executeMultipleInstancesJoinChecker(joinChecker, internalExecution
.getActivityInstance().getUUID());
} catch (final Exception e) {
throw new BonitaRuntimeException(e.getMessage(), e);
}
if (join) {
parent.setWaitingForActivityInstanceNb(1);
cleanActiveExecutions = true;
}
}
}
if (cleanActiveExecutions) {
for (final Execution execution : parent.getExecutions()) {
destroyEvents(execution);
}
} else {
destroyEvents(internalExecution);
}
internalExecution.end();
parent.removeExecution(internalExecution);
signal(parent, AbstractActivity.ACT_INSTANCE_FINISHED, null);
}
protected void endLoop(final Execution internalExecution) {
final ActivityDefinition activity = internalExecution.getNode();
final Execution parent = internalExecution.getParent();
int maxIterations = 0;
final String maxIterationsExpr = activity.getLoopMaximum();
if (maxIterationsExpr != null) {
try {
if (Misc.isJustAGroovyExpression(maxIterationsExpr)) {
final ProcessInstanceUUID instanceUUID = internalExecution.getInstance().getUUID();
final Querier journal = EnvTool.getJournalQueriers();
final ActivityInstance activityInstance = journal.getActivityInstance(instanceUUID,
internalExecution.getNodeName(), internalExecution.getIterationId(),
internalExecution.getActivityInstanceId(), internalExecution.getActivityInstance().getLoopId());
maxIterations = (Integer) GroovyUtil.evaluate(maxIterationsExpr, null, activityInstance.getUUID(), false,
false);
} else {
maxIterations = Integer.parseInt(maxIterationsExpr);
}
} catch (final Exception e) {
AbstractActivity.LOG.log(Level.SEVERE, "The maximum number of loop iterations for activity " + activityName
+ " must be an integer or an expression that evaluates to an integer", e);
}
}
parent.setWaitingForActivityInstanceNb(maxIterations);
signal(parent, AbstractActivity.ACT_INSTANCE_FINISHED, null);
if (!internalExecution.isFinished()) {
// the number of iteration reached the maximum loop iterations authorized
boolean loop = true;
if (!activity.evaluateLoopConditionBeforeExecution()) {
loop = ActivityUtil.evaluateLoopCondition(activity, internalExecution);
}
if (loop) {
destroyEvents(internalExecution);
parent.removeExecution(internalExecution);
execute(parent, false);
} else {
terminateInstanceIfNoOutgoingTransitions(internalExecution);
executeSplit(internalExecution, true);
}
}
}
private void terminateInstanceIfNoOutgoingTransitions(final Execution internalExecution) {
final ActivityDefinition activity = internalExecution.getNode();
final InternalProcessInstance instance = internalExecution.getInstance();
final ProcessInstanceUUID instanceUUID = instance.getUUID();
final ActivityInstanceUUID activityUUID = internalExecution.getActivityInstanceUUID();
if (activity.isTerminateProcess()
|| !(activity.hasOutgoingTransitions() || hasStillReadyActivities(instanceUUID, activityUUID) || hasStillReadyTransitions(instance))) {
final ProcessInstanceUUID parentInstanceUUID = instance.getParentInstanceUUID();
ConnectorExecutor.executeConnectors(internalExecution, HookDefinition.Event.instanceOnFinish);
final Recorder recorder = EnvTool.getRecorder();
recorder.recordInstanceEnded(instance.getUUID(), EnvTool.getUserId());
ProcessUtil.removeInternalInstanceEvents(instance.getUUID());
if (parentInstanceUUID != null) {
if (ProcessType.EVENT_SUB_PROCESS.equals(internalExecution.getProcessDefinition().getType())) {
final InternalProcessInstance parentInstance = EnvTool.getJournalQueriers().getProcessInstance(
parentInstanceUUID);
if (parentInstance.getParentActivityUUID() != null) {
final Execution rootExecution = EnvTool.getAllQueriers().getExecutionOnActivity(
parentInstance.getParentInstanceUUID(), parentInstance.getParentActivityUUID());
try {
rootExecution.getNode().getBehaviour().signal(rootExecution, BODY_FINISHED, null);
} catch (final Exception e) {
throw new BonitaRuntimeException(e.getMessage(), e);
}
} else {
parentInstance.finish();
}
} else {
// We are in a subflow
final Map signalParameters = new HashMap();
signalParameters.put("childInstanceUUID", instanceUUID);
final InternalProcessInstance parentInstance = EnvTool.getJournalQueriers().getProcessInstance(
parentInstanceUUID);
final Execution parentRootExecution = parentInstance.getRootExecution();
final Execution execToSignal = getSubflowExecution(parentRootExecution, instanceUUID);
try {
execToSignal.getNode().getBehaviour().signal(execToSignal, SubFlow.SUBFLOW_SIGNAL, signalParameters);
} catch (final Exception e) {
throw new BonitaRuntimeException(e.getMessage(), e);
}
}
} else {
instance.finish();
}
}
}
private boolean hasStillReadyActivities(final ProcessInstanceUUID instanceUUID,
final ActivityInstanceUUID activityUUID) {
return EnvTool.getJournalQueriers().containsOtherActiveActivities(instanceUUID, activityUUID);
}
private boolean hasStillReadyTransitions(final InternalProcessInstance instance) {
boolean hasStillReadyTransitions = false;
final Iterator iterator = instance.getTransitionsStates().values().iterator();
while (!hasStillReadyTransitions && iterator.hasNext()) {
final String state = iterator.next();
if (TransitionState.READY.toString().equals(state)) {
hasStillReadyTransitions = true;
}
}
return hasStillReadyTransitions;
}
private Execution getSubflowExecution(final Execution exec, final ProcessInstanceUUID subflowInstanceUUID) {
if (exec.getActivityInstance() != null && exec.getActivityInstance().getSubflowProcessInstanceUUID() != null
&& exec.getActivityInstance().getSubflowProcessInstanceUUID().equals(subflowInstanceUUID)) {
return exec;
}
for (final Execution child : exec.getExecutions()) {
final Execution e = getSubflowExecution(child, subflowInstanceUUID);
if (e != null) {
return e;
}
}
return null;
}
@Override
@SuppressWarnings("deprecation")
public void signal(final Execution execution, final String signal, final Map parameters) {
final Execution internalExecution = execution;
final InternalActivityDefinition activity = execution.getNode();
if (AbstractActivity.BODY_FINISHED.equals(signal)) {
end(internalExecution);
} else if (AbstractActivity.ACT_INSTANCE_FINISHED.equals(signal)) {
if (activity.getMultiInstantiationDefinition() != null || activity.getMultipleInstancesInstantiator() != null) {
// in case of a multi-instantiation
internalExecution.setWaitingForActivityInstanceNb(internalExecution.getWaitingForActivityInstanceNb() - 1);
if (internalExecution.getWaitingForActivityInstanceNb() == 0) {
removeChildrenActivityInstances(internalExecution);
terminateInstanceIfNoOutgoingTransitions(internalExecution);
executeSplit(internalExecution, false);
}
} else {
// in case of a loop
internalExecution.setActivityInstanceNb(internalExecution.getActivityInstanceNb() + 1);
final int maxIterations = internalExecution.getWaitingForActivityInstanceNb();
if (0 < maxIterations && maxIterations <= internalExecution.getActivityInstanceNb()) {
endChildrenActivityInstances(internalExecution);
terminateInstanceIfNoOutgoingTransitions(internalExecution);
executeSplit(internalExecution, false);
}
}
} else if (EventConstants.ASYNC.equals(signal)) {
Authentication.setUserId(BonitaConstants.SYSTEM_USER);
executeActivityInstance(internalExecution);
} else if (EventConstants.DEADLINE.equals(signal)) {
final Long id = (Long) parameters.get("id");
DeadlineDefinition deadline = null;
if (id != null) {
deadline = getMatchingDeadline(id, activity.getDeadlines());
} else {
final String className = (String) parameters.get("className");
deadline = getCompatibleDeadline(className, activity.getDeadlines());
}
if (deadline != null) {
Authentication.setUserId(BonitaConstants.SYSTEM_USER);
// By default, a deadline does not propagate execution
internalExecution.waitForSignal();
final String activityId = internalExecution.getNode().getName();
ConnectorExecutor.executeConnector(internalExecution, activityId, deadline);
}
} else if (EventConstants.BOUNDARY.equals(signal)) {
destroyEvents(internalExecution);
if (activity.getMultiInstantiationDefinition() != null || activity.getMultipleInstancesInstantiator() != null) {
if (internalExecution.getParent() != null) {
for (final Execution execToAbort : new ArrayList(internalExecution.getParent().getExecutions())) {
if (!execToAbort.equals(internalExecution) && execToAbort.isActive()) {
execToAbort.abort();
}
}
}
}
final InternalActivityInstance activityInstance = internalExecution.getActivityInstance();
EnvTool.getRecorder().recordBodyAborted(activityInstance);
TransientData.removeTransientData(activityInstance.getUUID());
if (activity.isSubflow()) {
final InternalProcessInstance subprocessInstance = EnvTool.getJournalQueriers().getProcessInstance(
activityInstance.getSubflowProcessInstanceUUID());
EnvTool.getRecorder().recordInstanceAborted(subprocessInstance.getUUID(), BonitaConstants.SYSTEM_USER);
}
internalExecution.setActivityInstance(null);
if (EventConstants.MESSAGE_BOUNDARY_EVENT.equals(signal)) {
ConnectorExecutor.executeConnectors(activity, execution, Event.onEvent, parameters);
}
final BoundaryEvent event = activity.getBoundaryEvent(parameters.get("eventName").toString());
final TransitionDefinition exceptionTransition = event.getTransition();
internalExecution.take(exceptionTransition);
} else if (AbstractActivity.BODY_SKIPPED.equals(signal)) {
skip(internalExecution);
} else if (EventConstants.CONNECTORS_AUTOMATIC_ON_ENTER_EXECUTED.equals(signal)) {
ConnectorExecutor.executeConnectors(activity, execution, Event.automaticOnExit);
end(internalExecution);
}
}
private DeadlineDefinition getCompatibleDeadline(final String className, final Set deadlines) {
for (final DeadlineDefinition deadline : deadlines) {
if (deadline.getClassName().equals(className)) {
return deadline;
}
}
return null;
}
private DeadlineDefinition getMatchingDeadline(final Long id, final Set deadlines) {
for (final DeadlineDefinition d : deadlines) {
final InternalConnectorDefinition deadline = (InternalConnectorDefinition) d;
if (deadline.getDbid() == id) {
return deadline;
}
}
return null;
}
private void removeChildrenActivityInstances(final Execution execution) {
if (execution.getExecutions() != null) {
for (final Execution execToAbort : new ArrayList(execution.getExecutions())) {
execToAbort.abort();
}
}
}
private void endChildrenActivityInstances(final Execution execution) {
if (execution.getExecutions() != null) {
for (final Execution execToEnd : new ArrayList(execution.getExecutions())) {
execToEnd.end();
execution.removeExecution(execToEnd);
}
}
}
private void initializeEvents(final Execution execution) throws GroovyException {
final InternalActivityDefinition activity = execution.getNode();
final Set deadlines = activity.getDeadlines();
final List boundaryEvents = activity.getBoundaryEvents();
if (!deadlines.isEmpty() || !boundaryEvents.isEmpty()) {
final String executionEventUUID = "event-" + UUID.randomUUID().toString();
execution.setEventUUID(executionEventUUID);
initializeTimers(execution, executionEventUUID);
initializeBoundaryEvents(execution, executionEventUUID);
}
}
private void initializeTimers(final Execution execution, final String executionEventUUID) throws GroovyException {
// initialize the timers
final InternalActivityDefinition activity = execution.getNode();
final ActivityInstanceUUID activityUUID = execution.getActivityInstanceUUID();
final Set deadlines = activity.getDeadlines();
if (!deadlines.isEmpty()) {
final EventService eventService = EnvTool.getEventService();
for (final DeadlineDefinition d : deadlines) {
final InternalConnectorDefinition deadline = (InternalConnectorDefinition) d;
final String condition = deadline.getCondition();
final long fireTime = ProcessUtil.getTimerDate(condition, activityUUID).getTime();
final Job dl = JobBuilder.deadlineJob("" + deadline.getDbid(), execution.getInstance().getRootInstanceUUID(),
executionEventUUID, fireTime, execution.getInstance().getProcessInstanceUUID());
eventService.storeJob(dl);
}
}
}
private void initializeBoundaryEvents(final Execution execution, final String executionEventUUID)
throws GroovyException {
final InternalActivityDefinition activity = execution.getNode();
final List boundaryEvents = activity.getBoundaryEvents();
if (!boundaryEvents.isEmpty()) {
final ActivityInstanceUUID activityUUID = execution.getActivityInstanceUUID();
final ActivityInstance activityInstance = execution.getActivityInstance();
final ProcessInstanceUUID instanceUUID = activityInstance.getProcessInstanceUUID();
final EventService eventService = EnvTool.getEventService();
final String processName = execution.getProcessDefinition().getName();
for (final BoundaryEvent boundaryEvent : boundaryEvents) {
if (boundaryEvent instanceof TimerBoundaryEventImpl) {
final TimerBoundaryEventImpl timer = (TimerBoundaryEventImpl) boundaryEvent;
final String eventName = timer.getName();
final String condition = timer.getCondition();
final Date date = ProcessUtil.getTimerDate(condition, activityUUID);
final ProcessInstanceUUID rootInstanceUUID = execution.getInstance().getRootInstanceUUID();
final Job boundaryTimer = JobBuilder.boundaryTimerJob(eventName, rootInstanceUUID, executionEventUUID,
date.getTime(), instanceUUID);
eventService.storeJob(boundaryTimer);
} else if (boundaryEvent instanceof MessageBoundaryEventImpl) {
final MessageBoundaryEventImpl message = (MessageBoundaryEventImpl) boundaryEvent;
final String expression = message.getExpression();
final IncomingEventInstance eventInstance = new IncomingEventInstance(message.getName(), expression,
instanceUUID, activity.getUUID(), activityUUID, processName, activityName, executionEventUUID,
EventConstants.MESSAGE_BOUNDARY_EVENT, System.currentTimeMillis(), true);
ActivityUtil.addCorrelationKeys(message, eventInstance, activityUUID);
eventService.subscribe(eventInstance);
} else if (boundaryEvent instanceof SignalBoundaryEventImpl) {
final SignalBoundaryEventImpl signal = (SignalBoundaryEventImpl) boundaryEvent;
final String signalName = signal.getSignalCode();
final IncomingEventInstance signalEventInstance = new IncomingEventInstance(signalName, null, instanceUUID, activity.getUUID(), activityUUID, processName,
signal.getName(), executionEventUUID, EventConstants.SIGNAL_BOUNDARY_EVENT, -1, false);
eventService.subscribe(signalEventInstance);
}
}
}
}
private static void destroyEvents(final Execution execution) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("destroying events of " + execution.toString());
}
final ActivityInstanceUUID activityUUID = execution.getActivityInstanceUUID();
if (activityUUID != null) {
if (execution.getNode() == null || execution.getNode().hasBoundaryEvents()) {
ActivityUtil.deleteBoundaryEvents(activityUUID);
}
ActivityUtil.deleteJobs(execution.getEventUUID());
}
}
private boolean executeBody(final Execution internalExecution) {
if (bodyStartAutomatically()) {
EnvTool.getRecorder().recordBodyStarted(internalExecution.getActivityInstance());
}
return executeBusinessLogic(internalExecution);
}
@Override
public String toString() {
final StringBuffer buffer = new StringBuffer();
buffer.append(this.getClass().getName());
buffer.append(": activtyName: " + getActivityName());
return buffer.toString();
}
public String getActivityName() {
return activityName;
}
public void executeSplit(final Execution execution, final boolean removeScope) {
final ActivityDefinition activity = execution.getNode();
Execution internalExecution = execution;
final InternalActivityDefinition currentNode = internalExecution.getNode();
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine("node = " + currentNode.getName() + " - splitType = " + activity.getSplitType()
+ " - execution = " + execution.getName());
}
final Set transitions = currentNode.getOutgoingTransitions();
if (transitions.isEmpty()) {
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine("node = " + currentNode.getName() + " - splitType = " + activity.getSplitType()
+ " - execution = " + execution.getName() + " no transition available. Ending execution");
}
internalExecution.end();
final Execution parent = internalExecution.getParent();
if (parent != null) {
parent.removeExecution(internalExecution);
}
} else {
TransitionDefinition defaultTransition = null;
final List transitionsToTake = new ArrayList();
for (final TransitionDefinition t : transitions) {
if (t.isDefault()) {
defaultTransition = t;
} else if (ActivityUtil.evaluateTransition(t, internalExecution)) {
final TransitionState transitionState = internalExecution.getInstance().getTransitionState(t.getName());
if (transitionState == null || transitionState.equals(TransitionState.READY)) {
internalExecution.getInstance().setTransitionState(t.getName(), TransitionState.READY);
transitionsToTake.add(t);
}
}
}
if (defaultTransition != null && transitionsToTake.size() == 0) {
final TransitionState transitionState = internalExecution.getInstance().getTransitionState(
defaultTransition.getName());
if (transitionState == null) {
internalExecution.getInstance().setTransitionState(defaultTransition.getName(), TransitionState.READY);
transitionsToTake.add(defaultTransition);
}
}
// remove not propagated variables
if (removeScope) {
destroyEvents(internalExecution);
internalExecution = internalExecution.backToParent();
}
internalExecution.setActivityInstance(null);
if (transitionsToTake.size() == 0) {
internalExecution.end();
final Execution parent = internalExecution.getParent();
if (parent != null) {
parent.removeExecution(internalExecution);
}
} else {
Set iterationDescriptors = null;
// check we are leaving a cycle
if (activity.isInCycle()) {
final ProcessDefinition process = EnvTool.getJournalQueriers()
.getProcess(activity.getProcessDefinitionUUID());
iterationDescriptors = process.getIterationDescriptors();
for (final IterationDescriptor itD : iterationDescriptors) {
boolean isLeaving = false;
for (final TransitionDefinition t : transitionsToTake) {
if (!itD.containsNode(t.getTo()) && itD.containsNode(t.getFrom())) {
isLeaving = true;
}
}
if (isLeaving) {
// abort execution of other nodes.
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine(activity.getName() + " is leaving a cycle, aborting other nodes in cycle.");
}
for (final String nodeToAbort : itD.getCycleNodes()) {
if (!nodeToAbort.equals(currentNode.getName())) {
final List execToAbortList = internalExecution.getInstance().getExecOnNode(nodeToAbort);
for (final Execution execToAbort : execToAbortList) {
if (execToAbort.isActive()) {
execToAbort.abort();
}
}
}
}
}
}
}
if (transitionsToTake.size() == 1 || SplitType.XOR.equals(activity.getSplitType())) {
// We are in a Split/AND and only one transition is true,
// or we are in a Split/XOR, so we take the first one that is true.
final TransitionDefinition t = transitionsToTake.get(0);
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine("Taking transition " + t);
}
internalExecution.take(t);
} else {
// We are in a Split/AND and more than one transition is true.
// check we are not leaving a cycle and staying in the cycle at the
// same time
if (EnvTool.getIterationDetectionPolicy() == IterationDetectionPolicy.ENABLE && activity.isInCycle()) {
for (final IterationDescriptor itD : iterationDescriptors) {
boolean isLeaving = false;
boolean isStaying = false;
for (final TransitionDefinition t : transitionsToTake) {
if (!itD.containsNode(t.getTo())) {
isLeaving = true;
} else {
isStaying = true;
}
}
if (isStaying && isLeaving) {
final String message = ExceptionManager.getInstance().getFullMessage("be_AA_5");
throw new BonitaWrapperException(new BonitaRuntimeException(message));
}
}
}
final List children = new ArrayList();
for (int i = 0; i < transitionsToTake.size(); i++) {
final TransitionDefinition t = transitionsToTake.get(i);
final String name = t.getFrom() + "_to_" + t.getTo();
final Execution childExecution = internalExecution.createChildExecution(name);
children.add(childExecution);
}
for (int i = 0; i < transitionsToTake.size(); i++) {
final Execution childExecution = children.get(i);
final TransitionDefinition t = transitionsToTake.get(i);
if (!childExecution.isFinished()) {
if (AbstractActivity.LOG.isLoggable(Level.FINE)) {
AbstractActivity.LOG.fine("Execution " + childExecution.getName() + " is taking transition " + t);
}
childExecution.take(t);
}
}
}
}
}
}
}