[jbpm-commits] JBoss JBPM SVN: r6001 - in jbpm4/trunk/modules: devguide/src/main/docbook/en/images and 1 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Sun Dec 20 07:44:20 EST 2009


Author: jbarrez
Date: 2009-12-20 07:44:20 -0500 (Sun, 20 Dec 2009)
New Revision: 6001

Added:
   jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.parallel.gateway.png
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/ExclusiveGatewayBinding.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/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml
Log:
JBPM-2662: parallel gateway

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	2009-12-20 12:42:36 UTC (rev 6000)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/AbstractGatewayBinding.java	2009-12-20 12:44:20 UTC (rev 6001)
@@ -1,20 +1,59 @@
+/*
+ * 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.flownodes;
 
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
 import org.jbpm.internal.log.Log;
+import org.jbpm.pvm.internal.util.XmlUtil;
 import org.jbpm.pvm.internal.wire.binding.ObjectBinding;
 import org.jbpm.pvm.internal.wire.xml.WireParser;
 import org.jbpm.pvm.internal.xml.Parse;
 import org.w3c.dom.Element;
 
+/**
+ * Abstract super class for all gateway types.
+ * 
+ * @author Ronald Van kuijk
+ * @author Joram Barrez
+ */
 public abstract class AbstractGatewayBinding extends BpmnBinding {
 
-  int incomming = 0;
-  int outgoing = 0;
+  protected static final Log log = Log.getLog(AbstractGatewayBinding.class.getName());
+
+  protected int incoming;
+  protected List<Element> inSequenceFlows;
   
-  String gatewayDirection = "unspeficied";
+  protected int outgoing;
+  protected List<Element> outSequenceFlows;
+  
+  protected String id;
+  protected String name;
+  
+  protected String gatewayDirection; 
   boolean valid = true;
   
-  protected static final Log log = Log.getLog(AbstractGatewayBinding.class.getName());
   static ObjectBinding objectBinding = new ObjectBinding();
   static WireParser wireParser = WireParser.getInstance();
 
@@ -22,31 +61,67 @@
     super(tagName);
   }
   
-  public void parse(Element element) {
-    incomming = 0;
-    outgoing = 0;
-    valid = true;
+  /**
+   * Subclasses should call this method while parsing.
+   * Common attributes and elements will be parsed and stored in the protected member fields.
+   */
+  public void parse(Element element, Parse parse) {
+    
+    resetMemberFields();
+    id = element.getAttribute("id");
+    name = element.getAttribute("name");
+    
+    // 'gatewayDirection' is a constraint on any gateway type. 
+    // Since this is an optional attribute, we can't rely on it at runtime.
+    // As such, it is only used at parsing time to check if the constraints are met.
     if (element.hasAttribute("gatewayDirection")) {
-      
       gatewayDirection = element.getAttribute("gatewayDirection");
     } else {
-      // unspecified should be the 'xsd' default, so maybe this is not even
-      // needed.
       gatewayDirection = "unspecified";
     }
 
+    // Count in/out sequence flow to validate gatewaydirection
+    List<Element> allSequenceFlow = XmlUtil.elements((Element) element.getParentNode(), "sequenceFlow");
+    Iterator<Element> iterator = allSequenceFlow.iterator();
+    
+    while (iterator.hasNext()) {
+      
+      Element sequenceFlowElement = iterator.next();
+      String sourceRef = sequenceFlowElement.getAttribute("sourceRef");
+      if (id.equals(sourceRef)) {
+        outgoing++;
+        outSequenceFlows.add(sequenceFlowElement);
+      } else if (sequenceFlowElement.getAttribute("targetRef").equals(id)) {
+        incoming++;
+        inSequenceFlows.add(sequenceFlowElement);
+      }
+      
+    }
+    
+    valid = validGatewayDirection(parse, name, element);
+    
   }
 
-  protected boolean validGatewayDirection(String gatewayDirection, int incomming, int outgoing, Parse parse, String elementName, Element element) {
+  private void resetMemberFields() {
+    incoming = 0;
+    inSequenceFlows = new ArrayList<Element>();
+    outgoing = 0;
+    outSequenceFlows = new ArrayList<Element>();
+    valid = true;
+  }
+
+  protected boolean validGatewayDirection(Parse parse, String elementName, Element element) {
    
-    log.debug(gatewayDirection + ": incomming: " + incomming + ", outgoing: " + outgoing);
+    if (log.isDebugEnabled()) {
+      log.debug(gatewayDirection + ": nr of incomming: " + incoming + ", nr of outgoing: " + outgoing);
+    }
     
-    boolean valid = !(("converging".equals(gatewayDirection) && (!(incomming > 1) || outgoing != 1))
-            || ("diverging".equals(gatewayDirection) && (incomming != 1 || !(outgoing > 1)))
-            || ("mixed".equals(gatewayDirection) && (incomming <= 1 || outgoing <= 1)));
+    boolean valid = !(("converging".equals(gatewayDirection) && (!(incoming > 1) || outgoing != 1))
+            || ("diverging".equals(gatewayDirection) && (incoming != 1 || !(outgoing > 1)))
+            || ("mixed".equals(gatewayDirection) && (incoming <= 1 || outgoing <= 1)));
 
     if (!valid) {
-      parse.addProblem(tagName+ " '" + elementName + "' has the wrong number of incomming (" + incomming + ") and outgoing (" + outgoing
+      parse.addProblem(tagName+ " '" + elementName + "' has the wrong number of incomming (" + incoming + ") and outgoing (" + outgoing
             + ") transitions for gatewayDirection='" + gatewayDirection + "'", element);
     }
     return valid;

Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ExclusiveGatewayBinding.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ExclusiveGatewayBinding.java	2009-12-20 12:42:36 UTC (rev 6000)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ExclusiveGatewayBinding.java	2009-12-20 12:44:20 UTC (rev 6001)
@@ -21,9 +21,6 @@
  */
 package org.jbpm.bpmn.flownodes;
 
-import java.util.Iterator;
-import java.util.List;
-
 import org.jbpm.pvm.internal.util.XmlUtil;
 import org.jbpm.pvm.internal.xml.Parse;
 import org.jbpm.pvm.internal.xml.Parser;
@@ -42,48 +39,38 @@
 
   public Object parse(Element element, Parse parse, Parser parser) {
 
-    super.parse(element);
+    super.parse(element, parse);
 
     String default_ = null;
     if (element.hasAttribute("default")) {
       default_ = element.getAttribute("default");
     }
 
+    // Check if all outgoing sequence flow have a condition (default excluded)
     boolean defaultExists = false;
-
-    List<Element> transitionElements = XmlUtil.elements((Element) element.getParentNode(), "sequenceFlow");
-    String elementId = element.getAttribute("id");
-    String elementName = element.getAttribute("name");
-
-    Element ce;
-
-    for (Iterator<Element> iterator = transitionElements.iterator(); iterator.hasNext();) {
-      Element transitionElement = iterator.next();
-      String sourceRef = transitionElement.getAttribute("sourceRef");
-      if (elementId.equals(sourceRef)) {
-        outgoing++;
-        ce = XmlUtil.element(transitionElement, "conditionExpression");
-
-        // TODO: Warn or error if CE is not of type tFormalExpression?
-
-        if (transitionElement.getAttribute("id").equals(default_)) {
+    for (Element outSeqFlow : outSequenceFlows) {
+      
+      String sourceRef = outSeqFlow.getAttribute("sourceRef");
+      Element conditionalExpression = XmlUtil.element(outSeqFlow, "conditionExpression");
+      
+      if (id.equals(sourceRef)) {
+        
+        if (outSeqFlow.getAttribute("id").equals(default_)) {
           defaultExists = true;
-          // All but the 'default' sequenceFlow need to have a condition
-        } else if (default_ != null && ce == null) {
-          parse.addProblem("exclusiveGateway '" + elementName + "' has default sequenceFlow '" + default_ + "' but " + transitionElement.getAttribute("id")
+        } else if (default_ != null && conditionalExpression == null) {  // All but the 'default' sequenceFlow need to have a condition
+          parse.addProblem("exclusiveGateway '" + name + "' has default sequenceFlow '" + default_ 
+                  + "' but " + outSeqFlow.getAttribute("id")
                   + " does not have a required conditionExpression", element);
           valid = false; // do not break. Parsing may find other issues;
         }
-      } else if (transitionElement.getAttribute("targetRef").equals(elementId)) {
-        incomming++;
+        
       }
+      
     }
 
-    boolean validGatewayDirection = validGatewayDirection(gatewayDirection, incomming, outgoing, parse, elementName, element);
-    valid = valid == false ? false : validGatewayDirection;
-
     if (default_ != null && !defaultExists) {
-      parse.addProblem("exclusiveGateway '" + elementName + "' default sequenceFlow '" + default_ + "' does not exist or is not related to this node", element);
+      parse.addProblem("exclusiveGateway '" + name + "' default sequenceFlow '" + default_ 
+              + "' does not exist or is not related to this node", element);
       valid = false;
     }
 

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	2009-12-20 12:42:36 UTC (rev 6000)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ParallelGatewayActivity.java	2009-12-20 12:44:20 UTC (rev 6001)
@@ -56,13 +56,21 @@
 
   public void execute(ExecutionImpl execution) {
     
-    if ("diverging".equals(gatewayDirection)) {
-      log.debug("Forking parallel gateway");
+    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");
+      }
       fork(execution);
-    } else if ("converging".equals(gatewayDirection)) {
-      log.debug("Joining parallel gateway");
+    } else if (nrOfIncoming > 1 && nrOfOutgoing == 1) {
+      if (log.isDebugEnabled()) {
+        log.debug("Joining parallel gateway");
+      }
       join(execution);
     }
+    
   }
   
   public void fork(ExecutionImpl execution) {

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	2009-12-20 12:42:36 UTC (rev 6000)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/ParallelGatewayBinding.java	2009-12-20 12:44:20 UTC (rev 6001)
@@ -21,10 +21,6 @@
  */
 package org.jbpm.bpmn.flownodes;
 
-import java.util.Iterator;
-import java.util.List;
-
-import org.jbpm.pvm.internal.util.XmlUtil;
 import org.jbpm.pvm.internal.xml.Parse;
 import org.jbpm.pvm.internal.xml.Parser;
 import org.w3c.dom.Element;
@@ -33,6 +29,7 @@
 /**
  * @author Tom Baeyens
  * @author Ronald van Kuijk (kukeltje)
+ * @author Joram Barrez
  * 
  */
 public class ParallelGatewayBinding extends AbstractGatewayBinding {
@@ -43,34 +40,14 @@
 
   public Object parse(Element element, Parse parse, Parser parser) {
 
-    super.parse(element);
-    
-    List<Element> transitionElements = XmlUtil.elements((Element) element.getParentNode(), "sequenceFlow");
-    String elementId = element.getAttribute("id");
-    String elementName = element.getAttribute("name");
+    super.parse(element, parse);
 
     if (gatewayDirection.equals("unspecified") || gatewayDirection.equals("mixed")) {
-      parse.addProblem("gatewayDirection='" + gatewayDirection + "' currently not supported on parallelGateway '" + elementName + "'", element);
+      parse.addProblem("gatewayDirection='" + gatewayDirection 
+              + "' currently not supported on parallelGateway '" + name + "'", element);
       return null;
     }
-    
-    for (Iterator<Element> iterator = transitionElements.iterator(); iterator.hasNext();) {
-      Element transitionElement = iterator.next();
-      String sourceRef = transitionElement.getAttribute("sourceRef");
-      if (elementId.equals(sourceRef)) {
-        outgoing++;
-        if (XmlUtil.element(transitionElement, "conditionExpression") != null) {
-          parse.addProblem("parallelGateway '" + elementName + "' has invalid conditionExpression outgoing transition", element);
-          valid = false;
-        }
-      } else if (transitionElement.getAttribute("targetRef").equals(elementId)) {
-        incomming++;
-      }
-    }
 
-    boolean validGatewayDirection = validGatewayDirection(gatewayDirection, incomming, outgoing, parse, elementName, element);
-    valid = valid == false ? false : validGatewayDirection;
-
     if (!valid) {
       return null;
     }

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


Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.parallel.gateway.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	2009-12-20 12:42:36 UTC (rev 6000)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml	2009-12-20 12:44:20 UTC (rev 6001)
@@ -436,6 +436,41 @@
         Gateways are depicted as a diamond shape, with an icon inside specifying the type 
         (exclusive, inclusive, etc.).
       </para>
+      
+      <para>
+        On every gateway type, the attribute <emphasis role="bold">gatewayDirection</emphasis>
+        can be set. following values are possible:
+        <itemizedlist>
+          <listitem>
+            <emphasis role="bold">unspecificed (default)</emphasis>: the gateway may have multiple
+            incoming and multiple sequence flow.
+          </listitem>
+          <listitem>
+            <emphasis role="bold">mixed</emphasis>: the gateway must have multiple incoming and
+            multiple outgoing sequence flow.
+          </listitem>
+          <listitem>
+            <emphasis role="bold">converging</emphasis>: the gateway must have multiple incoming
+            sequence flow, but can have only one outgoing sequence flow.
+          </listitem>
+          <listitem>
+            <emphasis role="bold">diverging</emphasis>: the gateway must have only one incoming
+            sequence flow and multiple outgoing sequence flow.
+          </listitem>
+        </itemizedlist>
+        Take for example the following example: a parallel gateway that has as gatewayDirection
+        'converging', will have a join behaviour.
+        <programlisting>
+&lt;parallelGateway id=&quot;myJoin&quot; name=&quot;My synchronizing join&quot; gatewayDirection=&quot;converging&quot; />        
+        </programlisting>
+        <emphasis role="bold">Note</emphasis>: the 'gatewayDirection' attribute is optional according 
+        to the specification. This means that we cannot rely on this attribute at runtime to
+        know which type of behaviour a certain gateway has (for example for a parallel gateway if
+        we have joining of forking behaviour). However, the 'gatewayDirection' attribute is used at parsing 
+        time as a constraint check for the incoming/outgoing sequence flow. So using this 
+        attirbute will lower the chance on errors in reference for sequence flow, but is not
+        required.
+      </para>
     
     </section>
     
@@ -454,7 +489,7 @@
         <emphasis role="bold">&lt;decision&gt;</emphasis> activity. The full technical name of the 
         exclusive gateway is the <emphasis role="bold">'exclusive data-based gateway'</emphasis>,
         but it is also often called the <emphasis role="bold">XOR Gateway</emphasis>.
-        The XOR gateway is depicted as a diamond with a plus icon inside. An empty diamond
+        The XOR gateway is depicted as a diamond with a 'X' icon inside. An empty diamond
         without a gateway also signifies an exclusive gateway.
       </para>
       
@@ -528,6 +563,93 @@
     
     </section>
     
+    <section id="parallelGateway">
+    
+      <title>Gateway: parallel Gateway</title>
+      
+      <para>
+        A parallel gateway is used to split or synchronize the respectively incoming or outgoing
+        sequence flow.
+        <itemizedlist>
+          <listitem>
+            A parallel gateway with one incoming sequence flow and more than one outgoing sequence
+            flow is called a <emphasis role="bold">'parallel split</emphasis> or an 
+            <emphasis role="bold">'AND-split'</emphasis>. All outgoing sequence flow are going to
+            be taken in parallel. <emphasis role="bold">Note: as defined by the specification,
+            conditions on the outgoing sequence flow are ignored.</emphasis>
+          </listitem>
+          <listitem>
+            A parallel gateway with multiple incoming sequence flow and one outgoing sequence flow
+            is called a <emphasis role="bold">'parallel join'</emphasis> or an 
+            <emphasis role="bold">AND-join</emphasis>. All incoming sequence flow need to arrive
+            in this parallel joing before the outgoing sequence flow is taken.
+          </listitem>
+        </itemizedlist>
+        A parallel gateway is defined as follows:
+        <programlisting>
+&lt;parallelGateway id=&quot;myParallelGateway&quot; name=&quot;My Parallel Gateway&quot; />        
+        </programlisting>
+        Note that the 'gatewayDirection' attribute can be used to catch modeling errors at parsing 
+        time (see above).
+      </para>
+      
+      <para>
+        The following diagrom shows how a parallel gateway can be used. After process start,
+        both the 'prepare shipment' and 'bill customer' user tasks will be active.
+        The parallel gateway is depicted as a diamond shape with a plus icon inside, both for the 
+        splitting and joining behaviour.
+        <mediaobject><imageobject><imagedata align="center" fileref="images/bpmn2.parallel.gateway.png"/></imageobject></mediaobject>
+        The XML counterpart of this diagram looks as follows:
+        <programlisting>
+  &lt;process id=&quot;parallelGateway&quot; name=&quot;BPMN2 example parallel gatewar&quot;&gt;
+  
+    &lt;startEvent id=&quot;Start&quot; /&gt;
+
+    &lt;sequenceFlow id=&quot;flow1&quot; name=&quot;fromStartToSplit&quot;
+      sourceRef=&quot;Start&quot;
+      targetRef=&quot;parallelGatewaySplit&quot;  /&gt;
+
+    &lt;parallelGateway id=&quot;parallelGatewaySplit&quot; name=&quot;Split&quot; 
+      gatewayDirection=&quot;diverging&quot;/&gt;
+
+    &lt;sequenceFlow id=&quot;flow2a&quot; name=&quot;Leg 1&quot;
+      sourceRef=&quot;parallelGatewaySplit&quot;
+      targetRef=&quot;prepareShipment&quot; /&gt;
+      
+    &lt;userTask id=&quot;prepareShipment&quot; name=&quot;Prepare shipment&quot; 
+      implementation=&quot;other&quot; /&gt;
+    
+    &lt;sequenceFlow id=&quot;flow2b&quot; name=&quot;fromPrepareShipmentToJoin&quot;
+      sourceRef=&quot;prepareShipment&quot;
+      targetRef=&quot;parallelGatewayJoin&quot;  /&gt;
+      
+    &lt;sequenceFlow id=&quot;flow3a&quot; name=&quot;Leg 2&quot; 
+      sourceRef=&quot;parallelGatewaySplit&quot;
+      targetRef=&quot;billCustomer&quot; /&gt;
+      
+    &lt;userTask id=&quot;billCustomer&quot; name=&quot;Bill customer&quot; 
+      implementation=&quot;other&quot; /&gt;
+    
+    &lt;sequenceFlow id=&quot;flow3b&quot; name=&quot;fromLeg2ToJoin&quot;
+      sourceRef=&quot;billCustomer&quot;
+      targetRef=&quot;parallelGatewayJoin&quot;  /&gt;
+
+    &lt;parallelGateway id=&quot;parallelGatewayJoin&quot; name=&quot;Join&quot; 
+      gatewayDirection=&quot;converging&quot;/&gt;
+      
+    &lt;sequenceFlow id=&quot;flow4&quot; 
+      sourceRef=&quot;parallelGatewayJoin&quot;
+      targetRef=&quot;End&quot;&gt;
+    &lt;/sequenceFlow&gt;
+
+    &lt;endEvent id=&quot;End&quot; name=&quot;End&quot; /&gt;
+    
+  &lt;/process&gt;
+        </programlisting>
+      </para>
+      
+    </section>
+    
     <section id="task">
 
       <title>Tasks</title>



More information about the jbpm-commits mailing list