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="decision"
targetRef="standard">
</sequenceFlow>
</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 @@
</process>
</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
>= 10}</conditionExpression>" +
+ " </sequenceFlow>" +
+ " <sequenceFlow id='flow3' sourceRef='decision'
targetRef='theEnd2' >" +
+ " <conditionExpression xsi:type='tFormalExpression'>${var
<= 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);
+ }
+
+}