[jbpm-commits] JBoss JBPM SVN: r6157 - in jbpm4/trunk/modules: bpmn/src/main/java/org/jbpm/bpmn/parser and 3 other directories.
do-not-reply at jboss.org
do-not-reply at jboss.org
Wed Feb 3 08:19:58 EST 2010
Author: jbarrez
Date: 2010-02-03 08:19:58 -0500 (Wed, 03 Feb 2010)
New Revision: 6157
Added:
jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.collapsed.subprocess.png
jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.embedded.subprocess.png
jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.subprocess.nested.png
jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.subprocess.parallel.paths.png
jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.subprocess.two.endevents.png
Modified:
jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/SubProcessActivity.java
jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/SubProcessBinding.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/test-db/src/test/java/org/jbpm/bpmn/test/subprocess/SubProcessTest.java
Log:
JBPM-2740: added doc/example for embedded subprocess
Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/SubProcessActivity.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/SubProcessActivity.java 2010-02-02 17:32:58 UTC (rev 6156)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/SubProcessActivity.java 2010-02-03 13:19:58 UTC (rev 6157)
@@ -29,7 +29,6 @@
import org.jbpm.api.JbpmException;
import org.jbpm.api.activity.ActivityExecution;
import org.jbpm.api.model.Activity;
-import org.jbpm.api.model.OpenExecution;
import org.jbpm.internal.log.Log;
import org.jbpm.pvm.internal.model.ActivityImpl;
import org.jbpm.pvm.internal.model.ExecutionImpl;
Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/SubProcessBinding.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/SubProcessBinding.java 2010-02-02 17:32:58 UTC (rev 6156)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/SubProcessBinding.java 2010-02-03 13:19:58 UTC (rev 6157)
@@ -69,7 +69,8 @@
ActivityBehaviour activityBehaviour = ((ActivityImpl) childActivity).getActivityBehaviour();
if ( (activityBehaviour instanceof BpmnEvent)
&& !(activityBehaviour instanceof NoneStartEventActivity) ) {
- parse.addProblem("Only none start events are allowed in an embedded sub process");
+ parse.addProblem("Only none start events are allowed in an embedded sub process. " +
+ "Event " + childActivity.getName() + " has no incoming sequence flow.");
}
}
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-02-02 17:32:58 UTC (rev 6156)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/parser/BpmnParser.java 2010-02-03 13:19:58 UTC (rev 6157)
@@ -152,8 +152,6 @@
// bind activities to their destinations
parseSequenceFlow(processElement, parse, processDefinition);
-
- postParsingValidations(parse, processDefinition);
} finally {
parse.contextStackPop();
@@ -474,84 +472,4 @@
}
- /**
- * Validations that are called at the end of the parsing: all activities,
- * sequence flow, etc are fully available to allow detailed validations.
- */
- public void postParsingValidations(Parse parse, BpmnProcessDefinition processDefinition) {
- validateSubProcessBoundaryNotCrossed(parse, processDefinition);
- }
-
- /* ---------------------
- * SUBPROCESS VALIDATION
- * --------------------- */
-
- /**
- * Validates that the boundary of a sub-process isn't crossed.
- */
- protected void validateSubProcessBoundaryNotCrossed(Parse parse, BpmnProcessDefinition processDefinition) {
- for (Activity activity : processDefinition.getActivities()) {
- ActivityImpl activityImpl = (ActivityImpl) activity;
- if ( activityImpl.getActivityBehaviour() instanceof SubProcessActivity) {
- validateSubProcessStartActivities(activityImpl, parse);
- validateSubProcessAllSequenceFlow(activityImpl, parse);
- }
- }
- }
-
- /**
- * Only none start activities and activities without incoming sequence flow
- * are allowed as start activities in a sub-process.
- */
- protected void validateSubProcessStartActivities(ActivityImpl subProcessActivity, Parse parse) {
- for (Activity childActivity : subProcessActivity.getActivities()) {
- if (childActivity.getIncomingTransitions().isEmpty()) {
-
- ActivityBehaviour activityBehaviour = ((ActivityImpl) childActivity).getActivityBehaviour();
- if ( (activityBehaviour instanceof BpmnEvent)
- && !(activityBehaviour instanceof NoneStartEventActivity) ) {
- parse.addProblem("Only none start events are allowed in an embedded sub process");
- }
-
- }
- }
- }
-
- /**
- * Sequence flow are not allowed to cross the sub-process boundary.
- * Exception to that rule is sequence flow which have as target a none start event (which actually
- * could graphically be viewed as boundary events).
- */
- protected void validateSubProcessAllSequenceFlow(ActivityImpl subProcessActivity, Parse parse) {
-
- // collect all child activity ids
- Set<String> childActivityIds = new HashSet<String>();
- for (Activity childActivity : subProcessActivity.getActivities()) {
- childActivityIds.add(childActivity.getName());
- }
-
- // Verify source/target of all sequenceflow
- for (Activity childActivity : subProcessActivity.getActivities()) {
- for (Transition incomingTransition : childActivity.getIncomingTransitions()) {
- validateSubProcessSequenceFlow(incomingTransition, childActivityIds, parse);
- }
- for (Transition outgoingTransition : childActivity.getOutgoingTransitions()) {
- validateSubProcessSequenceFlow(outgoingTransition, childActivityIds, parse);
- }
- }
- }
-
- protected void validateSubProcessSequenceFlow(Transition transition, Set<String> subProcessActivityIds, Parse parse) {
- if (!subProcessActivityIds.contains(transition.getSource().getName())) {
- parse.addProblem("Invalid sequence flow " + transition.getName()
- + ": cannot cross sub-process boundaries from " + transition.getSource().getName()
- + " into the sub process activity.");
- }
- if (!subProcessActivityIds.contains(transition.getDestination().getName())) {
- parse.addProblem("Invalid sequence flow " + transition.getName()
- + ": cannot cross sub-process boundaries to " + transition.getSource().getName()
- + " from within the sub process activity.");
- }
- }
-
}
Added: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.collapsed.subprocess.png
===================================================================
(Binary files differ)
Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.collapsed.subprocess.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.embedded.subprocess.png
===================================================================
(Binary files differ)
Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.embedded.subprocess.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.subprocess.nested.png
===================================================================
(Binary files differ)
Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.subprocess.nested.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.subprocess.parallel.paths.png
===================================================================
(Binary files differ)
Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.subprocess.parallel.paths.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.subprocess.two.endevents.png
===================================================================
(Binary files differ)
Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.subprocess.two.endevents.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-02-02 17:32:58 UTC (rev 6156)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml 2010-02-03 13:19:58 UTC (rev 6157)
@@ -1219,6 +1219,100 @@
<title>Advanced constructs</title>
+ <section id="embeddedSubProcess">
+
+ <title>Embedded sub-process</title>
+
+ <para>
+ Subprocesses are in the first place a way of making a process "hierarchical", meaning that
+ a modeller can create several 'levels' of detail. The top level view then explains the
+ high-level way of doing things, while the lowest level focusses on the nitty gritty
+ details.
+ </para>
+
+ <para>
+ Take for example the following diagram. In this model, only the high level steps are shown.
+ The actual implementation of the "Check credit" step is hidden behind a
+ <emphasis role="bold">collapsed subprocess</emphasis>, which may be the perfect level
+ of detail to discuss business processes with end-users.
+ <mediaobject><imageobject><imagedata align="center" fileref="images/bpmn2.collapsed.subprocess.png"/></imageobject></mediaobject>
+ </para>
+
+ <para>
+ The second major use case for sub-processes is that the sub-process "container"
+ acts as a scope for events. When an event is fired from within the sub-process, the catch
+ events on the boundary of the sub-process will be the first to receive this event.
+ </para>
+
+ <para>
+ A sub-process that is defined within a top-level process is called an <emphasis role="bold">
+ embeddable sub-process</emphasis>. All process data that is available in the parent
+ process is also available in the sub-process. The following diagram shows the expanded
+ version of the model above.
+ <mediaobject><imageobject><imagedata align="center" fileref="images/bpmn2.embedded.subprocess.png"/></imageobject></mediaobject>
+ The XML counterpart of this model looks as follows:$
+ <programlisting>
+<process id="embeddedSubprocess">
+
+ <startEvent id="theStart" />
+ <sequenceFlow id="flow1" sourceRef="theStart" targetRef="receiveOrder" />
+ <receiveTask name="Receive order" id="receiveOrder" />
+ <sequenceFlow id="flow2" sourceRef="receiveOrder" targetRef="checkCreditSubProcess" />
+ <emphasis role="bold"><subProcess id="checkCreditSubProcess" name="Credit check"></emphasis>
+
+ ...
+
+ <emphasis role="bold"></subProcess></emphasis>
+
+ <sequenceFlow id="flow9" sourceRef="checkCreditSubProcess" targetRef="theEnd" />
+ <endEvent id="theEnd" />
+
+</process>
+ </programlisting>
+ Note that inside the sub-process, events, activities, tasks are defined as if it were
+ a top-level process (hence the three "..." within the XML example above. Sub-processes
+ are <emphasis role="bold">only allowed to have a none start event</emphasis>.
+ </para>
+
+ <para>
+ Conceptually an embedded sub-process works as follows: when an execution arrives
+ at the subprocess, a child execution is created. The child execution can then later create
+ other (sub-)child executions, for example when a parallel gateway is used whithin the
+ sub-process. The sub-process however, is only completed when no executions are active anymore
+ within the subprocess. In that case, the parent execution is taken for further continuation
+ of the process.
+ </para>
+ <para>
+ For example, in the following diagram, the "Third task"
+ will only be reached after both the "First task" and the "Second task"
+ are completed. Completing one of the tasks in the sub-process, will not trigger the
+ continuation of the sub-process, since one execution is still active within the sub-process.
+ <mediaobject><imageobject><imagedata align="center" fileref="images/bpmn2.subprocess.two.endevents.png"/></imageobject></mediaobject>
+ </para>
+
+ <para>
+ Sub-processes can have multiple start events. In that case, multiple parallel paths
+ will exist within the sub-process. The rules for sub-process completion are unchanged:
+ the sub-process will only be left when all the executions of the parallel paths are
+ ended.
+ <mediaobject><imageobject><imagedata align="center" fileref="images/bpmn2.subprocess.parallel.paths.png"/></imageobject></mediaobject>
+ </para>
+
+ <para>
+ Nested sub-processes are also possible. This way, the process can be divided into several
+ levels of detail. There is no limitation on the levels of nesting.
+ <mediaobject><imageobject><imagedata align="center" fileref="images/bpmn2.subprocess.nested.png"/></imageobject></mediaobject>
+ </para>
+
+ <para>
+ Implementation note: According to the BPMN 2 specification, an activity without ougoing sequence
+ flow implicitly ends the current execution. However currently, it is necessary for a correct functioning to
+ specifically use an end event within the sub-process to end a certain path. This will
+ be enhanced in the future to be specification-compliant.
+ </para>
+
+ </section> <!-- End of embedded subprocess -->
+
<section id="Timer start event">
<title>Timer start event</title>
Modified: jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/subprocess/SubProcessTest.java
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/subprocess/SubProcessTest.java 2010-02-02 17:32:58 UTC (rev 6156)
+++ jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/subprocess/SubProcessTest.java 2010-02-03 13:19:58 UTC (rev 6157)
@@ -138,6 +138,33 @@
" </process>" +
"</definitions>";
+ private static final String SUBPROCESS_WITH_UNJOINED_PATHS =
+ "<definitions>" +
+ " <process id='unjoinedPaths'>" +
+ " <startEvent id='theStart' />" +
+ " <sequenceFlow id='flow1' sourceRef='theStart' targetRef='mySubProcess' />" +
+ " <subProcess id='mySubProcess'>" +
+ " <startEvent id='subProcessStart' />" +
+ " <sequenceFlow id='subFlow1' sourceRef='subProcessStart' targetRef='splitInSubProcess' />" +
+ " <parallelGateway id='splitInSubProcess' />" +
+ " <sequenceFlow id='subFlow2' sourceRef='splitInSubProcess' targetRef='subTask1' />" +
+ " <sequenceFlow id='subFlow3' sourceRef='splitInSubProcess' targetRef='subTask2' />" +
+ " <sequenceFlow id='subFlow4' sourceRef='splitInSubProcess' targetRef='subTask3' />" +
+ " <userTask id='subTask1' name='firstTask' />" +
+ " <userTask id='subTask2' name='secondTask' />" +
+ " <userTask id='subTask3' name='thirdTask' />" +
+ " <sequenceFlow id='subFlow4' sourceRef='subTask1' targetRef='subEnd1' />" +
+ " <endEvent id='subEnd1' />" +
+ " <sequenceFlow id='subFlow5' sourceRef='subTask2' targetRef='subEnd2' />" +
+ " <endEvent id='subEnd2' />" +
+ " <sequenceFlow id='subFlow6' sourceRef='subTask3' targetRef='subEnd3' />" +
+ " <endEvent id='subEnd3' />" +
+ " </subProcess>" +
+ " <sequenceFlow id='flow2' sourceRef='mySubProcess' targetRef='theEnd' />" +
+ " <endEvent id='theEnd' />" +
+ " </process>" +
+ "</definitions>";
+
/**
* Tests a simple sub process with sequentially one start, a user task and an end.
*/
@@ -241,5 +268,26 @@
taskService.completeTask(tasks.get(0).getId());
assertProcessInstanceEnded(pi);
}
+
+ /**
+ * Tests a process that has a sub-process which has a splitting parallelgatway without
+ * a merging parallel gateway later on. This way, execution state juggling gets a bit trickier.
+ */
+ public void testSubProcessWithUnjoinedPaths() {
+ deployBpmn2XmlString(SUBPROCESS_WITH_UNJOINED_PATHS);
+ ProcessInstance pi = executionService.startProcessInstanceByKey("unjoinedPaths");
+
+ TaskQuery query = taskService.createTaskQuery().processInstanceId(pi.getId()).orderAsc(TaskQuery.PROPERTY_NAME);
+ List<Task> tasks = query.list();
+ assertEquals(3, tasks.size());
+ assertEquals("firstTask", tasks.get(0).getName());
+ assertEquals("secondTask", tasks.get(1).getName());
+ assertEquals("thirdTask", tasks.get(2).getName());
+
+ taskService.completeTask(tasks.get(0).getId());
+ taskService.completeTask(tasks.get(1).getId());
+ taskService.completeTask(tasks.get(2).getId());
+ assertProcessInstanceEnded(pi);
+ }
}
More information about the jbpm-commits
mailing list