[jbpm-commits] JBoss JBPM SVN: r6077 - in jbpm4/trunk/modules: bpmn/src/main/java/org/jbpm/bpmn/flownodes and 9 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Wed Jan 13 17:18:26 EST 2010


Author: jbarrez
Date: 2010-01-13 17:18:25 -0500 (Wed, 13 Jan 2010)
New Revision: 6077

Added:
   jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.exclusive.gateway.splitting.and.merging.png
   jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.parallel.gateway.splitting.and.merging.png
   jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/
   jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/gateway/
   jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/gateway/ExclusiveGatewayMergeTest.java
   jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/gateway/ParallelGatewayMergeTest.java
Modified:
   jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/history/HistoryActivityInstance.java
   jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/AbstractGatewayBinding.java
   jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/BpmnActivity.java
   jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ExclusiveGatewayActivity.java
   jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ParallelGatewayActivity.java
   jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ParallelGatewayBinding.java
   jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/parser/BpmnParser.java
   jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/model/HistoryActivityInstanceImpl.java
   jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/JbpmTestCase.java
   jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/assertion/CollectionAssertions.java
Log:
JBPM-2742: enhanced parallel gateway to allow merging/splitting behaviour in the same parallel gateway

Modified: jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/history/HistoryActivityInstance.java
===================================================================
--- jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/history/HistoryActivityInstance.java	2010-01-13 18:55:43 UTC (rev 6076)
+++ jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/history/HistoryActivityInstance.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -22,6 +22,7 @@
 package org.jbpm.api.history;
 
 import java.util.Date;
+import java.util.List;
 
 /** represents one occurrence of an activity during a process 
  * instance.  
@@ -44,4 +45,10 @@
 
   /** the execution that was related to this activity occurrence */
   String getExecutionId();
+  
+  /** 
+   * The names of the transitions that were selected as outgoing transitions for the execution.
+   */
+  List<String> getTransitionNames();
+ 
 }
\ No newline at end of file

Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/AbstractGatewayBinding.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/AbstractGatewayBinding.java	2010-01-13 18:55:43 UTC (rev 6076)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/AbstractGatewayBinding.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -113,7 +113,7 @@
   protected boolean validGatewayDirection(Parse parse, String elementName, Element element) {
    
     if (log.isDebugEnabled()) {
-      log.debug(gatewayDirection + ": nr of incomming: " + incoming + ", nr of outgoing: " + outgoing);
+      log.debug("Defined gatewayDirection: " + gatewayDirection + ". Nr of incomming: " + incoming + ", nr of outgoing: " + outgoing);
     }
     
     boolean valid = !(("converging".equals(gatewayDirection) && (!(incoming > 1) || outgoing != 1))

Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/BpmnActivity.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/BpmnActivity.java	2010-01-13 18:55:43 UTC (rev 6076)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/BpmnActivity.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -66,15 +66,17 @@
 
     // if no outgoing transitions should be forked,
     if (transitions.size() == 0) {
+      if (log.isDebugEnabled()) {
+        log.debug("No outgoing transitions found. Ending the execution");
+      }
       execution.end();
     }
 
-    // if there is exactly 1 transition to be taken, just use the incoming
-    // execution
+    // if there is exactly 1 transition to be taken, just use the incoming execution
     else if (transitions.size() == 1) {
       execution.take(transitions.get(0));
 
-      // if there are more transitions
+    // if there are more transitions
     } else {
       ExecutionImpl concurrentRoot = null;
       if (Execution.STATE_ACTIVE_ROOT.equals(execution.getState())) {

Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ExclusiveGatewayActivity.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ExclusiveGatewayActivity.java	2010-01-13 18:55:43 UTC (rev 6076)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ExclusiveGatewayActivity.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -47,6 +47,11 @@
     execute((ExecutionImpl) execution);
   }
 
+  /*
+   * Converging/diverging behaviour for the exclusive gateway.
+   * 
+   * Note that no special handling is needed for the converging behaviour.
+   */
   public void execute(ExecutionImpl execution) {
 
     List<Transition> transitions = findTransitions(execution, CONDITIONS_CHECKED);

Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ParallelGatewayActivity.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ParallelGatewayActivity.java	2010-01-13 18:55:43 UTC (rev 6076)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ParallelGatewayActivity.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -33,67 +33,56 @@
 import org.jbpm.pvm.internal.env.EnvironmentImpl;
 import org.jbpm.pvm.internal.model.Activity;
 import org.jbpm.pvm.internal.model.ExecutionImpl;
-import org.jbpm.pvm.internal.model.Transition;
 
 /**
  * @author Ronald van Kuijk (kukeltje)
+ * @author Joram Barrez
  */
 public class ParallelGatewayActivity extends BpmnActivity {
 
-  private static final Log log = Log.getLog(ParallelGatewayActivity.class.getName());
+  private static final Log LOG = Log.getLog(ParallelGatewayActivity.class.getName());
   
   private static final long serialVersionUID = 1L;
   
-  int multiplicity = -1;
   LockMode lockMode = LockMode.UPGRADE;
 
-  //GatewayDirection indicates fork (divergence) or join (convergence). Maybe two different activities is better
+  //GatewayDirection indicates fork (divergence) or join (convergence). 
   private String gatewayDirection;
 
   public void execute(ActivityExecution execution) {
     execute((ExecutionImpl) execution);
   }
 
-  public void execute(ExecutionImpl execution) {
-    
+  public void execute(ExecutionImpl execution) { 
     int nrOfIncoming = execution.getActivity().getIncomingTransitions().size();
-    int nrOfOutgoing = execution.getActivity().getOutgoingTransitions().size();
     
-    if (nrOfIncoming == 1 && nrOfOutgoing > 1) {
-      if (log.isDebugEnabled()) {
-        log.debug("Forking parallel gateway");
+    if (nrOfIncoming == 1) { // no join behaviour needed, save some time and do a fork immediately
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Only one incoming sequence flow found. Executing fork logic");
       }
       fork(execution);
-    } else if (nrOfIncoming > 1 && nrOfOutgoing == 1) {
-      if (log.isDebugEnabled()) {
-        log.debug("Joining parallel gateway");
+    } else { // Join behaviour needed
+      
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Multiple incoming sequence flow found. Executing join logic");
       }
       join(execution);
+      
+      // After executing the join functionality, it could be that all executions have arrived 
+      // at the gateway. In that case, the gateway can be left using the fork functionality.
+      proceedIfPossible(execution);
+      
     }
-    
+
+   
   }
   
-  public void fork(ExecutionImpl execution) {
-
+  protected void fork(ExecutionImpl execution) {
     proceed(execution, findTransitions(execution, CONDITIONS_IGNORED));
-    
   }
   
-  private void join(ExecutionImpl execution) {
-    
-    Activity activity = execution.getActivity();
-    
-    // if this is a single, non concurrent root
-    if (Execution.STATE_ACTIVE_ROOT.equals(execution.getState())) {
-      // just pass through
-      
-      Transition transition = activity.getOutgoingTransitions().get(0);
-      if (transition==null) {
-        throw new JbpmException("join must have an outgoing transition");
-      }
-      execution.take(transition);
-      
-    } else if (Execution.STATE_ACTIVE_CONCURRENT.equals(execution.getState())) {
+  protected void join(ExecutionImpl execution) {
+    if (Execution.STATE_ACTIVE_CONCURRENT.equals(execution.getState())) {
      
       // force version increment in the parent execution
       Session session = EnvironmentImpl.getFromCurrent(Session.class);
@@ -101,46 +90,46 @@
 
       execution.setState(Execution.STATE_INACTIVE_JOIN);
       execution.waitForSignal();
-
-      ExecutionImpl concurrentRoot = execution.getParent();
-      List<ExecutionImpl> joinedExecutions = getJoinedExecutions(concurrentRoot, activity);
       
-      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.getOutgoingTransitions().get(0);
-        if (transition==null) {
-          throw new JbpmException("join must have an outgoing transition");
-        }
-        outgoingExecution.take(transition);
+    } else {
+      throw new JbpmException("invalid execution state: " + execution.getState());
+    }
+  }
+  
+  protected void proceedIfPossible(ExecutionImpl execution) {
+    Activity activity = execution.getActivity();
+    ExecutionImpl concurrentRoot = execution.getParent();
+    List<ExecutionImpl> joinedExecutions = getJoinedExecutions(concurrentRoot, activity);
+    
+    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);
       }
       
-    } else {
-      throw new JbpmException("invalid execution state");
+      outgoingExecution.setActivity(activity);
+      fork(outgoingExecution);
     }
   }
   
   protected boolean isComplete(List<ExecutionImpl> joinedExecutions, Activity activity) {
-    int nbrOfExecutionsToJoin = multiplicity;
-    if (multiplicity==-1) {
-      nbrOfExecutionsToJoin = activity.getIncomingTransitions().size();
+    boolean result = joinedExecutions.size() == activity.getIncomingTransitions().size();
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("All incoming executions have arrived at the gateway: " + result);
     }
-    return joinedExecutions.size()==nbrOfExecutionsToJoin;
+    return result;
   }
 
   protected List<ExecutionImpl> getJoinedExecutions(ExecutionImpl concurrentRoot, Activity activity) {
     List<ExecutionImpl> joinedExecutions = new ArrayList<ExecutionImpl>();
-    List concurrentExecutions = (List)concurrentRoot.getExecutions();
+    List<ExecutionImpl> concurrentExecutions = (List<ExecutionImpl>)concurrentRoot.getExecutions();
     for (ExecutionImpl concurrentExecution: (List<ExecutionImpl>)concurrentExecutions) {
       if ( (Execution.STATE_INACTIVE_JOIN.equals(concurrentExecution.getState()))
            && (concurrentExecution.getActivity()==activity)
@@ -148,6 +137,11 @@
         joinedExecutions.add(concurrentExecution);
       }
     }
+    
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Found " + joinedExecutions.size() + " executions currently waiting at the gateway");
+    }
+    
     return joinedExecutions;
   }
 
@@ -155,7 +149,6 @@
     for (ExecutionImpl joinedExecution: joinedExecutions) {
       joinedExecution.end();
     }
-    
   }
  
   public String getGatewayDirection() {

Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ParallelGatewayBinding.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ParallelGatewayBinding.java	2010-01-13 18:55:43 UTC (rev 6076)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ParallelGatewayBinding.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -42,12 +42,6 @@
 
     super.parse(element, parse);
 
-    if (gatewayDirection.equals("unspecified") || gatewayDirection.equals("mixed")) {
-      parse.addProblem("gatewayDirection='" + gatewayDirection 
-              + "' currently not supported on parallelGateway '" + name + "'", element);
-      return null;
-    }
-
     if (!valid) {
       return null;
     }

Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/parser/BpmnParser.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/parser/BpmnParser.java	2010-01-13 18:55:43 UTC (rev 6076)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/parser/BpmnParser.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -217,7 +217,11 @@
         activity.setType(activityBinding.getTagName());
         activity.setName(id);
         activity.setDescription(name);
-        log.debug("Parse Activity: " + name);
+        
+        if (log.isDebugEnabled()) {
+          log.debug("Parsing Activity: " + name + "(id=" + id + ")");          
+        }
+        
         ActivityBehaviour activityBehaviour = (ActivityBehaviour) activityBinding.parse(nestedElement, parse, this);
         activity.setActivityBehaviour(activityBehaviour);
       } finally {
@@ -234,9 +238,13 @@
       String sourceRef = XmlUtil.attribute(transitionElement, "sourceRef", true, parse);
       String targetRef = XmlUtil.attribute(transitionElement, "targetRef", true, parse);
 
-      log.trace(transitionId + ": " + sourceRef + " -> " + targetRef);
+      if (log.isDebugEnabled()) {
+        log.trace(transitionId + ": " + sourceRef + " -> " + targetRef);        
+      }
       Element conditionElement = XmlUtil.element(transitionElement, "conditionExpression");
-      log.trace("    with " + ((conditionElement == null) ? "0" : "1") + " conditionExpression");
+      if (log.isDebugEnabled()) {
+        log.trace("    with " + ((conditionElement == null) ? "0" : "1") + " conditionExpression");        
+      }
 
       TransitionImpl transition = compositeElement.findActivity(sourceRef).createOutgoingTransition();
       

Added: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.exclusive.gateway.splitting.and.merging.png
===================================================================
(Binary files differ)


Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.exclusive.gateway.splitting.and.merging.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.parallel.gateway.splitting.and.merging.png
===================================================================
(Binary files differ)


Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.parallel.gateway.splitting.and.merging.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Modified: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml	2010-01-13 18:55:43 UTC (rev 6076)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml	2010-01-13 22:18:25 UTC (rev 6077)
@@ -587,6 +587,11 @@
     sourceRef=&quot;decision&quot; targetRef=&quot;standard&quot;&gt;
 &lt;/sequenceFlow&gt;        
         </programlisting>
+        An exclusive gateway can have both convering and diverging functionality. The logic is 
+        easy to grasp: for every execution that arrives at the gateway, one outgoing sequence
+        flow is selected to continue the flow.  The following diagram is completely legal in
+        BPMN 2.0 (omitting names and conditions for clarity). 
+        <mediaobject><imageobject><imagedata align="center" fileref="images/bpmn2.exclusive.gateway.splitting.and.merging.png"/></imageobject></mediaobject>
       </para>
     
     </section>
@@ -674,6 +679,11 @@
     
   &lt;/process&gt;
         </programlisting>
+        A parallel gateway (as is the case for any gateway) can have both splitting and 
+        merging behaviour. The following diagram is completely legal BPMN 2.0. After process start,
+        both task A and B will be active. When both A en B are completed, tasks C,D and E will be 
+        active.                                 
+        <mediaobject><imageobject><imagedata align="center" fileref="images/bpmn2.parallel.gateway.splitting.and.merging.png"/></imageobject></mediaobject>
       </para>
       
     </section>

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/model/HistoryActivityInstanceImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/model/HistoryActivityInstanceImpl.java	2010-01-13 18:55:43 UTC (rev 6076)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/history/model/HistoryActivityInstanceImpl.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -23,6 +23,7 @@
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
@@ -126,4 +127,14 @@
   public void setType(String type) {
     this.type = type;
   }
+  public List<String> getTransitionNames() {
+    // TODO: expand for multiple outgoing transitions.
+    // Currently not possible, since only one transition name is stored.
+    if (transitionName != null) {
+      List<String> transitionNames = new ArrayList<String>();
+      transitionNames.add(transitionName);
+      return transitionNames;
+    }
+    return Collections.emptyList();
+  }
 }

Modified: jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/JbpmTestCase.java
===================================================================
--- jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/JbpmTestCase.java	2010-01-13 18:55:43 UTC (rev 6076)
+++ jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/JbpmTestCase.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -181,7 +181,17 @@
 
     return deploymentDbid;
   }
+  
+  public String deployBpmn2XmlString(String bpmn2XmlString) {
+    String deploymentDbid =
+      repositoryService.createDeployment()
+          .addResourceFromString("xmlstring.bpmn.xml", bpmn2XmlString)
+          .deploy();
 
+    registerDeployment(deploymentDbid);
+    return deploymentDbid;
+  }
+
   /** registered deployments will be deleted in the tearDown */
   protected void registerDeployment(String deploymentId) {
     registeredDeployments.add(deploymentId);

Modified: jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/assertion/CollectionAssertions.java
===================================================================
--- jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/assertion/CollectionAssertions.java	2010-01-13 18:55:43 UTC (rev 6076)
+++ jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/assertion/CollectionAssertions.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -36,22 +36,26 @@
  */
 public class CollectionAssertions {
   
+  /**
+   * Compares the elements of the two given collections.
+   * The order of elements is not checked.
+   */
   public static <T>  void assertElementsEqual(Collection<T> collection1, Collection<T> collection2) {
     
-    Assert.assertTrue( (collection1 == null && collection2 == null) 
+    Assert.assertTrue("One of the given collections is null, while the other collection is not null",
+                    (collection1 == null && collection2 == null) 
                     || (collection1 != null && collection2 != null) );
     
     if (collection1 != null && collection2 != null) {
       
-      Assert.assertEquals(collection1.size(), collection2.size());
+      Assert.assertEquals("Collection 1 does not have the same number of elements as collection 2 ",
+              collection1.size(), collection2.size());
       
-      Iterator<T> it1 = collection1.iterator();
-      Iterator<T> it2 = collection2.iterator();
-      
-      while (it1.hasNext()) {
-        T t1 = it1.next();
-        T t2 = it2.next();
-        Assert.assertEquals(t1, t2);
+      Iterator<T> it = collection1.iterator();
+      while (it.hasNext()) {
+        T t = it.next();
+        Assert.assertTrue("Collection 1 contains element" + t + ", which does not exist in collection 2 ",
+                collection2.contains(t));
       }
       
     }

Added: jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/gateway/ExclusiveGatewayMergeTest.java
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/gateway/ExclusiveGatewayMergeTest.java	                        (rev 0)
+++ jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/gateway/ExclusiveGatewayMergeTest.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -0,0 +1,75 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.bpmn.test.gateway;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jbpm.api.history.HistoryActivityInstance;
+import org.jbpm.api.history.HistoryActivityInstanceQuery;
+import org.jbpm.test.JbpmTestCase;
+
+/**
+ * Test case for the convering (merge) behaviour of an exclusive gateway.
+ * 
+ * @author Tom Baeyens
+ */
+public class ExclusiveGatewayMergeTest extends JbpmTestCase {
+  
+  private static final String TEST_PROCESS = 
+    "<definitions xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +
+    "  <process id='testProcess' name='exclusiveMerge' >" +
+    "    <startEvent id='theStart' />" +
+    "    <sequenceFlow id='flow1' sourceRef='theStart' targetRef='decision' />" +
+    "    <sequenceFlow id='flow2' sourceRef='theStart' targetRef='decision' />" +
+    "    <exclusiveGateway id='decision' />" +
+    "    <sequenceFlow id='flow2' sourceRef='decision' targetRef='theEnd1' >" +
+    "      <conditionExpression xsi:type='tFormalExpression'>${var &gt;= 10}</conditionExpression>" +
+    "    </sequenceFlow>" +
+    "    <sequenceFlow id='flow3' sourceRef='decision' targetRef='theEnd2' >" +
+    "      <conditionExpression xsi:type='tFormalExpression'>${var &lt;= 10}</conditionExpression>" +
+    "    </sequenceFlow>" +
+    "    <endEvent id='theEnd1' />" +
+    "    <endEvent id='theEnd2' />" +
+    "  </process>" +
+    "</definitions>";
+  
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    deployBpmn2XmlString(TEST_PROCESS);
+  }
+  
+  public void testExclusiveMerge() {
+    Map<String, Object> vars = new HashMap<String, Object>();
+    vars.put("var", 5);
+    executionService.startProcessInstanceByKey("testProcess", vars);
+    
+    HistoryActivityInstanceQuery query = historyService.createHistoryActivityInstanceQuery().activityName("decision");
+    List<HistoryActivityInstance> historyActivities = query.list();
+    assertEquals(2, historyActivities.size());
+    assertEquals("flow3", historyActivities.get(0).getTransitionNames().get(0));
+    assertEquals("flow3", historyActivities.get(1).getTransitionNames().get(0));
+  }
+
+}

Added: jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/gateway/ParallelGatewayMergeTest.java
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/gateway/ParallelGatewayMergeTest.java	                        (rev 0)
+++ jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/gateway/ParallelGatewayMergeTest.java	2010-01-13 22:18:25 UTC (rev 6077)
@@ -0,0 +1,104 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.bpmn.test.gateway;
+
+import java.util.Arrays;
+
+import org.jbpm.api.ProcessInstance;
+import org.jbpm.test.JbpmTestCase;
+import org.jbpm.test.assertion.CollectionAssertions;
+
+/**
+ * Test case for the merging behaviour of the parallel gateway.
+ * 
+ * @author Tom Baeyens
+ */
+public class ParallelGatewayMergeTest extends JbpmTestCase {
+  
+  /* Test process with parallel gateway that has 3 incoming and 2 outgoing sequence flow */
+  private static final String TEST_SIMPLE_MERGE_PROCESS = 
+    "<definitions>" +
+    "  <process id='simpleMerge' name='parallelMerge' >" +
+    "    <startEvent id='theStart' />" +
+    "    <sequenceFlow id='flow1' sourceRef='theStart' targetRef='parallelGateway' />" +
+    "    <sequenceFlow id='flow2' sourceRef='theStart' targetRef='parallelGateway' />" +
+    "    <sequenceFlow id='flow3' sourceRef='theStart' targetRef='parallelGateway' />" +
+    "    <parallelGateway id='parallelGateway' />" +
+    "    <sequenceFlow id='flow4' sourceRef='parallelGateway' targetRef='wait1' />" +
+    "    <sequenceFlow id='flow5' sourceRef='parallelGateway' targetRef='wait2' />" +
+    "    <receiveTask id='wait1' />" +
+    "    <sequenceFlow id='flow6' sourceRef='wait1' targetRef='theEnd' />" +
+    "    <receiveTask id='wait2' />" +
+    "    <sequenceFlow id='flow7' sourceRef='wait2' targetRef='theEnd' />" +
+    "    <endEvent id='theEnd' >" +
+    "      <terminateEventDefinition/>" +
+    "    </endEvent>" +
+    "  </process>" +
+    "</definitions>";
+  
+  /* 
+   * Test process with parallel gateway that has three outgoing sequence flow.
+   * Two of those sequence flow are merged before the resulting sequence flow is merged
+   * with the one remaining sequence flow
+   */
+  private static final String TEST_NESTED_MERGE_PROCESS = 
+    "<definitions>" +
+    "  <process id='nestedMerge' name='parallelNestedMerge' >" +
+    "    <startEvent id='theStart' />" +
+    "    <sequenceFlow id='flow1' sourceRef='theStart' targetRef='outerFork' />" +
+    "    <parallelGateway id='outerFork' />" +
+    "    <sequenceFlow id='flow2' sourceRef='outerFork' targetRef='wait1' />" +
+    "    <sequenceFlow id='flow3' sourceRef='outerFork' targetRef='innerJoin' />" +
+    "    <sequenceFlow id='flow4' sourceRef='outerFork' targetRef='innerJoin' />" +
+    "    <receiveTask id='wait1' />" +
+    "    <sequenceFlow id='flow5' sourceRef='wait1' targetRef='outerJoin' />" +
+    "    <parallelGateway id='innerJoin' />" +
+    "    <sequenceFlow id='flow6' sourceRef='innerJoin' targetRef='wait2' />" +
+    "    <receiveTask id='wait2' />" +
+    "    <sequenceFlow id='flow7' sourceRef='wait2' targetRef='outerJoin' />" +
+    "    <parallelGateway id='outerJoin' />" +
+    "    <sequenceFlow id='flow8' sourceRef='outerJoin' targetRef='theEnd' />" +
+    "    <endEvent id='theEnd' />" +
+    "  </process>" +
+    "</definitions>";
+
+  
+  public void testSimpleParallelMerge() {
+    deployBpmn2XmlString(TEST_SIMPLE_MERGE_PROCESS);
+    ProcessInstance pi = executionService.startProcessInstanceByKey("simpleMerge");
+    pi.findActiveActivityNames();
+    CollectionAssertions.assertElementsEqual(pi.findActiveActivityNames(), Arrays.asList("wait1", "wait2"));
+  }
+  
+  public void testNestedParallelMerge() {
+    deployBpmn2XmlString(TEST_NESTED_MERGE_PROCESS);
+    
+    ProcessInstance pi = executionService.startProcessInstanceByKey("nestedMerge");
+    
+    CollectionAssertions.assertElementsEqual(pi.findActiveActivityNames(), Arrays.asList("wait1", "wait2"));
+    
+    executionService.signalExecutionById(pi.findActiveExecutionIn("wait1").getId());
+    executionService.signalExecutionById(pi.findActiveExecutionIn("wait2").getId());
+    assertProcessInstanceEnded(pi);
+  }
+
+}



More information about the jbpm-commits mailing list