For version 2.1
Copyright © 2002, 2003, 2004, 2005, 2006, 2007 Danet GmbH
All rights reserved.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Table of Contents
List of Figures
List of Tables
This document describes how to integrate and use Danet's J2EE based workflow component. The Maintenance Guide describes the internal structures and design principles of the component.
Danet's workflow component is a J2EE based implementation of a workflow facility (workflow engine) as proposed by the Workflow Management Coalition (WfMC) and the Object Management Group (OMG).
The workflow component includes and is based on a set of JAVA interfaces that define an API for a workflow management facility. These "omgcore" interfaces follow OMG's Workflow Management Facility Specification, V1.2 very closely, while making some changes to adapt the CORBA service to the established design practices for a Java API.
Danet's workflow component provides a collection of EJBs that implement the omgcore interfaces together with some additional interfaces for tasks not covered by the OMG specification. The EJBs are provided as a J2EE module that can be used in any J2EE compliant application server.
The workflow engine is designed as a J2EE component. It is intended to be integrated in an application that requires a workflow engine. As a proof of concept and test environment, we provide a demo application. The demo application consists of the workflow component and some additional modules with a portal based GUI. Combined they provide a small workflow system that may be used to get acquainted with the workflow engine. You can find more information about this demo application in Appendix C, The demo applications
This manual assumes that you are familiar with Sun's Java™ 2 Platform Enterprise Edition Specification, v1.2.
describes all steps required to integrate the workflow component in an application.
describes all defined and supported states and state transitions of processes and activities.
gives an inside view of the internal structure of Danet's workflow component.
helps managing process definitions.
lists the tools available in this workflow component. Tools are applications that can be started from an activity.
shows how to develop or integrate a resource assignment service with the help of a simple example.
lists the bugs and limitations of the workflow component currently known.
describes the java user interface of the workflow components in javadoc format.
gives an inside view of the provided demo applications.
The following conventions will be applied throughout this document:
name
to state a common name or id as it is used within the workflow component.
package
for package name.
class
for class names.
variable
to describe a name of a variable.
Table of Contents
The workflow engine is designed as a component. Therefore the typical usage is to integrate it into your application. The following sections describe the steps required to do this. If you want to get acquainted with the workflow engine by installing a demo application, please proceed to Appendix C, The demo applications. If you want to experiment with the API, step by step instructions how to build a basic sample client can be found in Section 3.3, “Sample client”. If you want to integrate the workflow component with your application or understand its structure, continue reading here.
The binary distribution comes as an installer. In the simplest
case, the installer only copies the libraries and documentation to your
filesystem. It provides, however, additional operations to configure your
application server and initialize a database. The installer is
distributed as an executable jar. It is invoked as "java -jar
wfmopen-".
n.m-installer.jar
The figures below show the installer screens for copying the components to the filesystem.
$DIST
represents the top level directory of the
binary distribution, i.e. the installation directory that you have
specified in the dialog above.
WfMOpen requires JDK 1.4.2 (see Section 1.3.6, “Additional libraries” for more details). Older JDK versions back to 1.3 may work, tests have, however, only been made with JDK 1.4.2_15 and JDK 1.6.0_02.
The workflow component requires a database that supports distributed transactions. WfMOpen relies on operations on queues and on the database being made in a single transaction. This can only be accomplished by using distributed transactions[1]. If you are looking for an OpenSource solution, we recommend using MAXDB (formerly known as SAPDB).
The workflow component relies on the presence of a number of
tables in a database. The table definitions are provided as file
$DIST/lib/wfdemo/database/. The
files contain SQL statements that can be executed by appropriate
database tools.
RDBMS-type/create.sql
If you cannot find scripts for your database, you can still use
the generic table definition in
$DIST/lib/wfdemo/database/database-schema.xml. It
is suited to be processed by the Apache DDLUtils (see Apache DDLUtils
site)[2].
As an alternative, the schema can be created by the installer. In order to do this, choose the option "(Re-)create schema" as shown below.
The installer then uses the DDLUtils to create the schema in your database. This will work for all databases that are supported by DDLUtils.
The workflow component software consists of several JAR files (modules and libraries) that have to be assembled into a J2EE application or have to be included in the classpath of a client. The figure shows an overview of the JAR files and their usage.
The specified workflow APIs (packages
de.danet.an.workflow.omgcore
and de.danet.an.workflow.api,
see Section 3.2, “Client API”) are packaged in a
separate jar de.danet.an.wfcore-apis.jar
located in the distribution directory
$DIST/lib/wfcore. Only this JAR file should
be used in the classpath when compiling clients. Consequently,
it must also be included in the runtime classpath of a client.
The runtime-classes needed by a client that wants to use the
workflow component are provided as
de.danet.an.wfcore-client.jar in
$DIST/lib/wfcore. This JAR file is not self
contained, i.e. it relies on the presence of the workflow APIs
(de.danet.an.wfcore-apis.jar), the Danet AN
utility classes (de.danet.an.util.jar, see
following section) and the additional libraries described in Section 1.3.6, “Additional libraries”. In addition, the client needs some
information about how to contact the server. See the description of the
basic WorkflowServiceFactory (in Section A.2.51, “Class WorkflowServiceFactory”), the
description of the WfMOpen specific factory implementation (in de.danet.an.workflow.ejbs.client.StandardWorkflowServiceFactory)
and the remarks in Section 1.3.4, “Workflow module” below.
All J2EE based software from the division AN uses a library with
some common utility objects and components. This library is
supplied as de.danet.an.util.jar (again
located in the $DIST/lib/wfcore). Some
components in this library (currently the logging service) need
server side support. This support is provided by the
corresponding EJB module described below.
The Danet AN utility library (package
de.danet.an.util) is a general
library used at our site. This library is packaged as two JAR
files. By default, classes are in
de.danet.an.util.jar. Some classes in the
package (sub-package
de.danet.an.util.jsf),
however, are helper classes for JSF based portlets. These
classes are are not included in
de.danet.an.util.jar. They can be found in
de.danet.an.util-jsf.jar. The reason for
separating those classes is that they may not be put in the
common classpath of a J2EE application. In order to avoid
classpath problems, you have to put these JSF utility classes
in the same directory as the JSF libraries (usually the
WEB-INF/lib directory of your
web module). Note that the classes from
de.danet.an.util.jsf are
only needed by the portlets that come with the
workflow component. The deployment of the workflow EJBs requires
de.danet.an.util.jar only.
The central (server side) workflow component is an EJB-type J2EE
module. This module is not self contained, i.e. it relies on the
presence of the workflow APIs, the Danet AN utility library and
the additional libraries listed below. The module is located in
the distribution directory $DIST/lib/wfcore
as de.danet.an.wfcore-ejbs.jar.
The manifest file of
de.danet.an.wfcore-ejbs.jar includes in its
Class-Path: statement the entries
lib/de.danet.an.wfcore-apis.jar and
lib/de.danet.an.util.jar. Thus, the
dependencies between the workflow module, the workflow APIs and
the Danet AN utility library will be resolved automatically if
de.danet.an.util.jar is put in the
lib/ directory of the enterprise archive
(the .ear-file).
The file de.danet.an.wfcore-ejbs.jar
includes vendor specific deployment descriptors for some
application servers. These deployment descriptors define,
among other things, the binding of EJBs (EJB's home
interfaces, to be precise) to global JNDI
names[3]. As the workflow engine is
intended to be integrated in different applications that may
run on one application server concurrently, the JNDI names
must be adapted to the specific application the engine is
integrated with; else there will be conflicts between the
applications. All deployment descriptors therefore use
"generic" names for JNDI bindings such as
"ejb/@@@_JNDI_Name_Prefix_@@@SomeEJB".
When packing the workflow engine EJBs, the prefix
"@@@_JNDI_Name_Prefix_@@@"
should be replaced with some reasonable value (e.g.
""@@@_JNDI_Name_Prefix_@@@ =
de.danet.wfdemo.").
Whereever the workflow module references the utility module (see Section 1.3.5, “The utility module”) in the included vendor specific deployment descriptors, it uses the same symbolic names as the deployment descriptors of the utility module (again, see Section 1.3.5, “The utility module”). These symbolic names must be adapted as well when assembling an application.
Note that "generic" names and "symbolic" names for resources appear only in vendor specific deployment descriptors. So supplying your own vendor specific deployment descriptors from scratch is an alternative integration strategy.
The workflow module includes Ant helper scripts for executing the required adaptions. See Section 1.4.1, “Preparing the modules” for details.
One global JNDI name is of specific importance. It is the name
of the
WorkflowEngineEJB. This EJB
is the only EJB looked up directly in JNDI by a workflow
engine's client (remote interfaces of other EJBs are passed to
the client directly or indirectly by methods of the
WorkflowEngineEJB). Therefore,
the global JNDI name of the
WorkflowEngineEJB's home
interface must be made known to the client. The lookup of this
home interface need not be made explicitly. Rather, it is
encapsulated in the creation of a new workflow service by the
WorkflowServiceFactory (see
newWorkflowService()).
Thus the configuration of the JNDI name becomes a
configuration issue of WfMOpen's implementation of the
WorkflowServiceFactory. WfMOpen's
implementation class and its configuration is described in
detail in de.danet.an.workflow.ejbs.client.StandardWorkflowServiceFactory.
The preferred way to do the configuration[4] is to first create a
file de.danet.an.workflow-wfs.properties
with an entry engine =
ejb/@@@_JNDI_Name_Prefix_@@@WorkflowEngine
(applying the replacement described above) and then to add
this file to the client JAR
de.danet.an.wfcore-client.jar. This
results in an "application specific" client library. Anywhere
this client JAR is used, the resource
de.danet.an.workflow-wfs.properties is
found by the
StandardWorkflowServiceFactory
in the JAR and the proper workflow engine EJB is looked up.
Another value that may need replacement is the security
domain. The JBoss vendor specific deployment descriptor
defines the security domain as
java:/jaas/wfmopen. This
should be replaced by the application's domain.
In addition to the EJBs and the libraries, the workflow module
requires three queues to be defined. By default, the JNDI
names of these queues are
"queue/@@@_JNDI_Name_Prefix_@@@ApplicationInvocations",
"queue/@@@_JNDI_Name_Prefix_@@@InternalEventQueue"
and
"topic/@@@_JNDI_Name_Prefix_@@@EventService",
with the latter being a topic queue. These names are
referenced in the vendor specific deployment descriptors of
the EJBs and must be adapted with the prefix replacement as
described above.
You can find sample definitions of the required queues for
JBoss in
$DIST/lib/wfcore/wfcore-destinations-service.xml. Depending
on your application server, you have to created these queues
before the deployment of your application using e.g. some
console application. Alternatively, you may usually trigger
the creation and configuration of the queues by adding some
vendor specific information to your enterprise archive (this
mechanism is used in the demo applications, see Appendix C, The demo applications).
The workflow module as distributed uses in its deployment descriptors a predefined security role "WfMOpenAdmin" as only role and this role has all permissions[5].
As described above, all J2EE based software from the division AN
uses some common utility objects and components. While most of
these elements can be simply supplied as a library, some
components (currently the logging support) consist of a client
and a server part. The J2EE server side elements are packaged in
the distinct EJB-type J2EE module
de.danet.an.util-ejbs.jar that is also
located in the $DIST/lib/wfcore
distribution directory. This module must be deployed along with
the workflow module.
As the utility module is intended to be used in several applications, we have deliberately not defined defaults for some information needed during deployment. Providing defaults for these values would imply the risk that different applications inadvertently access each others utility EJBs. Instead of defaults we use symbolic names in the deployment descriptors that can reliably be replaced automatically.
All symbolic names are described below. The description should be sufficient to allow you to adapt the deployment descriptors for your application. For more information about these EJBs, see the maintenance manual.
The symbolic names used are:
@@@_Utility-EJBs_UtilEJB_JNDI_Name_@@@
The utility EJB's global JNDI name. This EJB has a
global JNDI name defined because it may be needed by
stand-alone clients. A reasonable value if the utility
module is used in a workflow application would be
de.danet.an.workflow.util-lib.Util.
@@@_Utility-EJBs_KeyGenEJB_JNDI_Name_@@@
The key generator EJB's global JNDI name. The key
generator EJB has a global JNDI name defined because it
may be needed by stand-alone clients. A reasonable value
if the utility module is used in a workflow application
would be
de.danet.an.workflow.util-lib.KeyGen.
@@@_Utility-EJBs_EJBSinkEJB_JNDI_Name_@@@
The log4j EJB-appender's global JNDI name. This EJB has
a global JNDI name defined because it may be needed by
stand-alone clients. A reasonable value if the utility
module is used a workflow application would be
de.danet.an.workflow.util-lib.EJBSink.
As distributed, the utility module's descriptors do not specify any security constraints. We do, however, strongly recommend adding such constraints as appropriate for an application's security domain when assembling the application[6]. A common configuration is to introduce the same security role as used for the workflow engine EJBs (i.e. "WfMOpenAdmin", see Section 1.3.4, “Workflow module”) and allow this role to execute all methods.
The module includes support for executing the required adaptions. See Section 1.4.1, “Preparing the modules” for details.
As is usually the case with complex Java applications, the workflow component needs some third party libraries in addition to the standard JDK. Those libraries are:
The commons-logging library from the Apache Jakarta Project (for server).
The log4j library from the Apache Group (for client and server).
The jdom library (for server).
The dom4j-full library (for server). This library also supplies the jaxen libraries.
The jsr173 (a.k.a StAX) library (for server and client).
The Rhino (JavaScript) library (for server).
The XMLBeans library (for server). This library is required by Rhino for the E4X support.
The jelly core, xml-tags and jsl-tags libraries (for server).
The BeanUtils library (for server, needed by jelly).
The axis library (for server).
When you want to use WfMOpen with JDK/JRE 1.4, updated versions
of the JRE XML packages (org.w3c.dom,
org.xml.sax,
org.xml.sax.ext and
org.xml.sax.helpers) are needed. You you must
therefore use the
Endorsed Standards Override Mechanism of the JDK to
provide those newer versions, i.e. you have to set the system
property java.endorsed.dirs to the
directory
$DIST/lib/wfdemo/endorsed[7]. For the versions of the
XML libraries currently used see the CVS information in the
tools/endorsed subdirectory.
As has been described in the previous sections, the deployment
descriptors of the EJB modules must be adapted to the
application that integrates the workflow engine. In order to
facilitate this task, the EJB JARs have in their subdirectory
assembly-resources ant scripts with targets
that may be called to perform the adaption. Of course, these
scripts do not have to be used to adapt the EJBs, they are
simply provided as useful helpers.
File assembly-resources/assembly-utils.xml
provides general
purpose targets that can be used for any EJB JAR, not only for
the workflow engine or utility EJBs.
add-ejb-resource-ref
Add a resource reference to an EJB. Must be called with properties "src-ejb-jar=<the ejb jar to patch>", "target-ejb-jar=<the patch result>", "ejb-name=<the ejb that references the resource>", "ref-name=<the locigal name used by the EJB to reference the resource>", "jndi-name=<the (global) JNDI entry for the resource>", "res-auth" and "res-type" as to be put into the ejb-jar.xml. This target needs additional resources (DTDs and stylesheets) that must be provided in a directory specified with property "resource-dir=<directory>".
adapt-ejb-jar
Modify the deployment descriptors of an ejb jar by replacing given strings with other strings as specified in a properties file. Must be called with properties "src-ejb-jar=<filename of distributed ejb jar>", "target-ejb-jar=<filename of adapted ejb jar>" and "props=<filename with properties>". If the special properties "security-roles", "security-identities" and "security-domain" are defined, security information will additionally be inserted into the deployment descriptors as specified by these properties. This target needs additional resources (DTDs and stylesheets) that must be provided in a directory specified with property "resource-dir=<directory>". This target also removes the sub-directory "assembly-resources" from the ejb jar if such a sub-directory exists.
adapt-war
Modify the deployment descriptors of a war by replacing given strings with other strings as specified in a properties file. Must be called with properties "src-war=<filename of distributed war>", "dest-war=<filename of adapted war>" and "props=<filename with properties>". An optional property "libs-to-remove" may be set to a comma separated list of files to remove from WEB-INF/lib (because they will be supplied by the containing EAR).
add-env-entry-to-servlet
Modify the deployment descriptors of a war by adding an environment entry. Must be called with properties "src-war=<filename of distributed war>", "dest-war=<filename of adapted war>" and "env-entry-name=<name of environment entry>", "env-entry-type=<type of environment entry>" and "env-entry-value=<value of environment entry>". The target needs additional resources (DTDs, schemas and "assembly-utils.xml") which must be provided in a directory specified with property "resource-dir=<directory>".
File assembly-resources/assembly-helpers.xml
in the workflow engine EJB JAR uses the general purposes targets
described above and adds to them, thus providing specific targets
for the workflow engine EJBs.
adapt-wfmopen-modules
Modify the deployment descriptors of WfMOpen modules "de.danet.an.wfcore-ejbs.jar", "de.danet.an.wfcore-client.jar" and "de.danet.an.workflow.wfxml.war". Must be called with properties "src-dir=<directory with distributed modules>", "target-dir=<directory for adapted modules>" and "props=<filename with properties>". The target needs additional resources (DTDs, schemas and "assembly-utils.xml") which must be provided in a directory specified with property "resource-dir=<directory>". An optional property "libs-to-remove" may be set to a comma separated list of files to remove from WEB-INF/lib of the WARs (because they will be supplied by the containing EAR).
adapt-client-jar
This target is called by "adapt-wfmopen-modules". It configures the StandardWorkflowEngineFactory by adding a file de.danet.an.workflow-wfs.properties with an appropriate entry to the client jar. Must be called with properties "src-client-jar=<filename of distributed client jar>", "target-client-jar=<filename of adapted client jar>" and "props=<filename with properties>".
make-deployment-service
Replace strings with other strings in a deployment descriptor as specified by a properties file and wraps the result as a SAR. This target is provided because JBoss documentation does not explicitly state that you can put arbitrary deployment descriptors (e.g. for creating a data source) in an EAR. You can, however, wrap them in a SAR and put this SAR in the EAR (and have it deployed by an entry in "jboss-app.xml". This target must be called with properties "deployment-xml=<the deployment description>", "dest-file=<filename of the SAR>" and "props=<filename with properties>".
File assembly-resources/assembly-helpers.xml
in the utility EJB JAR uses the general purposes targets
described above and adds to them, thus providing specific targets
for the utility EJBs.
adapt-util-ejbs
Modify the deployment descriptors of utility ejbs by replacing given strings with other strings as specified in a properties file and adding security information retrieved from the same properties file. Must be called with properties "src-ejb-jar=<filename of distributed ejb jar>", "target-ejb-jar=<filename of adapted ejb jar>" and "props=<filename with properties>". The target needs additional resources (DTDs, schemas and "assembly-utils.xml") which must be provided in a directory specified with property "resource-dir=<directory>".
adapt-util-modules
Modify the deployment descriptors of the utility library modules. Must be called with properties "src-dir=<directory with distributed modules>", "target-dir=<directory for adapted modules>" and "props=<filename with properties>". The target needs additional resources (DTDs, schemas and "assembly-utils.xml") which must be provided in a directory specified with property "resource-dir=<directory>".
A sample properties file for use with the above ant scripts is shown below.
# # Information needed for
application assembly #
# Adapt utility EJBs' JNDI names. They have no "reasonable" defaults,
# so we have to specify very much. Note that these JNDI names are
# define separately as the utility EJBs may be shared between
# different applications. Note that "ejb/" will be prepended to the names
# specified below automatically and the entries for local home interfaces
# have "Local" appended to the name.
@@@_Utility-EJBs_UtilEJB_JNDI_Name_@@@ = \
de.danet.an.wfdemo.util-lib.Util
@@@_Utility-EJBs_KeyGenEJB_JNDI_Name_@@@ = \
de.danet.an.wfdemo.util-lib.KeyGen
@@@_Utility-EJBs_KeyGenLockEJB_JNDI_Name_@@@ = \
de.danet.an.wfdemo.util-lib.KeyGenLock
@@@_Utility-EJBs_EJBSinkEJB_JNDI_Name_@@@ = \
de.danet.an.wfdemo.util-lib.EJBSink
# Adapt utility EJB's data source reference
java\:/DefaultDS = java:/WfMOpenDS
# Adapt other EJBs' JNDI names. Most application servers require that
# you specify JNDI names although all references to the EJB are via
# links within the application. We simply define a prefix for those.
# This prefix is also used for JNDI names of other resources. Note that
# "ejb/" will be prepended to the prefix specified below when used to
# derive JNDI names for EJBs.
@@@_JNDI_Name_Prefix_@@@ = de.danet.an.wfdemo.
util-ejbs-security-domain = java:/jaas/wfdemo
util-ejbs-security-roles = \
WfMOpenAdmin: \
KeyGen*KeyGenLock*EJBSink*Util;
util-ejbs-security-identities = TimeoutHandler:WfMOpenAdmin
util-ejbs-security-principals = TimeoutHandler:WfMOpenAdmin_Principal
# Adapt workflow engine (note that the engine uses the util EJBs,
# necessary replacements are already covered by the properties above).
java\:/jaas/wfmopen = java:/jaas/wfdemo
The workflow EJBs can be deployed in the usual way defined by J2EE:
<application>
<display-name>My application using WfMOpen</display-name>
<module>
<ejb>de.danet.an.util-ejbs.jar</ejb>
</module>
<module>
<ejb>de.danet.an.wfcore-ejbs.jar</ejb>
</module>
<module>
<ejb>some.user.my.application.jar</ejb>
</module>
</application>
Make sure that you have included all libraries needed by the
workflow EJBs in the lib/
directory of your J2EE application as described in Section 1.3.4, “Workflow module”. This is a usable configuration
if you only define workflow processes without any resources
(i.e. only automatically executed activities). If resource
assignment to activities is needed, some additional services
have to be supplied as described below.
If you combine the workflow engine EJBs and servlets (packed as
WARs) in a single EAR, it is advisable to have libraries used by
both components only in the EAR (i.e. not in the WARs'
WEB-INF/lib directory. In such a
configuration, the libraries must explicitly be deployed as Java
modules in application.xml. Note that this
and other packaging aspects are not WfMOpen specific. Rather
they apply to J2EE applications in general and details are
bexond the scope of this manual. See one of the many books about
J2EE for further informations.
An issue not necessarily handled by a workflow core service is
the issue of resource assignment. The OMG specification
explicitly leaves this topic to a to-be-defined resource
assignment facility. We have therefore chosen to introduce a
simple interface to a resource assignment service in our
design. This interface is described in detail in the package
de.danet.an.workflow.spis.ras.
In order to keep this interface easily implementable by any kind of architecture, access to this service is not based on JNDI and an EJB home interface. Access rather follows the established generic pattern to create a service using a factory class. In order to use the workflow component, an implementation of this service must be provided.
The workflow component includes a sample implementation of a resource assignment service. If you want to use this implementation, some additional configuration issues arise which are discussed in Section 6.1, “The sample assignment service”.
[1] Most applications servers still support distributed transactions if one participating resource does not support distributed transactions. If your application server does, you may use a database that does not support distributed transactions. Be prepared to get some warnings from your application server, though.
[2] The provided RDBMS specific scripts were generated by processing this file with the DDLUtils for the specific RDBMSs.
[3] You should expect that only EJBs that are to be looked up by clients require binding to global JNDI names. It has turned out, however, that some application servers require explicit specification of global JNDI names for all EJBs, and others (even worse) choose default global JNDI names based on the EJB's names. Therefore, to avoid conflicts between different instances of the workflow engine on one application server, global JNDI names must be supplied in any case.
[4] The other supported methods also have some benefits; it depends on your usage scenario.
[5] Thus you have three possibilities to provide the required priviledges:
In the user management system used by your application server, make all users of the workflow engine members of the role "WfMOpenAdmin".
If your application server supports mapping between application roles and roles managed in your security domain (JBoss does not support this, e.g. Sun AS does) you can map "WfMOpenAdmin" to an existing role in your security domain, thus allowing all users in the existing role to access the workflow engine.
In all deployment descriptors, replace "WfMOpenAdmin" with the name of an exsting role in your user management system. This is typically done during deployment but may also be done during application assembly.
[6] The source distribution includes a stylesheet that, together with the appropriate invocations from ant scripts, adds security information to deployment descriptors.
[7] If
you use JBoss, you do not have to set the endorsed library
directory, because JBoss comes updated libraries in its
$JBOSS_HOME/lib/endorsed directory. This
directory is automatically set as endorsed directory in the
JBoss run-scripts.
Table of Contents
Both WfProcess and WfActivity
objects can assume the same six different states. The following table
itemizes these states and explains their meaning for processes and
activities.
Table 2.1. Meaning of execution object states
| state \ object | process | activity |
|---|---|---|
open.not_running.not_started | After creation the process is active and ready to be initialized and started. | After creation the activity is active and ready to be initialized and started when its start condition is fulfilled. |
open.running | The process is active and executing in the workflow. The process may start new activities. | The activity is executing in the workflow. The activity is invoking the implementing tools or a sub process was started and is running. |
open.not_running.suspended | The process is active and quiescent, but ready to execute. Its execution is temporarily paused, so that no further activities depending on this process may be started. | The execution of the activity is temporarily paused. If the activity is implemented as a sub process the process is also suspended. |
closed.aborted | Indicates that the enactment of the process has been aborted before normal completion. The only assumption on the state of activities depending on this process is that no activity is running. Note, however, that tools may still be running if they do not support asynchronous termination. | Indicates that the enactment of the activity has been aborted before normal completion. No assumptions on the state of sub processes and tools depending on this activity are made when it enters this state. |
closed.terminated | Indicates that enactment of the process was stopped before normal completion. It is assumed that all activities depending on this process have never been started or are completed or are terminated when it enters this state. | Indicates that enactment of the activity was stopped before normal completion. It is assumed that all sub processes and tools depending on this activity are either completed or are terminated when it enters this state. |
closed.completed | When a process has finished its task normally in the overall workflow process it enters the completed state. It is assumed that all activities associated with the process are completed or not started when it enters this state. Further, the combination of the conditions on the incoming transitions of activities that are not started must evaluate to false. | When an activity has finished its task normally it enters the completed state. It is assumed that all tools or sub processes associated with the activity are completed when it enters this state. |
During the life cycle of processes and activities their states change.
The following figure shows supported state transitions of
WfProcess and
WfActivity objects.
As can be seen in the figure, both the
WfProcess and
WfActivity objects start in state
open.not_running.not_started when they are
created and finish in one of three different closed states.
State transitions are triggered by the client API and the engine or can be an reaction to exceptions occuring when invoking tools.
The following table shows how calling a client API operation changes the state of an execution object (process or activity). The numbers used in the following tables refer to the state transitions in the above state diagram.
Note that triggering a state change will cause the workflow engine to either make the intended transition or to throw one of the exceptions declared in the API (see Section A.1.36, “Interface WfExecutionObject”, Section A.1.42, “Interface WfProcess” and Section A.1.29, “Interface WfActivity”). As a result of the transition made, however, the object's state may further be updated by the engine or other clients running in different threads. Thus querying the state of an execution object immediately after successfully triggering a state change may return a state different from the target state of the transition in the table.
Table 2.2. State transitions triggered by client API calls
| object \ method | start | suspend | resume | terminate | abort | complete |
|---|---|---|---|---|---|---|
| WfProcess | 1 | 4 | 3 | 2, 7 | 5 | n. a. |
| WfActivity | n. a. | 4 | 3 | 2, 7 | 5 | 8, 9 |
The "unobservable" (from the client's point of view) state
transitions caused by a call to complete
may seem strange at first. See the method's API documentation
(complete())
for further information about the behaviour.
Usually, state transitions of an execution object will cause further state transitions of other execution objects. There are six cases to distinguish, which are shown in the following table. The head row of the table defines the state transition of the triggering object. This transition may influence the triggered object (triggering object -> triggered object). Its potential transitions are listed in the table elements. E. g. table element (1(a)) in the second table row (WfProcess (parent) -> WfActivity) and fifth column (3) means: The state transition 3 of a parent process may cause a state transition 1 of its activities if the start condition of the activities is fulfilled.
Special attention has to be paid to state transitions of
activities with manual start and/or finish mode. These modes are
implemented by setting the activity object to state
open.not_running.suspended instead of state
open.running (manual start mode) or state
closed.completed (manual finish mode). When
resuming an activity object (transition 3) the engine will
therefore take into account why the activity was suspended and proceed
accordingly.
Table 2.3. State transitions triggered by the engine
| object \ transition | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|
| WfProcess (parent) -> WfActivity | 0 | 1(a) | 1(a) | 5, 7, 4(j) | n. a. | 7 | n. a. | n. a. | ||
| WfProcess (sub) -> WfActivity | n. a. | n. a. | n. a. | 5 | 8 | 7 | n. a. | n. a. | ||
| WfActivity -> WfProcess (parent) | n. a. | n. a. | 4 | 6(d), 7(e) | 7(c) | |||||
| WfActivity -> WfProcess (sub) | 0 & 1(k) | n. a. | 3 | 4 | 5 | n. a. | 7 | n. a. | ||
| WfProcess -> WfProcess (itself) | 5(b) | n. a. | n. a. | |||||||
| WfActivity -> WfActivity (itself) | 4(f) | 4(g), 6(h) | 5(b) | 4(g), 6(i) |
If the start conditions of the activity evaluate to true.
If the triggering transition 4
(to open.not_running.suspended) was caused
by an activity state transition 5 (to
closed.aborted). Occurs if an activity
aborts (causing everything else to abort) and the process (or an
activity of the process) is in state
open.running. Then
closed.aborted can only be reached via an
intermediate
open.not_running.suspended.
If there are no more running activities or activities with start conditions evaluating to true.
If there are no more running activities and no
activities with start conditions evaluating to true and all
closed activities have state
closed.completed.
If there are no more running activities and no
activities with start conditions evaluating to true and one or
more closed activities have a state other than
closed.completed.
If start mode is manual.
If the activity's finish mode is manual and no work remains to be done.
If activity was suspended because finish mode is manual.
If the activity's finish mode is automatic and no work remains to be done.
If the activity cannot be terminated.
If the start mode of the activity is manual, creation and start of the sub-process will be delayed until the activity has been resumed.
Besides the triggering by the client or the engine, there are three more possible causes for state transitions:
A failure to invoke a tool causes state transition 7 of the
invoking WfActivity object.
The detection of a loop causes the activities on the path to
be reset, i.e. their state changes internally from
closed... to
open.not_running.not_started (see Section 4.3.4, “Loops” for details about loops). This change of
state is not recorded as an audit event, because the
repeated execution of an activity is interpreted as several
instances of the activity being executed one after the
other. Thus the first activity instance is started, runs and
completes, then the second activity instance is started,
runs and completes. There is no observable change from
closed... to
open.not_running.not_started.
If the preliminary choice of an activity in a deferred
choice is revoked (because another activity is chosen), its
state changes from open.running to
open.not_running.not_started (see Section 4.3.5, “Deferred choice” for details about the deferred
choice). This change of state is recorded as an audit event,
as it is part of the activity's execution sequence.
Besides events triggered by a client, an activity may also receive exceptions. Exceptions are defined in the XPDL specification as a general mechanism to signal an exceptional condition to an activity. The only specifically defined exceptions are those generated by the arrival of a deadline that has been defined for an activity. WfMOpen additionally supports handling exceptions from tool invocations, see Section 3.5.4, “Exception handling” for details.
As far as state is concerned, exceptions are basically handled like the final complete call[8]. Any running tool is terminated and tools not yet invoked are skipped.
It may at first be surprising that the activity reaches
closed.completed when an exception
occurs. However, any other resulting state of an activity would
have a strange effect on the final process state, as it would
prohibit the process from reaching the completed state (see Section 2.1, “States of processes and activities”)[9]. From a
process' point of view everything is all right. A deadline may
have occurred and some special transitions may have been taken,
but the process has still performed within its specification.
Things look a bit different, though, from the perspective of a subprocess started by an activity that receives an exception. This process is forcefully terminated by its requester (the activity that has received the exception). It therefore assumes the state terminated or aborted. In contrary to the normal state transitions, this does not cause the requesting activity to assume the same state as the activity is set to state completed by the exception processing.
Under normal circumstances, the occurrence of an exception should
be derived from the transitions taken in a process. However, as a
help for automated evaluations, WfMOpen has introduced the
sub-states closed.completed.normal and
closed.completed.abandoned with the latter
being assigned to an activity that has been completed due to an
exception.
XPDL introduces deadlines, OMG knows about a "suspended" state, but neither knows about the other. This leaves the question of how the suspended state affects deadlines. We have defined the semantics as follows.
If an activity is set to state suspended, deadlines are suspended as well, i.e. no exceptions from deadlines will occur[10]. Note that "if an activity is set to state suspended" is not the same as "if an activity is in state suspended". Activities may also reach the state suspended if they have manual start or finish mode. In these cases deadlines are not suspended[11].
If the deadline has been defined as an absolute date time value (see Section 4.2.4, “Deadlines” then setting an activity in the suspended state will not prolong the deadline. If the deadline is reached while the activity is suspended, the related exception will be delivered immediately when the activity is resumed.
If the deadline has been defined as a duration then setting an activity in the suspended state will prolong the deadline, i.e. the deadline will be delayed by the accumulated time that the activity has spent in the suspended state.
Dynamic deadline conditions, i.e. conditions that depend on process relevant data, will be re-evaluated every time the activity is resumed. The advantage of this behavior is that it effectively offers you a choice. If you want your expiration date to remain, you simply use only process relevant data that does not change. The disadvantage is that in order to have invariant process relevant data, you may have to make copies of several items (or, maybe better, calculate your deadline in an independent expression and keep it in some data field).
Maybe the biggest trap in re-evaluation is that the simple
conversion of a duration to an absolute date "new
Date((new Date()).getTime() + duration)" will not
work. While this yields a date, which is not prolonged by the
suspend state, it will be re-evaluated when the activity is
resumed. Thus the deadline will probably be delayed even more than
by using the duration in the first place. There is no solution to
this other than saving the start time of the activity in a data
item (e.g. by calling the JavaScript tool as first tool of the
activity).
Workflows may be run in debugging mode. In this mode, the activities assume some additional, intermediate states. Note that the associated state transitions are neither recorded nor distributed as state change events. The debug mode has been designed to run the workflow in a way that resembles the normal execution as closely as possible. The debug mode is not a simulation. It can best be compared to running a program in a debugger, i.e. the workflow is really executed. There are, however, predefined break points and the invocation of tools may be simulated instead of actually performed.
Debugging mode is enabled for a specific process by calling
setDebugEnabled(true) on the
process after creating, but before starting the process (see
setDebugEnabled(boolean)).
Debugging can also be enabled for a process type by default using the XPDL extension mechanism as described in Section 4.2.5.2, “Extensions on Package and Process Level”.
When debug mode is enabled, the execution of activities breaks before the invocation of a tool and before completion of an activity.
Immediately before invoking a tool, the activity's state changes
to open.running.debug.invoking. To continue
the execution, the activity's state must be changed to either
open.running or to
open.running.debug.skipping. In the former
case, the tool will be invoked as in non-debugging mode. In the
latter case, tool invocation will be skipped and the activity
will either assume the state
open.running.debug.invoking again (if there
are more tools to be executed by the activity) or the state
open.running.debug.completing (if the
invocation of the last tools has been skipped, see below). Of
course, the process data must subsequently be modified manually
to reflect the changes that would have been made by the tool
invocation.
Before the activity is eventually closed, it enters one of the
states open.running.debug.terminating,
...aborting or
...completing depending on the closed-state
that the activity will assume. To continue execution and cause
the activity to assume it proper closed state, the activity's
state must be changed to open.running.
In debugging mode, exceptions thrown by tools (i.e. calls to
abandon, see abandon(java.lang.String)
will cause the activity to assume the state
open.running.debug.abandoning. To continue
the execution, it is not sufficient to provide the possibility
to change the state to open.running as
described above for the "normal" transitions to the closed
state. There may be several exceptional transitions defined, and
it must be possible to specify which exception should be used,
else it wouldn't be possible to test the different paths during
debugging.
In order to avoid polluting the interface with methods that are
only used for debugging, we have defined a special sequence of
method invocations that cause the execution to continue
(i.e. the state will change to
closed.completed.abandoned and the
execution of subsequent activities will be triggered as
specified by the transitions). You first change the state to
open.running.debug.awaiting_exception and
then call abandon (see abandon(java.lang.String))
with the name of the exception to be processed. The preceding
state change causes abandon(String) to
behave differently from normal operation, effectively continuing
execution as described above.
In order to avoid any ambiguities, we strongly recommend to execute the two operations (state change and abandoning) in a single transaction. This may be achieved by using a user transaction as described in the J2EE specification or by using the method invocation batch (see Section A.2.31, “Class MethodInvocationBatch”).
WorkflowService wfs = ...;
MethodInvocationBatch mib = new MethodInvocationBatch(true);
mib.addInvocation (activity, "changeState",
new String[] {"java.lang.String"},
new Object[] {"open.running.debug.awaiting_exception"});
mib.addInvocation (activity, "abandon",
new String[] {"java.lang.String"},
new Object[] {exception});
MethodInvocationBatch.Result mir
= (MethodInvocationBatch.Result)wfs.executeBatch(mib);
Deadlines will be be started in debugging mode just as in
non-debugging mode. However, nothing happens when deadlines are
reached. The state of deadlines may be monitored by calling
deadlines(). To
cause the process to proceed as if a synchronous deadline had
been reached, you must first call
abandon(String), which causes the activity
to assume the state
open.running.debug.abandoning, and then
continue execution as described for exceptions in general above
(see Section 2.6.3, “Effect on exceptions”). This may, of
course, be done before the deadline has been reached,
i.e. the effect of a deadline may be tested without actually
waiting for the associated time (which may be quite long) to
elapse.
In order to simulate an asynchronous deadline, the state of an
activity must first be changed to
open.running.debug.forwarding_exception. This
causes a subsequent call to abandon to
mimic the behavior of an asynchronous deadline,
i.e. transitions will be triggered as specified for the given
exception. The activity will automatically resume the state that
it had before the change to
open.running.debug.forwarding_exception. Of
course, this sequence of method calls should also be executed in
a single transaction, as described above.
[8] The impact on transitions is quite different, of course.
[9] We could have relaxed this dependency, allowing the process to reach the completed state even if an activity is terminated or aborted, provided this state was reached due to an exception. But then the state definition wouldn't be OMG compliant any more.
[10] There has been some disussion if this is the proper behaviour. The reasoning is that setting the activity in the suspend state is nothing that occurs during normal workflow execution. It is a deliberate management action. This action would become farcial if it could be circumvented by a deadline.
[11] We assume that a process designer who defines start or finish mode manual together with a deadline wants that deadline to be executed to e.g. notify the administrator.
Table of Contents
The following figure shows the overall structure of Danet's workflow component.
As can be seen in the figure, the workflow core component provides an EJB based client API. Helper classes on the client side hide most of the EJB invocation details, thus enabling the usage of the component without constantly keeping EJB details in mind.
The workflow component relies on the availability of a resource assignment service. As this service must be provided to the workflow component, it can be thought of as an additional API, or SPI to be precise, of the workflow component.
The distribution includes a sample implementation of such a resource assignment service which is described in detail in Chapter 6, The sample resource assignment service.
Finally the workflow package defines an API (SPI) used to invoke applications that perform activities.
The following sections describe each API in detail.
A standard workflow Java API has not been defined yet. Still, we did not want to provide users of our workflow component with a completely proprietary API. Therefore, we have taken a two stage approach.
As a first step, we have adapted the API specified by OMG's
Workflow Management Facility
Specification, V1.2 to the Java domain. The result
of this adaptation can be found in the package description of
de.danet.an.workflow.omgcore (see de.danet.an.workflow.omgcore or