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

de.viadee.bpm.vPAV.processing.ElementGraphBuilder Maven / Gradle / Ivy

Go to download

The tool checks Camunda projects for consistency and discovers errors in process-driven applications. Called as a Maven plugin or JUnit test, it discovers esp. inconsistencies of a given BPMN model in the classpath and the sourcecode of an underlying java project, such as a delegate reference to a non-existing java class or a non-existing Spring bean.

There is a newer version: 3.0.8
Show newest version
/**
 * BSD 3-Clause License
 *
 * Copyright © 2019, viadee Unternehmensberatung AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package de.viadee.bpm.vPAV.processing;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import de.viadee.bpm.vPAV.BpmnScanner;
import de.viadee.bpm.vPAV.FileScanner;
import de.viadee.bpm.vPAV.config.model.Rule;
import de.viadee.bpm.vPAV.constants.BpmnConstants;
import de.viadee.bpm.vPAV.processing.code.flow.BpmnElement;
import de.viadee.bpm.vPAV.processing.code.flow.ControlFlowGraph;
import de.viadee.bpm.vPAV.processing.model.data.AnomalyContainer;
import de.viadee.bpm.vPAV.processing.model.data.ProcessVariableOperation;
import de.viadee.bpm.vPAV.processing.model.graph.Edge;
import de.viadee.bpm.vPAV.processing.model.graph.Graph;
import de.viadee.bpm.vPAV.processing.model.graph.Path;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.*;
import org.camunda.bpm.model.bpmn.instance.Process;
import org.camunda.bpm.model.bpmn.instance.camunda.CamundaIn;
import org.camunda.bpm.model.bpmn.instance.camunda.CamundaOut;

import java.io.File;
import java.util.*;

/**
 * Creates data flow graph based on a bpmn model
 *
 */
public class ElementGraphBuilder {

	private Map elementMap = new HashMap<>();

	private Map processIdToPathMap;

	private Map decisionRefToPathMap;

	private Map> messageIdToVariables;

	private Map> processIdToVariables;

	private BpmnScanner bpmnScanner;

	private Rule rule;

	public ElementGraphBuilder(BpmnScanner bpmnScanner) {
		this.bpmnScanner = bpmnScanner;
	}

	public ElementGraphBuilder(BpmnScanner bpmnScanner, final Rule rule) {
		this.bpmnScanner = bpmnScanner;
		this.rule = rule;
	}

	public ElementGraphBuilder(final Map decisionRefToPathMap,
			final Map processIdToPathMap, final Map> messageIdToVariables,
			final Map> processIdToVariables, final Rule rule, BpmnScanner bpmnScanner) {
		this.decisionRefToPathMap = decisionRefToPathMap;
		this.processIdToPathMap = processIdToPathMap;
		this.messageIdToVariables = messageIdToVariables;
		this.processIdToVariables = processIdToVariables;
		this.bpmnScanner = bpmnScanner;
		this.rule = rule;
	}

	public ElementGraphBuilder(final Map decisionRefToPathMap,
			final Map processIdToPathMap, final Map> messageIdToVariables,
			final Map> processIdToVariables, BpmnScanner bpmnScanner) {
		this.decisionRefToPathMap = decisionRefToPathMap;
		this.processIdToPathMap = processIdToPathMap;
		this.messageIdToVariables = messageIdToVariables;
		this.processIdToVariables = processIdToVariables;
		this.bpmnScanner = bpmnScanner;
	}

	public ElementGraphBuilder(final Map decisionRefToPathMap,
			final Map processIdToPathMap, BpmnScanner bpmnScanner) {
		this.decisionRefToPathMap = decisionRefToPathMap;
		this.processIdToPathMap = processIdToPathMap;
		this.bpmnScanner = bpmnScanner;
	}

	/**
	 * Create data flow graphs for a model
	 *
	 * @param fileScanner
	 *            FileScanner
	 * @param modelInstance
	 *            BpmnModelInstance
	 * @param processDefinition
	 *            processDefinition
	 * @param calledElementHierarchy
	 *            calledElementHierarchy
	 * @param scanner
	 *            OuterProcessVariablesScanner
	 * @return graphCollection returns graphCollection
	 */
	public Collection createProcessGraph(final FileScanner fileScanner, final BpmnModelInstance modelInstance,
			final String processDefinition, final Collection calledElementHierarchy,
			final ProcessVariablesScanner scanner) {

		final Collection graphCollection = new ArrayList<>();

		final Collection processes = modelInstance.getModelElementsByType(Process.class);
		for (final Process process : processes) {
			final Graph graph = new Graph(process.getId());
			final Collection elements = process.getFlowElements();
			final Collection flows = new ArrayList<>();
			final Collection boundaryEvents = new ArrayList<>();
			final Collection subProcesses = new ArrayList<>();
			final Collection callActivities = new ArrayList<>();

			for (final FlowElement element : elements) {

				final ControlFlowGraph controlFlowGraph = new ControlFlowGraph();
				// initialize element
				final BpmnElement node = new BpmnElement(processDefinition, element, controlFlowGraph);

				if (element instanceof SequenceFlow) {
					// mention sequence flows
					final SequenceFlow flow = (SequenceFlow) element;
					flows.add(flow);
				} else if (element instanceof BoundaryEvent) {
					// mention boundary events
					final BoundaryEvent event = (BoundaryEvent) element;
					boundaryEvents.add(event);
				} else if (element instanceof CallActivity) {
					// mention call activities
					final CallActivity callActivity = (CallActivity) element;
					callActivities.add(callActivity);
				} else if (element instanceof SubProcess) {
					final SubProcess subprocess = (SubProcess) element;
					addElementsSubprocess(fileScanner, subProcesses, flows, boundaryEvents, graph, subprocess,
							processDefinition, controlFlowGraph);
				}

				// Ordered map to hold operations in correct order
				final ListMultimap variables = ArrayListMultimap.create();

				// retrieve initial variable operation (should be WRITE)
				if (element.getElementType().getTypeName().equals(BpmnConstants.START_EVENT)) {
					final ArrayList messageRefs = bpmnScanner.getMessageRefs(element.getId());
					String messageName = "";
					if (messageRefs.size() == 1) {
						messageName = bpmnScanner.getMessageName(messageRefs.get(0));
					}
					// add process variables for start event, which set by call
					// startProcessInstanceByKey

					for (EntryPoint ep : scanner.getEntryPoints()) {
						if (ep.getMessageName().equals(messageName)) {
							variables.putAll(checkInitialVariableOperations(ep, node, processDefinition));
						}
					}
					graph.addStartNode(node);
				}

				if (element.getElementType().getTypeName().equals(BpmnConstants.RECEIVE_TASK)) {
					final ArrayList messageRefs = bpmnScanner.getMessageRefs(element.getId());
					String messageName = "";
					if (messageRefs.size() == 1) {
						messageName = bpmnScanner.getMessageName(messageRefs.get(0));
					}
					// add process variables for receive task, which set by call
					// startProcessInstanceByKey

					for (EntryPoint ep : scanner.getIntermediateEntryPoints()) {
						if (ep.getMessageName().equals(messageName)) {
							variables.putAll(checkInitialVariableOperations(ep, node, processDefinition));
						}
					}
				}

				// examine process variables and save it with access operation
				final ProcessVariableReader reader = new ProcessVariableReader(decisionRefToPathMap, rule, bpmnScanner);
				variables.putAll(reader.getVariablesFromElement(fileScanner, node, controlFlowGraph));
				// examine process variables for element and set it
				node.setProcessVariables(variables);

				// mention element
				elementMap.put(element.getId(), node);

				if (element.getElementType().getTypeName().equals(BpmnConstants.END_EVENT)) {
					graph.addEndNode(node);
				}
				// save process elements as a node
				graph.addVertex(node);
			}
			// add edges into the graph
			addEdges(graph, flows, boundaryEvents, subProcesses);

			// resolve call activities and integrate called processes
			for (final CallActivity callActivity : callActivities) {
				ControlFlowGraph controlFlowGraph = new ControlFlowGraph();
				integrateCallActivityFlow(fileScanner, processDefinition, modelInstance, callActivity, graph,
						calledElementHierarchy, scanner, controlFlowGraph);
			}

			graphCollection.add(graph);
		}

		return graphCollection;
	}

	/**
	 *
	 * Checks for initial variable operations (esp. initializations of variables)
	 *
	 * @param entryPoint
	 *            Current entryPoint (most likely rest controller classes)
	 * @param element
	 *            Current BPMN element
	 * @param resourceFilePath
	 *            Current BPMN location
	 * @return initial operations
	 */
	private ListMultimap checkInitialVariableOperations(final EntryPoint entryPoint,
																						  final BpmnElement element, final String resourceFilePath) {
		return new JavaReaderStatic().getVariablesFromClass(entryPoint.getClassName(), element,
				resourceFilePath, entryPoint);
	}

	public BpmnElement getElement(final String id) {
		return elementMap.get(id);
	}

	/**
	 * Create invalid paths for data flow anomalies
	 *
	 * @param graphCollection
	 *            IGraph
	 * @return invalidPathMap returns invalidPathMap
	 */
	public Map> createInvalidPaths(final Collection graphCollection) {
		final Map> invalidPathMap = new HashMap<>();

		for (final Graph g : graphCollection) {
			// get nodes with data anomalies
			final Map> anomalies = g.getNodesWithAnomalies();

			for (final BpmnElement element : anomalies.keySet()) {
				for (AnomalyContainer anomaly : anomalies.get(element)) {
					// create paths for data flow anomalies
					final List paths = g.getAllInvalidPaths(element, anomaly);
					for (final Path path : paths) {
						// reverse order for a better readability
						Collections.reverse(path.getElements());
					}
					invalidPathMap.put(anomaly, new ArrayList<>(paths));
				}
			}
		}

		return invalidPathMap;
	}

	/**
	 * Add edges to data flow graph
	 *
	 * @param graph
	 *            IGraph
	 * @param flows
	 *            Collection of SequenceFlows
	 * @param boundaryEvents
	 *            Collection of BoundaryEvents
	 * @param subProcesses
	 *            Collection of SubProcesses
	 */
	private void addEdges(final Graph graph, final Collection flows,
			final Collection boundaryEvents, final Collection subProcesses) {
		for (final SequenceFlow flow : flows) {
			final BpmnElement flowElement = elementMap.get(flow.getId());
			final BpmnElement srcElement = elementMap.get(flow.getSource().getId());
			final BpmnElement destElement = elementMap.get(flow.getTarget().getId());

			flowElement.addPredecessor(srcElement);
			flowElement.addSuccessor(destElement);

			graph.addEdge(srcElement, flowElement, 100);
			graph.addEdge(flowElement, destElement, 100);
		}
		for (final BoundaryEvent event : boundaryEvents) {
			final BpmnElement dstElement = elementMap.get(event.getId());
			final Activity source = event.getAttachedTo();
			final BpmnElement srcElement = elementMap.get(source.getId());
			graph.addEdge(srcElement, dstElement, 100);
		}
		for (final SubProcess subProcess : subProcesses) {
			final BpmnElement subprocessElement = elementMap.get(subProcess.getId());
			// integration of a subprocess in data flow graph
			// inner elements will be directly connected into the graph
			final Collection startEvents = subProcess.getChildElementsByType(StartEvent.class);
			final Collection endEvents = subProcess.getChildElementsByType(EndEvent.class);
			if (startEvents != null && startEvents.size() > 0 && endEvents != null && endEvents.size() > 0) {
				final Collection incomingFlows = subProcess.getIncoming();
				for (final SequenceFlow incomingFlow : incomingFlows) {
					final BpmnElement srcElement = elementMap.get(incomingFlow.getId());
					for (final StartEvent startEvent : startEvents) {
						final BpmnElement dstElement = elementMap.get(startEvent.getId());
						graph.addEdge(srcElement, dstElement, 100);
						graph.removeEdge(srcElement, subprocessElement);
					}
				}
				final Collection outgoingFlows = subProcess.getOutgoing();
				for (final EndEvent endEvent : endEvents) {
					final BpmnElement srcElement = elementMap.get(endEvent.getId());
					for (final SequenceFlow outgoingFlow : outgoingFlows) {
						final BpmnElement dstElement = elementMap.get(outgoingFlow.getId());
						graph.addEdge(srcElement, dstElement, 100);
						graph.removeEdge(subprocessElement, dstElement);
					}
				}
			}
		}
	}

	/**
	 * Add elements from subprocess to data flow graph
	 *
	 * @param fileScanner
	 *            FileScanner
	 * @param subProcesses
	 *            Collection of SubProcesses
	 * @param flows
	 *            Collection of SequenceFlows
	 * @param events
	 *            Collection of BoundaryEvents
	 * @param graph
	 *            Current Graph
	 * @param process
	 *            Current Process
	 * @param processDefinition
	 *            Current Path to process
	 */
	private void addElementsSubprocess(final FileScanner fileScanner, final Collection subProcesses,
			final Collection flows, final Collection events, final Graph graph,
			final SubProcess process, final String processDefinition, final ControlFlowGraph controlFlowGraph) {
		subProcesses.add(process);
		final Collection subElements = process.getFlowElements();
		for (final FlowElement subElement : subElements) {
			if (subElement instanceof SubProcess) {
				final SubProcess subProcess = (SubProcess) subElement;
				addElementsSubprocess(fileScanner, subProcesses, flows, events, graph, subProcess, processDefinition,
						controlFlowGraph);
			} else if (subElement instanceof SequenceFlow) {
				final SequenceFlow flow = (SequenceFlow) subElement;
				flows.add(flow);
			} else if (subElement instanceof BoundaryEvent) {
				final BoundaryEvent boundaryEvent = (BoundaryEvent) subElement;
				events.add(boundaryEvent);
			}
			// add elements of the sub process as nodes
			final BpmnElement node = new BpmnElement(processDefinition, subElement, controlFlowGraph);
			// determine process variables with operations
			final ListMultimap variables = ArrayListMultimap.create();
			variables.putAll(new ProcessVariableReader(decisionRefToPathMap, rule, bpmnScanner)
					.getVariablesFromElement(fileScanner, node, controlFlowGraph));
			// set process variables for the node
			node.setProcessVariables(variables);
			// mention the element
			elementMap.put(subElement.getId(), node);
			// add element as node
			graph.addVertex(node);
		}
	}

	/**
	 * Integrate a called activity into data flow graph
	 *
	 * @param fileScanner
	 *            FileScanner
	 * @param processdefinition
	 *            Current Path to process
	 * @param modelInstance
	 *            BpmnModelInstance
	 * @param callActivity
	 *            CallActivity
	 * @param graph
	 *            Current Graph
	 * @param calledElementHierarchy
	 *            Collection of Element Hierarchy
	 * @param scanner
	 *            OuterProcessVariableScanner
	 */
	private void integrateCallActivityFlow(final FileScanner fileScanner, final String processdefinition,
			final BpmnModelInstance modelInstance, final CallActivity callActivity, final Graph graph,
			final Collection calledElementHierarchy, final ProcessVariablesScanner scanner,
			final ControlFlowGraph controlFlowGraph) {

		final String calledElement = callActivity.getCalledElement();

		// check call hierarchy to avoid deadlocks
		if (calledElementHierarchy.contains(calledElement)) {
			throw new RuntimeException("call activity hierarchy causes a deadlock (see " + processdefinition + ", "
					+ callActivity.getId() + "). please avoid loops.");
		}
		calledElementHierarchy.add(calledElement);

		// integrate only, if file locations for process ids are known
		if (processIdToPathMap != null && processIdToPathMap.get(calledElement) != null) {

			// 1) read in- and output variables from call activity
			final Collection inVariables = new ArrayList<>();
			final Collection outVariables = new ArrayList<>();
			readCallActivityDataInterfaces(callActivity, inVariables, outVariables);

			// 2) add parallel gateways before and after the call activity in the main data
			// flow
			// They are necessary for connecting the sub process with the main flow
			final List parallelGateways = addParallelGatewaysBeforeAndAfterCallActivityInMainDataFlow(
					modelInstance, callActivity, graph, controlFlowGraph);
			final BpmnElement parallelGateway1 = parallelGateways.get(0);
			final BpmnElement parallelGateway2 = parallelGateways.get(1);

			// get file path of the called process
			final String callActivityPath = processIdToPathMap.get(calledElement);
			if (callActivityPath != null) {
				// 3) load process and transform it into a data flow graph
				final Collection subgraphs = createSubDataFlowsFromCallActivity(fileScanner,
						calledElementHierarchy, callActivityPath, scanner);

				for (final Graph subgraph : subgraphs) {
					// look only on the called process!
					if (subgraph.getProcessId().equals(calledElement)) {
						// 4) connect sub data flow with the main data flow
						connectParallelGatewaysWithSubDataFlow(graph, inVariables, outVariables, parallelGateway1,
								parallelGateway2, subgraph);
					}
				}
			}
		}
	}

	/**
	 * Add parallel gateways before and after a call activity. They are needed to
	 * connect the called process with the main flow
	 *
	 * @param modelInstance
	 *            BpmnModelInstance
	 * @param callActivity
	 *            CallActivity
	 * @param graph
	 *            Current Graph
	 * @return parallel gateway elements
	 */
	private List addParallelGatewaysBeforeAndAfterCallActivityInMainDataFlow(
			final BpmnModelInstance modelInstance, final CallActivity callActivity, final Graph graph,
			final ControlFlowGraph controlFlowGraph) {

		final ParallelGateway element1 = modelInstance.newInstance(ParallelGateway.class);
		element1.setAttributeValue(BpmnConstants.ATTR_ID, "_gw_in", true);

		final ParallelGateway element2 = modelInstance.newInstance(ParallelGateway.class);
		element2.setAttributeValue(BpmnConstants.ATTR_ID, "_gw_out", true);

		final List elements = new ArrayList<>();
		final BpmnElement parallelGateway1 = new BpmnElement(null, element1, controlFlowGraph);
		final BpmnElement parallelGateway2 = new BpmnElement(null, element2, controlFlowGraph);
		elements.add(parallelGateway1);
		elements.add(parallelGateway2);

		graph.addVertex(parallelGateway1);
		graph.addVertex(parallelGateway2);

		connectParallelGatewaysWithMainDataFlow(callActivity, graph, parallelGateway1, parallelGateway2);

		return elements;
	}

	/**
	 * Connect the parallel gateways in the data flow before and after the call
	 * activity
	 *
	 * @param graph
	 *            Current Graph
	 * @param inVariables
	 *            Collection of ingoing variables
	 * @param outVariables
	 *            Collection of outgoing variables
	 * @param parallelGateway1
	 *            First parallel gateway (BpmnElement)
	 * @param parallelGateway2
	 *            Second parallel gateway (BpmnElement)
	 * @param subgraph
	 *            Subgraph
	 */
	private void connectParallelGatewaysWithSubDataFlow(final Graph graph, final Collection inVariables,
			final Collection outVariables, final BpmnElement parallelGateway1,
			final BpmnElement parallelGateway2, final Graph subgraph) {

		// read nodes of the sub data flow
		final Collection vertices = subgraph.getVertices();
		for (final BpmnElement vertex : vertices) {
			// add _ before the element id to avoid name clashes
			final BaseElement baseElement = vertex.getBaseElement();
			baseElement.setId("_" + baseElement.getId());
			// add node to the main data flow
			graph.addVertex(vertex);
		}
		// read edges of the sub data flow
		final Collection> edges = subgraph.getEdges();
		for (final List list : edges) {
			for (final Edge edge : list) {
				final BpmnElement from = edge.getFrom();
				final BpmnElement to = edge.getTo();
				// add edge the the main data flow
				graph.addEdge(from, to, 100);
			}
		}

		// get start and end nodes of the sub data flow and connect parallel gateways in
		// the main flow
		// with it
		final Collection startNodes = subgraph.getStartNodes();
		for (final BpmnElement startNode : startNodes) {
			// set variables from in interface of the call activity
			startNode.setInCa(inVariables);
			graph.addEdge(parallelGateway1, startNode, 100);
		}
		final Collection endNodes = subgraph.getEndNodes();
		for (final BpmnElement endNode : endNodes) {
			// set variables from out interface of the call activity
			endNode.setOutCa(outVariables);
			graph.addEdge(endNode, parallelGateway2, 100);
		}
	}

	/**
	 * Read and transform process definition into data flows
	 *
	 * @param fileScanner
	 *            FileScanner
	 * @param calledElementHierarchy
	 *            Collection of Element Hierarchy
	 * @param callActivityPath
	 *            CallActivityPath
	 * @param scanner
	 *            OuterProcessVariableScanner
	 * @return Collection of IGraphs (subgraphs)
	 */
	private Collection createSubDataFlowsFromCallActivity(final FileScanner fileScanner,
			final Collection calledElementHierarchy, final String callActivityPath,
			final ProcessVariablesScanner scanner) {
		// read called process
		final BpmnModelInstance subModel = Bpmn.readModelFromFile(new File(callActivityPath));

		// transform process into data flow
		final ElementGraphBuilder graphBuilder = new ElementGraphBuilder(decisionRefToPathMap, processIdToPathMap,
				messageIdToVariables, processIdToVariables, rule, bpmnScanner);
		return graphBuilder.createProcessGraph(fileScanner, subModel, callActivityPath, calledElementHierarchy,
				scanner);
	}

	/**
	 * Integrate parallel gateways into the main data flow before and after the call
	 * activity
	 *
	 * @param callActivity
	 *            CallActivity
	 * @param graph
	 *            Current Graph
	 * @param parallelGateway1
	 *            First parallel gateway (BpmnElement)
	 * @param parallelGateway2
	 *            Second parallel gateway (BpmnElement)
	 */
	private void connectParallelGatewaysWithMainDataFlow(final CallActivity callActivity, final Graph graph,
			final BpmnElement parallelGateway1, final BpmnElement parallelGateway2) {

		// read incoming and outgoing sequence flows of the call activity
		final SequenceFlow incomingSequenceFlow = callActivity.getIncoming().iterator().next();
		final SequenceFlow outgoingSequenceFlow = callActivity.getOutgoing().iterator().next();

		// remove edges
		graph.removeEdge(elementMap.get(incomingSequenceFlow.getId()), elementMap.get(callActivity.getId()));
		graph.removeEdge(elementMap.get(callActivity.getId()), elementMap.get(outgoingSequenceFlow.getId()));

		// link parallel gateways with the existing data flow
		graph.addEdge(elementMap.get(incomingSequenceFlow.getId()), parallelGateway1, 100);
		graph.addEdge(parallelGateway2, elementMap.get(outgoingSequenceFlow.getId()), 100);
		graph.addEdge(parallelGateway1, elementMap.get(callActivity.getId()), 100);
		graph.addEdge(elementMap.get(callActivity.getId()), parallelGateway2, 100);
	}

	/**
	 * Read in- and output variables for a call activity
	 *
	 * @param callActivity
	 *            CallActivity
	 * @param inVariables
	 *            Collection of ingoing variables
	 * @param outVariables
	 *            Collection of outgoing variables
	 */
	private void readCallActivityDataInterfaces(final CallActivity callActivity, final Collection inVariables,
			final Collection outVariables) {

		final ExtensionElements extensionElements = callActivity.getExtensionElements();
		if (extensionElements != null) {
			final List inputAssociations = extensionElements.getElementsQuery().filterByType(CamundaIn.class)
					.list();
			for (final CamundaIn inputAssociation : inputAssociations) {
				final String source = inputAssociation.getCamundaSource();
				if (source != null && !source.isEmpty()) {
					inVariables.add(source);
				}
			}
			final List outputAssociations = extensionElements.getElementsQuery()
					.filterByType(CamundaOut.class).list();
			for (final CamundaOut outputAssociation : outputAssociations) {
				final String target = outputAssociation.getCamundaTarget();
				if (target != null && !target.isEmpty()) {
					outVariables.add(target);
				}
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy