[jboss-svn-commits] JBL Code SVN: r32428 - in labs/jbossrules/trunk: drools-compiler/src/test/java/org/drools/integrationtests and 9 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Mon Apr 5 17:58:54 EDT 2010


Author: KrisVerlaenen
Date: 2010-04-05 17:58:53 -0400 (Mon, 05 Apr 2010)
New Revision: 32428

Added:
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessRuleFlowGroupTest.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/DynamicUtils.java
Modified:
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/osgi/compiler/Activator.java
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessDynamicNodeTest.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/Agenda.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/audit/WorkingMemoryLogger.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/DefaultKnowledgeHelper.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/SequentialKnowledgeHelper.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/DefaultAgenda.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/InternalRuleFlowGroup.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/RuleFlowGroupImpl.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/impl/AbstractProcessInstanceMarshaller.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/impl/PersisterEnums.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/KnowledgeHelper.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/core/node/DynamicNode.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/ExtendedNodeInstanceImpl.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/NodeInstanceImpl.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/WorkflowProcessInstanceImpl.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/DynamicNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/RuleSetNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/SubProcessNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/WorkItemNodeInstance.java
Log:
JBRULES-2120: Dynamic or Ah-Hoc node
 - extended impl. of dynamic node

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/osgi/compiler/Activator.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/osgi/compiler/Activator.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/osgi/compiler/Activator.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -6,7 +6,6 @@
 import org.drools.Service;
 import org.drools.builder.KnowledgeBuilderFactoryService;
 import org.drools.builder.impl.KnowledgeBuilderFactoryServiceImpl;
-import org.drools.compiler.BPMN2ProcessFactory;
 import org.drools.compiler.BPMN2ProcessProvider;
 import org.drools.compiler.DecisionTableProvider;
 import org.drools.osgi.api.Activator.BundleContextInstantiator;
@@ -25,6 +24,7 @@
     private ServiceRegistration kbuilderReg;
 
     private ServiceTracker      dtableTracker;
+    private ServiceTracker      bpmn2Tracker;
 
     public void start(BundleContext bc) throws Exception {
         System.out.println( "registering compiler services" );
@@ -42,12 +42,19 @@
                                                                            this ) );
         this.dtableTracker.open();
 
+        this.bpmn2Tracker = new ServiceTracker( bc,
+								                BPMN2ProcessProvider.class.getName(),
+								                new DroolsServiceTracker( bc,
+								                                          this ) );
+        this.bpmn2Tracker.open();
+        
         System.out.println( "compiler services registered" );
     }
 
     public void stop(BundleContext bc) throws Exception {
         this.kbuilderReg.unregister();
         this.dtableTracker.close();
+        this.bpmn2Tracker.close();
     }
 
     public static class DroolsServiceTracker

Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessDynamicNodeTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessDynamicNodeTest.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessDynamicNodeTest.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -3,20 +3,34 @@
 import java.io.Reader;
 import java.io.StringReader;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import junit.framework.TestCase;
 
+import org.drools.KnowledgeBase;
 import org.drools.RuleBase;
 import org.drools.RuleBaseFactory;
 import org.drools.WorkingMemory;
+import org.drools.builder.KnowledgeBuilder;
+import org.drools.builder.KnowledgeBuilderFactory;
+import org.drools.builder.ResourceType;
 import org.drools.compiler.DroolsError;
 import org.drools.compiler.PackageBuilder;
+import org.drools.io.ResourceFactory;
+import org.drools.logger.KnowledgeRuntimeLogger;
+import org.drools.logger.KnowledgeRuntimeLoggerFactory;
 import org.drools.process.instance.ProcessInstance;
+import org.drools.process.instance.impl.demo.SystemOutWorkItemHandler;
 import org.drools.rule.Package;
+import org.drools.runtime.StatefulKnowledgeSession;
 import org.drools.runtime.process.WorkItem;
 import org.drools.runtime.process.WorkItemHandler;
 import org.drools.runtime.process.WorkItemManager;
+import org.drools.runtime.process.WorkflowProcessInstance;
+import org.drools.workflow.instance.node.DynamicNodeInstance;
+import org.drools.workflow.instance.node.DynamicUtils;
 
 public class ProcessDynamicNodeTest extends TestCase {
     
@@ -159,7 +173,147 @@
         assertEquals(ProcessInstance.STATE_COMPLETED, processInstance.getState());
         assertEquals(3, list.size());
     }
+    
+    public void testAddDynamicWorkItem() {
+    	Reader source = new StringReader(
+                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+                "<process xmlns=\"http://drools.org/drools-5.0/process\"\n" +
+                "         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+                "         xs:schemaLocation=\"http://drools.org/drools-5.0/process drools-processes-5.0.xsd\"\n" +
+                "         type=\"RuleFlow\" name=\"ruleflow\" id=\"org.drools.dynamic\" package-name=\"org.drools\" >\n" +
+                "\n" +
+                "  <header>\n" +
+                "  </header>\n" +
+                "\n" +
+                "  <nodes>\n" +
+                "    <start id=\"1\" name=\"Start\" />\n" + 
+                "    <dynamic id=\"2\" name=\"DynamicNode\" >\n" +
+                "      <nodes>\n" +
+                "        <actionNode id=\"1\" name=\"Action\" >\n" +
+                "          <action type=\"expression\" dialect=\"mvel\" >System.out.println(\"Action\");</action>\n" +
+                "        </actionNode>\n" +
+                "      </nodes>\n" +
+                "      <connections>\n" +
+                "      </connections>\n" +
+                "      <in-ports/>\n" +
+                "      <out-ports/>\n" +
+                "    </dynamic>\n" +
+                "    <end id=\"3\" name=\"End\" />\n" +
+                "  </nodes>\n" +
+                "\n" +
+                "  <connections>\n" +
+                "    <connection from=\"1\" to=\"2\" />\n" +
+                "    <connection from=\"2\" to=\"3\" />\n" +
+                "  </connections>\n" +
+                "</process>");
+    	KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+		kbuilder.add(ResourceFactory.newReaderResource(source), ResourceType.DRF);
+		KnowledgeBase kbase = kbuilder.newKnowledgeBase();
+		StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
+		KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
+		TestWorkItemHandler handler = new TestWorkItemHandler();
+		ksession.getWorkItemManager().registerWorkItemHandler("Human Task", handler);
+		// start a new process instance
+		ProcessInstance processInstance = (ProcessInstance) ksession.startProcess("org.drools.dynamic");
+		DynamicNodeInstance dynamicContext = (DynamicNodeInstance) 
+			((WorkflowProcessInstance) processInstance).getNodeInstances().iterator().next();
+		Map<String, Object> parameters = new HashMap<String, Object>();
+		parameters.put("TaskName", "Dynamic Task");
+		assertNull(handler.getWorkItem());
+		assertEquals(0, dynamicContext.getNodeInstances().size());
+		DynamicUtils.addDynamicWorkItem(dynamicContext, ksession, "Human Task", parameters);
+		assertNotNull(handler.getWorkItem());
+		assertEquals(1, dynamicContext.getNodeInstances().size());
+		logger.close();
+    }
 
+    public void testAddDynamicSubProcess() {
+    	Reader source = new StringReader(
+                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+                "<process xmlns=\"http://drools.org/drools-5.0/process\"\n" +
+                "         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+                "         xs:schemaLocation=\"http://drools.org/drools-5.0/process drools-processes-5.0.xsd\"\n" +
+                "         type=\"RuleFlow\" name=\"ruleflow\" id=\"org.drools.dynamic\" package-name=\"org.drools\" >\n" +
+                "\n" +
+                "  <header>\n" +
+                "  </header>\n" +
+                "\n" +
+                "  <nodes>\n" +
+                "    <start id=\"1\" name=\"Start\" />\n" + 
+                "    <dynamic id=\"2\" name=\"DynamicNode\" >\n" +
+                "      <nodes>\n" +
+                "        <actionNode id=\"1\" name=\"Action\" >\n" +
+                "          <action type=\"expression\" dialect=\"mvel\" >System.out.println(\"Action\");</action>\n" +
+                "        </actionNode>\n" +
+                "      </nodes>\n" +
+                "      <connections>\n" +
+                "      </connections>\n" +
+                "      <in-ports/>\n" +
+                "      <out-ports/>\n" +
+                "    </dynamic>\n" +
+                "    <end id=\"3\" name=\"End\" />\n" +
+                "  </nodes>\n" +
+                "\n" +
+                "  <connections>\n" +
+                "    <connection from=\"1\" to=\"2\" />\n" +
+                "    <connection from=\"2\" to=\"3\" />\n" +
+                "  </connections>\n" +
+                "</process>");
+    	Reader source2 = new StringReader(
+                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+                "<process xmlns=\"http://drools.org/drools-5.0/process\"\n" +
+                "         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+                "         xs:schemaLocation=\"http://drools.org/drools-5.0/process drools-processes-5.0.xsd\"\n" +
+                "         type=\"RuleFlow\" name=\"subflow\" id=\"org.drools.subflow\" package-name=\"org.drools\" >\n" +
+                "\n" +
+                "  <header>\n" +
+        		"    <variables>\n" +
+        		"      <variable name=\"x\" >\n" +
+        		"        <type name=\"org.drools.process.core.datatype.impl.type.StringDataType\" />\n" +
+        		"        <value>SomeText</value>\n" +
+        		"      </variable>\n" +
+        		"    </variables>\n" +
+                "  </header>\n" +
+                "\n" +
+                "  <nodes>\n" +
+                "    <start id=\"1\" name=\"Start\" />\n" + 
+                "    <actionNode id=\"2\" name=\"Action\" >\n" +
+                "      <action type=\"expression\" dialect=\"mvel\" >System.out.println(x);</action>\n" +
+                "    </actionNode>\n" +
+                "    <workItem id=\"3\" name=\"Work\" >\n" +
+	            "      <work name=\"Human Task\" />\n" +
+	            "    </workItem>\n" +
+	            "    <end id=\"4\" name=\"End\" />\n" +
+                "  </nodes>\n" +
+                "\n" +
+                "  <connections>\n" +
+                "    <connection from=\"1\" to=\"2\" />\n" +
+                "    <connection from=\"2\" to=\"3\" />\n" +
+                "    <connection from=\"3\" to=\"4\" />\n" +
+                "  </connections>\n" +
+                "</process>");
+    	KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+		kbuilder.add(ResourceFactory.newReaderResource(source), ResourceType.DRF);
+		kbuilder.add(ResourceFactory.newReaderResource(source2), ResourceType.DRF);
+		KnowledgeBase kbase = kbuilder.newKnowledgeBase();
+		StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
+		KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
+		TestWorkItemHandler handler = new TestWorkItemHandler();
+		ksession.getWorkItemManager().registerWorkItemHandler("Human Task", handler);
+		// start a new process instance
+		ProcessInstance processInstance = (ProcessInstance) ksession.startProcess("org.drools.dynamic");
+		DynamicNodeInstance dynamicContext = (DynamicNodeInstance) 
+			((WorkflowProcessInstance) processInstance).getNodeInstances().iterator().next();
+		Map<String, Object> parameters = new HashMap<String, Object>();
+		parameters.put("x", "NewValue");
+		assertNull(handler.getWorkItem());
+		assertEquals(0, dynamicContext.getNodeInstances().size());
+		DynamicUtils.addDynamicSubProcess(dynamicContext, ksession, "org.drools.subflow", parameters);
+		assertNotNull(handler.getWorkItem());
+		assertEquals(1, dynamicContext.getNodeInstances().size());
+		logger.close();
+    }
+
     private static class TestWorkItemHandler implements WorkItemHandler {
         private WorkItem workItem;
         public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {

Added: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessRuleFlowGroupTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessRuleFlowGroupTest.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessRuleFlowGroupTest.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -0,0 +1,73 @@
+package org.drools.integrationtests;
+
+import java.io.Reader;
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.drools.Person;
+import org.drools.RuleBase;
+import org.drools.RuleBaseFactory;
+import org.drools.WorkingMemory;
+import org.drools.compiler.PackageBuilder;
+import org.drools.process.instance.ProcessInstance;
+import org.drools.rule.Package;
+import org.drools.ruleflow.instance.RuleFlowProcessInstance;
+
+public class ProcessRuleFlowGroupTest extends TestCase {
+    
+    public void testRuleSetProcessContext() throws Exception {
+        PackageBuilder builder = new PackageBuilder();
+        Reader source = new StringReader(
+            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+            "<process xmlns=\"http://drools.org/drools-5.0/process\"\n" +
+            "         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+            "         xs:schemaLocation=\"http://drools.org/drools-5.0/process drools-processes-5.0.xsd\"\n" +
+            "         type=\"RuleFlow\" name=\"flow\" id=\"org.drools.ruleset\" package-name=\"org.drools\" version=\"1\" >\n" +
+            "\n" +
+            "  <header>\n" +
+            "  </header>\n" +
+            "\n" +
+            "  <nodes>\n" +
+            "    <start id=\"1\" name=\"Start\" />\n" +
+            "    <ruleSet id=\"2\" name=\"RuleSet\" ruleFlowGroup=\"MyGroup\" >\n" +
+            "    </ruleSet>\n" +
+            "    <end id=\"3\" name=\"End\" />\n" +
+            "  </nodes>\n" +
+            "\n" +
+            "  <connections>\n" +
+            "    <connection from=\"1\" to=\"2\" />\n" +
+            "    <connection from=\"2\" to=\"3\" />\n" +
+            "  </connections>\n" +
+            "\n" +
+            "</process>");
+        Reader source2 = new StringReader(
+            "package org.drools;\n" +
+            "\n" +
+            "import org.drools.Person;\n" +
+            "import org.drools.runtime.process.ProcessContext;\n" +
+            "\n" +
+            "rule MyRule ruleflow-group \"MyGroup\"\n" +
+            "  when\n" +
+            "    Person( age > 25 )\n" +
+            "  then\n" +
+            "    System.out.println(drools.getContext(ProcessContext.class).getProcessInstance().getProcessName());\n" +
+            "end");
+        builder.addRuleFlow(source);
+        builder.addPackageFromDrl(source2);
+        Package pkg = builder.getPackage();
+        RuleBase ruleBase = RuleBaseFactory.newRuleBase();
+        ruleBase.addPackage( pkg );
+        WorkingMemory workingMemory = ruleBase.newStatefulSession();
+        Person person = new Person();
+        person.setAge(30);
+        workingMemory.insert(person);
+        // start process
+        RuleFlowProcessInstance processInstance = (RuleFlowProcessInstance)
+            workingMemory.startProcess("org.drools.ruleset");
+        assertEquals(ProcessInstance.STATE_ACTIVE, processInstance.getState());
+        workingMemory.fireAllRules();
+        assertEquals(ProcessInstance.STATE_COMPLETED, processInstance.getState());
+    }
+
+}

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/Agenda.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/Agenda.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/Agenda.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -48,6 +48,16 @@
      * its activations are automatically added to the agenda. 
      */
     public void activateRuleFlowGroup(String name);
+    
+    /**
+     * Activates the <code>RuleFlowGroup</code> with the given name.
+     * All activations in the given <code>RuleFlowGroup</code> are added to the agenda.
+     * As long as the <code>RuleFlowGroup</code> remains active,
+     * its activations are automatically added to the agenda.
+     * The given processInstanceId and nodeInstanceId define the process context
+     * in which this <code>RuleFlowGroup</code> is used.
+     */
+    public void activateRuleFlowGroup(String name, long processInstanceId, String nodeInstanceId);
 
     /**
      * Deactivates the <code>RuleFlowGroup</code> with the given name.

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/audit/WorkingMemoryLogger.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/audit/WorkingMemoryLogger.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/audit/WorkingMemoryLogger.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -459,6 +459,9 @@
     
     private String createNodeId(NodeInstance nodeInstance) {
     	Node node = ((org.drools.workflow.instance.NodeInstance) nodeInstance).getNode();
+    	if (node == null) {
+    		return "";
+    	}
     	String nodeId = "" + node.getId();
     	NodeContainer nodeContainer = node.getNodeContainer();
     	while (nodeContainer != null) {

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/DefaultKnowledgeHelper.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/DefaultKnowledgeHelper.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/DefaultKnowledgeHelper.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -27,7 +27,10 @@
 import org.drools.FactException;
 import org.drools.FactHandle;
 import org.drools.WorkingMemory;
+import org.drools.common.InternalFactHandle;
+import org.drools.common.InternalRuleFlowGroup;
 import org.drools.common.InternalWorkingMemoryActions;
+import org.drools.common.InternalWorkingMemoryEntryPoint;
 import org.drools.impl.StatefulKnowledgeSessionImpl;
 import org.drools.reteoo.ReteooWorkingMemory;
 import org.drools.rule.Declaration;
@@ -35,11 +38,12 @@
 import org.drools.rule.Rule;
 import org.drools.runtime.ExitPoint;
 import org.drools.runtime.KnowledgeRuntime;
+import org.drools.runtime.process.NodeInstance;
+import org.drools.runtime.process.NodeInstanceContainer;
+import org.drools.runtime.process.ProcessContext;
+import org.drools.runtime.process.ProcessInstance;
+import org.drools.runtime.process.WorkflowProcessInstance;
 import org.drools.runtime.rule.WorkingMemoryEntryPoint;
-import org.drools.FactHandle;
-import org.drools.WorkingMemory;
-import org.drools.common.InternalFactHandle;
-import org.drools.common.InternalWorkingMemoryEntryPoint;
 import org.drools.common.LogicalDependency;
 import org.drools.core.util.LinkedList;
 import org.drools.spi.Activation;
@@ -303,5 +307,43 @@
         }
         return handle;
     }
+    
+    @SuppressWarnings("unchecked")
+	public <T> T getContext(Class<T> contextClass) {
+    	if (ProcessContext.class.equals(contextClass)) {
+    		String ruleflowGroupName = getActivation().getRule().getRuleFlowGroup();
+    		if (ruleflowGroupName != null) {
+    			Map<Long, String> nodeInstances = ((InternalRuleFlowGroup) workingMemory.getAgenda().getRuleFlowGroup(ruleflowGroupName)).getNodeInstances();
+    			if (!nodeInstances.isEmpty()) {
+    				if (nodeInstances.size() > 1) {
+    					// TODO
+    					throw new UnsupportedOperationException(
+							"Not supporting multiple node instances for the same ruleflow group");
+    				}
+    				Map.Entry<Long, String> entry = nodeInstances.entrySet().iterator().next();
+    				ProcessInstance processInstance = workingMemory.getProcessInstance(entry.getKey());
+    				org.drools.spi.ProcessContext context = new org.drools.spi.ProcessContext();
+    				context.setProcessInstance((org.drools.process.instance.ProcessInstance) processInstance);
+    				String nodeInstance = entry.getValue();
+    				String[] nodeInstanceIds = nodeInstance.split(":");
+    				NodeInstanceContainer container = (WorkflowProcessInstance) processInstance;
+    				for (int i = 0; i < nodeInstanceIds.length; i++) {
+    					for (NodeInstance subNodeInstance: container.getNodeInstances()) {
+    						if (subNodeInstance.getId() == new Long(nodeInstanceIds[i])) {
+    							if (i == nodeInstanceIds.length - 1) {
+    								context.setNodeInstance(subNodeInstance);
+    								break;
+    							} else {
+    								container = (NodeInstanceContainer) subNodeInstance;
+    							}
+    						}
+    					}
+    				}
+    				return (T) context;
+    			}
+    		}
+    	}
+    	return null;
+    }
 
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/SequentialKnowledgeHelper.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/SequentialKnowledgeHelper.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/SequentialKnowledgeHelper.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -21,9 +21,10 @@
 import java.util.Map;
 
 import org.drools.FactException;
+import org.drools.FactHandle;
+import org.drools.WorkingMemory;
 import org.drools.common.InternalWorkingMemoryActions;
 import org.drools.impl.StatefulKnowledgeSessionImpl;
-import org.drools.reteoo.ReteooStatefulSession;
 import org.drools.reteoo.ReteooWorkingMemory;
 import org.drools.rule.Declaration;
 import org.drools.rule.GroupElement;
@@ -31,8 +32,6 @@
 import org.drools.runtime.ExitPoint;
 import org.drools.runtime.KnowledgeRuntime;
 import org.drools.runtime.rule.WorkingMemoryEntryPoint;
-import org.drools.FactHandle;
-import org.drools.WorkingMemory;
 import org.drools.spi.Activation;
 import org.drools.spi.KnowledgeHelper;
 import org.drools.spi.Tuple;
@@ -216,8 +215,14 @@
         this.identityMap = identityMap;
     }
 
+	public <T> T getContext(Class<T> contextClass) {
+		// TODO
+		return null;
+	}
+
     public void cancelRemainingPreviousLogicalDependencies() {
         // TODO Auto-generated method stub
         
     }
+
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/DefaultAgenda.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/DefaultAgenda.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/DefaultAgenda.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -571,6 +571,12 @@
         ((InternalRuleFlowGroup) getRuleFlowGroup( name )).setActive( true );
     }
 
+    public void activateRuleFlowGroup(final String name, long processInstanceId, String nodeInstanceId) {
+    	InternalRuleFlowGroup ruleFlowGroup = (InternalRuleFlowGroup) getRuleFlowGroup( name );
+    	ruleFlowGroup.addNodeInstance(processInstanceId, nodeInstanceId);
+        ruleFlowGroup.setActive( true );
+    }
+
     public void deactivateRuleFlowGroup(final String name) {
         ((InternalRuleFlowGroup) getRuleFlowGroup( name )).setActive( false );
     }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/InternalRuleFlowGroup.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/InternalRuleFlowGroup.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/InternalRuleFlowGroup.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -1,5 +1,7 @@
 package org.drools.common;
 
+import java.util.Map;
+
 import org.drools.spi.Activation;
 import org.drools.spi.RuleFlowGroup;
 
@@ -34,4 +36,10 @@
     
     void removeRuleFlowGroupListener(RuleFlowGroupListener listener);
     
+    void addNodeInstance(Long processInstanceId, String nodeInstanceId);
+
+    void removeNodeInstance(Long processInstanceId, String nodeInstanceId);
+    
+    Map<Long, String> getNodeInstances();
+    
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/RuleFlowGroupImpl.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/RuleFlowGroupImpl.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/RuleFlowGroupImpl.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -19,7 +19,9 @@
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.drools.core.util.Iterator;
@@ -54,6 +56,7 @@
     private boolean                     autoDeactivate   = true;    
     private LinkedList                  list;
     private List<RuleFlowGroupListener> listeners;
+    private Map<Long, String>           nodeInstances    = new HashMap<Long, String>();
 
     public RuleFlowGroupImpl() {
 
@@ -139,6 +142,7 @@
                     activation.getActivationGroupNode().getActivationGroup().removeActivation( activation );
                 }
             }
+            nodeInstances.clear();
             notifyRuleFlowGroupListeners();
             ((EventSupport) this.workingMemory).getRuleFlowEventSupport().fireAfterRuleFlowGroupDeactivated( this,
                                                                                                              this.workingMemory );
@@ -289,4 +293,17 @@
             }
         }
     }
+    
+    public void addNodeInstance(Long processInstanceId, String nodeInstanceId) {
+    	nodeInstances.put(processInstanceId, nodeInstanceId);
+    }
+
+    public void removeNodeInstance(Long processInstanceId, String nodeInstanceId) {
+    	nodeInstances.put(processInstanceId, nodeInstanceId);
+    }
+    
+    public Map<Long, String> getNodeInstances() {
+    	return nodeInstances;
+    }
+    
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/impl/AbstractProcessInstanceMarshaller.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/impl/AbstractProcessInstanceMarshaller.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/impl/AbstractProcessInstanceMarshaller.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -26,6 +26,7 @@
 import org.drools.workflow.instance.impl.NodeInstanceImpl;
 import org.drools.workflow.instance.impl.WorkflowProcessInstanceImpl;
 import org.drools.workflow.instance.node.CompositeContextNodeInstance;
+import org.drools.workflow.instance.node.DynamicNodeInstance;
 import org.drools.workflow.instance.node.ForEachNodeInstance;
 import org.drools.workflow.instance.node.HumanTaskNodeInstance;
 import org.drools.workflow.instance.node.JoinInstance;
@@ -175,6 +176,52 @@
             } else {
                 stream.writeInt(0);
             }
+        } else if (nodeInstance instanceof DynamicNodeInstance) {
+            stream.writeShort(PersisterEnums.DYNAMIC_NODE_INSTANCE);
+            DynamicNodeInstance dynamicNodeInstance = (DynamicNodeInstance) nodeInstance;
+            List<Long> timerInstances = dynamicNodeInstance.getTimerInstances();
+            if (timerInstances != null) {
+                stream.writeInt(timerInstances.size());
+                for (Long id : timerInstances) {
+                    stream.writeLong(id);
+                }
+            } else {
+                stream.writeInt(0);
+            }
+            VariableScopeInstance variableScopeInstance = (VariableScopeInstance) dynamicNodeInstance.getContextInstance(VariableScope.VARIABLE_SCOPE);
+            if (variableScopeInstance == null) {
+            	stream.writeInt(0);
+            } else {
+	            Map<String, Object> variables = variableScopeInstance.getVariables();
+	            List<String> keys = new ArrayList<String>(variables.keySet());
+	            Collections.sort(keys,
+	                    new Comparator<String>() {
+	                        public int compare(String o1,
+	                                String o2) {
+	                            return o1.compareTo(o2);
+	                        }
+	                    });
+	            stream.writeInt(keys.size());
+	            for (String key : keys) {
+	                stream.writeUTF(key);
+	                stream.writeObject(variables.get(key));
+	            }
+            }
+            List<NodeInstance> nodeInstances = new ArrayList<NodeInstance>(dynamicNodeInstance.getNodeInstances());
+            Collections.sort(nodeInstances,
+                    new Comparator<NodeInstance>() {
+
+                        public int compare(NodeInstance o1,
+                                NodeInstance o2) {
+                            return (int) (o1.getId() - o2.getId());
+                        }
+                    });
+            for (NodeInstance subNodeInstance : nodeInstances) {
+                stream.writeShort(PersisterEnums.NODE_INSTANCE);
+                writeNodeInstance(context,
+                        subNodeInstance);
+            }
+            stream.writeShort(PersisterEnums.END);
         } else if (nodeInstance instanceof CompositeContextNodeInstance) {
             stream.writeShort(PersisterEnums.COMPOSITE_NODE_INSTANCE);
             CompositeContextNodeInstance compositeNodeInstance = (CompositeContextNodeInstance) nodeInstance;
@@ -327,6 +374,7 @@
 
         switch (nodeType) {
             case PersisterEnums.COMPOSITE_NODE_INSTANCE:
+            case PersisterEnums.DYNAMIC_NODE_INSTANCE:
                 int nbVariables = stream.readInt();
                 if (nbVariables > 0) {
                     Context variableScope = ((org.drools.process.core.Process) processInstance.getProcess()).getDefaultContext(VariableScope.VARIABLE_SCOPE);
@@ -347,7 +395,7 @@
                             (CompositeContextNodeInstance) nodeInstance,
                             processInstance);
                 }
-                break;
+                // don't break just yet, also do below
             case PersisterEnums.FOR_EACH_NODE_INSTANCE:
                 while (stream.readShort() == PersisterEnums.NODE_INSTANCE) {
                     readNodeInstance(context,
@@ -425,6 +473,9 @@
             case PersisterEnums.FOR_EACH_NODE_INSTANCE:
                 nodeInstance = new ForEachNodeInstance();
                 break;
+            case PersisterEnums.DYNAMIC_NODE_INSTANCE:
+                nodeInstance = new DynamicNodeInstance();
+                break;
             case PersisterEnums.STATE_NODE_INSTANCE:
                 nodeInstance = new StateNodeInstance();
                 nbTimerInstances = stream.readInt();

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/impl/PersisterEnums.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/impl/PersisterEnums.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/impl/PersisterEnums.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -40,5 +40,6 @@
     public static final short FOR_EACH_NODE_INSTANCE    = 28;
     public static final short TIMER                     = 29;
     public static final short STATE_NODE_INSTANCE       = 30;
+    public static final short DYNAMIC_NODE_INSTANCE     = 31;
 
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/KnowledgeHelper.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/KnowledgeHelper.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/KnowledgeHelper.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -124,4 +124,6 @@
      public IdentityHashMap<Object, FactHandle> getIdentityMap();
 
     public void setIdentityMap(IdentityHashMap<Object, FactHandle> identityMap);
+    
+    <T> T getContext(Class<T> contextClass);
 }
\ No newline at end of file

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	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/CompositeNode.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -24,7 +24,8 @@
     private org.drools.workflow.core.NodeContainer nodeContainer;
     private Map<String, CompositeNode.NodeAndType> inConnectionMap = new HashMap<String, CompositeNode.NodeAndType>();
     private Map<String, CompositeNode.NodeAndType> outConnectionMap = new HashMap<String, CompositeNode.NodeAndType>();
-    
+	private boolean cancelRemainingInstances = true;
+	
     public CompositeNode() {
         this.nodeContainer = new NodeContainerImpl();
     }
@@ -321,6 +322,14 @@
         }
     }
     
+	public boolean isCancelRemainingInstances() {
+		return cancelRemainingInstances;
+	}
+
+	public void setCancelRemainingInstances(boolean cancelRemainingInstances) {
+		this.cancelRemainingInstances = cancelRemainingInstances;
+	}
+
     public class NodeAndType implements Serializable {
 
 		private static final long serialVersionUID = 1L;

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/DynamicNode.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/DynamicNode.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/DynamicNode.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -1,7 +1,35 @@
 package org.drools.workflow.core.node;
 
+import org.drools.definition.process.Node;
+
 public class DynamicNode extends CompositeContextNode {
 
 	private static final long serialVersionUID = 400L;
 	
+	private boolean autoComplete = false;
+		
+	public boolean isAutoComplete() {
+		return autoComplete;
+	}
+
+	public void setAutoComplete(boolean autoComplete) {
+		this.autoComplete = autoComplete;
+	}
+
+	public boolean acceptsEvent(String type, Object event) {
+		for (Node node: getNodes()) {
+			if (type.equals(node.getName()) && node.getIncomingConnections().isEmpty()) {
+				return true;
+			}
+		}
+		return super.acceptsEvent(type, event);
+	}
+	
+    public Node internalGetNode(long id) {
+    	try {
+    		return getNode(id);
+    	} catch (IllegalArgumentException e) {
+    		return null;
+    	}
+    }
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/ExtendedNodeInstanceImpl.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/ExtendedNodeInstanceImpl.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/ExtendedNodeInstanceImpl.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -38,7 +38,11 @@
 	}
 	
 	protected void triggerEvent(String type) {
-		List<DroolsAction> actions = getExtendedNode().getActions(type);
+		ExtendedNodeImpl extendedNode = getExtendedNode();
+		if (extendedNode == null) {
+			return;
+		}
+		List<DroolsAction> actions = extendedNode.getActions(type);
 		if (actions != null) {
 			KnowledgeHelper knowledgeHelper = createKnowledgeHelper();
 			for (DroolsAction droolsAction: actions) {

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/NodeInstanceImpl.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/NodeInstanceImpl.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/NodeInstanceImpl.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -33,6 +33,7 @@
 import org.drools.runtime.process.NodeInstanceContainer;
 import org.drools.workflow.core.impl.NodeImpl;
 import org.drools.workflow.instance.WorkflowProcessInstance;
+import org.drools.workflow.instance.node.CompositeNodeInstance;
 
 /**
  * Default implementation of a RuleFlow node instance.
@@ -65,7 +66,8 @@
     }
     
     public String getNodeName() {
-    	return getNode().getName();
+    	Node node = getNode();
+    	return node == null ? "" : node.getName();
     }
 
     public void setProcessInstance(final WorkflowProcessInstance processInstance) {
@@ -122,18 +124,23 @@
             ((org.drools.workflow.instance.NodeInstanceContainer) getNodeInstanceContainer())
             	.removeNodeInstance(this);
         }
-        List<Connection> connections = getNode().getOutgoingConnections(type);
+        Node node = getNode();
+        List<Connection> connections = null;
+        if (node != null) {
+        	connections = node.getOutgoingConnections(type);
+        }
         if (connections == null || connections.isEmpty()) {
         	((org.drools.workflow.instance.NodeInstanceContainer) getNodeInstanceContainer())
         		.nodeInstanceCompleted(this, type);
+        } else {
+	        for (Connection connection: connections) {
+	        	// stop if this process instance has been aborted / completed
+	        	if (getProcessInstance().getState() != ProcessInstance.STATE_ACTIVE) {
+	        		return;
+	        	}
+	    		triggerConnection(connection);
+	        }
         }
-        for (Connection connection: connections) {
-        	// stop if this process instance has been aborted / completed
-        	if (getProcessInstance().getState() != ProcessInstance.STATE_ACTIVE) {
-        		return;
-        	}
-    		triggerConnection(connection);
-        }
     }
     
     protected void triggerConnection(Connection connection) {
@@ -201,4 +208,15 @@
     	}
     }
     
+    public String getUniqueId() {
+    	String result = "" + getId();
+    	NodeInstanceContainer parent = getNodeInstanceContainer();
+    	while (parent instanceof CompositeNodeInstance) {
+    		CompositeNodeInstance nodeInstance = (CompositeNodeInstance) parent;
+    		result = nodeInstance.getId() + ":" + result;
+    		parent = nodeInstance.getNodeInstanceContainer();
+    	}
+    	return result;
+    }
+    
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/WorkflowProcessInstanceImpl.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/WorkflowProcessInstanceImpl.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/WorkflowProcessInstanceImpl.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -38,6 +38,7 @@
 import org.drools.process.instance.impl.ProcessInstanceImpl;
 import org.drools.runtime.process.EventListener;
 import org.drools.runtime.process.NodeInstanceContainer;
+import org.drools.workflow.core.impl.NodeImpl;
 import org.drools.workflow.core.node.EventNode;
 import org.drools.workflow.core.node.EventNodeInterface;
 import org.drools.workflow.instance.NodeInstance;
@@ -102,6 +103,21 @@
 		return Collections.unmodifiableCollection(result);
 	}
 
+	public List<String> getActiveNodeIds() {
+		List<String> result = new ArrayList<String>();
+		addActiveNodeIds(this, result);
+		return result;
+	}
+	
+	private void addActiveNodeIds(NodeInstanceContainer container, List<String> result) {
+		for (org.drools.runtime.process.NodeInstance nodeInstance: container.getNodeInstances()) {
+			result.add(((NodeImpl) ((NodeInstanceImpl) nodeInstance).getNode()).getUniqueId());
+			if (nodeInstance instanceof NodeInstanceContainer) {
+				addActiveNodeIds((NodeInstanceContainer) nodeInstance, result);
+			}
+		}
+	}
+
 	public NodeInstance getFirstNodeInstance(final long nodeId) {
 		for (final Iterator<NodeInstance> iterator = this.nodeInstances
 				.iterator(); iterator.hasNext();) {

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	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/CompositeNodeInstance.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -126,10 +126,13 @@
     }
 
     public void triggerCompleted(String outType) {
-        triggerCompleted(outType, true);
-        while (!nodeInstances.isEmpty()) {
-            NodeInstance nodeInstance = (NodeInstance) nodeInstances.get(0);
-            ((org.drools.workflow.instance.NodeInstance) nodeInstance).cancel();
+    	boolean cancelRemainingInstances = getCompositeNode().isCancelRemainingInstances();
+        triggerCompleted(outType, cancelRemainingInstances);
+        if (cancelRemainingInstances) {
+	        while (!nodeInstances.isEmpty()) {
+	            NodeInstance nodeInstance = (NodeInstance) nodeInstances.get(0);
+	            ((org.drools.workflow.instance.NodeInstance) nodeInstance).cancel();
+	        }
         }
     }
 

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/DynamicNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/DynamicNodeInstance.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/DynamicNodeInstance.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -1,45 +1,53 @@
 package org.drools.workflow.instance.node;
 
-import java.util.List;
-import java.util.Map;
-
-import org.drools.definition.process.Connection;
 import org.drools.definition.process.Node;
 import org.drools.runtime.process.NodeInstance;
 import org.drools.workflow.core.impl.NodeImpl;
+import org.drools.workflow.core.node.DynamicNode;
 
 public class DynamicNodeInstance extends CompositeContextNodeInstance {
 
 	private static final long serialVersionUID = 4L;
 	
-	private transient boolean executing = false;
+	private String getRuleFlowGroupName() {
+		return getNodeName();
+	}
 	
+	protected DynamicNode getDynamicNode() {
+		return (DynamicNode) getNode();
+	}
+	
     public void internalTrigger(NodeInstance from, String type) {
-    	executing = true;
-    	createNodeInstances();
-    	executing = false;
-    	if (getNodeInstances(false).isEmpty()) {
-    		triggerCompleted(NodeImpl.CONNECTION_DEFAULT_TYPE);
-    	}
+    	getProcessInstance().getWorkingMemory().getAgenda().getRuleFlowGroup(getRuleFlowGroupName()).setAutoDeactivate(false);
+    	getProcessInstance().getWorkingMemory().getAgenda().activateRuleFlowGroup(
+			getRuleFlowGroupName(), getProcessInstance().getId(), getUniqueId());
+//    	if (getDynamicNode().isAutoComplete() && getNodeInstances(false).isEmpty()) {
+//    		triggerCompleted(NodeImpl.CONNECTION_DEFAULT_TYPE);
+//    	}
     }
-    
-    private void createNodeInstances() {
-    	for (Node node: getCompositeNode().getNodes()) {
-    		Map<String, List<Connection>> incomingConnections = node.getIncomingConnections();
-    		if (incomingConnections.isEmpty()) {
-    			NodeInstance nodeInstance = getNodeInstance(node);
-                ((org.drools.workflow.instance.NodeInstance) nodeInstance)
-                	.trigger(null, NodeImpl.CONNECTION_DEFAULT_TYPE);
-    		}
-    	}
-    }
 
 	public void nodeInstanceCompleted(org.drools.workflow.instance.NodeInstance nodeInstance, String outType) {
 		// TODO what if we reach the end of one branch but others might still need to be created ?
 		// TODO are we sure there will always be node instances left if we are not done yet?
-		if (!executing && getNodeInstances(false).isEmpty()) {
+		if (getDynamicNode().isAutoComplete() && getNodeInstances(false).isEmpty()) {
     		triggerCompleted(NodeImpl.CONNECTION_DEFAULT_TYPE);
     	}
 	}
+	
+    public void triggerCompleted(String outType) {
+    	getProcessInstance().getWorkingMemory().getAgenda().deactivateRuleFlowGroup(getRuleFlowGroupName());
+    	super.triggerCompleted(outType);
+    }
 
+	public void signalEvent(String type, Object event) {
+		super.signalEvent(type, event);
+		for (Node node: getCompositeNode().getNodes()) {
+			if (type.equals(node.getName()) && node.getIncomingConnections().isEmpty()) {
+    			NodeInstance nodeInstance = getNodeInstance(node);
+                ((org.drools.workflow.instance.NodeInstance) nodeInstance)
+                	.trigger(null, NodeImpl.CONNECTION_DEFAULT_TYPE);
+    		}
+		}
+	}
+	
 }

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/DynamicUtils.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/DynamicUtils.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/DynamicUtils.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -0,0 +1,67 @@
+package org.drools.workflow.instance.node;
+
+import java.util.Map;
+
+import org.drools.common.EventSupport;
+import org.drools.common.InternalRuleBase;
+import org.drools.common.InternalWorkingMemory;
+import org.drools.definition.process.Process;
+import org.drools.impl.StatefulKnowledgeSessionImpl;
+import org.drools.process.instance.ProcessInstance;
+import org.drools.process.instance.WorkItemManager;
+import org.drools.process.instance.impl.WorkItemImpl;
+import org.drools.runtime.process.ProcessRuntime;
+import org.drools.runtime.process.WorkItem;
+import org.drools.workflow.instance.WorkflowProcessInstance;
+
+
+public class DynamicUtils {
+	
+	public static void addDynamicWorkItem(
+			DynamicNodeInstance dynamicContext, ProcessRuntime ksession,
+			String workItemName, Map<String, Object> parameters) {
+		WorkflowProcessInstance processInstance = dynamicContext.getProcessInstance();
+		WorkItemImpl workItem = new WorkItemImpl();
+		workItem.setState(WorkItem.ACTIVE);
+		workItem.setProcessInstanceId(processInstance.getId());
+		workItem.setName(workItemName);
+		workItem.setParameters(parameters);
+		WorkItemNodeInstance workItemNodeInstance = new WorkItemNodeInstance();
+    	workItemNodeInstance.setNodeInstanceContainer(dynamicContext);
+		workItemNodeInstance.setProcessInstance(processInstance);
+		workItemNodeInstance.internalSetWorkItem(workItem);
+    	workItemNodeInstance.addEventListeners();
+		InternalWorkingMemory workingMemory = ((StatefulKnowledgeSessionImpl) ksession).session;
+		((EventSupport) workingMemory).getRuleFlowEventSupport().fireBeforeRuleFlowNodeTriggered(workItemNodeInstance, workingMemory);
+		((WorkItemManager) ksession.getWorkItemManager()).internalExecuteWorkItem(workItem);
+        ((EventSupport) workingMemory).getRuleFlowEventSupport().fireAfterRuleFlowNodeTriggered(workItemNodeInstance, (InternalWorkingMemory) workingMemory);
+	}
+
+	public static void addDynamicSubProcess(
+			DynamicNodeInstance dynamicContext, ProcessRuntime ksession,
+			String processId, Map<String, Object> parameters) {
+		WorkflowProcessInstance processInstance = dynamicContext.getProcessInstance();
+		SubProcessNodeInstance subProcessNodeInstance = new SubProcessNodeInstance();
+    	subProcessNodeInstance.setNodeInstanceContainer(dynamicContext);
+		subProcessNodeInstance.setProcessInstance(processInstance);
+		InternalWorkingMemory workingMemory = ((StatefulKnowledgeSessionImpl) ksession).session;
+		Process process = ((InternalRuleBase) workingMemory.getRuleBase()).getProcess(processId);
+        if (process == null) {
+        	System.err.println("Could not find process " + processId);
+        	System.err.println("Aborting process");
+        	processInstance.setState(ProcessInstance.STATE_ABORTED);
+        } else {
+        	((EventSupport) workingMemory).getRuleFlowEventSupport().fireBeforeRuleFlowNodeTriggered(subProcessNodeInstance, workingMemory);
+    		ProcessInstance subProcessInstance = (ProcessInstance)
+	    		workingMemory.startProcess(processId, parameters);
+    		((EventSupport) workingMemory).getRuleFlowEventSupport().fireAfterRuleFlowNodeTriggered(subProcessNodeInstance, (InternalWorkingMemory) workingMemory);
+    		if (subProcessInstance.getState() == ProcessInstance.STATE_COMPLETED) {
+	    		subProcessNodeInstance.triggerCompleted();
+	    	} else {
+	    		subProcessNodeInstance.internalSetProcessInstanceId(subProcessInstance.getId());
+	    	    subProcessNodeInstance.addEventListeners();
+	    	}
+        }
+	}
+
+}

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/RuleSetNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/RuleSetNodeInstance.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/RuleSetNodeInstance.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -39,7 +39,7 @@
             throw new IllegalArgumentException( "A RuleSetNode only accepts default incoming connections!" );
         }
         addRuleSetListener();
-        ((ProcessInstance) getProcessInstance()).getAgenda().activateRuleFlowGroup( getRuleSetNode().getRuleFlowGroup() );
+        ((ProcessInstance) getProcessInstance()).getAgenda().activateRuleFlowGroup( getRuleSetNode().getRuleFlowGroup(), getProcessInstance().getId(), getUniqueId() );
     }
 
     public void addEventListeners() {

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/SubProcessNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/SubProcessNodeInstance.java	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/SubProcessNodeInstance.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -22,9 +22,11 @@
 import java.util.regex.Pattern;
 
 import org.drools.common.InternalRuleBase;
+import org.drools.definition.process.Node;
 import org.drools.definition.process.Process;
 import org.drools.process.core.context.variable.VariableScope;
 import org.drools.process.instance.ProcessInstance;
+import org.drools.process.instance.WorkItem;
 import org.drools.process.instance.context.variable.VariableScopeInstance;
 import org.drools.runtime.process.EventListener;
 import org.drools.runtime.process.NodeInstance;
@@ -129,7 +131,7 @@
     
     public void cancel() {
         super.cancel();
-        if (!getSubProcessNode().isIndependent()) {
+        if (getSubProcessNode() == null || !getSubProcessNode().isIndependent()) {
             ProcessInstance processInstance = (ProcessInstance)
                 ((ProcessInstance) getProcessInstance()).getWorkingMemory()
                     .getProcessInstance(processInstanceId);
@@ -202,5 +204,13 @@
 	        }
 	    }
     }
+    
+    public String getNodeName() {
+    	Node node = getNode();
+    	if (node == null) {
+    		return "[Dynamic] Sub Process";
+    	}
+    	return super.getNodeName();
+    }
 
 }
\ No newline at end of file

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	2010-04-05 20:04:24 UTC (rev 32427)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/WorkItemNodeInstance.java	2010-04-05 21:58:53 UTC (rev 32428)
@@ -24,6 +24,7 @@
 
 import org.drools.WorkingMemory;
 import org.drools.common.InternalRuleBase;
+import org.drools.definition.process.Node;
 import org.drools.process.core.Work;
 import org.drools.process.core.context.variable.VariableScope;
 import org.drools.process.instance.ProcessInstance;
@@ -71,6 +72,10 @@
     	this.workItemId = workItemId;
     }
     
+    public void internalSetWorkItem(WorkItem workItem) {
+    	this.workItem = workItem;
+    }
+    
     public boolean isInversionOfControl() {
         return ((InternalRuleBase) ((ProcessInstance) getProcessInstance())
     		.getWorkingMemory().getRuleBase()).getConfiguration().isAdvancedProcessRuleIntegration();
@@ -165,26 +170,29 @@
     }
 
     public void triggerCompleted(WorkItem workItem) {
-        for (Iterator<Map.Entry<String, String>> iterator = getWorkItemNode().getOutMappings().entrySet().iterator(); iterator.hasNext(); ) {
-            Map.Entry<String, String> mapping = iterator.next();
-            VariableScopeInstance variableScopeInstance = (VariableScopeInstance)
-                resolveContextInstance(VariableScope.VARIABLE_SCOPE, mapping.getValue());
-            if (variableScopeInstance != null) {
-            	Object value = workItem.getResult(mapping.getKey());
-            	if (value == null) {
-            		try {
-                		value = MVEL.eval(mapping.getKey(), new WorkItemResolverFactory(workItem));
-                	} catch (Throwable t) {
-                		// do nothing
-                	}
-            	}
-                variableScopeInstance.setVariable(mapping.getValue(), value);
-            } else {
-                System.err.println("Could not find variable scope for variable " + mapping.getValue());
-                System.err.println("when trying to complete Work Item " + workItem.getName());
-                System.err.println("Continuing without setting variable.");
-            }
-        }
+    	WorkItemNode workItemNode = getWorkItemNode();
+    	if (workItemNode != null) {
+	        for (Iterator<Map.Entry<String, String>> iterator = getWorkItemNode().getOutMappings().entrySet().iterator(); iterator.hasNext(); ) {
+	            Map.Entry<String, String> mapping = iterator.next();
+	            VariableScopeInstance variableScopeInstance = (VariableScopeInstance)
+	                resolveContextInstance(VariableScope.VARIABLE_SCOPE, mapping.getValue());
+	            if (variableScopeInstance != null) {
+	            	Object value = workItem.getResult(mapping.getKey());
+	            	if (value == null) {
+	            		try {
+	                		value = MVEL.eval(mapping.getKey(), new WorkItemResolverFactory(workItem));
+	                	} catch (Throwable t) {
+	                		// do nothing
+	                	}
+	            	}
+	                variableScopeInstance.setVariable(mapping.getValue(), value);
+	            } else {
+	                System.err.println("Could not find variable scope for variable " + mapping.getValue());
+	                System.err.println("when trying to complete Work Item " + workItem.getName());
+	                System.err.println("Continuing without setting variable.");
+	            }
+	        }
+    	}
         if (isInversionOfControl()) {
             WorkingMemory workingMemory = ((ProcessInstance) getProcessInstance()).getWorkingMemory();
             workingMemory.update(workingMemory.getFactHandle(this), this);
@@ -247,4 +255,17 @@
         }
     }
     
+    public String getNodeName() {
+    	Node node = getNode();
+    	if (node == null) {
+    		String nodeName =  "[Dynamic]";
+    		WorkItem workItem = getWorkItem();
+    		if (workItem != null) {
+    			nodeName += " " + workItem.getParameter("TaskName");
+    		}
+    		return nodeName;
+    	}
+    	return super.getNodeName();
+    }
+    
 }
\ No newline at end of file



More information about the jboss-svn-commits mailing list