/** * Copyright 2005 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jbpm.workflow.core.node; import java.util.ArrayList; import java.util.List; import org.kie.api.definition.process.Node; import org.drools.core.process.core.datatype.DataType; import org.jbpm.process.core.Context; import org.jbpm.process.core.context.AbstractContext; import org.jbpm.process.core.context.variable.Variable; import org.jbpm.process.core.context.variable.VariableScope; import org.jbpm.workflow.core.impl.ConnectionImpl; import org.jbpm.workflow.core.impl.ExtendedNodeImpl; /** * A for each node. * * This node activates the contained subflow for each element of a collection. * The node continues if all activated the subflow has been completed for each * of the elements in the collection. * */ public class ForEachNode extends CompositeContextNode { private static final long serialVersionUID = 510l; private String variableName; private String outputVariableName; private String collectionExpression; private String outputCollectionExpression; private String completionConditionExpression; private boolean waitForCompletion = true; public ForEachNode() { // Split ForEachSplitNode split = new ForEachSplitNode(); split.setName("ForEachSplit"); split.setMetaData("hidden", true); split.setMetaData("UniqueId", getMetaData("Uniqueid") + ":foreach:split"); super.addNode(split); super.linkIncomingConnections( org.jbpm.workflow.core.Node.CONNECTION_DEFAULT_TYPE, new CompositeNode.NodeAndType(split, org.jbpm.workflow.core.Node.CONNECTION_DEFAULT_TYPE)); // Composite node CompositeContextNode compositeNode = new CompositeContextNode(); compositeNode.setName("ForEachComposite"); compositeNode.setMetaData("hidden", true); compositeNode.setMetaData("UniqueId", getMetaData("Uniqueid") + ":foreach:composite"); super.addNode(compositeNode); VariableScope variableScope = new VariableScope(); compositeNode.addContext(variableScope); compositeNode.setDefaultContext(variableScope); // Join ForEachJoinNode join = new ForEachJoinNode(); join.setName("ForEachJoin"); join.setMetaData("hidden", true); join.setMetaData("UniqueId", getMetaData("Uniqueid") + ":foreach:join"); super.addNode(join); super.linkOutgoingConnections( new CompositeNode.NodeAndType(join, org.jbpm.workflow.core.Node.CONNECTION_DEFAULT_TYPE), org.jbpm.workflow.core.Node.CONNECTION_DEFAULT_TYPE); new ConnectionImpl( super.getNode(1), org.jbpm.workflow.core.Node.CONNECTION_DEFAULT_TYPE, getCompositeNode(), org.jbpm.workflow.core.Node.CONNECTION_DEFAULT_TYPE ); new ConnectionImpl( getCompositeNode(), org.jbpm.workflow.core.Node.CONNECTION_DEFAULT_TYPE, super.getNode(3), org.jbpm.workflow.core.Node.CONNECTION_DEFAULT_TYPE ); } public String getVariableName() { return variableName; } public DataType getVariableType() { if (variableName == null) { return null; } for (Variable variable: ((VariableScope) getCompositeNode().getDefaultContext(VariableScope.VARIABLE_SCOPE)).getVariables()) { if (variableName.equals(variable.getName())) { return variable.getType(); } } return null; } public String getOutputVariableName() { return outputVariableName; } public DataType getOutputVariableType() { if (outputVariableName == null) { return null; } for (Variable variable: ((VariableScope) getCompositeNode().getDefaultContext(VariableScope.VARIABLE_SCOPE)).getVariables()) { if (outputVariableName.equals(variable.getName())) { return variable.getType(); } } return null; } public CompositeContextNode getCompositeNode() { return (CompositeContextNode) super.getNode(2); } public ForEachSplitNode getForEachSplitNode() { return (ForEachSplitNode) super.getNode(1); } public ForEachJoinNode getForEachJoinNode() { return (ForEachJoinNode) super.getNode(3); } public void addNode(Node node) { getCompositeNode().addNode(node); } protected void internalAddNode(Node node) { super.addNode(node); } public Node getNode(long id) { return getCompositeNode().getNode(id); } public Node internalGetNode(long id) { return super.getNode(id); } public Node[] getNodes() { return getCompositeNode().getNodes(); } public Node[] internalGetNodes() { return super.getNodes(); } public void removeNode(Node node) { getCompositeNode().removeNode(node); } protected void internalRemoveNode(Node node) { super.removeNode(node); } public void linkIncomingConnections(String inType, long inNodeId, String inNodeType) { getCompositeNode().linkIncomingConnections(inType, inNodeId, inNodeType); } public void linkOutgoingConnections(long outNodeId, String outNodeType, String outType) { getCompositeNode().linkOutgoingConnections(outNodeId, outNodeType, outType); } public CompositeNode.NodeAndType getLinkedIncomingNode(String inType) { return getCompositeNode().getLinkedIncomingNode(inType); } public CompositeNode.NodeAndType internalGetLinkedIncomingNode(String inType) { return super.getLinkedIncomingNode(inType); } public CompositeNode.NodeAndType getLinkedOutgoingNode(String inType) { return getCompositeNode().getLinkedOutgoingNode(inType); } public CompositeNode.NodeAndType internalGetLinkedOutgoingNode(String inType) { return super.getLinkedOutgoingNode(inType); } public void setVariable(String variableName, DataType type) { this.variableName = variableName; VariableScope variableScope = (VariableScope) getCompositeNode().getDefaultContext(VariableScope.VARIABLE_SCOPE); List<Variable> variables = variableScope.getVariables(); if (variables == null) { variables = new ArrayList<Variable>(); variableScope.setVariables(variables); } Variable variable = new Variable(); variable.setName(variableName); variable.setType(type); variables.add(variable); } public void setOutputVariable(String variableName, DataType type) { this.outputVariableName = variableName; VariableScope variableScope = (VariableScope) getCompositeNode().getDefaultContext(VariableScope.VARIABLE_SCOPE); List<Variable> variables = variableScope.getVariables(); if (variables == null) { variables = new ArrayList<Variable>(); variableScope.setVariables(variables); } Variable variable = new Variable(); variable.setName(variableName); variable.setType(type); variables.add(variable); Variable tmpvariable = new Variable(); tmpvariable.setName("foreach_output"); tmpvariable.setType(type); variables.add(tmpvariable); } public String getCollectionExpression() { return collectionExpression; } public void setCollectionExpression(String collectionExpression) { this.collectionExpression = collectionExpression; } public String getOutputCollectionExpression() { return outputCollectionExpression; } public void setOutputCollectionExpression(String collectionExpression) { this.outputCollectionExpression = collectionExpression; } public boolean isWaitForCompletion() { return waitForCompletion; } public void setWaitForCompletion(boolean waitForCompletion) { this.waitForCompletion = waitForCompletion; } public static class ForEachSplitNode extends ExtendedNodeImpl { private static final long serialVersionUID = 510l; } public static class ForEachJoinNode extends ExtendedNodeImpl { private static final long serialVersionUID = 510l; } @Override public Context getContext(String contextType) { Context context = getCompositeNode().getDefaultContext(contextType); if (context != null) { return context; } return super.getContext(contextType); } @Override public void addContext(Context context) { getCompositeNode().addContext(context); ((AbstractContext) context).setContextContainer(getCompositeNode()); } @Override public void setDefaultContext(Context context) { getCompositeNode().setDefaultContext(context); ((AbstractContext) context).setContextContainer(getCompositeNode()); } @Override public List<Context> getContexts(String contextType) { List<Context> contexts = super.getContexts(contextType); if (contexts == null) { contexts = getCompositeNode().getContexts(contextType); } return contexts; } @Override public Context getContext(String contextType, long id) { Context ctx = super.getContext(contextType, id); if (ctx == null) { ctx = getCompositeNode().getContext(contextType, id); } return ctx; } public String getCompletionConditionExpression() { return completionConditionExpression; } public void setCompletionConditionExpression( String completionConditionExpression) { this.completionConditionExpression = completionConditionExpression; } }