All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yaoqiang.bpmn.engine.operation.FlowNodeExecute Maven / Gradle / Ivy

package org.yaoqiang.bpmn.engine.operation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import org.yaoqiang.bpmn.engine.runtime.Execution;
import org.yaoqiang.bpmn.model.elements.activities.Activity;
import org.yaoqiang.bpmn.model.elements.activities.SubProcess;
import org.yaoqiang.bpmn.model.elements.core.common.FlowNode;
import org.yaoqiang.bpmn.model.elements.core.common.SequenceFlow;
import org.yaoqiang.bpmn.model.elements.events.BoundaryEvent;
import org.yaoqiang.bpmn.model.elements.gateways.ExclusiveGateway;
import org.yaoqiang.bpmn.model.elements.gateways.Gateway;
import org.yaoqiang.bpmn.model.elements.gateways.InclusiveGateway;
import org.yaoqiang.bpmn.model.elements.gateways.ParallelGateway;

/**
 * FlowNodeExecute
 * 
 * @author Shi Yaoqiang([email protected])
 */
public class FlowNodeExecute implements ExecutionOperation {

	private static Logger log = Logger.getLogger(FlowNodeExecute.class.getName());

	public void execute(Execution execution) {
		FlowNode flowNode = execution.getFlowNode();

		if (flowNode instanceof Gateway) {
			if (flowNode instanceof ParallelGateway) {
				executeParallelGateway(execution);
			} else if (flowNode instanceof ExclusiveGateway) {
				executeExclusiveGateway(execution);
			} else if (flowNode instanceof InclusiveGateway) {
				executeInclusiveGateway(execution);
			}
		} else if (flowNode instanceof Activity) {
			Set events = ((Activity) flowNode).getBoundaryEventRefs();
			boolean fireEvent = false;
			if (events != null) {
				for (BoundaryEvent event : events) {
					if (Math.random() > 0.5) {
						fireEvent = true;
						execution.executeFlowNode(event);
					}
				}
			}
			if (!fireEvent) {
				if (flowNode instanceof SubProcess) {
					executeSubProcess(execution);
				} else {
					executeFlowNode(execution);
				}
			}
		} else {
			executeFlowNode(execution);
		}
	}

	private void executeParallelGateway(Execution execution) {
		FlowNode flowNode = execution.getFlowNode();
		List outgoingSequenceFlows = flowNode.getOutgoingSequenceFlows();

		execution.inactivate();

		List joinedExecutions = execution.findInactiveConcurrentExecutions(flowNode);

		int nbrOfExecutionsToJoin = flowNode.getIncomingSequenceFlows().size();
		int nbrOfExecutionsJoined = joinedExecutions.size();

		if (nbrOfExecutionsJoined == nbrOfExecutionsToJoin) {
			log.fine("Parallel gateway '" + flowNode.getName() + "' activates: " + nbrOfExecutionsJoined + " of " + nbrOfExecutionsToJoin + " joined");
			execution.takeAll(outgoingSequenceFlows, joinedExecutions);
		} else {
			log.fine("Parallel gateway '" + flowNode.getName() + "' does not activate: " + nbrOfExecutionsJoined + " of " + nbrOfExecutionsToJoin + " joined");
		}
	}

	private void executeExclusiveGateway(Execution execution) {
		FlowNode flowNode = execution.getFlowNode();
		log.fine("Leaving Exclusive gateway '" + flowNode.getName() + "'");
		SequenceFlow defaultSequenceFlow = ((ExclusiveGateway) flowNode).getDefaultSequenceFlow();

		int randomFlow = (int) Math.floor(Math.random() * flowNode.getOutgoingSequenceFlows().size());
		SequenceFlow outgoingSequenceFlow = flowNode.getOutgoingSequenceFlows().get(randomFlow);
		if (outgoingSequenceFlow == defaultSequenceFlow) {
			log.fine("Default Sequence flow '" + outgoingSequenceFlow.getId() + " '" + "selected as outgoing sequence flow.");
		} else {
			log.fine("Sequence flow '" + outgoingSequenceFlow.getId() + " '" + "selected as outgoing sequence flow.");
			execution.take(outgoingSequenceFlow);
		}
	}

	private void executeInclusiveGateway(Execution execution) {
		FlowNode flowNode = execution.getFlowNode();
		if (!activeConcurrentExecutionsExist(execution)) {
			log.fine("Inclusive gateway '" + flowNode.getName() + "' activates");
			SequenceFlow defaultSequenceFlow = ((InclusiveGateway) flowNode).getDefaultSequenceFlow();

			List joinedExecutions = execution.findInactiveConcurrentExecutions(flowNode);
			List sequenceFlowToTake = new ArrayList();

			for (SequenceFlow outgoingSequenceFlow : flowNode.getOutgoingSequenceFlows()) {
				if (outgoingSequenceFlow != defaultSequenceFlow && Math.random() > 0.5) {
					sequenceFlowToTake.add(outgoingSequenceFlow);
				}
			}

			if (sequenceFlowToTake.size() > 0) {
				execution.takeAll(sequenceFlowToTake, joinedExecutions);
			} else if (defaultSequenceFlow != null) {
				execution.take(defaultSequenceFlow);
			} else {
				execution.take(flowNode.getOutgoingSequenceFlows().get(0));
			}
		} else {
			log.fine("Inclusive gateway '" + flowNode.getName() + "' does not activate");
		}
	}

	private void executeSubProcess(Execution execution) {
		FlowNode flowNode = execution.getFlowNode();
		List startFlowNodes = new ArrayList();
		for (FlowNode node : ((SubProcess) flowNode).getFlowNodes()) {
			if (node.getIncomingSequenceFlows().isEmpty()) {
				startFlowNodes.add(node);
			}
		}
		if (startFlowNodes.isEmpty()) {
			executeFlowNode(execution);
		} else {
			for (FlowNode startFlowNode : startFlowNodes) {
				execution.executeFlowNode(startFlowNode);
			}
		}
	}

	private void executeFlowNode(Execution execution) {
		FlowNode flowNode = execution.getFlowNode();
		List outgoingSequenceFlows = flowNode.getOutgoingSequenceFlows();
		if (outgoingSequenceFlows.isEmpty()) {
			execution.end();
		} else {
			List sequenceFlowToTake = new ArrayList();
			SequenceFlow defaultSequenceFlow = null;
			if (flowNode instanceof Activity) {
				defaultSequenceFlow = ((Activity) flowNode).getDefaultSequenceFlow();
			}
			for (SequenceFlow outgoingSequenceFlow : flowNode.getOutgoingSequenceFlows()) {
				if (outgoingSequenceFlow != defaultSequenceFlow && Math.random() > 0.5) {
					sequenceFlowToTake.add(outgoingSequenceFlow);
				}
			}

			if (sequenceFlowToTake.size() > 0) {
				execution.takeAll(sequenceFlowToTake, Collections. emptyList());
			} else if (defaultSequenceFlow != null) {
				execution.take(defaultSequenceFlow);
			} else {
				execution.take(flowNode.getOutgoingSequenceFlows().get(0));
			}
		}
	}

	private boolean activeConcurrentExecutionsExist(Execution execution) {
		FlowNode flowNode = execution.getFlowNode();
		if (execution.isConcurrent()) {
			for (Execution concurrentExecution : execution.getParent().getExecutions()) {
				if (concurrentExecution.isActive() && concurrentExecution.getFlowNode() != flowNode) {

					// TODO: when is transitionBeingTaken cleared? Should we clear it?
					boolean reachable = false;
					SequenceFlow sequenceFlow = concurrentExecution.getSequenceFlow();
					if (sequenceFlow != null) {
						reachable = isReachable(sequenceFlow.getTargetFlowNode(), flowNode, new HashSet());
					} else {
						reachable = isReachable(concurrentExecution.getFlowNode(), flowNode, new HashSet());
					}

					if (reachable) {
						log.fine("an active concurrent execution found: '" + concurrentExecution.getFlowNode());
						return true;
					}
				}
			}
		}

		return false;
	}

	private boolean isReachable(FlowNode srcFlowNode, FlowNode targetFlowNode, Set visitedFlowNodes) {

		if (srcFlowNode.equals(targetFlowNode)) {
			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.
		visitedFlowNodes.add(srcFlowNode);

		List transitionList = srcFlowNode.getOutgoingSequenceFlows();
		if (transitionList != null && transitionList.size() > 0) {
			for (SequenceFlow pvmTransition : transitionList) {
				FlowNode destinationActivity = pvmTransition.getTargetFlowNode();
				if (destinationActivity != null && !visitedFlowNodes.contains(destinationActivity)) {
					boolean reachable = isReachable(destinationActivity, targetFlowNode, visitedFlowNodes);

					// If false, we should investigate other paths, and not yet return the result
					if (reachable) {
						return true;
					}

				}
			}
		}
		return false;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy