[jboss-svn-commits] JBL Code SVN: r20428 - in labs/jbossrules/trunk/drools-core/src: main/java/org/drools/process/core/datatype/impl/type and 5 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Wed Jun 11 20:06:52 EDT 2008


Author: KrisVerlaenen
Date: 2008-06-11 20:06:52 -0400 (Wed, 11 Jun 2008)
New Revision: 20428

Added:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/datatype/impl/type/ObjectDataType.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/ForEachNode.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/HumanTaskNode.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/ForEachNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/HumanTaskNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/process/ForEachTest.java
Modified:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/context/swimlane/SwimlaneContext.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/ruleflow/core/RuleFlowProcess.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/CompositeNode.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/NodeInstanceFactoryRegistry.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/CompositeNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/WorkItemNodeInstance.java
Log:
JBRULES-1641: ForEach node
 - initial core implementation of a for each node
JBRULES-1551: Workflow human tasks
 - human task node with swimlane integration

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/context/swimlane/SwimlaneContext.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/context/swimlane/SwimlaneContext.java	2008-06-11 21:03:23 UTC (rev 20427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/context/swimlane/SwimlaneContext.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -1,5 +1,6 @@
 package org.drools.process.core.context.swimlane;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -12,7 +13,7 @@
 
     public static final String SWIMLANE_SCOPE = "SwimlaneScope";
     
-	private Map<String, Swimlane> swimlanes = new HashMap();
+	private Map<String, Swimlane> swimlanes = new HashMap<String, Swimlane>();
 
 	public String getType() {
 		return SWIMLANE_SCOPE;
@@ -29,6 +30,10 @@
     public void removeSwimlane(String name) {
         this.swimlanes.remove(name);
     }
+    
+    public Collection<Swimlane> getSwimlanes() {
+        return swimlanes.values();
+    }
 
 	public Context resolveContext(Object param) {
 		if (param instanceof String) {

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/datatype/impl/type/ObjectDataType.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/datatype/impl/type/ObjectDataType.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/datatype/impl/type/ObjectDataType.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -0,0 +1,62 @@
+package org.drools.process.core.datatype.impl.type;
+
+/*
+ * Copyright 2005 JBoss Inc
+ * 
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.drools.process.core.datatype.DataType;
+
+/**
+ * Representation of an object datatype.
+ * 
+ * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
+ */
+public final class ObjectDataType implements DataType {
+
+    private static final long serialVersionUID = 4L;
+
+    private String className;
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+    }
+
+    public void writeExternal(ObjectOutput out) throws IOException {
+    }
+
+    public boolean verifyDataType(final Object value) {
+        try {
+            Class<?> clazz = ObjectDataType.class.forName(className);
+            if (clazz.isInstance(value)) {
+                return true;
+            }
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException(
+                "Could not find data type " + className);
+        }
+        return false;
+    }
+}

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/ruleflow/core/RuleFlowProcess.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/ruleflow/core/RuleFlowProcess.java	2008-06-11 21:03:23 UTC (rev 20427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/ruleflow/core/RuleFlowProcess.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -1,5 +1,6 @@
 package org.drools.ruleflow.core;
 
+import org.drools.process.core.context.swimlane.SwimlaneContext;
 import org.drools.process.core.context.variable.VariableScope;
 import org.drools.workflow.core.Node;
 import org.drools.workflow.core.NodeContainer;
@@ -18,11 +19,18 @@
         VariableScope variableScope = new VariableScope();
         addContext(variableScope);
         setDefaultContext(variableScope);
+        SwimlaneContext swimLaneContext = new SwimlaneContext();
+        addContext(swimLaneContext);
+        setDefaultContext(swimLaneContext);
     }
     
     public VariableScope getVariableScope() {
         return (VariableScope) getDefaultContext(VariableScope.VARIABLE_SCOPE);
     }
+    
+    public SwimlaneContext getSwimlaneContext() {
+        return (SwimlaneContext) getDefaultContext(SwimlaneContext.SWIMLANE_SCOPE);
+    }
 
     protected NodeContainer createNodeContainer() {
         return new WorkflowProcessNodeContainer();

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/CompositeNode.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/CompositeNode.java	2008-06-11 21:03:23 UTC (rev 20427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/CompositeNode.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -67,7 +67,7 @@
     }
     
     public void linkOutgoingConnections(long outNodeId, String outNodeType, String outType) {
-        inConnectionMap.put(outType, new NodeAndType(outNodeId, outNodeType));
+        outConnectionMap.put(outType, new NodeAndType(outNodeId, outNodeType));
     }
     
     public void linkOutgoingConnections(CompositeNode.NodeAndType outNode, String outType) {

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/ForEachNode.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/ForEachNode.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/ForEachNode.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -0,0 +1,110 @@
+package org.drools.workflow.core.node;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.drools.process.core.context.variable.Variable;
+import org.drools.process.core.context.variable.VariableScope;
+import org.drools.process.core.datatype.DataType;
+import org.drools.workflow.core.Node;
+import org.drools.workflow.core.impl.ConnectionImpl;
+
+/*
+ * Copyright 2005 JBoss Inc
+ * 
+ * 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.
+ */
+
+/**
+ * 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.
+ * 
+ * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
+ */
+public class ForEachNode extends CompositeNode {
+    
+    private static final long serialVersionUID = 4L;
+    
+    private String variableName;
+    private String collectionExpression;
+
+    public ForEachNode() {
+        // Split
+        ForEachSplitNode split = new ForEachSplitNode();
+        split.setName("ForEachSplit");
+        addNode(split);
+        linkIncomingConnections(
+            Node.CONNECTION_DEFAULT_TYPE, 
+            new CompositeNode.NodeAndType(split, Node.CONNECTION_DEFAULT_TYPE));
+        // Composite node
+        CompositeNode compositeNode = new CompositeNode();
+        compositeNode.setName("ForEachComposite");
+        addNode(compositeNode);
+        VariableScope variableScope = new VariableScope();
+        compositeNode.setContext(VariableScope.VARIABLE_SCOPE, variableScope);
+        // Join
+        ForEachJoinNode join = new ForEachJoinNode();
+        join.setName("ForEachJoin");
+        addNode(join);
+        linkOutgoingConnections(
+            new CompositeNode.NodeAndType(join, Node.CONNECTION_DEFAULT_TYPE),
+            Node.CONNECTION_DEFAULT_TYPE);
+    }
+    
+    public String getVariableName() {
+        return variableName;
+    }
+    
+    public CompositeNode getCompositeNode() {
+        return (CompositeNode) getNode(2); 
+    }
+
+    public void setVariable(String variableName, DataType type) {
+        this.variableName = variableName;
+        List<Variable> variables = new ArrayList<Variable>();
+        Variable variable = new Variable();
+        variable.setName(variableName);
+        variable.setType(type);
+        variables.add(variable);
+        ((VariableScope) getCompositeNode().getContext(VariableScope.VARIABLE_SCOPE)).setVariables(variables);
+        // TODO: can only create connections after linking composite node ports 
+        new ConnectionImpl(
+            getNode(1), Node.CONNECTION_DEFAULT_TYPE,
+            getCompositeNode(), Node.CONNECTION_DEFAULT_TYPE
+        );
+        new ConnectionImpl(
+            getCompositeNode(), Node.CONNECTION_DEFAULT_TYPE,
+            getNode(3), Node.CONNECTION_DEFAULT_TYPE
+        );
+    }
+    
+    public String getCollectionExpression() {
+        return collectionExpression;
+    }
+
+    public void setCollectionExpression(String collectionExpression) {
+        this.collectionExpression = collectionExpression;
+    }
+
+    public class ForEachSplitNode extends SequenceNode {
+        private static final long serialVersionUID = 4L;
+    }
+
+    public class ForEachJoinNode extends SequenceNode {
+        private static final long serialVersionUID = 4L;
+    }
+
+}

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/HumanTaskNode.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/HumanTaskNode.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/HumanTaskNode.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -0,0 +1,26 @@
+package org.drools.workflow.core.node;
+
+import org.drools.process.core.Work;
+import org.drools.process.core.impl.WorkImpl;
+
+public class HumanTaskNode extends WorkItemNode {
+
+    private static final long serialVersionUID = 4L;
+
+    private String swimlane;
+    
+    public HumanTaskNode() {
+        Work work = new WorkImpl();
+        work.setName("Human Task");
+        setWork(work);
+    }
+
+    public String getSwimlane() {
+        return swimlane;
+    }
+
+    public void setSwimlane(String swimlane) {
+        this.swimlane = swimlane;
+    }
+
+}

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/NodeInstanceFactoryRegistry.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/NodeInstanceFactoryRegistry.java	2008-06-11 21:03:23 UTC (rev 20427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/NodeInstanceFactoryRegistry.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -8,6 +8,8 @@
 import org.drools.workflow.core.node.CompositeNode;
 import org.drools.workflow.core.node.EndNode;
 import org.drools.workflow.core.node.FaultNode;
+import org.drools.workflow.core.node.ForEachNode;
+import org.drools.workflow.core.node.HumanTaskNode;
 import org.drools.workflow.core.node.Join;
 import org.drools.workflow.core.node.MilestoneNode;
 import org.drools.workflow.core.node.RuleSetNode;
@@ -22,6 +24,8 @@
 import org.drools.workflow.instance.node.CompositeNodeInstance;
 import org.drools.workflow.instance.node.EndNodeInstance;
 import org.drools.workflow.instance.node.FaultNodeInstance;
+import org.drools.workflow.instance.node.ForEachNodeInstance;
+import org.drools.workflow.instance.node.HumanTaskNodeInstance;
 import org.drools.workflow.instance.node.JoinInstance;
 import org.drools.workflow.instance.node.MilestoneNodeInstance;
 import org.drools.workflow.instance.node.RuleSetNodeInstance;
@@ -64,6 +68,10 @@
                   new CreateNewNodeFactory( FaultNodeInstance.class ) );
         register( CompositeNode.class,
                   new CreateNewNodeFactory( CompositeNodeInstance.class ) );
+        register( HumanTaskNode.class,
+                  new CreateNewNodeFactory( HumanTaskNodeInstance.class ) );
+        register( ForEachNode.class,
+                  new CreateNewNodeFactory( ForEachNodeInstance.class ) );
     }
 
     public void register(Class< ? extends Node> cls,

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/CompositeNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/CompositeNodeInstance.java	2008-06-11 21:03:23 UTC (rev 20427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/CompositeNodeInstance.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -141,9 +141,6 @@
             throw new IllegalArgumentException("Illegal node type: " + node.getClass());
         }
         NodeInstanceImpl nodeInstance = (NodeInstanceImpl) conf.getNodeInstance(node, getProcessInstance(), this);
-        nodeInstance.setNodeId(node.getId());
-        nodeInstance.setNodeInstanceContainer(this);
-        nodeInstance.setProcessInstance(getProcessInstance());
         if (nodeInstance == null) {
             throw new IllegalArgumentException("Illegal node type: " + node.getClass());
         }
@@ -181,7 +178,6 @@
         }
         
         public void triggerCompleted() {
-            getNodeInstanceContainer().removeNodeInstance(this);
             CompositeNodeInstance.this.triggerCompleted(
                 getCompositeNodeEnd().getOutType());
         }

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/ForEachNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/ForEachNodeInstance.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/ForEachNodeInstance.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -0,0 +1,125 @@
+package org.drools.workflow.instance.node;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.drools.process.core.context.variable.VariableScope;
+import org.drools.process.instance.context.variable.VariableScopeInstance;
+import org.drools.workflow.core.Connection;
+import org.drools.workflow.core.Node;
+import org.drools.workflow.core.node.ForEachNode;
+import org.drools.workflow.core.node.ForEachNode.ForEachJoinNode;
+import org.drools.workflow.core.node.ForEachNode.ForEachSplitNode;
+import org.drools.workflow.instance.NodeInstance;
+import org.drools.workflow.instance.impl.NodeInstanceImpl;
+
+/*
+ * Copyright 2005 JBoss Inc
+ * 
+ * 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.
+ */
+
+/**
+ * Runtime counterpart of a for each node.
+ * 
+ * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
+ */
+public class ForEachNodeInstance extends CompositeNodeInstance {
+
+    private static final long serialVersionUID = 4L;
+    
+    public ForEachNode getForEachNode() {
+        return (ForEachNode) getNode();
+    }
+
+    public NodeInstance getNodeInstance(final Node node) {
+        // TODO do this cleaner for split / join of for each?
+        if (node instanceof ForEachSplitNode) {
+            ForEachSplitNodeInstance nodeInstance = new ForEachSplitNodeInstance();
+            nodeInstance.setNodeId(node.getId());
+            nodeInstance.setNodeInstanceContainer(this);
+            nodeInstance.setProcessInstance(getProcessInstance());
+            return nodeInstance;
+        } else if (node instanceof ForEachJoinNode) {
+            ForEachJoinNodeInstance nodeInstance = (ForEachJoinNodeInstance)
+                getFirstNodeInstance(node.getId());
+            if (nodeInstance == null) {
+                nodeInstance = new ForEachJoinNodeInstance();
+                nodeInstance.setNodeId(node.getId());
+                nodeInstance.setNodeInstanceContainer(this);
+                nodeInstance.setProcessInstance(getProcessInstance());
+            }
+            return nodeInstance;
+        }
+        return super.getNodeInstance(node);
+    }
+    
+    public class ForEachSplitNodeInstance extends NodeInstanceImpl {
+
+        private static final long serialVersionUID = 4L;
+        
+        public ForEachSplitNode getForEachSplitNode() {
+            return (ForEachSplitNode) getNode();
+        }
+
+        public void internalTrigger(NodeInstance from, String type) {
+            String collectionExpression = getForEachNode().getCollectionExpression();
+            Collection<?> collection = evaluateCollectionExpression(collectionExpression);
+            getNodeInstanceContainer().removeNodeInstance(this);
+            List<NodeInstance> nodeInstances = new ArrayList<NodeInstance>();
+            for (Object o: collection) {
+                String variableName = getForEachNode().getVariableName();
+                CompositeNodeInstance nodeInstance = (CompositeNodeInstance)
+                    getNodeInstanceContainer().getNodeInstance(getForEachSplitNode().getTo().getTo());
+                VariableScopeInstance variableScopeInstance = (VariableScopeInstance)
+                    nodeInstance.resolveContextInstance(VariableScope.VARIABLE_SCOPE, variableName);
+                variableScopeInstance.setVariable(variableName, o);
+                nodeInstances.add(nodeInstance);
+            }
+            for (NodeInstance nodeInstance: nodeInstances) {
+                nodeInstance.trigger(this, getForEachSplitNode().getTo().getToType());
+            }
+        }
+        
+        private Collection<?> evaluateCollectionExpression(String collectionExpression) {
+            // TODO: should evaluate this expression using MVEL
+            VariableScopeInstance variableScopeInstance = (VariableScopeInstance)
+                resolveContextInstance(VariableScope.VARIABLE_SCOPE, collectionExpression);
+            if (variableScopeInstance == null) {
+                throw new IllegalArgumentException(
+                    "Could not find collection " + collectionExpression);
+            }
+            return (Collection<?>) variableScopeInstance.getVariable(collectionExpression);
+        }
+        
+    }
+    
+    public class ForEachJoinNodeInstance extends NodeInstanceImpl {
+
+        private static final long serialVersionUID = 4L;
+        
+        public ForEachJoinNode getForEachJoinNode() {
+            return (ForEachJoinNode) getNode();
+        }
+
+        public void internalTrigger(NodeInstance from, String type) {
+            if (getNodeInstanceContainer().getNodeInstances().size() == 1) {
+                getNodeInstanceContainer().removeNodeInstance(this);
+                triggerConnection(getForEachJoinNode().getTo());
+            }
+        }
+        
+    }
+    
+}

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/HumanTaskNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/HumanTaskNodeInstance.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/HumanTaskNodeInstance.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -0,0 +1,82 @@
+package org.drools.workflow.instance.node;
+
+import org.drools.process.core.context.swimlane.SwimlaneContext;
+import org.drools.process.instance.WorkItem;
+import org.drools.process.instance.context.swimlane.SwimlaneContextInstance;
+import org.drools.process.instance.impl.WorkItemImpl;
+import org.drools.workflow.core.node.HumanTaskNode;
+import org.drools.workflow.core.node.WorkItemNode;
+
+public class HumanTaskNodeInstance extends WorkItemNodeInstance {
+
+    private static final long serialVersionUID = 4L;
+    
+    private transient SwimlaneContextInstance swimlaneContextInstance;
+    
+    public HumanTaskNode getHumanTaskNode() {
+        return (HumanTaskNode) getNode();
+    }
+    
+    protected WorkItem createWorkItem(WorkItemNode workItemNode) {
+        WorkItem workItem = super.createWorkItem(workItemNode);
+        String actorId = assignWorkItem();
+        if (actorId != null) {
+            ((WorkItemImpl) workItem).setParameter("ActorId", actorId);
+        }
+        return workItem;
+    }
+    
+    protected String assignWorkItem() {
+        String actorId = null;
+        // if this human task node is part of a swim lane, check whether an actor
+        // has already been assigned to this swim lane
+        String swimlaneName = getHumanTaskNode().getSwimlane();
+        SwimlaneContextInstance swimlaneContextInstance = getSwimlaneContextInstance(swimlaneName);
+        if (swimlaneContextInstance != null) {
+            actorId = swimlaneContextInstance.getActorId(swimlaneName);
+        }
+        if (actorId == null) {
+            // if the actorId has not yet been assigned, check whether assigners are
+            // defined for this human task node
+            // TODO
+        }
+        if (actorId == null) {
+            // if the actorId has not yet been assigned, check whether assigners are
+            // defined for this swim lane
+        }
+        return actorId;
+    }
+    
+    private SwimlaneContextInstance getSwimlaneContextInstance(String swimlaneName) {
+        if (this.swimlaneContextInstance == null) {
+            if (swimlaneName == null) {
+                return null;
+            }
+            SwimlaneContextInstance swimlaneContextInstance =
+                (SwimlaneContextInstance) resolveContextInstance(
+                    SwimlaneContext.SWIMLANE_SCOPE, swimlaneName);
+            if (swimlaneContextInstance == null) {
+                throw new IllegalArgumentException(
+                    "Could not find swimlane context instance");
+            }
+            this.swimlaneContextInstance = swimlaneContextInstance;
+        }
+        return this.swimlaneContextInstance;
+    }
+    
+    public void triggerCompleted(WorkItem workItem) {
+        String swimlaneName = getHumanTaskNode().getSwimlane();
+        SwimlaneContextInstance swimlaneContextInstance = getSwimlaneContextInstance(swimlaneName);
+        if (swimlaneContextInstance != null) {
+            String oldActorId = swimlaneContextInstance.getActorId(swimlaneName);
+            // only assign if swimlane has not already been assigned to an actor
+            if (oldActorId == null) {
+                String newActorId = (String) workItem.getResult("ActorId");
+                if (newActorId != null) {
+                    swimlaneContextInstance.setActorId(swimlaneName, newActorId);
+                }
+            }
+        }
+        super.triggerCompleted(workItem);
+    }
+}

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/WorkItemNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/WorkItemNodeInstance.java	2008-06-11 21:03:23 UTC (rev 20427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/WorkItemNodeInstance.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -64,12 +64,25 @@
 //                "A WorkItemNode only accepts default incoming connections!");
 //        }
         WorkItemNode workItemNode = getWorkItemNode();
+        WorkItem workItem = createWorkItem(workItemNode);
+		if (workItemNode.isWaitForCompletion()) {
+		    addEventListeners();
+        }
+        getProcessInstance().getWorkingMemory().getWorkItemManager().internalExecuteWorkItem(workItem);
+        if (!workItemNode.isWaitForCompletion()) {
+            triggerCompleted();
+        } else {
+        	this.workItemId = workItem.getId();
+        }
+    }
+    
+    protected WorkItem createWorkItem(WorkItemNode workItemNode) {
         Work work = workItemNode.getWork();
-		workItem = new WorkItemImpl();
-		workItem.setName(work.getName());
-		workItem.setProcessInstanceId(getProcessInstance().getId());
-		workItem.setParameters(new HashMap<String, Object>(work.getParameters()));
-		for (Iterator<Map.Entry<String, String>> iterator = workItemNode.getInMappings().entrySet().iterator(); iterator.hasNext(); ) {
+        WorkItemImpl workItem = new WorkItemImpl();
+        workItem.setName(work.getName());
+        workItem.setProcessInstanceId(getProcessInstance().getId());
+        workItem.setParameters(new HashMap<String, Object>(work.getParameters()));
+        for (Iterator<Map.Entry<String, String>> iterator = workItemNode.getInMappings().entrySet().iterator(); iterator.hasNext(); ) {
             Map.Entry<String, String> mapping = iterator.next();
             VariableScopeInstance variableScopeInstance = (VariableScopeInstance)
                 resolveContextInstance(VariableScope.VARIABLE_SCOPE, mapping.getValue());
@@ -81,15 +94,7 @@
                 System.err.println("Continuing without setting parameter.");
             }
         }
-		if (workItemNode.isWaitForCompletion()) {
-		    addEventListeners();
-        }
-        getProcessInstance().getWorkingMemory().getWorkItemManager().internalExecuteWorkItem(workItem);
-        if (!workItemNode.isWaitForCompletion()) {
-            triggerCompleted();
-        } else {
-        	this.workItemId = workItem.getId();
-        }
+        return workItem;
     }
 
     public void triggerCompleted(WorkItem workItem) {

Added: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/process/ForEachTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/process/ForEachTest.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/process/ForEachTest.java	2008-06-12 00:06:52 UTC (rev 20428)
@@ -0,0 +1,101 @@
+package org.drools.process;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.drools.Person;
+import org.drools.RuleBaseFactory;
+import org.drools.WorkingMemory;
+import org.drools.common.AbstractRuleBase;
+import org.drools.common.InternalWorkingMemory;
+import org.drools.process.core.context.variable.Variable;
+import org.drools.process.core.datatype.impl.type.ListDataType;
+import org.drools.process.core.datatype.impl.type.ObjectDataType;
+import org.drools.reteoo.ReteooWorkingMemory;
+import org.drools.ruleflow.core.RuleFlowProcess;
+import org.drools.spi.Action;
+import org.drools.spi.KnowledgeHelper;
+import org.drools.workflow.core.Node;
+import org.drools.workflow.core.impl.ConnectionImpl;
+import org.drools.workflow.core.node.ActionNode;
+import org.drools.workflow.core.node.EndNode;
+import org.drools.workflow.core.node.ForEachNode;
+import org.drools.workflow.core.node.StartNode;
+
+public class ForEachTest extends TestCase {
+    
+    public void testForEach() {
+        RuleFlowProcess process = new RuleFlowProcess();
+        process.setId("org.drools.process.foreach");
+        process.setName("ForEach Process");
+        
+        List<Variable> variables = new ArrayList<Variable>();
+        Variable variable = new Variable();
+        variable.setName("persons");
+        ListDataType listDataType = new ListDataType();
+        ObjectDataType personDataType = new ObjectDataType();
+        personDataType.setClassName("org.drools.Person");
+        listDataType.setDataType(personDataType);
+        variable.setType(listDataType);
+        variables.add(variable);
+        process.getVariableScope().setVariables(variables);
+        
+        StartNode startNode = new StartNode();
+        startNode.setName("Start");
+        startNode.setId(1);
+        process.addNode(startNode);
+        EndNode endNode = new EndNode();
+        endNode.setName("EndNode");
+        endNode.setId(2);
+        process.addNode(endNode);
+        ForEachNode forEachNode = new ForEachNode();
+        forEachNode.setName("ForEach");
+        forEachNode.setId(3);
+        forEachNode.setCollectionExpression("persons");
+        personDataType = new ObjectDataType();
+        personDataType.setClassName("org.drools.Person");
+        process.addNode(forEachNode);
+        new ConnectionImpl(
+            startNode, Node.CONNECTION_DEFAULT_TYPE,
+            forEachNode, Node.CONNECTION_DEFAULT_TYPE
+        );
+        new ConnectionImpl(
+            forEachNode, Node.CONNECTION_DEFAULT_TYPE,
+            endNode, Node.CONNECTION_DEFAULT_TYPE
+        );
+        
+        final List<String> myList = new ArrayList<String>();
+        ActionNode actionNode = new ActionNode();
+        actionNode.setName("Print child");
+        actionNode.setAction(new Action() {
+            public void execute(KnowledgeHelper knowledgeHelper, WorkingMemory workingMemory) throws Exception {
+                myList.add("Executed action");
+            }
+        });
+        forEachNode.getCompositeNode().addNode(actionNode);
+        forEachNode.getCompositeNode().linkIncomingConnections(
+            Node.CONNECTION_DEFAULT_TYPE,
+            actionNode.getId(), Node.CONNECTION_DEFAULT_TYPE);
+        forEachNode.getCompositeNode().linkOutgoingConnections(
+            actionNode.getId(), Node.CONNECTION_DEFAULT_TYPE,
+            Node.CONNECTION_DEFAULT_TYPE);
+        forEachNode.setVariable("child", personDataType);
+        
+        AbstractRuleBase ruleBase = (AbstractRuleBase) RuleBaseFactory.newRuleBase();
+        ruleBase.addProcess(process);
+        InternalWorkingMemory workingMemory = new ReteooWorkingMemory(1, ruleBase);
+        Map<String, Object> parameters = new HashMap<String, Object>();
+        List<Person> persons = new ArrayList<Person>();
+        persons.add(new Person("John Doe", 30));
+        persons.add(new Person("Jane Doe", 20));
+        persons.add(new Person("Jack", 60));
+        parameters.put("persons", persons);
+        workingMemory.startProcess("org.drools.process.foreach", parameters);
+        assertEquals(3, myList.size());
+    }
+
+}




More information about the jboss-svn-commits mailing list