Like Quartz, OSWorkflow is an open source project built entirely in Java and is also part of the OpenSymphony family of projects. Many workflow projects are available, both commercial and open source. OSWorkflow shares many similarities in design with Quartz, and the integration between the two frameworks makes it a no-brainer for us.
OSWorkflow operates on the principle of a finite state machine. A workflow consists of a set of states, with a start state and one or more end states. To move from one state to another, a transition needs to occur. There might be multiple transitions out of a particular statein fact, you can have multiple transitions out of a state at the same time. The transition that is chosen depends on the environment, the inputs to the state, and some conditional information that we discuss later.
No Substitution for the OSWorkflow Documentation
The material on OSWorkflow in this chapter should not replace a thorough review of the documentation that is available on the OSWorkflow site. We are primarily concerned with explaining how to use OSWorkflow with Quartz. For the examples in this chapter, we don't use very many of the available features of OSWorkflow because we are interested only in giving you an overall taste of what OSWorkflow can do. We do not have time to explore many other features, so be sure to read the documentation and tutorials available on the OSWorkflow Web site.
Workflow Descriptor File
One of the key components of OSWorkflow is the workflow descriptor, which is sometimes called the workflow definition; we use the two terms interchangeably here. The workflow descriptor defines all the aspects of a particular workflow. The descriptor is implemented as an XML file, and the framework includes a DTD for validation. Much of your time working with OSWorkflow will involve understanding the layout and rules for the descriptor file. You can view the DTD for version 2.7 at www.opensymphony.com/osworkflow/workflow_2_7.dtd.
To help the discussion, we'll create a fictitious workflow and use it throughout the remainder of this chapter. When created, this workflow will scan a directory looking for files. In the medical field, these could be electronic orders from customers or patient information.
If any files are present when we check, the workflow process reads them and stores the information in a database. The last step in the workflow generates an e-mail with a count of records that were inserted into the database. You can imagine that if we were running a worldwide business, we would expect that files could be dropped at any time of the day or night. That's why Quartz is so perfect for the scheduling portion.
We want to build a system using Quartz and OSWorkflow that will check for these files periodically and, when one or more is received, process the file(s) through a specific workflow. Figure 14.1 shows the workflow that we want to use.
Figure 14.1. An example workflow for processing electronic data files
As you can see from the workflow in Figure 14.1, several steps make up the workflow itself. It's a good idea to develop a set of generic steps that can be reused in many different workflows. Let's look at a quick series of definitions and explanations for the example workflow.
First, a workflow descriptor (definition) file has the following format:
We now go through the important parts of the workflow.
A workflow consists of a number of states or steps. Each step is given a name of your choosing. In OSWorkflow, the transition from one step to another is a result of an action. The following XML fragment illustrates a step:
Simply put, the goal of any workflow engine is to progress the workflow from the start to the finish. That means we need a way to transition the workflow from one step to another. In OSWorkflow, actions are used to determine which transition path is chosen and, therefore, which step is transitioned to. A single step in the workflow might have multiple paths (or transitions) that it can perform based on the result of the action. Several factors can be used to help determine which path the workflow takes, including external events and input from users. Workflow actions use conditions and functions to determine the action result and, therefore, which transition to take. Each action must have at least one unconditional result and might have zero or more conditional results. This helps ensure that a workflow will transition out of the step, even if none of the conditional results causes a transition. In general, an action will result in a single transition out of a step. As we discuss later, this is not entirely true because you can cause a split to occur where multiple transitions out of a step take place. Eventually, these multiple transitions must join back into a single path. The following XML fragment provides an example of a workflow action element:
Special types of actions called initial actions are used to start a workflow by specifying the first step to execute. Here's an example of an initial-actions element:
An action result tells the workflow what tasks to do next. OSWorkflow provides both conditional and unconditional results. A result can have multiple condition elements that evaluate to TRue or false. The first condition within the result element that evaluates to TRue is executed and determines the next step. Unconditional results will execute if it's the only one present or if none of the conditional ones resulted in a true value.
Three types of supported workflow result elements exist, regardless of whether they are conditional or unconditional:
You will use a combination of these to build your workflows.
In OSWorkflow, most of its power and flexibility comes from the use of functions and conditions. Functions are logic that can be performed during a transition from one step to another; they are where most of the work takes place, especially for our Quartz + OSWorkflow integration approach. OSWorkflow includes functions to call EJB methods, functions that use the Java Message Service (JMS), functions that send e-mails, and many more. The function support that we are interested in is the one that can call an ordinary Java class.
OSWorkflow includes the function interface com.opensymphony.workflow.FunctionProvider. All we need to do is create a Java class that implements the FunctionProvider interface, which contains a single method:
public void execute(java.util.Map transientVars, java.util.Map args, com.opensymphony.module.propertyset.PropertySet ps) throws WorkflowException;
After creating the FunctionProvider class, we set up the function in the workflow like this:
function type="class"> org.cavaness.quartzbook.chapter14.ReadFileFunction
When the workflow gets to the step and action with this function definition, it calls our Java class and invokes the function's execute() method. This is really powerful because you can easily integrate new and legacy systems into your workflow.
If you are building workflows with steps that you want to automatically transition without user input, you can use the auto property on an action to force the action to occur. This means that the workflow, once started, will run through its steps automatically and will not wait for an external event to cause it to transition.
Workflow GUI Designer
We don't use the GUI designer here, but it's worth noting that the OSWorkflow team has built a graphical tool to create and edit workflow definitions. The tool is a rich client that can be launched using Sun's Java Web Start technology. Figure 14.2 shows a screenshot of the GUI tool with the example workflow loaded.
Figure 14.2. The OSWorkflow Designer is a nice tool for creating and modifying workflows.
Scheduling in the Enterprise
Getting Started with Quartz
Cron Triggers and More
JobStores and Persistence
Implementing Quartz Listeners
Using Quartz Plug-Ins
Using Quartz Remotely
Using Quartz with J2EE
Quartz and Web Applications
Using Quartz with Workflow
Appendix A. Quartz Configuration Reference