[jbpm-commits] JBoss JBPM SVN: r4749 - in jbpm4/trunk: modules/devguide/src/main/docbook/en and 21 other directories.
do-not-reply at jboss.org
do-not-reply at jboss.org
Wed May 6 10:03:44 EDT 2009
Author: tom.baeyens at jboss.com
Date: 2009-05-06 10:03:44 -0400 (Wed, 06 May 2009)
New Revision: 4749
Added:
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Configuration.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-Architecture.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ImplementingBasicActivities.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ProcessAnatomy.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ImplementingAdvancedActivities.xml
jbpm4/trunk/modules/distro/src/main/files/jboss/config.jboss4/deploy/jbpm/jbpm-service.sar/META-INF/
jbpm4/trunk/modules/distro/src/main/files/jboss/config.jboss4/deploy/jbpm/jbpm-service.sar/META-INF/jboss-service.xml
Removed:
jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/ProcessService.java
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Architecture.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-ImplementingBasicActivities.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ProcessAnatomy.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ImplementingAdvancedActivities.xml
jbpm4/trunk/modules/distro/src/main/deployer/
jbpm4/trunk/modules/distro/src/main/resources/
Modified:
jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch01-Introduction.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch02-ProcessVirtualMachine.xml
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/chxx-ExecutionModes.xml
jbpm4/trunk/modules/distro/src/main/files/jboss/config.common/deploy/jbpm/jbpm-service.sar/jbpm.cfg.xml
jbpm4/trunk/modules/distro/src/main/files/jboss/jbpm.cfg.integration.tests/jbpm.cfg.xml
jbpm4/trunk/modules/distro/src/main/files/jboss/jbpm.cfg.remote.client/jbpm.cfg.xml
jbpm4/trunk/modules/enterprise/src/test/java/org/jbpm/enterprise/internal/ejb/TimerTest.java
jbpm4/trunk/modules/enterprise/src/test/java/org/jbpm/test/deployer/DeployerTestServlet.java
jbpm4/trunk/modules/examples/src/test/resources/jbpm.cfg.xml
jbpm4/trunk/modules/jpdl/src/main/resources/jbpm.jpdl.cfg.xml
jbpm4/trunk/modules/jpdl/src/test/resources/jbpm.cfg.xml
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/env/JbpmConfigurationParser.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/binding/VersionTimestampPolicy.java
jbpm4/trunk/modules/pvm/src/main/resources/jbpm.default.cfg.xml
jbpm4/trunk/modules/pvm/src/main/resources/jbpm.identity.cfg.xml
jbpm4/trunk/modules/pvm/src/main/resources/jbpm.jbossremote.cfg.xml
jbpm4/trunk/modules/pvm/src/main/resources/jbpm.jobexecutor.cfg.xml
jbpm4/trunk/modules/pvm/src/main/resources/jbpm.tx.hibernate.cfg.xml
jbpm4/trunk/modules/pvm/src/main/resources/jbpm.tx.jta.cfg.xml
jbpm4/trunk/modules/pvm/src/test/resources/jbpm.cfg.xml
jbpm4/trunk/modules/pvm/src/test/resources/org/jbpm/pvm/api/db/svc/environment.cfg.xml
jbpm4/trunk/modules/pvm/src/test/resources/org/jbpm/pvm/api/timer/environment.cfg.xml
jbpm4/trunk/modules/test-db/src/test/resources/jbpm.cfg.xml
jbpm4/trunk/modules/test-load/src/test/resources/jbpm.cfg.xml
jbpm4/trunk/qa/hudson-jbpm4-jboss.sh
Log:
cleanup and developer documentation
Deleted: jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/ProcessService.java
===================================================================
--- jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/ProcessService.java 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/ProcessService.java 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,59 +0,0 @@
-/*
- * 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.api;
-
-import java.util.List;
-
-
-/** a process definition repository.
- *
- * @author Tom Baeyens
- */
-public interface ProcessService {
-
- /** start a deployment */
- Deployment createDeployment();
-
- /** all deployed process definition keys. */
- List<String> findProcessDefinitionKeys();
-
- /** all versions of the given process.
- * @return the process definitions in descending version order. So you get the
- * highest version number as the first. */
- List<ProcessDefinition> findProcessDefinitionsByKey(String processDefinitionKey);
-
- /** latest version of the processDefinition with the given key. */
- ProcessDefinition findLatestProcessDefinitionByKey(String processDefinitionKey);
-
- /** specific version of a named processDefinition. */
- ProcessDefinition findProcessDefinitionById(String processDefinitionId);
-
- /** search for process definitions */
- ProcessDefinitionQuery createProcessDefinitionQuery();
-
- /** deletes process definition if there are no existing executions.
- * @throws JbpmException if there are existing executions or history. */
- void deleteProcessDefinition(String processDefinitionId);
-
- /** deletes process definition, the existing executions and the history. */
- void deleteProcessDefinitionCascade(String processDefinitionId);
-}
Modified: jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/master.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -3,10 +3,11 @@
<!DOCTYPE book [
<!ENTITY ch01-Introduction SYSTEM "modules/ch01-Introduction.xml">
<!ENTITY ch02-ProcessVirtualMachine SYSTEM "modules/ch02-ProcessVirtualMachine.xml">
- <!ENTITY ch03-Architecture SYSTEM "modules/ch03-Architecture.xml">
- <!ENTITY ch04-ImplementingBasicActivities SYSTEM "modules/ch04-ImplementingBasicActivities.xml">
- <!ENTITY ch05-ProcessAnatomy SYSTEM "modules/ch05-ProcessAnatomy.xml">
- <!ENTITY ch06-ImplementingAdvancedActivities SYSTEM "modules/ch06-ImplementingAdvancedActivities.xml">
+ <!ENTITY ch03-Configuration SYSTEM "modules/ch03-Configuration.xml">
+ <!ENTITY ch04-Architecture SYSTEM "modules/ch04-Architecture.xml">
+ <!ENTITY ch05-ImplementingBasicActivities SYSTEM "modules/ch05-ImplementingBasicActivities.xml">
+ <!ENTITY ch06-ProcessAnatomy SYSTEM "modules/ch06-ProcessAnatomy.xml">
+ <!ENTITY ch07-ImplementingAdvancedActivities SYSTEM "modules/ch07-ImplementingAdvancedActivities.xml">
<!ENTITY ch10-SoftwareLogging SYSTEM "modules/ch10-SoftwareLogging.xml">
<!ENTITY ch11-History SYSTEM "modules/ch11-History.xml">
]>
@@ -21,10 +22,11 @@
&ch01-Introduction;
&ch02-ProcessVirtualMachine;
- &ch03-Architecture;
- &ch04-ImplementingBasicActivities;
- &ch05-ProcessAnatomy;
- &ch06-ImplementingAdvancedActivities;
+ &ch03-Configuration;
+ &ch04-Architecture;
+ &ch05-ImplementingBasicActivities;
+ &ch06-ProcessAnatomy;
+ &ch07-ImplementingAdvancedActivities;
&ch10-SoftwareLogging;
&ch11-History;
Modified: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch01-Introduction.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch01-Introduction.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch01-Introduction.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -10,12 +10,13 @@
</section>
<section>
- <title>Sources</title>
- <para>The source code for jBPM can be found here:
+ <title>Sources and WIKI</title>
+ <para>The source code for jBPM can be found in our <ulink url="http://subversion.tigris.org/">SVN</ulink> repository:</para>
<ulink url="https://anonsvn.jboss.org/repos/jbpm/jbpm4/">https://anonsvn.jboss.org/repos/jbpm/jbpm4/</ulink>
- </para>
<para>A description of how to build the sources is available in the wiki:</para>
<ulink url="http://www.jboss.org/community/docs/DOC-12867">http://www.jboss.org/community/docs/DOC-12867</ulink>
+ <para>The jBPM WIKI is located here:</para>
+ <ulink url="http://www.jboss.org/community/docs/DOC-11184">http://www.jboss.org/community/docs/DOC-11184</ulink>
</section>
<section>
Modified: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch02-ProcessVirtualMachine.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch02-ProcessVirtualMachine.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch02-ProcessVirtualMachine.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -26,10 +26,11 @@
</figure>
<para>The Process Virtual
Machine doesn't contain any such activity implementations. It only provides the
- execution environment and an activity API to write <literal>Activity</literal>
+ execution environment and an activity API to write <literal>ActivityBehaviour</literal>
implementations as Java components. Activities can also be wait states. This means
that the activity control flow goes outside the process system. For example a human task
- or invoking an service asynchronously.
+ or invoking an service asynchronously. While the execution is waiting, the runtime state
+ of that execution can be persisted in a DB.
</para>
<para>Many executions can be started for one process definition. An execution is a pointer
that keeps track of the current activity.
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Architecture.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Architecture.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Architecture.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,250 +0,0 @@
-<chapter id="architecture">
- <title>Architecture</title>
-
- <section id="apis">
- <title>APIs</title>
- <para>The Process Virtual Machine has 4 integrated API's that together
- offer a complete coverage of working with processes in the different execution modes.
- Each of the APIs has a specific purpose that fits within the following overall
- architecture.
- </para>
- <figure id="apis">
- <title>The 4 API's of the Process Virtual Machine</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/apis.png"/></imageobject></mediaobject>
- </figure>
- <para>The services interfaces should be used from application code that wants to interact
- with the Process Virtual Machine which runs in transactional persistent mode, backed by a
- database. This is the most typical way how users interact with the PVM as a workflow engine.
- </para>
- <para>To execute processes without persistence, the client API can be used to work with process
- and execution objects directly. The client API expose the methods of the core model objects.
- </para>
- <para>The activity API is used to implement the runtime behaviour of activities. So a activity
- type is in fact a component with at the core an implementation of the <literal>Activity</literal>
- interface. Activity implementations can control the flow of execution.
- </para>
- <para>The event listener API serves to write pieces of Java code that should be executed upon
- process events. It's very similar to the activity API with that exception that event listeners
- are not able to control the flow of execution.
- </para>
- </section>
-
- <section>
- <title>Activity API</title>
- <para>The activity API allows to implement the runtime activity behaviour in Java.
- </para>
- <programlisting>public interface Activity extends Serializable {
- void execute(ActivityExecution execution) throws Exception;
-}</programlisting>
- <para>An activity is the behaviour of the activity to which it is associated.
- The provided execution is the execution that arrives in the activity.
- The interface <literal>ActivityExecution</literal> exposes special
- methods to control the execution flow.
- </para>
- <programlisting>public interface ActivityExecution extends OpenExecution {
-
- void waitForSignal();
- void take(String transitionName);
- void execute(String activityName);
-
- ...
-
-}</programlisting>
- </section>
-
- <section>
- <title>Event listener API</title>
- <para>The event listener API allows for listeners to be developed in Java code
- and that are invoked on specific process events like entering a activity or leaving
- a activity. It is very similar to the activity API, but the difference is
- that the propagation of the execution flow cannot be controlled. E.g. when an execution
- is taking a transition, a listener to that event can be notified, but since the
- transition is already being taking, the execution flow cannot be changed
- by the event listeners.
- </para>
- <programlisting>public interface EventListener extends Serializable {
-
- void notify(EventListenerExecution execution) throws Exception;
-
-}</programlisting>
- </section>
-
- <section>
- <title>Client API</title>
- <para>The client API was already introduced above in the object execution mode
- and embedded execution mode. It's an interface that exposes the methods for
- managing executions on the plain process definition and execution objects directly.
- </para>
- <para>At a minimal, the client API and the activity API are needed to create
- some a process definition with activities and execute it.
- </para>
- </section>
-
- <section>
- <title>Environment</title>
- <para>In the persistent execution mode, the first purpose of the environment is
- to enable processes to be executed in different transactional environments like
- standard Java, enterprise Java, SEAM and Spring.
- </para>
- <para>The PVM code itself will only use transactional resources through self-defined
- interfaces. For example, the PVM itself has interfaces for some methods on the hibernate
- session, a async messaging session and a timer session.
- </para>
- <para>The environment allows to configure the actual implementations, lazy
- initialization of the services on a request-basis and caching the service
- objects for the duration of the transaction.
- </para>
- <para>An environment factory is static and one environment factory can serve
- all the threads in an application.
- </para>
- <programlisting>EnvironmentFactory environmentFactory = new PvmEnvironmentFactory("environment.cfg.xml");</programlisting>
- <para>Environment blocks can surround persistent process operations
- like this:
- </para>
- <programlisting>Environment environment = environmentFactory.openEnvironment();
-try {
-
- ... inside the environment block...
-
-} finally {
- environment.close();
-}</programlisting>
- <para>The PVM itself will fetch all it's transactional resources and configurations
- from the environment. It's recommended that <literal>Activity</literal> implementations
- do the same.
- </para>
- </section>
-
- <section>
- <title>Commands</title>
- <para>Commands encapsulate operations that are to be executed within an environment
- block. The main purpose for commands is to capture the logic of
- </para>
- <programlisting>public interface Command<T> extends Serializable {
-
- T execute(Environment environment) throws Exception;
-
-}</programlisting>
- <para></para>
- </section>
-
- <section>
- <title>Services</title>
- <para>There are three services: <literal>ProcessService</literal>,
- <literal>ExecutionService</literal> and <literal>ManagementService</literal>.
- In general, services are session facades that expose methods for persistent
- usage of the PVM. The next fragments show the essential methods as example
- to illustrate those services.
- </para>
- <para>The <literal>ProcessService</literal> manages the repository of
- process definitions.
- </para>
- <programlisting>public interface ProcessService {
-
- ProcessDefinition deploy(Deployment deployment);
-
- ProcessDefinition findLatestProcessDefinition(String processDefinitionName);
-
- ...
-
-}</programlisting>
- <para>The <literal>ExecutionService</literal> manages the runtime
- executions.</para>
- <programlisting>public interface ExecutionService {
-
- Execution startExecution(String processDefinitionId, String executionKey);
-
- Execution signalExecution(String executionId, String signalName);
-
- ...
-
-}</programlisting>
- <para>The <literal>ManagementService</literal> groups all management operations
- that are needed to keep the system up and running.
- </para>
- <programlisting>public interface ManagementService {
-
- List<Job> getJobsWithException(int firstResult, int maxResults);
-
- void executeJob(String jobId);
-
- ...
-
-}</programlisting>
- <para>The implementation of all these methods is encapsulated in
- <literal>Command</literal>s. And the three services all delegate the
- execution of the commands to a <literal>CommandService</literal>:
- </para>
- <programlisting>public interface CommandService {
-
- <T> T execute(Command<T> command);
-
-}</programlisting>
- <para>The <literal>CommandService</literal> is configured in the
- environment. A chain of CommandServices can act as interceptors
- around a command. This is the core mechanism on how persistence and
- transactional support can be offered in a variety of environments.
- </para>
- <para>From the default configuration which is included in full above,
- here is the section that configures the services
- </para>
- <programlisting><jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
-
- <process-engine>
-
- <process-service />
- <execution-service />
- <management-service />
-
- <command-service>
- <retry-interceptor />
- <environment-interceptor />
- <standard-transaction-interceptor />
- </command-service>
-
- ...
- </programlisting>
- <para>The three services <literal>process-service</literal>, <literal>execution-service</literal>
- and <literal>management-service</literal> will look up the configured
- <literal>command-service</literal> by type. The <literal>command-service</literal>
- tag corresponds to the default command service that essentially does nothing else
- then just execute the command providing it the current environment.
- </para>
- <para>The configured <literal>command-service</literal> results into the following
- a chain of three interceptors followed by the default command executor.
- </para>
- <figure id="interceptors">
- <title>The CommandService interceptors</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/interceptors.png"/></imageobject></mediaobject>
- </figure>
- <para>The retry interceptor is the first in the chain and that one that will be exposed as the
- <literal>CommandService.class</literal> from the environment. So the retry interceptor
- will be given to the respective services <literal>process-service</literal>, <literal>execution-service</literal>
- and <literal>management-service</literal>.
- </para>
- <para>The <literal>retry-interceptor</literal> will catch hibernate StaleObjectExceptions
- (indicating optimistic locking failures) and retry to execute the command.
- </para>
- <para>The <literal>environment-interceptor</literal> will put an environment block
- around the execution of the command.
- </para>
- <para>The <literal>standard-transaction-interceptor</literal> will initialize a
- <literal>StandardTransaction</literal>. The hibernate session/transaction will be
- enlisted as a resource with this standard transaction.
- </para>
- <para>Different configurations of this interceptor stack will also enable to
- </para>
- <itemizedlist>
- <listitem>delegate execution to a local ejb command service so that an container
- managed transaction is started.
- </listitem>
- <listitem>delegate to a remote ejb command service so that the command actually
- gets executed on a different JVM.
- </listitem>
- <listitem>package the command as an asynchronous message so that the command gets
- executed asynchronously in a different transaction.
- </listitem>
- </itemizedlist>
- </section>
-
-</chapter>
\ No newline at end of file
Added: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Configuration.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Configuration.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Configuration.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -0,0 +1,66 @@
+<chapter id="configuration">
+ <title>Configuration</title>
+
+ <para>The jbpm.jar contains a number of default configuration
+ files that can be imported by the user configuration file.
+ </para>
+ <para>This way, it's easy to include
+ or exclude features for users. And also the configuration details are kept in
+ the implementation so users that only import those configuration files
+ will not be affected when we release changes in those configuration files.
+ </para>
+ <para>Configuration files that can be imported by the user's <literal>jbpm.cfg.xml</literal>:</para>
+ <programlisting>jbpm.default.cfg.xml
+jbpm.identity.cfg.xml
+jbpm.jbossremote.cfg.xml
+jbpm.jobexecutor.cfg.xml
+jbpm.tx.hibernate.cfg.xml
+jbpm.tx.jta.cfg.xml</programlisting>
+ <para><literal>jbpm.default.cfg.xml</literal>: Contains the default configurations
+ like the services, the hibernate configuration (configured from resource jbpm.hibernate.cfg.xml),
+ hibernate session factory, business calendar and so on.
+ </para>
+ <para>A typical configuration for standard java would look like this:
+ </para>
+ <programlisting><?xml version="1.0" encoding="UTF-8"?>
+
+<jbpm-configuration>
+
+ <import resource="jbpm.default.cfg.xml" />
+ <import resource="jbpm.tx.hibernate.cfg.xml" />
+ <import resource="jbpm.jpdl.cfg.xml" />
+ <import resource="jbpm.identity.cfg.xml" />
+ <import resource="jbpm.jobexecutor.cfg.xml" />
+
+</jbpm-configuration></programlisting>
+ <para>In a JTA environment, replace <literal>jbpm.tx.hibernate.cfg.xml</literal>
+ with <literal>jbpm.tx.jta.cfg.xml</literal> </para>
+ <para>To customize any of these configurations users can just replace
+ the import with the customized content in the <literal>jbpm.cfg.xml</literal>.
+ </para>
+
+ <para>The jbpm.jar contains also following hibernate mapping configuration files:</para>
+ <programlisting>jbpm.execution.hbm.xml
+jbpm.history.hbm.xml
+jbpm.identity.hbm.xml
+jbpm.repository.hbm.xml
+jbpm.task.hbm.xml
+jbpm.jpdl.hbm.xml</programlisting>
+ <para>These all map the java domain model objects to a relational database.
+ </para>
+ <para>Other various configuration files that are included in jbpm.jar:</para>
+ <programlisting>jbpm.task.lifecycle.xml
+jbpm.variable.types.xml
+jbpm.wire.bindings.xml
+jbpm.jpdl.activities.xml
+jbpm.jpdl.eventlisteners.xml</programlisting>
+
+ <para>To get started on the parsing for the configuration files, see
+ </para>
+ <itemizedlist>
+ <listitem>class org.jbpm.pvm.internal.env.JbpmConfigurationParser</listitem>
+ <listitem>resource modules/pvm/src/main/resources/jbpm.wire.bindings.xml</listitem>
+ <listitem>package modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/binding</listitem>
+ </itemizedlist>
+
+</chapter>
\ No newline at end of file
Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Configuration.xml
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-Architecture.xml (from rev 4742, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Architecture.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-Architecture.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-Architecture.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -0,0 +1,260 @@
+<chapter id="architecture">
+ <title>Architecture</title>
+
+ <section id="apis">
+ <title>APIs</title>
+ <para>The Process Virtual Machine has 4 integrated API's that together
+ offer a complete coverage of working with processes in the different execution modes.
+ Each of the APIs has a specific purpose that fits within the following overall
+ architecture.
+ </para>
+ <figure id="apis">
+ <title>The 4 API's of the Process Virtual Machine</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/apis.png"/></imageobject></mediaobject>
+ </figure>
+ <para>The services interfaces should be used from application code that wants to interact
+ with the Process Virtual Machine which runs in transactional persistent mode, backed by a
+ database. This is the most typical way how users interact with the PVM as a workflow engine.
+ </para>
+ <para>To execute processes without persistence, the client API can be used to work with process
+ and execution objects directly. The client API expose the methods of the core model objects.
+ </para>
+ <para>The activity API is used to implement the runtime behaviour of activities. So a activity
+ type is in fact a component with at the core an implementation of the <literal>ActivityBehaviour</literal>
+ interface. ActivityBehaviour implementations can control the flow of execution.
+ </para>
+ <para>The event listener API serves to write pieces of Java code that should be executed upon
+ process events. It's very similar to the activity API with that exception that event listeners
+ are not able to control the flow of execution.
+ </para>
+ </section>
+
+ <section>
+ <title>Activity API</title>
+ <para>The activity API allows to implement the runtime activity behaviour in Java.
+ </para>
+ <programlisting>public interface ActivityBehaviour extends Serializable {
+ void execute(ActivityExecution execution) throws Exception;
+}</programlisting>
+ <para>An activity is the behaviour of the activity to which it is associated.
+ The provided execution is the execution that arrives in the activity.
+ The interface <literal>ActivityExecution</literal> exposes special
+ methods to control the execution flow.
+ </para>
+ <programlisting>public interface ActivityExecution extends OpenExecution {
+
+ void waitForSignal();
+ void take(String transitionName);
+ void execute(String activityName);
+
+ ...
+
+}</programlisting>
+ </section>
+
+ <section>
+ <title>Event listener API</title>
+ <para>The event listener API allows for listeners to be developed in Java code
+ and that are invoked on specific process events like entering a activity or leaving
+ a activity. It is very similar to the activity API, but the difference is
+ that the propagation of the execution flow cannot be controlled. E.g. when an execution
+ is taking a transition, a listener to that event can be notified, but since the
+ transition is already being taking, the execution flow cannot be changed
+ by the event listeners.
+ </para>
+ <programlisting>public interface EventListener extends Serializable {
+
+ void notify(EventListenerExecution execution) throws Exception;
+
+}</programlisting>
+ </section>
+
+ <section>
+ <title>Client API</title>
+ <para>The client API is the interface that exposes the methods for
+ managing executions on the plain process definition and execution objects directly.
+ </para>
+ <para>At a minimal, the client API and the activity API are needed to create
+ some a process definition with activities and execute it.
+ </para>
+ </section>
+
+ <section>
+ <title>Environment</title>
+ <para>In the persistent execution mode, the first purpose of the environment is
+ to enable processes to be executed in different transactional environments like
+ standard Java, enterprise Java, SEAM and Spring.
+ </para>
+ <para>The PVM code itself will only use transactional resources through self-defined
+ interfaces. For example, the PVM itself has interfaces for some methods on the hibernate
+ session, a async messaging session and a timer session.
+ </para>
+ <para>The environment allows to configure the actual implementations, lazy
+ initialization of the services on a request-basis and caching the service
+ objects for the duration of the transaction.
+ </para>
+ <para>An environment factory is static and one environment factory can serve
+ all the threads in an application.
+ </para>
+ <programlisting>EnvironmentFactory environmentFactory = new PvmEnvironmentFactory("environment.cfg.xml");</programlisting>
+ <para>Environment blocks can surround persistent process operations
+ like this:
+ </para>
+ <programlisting>Environment environment = environmentFactory.openEnvironment();
+try {
+
+ ... inside the environment block...
+
+} finally {
+ environment.close();
+}</programlisting>
+ <para>The PVM itself will fetch all it's transactional resources and configurations
+ from the environment. It's recommended that <literal>Activity</literal> implementations
+ do the same.
+ </para>
+ <para>The <literal>org.jbpm.pvm.internal.cfg.JbpmConfiguration</literal> acts as Configuration,
+ ProcessEngine and EnvironmentFactory.
+ </para>
+ </section>
+
+ <section>
+ <title>Commands</title>
+ <para>Commands encapsulate operations that are to be executed within an environment
+ block. The main purpose for commands is to capture the logic of
+ </para>
+ <programlisting>public interface Command<T> extends Serializable {
+
+ T execute(Environment environment) throws Exception;
+
+}</programlisting>
+ <para></para>
+ </section>
+
+ <section>
+ <title>Services</title>
+ <para>There are three main services: <literal>RepositoryService</literal>,
+ <literal>ExecutionService</literal> and <literal>ManagementService</literal>.
+ In general, services are session facades that expose methods for persistent
+ usage of the PVM. The next fragments show the essential methods as example
+ to illustrate those services.
+ </para>
+ <para>The <literal>RepositoryService</literal> manages the repository of
+ process definitions.
+ </para>
+ <programlisting>public interface RepositoryService {
+
+ Deployment createDeployment();
+
+ ProcessDefinitionQuery createProcessDefinitionQuery();
+
+ ...
+
+}</programlisting>
+ <para>The <literal>ExecutionService</literal> manages the runtime
+ executions.</para>
+ <programlisting>public interface ExecutionService {
+
+ ProcessInstance startProcessInstanceById(String processDefinitionId);
+
+ ProcessInstance signalExecutionById(String executionId);
+
+ ...
+
+}</programlisting>
+ <para>The <literal>ManagementService</literal> groups all management operations
+ that are needed to keep the system up and running.
+ </para>
+ <programlisting>public interface ManagementService {
+
+ JobQuery createJobQuery();
+
+ void executeJob(long jobDbid);
+
+ ...
+
+}</programlisting>
+ <para>The implementation of all these methods is encapsulated in
+ <literal>Command</literal>s. And the three services all delegate the
+ execution of the commands to a <literal>CommandService</literal>:
+ </para>
+ <programlisting>public interface CommandService {
+
+ <T> T execute(Command<T> command);
+
+}</programlisting>
+ <para>The <literal>CommandService</literal> is configured in the
+ environment. A chain of CommandServices can act as interceptors
+ around a command. This is the core mechanism on how persistence and
+ transactional support can be offered in a variety of environments.
+ </para>
+ <para>The default configuration file <literal>jbpm.default.cfg.xml</literal>
+ includes following section that configures the services
+ </para>
+ <programlisting><jbpm-configuration>
+
+ <process-engine>
+
+ <repository-service />
+ <repository-cache />
+ <execution-service />
+ <history-service />
+ <management-service />
+ <identity-service />
+ <task-service /></programlisting>
+ <para>And the file <literal>jbpm.tx.hibernate.cfg.xml</literal> contains the
+ following command service configuration:</para>
+ <programlisting><jbpm-configuration>
+
+ <process-engine-context>
+ <command-service>
+ <retry-interceptor />
+ <environment-interceptor />
+ <standard-transaction-interceptor />
+ </command-service>
+ </process-engine-context>
+
+ ...</programlisting>
+ <para>The services like e.g. <literal>repository-service</literal>, <literal>execution-service</literal>
+ and <literal>management-service</literal> will look up the configured
+ <literal>command-service</literal> by type. The <literal>command-service</literal>
+ tag corresponds to the default command service that essentially does nothing else
+ then just execute the command providing it the current environment.
+ </para>
+ <para>The configured <literal>command-service</literal> results into the following
+ a chain of three interceptors followed by the default command executor.
+ </para>
+ <figure id="interceptors">
+ <title>The CommandService interceptors</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/interceptors.png"/></imageobject></mediaobject>
+ </figure>
+ <para>The retry interceptor is the first in the chain and that one that will be exposed as the
+ <literal>CommandService.class</literal> from the environment. So the retry interceptor
+ will be given to the respective services <literal>repository-service</literal>, <literal>execution-service</literal>
+ and <literal>management-service</literal>.
+ </para>
+ <para>The <literal>retry-interceptor</literal> will catch hibernate StaleObjectExceptions
+ (indicating optimistic locking failures) and retry to execute the command.
+ </para>
+ <para>The <literal>environment-interceptor</literal> will put an environment block
+ around the execution of the command.
+ </para>
+ <para>The <literal>standard-transaction-interceptor</literal> will initialize a
+ <literal>StandardTransaction</literal>. The hibernate session/transaction will be
+ enlisted as a resource with this standard transaction.
+ </para>
+ <para>Different configurations of this interceptor stack will also enable to
+ </para>
+ <itemizedlist>
+ <listitem>delegate execution to a local ejb command service so that an container
+ managed transaction is started.
+ </listitem>
+ <listitem>delegate to a remote ejb command service so that the command actually
+ gets executed on a different JVM.
+ </listitem>
+ <listitem>package the command as an asynchronous message so that the command gets
+ executed asynchronously in a different transaction.
+ </listitem>
+ </itemizedlist>
+ </section>
+
+</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-ImplementingBasicActivities.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-ImplementingBasicActivities.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-ImplementingBasicActivities.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,490 +0,0 @@
-<chapter id="implementingbasicactivities">
- <title>Implementing basic activities</title>
-
- <para>This chapter explains the basics of process definitions, the features offered by
- the Process Virtual Machine and how activity implementations can be build. At the same
- time the client API is shown to execute processes with those activity implementations.
- </para>
-
- <!-- ### Activity ####################################################### -->
- <section id="activity">
- <title>Activity</title>
- <para>The PVM library doesn't have a fixed set of process constructs.
- Instead, runtime behaviour of a activity is delegated to an <literal>Activity</literal>.
- In other words, <literal>Activity</literal> is an interface to implement the runtime
- behaviour of process constructs in plain Java.
- </para>
- <programlisting>public <emphasis role="bold">interface Activity</emphasis> extends Serializable {
-
- void <emphasis role="bold">execute</emphasis>(ActivityExecution execution) throws Exception;
-
-}</programlisting>
- <para>When an activity is used as the activity behaviour, it is in full control of the further
- propagation of the execution. In other words, a activity behaviour can decide what the execution
- should do next. For example, it can take a transition with
- <literal>execution.take(Transition)</literal> or go into a wait state with
- <literal>execution.waitForSignal()</literal>. In case the activity behaviour does not invoke
- any of the above execution propagation methods, the execution will
- <link linkend="implicitproceedbehaviour">proceed in a default way</link>.
- </para>
- </section>
-
- <!-- ### Activity example ############################################### -->
- <section id="activityexample">
- <title>Activity example</title>
- <para>We'll start with a very original hello world example. A Display
- activity will print a message to the console:
- </para>
- <programlisting>public <emphasis role="bold">class Display</emphasis> implements <emphasis role="bold">Activity</emphasis> {
-
- String message;
-
- public Display(String message) {
- this.message = message;
- }
-
- public void execute(ActivityExecution execution) {
- <emphasis role="bold">System.out.println(message);</emphasis>
- }
-}</programlisting>
- <para>Let' build our first process definition with this activity:</para>
- <figure id="activity.example">
- <title>Display example process</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
- </figure>
- <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build()
- .<emphasis role="bold">activity("a").initial()</emphasis>.behaviour(<emphasis role="bold">new Display("hello")</emphasis>)
- .transition().to("b")
- .<emphasis role="bold">activity("b")</emphasis>.behaviour(<emphasis role="bold">new Display("world")</emphasis>)
-.done();</programlisting>
- <para>Now we can execute this process as follows:</para>
- <programlisting>Execution execution = processDefinition.startExecution();</programlisting>
- <para>The invocation of <literal>startExecution</literal> will print hello world to the console:</para>
- <programlisting>hello
-world</programlisting>
- <para>One thing already worth noticing is that activities can be configured
- with properties. In the Display example, you can see that the message property
- is configured differently in the two usages. With configuration properties
- it becomes possible to write reusable activities. They can then be configured
- differently each time they are used in a process. That is an essential part of
- how process languages can be build on top of the Process Virtual Machine.
- </para>
- <para>The other part that needs explanation is that this activity
- implementation does not contain any instructions for the propagation of the
- execution. When a new process instance is started, the execution is positioned
- in the initial activity and that activity is executed. The method
- <literal>Display.execute</literal> makes use of what is called implicit propagation
- of execution. Concretely this means that the activity itself does not
- invoke any of the methods on the execution to propagate it. In that case
- implicit propagation kicks in. Implicit propagation will take the first
- transition if there is one. If not, it will end the execution. This explains
- why both activities <literal>a</literal> and <literal>b</literal> are executed and that
- the execution stops after activity <literal>b</literal> is executed.
- </para>
- <para>More details about the implicit proceed behaviour can be found
- in <xref linkend="implicitproceedbehaviour" /></para>
- </section>
-
- <!-- ### ExternalActivity ############################################### -->
- <section id="externalactivity">
- <title>ExternalActivity</title>
- <para>External activities are activities for which the responsibility for proceeding
- the execution is transferred externally, meaning outside the process system. This
- means that for the system that is executing the process, it's a wait state. The
- execution will wait until an external trigger is given.
- </para>
- <para>For dealing with external triggers, <literal>ExternalActivity</literal>
- adds two methods to the <literal>Activity</literal>:</para>
- <programlisting>public <emphasis role="bold">interface ExternalActivity</emphasis> extends <emphasis role="bold">Activity</emphasis> {
-
- void <emphasis role="bold">signal</emphasis>(Execution execution,
- String signal,
- Map<String, Object> parameters) throws Exception;
-
-}</programlisting>
- <para>Just like with plain activities, when an execution arrives in a activity, the
- <literal>execute</literal>-method of the activity behaviour is invoked.
- In external activities, the execute method typically does something to
- transfer the responsibility to another system and then enters a wait
- state by invoking <literal>execution.waitForSignal()</literal>. For
- example in the execute method, responsibility could be transferred to a
- person by creating a task entry in a task management system and then
- wait until the person completes the task.
- </para>
- <para>In case a activity behaves as a wait state, then the execution will
- wait in that activity until the execution's <literal>signal</literal> method
- is invoked. The execution will delegate that signal to the behaviour Activity
- of the current activity.
- </para>
- <para>So the Activity's <literal>signal</literal>-method is invoked
- when the execution receives an external trigger during the wait state. With the
- signal method, responsibility is transferred back to the process execution. For
- example, when a person completes a task, the task management system calls the
- signal method on the execution.
- </para>
- <para>A signal can optionally have a signal name and a map of parameters. Most
- common way on how activity behaviours interprete the signal and parameters is that
- the signal relates to the outgoing transition that needs to be taken and that the
- parameters are set as variables on the execution. But those are just examples, it
- is up to the activity to use the signal and the parameters as it pleases.
- </para>
- </section>
-
- <!-- ### ExternalActivity example ####################################### -->
- <section id="externalactivityexample">
- <title>ExternalActivity example</title>
- <para>Here's a first example of a simple wait state implementation:
- </para>
- <programlisting>public <emphasis role="bold">class WaitState</emphasis> implements <emphasis role="bold">ExternalActivity</emphasis> {
-
- public void execute(ActivityExecution execution) {
- <emphasis role="bold">execution.waitForSignal();</emphasis>
- }
-
- public void signal(ActivityExecution execution,
- String signalName,
- Map<String, Object> parameters) {
- <emphasis role="bold">execution.take(signalName);</emphasis>
- }
-}</programlisting>
- <para>The <literal>execute</literal>-method calls
- <literal>execution.waitForSignal()</literal>. The invocation of
- <literal>execution.waitForSignal()</literal> will bring the process execution
- into a wait state until an external trigger is given.
- </para>
- <para><literal>signal</literal>-method takes the transition with
- the signal parameter as the transition name. So when an execution receives an
- external trigger, the signal name is interpreted as the name of an outgoing
- transition and the execution will be propagated over that transition.
- </para>
- <para>Here's the same simple process that has a transition from a to b. This
- time, the behaviour of the two activities will be WaitState's.
- </para>
- <figure id="process.diagram">
- <title>The external activity example process</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
- </figure>
- <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build()
- <emphasis role="bold">.activity("a").initial().behaviour(new WaitState())</emphasis>
- .transition().to("b")
- <emphasis role="bold">.activity("b").behaviour(new WaitState())</emphasis>
-.done();</programlisting>
- <para>Let's start a new process instance for this process definition:</para>
- <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
- <para>Starting this process will execute the <literal>WaitState</literal> activity
- in activity <literal>a</literal>. <literal>WaitState.execute</literal> will invoke
- <literal>ActivityExecution.waitForSignal</literal>. So when the
- <literal>processDefinition.startProcessInstance()</literal> returns, the execution
- will still be positioned in activity a.
- </para>
- <programlisting>assertEquals("a", execution.getActivityName());</programlisting>
- <para>Then we provide the external trigger by calling the <literal>signal</literal>
- method.
- </para>
- <programlisting>execution.signal();</programlisting>
- <para>The <literal>execution.signal()</literal> will delegate to the activity
- of the current activity. So in this case that is the <literal>WaitState</literal>
- activity in activity <literal>a</literal>. The <literal>WaitState.signal</literal>
- will invoke the <literal>ActivityExecution.take(String transitionName)</literal>.
- Since we didn't supply a signalName, the first transition with name <literal>null</literal>
- will be taken. The only transition we specified out of activity <literal>a</literal>
- didn't get a name so that one will be taken. And that transition points to activity
- <literal>b</literal>. When the execution arrives in activity <literal>b</literal>,
- the <literal>WaitState</literal> in activity <literal>b</literal> is executed.
- Similar as we saw above, the execution will wait in activity <literal>b</literal>
- and this time the <literal>signal</literal> method will return, leaving the
- execution positioned in activity <literal>b</literal>.
- </para>
- <programlisting>assertEquals("b", execution.getActivityName());</programlisting>
- </section>
-
- <!-- ### BASIC PROCESS EXECUTION ######################################## -->
- <section id="basicprocessexecution">
- <title>Basic process execution</title>
- <para>In this next example, we'll combine automatic activities and wait states.
- This example builds upon the loan approval process with the <literal>WaitState</literal>
- and <literal>Display</literal> activities that we've just created. Graphically,
- the loan process looks like this:
- </para>
- <figure id="basicprocessexecution.loan.process">
- <title>The loan process</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.loan.png"/></imageobject></mediaobject>
- </figure>
- <para>Building process graphs in Java code can be tedious because you have to keep track of all the
- references in local variables. To resolve that, the Process Virtual Machine comes with a
- ProcessFactory. The ProcessFactory is a kind of domain specific language (DSL) that is embedded
- in Java and eases the construction of process graphs. This pattern is also known as
- a <ulink url="http://martinfowler.com/bliki/FluentInterface.html">fluent
- interface</ulink>.
- </para>
- <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build("loan")
- .activity(<emphasis role="bold">"submit loan request"</emphasis>).initial().behaviour(new Display("loan request submitted"))
- .transition().to("evaluate")
- <emphasis role="bold">.activity("evaluate").behaviour(new WaitState())</emphasis>
- .transition("approve").to("wire money")
- .transition("reject").to("end")
- <emphasis role="bold">.activity("wire money").behaviour(new Display("wire the money"))</emphasis>
- .transition().to("archive")
- <emphasis role="bold">.activity("archive").behaviour(new WaitState())</emphasis>
- .transition().to("end")
- <emphasis role="bold">.activity("end").behaviour(new WaitState())</emphasis>
-.done();</programlisting>
- <para>For more details about the ProcessFactory, see <ulink url="../../api/org/jbpm/pvm/package-summary.html">the
- api docs</ulink>. An alternative for
- the ProcessFactory would be to create an XML language and an XML parser for expressing
- processes. The XML parser can then instantiate the classes of package
- <literal>org.jbpm.pvm.internal.model</literal> directly. That approach is typically taken by
- process languages.
- </para>
- <para>The initial activity <literal>submit loan request</literal> and the activity
- <literal>wire the money</literal> are automatic activities. In this example,
- the <literal>Display</literal> implementation of activity
- <literal>wire the money</literal> uses the Java API's to just print a
- message to the console. But the witty reader can imagine an alternative
- <literal>Activity</literal> implementation that uses the Java API of a payment
- processing library to make a real automatic payment.
- </para>
- <para>A new execution for the process above can be started like this
- </para>
- <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
- <para>When the <literal>startExecution</literal>-method returns, the activity
- <literal>submit loan request</literal> will be executed and the execution will be
- positioned in the activity <literal>evaluate</literal>.
- </para>
- <figure id="execution.loan.evaluate">
- <title>Execution positioned in the 'evaluate' activity</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.evaluate.png"/></imageobject></mediaobject>
- </figure>
- <para>Now, the execution is at an interesting point. There are two transitions out of
- the state <literal>evaluate</literal>. One transition is called <literal>approve</literal>
- and one transition is called <literal>reject</literal>. As we explained above, the WaitState
- implementation will take the transition that corresponds to the signal that is given.
- Let's feed in the 'approve' signal like this:
- </para>
- <programlisting>execution.signal("approve");</programlisting>
- <para>The <literal>approve</literal> signal will cause the execution to take the <literal>approve</literal>
- transition and it will arrive in the activity <literal>wire money</literal>.
- </para>
- <para>In activity <literal>wire money</literal>, the message will be printed to the console.
- Since, the <literal>Display</literal> activity didn't invoke the
- <literal>execution.waitForSignal()</literal>, nor any of the other execution propagation
- methods, the implicit proceed behaviour will just make the execution continue
- over the outgoing transition to activity <literal>archive</literal>, which is again
- a <literal>WaitState</literal>.
- </para>
- <figure id="execution.loan.archive">
- <title>Execution positioned in 'archive' activity</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.archive.png"/></imageobject></mediaobject>
- </figure>
- <para>So only when the <literal>archive</literal> wait state is reached,
- the <literal>signal("approve")</literal> returns.
- </para>
- <para>Another signal like this:</para>
- <programlisting>execution.signal("approve");</programlisting>
- <para>will bring the execution eventually in the end state.</para>
- <figure id="execution.loan.end">
- <title>Execution positioned in the 'end' activity</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.end.png"/></imageobject></mediaobject>
- </figure>
- </section>
-
- <!-- ### EVENTS ######################################################### -->
- <section id="events">
- <title>Events</title>
- <para>Events are points in the process definition to which a list of
- <literal>EventListener</literal>s can be subscribed.
- </para>
- <programlisting>public interface EventListener extends Serializable {
-
- void notify(EventListenerExecution execution) throws Exception;
-
-}</programlisting>
- <para>The motivation for events is to allow for
- developers to add programming logic to a process without changing the process diagram.
- This is a very valuable instrument in facilitating the collaboration between business analysts
- and developers. Business analysts
- are responsible for expressing the requirements. When they use a process graph to document
- those requirements, developers can take this diagram and make it executable. Events can
- be a very handy to insert technical details into a process (like e.g. some database insert)
- in which the business analyst is not interested.
- </para>
- <para>Most common events are fired by the execution automatically:
- </para>
- <para>TODO: explain events in userguide</para>
- <para>Events are identified by the combination of a process element
- and an event name. Users and process languages can also fire events
- programmatically with the fire method on the Execution:
- </para>
- <programlisting>public interface Execution extends Serializable {
- ...
- void fire(String eventName, ProcessElement eventSource);
- ...
-}</programlisting>
-
- <para>A list of <literal>EventListeners</literal> can be associated to an
- event. But event listeners can not influence the control flow of the execution since
- they are merely listeners to an execution which is already in progress. This is different from
- activities that serve as the behaviour for activities. Activity behaviour activities are responsible
- for propagating the execution.
- </para>
- <para>We'll create a <literal>PrintLn</literal> event listener which is
- very similar to the <literal>Display</literal> activity from above.
- </para>
- <programlisting>public class PrintLn implements EventListener {
-
- String message;
-
- public PrintLn(String message) {
- this.message = message;
- }
-
- public void notify(EventListenerExecution execution) throws Exception {
- System.out.println("message");
- }
-}</programlisting>
- <para>Several <literal>PrintLn</literal> listeners will be subscribed to events in
- the process.</para>
- <figure id="action.process">
- <title>The PrintLn listener process</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
- </figure>
- <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build()
- .activity("a").initial().behaviour(new AutomaticActivity())
- <emphasis role="bold">.event("end")
- .listener(new PrintLn("leaving a"))
- .listener(new PrintLn("second message while leaving a"))</emphasis>
- .transition().to("b")
- <emphasis role="bold">.listener(new PrintLn("taking transition"))</emphasis>
- .activity("b").behaviour(new WaitState())
- .event("start")
- <emphasis role="bold">.listener(new PrintLn("entering b"))</emphasis>
-.done();</programlisting>
- <para>The first event shows how to register multiple listeners to the same
- event. They will be notified in the order as they are specified.
- </para>
- <para>Then, on the transition, there is only one type of event. So in that case,
- the event type must not be specified and the listeners can be added directly on
- the transition.
- </para>
- <para>A listeners will be called each time an execution fires the event to
- which the listener is subscribed. The execution will be provided in the activity
- interface as a parameter and can be used by listeners except for the methods that
- control the propagation of execution.
- </para>
- </section>
-
- <!-- ### EVENT PROPAGATION ############################################## -->
- <section>
- <title>Event propagation</title>
- <para>Events are by default propagated to enclosing process elements. The motivation
- is to allow for listeners on process definitions or composite activities that get executed
- for all events that occur within that process element. For example this feature
- allows to register an event listener on a process definition or a composite activity on
- <literal>end</literal> events. Such action will be executed if that activity is
- left. And if that event listener is registered on a composite activity, it will also be executed
- for all activities that are left within that composite activity.
- </para>
- <para>To show this clearly, we'll create a <literal>DisplaySource</literal> event listener
- that will print the message <literal>leaving</literal> and the source of the event
- to the console.
- </para>
- <programlisting>public class <emphasis role="bold">DisplaySource</emphasis> implements EventListener {
-
- public void execute(EventListenerExecution execution) {
- <emphasis role="bold">System.out.println("leaving "+execution.getEventSource());</emphasis>
- }
-}</programlisting>
- <para>Note that the purpose of event listeners is not to be visible, that's why the event listener
- itself should not be displayed in the diagram. A <literal>DisplaySource</literal> event listener
- will be added as a listener to the event <literal>end</literal> on the composite activity.
- </para>
- <para>The next process shows how the <literal>DisplaySource</literal> event listener is registered
- as a listener to to the 'end' event on the <literal>composite</literal> activity:</para>
- <figure id="process.propagate">
- <title>A process with an invisible event listener on a end event on a composite activity.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.propagate.png"/></imageobject></mediaobject>
- </figure>
- <programlisting>TODO update code snippet</programlisting>
- <para>Next we'll start an execution.</para>
- <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
- <para>After starting a new execution, the execution will be in activity <literal>a</literal> as
- that is the initial activity. No activities have been left so no message is logged. Next a signal
- will be given to the execution, causing it to take the transition from <literal>a</literal>
- to <literal>b</literal>.
- </para>
- <programlisting>execution.signal();</programlisting>
- <para>When the signal method returns, the execution will have taken the transition and
- the <literal>end</literal> event will be fired on activity <literal>a</literal>. That
- event will be propagated to the
- composite activity and to the process definition. Since our <literal>DisplaySource</literal>
- event listener is placed
- on the <literal>composite</literal> activity, it will receive the event and print the following
- message on the console:
- </para>
- <programlisting>leaving activity(a)</programlisting>
- <para>Another</para>
- <programlisting>execution.signal();</programlisting>
- <para>will take the transition from b to c. That will fire two activity-leave events. One on
- activity b and one on activity composite. So the following lines will be appended to the console
- output:</para>
- <programlisting>leaving activity(b)
-leaving activity(composite)</programlisting>
- <para>Event propagation is build on the hierarchical composition structure of the process
- definition. The top level element is always the process definition. The process
- definition contains a list of activities. Each activity can be a leaf activity or it can be a
- composite activity, which means that it contains a list of nested activities. Nested activities
- can be used for e.g. super states or composite activities in nested process languages like BPEL.
- </para>
- <para>So the even model also works similarly for composite activities as it did for the process
- definition above. Suppose that 'Phase one' models
- a super state as in state machines. Then event propagation allows to subscribe to all events
- within that super state. The idea is that the hierarchical composition corresponds to
- diagram representation. If an element 'e' is drawn inside another element 'p', then p
- is the parent of e. A process definition has a set of top level activities. Every activity can have
- a set of nested activities. The parent of a transition is considered as the first common
- parent for it's source and destination.
- </para>
- <para>If an event listener is not interested in propagated events, propagation can be disabled
- with <literal>propagationDisabled()</literal> while building the process with the
- <literal>ProcessFactory</literal>. The next process is the same process
- as above except that propagated events will be disabled on the event listener. The graph diagram
- remains the same.
- </para>
- <figure id="process.propagate.propagation.disabled">
- <title>A process with an event listener to 'end' events with propagation disabled.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.propagate.png"/></imageobject></mediaobject>
- </figure>
- <para>Building the process with the process factory:
- </para>
- <programlisting>TODO update code snippet</programlisting>
- <para>So when the first signal is given for this process, again the <literal>end</literal>
- event will be fired on activity <literal>a</literal>, but now the event listener on the composite
- activity will not be executed cause
- propagated events have been disabled. Disabling propagation is a property on the individual
- event listener and doesn't influence the other listeners. The event will always be fired and
- propagated over the whole parent hierarchy.
- </para>
- <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
- <para>The first signal will take the process from <literal>a</literal> to
- <literal>b</literal>. No messages will be printed to the console.
- </para>
- <programlisting>execution.signal();</programlisting>
- <para>Next, the second signal will take the transition from b to c.
- </para>
- <programlisting>execution.signal()</programlisting>
- <para>Again two <literal>end</literal>
- events are fired just like above on activities <literal>b</literal> and <literal>composite</literal>
- respectively. The first event
- is the <literal>end</literal> event on activity <literal>b</literal>. That will be propagated
- to the <literal>composite</literal> activity. So the event
- listener will not be executed for this event cause it has propagation disabled. But the
- event listener will be executed for the <literal>end</literal> event on the
- <literal>composite</literal> activity. That is not
- propagated, but fired directly on the <literal>composite</literal> activity. So the event
- listener will now be executed
- only once for the composite activity as shown in the following console output:
- </para>
- <programlisting>leaving activity(composite)</programlisting>
- </section>
-
-</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ImplementingBasicActivities.xml (from rev 4742, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch04-ImplementingBasicActivities.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ImplementingBasicActivities.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ImplementingBasicActivities.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -0,0 +1,486 @@
+<chapter id="implementingbasicactivities">
+ <title>Implementing basic activities</title>
+
+ <para>This chapter explains the basics of process definitions, the features offered by
+ the Process Virtual Machine and how activity implementations can be build. At the same
+ time the client API is shown to execute processes with those activity implementations.
+ </para>
+
+ <!-- ### Activity ####################################################### -->
+ <section id="activity">
+ <title>ActivityBehaviour</title>
+ <para>The PVM library doesn't have a fixed set of process constructs.
+ Instead, runtime behaviour of a activity is delegated to an <literal>ActivityBehaviour</literal>.
+ In other words, <literal>ActivityBehaviour</literal> is an interface to implement the runtime
+ behaviour of process constructs in plain Java.
+ </para>
+ <programlisting>public <emphasis role="bold">interface ActivityBehaviour</emphasis> extends Serializable {
+
+ void <emphasis role="bold">execute</emphasis>(ActivityExecution execution) throws Exception;
+
+}</programlisting>
+ <para>When an activity behaviour is called, it is in full control of the further
+ propagation of the execution. In other words, an activity behaviour can decide what the execution
+ should do next. For example, it can take a transition with
+ <literal>execution.take(Transition)</literal> or go into a wait state with
+ <literal>execution.waitForSignal()</literal>. In case the activity behaviour does not invoke
+ any of the above execution propagation methods, the execution will
+ <link linkend="implicitproceedbehaviour">proceed in a default way</link>.
+ </para>
+ </section>
+
+ <!-- ### ActivityBehaviour example ############################################### -->
+ <section id="activitybehaviourexample">
+ <title>ActivityBehaviour example</title>
+ <para>We'll start with a very original hello world example. A Display
+ activity will print a message to the console:
+ </para>
+ <programlisting>public <emphasis role="bold">class Display</emphasis> implements <emphasis role="bold">ActivityBehaviour</emphasis> {
+
+ String message;
+
+ public Display(String message) {
+ this.message = message;
+ }
+
+ public void execute(ActivityExecution execution) {
+ <emphasis role="bold">System.out.println(message);</emphasis>
+ }
+}</programlisting>
+ <para>Let' build our first process definition with this activity:</para>
+ <figure id="activity.example">
+ <title>Display example process</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
+ </figure>
+ <programlisting>TODO add ProcessBuilder example code</programlisting>
+ <para>Now we can execute this process as follows:</para>
+ <programlisting>Execution execution = processDefinition.startExecution();</programlisting>
+ <para>The invocation of <literal>startExecution</literal> will print hello world to the console:</para>
+ <programlisting>hello
+world</programlisting>
+ <para>One thing already worth noticing is that activities can be configured
+ with properties. In the Display example, you can see that the message property
+ is configured differently in the two usages. With configuration properties
+ it becomes possible to write reusable activities. They can then be configured
+ differently each time they are used in a process. That is an essential part of
+ how process languages can be build on top of the Process Virtual Machine.
+ </para>
+ <para>The other part that needs explanation is that this activity
+ implementation does not contain any instructions for the propagation of the
+ execution. When a new process instance is started, the execution is positioned
+ in the initial activity and that activity is executed. The method
+ <literal>Display.execute</literal> makes use of what is called implicit propagation
+ of execution. Concretely this means that the activity itself does not
+ invoke any of the methods on the execution to propagate it. In that case
+ implicit propagation kicks in. Implicit propagation will take the first
+ transition if there is one. If not, it will end the execution. This explains
+ why both activities <literal>a</literal> and <literal>b</literal> are executed and that
+ the execution stops after activity <literal>b</literal> is executed.
+ </para>
+ <para>More details about the implicit proceed behaviour can be found
+ in <xref linkend="implicitproceedbehaviour" /></para>
+ </section>
+
+ <!-- ### ExternalActivityBehaviour ############################################### -->
+ <section id="externalactivitybehaviour">
+ <title>ExternalActivityBehaviour</title>
+ <para>External activities are activities for which the responsibility for proceeding
+ the execution is transferred externally, meaning outside the process system. This
+ means that for the system that is executing the process, it's a wait state. The
+ execution will wait until an external trigger is given.
+ </para>
+ <para>For dealing with external triggers, <literal>ExternalActivityBehaviour</literal>
+ adds one method to the <literal>ActivityBehaviour</literal>:</para>
+ <programlisting>public <emphasis role="bold">interface ExternalActivity</emphasis> extends <emphasis role="bold">Activity</emphasis> {
+
+ void <emphasis role="bold">signal</emphasis>(Execution execution,
+ String signal,
+ Map<String, Object> parameters) throws Exception;
+
+}</programlisting>
+ <para>Just like with plain activities, when an execution arrives in a activity, the
+ <literal>execute</literal>-method of the external activity behaviour is invoked.
+ In external activities, the execute method typically does something to
+ transfer the responsibility to another system and then enters a wait
+ state by invoking <literal>execution.waitForSignal()</literal>. For
+ example in the execute method, responsibility could be transferred to a
+ person by creating a task entry in a task management system and then
+ wait until the person completes the task.
+ </para>
+ <para>In case a activity behaves as a wait state, then the execution will
+ wait in that activity until the execution's <literal>signal</literal> method
+ is invoked. The execution will delegate that signal to the ExternalActivityBehaviour
+ object associated to the current activity.
+ </para>
+ <para>So the Activity's <literal>signal</literal>-method is invoked
+ when the execution receives an external trigger during the wait state. With the
+ signal method, responsibility is transferred back to the process execution. For
+ example, when a person completes a task, the task management system calls the
+ signal method on the execution.
+ </para>
+ <para>A signal can optionally have a signal name and a map of parameters. Most
+ common way on how activity behaviours interprete the signal and parameters is that
+ the signal relates to the outgoing transition that needs to be taken and that the
+ parameters are set as variables on the execution. But those are just examples, it
+ is up to the activity to use the signal and the parameters as it pleases.
+ </para>
+ </section>
+
+ <!-- ### ExternalActivity example ####################################### -->
+ <section id="externalactivityexample">
+ <title>ExternalActivity example</title>
+ <para>Here's a first example of a simple wait state implementation:
+ </para>
+ <programlisting>public <emphasis role="bold">class WaitState</emphasis> implements <emphasis role="bold">ExternalActivity</emphasis> {
+
+ public void execute(ActivityExecution execution) {
+ <emphasis role="bold">execution.waitForSignal();</emphasis>
+ }
+
+ public void signal(ActivityExecution execution,
+ String signalName,
+ Map<String, Object> parameters) {
+ <emphasis role="bold">execution.take(signalName);</emphasis>
+ }
+}</programlisting>
+ <para>The <literal>execute</literal>-method calls
+ <literal>execution.waitForSignal()</literal>. The invocation of
+ <literal>execution.waitForSignal()</literal> will bring the process execution
+ into a wait state until an external trigger is given.
+ </para>
+ <para><literal>signal</literal>-method takes the transition with
+ the signal parameter as the transition name. So when an execution receives an
+ external trigger, the signal name is interpreted as the name of an outgoing
+ transition and the execution will be propagated over that transition.
+ </para>
+ <para>Here's the same simple process that has a transition from a to b. This
+ time, the behaviour of the two activities will be WaitState's.
+ </para>
+ <figure id="process.diagram">
+ <title>The external activity example process</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
+ </figure>
+ <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build()
+ <emphasis role="bold">.activity("a").initial().behaviour(new WaitState())</emphasis>
+ .transition().to("b")
+ <emphasis role="bold">.activity("b").behaviour(new WaitState())</emphasis>
+.done();</programlisting>
+ <para>Let's start a new process instance for this process definition:</para>
+ <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
+ <para>Starting this process will execute the <literal>WaitState</literal> activity
+ in activity <literal>a</literal>. <literal>WaitState.execute</literal> will invoke
+ <literal>ActivityExecution.waitForSignal</literal>. So when the
+ <literal>processDefinition.startProcessInstance()</literal> returns, the execution
+ will still be positioned in activity a.
+ </para>
+ <programlisting>assertEquals("a", execution.getActivityName());</programlisting>
+ <para>Then we provide the external trigger by calling the <literal>signal</literal>
+ method.
+ </para>
+ <programlisting>execution.signal();</programlisting>
+ <para>The <literal>execution.signal()</literal> will delegate to the activity
+ of the current activity. So in this case that is the <literal>WaitState</literal>
+ activity in activity <literal>a</literal>. The <literal>WaitState.signal</literal>
+ will invoke the <literal>ActivityExecution.take(String transitionName)</literal>.
+ Since we didn't supply a signalName, the first transition with name <literal>null</literal>
+ will be taken. The only transition we specified out of activity <literal>a</literal>
+ didn't get a name so that one will be taken. And that transition points to activity
+ <literal>b</literal>. When the execution arrives in activity <literal>b</literal>,
+ the <literal>WaitState</literal> in activity <literal>b</literal> is executed.
+ Similar as we saw above, the execution will wait in activity <literal>b</literal>
+ and this time the <literal>signal</literal> method will return, leaving the
+ execution positioned in activity <literal>b</literal>.
+ </para>
+ <programlisting>assertEquals("b", execution.getActivityName());</programlisting>
+ </section>
+
+ <!-- ### BASIC PROCESS EXECUTION ######################################## -->
+ <section id="basicprocessexecution">
+ <title>Basic process execution</title>
+ <para>In this next example, we'll combine automatic activities and wait states.
+ This example builds upon the loan approval process with the <literal>WaitState</literal>
+ and <literal>Display</literal> activities that we've just created. Graphically,
+ the loan process looks like this:
+ </para>
+ <figure id="basicprocessexecution.loan.process">
+ <title>The loan process</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.loan.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Building process graphs in Java code can be tedious because you have to keep track of all the
+ references in local variables. To resolve that, the Process Virtual Machine comes with a
+ ProcessFactory. The ProcessFactory is a kind of domain specific language (DSL) that is embedded
+ in Java and eases the construction of process graphs. This pattern is also known as
+ a <ulink url="http://martinfowler.com/bliki/FluentInterface.html">fluent
+ interface</ulink>.
+ </para>
+ <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build("loan")
+ .activity(<emphasis role="bold">"submit loan request"</emphasis>).initial().behaviour(new Display("loan request submitted"))
+ .transition().to("evaluate")
+ <emphasis role="bold">.activity("evaluate").behaviour(new WaitState())</emphasis>
+ .transition("approve").to("wire money")
+ .transition("reject").to("end")
+ <emphasis role="bold">.activity("wire money").behaviour(new Display("wire the money"))</emphasis>
+ .transition().to("archive")
+ <emphasis role="bold">.activity("archive").behaviour(new WaitState())</emphasis>
+ .transition().to("end")
+ <emphasis role="bold">.activity("end").behaviour(new WaitState())</emphasis>
+.done();</programlisting>
+ <para>For more details about the ProcessFactory, see <ulink url="../../api/org/jbpm/pvm/package-summary.html">the
+ api docs</ulink>. An alternative for
+ the ProcessFactory would be to create an XML language and an XML parser for expressing
+ processes. The XML parser can then instantiate the classes of package
+ <literal>org.jbpm.pvm.internal.model</literal> directly. That approach is typically taken by
+ process languages.
+ </para>
+ <para>The initial activity <literal>submit loan request</literal> and the activity
+ <literal>wire the money</literal> are automatic activities. In this example,
+ the <literal>Display</literal> implementation of activity
+ <literal>wire the money</literal> uses the Java API's to just print a
+ message to the console. But the witty reader can imagine an alternative
+ <literal>Activity</literal> implementation that uses the Java API of a payment
+ processing library to make a real automatic payment.
+ </para>
+ <para>A new execution for the process above can be started like this
+ </para>
+ <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
+ <para>When the <literal>startExecution</literal>-method returns, the activity
+ <literal>submit loan request</literal> will be executed and the execution will be
+ positioned in the activity <literal>evaluate</literal>.
+ </para>
+ <figure id="execution.loan.evaluate">
+ <title>Execution positioned in the 'evaluate' activity</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.evaluate.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Now, the execution is at an interesting point. There are two transitions out of
+ the state <literal>evaluate</literal>. One transition is called <literal>approve</literal>
+ and one transition is called <literal>reject</literal>. As we explained above, the WaitState
+ implementation will take the transition that corresponds to the signal that is given.
+ Let's feed in the 'approve' signal like this:
+ </para>
+ <programlisting>execution.signal("approve");</programlisting>
+ <para>The <literal>approve</literal> signal will cause the execution to take the <literal>approve</literal>
+ transition and it will arrive in the activity <literal>wire money</literal>.
+ </para>
+ <para>In activity <literal>wire money</literal>, the message will be printed to the console.
+ Since, the <literal>Display</literal> activity didn't invoke the
+ <literal>execution.waitForSignal()</literal>, nor any of the other execution propagation
+ methods, the implicit proceed behaviour will just make the execution continue
+ over the outgoing transition to activity <literal>archive</literal>, which is again
+ a <literal>WaitState</literal>.
+ </para>
+ <figure id="execution.loan.archive">
+ <title>Execution positioned in 'archive' activity</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.archive.png"/></imageobject></mediaobject>
+ </figure>
+ <para>So only when the <literal>archive</literal> wait state is reached,
+ the <literal>signal("approve")</literal> returns.
+ </para>
+ <para>Another signal like this:</para>
+ <programlisting>execution.signal("approve");</programlisting>
+ <para>will bring the execution eventually in the end state.</para>
+ <figure id="execution.loan.end">
+ <title>Execution positioned in the 'end' activity</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.loan.end.png"/></imageobject></mediaobject>
+ </figure>
+ </section>
+
+ <!-- ### EVENTS ######################################################### -->
+ <section id="events">
+ <title>Events</title>
+ <para>Events are points in the process definition to which a list of
+ <literal>EventListener</literal>s can be subscribed.
+ </para>
+ <programlisting>public interface EventListener extends Serializable {
+
+ void notify(EventListenerExecution execution) throws Exception;
+
+}</programlisting>
+ <para>The motivation for events is to allow for
+ developers to add programming logic to a process without changing the process diagram.
+ This is a very valuable instrument in facilitating the collaboration between business analysts
+ and developers. Business analysts
+ are responsible for expressing the requirements. When they use a process graph to document
+ those requirements, developers can take this diagram and make it executable. Events can
+ be a very handy to insert technical details into a process (like e.g. some database insert)
+ in which the business analyst is not interested.
+ </para>
+ <para>Most common events are fired by the execution automatically:
+ </para>
+ <para>TODO: explain events in userguide</para>
+ <para>Events are identified by the combination of a process element
+ and an event name. Users and process languages can also fire events
+ programmatically with the fire method on the Execution:
+ </para>
+ <programlisting>public interface Execution extends Serializable {
+ ...
+ void fire(String eventName, ProcessElement eventSource);
+ ...
+}</programlisting>
+
+ <para>A list of <literal>EventListeners</literal> can be associated to an
+ event. But event listeners can not influence the control flow of the execution since
+ they are merely listeners to an execution which is already in progress. This is different from
+ activities that serve as the behaviour for activities. Activity behaviour activities are responsible
+ for propagating the execution.
+ </para>
+ <para>We'll create a <literal>PrintLn</literal> event listener which is
+ very similar to the <literal>Display</literal> activity from above.
+ </para>
+ <programlisting>public class PrintLn implements EventListener {
+
+ String message;
+
+ public PrintLn(String message) {
+ this.message = message;
+ }
+
+ public void notify(EventListenerExecution execution) throws Exception {
+ System.out.println("message");
+ }
+}</programlisting>
+ <para>Several <literal>PrintLn</literal> listeners will be subscribed to events in
+ the process.</para>
+ <figure id="action.process">
+ <title>The PrintLn listener process</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.ab.png"/></imageobject></mediaobject>
+ </figure>
+ <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build()
+ .activity("a").initial().behaviour(new AutomaticActivity())
+ <emphasis role="bold">.event("end")
+ .listener(new PrintLn("leaving a"))
+ .listener(new PrintLn("second message while leaving a"))</emphasis>
+ .transition().to("b")
+ <emphasis role="bold">.listener(new PrintLn("taking transition"))</emphasis>
+ .activity("b").behaviour(new WaitState())
+ .event("start")
+ <emphasis role="bold">.listener(new PrintLn("entering b"))</emphasis>
+.done();</programlisting>
+ <para>The first event shows how to register multiple listeners to the same
+ event. They will be notified in the order as they are specified.
+ </para>
+ <para>Then, on the transition, there is only one type of event. So in that case,
+ the event type must not be specified and the listeners can be added directly on
+ the transition.
+ </para>
+ <para>A listeners will be called each time an execution fires the event to
+ which the listener is subscribed. The execution will be provided in the activity
+ interface as a parameter and can be used by listeners except for the methods that
+ control the propagation of execution.
+ </para>
+ </section>
+
+ <!-- ### EVENT PROPAGATION ############################################## -->
+ <section>
+ <title>Event propagation</title>
+ <para>Events are by default propagated to enclosing process elements. The motivation
+ is to allow for listeners on process definitions or composite activities that get executed
+ for all events that occur within that process element. For example this feature
+ allows to register an event listener on a process definition or a composite activity on
+ <literal>end</literal> events. Such action will be executed if that activity is
+ left. And if that event listener is registered on a composite activity, it will also be executed
+ for all activities that are left within that composite activity.
+ </para>
+ <para>To show this clearly, we'll create a <literal>DisplaySource</literal> event listener
+ that will print the message <literal>leaving</literal> and the source of the event
+ to the console.
+ </para>
+ <programlisting>public class <emphasis role="bold">DisplaySource</emphasis> implements EventListener {
+
+ public void execute(EventListenerExecution execution) {
+ <emphasis role="bold">System.out.println("leaving "+execution.getEventSource());</emphasis>
+ }
+}</programlisting>
+ <para>Note that the purpose of event listeners is not to be visible, that's why the event listener
+ itself should not be displayed in the diagram. A <literal>DisplaySource</literal> event listener
+ will be added as a listener to the event <literal>end</literal> on the composite activity.
+ </para>
+ <para>The next process shows how the <literal>DisplaySource</literal> event listener is registered
+ as a listener to to the 'end' event on the <literal>composite</literal> activity:</para>
+ <figure id="process.propagate">
+ <title>A process with an invisible event listener on a end event on a composite activity.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.propagate.png"/></imageobject></mediaobject>
+ </figure>
+ <programlisting>TODO update code snippet</programlisting>
+ <para>Next we'll start an execution.</para>
+ <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
+ <para>After starting a new execution, the execution will be in activity <literal>a</literal> as
+ that is the initial activity. No activities have been left so no message is logged. Next a signal
+ will be given to the execution, causing it to take the transition from <literal>a</literal>
+ to <literal>b</literal>.
+ </para>
+ <programlisting>execution.signal();</programlisting>
+ <para>When the signal method returns, the execution will have taken the transition and
+ the <literal>end</literal> event will be fired on activity <literal>a</literal>. That
+ event will be propagated to the
+ composite activity and to the process definition. Since our <literal>DisplaySource</literal>
+ event listener is placed
+ on the <literal>composite</literal> activity, it will receive the event and print the following
+ message on the console:
+ </para>
+ <programlisting>leaving activity(a)</programlisting>
+ <para>Another</para>
+ <programlisting>execution.signal();</programlisting>
+ <para>will take the transition from b to c. That will fire two activity-leave events. One on
+ activity b and one on activity composite. So the following lines will be appended to the console
+ output:</para>
+ <programlisting>leaving activity(b)
+leaving activity(composite)</programlisting>
+ <para>Event propagation is build on the hierarchical composition structure of the process
+ definition. The top level element is always the process definition. The process
+ definition contains a list of activities. Each activity can be a leaf activity or it can be a
+ composite activity, which means that it contains a list of nested activities. Nested activities
+ can be used for e.g. super states or composite activities in nested process languages like BPEL.
+ </para>
+ <para>So the even model also works similarly for composite activities as it did for the process
+ definition above. Suppose that 'Phase one' models
+ a super state as in state machines. Then event propagation allows to subscribe to all events
+ within that super state. The idea is that the hierarchical composition corresponds to
+ diagram representation. If an element 'e' is drawn inside another element 'p', then p
+ is the parent of e. A process definition has a set of top level activities. Every activity can have
+ a set of nested activities. The parent of a transition is considered as the first common
+ parent for it's source and destination.
+ </para>
+ <para>If an event listener is not interested in propagated events, propagation can be disabled
+ with <literal>propagationDisabled()</literal> while building the process with the
+ <literal>ProcessFactory</literal>. The next process is the same process
+ as above except that propagated events will be disabled on the event listener. The graph diagram
+ remains the same.
+ </para>
+ <figure id="process.propagate.propagation.disabled">
+ <title>A process with an event listener to 'end' events with propagation disabled.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.propagate.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Building the process with the process factory:
+ </para>
+ <programlisting>TODO update code snippet</programlisting>
+ <para>So when the first signal is given for this process, again the <literal>end</literal>
+ event will be fired on activity <literal>a</literal>, but now the event listener on the composite
+ activity will not be executed cause
+ propagated events have been disabled. Disabling propagation is a property on the individual
+ event listener and doesn't influence the other listeners. The event will always be fired and
+ propagated over the whole parent hierarchy.
+ </para>
+ <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
+ <para>The first signal will take the process from <literal>a</literal> to
+ <literal>b</literal>. No messages will be printed to the console.
+ </para>
+ <programlisting>execution.signal();</programlisting>
+ <para>Next, the second signal will take the transition from b to c.
+ </para>
+ <programlisting>execution.signal()</programlisting>
+ <para>Again two <literal>end</literal>
+ events are fired just like above on activities <literal>b</literal> and <literal>composite</literal>
+ respectively. The first event
+ is the <literal>end</literal> event on activity <literal>b</literal>. That will be propagated
+ to the <literal>composite</literal> activity. So the event
+ listener will not be executed for this event cause it has propagation disabled. But the
+ event listener will be executed for the <literal>end</literal> event on the
+ <literal>composite</literal> activity. That is not
+ propagated, but fired directly on the <literal>composite</literal> activity. So the event
+ listener will now be executed
+ only once for the composite activity as shown in the following console output:
+ </para>
+ <programlisting>leaving activity(composite)</programlisting>
+ </section>
+
+</chapter>
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ProcessAnatomy.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ProcessAnatomy.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ProcessAnatomy.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,62 +0,0 @@
-<chapter id="processanatomy">
- <title>Process anatomy</title>
-
- <para>Above we already touched briefly on the two main process constructs:
- Activities, transitions and activity composition. This chapter explores in full
- all the possibilities of the process definition structures.
- </para>
-
- <para>There are basically two forms of process languages: graph based and composite
- process languages. First of all, the process supports both. Even graph based execution
- and activity composition can be used in combination to implement something like UML super states.
- Furthermore, automatic functional activities can be implemented so that they can be
- used with transitions as well as with activity composition.
- </para>
-
- <figure id="process.anatomy">
- <title>UML class diagram of the logical process structure</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.anatomy.classes.png"/></imageobject></mediaobject>
- </figure>
-
- <para>Next we'll show a series of example diagram structures that can be formed
- with the PVM process model.
- </para>
-
- <figure id="transition">
- <title>Any two activities can be connected with a transition.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.png"/></imageobject></mediaobject>
- </figure>
-
- <figure id="self.transition">
- <title>A self transition.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/self.transition.png"/></imageobject></mediaobject>
- </figure>
- <figure id="composite.activity">
- <title>Composite activity is a list of nested activities.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/composite.activity.png"/></imageobject></mediaobject>
- </figure>
- <figure id="transition.into.composite">
- <title>Transition to a activity inside a composite.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.into.composite.png"/></imageobject></mediaobject>
- </figure>
- <figure id="transition.out.of.composite">
- <title>Transition from a activity inside a composite to a activity outside the composite.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.out.of.composite.png"/></imageobject></mediaobject>
- </figure>
- <figure id="transition.inheritence">
- <title>Transition of composite activities are inherited. The activity inside can take the transition of the composite activity.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.inheritence.png"/></imageobject></mediaobject>
- </figure>
- <figure id="transition.to.outer">
- <title>Transition from a activity to an outer composite.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.to.outer.png"/></imageobject></mediaobject>
- </figure>
- <figure id="transition.to.inner">
- <title>Transition from a composite activity to an inner composed activity.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transition.to.inner.png"/></imageobject></mediaobject>
- </figure>
- <figure id="initial.in.composite">
- <title>An initial activity inside a composite activity.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/initial.in.composite.png"/></imageobject></mediaobject>
- </figure>
-</chapter>
\ No newline at end of file
Deleted: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ImplementingAdvancedActivities.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ImplementingAdvancedActivities.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ImplementingAdvancedActivities.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,393 +0,0 @@
-<chapter id="advancedgraphexecution">
- <title>Advanced graph execution</title>
-
- <!-- ### LOOPS ########################################################## -->
- <section>
- <title>Loops</title>
- <para>Activities can implement loops based on transitions or on activity composition.
- Loops can contain wait states.
- </para>
- <para>To support high numbers of automatic loop executions, the Process Virtual Machine
- tranformed the propagation of execution from tail recursion to a while loop.
- </para>
- </section>
-
- <!-- ### SUB PROCESSES ################################################## -->
- <section>
- <title>Sub processes</title>
- <para>TODO: sub processes</para>
- </section>
-
- <!-- ### DEFAULT PROCEED BEHAVIOUR ###################################### -->
- <section id="implicitproceedbehaviour">
- <title>Implicit proceed behaviour</title>
- <para>When an <literal>Activity</literal> is used as activity behaviour, it can
- explicitely propagate the execution with following methods:
- </para>
- <itemizedlist>
- <listitem><literal>waitForSignal()</literal></listitem>
- <listitem><literal>take(Transition)</literal></listitem>
- <listitem><literal>end(*)</literal></listitem>
- <listitem><literal>execute(Activity)</literal></listitem>
- <listitem><literal>createExecution(*)</literal></listitem>
- </itemizedlist>
- <para>When <literal>Activity</literal> implementations used for activity behviour
- don't call any of the following execution propagation methods, then, after
- the activity is executed, the execution will apply the implicit proceed behaviour.
- </para>
- <para>The implicit proceed behaviour is defined as follows:</para>
- <itemizedlist>
- <listitem>If the current activity has a default outgoing transition, take it.</listitem>
- <listitem>If the current activity has a parent activity, move back to the parent activity.</listitem>
- <listitem>Otherwise, end this execution.</listitem>
- </itemizedlist>
- <para>Process languages can overwrite the implicit proceed behaviour
- by overriding the <literal>proceed</literal> method in
- <literal>ExecutionImpl</literal>.
- </para>
- </section>
-
- <!-- ### FUNCTIONAL ACTIVITIES ################################ -->
- <section id="functionalactivities">
- <title>Functional activities</title>
- <para>Activities that also can be used as event listeners are called functional
- activities. Examples of automatic activities are sending an email, doing a database
- update, generating a pdf, calculating an average, etc. All of these are automatic
- activities that do not change the execution flow. Here's how such activities can
- be implemented:
- </para>
- <programlisting>public class FunctionalActivity implements Activity, EventListener {
- public void execute(ActivityExecution execution) {
- perform(execution);
- }
- public void notify(EventListenerExecution execution) {
- perform(execution);
- }
- void perform(OpenExecution execution) {
- ...do functional work...
- }
- }</programlisting>
- <para>The <literal>perform</literal> method takes an <literal>OpenExecution</literal>,
- which is the supertype of both <literal>ActivityExecution</literal> and
- <literal>EventListenerExecution</literal>. <literal>OpenExecution</literal>
- does not allow any of the specific purpose methods, but still
- the current state and the process definition can be inspected as well
- as the variables, which contain the context information for the process
- execution.
- </para>
- <para>None of these methods actually invoke execution propagation methods.
- So after the perform method is completed, the execution will
- <link linkend="implicitproceedbehaviour">proceed in the default way</link>.
- </para>
- </section>
-
-
- <!-- ### EXECUTION AND THREADS ########################################## -->
- <section id="executionandthreads">
- <title>Execution and threads</title>
- <para>This section explains how the Process Virtual Machine boroughs the thread
- from the client to bring an execution from one wait state to another.
- </para>
- <para>When a client invokes a method (like e.g. the signal method) on an execution,
- by default, the Process Virtual Machine will use that thread to progress the execution
- until it reached a wait state. Once the next wait state has been reached, the
- method returns and the client gets the thread back. This is the default way
- for the Process Virtual Machine to operate. Two more levels of asynchonous
- execution complement this default behaviour:
- <link linkend="asynchronouscontinuations">Asynchronous continuations</link>
- and the <link linkend="architecture">asynchronous command service</link>.
- </para>
- <para>The next process will show the basics concretely. It has three wait states
- and four automatic activities.
- </para>
- <figure id="process.automatic">
- <title>Process with many sequential automatic activities.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/process.automatic.png"/></imageobject></mediaobject>
- </figure>
- <para>Here's how to build the process:</para>
- <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build("automatic")
- .<emphasis role="bold">activity("wait 1").initial()</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
- .transition().to("automatic 1")
- .<emphasis role="bold">activity("automatic 1")</emphasis>.behaviour(new <emphasis role="bold">Display("one")</emphasis>)
- .transition().to("wait 2")
- .<emphasis role="bold">activity("wait 2")</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
- .transition().to("automatic 2")
- .<emphasis role="bold">activity("automatic 2")</emphasis>.behaviour(new <emphasis role="bold">Display("two")</emphasis>)
- .transition().to("automatic 3")
- .<emphasis role="bold">activity("automatic 3")</emphasis>.behaviour(new <emphasis role="bold">Display("three")</emphasis>)
- .transition().to("automatic 4")
- .<emphasis role="bold">activity("automatic 4")</emphasis>.behaviour(new <emphasis role="bold">Display("four")</emphasis>)
- .transition().to("wait 3")
- .<emphasis role="bold">activity("wait 3")</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
-.done();</programlisting>
- <para>Let's walk you through one execution of this process.
- </para>
- <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
- <para>Starting a new execution means that the initial activity is executed. So if an automatic
- activity is the initial activity, this means that immediately the first unnamed outgoing transition
- is taken. This happens all inside of the invocation of <literal>startProcessInstance</literal>.
- </para>
- <para>In this case however, the initial activity is a wait state. So
- the method <literal>startProcessInstance</literal> returns immediately and the execution will be
- positioned in the initial activity 'wait 1'.
- </para>
- <figure id="execution.automatic.wait1">
- <title>A new execution will be positioned in 'wait 1'.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.automatic.wait1.png"/></imageobject></mediaobject>
- </figure>
- <para>Then an external trigger is given with the signal method.</para>
- <programlisting>execution.signal();</programlisting>
- <para>As explained above when <link linkend="externalactivityexample">introducing the WaitState</link>,
- that signal will cause the default transition to be taken. The
- transition will move the execution to activity <literal>automatic 1</literal> and execute it.
- The execute method of the <literal>Display</literal> activity in <literal>automatic 1</literal>
- print a line to the console and it will <emphasis role="bold">not</emphasis> call
- <literal>execution.waitForSignal()</literal>. Therefore, the execution will proceed by
- taking the default transition out of <literal>automatic 1</literal>. At this stage, the
- signal method is still blocking. Another way to think about it is that the execution
- methods like <literal>signal</literal> will use the thread of the client to interpret
- the process definition until a wait state is reached.
- </para>
- <para>Then the execution arrives in <literal>wait 2</literal> and executes
- the <literal>WaitState</literal> activity. That method will invoke
- the <literal>execution.waitForSignal()</literal>, which will cause the signal method
- to return. That is when the thread is given back to the client that invoked the
- <literal>signal</literal> method.
- </para>
- <para>So when the signal method returns, the execution is positioned in <literal>wait 2</literal>.</para>
- <figure id="execution.automatic.wait2">
- <title>One signal brought the execution from 'initial' to 'wait 2'.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.automatic.wait2.png"/></imageobject></mediaobject>
- </figure>
- <para>Then the execution is now waiting for an external trigger just as an object
- (more precisely an object graph) in memory until the next external trigger is given
- with the signal method.
- </para>
- <programlisting>execution.signal();</programlisting>
- <para>This second invocation of signal will take the execution similarly all the
- way to <literal>wait 3</literal> before it returns.
- </para>
- <figure id="automatic.wait3">
- <title>The second signal brought the execution all the way to 'wait 3'.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/ch04.automatic.wait3.png"/></imageobject></mediaobject>
- </figure>
- <para>The benefits of using this paradigm is that the same process definition
- can be executed in <link linkend="clientexecutionmode">client execution mode</link>
- (in-memory without persistence) as well as in <link linkend="persistentexecutionmode">
- persistent execution mode</link>, depending on the application and on the environment.
- </para>
- <para>When executing a process in persistent mode, this is how you typically want
- to bind that process execution to transactions of the database:
- </para>
- <figure id="transactions.png">
- <title>Transactions over time in persistent execution mode.</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/transactions.png"/></imageobject></mediaobject>
- </figure>
- <para>In most situations, the computational work that needs to be done as part of
- the process after an external trigger (the red pieces) is pretty minimal. Typically
- transactions combining the process execution and processing the request from the
- UI takes typically less then a second. Whereas the wait state in business processes
- typically can span for hours, days or even years. The clue is to clearly distinct
- when a wait state starts so that only the computational work done before the start
- of that wait state should be included in the transaction.
- </para>
- <para>Think of
- it this way: "When an approval arrives, what are all the automated processing that
- needs to be done before the process system needs to wait for another external
- trigger?" Unless pdf's need to be generated or mass emails need to be send,
- the amount of time that this takes is usually neglectable. That is why in the
- default persistent execution mode, the process work is executed in the thread
- of the client.
- </para>
- <para>This reasoning even holds in case of concurrent paths of execution.
- When a single path of execution splits into concurrent paths of execution,
- the process overhead of calculating that is neglectable. So that is why it
- makes sense for a fork or split activity implementation that targets persistent
- execution mode to spawn the concurrent paths sequentially in the same thread.
- Basically it's all just computational work as part of the same transaction.
- This can only be done because the fork/split knows that each concurrent path
- of execution will return whenever a wait state is encountered.
- </para>
- <para>Since this is a difficult concept to grasp, I'll explain it again with other
- words. Look at it from the overhead that is produced by the process execution
- itself in persistent execution mode. If in a transaction, an execution is given
- an external trigger and that causes the execution to split into multiple concurrent
- paths of execution. Then the process overhead of calculating this is neglectable.
- Also the overhead of the generated SQL is neglectable. And since all the work done
- in the concurrent branches must be done inside that single transaction, there is
- typically no point in having fork/split implementations spawn the concurrent
- paths of execution in multiple threads.
- </para>
- <para>To make executable processes, developers need to know exactly what the automatic activities
- are, what the wait states are and which threads will be allocated to the process execution.
- For business analysts that draw the analysis process, things are a bit simpler. For the
- activities they draw, they usually know whether it's a human or a system that is responsible.
- But they typically don't not how this translates to threads and transactions.
- </para>
- <para>So for the developer, the first job is to analyse what needs to be executed
- within the thread of control of the process and what is outside. Looking for the external
- triggers can be a good start to find the wait states in a process, just like verbs and nouns
- can be the rule of thumb in building UML class diagrams.
- </para>
- </section>
-
- <!-- ### PROCESS CONCURRENCY ############################################ -->
- <section>
- <title>Process concurrency</title>
- <para>To model process concurrency, there is a parent-child tree structure on the
- execution. The idea is that the main path of execution is the root of that tree.
- The main path of execution is also called the process instance. It is the execution
- that is created when starting or creating a new process instance for a given
- process definition.
- </para>
- <para>Now, because the main path of execution is the same object as the
- process instance, this keeps the usage simple in case of simple processes
- without concurrency.
- </para>
- <figure id="execution.structure">
- <title>UML class diagram of the basic execution structure</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/class.diagram.process.execution.png"/></imageobject></mediaobject>
- </figure>
- <para>To establish multiple concurrent paths of execution, activity implementations
- like a fork or split can create child executions with method
- <literal>ActivityExecution.createExecution</literal>. Activity implementations
- like join or merge can stop these concurrent paths of execution by calling
- method <literal>stop</literal> on the concurrent execution.
- </para>
- <para>Only leaf executions can be active. Non-leave executions should be
- inactive. This tree structure of executions doesn't enforce a particular type of
- concurrency or join behaviour. It's up to the forks or and-splits and to the joins
- or and-merges to use the execution tree structure in any way they want to define
- the wanted concurrency behaviour. Here you see an example
- of concurrent executions.
- </para>
- <figure id="concurrency">
- <title>Concurrent paths of execution</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/execution.concurrency.png"/></imageobject></mediaobject>
- </figure>
- <para>There is a billing and a shipping path of execution. In this case, the
- flat bar activities represent activities that fork and join. The execution shows a three
- executions. The main path of execution is inactive (represented as gray) and the
- billing and shipping paths of execution are active and point to the activity
- <literal>bill</literal> and <literal>ship</literal> respectively.
- </para>
- <para>It's up to the activity behaviour implementations how they want to use this
- execution structure. Suppose that multiple tasks have to be completed before the
- execution is to proceed. The activity behaviour can spawn a series of child executions
- for this. Or alternatively, the task component could support task groups that
- are associated to one single execution. In that case, the task component becomes
- responsible for synchronizing the tasks, thereby moving this responsibility
- outside the scope of the execution tree structure.
- </para>
- </section>
-
- <!-- ### EXCEPTION HANDLERS ############################################# -->
- <section>
- <title>Exception handlers</title>
- <para>In all the code that is associated to a process
- like <literal>Activity</literal>s, <literal>EventListeners</literal> and
- <literal>Condition</literal>s, it's possible to associate exception handlers. This
- can be thought of as including try-catch blocks in
- the method implementations of those implementations. But in order to build more reusable building
- blocks for both the delegation classes and the exception handling logic, exception handlers are
- added to the core process model.
- </para>
- <para>An exception handler can be associated to any process element. When an exception
- occurs in a delegation class, a matching exception handler will be searched for. If
- such an exception handler is found, it will get a chance to handle the exception.
- </para>
- <para>If an exception handler completes without problems, then the exception is considered
- handled and the execution resumes right after the delegation code that was called. For example,
- a transition has three actions and the second action throws an exception that is handled
- by an exception handler, then
- </para>
- <para>Writing automatic activities that are exception handler aware is easy. The
- default is to proceed anyway. No method needs to be called on the execution. So
- if an automatic activity throws an exception that is handled by an exception handler,
- the execution will just proceed after that activity. It becomes a big more difficult
- for control flow activities. They might have to include try-finally blocks to
- invoke the proper methods on the execution before an exception handler gets a
- chance to handle the exception. For example, if an activity is a wait state and
- an exception occurs, then there is a risk that the thread jumps over the
- invocation of <literal>execution.waitForSignal()</literal>, causing the execution
- to proceed after the activity.
- </para>
- <para>TODO: exceptionhandler.isRethrowMasked</para>
- <para>TODO: transactional exception handlers</para>
- <para>TODO: we never catch errors</para>
- </section>
-
- <!-- ### PROCESS MODIFICATIONS ########################################## -->
- <section>
- <title>Process modifications</title>
- <para>TODO: process modifications</para>
- </section>
-
- <!-- ### LOCKING AND EXECUTION STATE #################################### -->
- <section>
- <title>Locking and execution state</title>
- <para>The state of an execution is either active or locked. An active
- execution is either executing or waiting for an external trigger. If an
- execution is not in <literal>STATE_ACTIVE</literal>, then it is locked.
- A locked execution is read only and cannot receive any external triggers.
- </para>
- <para>When a new execution is created, it is in STATE_ACTIVE. To change
- the state to a locked state, use lock(String). Some STATE_* constants
- are provided that represent the most commonly used locked states. But
- the state '...' in the picture indicates that any string can be provided
- as the state in the lock method.
- </para>
- <figure id="execution.states">
- <title>States of an execution</title>
- <mediaobject><imageobject><imagedata align="center" fileref="images/ch04.execution.states.png"/></imageobject></mediaobject>
- </figure>
- <para>If an execution is locked, methods that change the execution will
- throw a PvmException and the message will reference the actual locking state.
- Firing events, updating variables, updating priority and adding comments
- are not considered to change an execution. Also creation and removal of child
- executions are unchecked, which means that those methods can be invoked by
- external API clients and activity behaviour methods, even while the execution
- is in a locked state.
- </para>
- <para>Make sure that comparisons between getState() and the STATE_* constants
- are done with .equals and not with '==' because if executions are loaded
- from persistent storage, a new string is created instead of the constants.
- </para>
- <para>An execution implementation will be locked:
- </para>
- <itemizedlist>
- <listitem>When it is ended</listitem>
- <listitem>When it is suspended</listitem>
- <listitem>During asynchronous continuations</listitem>
- </itemizedlist>
- <para>Furthermore, locking can be used by Activity implementations to make
- executions read only during wait states hen responsibility for the execution is
- transferred to an external entity such as:
- </para>
- <itemizedlist>
- <listitem>A human task</listitem>
- <listitem>A service invocation</listitem>
- <listitem>A wait state that ends when a scanner detects that a file appears</listitem>
- </itemizedlist>
- <para>In these situations the strategy is that the external entity should get
- full control over the execution because it wants to control what is allowed
- and what not. To get that control, they lock the execution so that all interactions
- have to go through the external entity.
- </para>
- <para>One of the main reasons to create external entities is that they can live
- on after the execution has already proceeded. For example, in case
- of a service invocation, a timer could cause the execution to take the timeout transition.
- When the response arrives after the timeout, the service invocation entity should
- make sure it doesn't signal the execution. So the service invocation can be
- seen as a activity instance (aka activity instance) and is unique for every execution
- of the activity.
- </para>
- <para>External entities themselves are responsible for managing the execution
- lock. If the timers and client applications are consequent in addressing the
- external entities instead of the execution directly, then locking is in theory
- unnecessary. It's up to the activity behaviour implementations whether they want
- to take the overhead of locking and unlocking.
- </para>
- </section>
-
-</chapter>
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ProcessAnatomy.xml (from rev 4742, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch05-ProcessAnatomy.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ProcessAnatomy.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ProcessAnatomy.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -0,0 +1,62 @@
+<chapter id="processanatomy">
+ <title>Process anatomy</title>
+
+ <para>Above we already touched briefly on the two main process constructs:
+ Activities, transitions and activity composition. This chapter explores in full
+ all the possibilities of the process definition structures.
+ </para>
+
+ <para>There are basically two forms of process languages: graph based and composite
+ process languages. First of all, the process supports both. Even graph based execution
+ and activity composition can be used in combination to implement something like UML super states.
+ Furthermore, automatic functional activities can be implemented so that they can be
+ used with transitions as well as with activity composition.
+ </para>
+
+ <figure id="process.anatomy">
+ <title>UML class diagram of the logical process structure</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.anatomy.classes.png"/></imageobject></mediaobject>
+ </figure>
+
+ <para>Next we'll show a series of example diagram structures that can be formed
+ with the PVM process model.
+ </para>
+
+ <figure id="transition">
+ <title>Any two activities can be connected with a transition.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.png"/></imageobject></mediaobject>
+ </figure>
+
+ <figure id="self.transition">
+ <title>A self transition.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/self.transition.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="composite.activity">
+ <title>Composite activity is a list of nested activities.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/composite.activity.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="transition.into.composite">
+ <title>Transition to a activity inside a composite.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.into.composite.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="transition.out.of.composite">
+ <title>Transition from a activity inside a composite to a activity outside the composite.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.out.of.composite.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="transition.inheritence">
+ <title>Transition of composite activities are inherited. The activity inside can take the transition of the composite activity.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.inheritence.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="transition.to.outer">
+ <title>Transition from a activity to an outer composite.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.to.outer.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="transition.to.inner">
+ <title>Transition from a composite activity to an inner composed activity.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transition.to.inner.png"/></imageobject></mediaobject>
+ </figure>
+ <figure id="initial.in.composite">
+ <title>An initial activity inside a composite activity.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/initial.in.composite.png"/></imageobject></mediaobject>
+ </figure>
+</chapter>
\ No newline at end of file
Copied: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ImplementingAdvancedActivities.xml (from rev 4742, jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch06-ImplementingAdvancedActivities.xml)
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ImplementingAdvancedActivities.xml (rev 0)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch07-ImplementingAdvancedActivities.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -0,0 +1,393 @@
+<chapter id="advancedgraphexecution">
+ <title>Advanced graph execution</title>
+
+ <!-- ### LOOPS ########################################################## -->
+ <section>
+ <title>Loops</title>
+ <para>Activities can implement loops based on transitions or on activity composition.
+ Loops can contain wait states.
+ </para>
+ <para>To support high numbers of automatic loop executions, the Process Virtual Machine
+ tranformed the propagation of execution from tail recursion to a while loop.
+ </para>
+ </section>
+
+ <!-- ### SUB PROCESSES ################################################## -->
+ <section>
+ <title>Sub processes</title>
+ <para>TODO: sub processes</para>
+ </section>
+
+ <!-- ### DEFAULT PROCEED BEHAVIOUR ###################################### -->
+ <section id="implicitproceedbehaviour">
+ <title>Implicit proceed behaviour</title>
+ <para>When an <literal>Activity</literal> is used as activity behaviour, it can
+ explicitely propagate the execution with following methods:
+ </para>
+ <itemizedlist>
+ <listitem><literal>waitForSignal()</literal></listitem>
+ <listitem><literal>take(Transition)</literal></listitem>
+ <listitem><literal>end(*)</literal></listitem>
+ <listitem><literal>execute(Activity)</literal></listitem>
+ <listitem><literal>createExecution(*)</literal></listitem>
+ </itemizedlist>
+ <para>When <literal>Activity</literal> implementations used for activity behviour
+ don't call any of the following execution propagation methods, then, after
+ the activity is executed, the execution will apply the implicit proceed behaviour.
+ </para>
+ <para>The implicit proceed behaviour is defined as follows:</para>
+ <itemizedlist>
+ <listitem>If the current activity has a default outgoing transition, take it.</listitem>
+ <listitem>If the current activity has a parent activity, move back to the parent activity.</listitem>
+ <listitem>Otherwise, end this execution.</listitem>
+ </itemizedlist>
+ <para>Process languages can overwrite the implicit proceed behaviour
+ by overriding the <literal>proceed</literal> method in
+ <literal>ExecutionImpl</literal>.
+ </para>
+ </section>
+
+ <!-- ### FUNCTIONAL ACTIVITIES ################################ -->
+ <section id="functionalactivities">
+ <title>Functional activities</title>
+ <para>Activities that also can be used as event listeners are called functional
+ activities. Examples of automatic activities are sending an email, doing a database
+ update, generating a pdf, calculating an average, etc. All of these are automatic
+ activities that do not change the execution flow. Here's how such activities can
+ be implemented:
+ </para>
+ <programlisting>public class FunctionalActivity implements Activity, EventListener {
+ public void execute(ActivityExecution execution) {
+ perform(execution);
+ }
+ public void notify(EventListenerExecution execution) {
+ perform(execution);
+ }
+ void perform(OpenExecution execution) {
+ ...do functional work...
+ }
+ }</programlisting>
+ <para>The <literal>perform</literal> method takes an <literal>OpenExecution</literal>,
+ which is the supertype of both <literal>ActivityExecution</literal> and
+ <literal>EventListenerExecution</literal>. <literal>OpenExecution</literal>
+ does not allow any of the specific purpose methods, but still
+ the current state and the process definition can be inspected as well
+ as the variables, which contain the context information for the process
+ execution.
+ </para>
+ <para>None of these methods actually invoke execution propagation methods.
+ So after the perform method is completed, the execution will
+ <link linkend="implicitproceedbehaviour">proceed in the default way</link>.
+ </para>
+ </section>
+
+
+ <!-- ### EXECUTION AND THREADS ########################################## -->
+ <section id="executionandthreads">
+ <title>Execution and threads</title>
+ <para>This section explains how the Process Virtual Machine boroughs the thread
+ from the client to bring an execution from one wait state to another.
+ </para>
+ <para>When a client invokes a method (like e.g. the signal method) on an execution,
+ by default, the Process Virtual Machine will use that thread to progress the execution
+ until it reached a wait state. Once the next wait state has been reached, the
+ method returns and the client gets the thread back. This is the default way
+ for the Process Virtual Machine to operate. Two more levels of asynchonous
+ execution complement this default behaviour:
+ <link linkend="asynchronouscontinuations">Asynchronous continuations</link>
+ and the <link linkend="architecture">asynchronous command service</link>.
+ </para>
+ <para>The next process will show the basics concretely. It has three wait states
+ and four automatic activities.
+ </para>
+ <figure id="process.automatic">
+ <title>Process with many sequential automatic activities.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/process.automatic.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Here's how to build the process:</para>
+ <programlisting>ClientProcessDefinition processDefinition = ProcessFactory.build("automatic")
+ .<emphasis role="bold">activity("wait 1").initial()</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
+ .transition().to("automatic 1")
+ .<emphasis role="bold">activity("automatic 1")</emphasis>.behaviour(new <emphasis role="bold">Display("one")</emphasis>)
+ .transition().to("wait 2")
+ .<emphasis role="bold">activity("wait 2")</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
+ .transition().to("automatic 2")
+ .<emphasis role="bold">activity("automatic 2")</emphasis>.behaviour(new <emphasis role="bold">Display("two")</emphasis>)
+ .transition().to("automatic 3")
+ .<emphasis role="bold">activity("automatic 3")</emphasis>.behaviour(new <emphasis role="bold">Display("three")</emphasis>)
+ .transition().to("automatic 4")
+ .<emphasis role="bold">activity("automatic 4")</emphasis>.behaviour(new <emphasis role="bold">Display("four")</emphasis>)
+ .transition().to("wait 3")
+ .<emphasis role="bold">activity("wait 3")</emphasis>.behaviour(new <emphasis role="bold">WaitState</emphasis>())
+.done();</programlisting>
+ <para>Let's walk you through one execution of this process.
+ </para>
+ <programlisting>ClientExecution execution = processDefinition.startProcessInstance();</programlisting>
+ <para>Starting a new execution means that the initial activity is executed. So if an automatic
+ activity is the initial activity, this means that immediately the first unnamed outgoing transition
+ is taken. This happens all inside of the invocation of <literal>startProcessInstance</literal>.
+ </para>
+ <para>In this case however, the initial activity is a wait state. So
+ the method <literal>startProcessInstance</literal> returns immediately and the execution will be
+ positioned in the initial activity 'wait 1'.
+ </para>
+ <figure id="execution.automatic.wait1">
+ <title>A new execution will be positioned in 'wait 1'.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.automatic.wait1.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Then an external trigger is given with the signal method.</para>
+ <programlisting>execution.signal();</programlisting>
+ <para>As explained above when <link linkend="externalactivityexample">introducing the WaitState</link>,
+ that signal will cause the default transition to be taken. The
+ transition will move the execution to activity <literal>automatic 1</literal> and execute it.
+ The execute method of the <literal>Display</literal> activity in <literal>automatic 1</literal>
+ print a line to the console and it will <emphasis role="bold">not</emphasis> call
+ <literal>execution.waitForSignal()</literal>. Therefore, the execution will proceed by
+ taking the default transition out of <literal>automatic 1</literal>. At this stage, the
+ signal method is still blocking. Another way to think about it is that the execution
+ methods like <literal>signal</literal> will use the thread of the client to interpret
+ the process definition until a wait state is reached.
+ </para>
+ <para>Then the execution arrives in <literal>wait 2</literal> and executes
+ the <literal>WaitState</literal> activity. That method will invoke
+ the <literal>execution.waitForSignal()</literal>, which will cause the signal method
+ to return. That is when the thread is given back to the client that invoked the
+ <literal>signal</literal> method.
+ </para>
+ <para>So when the signal method returns, the execution is positioned in <literal>wait 2</literal>.</para>
+ <figure id="execution.automatic.wait2">
+ <title>One signal brought the execution from 'initial' to 'wait 2'.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.automatic.wait2.png"/></imageobject></mediaobject>
+ </figure>
+ <para>Then the execution is now waiting for an external trigger just as an object
+ (more precisely an object graph) in memory until the next external trigger is given
+ with the signal method.
+ </para>
+ <programlisting>execution.signal();</programlisting>
+ <para>This second invocation of signal will take the execution similarly all the
+ way to <literal>wait 3</literal> before it returns.
+ </para>
+ <figure id="automatic.wait3">
+ <title>The second signal brought the execution all the way to 'wait 3'.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/ch04.automatic.wait3.png"/></imageobject></mediaobject>
+ </figure>
+ <para>The benefits of using this paradigm is that the same process definition
+ can be executed in <link linkend="clientexecutionmode">client execution mode</link>
+ (in-memory without persistence) as well as in <link linkend="persistentexecutionmode">
+ persistent execution mode</link>, depending on the application and on the environment.
+ </para>
+ <para>When executing a process in persistent mode, this is how you typically want
+ to bind that process execution to transactions of the database:
+ </para>
+ <figure id="transactions.png">
+ <title>Transactions over time in persistent execution mode.</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/transactions.png"/></imageobject></mediaobject>
+ </figure>
+ <para>In most situations, the computational work that needs to be done as part of
+ the process after an external trigger (the red pieces) is pretty minimal. Typically
+ transactions combining the process execution and processing the request from the
+ UI takes typically less then a second. Whereas the wait state in business processes
+ typically can span for hours, days or even years. The clue is to clearly distinct
+ when a wait state starts so that only the computational work done before the start
+ of that wait state should be included in the transaction.
+ </para>
+ <para>Think of
+ it this way: "When an approval arrives, what are all the automated processing that
+ needs to be done before the process system needs to wait for another external
+ trigger?" Unless pdf's need to be generated or mass emails need to be send,
+ the amount of time that this takes is usually neglectable. That is why in the
+ default persistent execution mode, the process work is executed in the thread
+ of the client.
+ </para>
+ <para>This reasoning even holds in case of concurrent paths of execution.
+ When a single path of execution splits into concurrent paths of execution,
+ the process overhead of calculating that is neglectable. So that is why it
+ makes sense for a fork or split activity implementation that targets persistent
+ execution mode to spawn the concurrent paths sequentially in the same thread.
+ Basically it's all just computational work as part of the same transaction.
+ This can only be done because the fork/split knows that each concurrent path
+ of execution will return whenever a wait state is encountered.
+ </para>
+ <para>Since this is a difficult concept to grasp, I'll explain it again with other
+ words. Look at it from the overhead that is produced by the process execution
+ itself in persistent execution mode. If in a transaction, an execution is given
+ an external trigger and that causes the execution to split into multiple concurrent
+ paths of execution. Then the process overhead of calculating this is neglectable.
+ Also the overhead of the generated SQL is neglectable. And since all the work done
+ in the concurrent branches must be done inside that single transaction, there is
+ typically no point in having fork/split implementations spawn the concurrent
+ paths of execution in multiple threads.
+ </para>
+ <para>To make executable processes, developers need to know exactly what the automatic activities
+ are, what the wait states are and which threads will be allocated to the process execution.
+ For business analysts that draw the analysis process, things are a bit simpler. For the
+ activities they draw, they usually know whether it's a human or a system that is responsible.
+ But they typically don't not how this translates to threads and transactions.
+ </para>
+ <para>So for the developer, the first job is to analyse what needs to be executed
+ within the thread of control of the process and what is outside. Looking for the external
+ triggers can be a good start to find the wait states in a process, just like verbs and nouns
+ can be the rule of thumb in building UML class diagrams.
+ </para>
+ </section>
+
+ <!-- ### PROCESS CONCURRENCY ############################################ -->
+ <section>
+ <title>Process concurrency</title>
+ <para>To model process concurrency, there is a parent-child tree structure on the
+ execution. The idea is that the main path of execution is the root of that tree.
+ The main path of execution is also called the process instance. It is the execution
+ that is created when starting or creating a new process instance for a given
+ process definition.
+ </para>
+ <para>Now, because the main path of execution is the same object as the
+ process instance, this keeps the usage simple in case of simple processes
+ without concurrency.
+ </para>
+ <figure id="execution.structure">
+ <title>UML class diagram of the basic execution structure</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/class.diagram.process.execution.png"/></imageobject></mediaobject>
+ </figure>
+ <para>To establish multiple concurrent paths of execution, activity implementations
+ like a fork or split can create child executions with method
+ <literal>ActivityExecution.createExecution</literal>. Activity implementations
+ like join or merge can stop these concurrent paths of execution by calling
+ method <literal>stop</literal> on the concurrent execution.
+ </para>
+ <para>Only leaf executions can be active. Non-leave executions should be
+ inactive. This tree structure of executions doesn't enforce a particular type of
+ concurrency or join behaviour. It's up to the forks or and-splits and to the joins
+ or and-merges to use the execution tree structure in any way they want to define
+ the wanted concurrency behaviour. Here you see an example
+ of concurrent executions.
+ </para>
+ <figure id="concurrency">
+ <title>Concurrent paths of execution</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/execution.concurrency.png"/></imageobject></mediaobject>
+ </figure>
+ <para>There is a billing and a shipping path of execution. In this case, the
+ flat bar activities represent activities that fork and join. The execution shows a three
+ executions. The main path of execution is inactive (represented as gray) and the
+ billing and shipping paths of execution are active and point to the activity
+ <literal>bill</literal> and <literal>ship</literal> respectively.
+ </para>
+ <para>It's up to the activity behaviour implementations how they want to use this
+ execution structure. Suppose that multiple tasks have to be completed before the
+ execution is to proceed. The activity behaviour can spawn a series of child executions
+ for this. Or alternatively, the task component could support task groups that
+ are associated to one single execution. In that case, the task component becomes
+ responsible for synchronizing the tasks, thereby moving this responsibility
+ outside the scope of the execution tree structure.
+ </para>
+ </section>
+
+ <!-- ### EXCEPTION HANDLERS ############################################# -->
+ <section>
+ <title>Exception handlers</title>
+ <para>In all the code that is associated to a process
+ like <literal>Activity</literal>s, <literal>EventListeners</literal> and
+ <literal>Condition</literal>s, it's possible to associate exception handlers. This
+ can be thought of as including try-catch blocks in
+ the method implementations of those implementations. But in order to build more reusable building
+ blocks for both the delegation classes and the exception handling logic, exception handlers are
+ added to the core process model.
+ </para>
+ <para>An exception handler can be associated to any process element. When an exception
+ occurs in a delegation class, a matching exception handler will be searched for. If
+ such an exception handler is found, it will get a chance to handle the exception.
+ </para>
+ <para>If an exception handler completes without problems, then the exception is considered
+ handled and the execution resumes right after the delegation code that was called. For example,
+ a transition has three actions and the second action throws an exception that is handled
+ by an exception handler, then
+ </para>
+ <para>Writing automatic activities that are exception handler aware is easy. The
+ default is to proceed anyway. No method needs to be called on the execution. So
+ if an automatic activity throws an exception that is handled by an exception handler,
+ the execution will just proceed after that activity. It becomes a big more difficult
+ for control flow activities. They might have to include try-finally blocks to
+ invoke the proper methods on the execution before an exception handler gets a
+ chance to handle the exception. For example, if an activity is a wait state and
+ an exception occurs, then there is a risk that the thread jumps over the
+ invocation of <literal>execution.waitForSignal()</literal>, causing the execution
+ to proceed after the activity.
+ </para>
+ <para>TODO: exceptionhandler.isRethrowMasked</para>
+ <para>TODO: transactional exception handlers</para>
+ <para>TODO: we never catch errors</para>
+ </section>
+
+ <!-- ### PROCESS MODIFICATIONS ########################################## -->
+ <section>
+ <title>Process modifications</title>
+ <para>TODO: process modifications</para>
+ </section>
+
+ <!-- ### LOCKING AND EXECUTION STATE #################################### -->
+ <section>
+ <title>Locking and execution state</title>
+ <para>The state of an execution is either active or locked. An active
+ execution is either executing or waiting for an external trigger. If an
+ execution is not in <literal>STATE_ACTIVE</literal>, then it is locked.
+ A locked execution is read only and cannot receive any external triggers.
+ </para>
+ <para>When a new execution is created, it is in STATE_ACTIVE. To change
+ the state to a locked state, use lock(String). Some STATE_* constants
+ are provided that represent the most commonly used locked states. But
+ the state '...' in the picture indicates that any string can be provided
+ as the state in the lock method.
+ </para>
+ <figure id="execution.states">
+ <title>States of an execution</title>
+ <mediaobject><imageobject><imagedata align="center" fileref="images/ch04.execution.states.png"/></imageobject></mediaobject>
+ </figure>
+ <para>If an execution is locked, methods that change the execution will
+ throw a PvmException and the message will reference the actual locking state.
+ Firing events, updating variables, updating priority and adding comments
+ are not considered to change an execution. Also creation and removal of child
+ executions are unchecked, which means that those methods can be invoked by
+ external API clients and activity behaviour methods, even while the execution
+ is in a locked state.
+ </para>
+ <para>Make sure that comparisons between getState() and the STATE_* constants
+ are done with .equals and not with '==' because if executions are loaded
+ from persistent storage, a new string is created instead of the constants.
+ </para>
+ <para>An execution implementation will be locked:
+ </para>
+ <itemizedlist>
+ <listitem>When it is ended</listitem>
+ <listitem>When it is suspended</listitem>
+ <listitem>During asynchronous continuations</listitem>
+ </itemizedlist>
+ <para>Furthermore, locking can be used by Activity implementations to make
+ executions read only during wait states hen responsibility for the execution is
+ transferred to an external entity such as:
+ </para>
+ <itemizedlist>
+ <listitem>A human task</listitem>
+ <listitem>A service invocation</listitem>
+ <listitem>A wait state that ends when a scanner detects that a file appears</listitem>
+ </itemizedlist>
+ <para>In these situations the strategy is that the external entity should get
+ full control over the execution because it wants to control what is allowed
+ and what not. To get that control, they lock the execution so that all interactions
+ have to go through the external entity.
+ </para>
+ <para>One of the main reasons to create external entities is that they can live
+ on after the execution has already proceeded. For example, in case
+ of a service invocation, a timer could cause the execution to take the timeout transition.
+ When the response arrives after the timeout, the service invocation entity should
+ make sure it doesn't signal the execution. So the service invocation can be
+ seen as a activity instance (aka activity instance) and is unique for every execution
+ of the activity.
+ </para>
+ <para>External entities themselves are responsible for managing the execution
+ lock. If the timers and client applications are consequent in addressing the
+ external entities instead of the execution directly, then locking is in theory
+ unnecessary. It's up to the activity behaviour implementations whether they want
+ to take the overhead of locking and unlocking.
+ </para>
+ </section>
+
+</chapter>
Modified: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/chxx-ExecutionModes.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/chxx-ExecutionModes.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/chxx-ExecutionModes.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -102,7 +102,7 @@
like this:
</para>
<literal><emphasis role="bold">environment.cfg.xml</emphasis>:</literal>
- <programlisting><jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+ <programlisting><jbpm-configuration>
<process-engine-context>
Modified: jbpm4/trunk/modules/distro/src/main/files/jboss/config.common/deploy/jbpm/jbpm-service.sar/jbpm.cfg.xml
===================================================================
--- jbpm4/trunk/modules/distro/src/main/files/jboss/config.common/deploy/jbpm/jbpm-service.sar/jbpm.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/distro/src/main/files/jboss/config.common/deploy/jbpm/jbpm-service.sar/jbpm.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<import resource="jbpm.default.cfg.xml" />
<import resource="jbpm.tx.jta.cfg.xml" />
Copied: jbpm4/trunk/modules/distro/src/main/files/jboss/config.jboss4/deploy/jbpm/jbpm-service.sar/META-INF/jboss-service.xml (from rev 4742, jbpm4/trunk/modules/distro/src/main/deployer/config.jboss4/deploy/jbpm/jbpm-service.sar/META-INF/jboss-service.xml)
===================================================================
--- jbpm4/trunk/modules/distro/src/main/files/jboss/config.jboss4/deploy/jbpm/jbpm-service.sar/META-INF/jboss-service.xml (rev 0)
+++ jbpm4/trunk/modules/distro/src/main/files/jboss/config.jboss4/deploy/jbpm/jbpm-service.sar/META-INF/jboss-service.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- $Id: jboss-service.xml 44143 2006-04-24 18:19:21Z kkhan $ -->
+
+<!-- ===================================================================== -->
+<!-- JBoss Server Configuration -->
+<!-- ===================================================================== -->
+
+<server>
+
+ <mbean code="org.jbpm.integration.jboss4.JBPMDeployer"
+ name="org.jbpm:service=JBPMDeployer">
+ </mbean>
+
+</server>
Property changes on: jbpm4/trunk/modules/distro/src/main/files/jboss/config.jboss4/deploy/jbpm/jbpm-service.sar/META-INF/jboss-service.xml
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: jbpm4/trunk/modules/distro/src/main/files/jboss/jbpm.cfg.integration.tests/jbpm.cfg.xml
===================================================================
--- jbpm4/trunk/modules/distro/src/main/files/jboss/jbpm.cfg.integration.tests/jbpm.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/distro/src/main/files/jboss/jbpm.cfg.integration.tests/jbpm.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,12 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<import resource="jbpm.default.cfg.xml" />
<import resource="jbpm.tx.jta.cfg.xml" />
<import resource="jbpm.jpdl.cfg.xml" />
<import resource="jbpm.identity.cfg.xml" />
+ <!-- Job executor is excluded for running the example test cases.
+ To enable timers and messages in production use, this should be included.
+ import resource="jbpm.jobexecutor.cfg.xml" / -->
+
<process-engine-context>
<mail-template name="MemoTemplate">
Modified: jbpm4/trunk/modules/distro/src/main/files/jboss/jbpm.cfg.remote.client/jbpm.cfg.xml
===================================================================
--- jbpm4/trunk/modules/distro/src/main/files/jboss/jbpm.cfg.remote.client/jbpm.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/distro/src/main/files/jboss/jbpm.cfg.remote.client/jbpm.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<import resource="jbpm.jbossremote.cfg.xml" />
Modified: jbpm4/trunk/modules/enterprise/src/test/java/org/jbpm/enterprise/internal/ejb/TimerTest.java
===================================================================
--- jbpm4/trunk/modules/enterprise/src/test/java/org/jbpm/enterprise/internal/ejb/TimerTest.java 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/enterprise/src/test/java/org/jbpm/enterprise/internal/ejb/TimerTest.java 2009-05-06 14:03:44 UTC (rev 4749)
@@ -30,7 +30,6 @@
import org.jbpm.api.Execution;
import org.jbpm.api.ExecutionService;
-import org.jbpm.api.ProcessService;
import org.jbpm.api.RepositoryService;
import org.jbpm.api.client.ClientProcessDefinition;
import org.jbpm.api.cmd.Command;
Modified: jbpm4/trunk/modules/enterprise/src/test/java/org/jbpm/test/deployer/DeployerTestServlet.java
===================================================================
--- jbpm4/trunk/modules/enterprise/src/test/java/org/jbpm/test/deployer/DeployerTestServlet.java 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/enterprise/src/test/java/org/jbpm/test/deployer/DeployerTestServlet.java 2009-05-06 14:03:44 UTC (rev 4749)
@@ -21,22 +21,22 @@
*/
package org.jbpm.test.deployer;
-import org.jbpm.api.ProcessDefinition;
-import org.jbpm.api.ProcessDefinitionQuery;
-import org.jbpm.api.ProcessEngine;
-import org.jbpm.api.ProcessService;
-import org.jbpm.api.RepositoryService;
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.naming.InitialContext;
+import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import javax.servlet.ServletException;
-import javax.naming.InitialContext;
+import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
-import javax.transaction.SystemException;
-import java.io.IOException;
-import java.io.PrintWriter;
+import org.jbpm.api.ProcessDefinition;
+import org.jbpm.api.ProcessDefinitionQuery;
+import org.jbpm.api.ProcessEngine;
+import org.jbpm.api.RepositoryService;
+
/**
* @author Heiko.Braun <heiko.braun at jboss.com>
*/
Modified: jbpm4/trunk/modules/examples/src/test/resources/jbpm.cfg.xml
===================================================================
--- jbpm4/trunk/modules/examples/src/test/resources/jbpm.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/examples/src/test/resources/jbpm.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,12 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<import resource="jbpm.default.cfg.xml" />
<import resource="jbpm.tx.hibernate.cfg.xml" />
<import resource="jbpm.jpdl.cfg.xml" />
<import resource="jbpm.identity.cfg.xml" />
+ <!-- Job executor is excluded for running the example test cases.
+ To enable timers and messages in production use, this should be included.
+ import resource="jbpm.jobexecutor.cfg.xml" / -->
+
<process-engine-context>
<mail-template name="MemoTemplate">
Modified: jbpm4/trunk/modules/jpdl/src/main/resources/jbpm.jpdl.cfg.xml
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/resources/jbpm.jpdl.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/jpdl/src/main/resources/jbpm.jpdl.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<process-engine-context>
Modified: jbpm4/trunk/modules/jpdl/src/test/resources/jbpm.cfg.xml
===================================================================
--- jbpm4/trunk/modules/jpdl/src/test/resources/jbpm.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/jpdl/src/test/resources/jbpm.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<import resource="jbpm.default.cfg.xml" />
<import resource="jbpm.tx.hibernate.cfg.xml" />
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/env/JbpmConfigurationParser.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/env/JbpmConfigurationParser.java 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/env/JbpmConfigurationParser.java 2009-05-06 14:03:44 UTC (rev 4749)
@@ -21,7 +21,6 @@
*/
package org.jbpm.pvm.internal.env;
-import org.jbpm.api.JbpmException;
import org.jbpm.pvm.internal.cfg.JbpmConfiguration;
import org.jbpm.pvm.internal.util.XmlUtil;
import org.jbpm.pvm.internal.wire.WireDefinition;
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/binding/VersionTimestampPolicy.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/binding/VersionTimestampPolicy.java 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/binding/VersionTimestampPolicy.java 2009-05-06 14:03:44 UTC (rev 4749)
@@ -22,18 +22,10 @@
package org.jbpm.pvm.internal.wire.binding;
import java.io.Serializable;
-import java.util.List;
-import org.jbpm.api.ProcessDefinition;
-import org.jbpm.api.ProcessDefinitionQuery;
-import org.jbpm.api.ProcessService;
-import org.jbpm.api.client.ClientProcessDefinition;
import org.jbpm.api.env.Environment;
import org.jbpm.internal.log.Log;
import org.jbpm.pvm.internal.repository.DeploymentImpl;
-import org.jbpm.pvm.internal.util.XmlUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
/**
* @author Heiko.Braun <heiko.braun at jboss.com>
Modified: jbpm4/trunk/modules/pvm/src/main/resources/jbpm.default.cfg.xml
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/resources/jbpm.default.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/pvm/src/main/resources/jbpm.default.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<process-engine-context>
Modified: jbpm4/trunk/modules/pvm/src/main/resources/jbpm.identity.cfg.xml
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/resources/jbpm.identity.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/pvm/src/main/resources/jbpm.identity.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<transaction-context>
<identity-session />
Modified: jbpm4/trunk/modules/pvm/src/main/resources/jbpm.jbossremote.cfg.xml
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/resources/jbpm.jbossremote.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/pvm/src/main/resources/jbpm.jbossremote.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<process-engine-context>
Modified: jbpm4/trunk/modules/pvm/src/main/resources/jbpm.jobexecutor.cfg.xml
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/resources/jbpm.jobexecutor.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/pvm/src/main/resources/jbpm.jobexecutor.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<process-engine-context>
Modified: jbpm4/trunk/modules/pvm/src/main/resources/jbpm.tx.hibernate.cfg.xml
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/resources/jbpm.tx.hibernate.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/pvm/src/main/resources/jbpm.tx.hibernate.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<process-engine-context>
<command-service>
Modified: jbpm4/trunk/modules/pvm/src/main/resources/jbpm.tx.jta.cfg.xml
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/resources/jbpm.tx.jta.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/pvm/src/main/resources/jbpm.tx.jta.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<process-engine-context>
<command-service>
Modified: jbpm4/trunk/modules/pvm/src/test/resources/jbpm.cfg.xml
===================================================================
--- jbpm4/trunk/modules/pvm/src/test/resources/jbpm.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/pvm/src/test/resources/jbpm.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<import resource="jbpm.default.cfg.xml" />
<import resource="jbpm.tx.hibernate.cfg.xml" />
Modified: jbpm4/trunk/modules/pvm/src/test/resources/org/jbpm/pvm/api/db/svc/environment.cfg.xml
===================================================================
--- jbpm4/trunk/modules/pvm/src/test/resources/org/jbpm/pvm/api/db/svc/environment.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/pvm/src/test/resources/org/jbpm/pvm/api/db/svc/environment.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<process-engine-context>
Modified: jbpm4/trunk/modules/pvm/src/test/resources/org/jbpm/pvm/api/timer/environment.cfg.xml
===================================================================
--- jbpm4/trunk/modules/pvm/src/test/resources/org/jbpm/pvm/api/timer/environment.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/pvm/src/test/resources/org/jbpm/pvm/api/timer/environment.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<process-engine-context>
Modified: jbpm4/trunk/modules/test-db/src/test/resources/jbpm.cfg.xml
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/resources/jbpm.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/test-db/src/test/resources/jbpm.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<import resource="jbpm.default.cfg.xml" />
<import resource="jbpm.tx.hibernate.cfg.xml" />
Modified: jbpm4/trunk/modules/test-load/src/test/resources/jbpm.cfg.xml
===================================================================
--- jbpm4/trunk/modules/test-load/src/test/resources/jbpm.cfg.xml 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/modules/test-load/src/test/resources/jbpm.cfg.xml 2009-05-06 14:03:44 UTC (rev 4749)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">
+<jbpm-configuration>
<import resource="jbpm.default.cfg.xml" />
<import resource="jbpm.tx.hibernate.cfg.xml" />
Modified: jbpm4/trunk/qa/hudson-jbpm4-jboss.sh
===================================================================
--- jbpm4/trunk/qa/hudson-jbpm4-jboss.sh 2009-05-06 12:55:13 UTC (rev 4748)
+++ jbpm4/trunk/qa/hudson-jbpm4-jboss.sh 2009-05-06 14:03:44 UTC (rev 4749)
@@ -2,6 +2,7 @@
#
# runs the jboss integration test suite
+MAVEN_OPTS="-Xms1024M -Xmx1024M"
ANT_PROPERTIES="-Ddatabase=$DATABASE -Djboss.version=$JBOSS_VERSION -Djbpm.parent.dir=$WORKSPACE -Djboss.distro.dir=$SOURCE_REPO/jboss"
echo ANT_PROPERTIES=${ANT_PROPERTIES}
More information about the jbpm-commits
mailing list