[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>
+<parallelGateway id="myJoin" name="My synchronizing join" gatewayDirection="converging" />
+ </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"><decision></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>
+<parallelGateway id="myParallelGateway" name="My Parallel Gateway" />
+ </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>
+ <process id="parallelGateway" name="BPMN2 example parallel gatewar">
+
+ <startEvent id="Start" />
+
+ <sequenceFlow id="flow1" name="fromStartToSplit"
+ sourceRef="Start"
+ targetRef="parallelGatewaySplit" />
+
+ <parallelGateway id="parallelGatewaySplit" name="Split"
+ gatewayDirection="diverging"/>
+
+ <sequenceFlow id="flow2a" name="Leg 1"
+ sourceRef="parallelGatewaySplit"
+ targetRef="prepareShipment" />
+
+ <userTask id="prepareShipment" name="Prepare shipment"
+ implementation="other" />
+
+ <sequenceFlow id="flow2b" name="fromPrepareShipmentToJoin"
+ sourceRef="prepareShipment"
+ targetRef="parallelGatewayJoin" />
+
+ <sequenceFlow id="flow3a" name="Leg 2"
+ sourceRef="parallelGatewaySplit"
+ targetRef="billCustomer" />
+
+ <userTask id="billCustomer" name="Bill customer"
+ implementation="other" />
+
+ <sequenceFlow id="flow3b" name="fromLeg2ToJoin"
+ sourceRef="billCustomer"
+ targetRef="parallelGatewayJoin" />
+
+ <parallelGateway id="parallelGatewayJoin" name="Join"
+ gatewayDirection="converging"/>
+
+ <sequenceFlow id="flow4"
+ sourceRef="parallelGatewayJoin"
+ targetRef="End">
+ </sequenceFlow>
+
+ <endEvent id="End" name="End" />
+
+ </process>
+ </programlisting>
+ </para>
+
+ </section>
+
<section id="task">
<title>Tasks</title>
More information about the jbpm-commits
mailing list