use of org.activiti.engine.impl.pvm.PvmTransition in project Activiti by Activiti.
the class ExecutionEntity method takeAll.
@SuppressWarnings({ "unchecked", "rawtypes" })
public void takeAll(List<PvmTransition> transitions, List<ActivityExecution> recyclableExecutions) {
fireActivityCompletedEvent();
transitions = new ArrayList<PvmTransition>(transitions);
recyclableExecutions = (recyclableExecutions != null ? new ArrayList<ActivityExecution>(recyclableExecutions) : new ArrayList<ActivityExecution>());
if (recyclableExecutions.size() > 1) {
for (ActivityExecution recyclableExecution : recyclableExecutions) {
if (((ExecutionEntity) recyclableExecution).isScope()) {
throw new PvmException("joining scope executions is not allowed");
}
}
}
ExecutionEntity concurrentRoot = ((isConcurrent && !isScope) ? getParent() : this);
List<ExecutionEntity> concurrentActiveExecutions = new ArrayList<ExecutionEntity>();
List<ExecutionEntity> concurrentInActiveExecutions = new ArrayList<ExecutionEntity>();
for (ExecutionEntity execution : concurrentRoot.getExecutions()) {
if (execution.isActive()) {
concurrentActiveExecutions.add(execution);
} else {
concurrentInActiveExecutions.add(execution);
}
}
if (log.isDebugEnabled()) {
log.debug("transitions to take concurrent: {}", transitions);
log.debug("active concurrent executions: {}", concurrentActiveExecutions);
}
if ((transitions.size() == 1) && (concurrentActiveExecutions.isEmpty()) && allExecutionsInSameActivity(concurrentInActiveExecutions)) {
List<ExecutionEntity> recyclableExecutionImpls = (List) recyclableExecutions;
recyclableExecutions.remove(concurrentRoot);
for (ExecutionEntity prunedExecution : recyclableExecutionImpls) {
// End the pruned executions if necessary.
// Some recyclable executions are inactivated (joined executions)
// Others are already ended (end activities)
// Need to call the activity end here. If we would do it later,
// the executions are removed and the historic activity instances are
// never ended as the combination of {activityId,executionId} is not valid anymor
Context.getCommandContext().getHistoryManager().recordActivityEnd(prunedExecution);
log.debug("pruning execution {}", prunedExecution);
prunedExecution.remove();
}
log.debug("activating the concurrent root {} as the single path of execution going forward", concurrentRoot);
concurrentRoot.setActive(true);
concurrentRoot.setActivity(activity);
concurrentRoot.setConcurrent(false);
concurrentRoot.take(transitions.get(0), false);
} else {
List<OutgoingExecution> outgoingExecutions = new ArrayList<OutgoingExecution>();
recyclableExecutions.remove(concurrentRoot);
log.debug("recyclable executions for reuse: {}", recyclableExecutions);
// first create the concurrent executions
while (!transitions.isEmpty()) {
PvmTransition outgoingTransition = transitions.remove(0);
ExecutionEntity outgoingExecution = null;
if (recyclableExecutions.isEmpty()) {
outgoingExecution = concurrentRoot.createExecution();
log.debug("new {} with parent {} created to take transition {}", outgoingExecution, outgoingExecution.getParent(), outgoingTransition);
} else {
outgoingExecution = (ExecutionEntity) recyclableExecutions.remove(0);
log.debug("recycled {} to take transition {}", outgoingExecution, outgoingTransition);
}
outgoingExecution.setActive(true);
outgoingExecution.setScope(false);
outgoingExecution.setConcurrent(true);
outgoingExecution.setTransitionBeingTaken((TransitionImpl) outgoingTransition);
outgoingExecutions.add(new OutgoingExecution(outgoingExecution, outgoingTransition, true));
}
// prune the executions that are not recycled
for (ActivityExecution prunedExecution : recyclableExecutions) {
log.debug("pruning execution {}", prunedExecution);
prunedExecution.end();
}
// then launch all the concurrent executions
for (OutgoingExecution outgoingExecution : outgoingExecutions) {
outgoingExecution.take(false);
}
}
}
use of org.activiti.engine.impl.pvm.PvmTransition in project Activiti by Activiti.
the class BpmnActivityBehavior method performOutgoingBehavior.
/**
* Actual implementation of leaving an activity.
*
* @param execution
* The current execution context
* @param checkConditions
* Whether or not to check conditions before determining whether or
* not to take a transition.
* @param throwExceptionIfExecutionStuck
* If true, an {@link ActivitiException} will be thrown in case no
* transition could be found to leave the activity.
*/
protected void performOutgoingBehavior(ActivityExecution execution, boolean checkConditions, boolean throwExceptionIfExecutionStuck, List<ActivityExecution> reusableExecutions) {
if (log.isDebugEnabled()) {
log.debug("Leaving activity '{}'", execution.getActivity().getId());
}
String defaultSequenceFlow = (String) execution.getActivity().getProperty("default");
List<PvmTransition> transitionsToTake = new ArrayList<PvmTransition>();
List<PvmTransition> outgoingTransitions = execution.getActivity().getOutgoingTransitions();
for (PvmTransition outgoingTransition : outgoingTransitions) {
Expression skipExpression = outgoingTransition.getSkipExpression();
if (!SkipExpressionUtil.isSkipExpressionEnabled(execution, skipExpression)) {
if (defaultSequenceFlow == null || !outgoingTransition.getId().equals(defaultSequenceFlow)) {
Condition condition = (Condition) outgoingTransition.getProperty(BpmnParse.PROPERTYNAME_CONDITION);
if (condition == null || !checkConditions || condition.evaluate(outgoingTransition.getId(), execution)) {
transitionsToTake.add(outgoingTransition);
}
}
} else if (SkipExpressionUtil.shouldSkipFlowElement(execution, skipExpression)) {
transitionsToTake.add(outgoingTransition);
}
}
if (transitionsToTake.size() == 1) {
execution.take(transitionsToTake.get(0));
} else if (transitionsToTake.size() >= 1) {
execution.inactivate();
if (reusableExecutions == null || reusableExecutions.isEmpty()) {
execution.takeAll(transitionsToTake, Arrays.asList(execution));
} else {
execution.takeAll(transitionsToTake, reusableExecutions);
}
} else {
if (defaultSequenceFlow != null) {
PvmTransition defaultTransition = execution.getActivity().findOutgoingTransition(defaultSequenceFlow);
if (defaultTransition != null) {
execution.take(defaultTransition);
} else {
throw new ActivitiException("Default sequence flow '" + defaultSequenceFlow + "' could not be not found");
}
} else {
Object isForCompensation = execution.getActivity().getProperty(BpmnParse.PROPERTYNAME_IS_FOR_COMPENSATION);
if (isForCompensation != null && (Boolean) isForCompensation) {
if (execution instanceof ExecutionEntity) {
Context.getCommandContext().getHistoryManager().recordActivityEnd((ExecutionEntity) execution);
}
InterpretableExecution parentExecution = (InterpretableExecution) execution.getParent();
((InterpretableExecution) execution).remove();
parentExecution.signal("compensationDone", null);
} else {
if (log.isDebugEnabled()) {
log.debug("No outgoing sequence flow found for {}. Ending execution.", execution.getActivity().getId());
}
execution.end();
if (throwExceptionIfExecutionStuck) {
throw new ActivitiException("No outgoing sequence flow of the inclusive gateway '" + execution.getActivity().getId() + "' could be selected for continuing the process");
}
}
}
}
}
use of org.activiti.engine.impl.pvm.PvmTransition in project Activiti by Activiti.
the class InclusiveGatewayActivityBehavior method execute.
public void execute(ActivityExecution execution) throws Exception {
execution.inactivate();
lockConcurrentRoot(execution);
PvmActivity activity = execution.getActivity();
if (!activeConcurrentExecutionsExist(execution)) {
if (log.isDebugEnabled()) {
log.debug("inclusive gateway '{}' activates", activity.getId());
}
List<ActivityExecution> joinedExecutions = execution.findInactiveConcurrentExecutions(activity);
String defaultSequenceFlow = (String) execution.getActivity().getProperty("default");
List<PvmTransition> transitionsToTake = new ArrayList<PvmTransition>();
for (PvmTransition outgoingTransition : execution.getActivity().getOutgoingTransitions()) {
Expression skipExpression = outgoingTransition.getSkipExpression();
if (!SkipExpressionUtil.isSkipExpressionEnabled(execution, skipExpression)) {
if (defaultSequenceFlow == null || !outgoingTransition.getId().equals(defaultSequenceFlow)) {
Condition condition = (Condition) outgoingTransition.getProperty(BpmnParse.PROPERTYNAME_CONDITION);
if (condition == null || condition.evaluate(outgoingTransition.getId(), execution)) {
transitionsToTake.add(outgoingTransition);
}
}
} else if (SkipExpressionUtil.shouldSkipFlowElement(execution, skipExpression)) {
transitionsToTake.add(outgoingTransition);
}
}
if (!transitionsToTake.isEmpty()) {
execution.takeAll(transitionsToTake, joinedExecutions);
} else {
if (defaultSequenceFlow != null) {
PvmTransition defaultTransition = execution.getActivity().findOutgoingTransition(defaultSequenceFlow);
if (defaultTransition != null) {
transitionsToTake.add(defaultTransition);
execution.takeAll(transitionsToTake, joinedExecutions);
} else {
throw new ActivitiException("Default sequence flow '" + defaultSequenceFlow + "' could not be not found");
}
} else {
// No sequence flow could be found, not even a default one
throw new ActivitiException("No outgoing sequence flow of the inclusive gateway '" + execution.getActivity().getId() + "' could be selected for continuing the process");
}
}
} else {
if (log.isDebugEnabled()) {
log.debug("Inclusive gateway '{}' does not activate", activity.getId());
}
}
}
use of org.activiti.engine.impl.pvm.PvmTransition in project Activiti by Activiti.
the class InclusiveGatewayActivityBehavior method isReachable.
protected boolean isReachable(PvmActivity srcActivity, PvmActivity targetActivity, Set<PvmActivity> visitedActivities) {
// if source has no outputs, it is the end of the process, and its parent process should be checked.
if (srcActivity.getOutgoingTransitions().isEmpty()) {
visitedActivities.add(srcActivity);
if (!(srcActivity.getParent() instanceof PvmActivity)) {
return false;
}
srcActivity = (PvmActivity) srcActivity.getParent();
}
if (srcActivity.equals(targetActivity)) {
return true;
}
// To avoid infinite looping, we must capture every node we visit
// and check before going further in the graph if we have already visitied
// the node.
visitedActivities.add(srcActivity);
List<PvmTransition> transitionList = srcActivity.getOutgoingTransitions();
if (transitionList != null && !transitionList.isEmpty()) {
for (PvmTransition pvmTransition : transitionList) {
PvmActivity destinationActivity = pvmTransition.getDestination();
if (destinationActivity != null && !visitedActivities.contains(destinationActivity)) {
boolean reachable = isReachable(destinationActivity, targetActivity, visitedActivities);
// result
if (reachable) {
return true;
}
}
}
}
return false;
}
use of org.activiti.engine.impl.pvm.PvmTransition in project Activiti by Activiti.
the class BaseProcessDefinitionDiagramLayoutResource method getActivity.
private void getActivity(String processInstanceId, ActivityImpl activity, ArrayNode activityArray, ArrayNode sequenceFlowArray, ProcessInstance processInstance, List<String> highLightedFlows, Map<String, ObjectNode> subProcessInstanceMap) {
ObjectNode activityJSON = new ObjectMapper().createObjectNode();
// Gather info on the multi instance marker
String multiInstance = (String) activity.getProperty("multiInstance");
if (multiInstance != null) {
if (!"sequential".equals(multiInstance)) {
multiInstance = "parallel";
}
}
ActivityBehavior activityBehavior = activity.getActivityBehavior();
// Gather info on the collapsed marker
Boolean collapsed = (activityBehavior instanceof CallActivityBehavior);
Boolean expanded = (Boolean) activity.getProperty(BpmnParse.PROPERTYNAME_ISEXPANDED);
if (expanded != null) {
collapsed = !expanded;
}
Boolean isInterrupting = null;
if (activityBehavior instanceof BoundaryEventActivityBehavior) {
isInterrupting = ((BoundaryEventActivityBehavior) activityBehavior).isInterrupting();
}
// Outgoing transitions of activity
for (PvmTransition sequenceFlow : activity.getOutgoingTransitions()) {
String flowName = (String) sequenceFlow.getProperty("name");
boolean isHighLighted = (highLightedFlows.contains(sequenceFlow.getId()));
boolean isConditional = sequenceFlow.getProperty(BpmnParse.PROPERTYNAME_CONDITION) != null && !((String) activity.getProperty("type")).toLowerCase().contains("gateway");
boolean isDefault = sequenceFlow.getId().equals(activity.getProperty("default")) && ((String) activity.getProperty("type")).toLowerCase().contains("gateway");
List<Integer> waypoints = ((TransitionImpl) sequenceFlow).getWaypoints();
ArrayNode xPointArray = new ObjectMapper().createArrayNode();
ArrayNode yPointArray = new ObjectMapper().createArrayNode();
for (int i = 0; i < waypoints.size(); i += 2) {
// waypoints.size()
// minimally 4: x1, y1,
// x2, y2
xPointArray.add(waypoints.get(i));
yPointArray.add(waypoints.get(i + 1));
}
ObjectNode flowJSON = new ObjectMapper().createObjectNode();
flowJSON.put("id", sequenceFlow.getId());
flowJSON.put("name", flowName);
flowJSON.put("flow", "(" + sequenceFlow.getSource().getId() + ")--" + sequenceFlow.getId() + "-->(" + sequenceFlow.getDestination().getId() + ")");
if (isConditional)
flowJSON.put("isConditional", isConditional);
if (isDefault)
flowJSON.put("isDefault", isDefault);
if (isHighLighted)
flowJSON.put("isHighLighted", isHighLighted);
flowJSON.put("xPointArray", xPointArray);
flowJSON.put("yPointArray", yPointArray);
sequenceFlowArray.add(flowJSON);
}
// Nested activities (boundary events)
ArrayNode nestedActivityArray = new ObjectMapper().createArrayNode();
for (ActivityImpl nestedActivity : activity.getActivities()) {
nestedActivityArray.add(nestedActivity.getId());
}
Map<String, Object> properties = activity.getProperties();
ObjectNode propertiesJSON = new ObjectMapper().createObjectNode();
for (String key : properties.keySet()) {
Object prop = properties.get(key);
if (prop instanceof String)
propertiesJSON.put(key, (String) properties.get(key));
else if (prop instanceof Integer)
propertiesJSON.put(key, (Integer) properties.get(key));
else if (prop instanceof Boolean)
propertiesJSON.put(key, (Boolean) properties.get(key));
else if ("initial".equals(key)) {
ActivityImpl act = (ActivityImpl) properties.get(key);
propertiesJSON.put(key, act.getId());
} else if ("timerDeclarations".equals(key)) {
ArrayList<TimerDeclarationImpl> timerDeclarations = (ArrayList<TimerDeclarationImpl>) properties.get(key);
ArrayNode timerDeclarationArray = new ObjectMapper().createArrayNode();
if (timerDeclarations != null)
for (TimerDeclarationImpl timerDeclaration : timerDeclarations) {
ObjectNode timerDeclarationJSON = new ObjectMapper().createObjectNode();
timerDeclarationJSON.put("isExclusive", timerDeclaration.isExclusive());
if (timerDeclaration.getRepeat() != null)
timerDeclarationJSON.put("repeat", timerDeclaration.getRepeat());
timerDeclarationJSON.put("retries", String.valueOf(timerDeclaration.getRetries()));
timerDeclarationJSON.put("type", timerDeclaration.getJobHandlerType());
timerDeclarationJSON.put("configuration", timerDeclaration.getJobHandlerConfiguration());
//timerDeclarationJSON.put("expression", timerDeclaration.getDescription());
timerDeclarationArray.add(timerDeclarationJSON);
}
if (timerDeclarationArray.size() > 0)
propertiesJSON.put(key, timerDeclarationArray);
// TODO: implement getting description
} else if ("eventDefinitions".equals(key)) {
ArrayList<EventSubscriptionDeclaration> eventDefinitions = (ArrayList<EventSubscriptionDeclaration>) properties.get(key);
ArrayNode eventDefinitionsArray = new ObjectMapper().createArrayNode();
if (eventDefinitions != null) {
for (EventSubscriptionDeclaration eventDefinition : eventDefinitions) {
ObjectNode eventDefinitionJSON = new ObjectMapper().createObjectNode();
if (eventDefinition.getActivityId() != null)
eventDefinitionJSON.put("activityId", eventDefinition.getActivityId());
eventDefinitionJSON.put("eventName", eventDefinition.getEventName());
eventDefinitionJSON.put("eventType", eventDefinition.getEventType());
eventDefinitionJSON.put("isAsync", eventDefinition.isAsync());
eventDefinitionJSON.put("isStartEvent", eventDefinition.isStartEvent());
eventDefinitionsArray.add(eventDefinitionJSON);
}
}
if (eventDefinitionsArray.size() > 0)
propertiesJSON.put(key, eventDefinitionsArray);
// TODO: implement it
} else if ("errorEventDefinitions".equals(key)) {
ArrayList<ErrorEventDefinition> errorEventDefinitions = (ArrayList<ErrorEventDefinition>) properties.get(key);
ArrayNode errorEventDefinitionsArray = new ObjectMapper().createArrayNode();
if (errorEventDefinitions != null) {
for (ErrorEventDefinition errorEventDefinition : errorEventDefinitions) {
ObjectNode errorEventDefinitionJSON = new ObjectMapper().createObjectNode();
if (errorEventDefinition.getErrorCode() != null)
errorEventDefinitionJSON.put("errorCode", errorEventDefinition.getErrorCode());
else
errorEventDefinitionJSON.putNull("errorCode");
errorEventDefinitionJSON.put("handlerActivityId", errorEventDefinition.getHandlerActivityId());
errorEventDefinitionsArray.add(errorEventDefinitionJSON);
}
}
if (errorEventDefinitionsArray.size() > 0)
propertiesJSON.put(key, errorEventDefinitionsArray);
}
}
if ("callActivity".equals(properties.get("type"))) {
CallActivityBehavior callActivityBehavior = null;
if (activityBehavior instanceof CallActivityBehavior) {
callActivityBehavior = (CallActivityBehavior) activityBehavior;
}
if (callActivityBehavior != null) {
propertiesJSON.put("processDefinitonKey", callActivityBehavior.getProcessDefinitonKey());
// get processDefinitonId from execution or get last processDefinitonId
// by key
ArrayNode processInstanceArray = new ObjectMapper().createArrayNode();
if (processInstance != null) {
List<Execution> executionList = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).activityId(activity.getId()).list();
if (!executionList.isEmpty()) {
for (Execution execution : executionList) {
ObjectNode processInstanceJSON = subProcessInstanceMap.get(execution.getId());
processInstanceArray.add(processInstanceJSON);
}
}
}
// last definition
if (processInstanceArray.size() == 0 && StringUtils.isNotEmpty(callActivityBehavior.getProcessDefinitonKey())) {
// Get last definition by key
ProcessDefinition lastProcessDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(callActivityBehavior.getProcessDefinitonKey()).latestVersion().singleResult();
// TODO: unuseful fields there are processDefinitionName, processDefinitionKey
if (lastProcessDefinition != null) {
ObjectNode processInstanceJSON = new ObjectMapper().createObjectNode();
processInstanceJSON.put("processDefinitionId", lastProcessDefinition.getId());
processInstanceJSON.put("processDefinitionKey", lastProcessDefinition.getKey());
processInstanceJSON.put("processDefinitionName", lastProcessDefinition.getName());
processInstanceArray.add(processInstanceJSON);
}
}
if (processInstanceArray.size() > 0) {
propertiesJSON.put("processDefinitons", processInstanceArray);
}
}
}
activityJSON.put("activityId", activity.getId());
activityJSON.put("properties", propertiesJSON);
if (multiInstance != null)
activityJSON.put("multiInstance", multiInstance);
if (collapsed)
activityJSON.put("collapsed", collapsed);
if (nestedActivityArray.size() > 0)
activityJSON.put("nestedActivities", nestedActivityArray);
if (isInterrupting != null)
activityJSON.put("isInterrupting", isInterrupting);
activityJSON.put("x", activity.getX());
activityJSON.put("y", activity.getY());
activityJSON.put("width", activity.getWidth());
activityJSON.put("height", activity.getHeight());
activityArray.add(activityJSON);
// Nested activities (boundary events)
for (ActivityImpl nestedActivity : activity.getActivities()) {
getActivity(processInstanceId, nestedActivity, activityArray, sequenceFlowArray, processInstance, highLightedFlows, subProcessInstanceMap);
}
}
Aggregations