[jbpm-commits] JBoss JBPM SVN: r4828 - in jbpm4/trunk/modules: api/src/main/java/org/jbpm/api/activity and 7 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Sat May 16 06:33:16 EDT 2009


Author: tom.baeyens at jboss.com
Date: 2009-05-16 06:33:13 -0400 (Sat, 16 May 2009)
New Revision: 4828

Removed:
   jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/TransitionBasedConcurrencyTest.java
Modified:
   jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/Execution.java
   jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/activity/ActivityExecution.java
   jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForkActivity.java
   jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinActivity.java
   jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/SuperStateActivity.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/hibernate/ExecutionType.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ExecutionImpl.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/ExecuteActivityMessage.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/ProceedToDestinationMessage.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/SignalMessage.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/TakeTransitionMessage.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/AsyncCommandMessage.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskImpl.java
   jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ExecutionStateTest.java
   jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ScopeStateTest.java
   jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ScopeVariableTest.java
Log:
JBPM-2026 updated fork and join to fit with execution.state updates in context of adding super-state

Modified: jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/Execution.java
===================================================================
--- jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/Execution.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/Execution.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -35,12 +35,12 @@
  * <h3 id="state">State of an execution</h3>
  * 
  * <p>The state of an execution is either active or locked.  An active execution is either 
- * executing or waiting for an external trigger.  If an execution is not in {@link #STATE_ACTIVE},
+ * executing or waiting for an external trigger.  If an execution is not in {@link #STATE_ACTIVE_ROOT},
  * then it is locked.  A locked execution is read only.  
  * </p>
  * 
- * <p>When a new execution is created, it is in {@link #STATE_ACTIVE}.  
- * {@link #STATE_ACTIVE Some STATE_* constants} are provided that represent the 
+ * <p>When a new execution is created, it is in {@link #STATE_ACTIVE_ROOT}.  
+ * {@link #STATE_ACTIVE_ROOT Some STATE_* constants} are provided that represent the 
  * most commonly used locked states.  But the state '...' in the picture indicates 
  * that any string can be provided as the state in the lock method.
  * </p>
@@ -58,7 +58,7 @@
  * </p>    
  * 
  * <p>Make sure that comparisons between {@link #getState()} and the 
- * {@link #STATE_ACTIVE STATE_* constants} are  
+ * {@link #STATE_ACTIVE_ROOT STATE_* constants} are  
  * done with .equals and not with '==' because if executions are 
  * loaded from persistent storage, a new string is created instead 
  * of the constants.
@@ -77,15 +77,31 @@
    * initializations of variables and timers */
   String STATE_CREATED = "created";
   
-  /** either executing or in a wait state waiting for a signal.
+  /** single (non-concurrent) path of execution that is an active indicator 
+   * of the current position in the diagram.  jBPM can be executing automatic 
+   * activities or some external entity might be responsible for continuing the 
+   * execution (wait state for jBPM).  An active execution is always 
+   * a leaf in the execution tree.  
    * This is the normal state of an execution and the initial state 
    * when creating a new execution. Make sure that comparisons are 
    * done with .equals and not with '==' because if executions are 
    * loaded from persistent storage, a new string is created instead 
    * of the constants. */
-  String STATE_ACTIVE = "active";
-  
-  /** parents with concurrent child executions are inactive.  
+  String STATE_ACTIVE_ROOT = "active-root";
+
+  /** concurrent path of execution that is an active indicator 
+   * of the current position in the diagram.  The parent of an active 
+   * concurrent execution is always an inactive concurrent root.  jBPM can 
+   * be executing automatic 
+   * activities or some external entity might be responsible for continuing the 
+   * execution (wait state for jBPM).
+   * Make sure that comparisons are 
+   * done with .equals and not with '==' because if executions are 
+   * loaded from persistent storage, a new string is created instead 
+   * of the constants. */
+  String STATE_ACTIVE_CONCURRENT = "active-concurrent";
+
+  /** parent of concurrent child executions.  
    * When an execution has concurrent child executions, it implies that 
    * this execution can't be active.  For example, at a fork, the parent
    * execution can wait inactively in the fork being till all the
@@ -94,14 +110,26 @@
    * done with .equals and not with '==' because if executions are 
    * loaded from persistent storage, a new string is created instead 
    * of the constants. */
-  String STATE_INACTIVE = "inactive";
+  String STATE_INACTIVE_CONCURRENT_ROOT = "inactive-concurrent-root";
   
-  /** this execution has ended. Make sure that comparisons are 
+  /** parent of a scoped execution.  This execution is inactive, 
+   * but points to the parent scope like e.g. a super-state.
+   * This execution has exactly 1 child execution.  That indicates 
+   * the state inside of the scope.
+   * Make sure that comparisons are 
    * done with .equals and not with '==' because if executions are 
    * loaded from persistent storage, a new string is created instead 
    * of the constants. */
-  String STATE_ENDED = "ended";
-  
+  String STATE_INACTIVE_SCOPE = "inactive-scope";
+
+  /** concurrent execution that is inactively waiting in a join  
+   * until other concurrent executions arrive.
+   * Make sure that comparisons are 
+   * done with .equals and not with '==' because if executions are 
+   * loaded from persistent storage, a new string is created instead 
+   * of the constants. */
+  String STATE_INACTIVE_JOIN = "inactive-join";
+
   /** indicates that this execution is temporary suspended with the
    * {@link #suspend()} method.  Human tasks of a suspended execution
    * shouldn't show up in people's task list and timers of suspended
@@ -114,6 +142,12 @@
   /** indicates that this execution is doing an asynchronous continuation. */
   String STATE_ASYNC = "async";
 
+  /** this execution has ended. Make sure that comparisons are 
+   * done with .equals and not with '==' because if executions are 
+   * loaded from persistent storage, a new string is created instead 
+   * of the constants. */
+  String STATE_ENDED = "ended";
+
   /** the externally given name or id of this execution. The id of a main 
    * path of execution is null.   Can be used to differentiate concurrent 
    * paths of execution e.g. the shipping and billing paths.  */

Modified: jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/activity/ActivityExecution.java
===================================================================
--- jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/activity/ActivityExecution.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/activity/ActivityExecution.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -148,7 +148,7 @@
    * status.  
    * 
    * <p>It is not recommended to use any of 
-   * {@link #STATE_ACTIVE the defined statuses} as that may case unpredictable 
+   * {@link Execution the defined statuses in Execution} as that may case unpredictable 
    * side effects.</p>
    *  
    * <p>The execution will be removed from it's parent.</p> */

Modified: jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForkActivity.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForkActivity.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForkActivity.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -21,12 +21,13 @@
  */
 package org.jbpm.jpdl.internal.activity;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.jbpm.api.Execution;
 import org.jbpm.api.activity.ActivityExecution;
 import org.jbpm.api.model.Activity;
-import org.jbpm.api.model.OpenExecution;
+import org.jbpm.api.model.Condition;
 import org.jbpm.api.model.Transition;
 import org.jbpm.pvm.internal.model.ExecutionImpl;
 
@@ -38,25 +39,53 @@
 
   private static final long serialVersionUID = 1L;
   
-  public void execute(ActivityExecution execution) throws Exception {
-    OpenExecution processInstance = execution.getProcessInstance();
+  public void execute(ActivityExecution execution) {
+    execute((ExecutionImpl)execution);
+  }
 
+  public void execute(ExecutionImpl execution) {
     Activity activity = execution.getActivity();
+
+    // evaluate the conditions and find the transitions that should be forked
+    List<Transition> forkingTransitions = new ArrayList<Transition>();
     List<Transition> outgoingTransitions = activity.getOutgoingTransitions();
-
-    // for each outgoing transition
-    for (Transition outgoingTransition: outgoingTransitions) {
-      // launch a concurrent path of execution
-      String childExecutionName = outgoingTransition.getName();
-      // creating the execution will cause the execution to become inactive
-      ExecutionImpl executionImpl = (ExecutionImpl) execution;
-      Execution childExecution = executionImpl.createExecution(childExecutionName, processInstance);
-      execution.take(outgoingTransition, childExecution);
+    for (Transition transition: outgoingTransitions) {
+      Condition condition = transition.getCondition();
+      if  ( (condition==null)
+            || (condition.evaluate(execution))
+          ) {
+        forkingTransitions.add(transition);
+      }
     }
 
-    // if this was the first fork
-    if (execution.isProcessInstance()) {
-      execution.setActivity(null);
+    // if no outgoing transitions should be forked, 
+    if (forkingTransitions.size()==0) {
+      // end this execution
+      execution.end();
+      
+    // if there is exactly 1 transition to be taken, just use the incoming execution
+    } else if (forkingTransitions.size()==1) {
+      execution.take(forkingTransitions.get(0));
+      
+    // if there are more transitions
+    } else {
+      ExecutionImpl concurrentRoot = null;
+      if (Execution.STATE_ACTIVE_ROOT.equals(execution.getState())) {
+        concurrentRoot = execution;
+        execution.setState(Execution.STATE_INACTIVE_CONCURRENT_ROOT);
+        execution.setActivity(null);
+      } else if (Execution.STATE_ACTIVE_CONCURRENT.equals(execution.getState())) {
+        concurrentRoot = execution.getParent();
+      }
+
+      for (Transition transition: forkingTransitions) {
+        // launch a concurrent path of execution
+        String childExecutionName = transition.getName();
+        ExecutionImpl concurrentExecution = concurrentRoot.createExecution(childExecutionName);
+        concurrentExecution.setActivity(activity);
+        concurrentExecution.setState(Execution.STATE_ACTIVE_CONCURRENT);
+        concurrentExecution.take(transition);
+      }
     }
   }
 }

Modified: jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinActivity.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinActivity.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinActivity.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -26,6 +26,7 @@
 import java.util.List;
 
 import org.jbpm.api.Execution;
+import org.jbpm.api.JbpmException;
 import org.jbpm.api.activity.ActivityExecution;
 import org.jbpm.api.model.Activity;
 import org.jbpm.api.model.OpenExecution;
@@ -39,65 +40,76 @@
 public class JoinActivity extends JpdlActivity {
 
   private static final long serialVersionUID = 1L;
+  
+  int multiplicity = -1;
 
-  public void execute(ActivityExecution execution) throws Exception {
-    // end the child execution execution
-    // this will also remove the execution from it's parent
-    execution.setState(Execution.STATE_INACTIVE);
-    execution.waitForSignal();
+  public void execute(ActivityExecution execution) {
+    execute((ExecutionImpl)execution);
+  }
+
+  public void execute(ExecutionImpl execution) {
+    Activity activity = execution.getActivity();
     
-    Activity join = execution.getActivity();
-    List<OpenExecution> joinedExecutions = findJoinedExecutions(execution, join);
-    
-    if (isComplete(joinedExecutions, join)) {
-      endJoinedExecutions(joinedExecutions, execution);
+    // if this is a single, non concurrent root
+    if (Execution.STATE_ACTIVE_ROOT.equals(execution.getState())) {
+      // just pass through
+      Transition transition = activity.getDefaultOutgoingTransition();
+      execution.take(transition);
+      
+    } else if (Execution.STATE_ACTIVE_CONCURRENT.equals(execution.getState())) {
 
-      OpenExecution processInstance = execution.getProcessInstance();
+      execution.setState(Execution.STATE_INACTIVE_JOIN);
+      execution.waitForSignal();
+
+      ExecutionImpl concurrentRoot = execution.getParent();
+      List<ExecutionImpl> joinedExecutions = getJoinedExecutions(concurrentRoot, activity);
       
-      Execution outgoingExecution = null;
-      if ( processInstance.getExecutions()==null
-           || processInstance.getExecutions().isEmpty() 
-         ) {
-        outgoingExecution = processInstance;
-      } else {
-        ExecutionImpl executionImpl = (ExecutionImpl) execution;
-        outgoingExecution = executionImpl.createExecution(processInstance);
+      if (isComplete(joinedExecutions, activity)) {
+        endJoinedExecutions(joinedExecutions);
+
+        ExecutionImpl outgoingExecution = null;
+        if (concurrentRoot.getExecutions().size()==0) {
+          outgoingExecution = concurrentRoot;
+          outgoingExecution.setState(Execution.STATE_ACTIVE_ROOT);
+        } else {
+          outgoingExecution = concurrentRoot.createExecution();
+          outgoingExecution.setState(Execution.STATE_ACTIVE_CONCURRENT);
+        }
+
+        execution.setActivity(activity, outgoingExecution);
+        Transition transition = activity.getDefaultOutgoingTransition();
+        outgoingExecution.take(transition);
       }
       
-      execution.setActivity(join, outgoingExecution);
-      Transition transition = join.getDefaultOutgoingTransition();
-      execution.take(transition, outgoingExecution);
+    } else {
+      throw new JbpmException("invalid execution state");
     }
   }
   
-  List<OpenExecution> findJoinedExecutions(OpenExecution execution, Activity join) {
-    List<OpenExecution> joinedExecutions = new ArrayList<OpenExecution>();
-    scanRecursive((OpenExecution)execution.getProcessInstance(), join, joinedExecutions);
-    return joinedExecutions;
+  protected boolean isComplete(List<ExecutionImpl> joinedExecutions, Activity activity) {
+    int nbrOfExecutionsToJoin = multiplicity;
+    if (multiplicity==-1) {
+      nbrOfExecutionsToJoin = activity.getIncomingTransitions().size();
+    }
+    return joinedExecutions.size()==nbrOfExecutionsToJoin;
   }
 
-  void scanRecursive(OpenExecution execution, Activity join, List<OpenExecution> joinedExecutions) {
-    // if the execution is positioned in the join
-    if (join.equals(execution.getActivity())) {
-      joinedExecutions.add(execution);
-    }
-    Collection<OpenExecution> childExecutions = (Collection)execution.getExecutions();
-    if (childExecutions!=null) {
-      for (OpenExecution childExecution: childExecutions) {
-        scanRecursive(childExecution, join, joinedExecutions);
+  protected List<ExecutionImpl> getJoinedExecutions(ExecutionImpl concurrentRoot, Activity activity) {
+    List<ExecutionImpl> joinedExecutions = new ArrayList<ExecutionImpl>();
+    List concurrentExecutions = (List)concurrentRoot.getExecutions();
+    for (ExecutionImpl concurrentExecution: (List<ExecutionImpl>)concurrentExecutions) {
+      if ( (Execution.STATE_INACTIVE_JOIN.equals(concurrentExecution.getState()))
+           && (concurrentExecution.getActivity()==activity)
+         ) {
+        joinedExecutions.add(concurrentExecution);
       }
     }
+    return joinedExecutions;
   }
 
-  boolean isComplete(List<OpenExecution> joinedExecutions, Activity join) {
-    int executionsToJoin = join.getIncomingTransitions().size();
-    return (executionsToJoin==joinedExecutions.size());
-  }
-
-  void endJoinedExecutions(List<OpenExecution> joinedExecutions, ActivityExecution execution) {
-    for (OpenExecution joinedExecution: joinedExecutions) {
-      execution.end(joinedExecution);
+  protected void endJoinedExecutions(List<ExecutionImpl> joinedExecutions) {
+    for (ExecutionImpl joinedExecution: joinedExecutions) {
+      joinedExecution.end();
     }
   }
-
 }

Modified: jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/SuperStateActivity.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/SuperStateActivity.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/SuperStateActivity.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -25,11 +25,13 @@
 import java.util.List;
 import java.util.Map;
 
+import org.jbpm.api.Execution;
 import org.jbpm.api.JbpmException;
 import org.jbpm.api.activity.ActivityExecution;
 import org.jbpm.api.model.Activity;
 import org.jbpm.api.model.Transition;
 import org.jbpm.pvm.internal.model.ActivityImpl;
+import org.jbpm.pvm.internal.model.ExecutionImpl;
 
 
 /**
@@ -40,11 +42,31 @@
   private static final long serialVersionUID = 1L;
 
   public void execute(ActivityExecution execution) throws Exception {
+    execute((ExecutionImpl)execution);
+  }
+  public void execute(ExecutionImpl execution) throws Exception {
     // find the start activity
     Activity activity = execution.getActivity();
     List<Activity> startActivities = findStartActivities(activity);
     if (startActivities.size()==1) {
       execution.execute(startActivities.get(0));
+    } else {
+      
+      ExecutionImpl concurrentRoot = null;
+      if (Execution.STATE_ACTIVE_ROOT.equals(execution.getState())) {
+        concurrentRoot = execution;
+      } else if (Execution.STATE_ACTIVE_ROOT.equals(execution.getState())) {
+        concurrentRoot = execution.getParent();
+        
+      } else {
+        throw new JbpmException("illegal state");
+      }
+      
+      for (Activity startActivity: startActivities) {
+        ExecutionImpl concurrentExecution = concurrentRoot.createExecution();
+        concurrentExecution.setState(Execution.STATE_ACTIVE_CONCURRENT);
+        concurrentExecution.execute(startActivity);
+      }
     }
   }
 

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/hibernate/ExecutionType.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/hibernate/ExecutionType.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/hibernate/ExecutionType.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -42,7 +42,7 @@
     String activityName = rs.getString(names[0]);
     ActivityImpl activity = (ActivityImpl) execution.getProcessDefinition().getActivity(activityName);
     execution.setActivity(activity);
-    execution.setState(Execution.STATE_ACTIVE);
+    execution.setState(Execution.STATE_ACTIVE_ROOT);
     return execution;
   }
 

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ExecutionImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ExecutionImpl.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ExecutionImpl.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -191,7 +191,7 @@
     if (state!=STATE_CREATED) {
       throw new JbpmException(toString()+" is already begun: "+state);
     }
-    this.state = STATE_ACTIVE;
+    this.state = STATE_ACTIVE_ROOT;
     ExecutionImpl scopedExecution = initializeScopes();
     
     fireHistoryEvent(new ProcessInstanceStart());
@@ -235,6 +235,9 @@
   public ExecutionImpl createScope(ScopeElementImpl scope) {
     ExecutionImpl child = createExecution(scope.getName());
     
+    setState(STATE_INACTIVE_SCOPE);
+    child.setState(STATE_ACTIVE_ROOT);
+    
     // copy the current state from the child execution to the parent execution
     child.setActivity(getActivity());
     child.setTransition(getTransition());
@@ -253,13 +256,22 @@
     destroyTimers(scope);
     
     // copy the current state from the child execution to the parent execution
-    getParent().setActivity(getActivity());
-    getParent().setTransition(getTransition());
-    getParent().setPropagation(getPropagation());
-    getParent().setTransitionOrigin(getTransitionOrigin());
-    getParent().setPreviousTransition(getPreviousTransition());
-    getParent().setPreviousActivity(getPreviousActivity());
+    parent.setActivity(getActivity());
+    parent.setTransition(getTransition());
+    parent.setPropagation(getPropagation());
+    parent.setTransitionOrigin(getTransitionOrigin());
+    parent.setPreviousTransition(getPreviousTransition());
+    parent.setPreviousActivity(getPreviousActivity());
     
+    ExecutionImpl parentsParent = parent.getParent();
+    if ( (parentsParent!=null)
+         && (STATE_INACTIVE_CONCURRENT_ROOT.equals(parentsParent.getState()))
+       ) {
+      parent.setState(STATE_ACTIVE_CONCURRENT);
+    } else {
+      parent.setState(STATE_ACTIVE_ROOT);
+    }
+    
     end();
 
     return parent;
@@ -287,9 +299,13 @@
     if (state==null) {
       throw new JbpmException("state is null");
     }
-    if (state.equals(STATE_ACTIVE)
-        || state.equals(STATE_CREATED)
-        || state.equals(STATE_INACTIVE)
+
+    if (state.equals(STATE_CREATED)
+        || state.equals(STATE_ACTIVE_ROOT)
+        || state.equals(STATE_ACTIVE_CONCURRENT)
+        || state.equals(STATE_INACTIVE_CONCURRENT_ROOT)
+        || state.equals(STATE_INACTIVE_SCOPE)
+        || state.equals(STATE_INACTIVE_JOIN)
         || state.equals(STATE_SUSPENDED)
         || state.equals(STATE_ASYNC)) {
       throw new JbpmException("invalid end state: "+state);
@@ -730,47 +746,29 @@
 
   // child executions /////////////////////////////////////////////////////////
 
-  /** @see Execution#createProcessInstance() */
   public ExecutionImpl createExecution() {
-    return createExecution((String)null);
+    return createExecution(null);
   }
 
-  public Execution createExecution(Execution parent) {
-    return ((ExecutionImpl)parent).createExecution();
-  }
-
-  public Execution createExecution(String name, Execution parent) {
-    return ((ExecutionImpl)parent).createExecution(name);
-  }
-
-  /** @see Execution#createProcessInstance(String) */
   public ExecutionImpl createExecution(String name) {
-    // creating a child execution implies that this execution 
-    // is not a leave any more and therefore, it is inactivated
-    if (isActive()) {
-      setState(STATE_INACTIVE);
-      propagation = Propagation.EXPLICIT;
-    }
+    // ?!
+    propagation = Propagation.EXPLICIT;
 
     // create child execution
     ExecutionImpl childExecution = newChildExecution();
+    addExecution(childExecution);
+
+    // initialize new concurrent execution 
     childExecution.setProcessDefinition(getProcessDefinition());
-    childExecution.setActivity(getActivity());
     childExecution.processInstance = this.processInstance;
-    childExecution.state = STATE_ACTIVE;
     childExecution.name = name;
     log.debug("creating "+childExecution);
-    // add it to this execution
-    addExecution(childExecution);
-    // invalidate the cached executionsMap
-    executionsMap = null;
-    
-    // id generation
+
+    // id generation (after initialization)
     IdGenerator keyGenerator = Environment.getFromCurrent(IdGenerator.class, false);
     if (keyGenerator!=null) {
       childExecution.id = keyGenerator.createId(getProcessDefinition(), this, childExecution);
     }
-
     
     return childExecution;
   }
@@ -786,6 +784,7 @@
       executions = new ArrayList<ExecutionImpl>();
     }
     executions.add(executionImpl);
+    executionsMap = null;
   }
 
   /** @see Execution#getExecution(String) */
@@ -797,16 +796,6 @@
   public void removeExecution(Execution child) {
     if (executions!=null) {
       if (executions.remove(child)) {
-        if ( state.equals(STATE_INACTIVE) && 
-            (executions.isEmpty())
-          ) {
-         if (log.isTraceEnabled()) {
-           log.trace("last child execution was removed; unlocking");
-         }
-         state = STATE_ACTIVE;
-        } else if (log.isTraceEnabled()) {
-          log.trace("removed "+child+" from "+this);
-        }
         // invalidate the executionsMap cache
         executionsMap = null;
       } else {
@@ -815,10 +804,6 @@
     }
   }
 
-  public void removeExecution(Execution child, Execution parent) {
-    ((ExecutionImpl)parent).removeExecution(child);
-  }
-
   public Map<String, Execution> getExecutionsMap() {
     if ( (executionsMap==null)
          && (executions!=null)
@@ -848,7 +833,7 @@
   }
 
   protected Set<String> addActiveActivityNames(Set<String> activityNames) {
-    if ( (state.equals(STATE_ACTIVE))
+    if ( (state.equals(STATE_ACTIVE_ROOT))
          && (activityName!=null)
        ) {
       activityNames.add(activityName);
@@ -865,7 +850,7 @@
 
   public ExecutionImpl findActiveExecutionIn(String activityName) {
     if ( activityName.equals(this.activityName)
-         && state.equals(STATE_ACTIVE)) {
+         && isActive()) {
       return this;
     }
 
@@ -931,10 +916,38 @@
   }
 
   protected void checkActive() {
-    if (!Execution.STATE_ACTIVE.equals(state)) {
+    if (!isActive()) {
       throw new JbpmException(toString()+" is not active: "+state);
     }
   }
+  
+  public boolean isEnded() {
+    if (Execution.STATE_ENDED.equals(state)) {
+      return true;
+    }
+    if (Execution.STATE_CREATED.equals(state)) {
+      return false;
+    }
+    if (Execution.STATE_ACTIVE_ROOT.equals(state)) {
+      return false;
+    }
+    if (Execution.STATE_ACTIVE_CONCURRENT.equals(state)) {
+      return false;
+    }
+    if (Execution.STATE_INACTIVE_CONCURRENT_ROOT.equals(state)) {
+      return false;
+    }
+    if (Execution.STATE_INACTIVE_SCOPE.equals(state)) {
+      return false;
+    }
+    if (Execution.STATE_SUSPENDED.equals(state)) {
+      return false;
+    }
+    if (Execution.STATE_ASYNC.equals(state)) {
+      return false;
+    }
+    return true;
+  }
 
   ////////////////////////////////////////////////////////////////////////////////
 

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -33,6 +33,8 @@
 
 import org.jbpm.api.Execution;
 import org.jbpm.api.JbpmException;
+import org.jbpm.api.client.ClientExecution;
+import org.jbpm.api.client.ClientProcessDefinition;
 import org.jbpm.api.env.Environment;
 import org.jbpm.api.job.Timer;
 import org.jbpm.api.session.TimerSession;
@@ -90,10 +92,6 @@
   }
 
   public void createVariable(String key, Object value, String typeName) {
-    if (isEnded()) {
-      throw new JbpmException("can't create variable '"+key+"' on "+this+": "+state);
-    }
-
     log.debug("create variable '"+key+"' in '"+this+"' with value '"+value+"'");
     
     Type type = null;
@@ -147,9 +145,6 @@
   }
 
   public void setVariable(String key, Object value) {
-    if (isEnded()) {
-      throw new JbpmException("can't update variable '"+key+"' on "+this+": "+state);
-    }
     Variable variable = getVariableObject(key);
     // if there is already a variable instance and it doesn't support the current type...
     if ( (variable!=null) 
@@ -250,10 +245,6 @@
   }
 
   public boolean removeVariable(String key) {
-    if (isEnded()) {
-      throw new JbpmException("can't remove variable '"+key+"' on "+this+": "+state);
-    }
-
     Variable variable = null;
     if (hasVariables) {
       variable = variables.remove(key);
@@ -429,19 +420,14 @@
 
   /** @see Execution#isActive() */
   public boolean isActive() {
-    return Execution.STATE_ACTIVE.equals(state);
+    return Execution.STATE_ACTIVE_ROOT.equals(state)
+           || Execution.STATE_ACTIVE_CONCURRENT.equals(state);
   }
 
-  /** @see Execution#isSuspended() */
   public boolean isSuspended() {
     return Execution.STATE_SUSPENDED.equals(state);
   }
 
-  /** @see Execution#isEnded() */
-  public boolean isEnded() {
-    return Execution.STATE_ENDED.equals(state);
-  }
-
   // customizable methods /////////////////////////////////////////////////////
   
   public ExecutionImpl getProcessInstance() {

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/ExecuteActivityMessage.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/ExecuteActivityMessage.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/ExecuteActivityMessage.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -42,7 +42,7 @@
   }
 
   public Object execute(Environment environment) throws Exception {
-    execution.setState(Execution.STATE_ACTIVE);
+    execution.setState(Execution.STATE_ACTIVE_ROOT);
     
     execution.performAtomicOperationSync(ExecutionImpl.EXECUTE_ACTIVITY);
 

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/ProceedToDestinationMessage.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/ProceedToDestinationMessage.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/ProceedToDestinationMessage.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -43,7 +43,7 @@
   }
 
   public Object execute(Environment environment) throws Exception {
-    execution.setState(Execution.STATE_ACTIVE);
+    execution.setState(Execution.STATE_ACTIVE_ROOT);
     execution.performAtomicOperationSync(ExecutionImpl.PROCEED_TO_DESTINATION);
     
     JobDbSession jobDbSession = environment.get(JobDbSession.class);

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/SignalMessage.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/SignalMessage.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/SignalMessage.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -48,7 +48,7 @@
   }
 
   public Object execute(Environment environment) throws Exception {
-    execution.setState(Execution.STATE_ACTIVE);
+    execution.setState(Execution.STATE_ACTIVE_ROOT);
     
     Signal signal = new Signal(signalName, null, activity);
     execution.performAtomicOperationSync(signal);

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/TakeTransitionMessage.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/TakeTransitionMessage.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/op/TakeTransitionMessage.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -42,7 +42,7 @@
   }
 
   public Object execute(Environment environment) throws Exception {
-    execution.setState(Execution.STATE_ACTIVE);
+    execution.setState(Execution.STATE_ACTIVE_ROOT);
 
     execution.performAtomicOperationSync(ExecutionImpl.TAKE_TRANSITION);
     

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/AsyncCommandMessage.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/AsyncCommandMessage.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/AsyncCommandMessage.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -48,7 +48,7 @@
   }
 
   public Object execute(Environment environment) throws Exception {
-    execution.setState(Execution.STATE_ACTIVE);
+    execution.setState(Execution.STATE_ACTIVE_ROOT);
 
     if (userId!=null) {
       environment.setUserId(userId);

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskImpl.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/task/TaskImpl.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -64,6 +64,9 @@
   
   private static final TaskHandler DEFAULT_TASK_HANDLER = new TaskHandler();
 
+  public static final String STATE_CREATED = "created"; 
+  public static final String STATE_ASSIGNED = "assigned"; 
+  public static final String STATE_COMPLETED = "completed"; 
   public static final String STATE_SUSPENDED = "suspended"; 
   public static final String STATE_ACTIVE = "active"; 
   
@@ -210,6 +213,15 @@
     getTaskHandler().taskCancel(this, reason);
   }
   
+  // state ////////////////////////////////////////////////////////////////////
+  
+  public boolean isCompleted() {
+    if (STATE_COMPLETED.equals(state)) {
+      return true;
+    }
+    return false;
+  }
+
   // variables ////////////////////////////////////////////////////////////////
   
   public void setVariable(String key, Object value) {

Modified: jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ExecutionStateTest.java
===================================================================
--- jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ExecutionStateTest.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ExecutionStateTest.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -60,18 +60,18 @@
   public static class AutomaticActivity implements ActivityBehaviour {
     private static final long serialVersionUID = 1L;
     public void execute(ActivityExecution execution) {
-      assertEquals(Execution.STATE_ACTIVE, execution.getState());
+      assertEquals(Execution.STATE_ACTIVE_ROOT, execution.getState());
     }
   }
 
   public static class WaitState implements ExternalActivityBehaviour {
     private static final long serialVersionUID = 1L;
     public void execute(ActivityExecution execution) {
-      assertEquals(Execution.STATE_ACTIVE, execution.getState());
+      assertEquals(Execution.STATE_ACTIVE_ROOT, execution.getState());
       execution.waitForSignal();
     }
     public void signal(ActivityExecution execution, String signalName, Map<String, Object> parameters) {
-      assertEquals(Execution.STATE_ACTIVE, execution.getState());
+      assertEquals(Execution.STATE_ACTIVE_ROOT, execution.getState());
       execution.take(signalName);
     }
   }
@@ -95,7 +95,7 @@
     
     processInstance.start();
 
-    assertEquals(Execution.STATE_ACTIVE, processInstance.getState());
+    assertEquals(Execution.STATE_ACTIVE_ROOT, processInstance.getState());
 
     processInstance.signal();
 
@@ -119,7 +119,7 @@
     ClientProcessInstance processInstance = processDefinition.createProcessInstance();
     processInstance.start();
   
-    assertEquals(Execution.STATE_INACTIVE, processInstance.getState());
+    assertEquals(Execution.STATE_INACTIVE_SCOPE, processInstance.getState());
   
     try {
       processInstance.signal();
@@ -176,39 +176,53 @@
     processInstance.start();
     
     try {
-      processInstance.end("active");
+      processInstance.end(Execution.STATE_CREATED);
       fail("expected exception");
     } catch (JbpmException e) {
       // OK
-      assertTextPresent("invalid end state: active", e.getMessage());
+      assertTextPresent("invalid end state: "+Execution.STATE_CREATED, e.getMessage());
     }
     try {
-      processInstance.end("suspended");
+      processInstance.end(Execution.STATE_ACTIVE_ROOT);
       fail("expected exception");
     } catch (JbpmException e) {
       // OK
-      assertTextPresent("invalid end state: suspended", e.getMessage());
+      assertTextPresent("invalid end state: "+Execution.STATE_ACTIVE_ROOT, e.getMessage());
     }
     try {
-      processInstance.end("created");
+      processInstance.end(Execution.STATE_ACTIVE_CONCURRENT);
       fail("expected exception");
     } catch (JbpmException e) {
       // OK
-      assertTextPresent("invalid end state: created", e.getMessage());
+      assertTextPresent("invalid end state: "+Execution.STATE_ACTIVE_CONCURRENT, e.getMessage());
     }
     try {
-      processInstance.end("async");
+      processInstance.end(Execution.STATE_INACTIVE_CONCURRENT_ROOT);
       fail("expected exception");
     } catch (JbpmException e) {
       // OK
-      assertTextPresent("invalid end state: async", e.getMessage());
+      assertTextPresent("invalid end state: "+Execution.STATE_INACTIVE_CONCURRENT_ROOT, e.getMessage());
     }
     try {
-      processInstance.end("inactive");
+      processInstance.end(Execution.STATE_INACTIVE_SCOPE);
       fail("expected exception");
     } catch (JbpmException e) {
       // OK
-      assertTextPresent("invalid end state: inactive", e.getMessage());
+      assertTextPresent("invalid end state: "+Execution.STATE_INACTIVE_SCOPE, e.getMessage());
     }
+    try {
+      processInstance.end(Execution.STATE_SUSPENDED);
+      fail("expected exception");
+    } catch (JbpmException e) {
+      // OK
+      assertTextPresent("invalid end state: "+Execution.STATE_SUSPENDED, e.getMessage());
+    }
+    try {
+      processInstance.end(Execution.STATE_ASYNC);
+      fail("expected exception");
+    } catch (JbpmException e) {
+      // OK
+      assertTextPresent("invalid end state: "+Execution.STATE_ASYNC, e.getMessage());
+    }
   }
 }

Modified: jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ScopeStateTest.java
===================================================================
--- jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ScopeStateTest.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ScopeStateTest.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -41,18 +41,18 @@
   public static class AutomaticActivity implements ActivityBehaviour {
     private static final long serialVersionUID = 1L;
     public void execute(ActivityExecution execution) {
-      assertEquals(Execution.STATE_ACTIVE, execution.getState());
+      assertEquals(Execution.STATE_ACTIVE_ROOT, execution.getState());
     }
   }
 
   public static class WaitState implements ExternalActivityBehaviour {
     private static final long serialVersionUID = 1L;
     public void execute(ActivityExecution execution) {
-      assertEquals(Execution.STATE_ACTIVE, execution.getState());
+      assertEquals(Execution.STATE_ACTIVE_ROOT, execution.getState());
       execution.waitForSignal();
     }
     public void signal(ActivityExecution execution, String signalName, Map<String, Object> parameters) throws Exception {
-      assertEquals(Execution.STATE_ACTIVE, execution.getState());
+      assertEquals(Execution.STATE_ACTIVE_ROOT, execution.getState());
       execution.take(signalName);
     }
   }
@@ -79,12 +79,12 @@
     processInstance.start();
     Execution scopeExecution = processInstance.getExecutions().iterator().next();
 
-    assertEquals(Execution.STATE_INACTIVE, processInstance.getState());
-    assertEquals(Execution.STATE_ACTIVE, scopeExecution.getState());
+    assertEquals(Execution.STATE_INACTIVE_SCOPE, processInstance.getState());
+    assertEquals(Execution.STATE_ACTIVE_ROOT, scopeExecution.getState());
     
     processInstance.signal(scopeExecution);
 
     assertEquals(Execution.STATE_ENDED, scopeExecution.getState());
-    assertEquals(Execution.STATE_ACTIVE, processInstance.getState());
+    assertEquals(Execution.STATE_ACTIVE_ROOT, processInstance.getState());
   }
 }

Modified: jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ScopeVariableTest.java
===================================================================
--- jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ScopeVariableTest.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/ScopeVariableTest.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -199,14 +199,5 @@
     bScope.createVariable("temp", "28C");
     
     processInstance.signal(bScope);
-    
-    try {
-      bScope.setVariable("temp", "21C");
-      fail("expected exception");
-    } catch (JbpmException e) {
-      // OK
-      assertTextPresent("can't update variable 'temp' on execution[b]", e.getMessage());
-    }
   }
-
 }

Deleted: jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/TransitionBasedConcurrencyTest.java
===================================================================
--- jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/TransitionBasedConcurrencyTest.java	2009-05-15 19:55:27 UTC (rev 4827)
+++ jbpm4/trunk/modules/test-pojo/src/main/java/org/jbpm/test/activities/TransitionBasedConcurrencyTest.java	2009-05-16 10:33:13 UTC (rev 4828)
@@ -1,187 +0,0 @@
-package org.jbpm.test.activities;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import org.jbpm.api.Execution;
-import org.jbpm.api.activity.ActivityBehaviour;
-import org.jbpm.api.activity.ActivityExecution;
-import org.jbpm.api.activity.ExternalActivityBehaviour;
-import org.jbpm.api.client.ClientExecution;
-import org.jbpm.api.client.ClientProcessDefinition;
-import org.jbpm.api.model.Activity;
-import org.jbpm.api.model.OpenExecution;
-import org.jbpm.api.model.Transition;
-import org.jbpm.pvm.internal.builder.ProcessDefinitionBuilder;
-import org.jbpm.pvm.internal.model.ExecutionImpl;
-import org.jbpm.test.BaseJbpmTestCase;
-
-/**
- * concurrent execution where synchronization is done by checking if the 
- * number of expected child executions arrived at the join.
- * 
- * @author Tom Baeyens
- */
-public class TransitionBasedConcurrencyTest extends BaseJbpmTestCase {
-  
-  public static class Fork implements ActivityBehaviour {
-    private static final long serialVersionUID = 1L;
-    public void execute(ActivityExecution execution) {
-      OpenExecution processInstance = execution.getProcessInstance();
-
-      Activity activity = execution.getActivity();
-      List<Transition> outgoingTransitions = activity.getOutgoingTransitions();
-
-      // for each outgoing transition
-      for (Transition outgoingTransition: outgoingTransitions) {
-        // launch a concurrent path of execution
-        String childExecutionName = outgoingTransition.getName();
-        // creating the execution will cause the execution to become inactive
-        ExecutionImpl executionImpl = (ExecutionImpl) execution;
-        Execution childExecution = executionImpl.createExecution(childExecutionName, processInstance);
-        execution.take(outgoingTransition, childExecution);
-      }
-
-      // if this was the first fork
-      if (execution.isProcessInstance()) {
-        execution.setActivity(null);
-      }
-    }
-  }
-
-  public static class Join implements ActivityBehaviour {
-    private static final long serialVersionUID = 1L;
-    public void execute(ActivityExecution execution) throws Exception {
-      // end the child execution execution
-      // this will also remove the execution from it's parent
-      execution.setState(Execution.STATE_INACTIVE);
-      execution.waitForSignal();
-      
-      Activity join = execution.getActivity();
-      List<OpenExecution> joinedExecutions = findJoinedExecutions(execution, join);
-      
-      if (isComplete(joinedExecutions, join)) {
-        endJoinedExecutions(joinedExecutions, execution);
-
-        OpenExecution processInstance = execution.getProcessInstance();
-        
-        Execution outgoingExecution = null;
-        if ( processInstance.getExecutions()==null
-             || processInstance.getExecutions().isEmpty() 
-           ) {
-          outgoingExecution = processInstance;
-        } else {
-          ExecutionImpl executionImpl = (ExecutionImpl) execution;
-          outgoingExecution = executionImpl.createExecution(processInstance);
-        }
-        
-        execution.setActivity(join, outgoingExecution);
-        Transition transition = join.getDefaultOutgoingTransition();
-        execution.take(transition, outgoingExecution);
-      }
-    }
-    
-    List<OpenExecution> findJoinedExecutions(OpenExecution execution, Activity join) {
-      List<OpenExecution> joinedExecutions = new ArrayList<OpenExecution>();
-      scanRecursive(execution.getProcessInstance(), join, joinedExecutions);
-      return joinedExecutions;
-    }
-
-    void scanRecursive(OpenExecution execution, Activity join, List<OpenExecution> joinedExecutions) {
-      // if the execution is positioned in the join
-      if (join.equals(execution.getActivity())) {
-        joinedExecutions.add(execution);
-      }
-      Collection<OpenExecution> childExecutions = (List)execution.getExecutions();
-      if (childExecutions!=null) {
-        for (OpenExecution childExecution: childExecutions) {
-          scanRecursive(childExecution, join, joinedExecutions);
-        }
-      }
-    }
-
-    boolean isComplete(List<OpenExecution> joinedExecutions, Activity join) {
-      int executionsToJoin = join.getIncomingTransitions().size();
-      return (executionsToJoin==joinedExecutions.size());
-    }
-
-    void endJoinedExecutions(List<OpenExecution> joinedExecutions, ActivityExecution execution) {
-      for (OpenExecution joinedExecution: joinedExecutions) {
-        execution.end(joinedExecution);
-      }
-    }
-  }
-
-  public static class WaitState implements ExternalActivityBehaviour {
-    private static final long serialVersionUID = 1L;
-    public void execute(ActivityExecution execution) {
-      execution.waitForSignal();
-    }
-    public void signal(ActivityExecution execution, String signalName, Map<String, Object> parameters) {
-      execution.take(signalName);
-    }
-  }
-
-  public void testTransitionBasedConcurrency() {
-
-    ClientProcessDefinition processDefinition = ProcessDefinitionBuilder
-    .startProcess()
-      .startActivity("fork", new Fork())
-        .initial()
-        .transition("bill", "billing")
-        .transition("ship", "shipping")
-      .endActivity()
-      .startActivity("bill", new WaitState())
-        .transition("join")
-      .endActivity()
-      .startActivity("ship", new WaitState())
-        .transition("join")
-      .endActivity()
-      .startActivity("join", new Join())
-        .transition("end")
-      .endActivity()
-      .startActivity("end", new WaitState())
-      .endActivity()
-    .endProcess();
-
-    ClientExecution main = processDefinition.startProcessInstance();
-    
-    assertNull("fork", main.getActivity());
-    assertEquals(Execution.STATE_INACTIVE, main.getState());
-    
-    Execution billing = main.getExecution("billing");
-    assertNotNull(billing);
-    assertEquals("bill", billing.getActivityName());
-    assertFalse(billing.isEnded());
-    
-    Execution shipping = main.getExecution("shipping");
-    
-    assertNotNull(shipping);
-    assertEquals("ship", shipping.getActivityName());
-    assertFalse(shipping.isEnded());
-    assertTrue(main.getExecutions().contains(billing));
-    assertTrue(main.getExecutions().contains(shipping));
-
-    main.signal(billing);
-    
-    assertNull(main.getActivityName());
-    assertEquals("join", billing.getActivityName());
-    assertEquals("ship", shipping.getActivityName());
-    assertEquals(Execution.STATE_ACTIVE, shipping.getState());
-    assertEquals(Execution.STATE_INACTIVE, billing.getState());
-    assertEquals(Execution.STATE_INACTIVE, main.getState());
-
-    main.signal(shipping);
-    
-    assertEquals(Execution.STATE_ACTIVE, main.getState());
-    assertEquals("end", main.getActivityName());
-    assertEquals("join", billing.getActivityName());
-    assertTrue(billing.isEnded());
-    assertEquals("join", shipping.getActivityName());
-    assertTrue(shipping.isEnded());
-    assertFalse(main.getExecutions().contains(billing));
-    assertFalse(main.getExecutions().contains(shipping));
-  }
-}




More information about the jbpm-commits mailing list