Use Spring to create a simple workflow engine

Organize your backend processing tasks into an easy-to-use Spring-based workflow

1 2 Page 2
Page 2 of 2

In the example of an airfare reduction, the workflow process seed data includes airline route information and rate decrease. With the easy-to-test airline workflow example, seeding and kicking off a single workflow process via the doActivities(Object seedData) method is simple:


BaseProcessor processor = (BaseProcessor)context.getBean("rateDropProcessor");
   processor.doActivities(createSeedData());

This excerpt is from the example test case included with this article. The rateDropProcessor bean is retrieved from the ApplicationContext. The rateDropProcessor is actually wired as an instance of SequenceProcessor to handle sequential execution. The createSeedData() method instantiates an object encapsulating all the seed data needed for the airline workflow to be initiated.

Processor options

Although the only concrete subclass of Processor included with the source code is the SequenceProcessor, many implementations of the Processor interface are conceivable. Other workflow processor subclasses could be developed to control different workflow types—for example, other workflows with varying execution paths like the Parallel Splits pattern. The SequenceProcessor is a good candidate for simple workflows because the activity order is predetermined. Although not included here, the Exclusive Choice pattern is another good candidate for implementation using a Spring-based simple workflow. Regarding Exclusive Choice, after execution of each Activity, the Processor concrete class asks the ProcessContext which Activity to execute next.

Note: For more information on the Parallel Splits, Exclusive Choice, and other workflow patterns, please see Workflow Patterns, W.M.P. van der Aalst et al.

Kicking off the workflow

Given the asynchronous nature at which a workflow process is often required to perform, it makes sense that a separate thread of execution must exist to kick off the workflow. Several options exist for kicking off the workflow asynchronously; we focus on two, actively polling a queue or using an event-driven kickoff through an ESB (enterprise service bus) such as Mule, an open source ESB (for more information on Mule, see "Event-Driven Services in SOA" (JavaWorld, January 2005)).

Figures 3 and 4 depict the two kickoff strategies. In Figure 3, active polling takes place where the first activity in a workflow is constantly checking a resource such as a datasource or a POP3 email account. If the polling activity in Figure 3 finds a task waiting to be processed, kickoff begins.

On the other hand, Figure 4 is a representation of a standard J2EE application using JMS (Java Message Service) to place an event on a queue. An event listener configured through the ESB picks up the event in Figure 4 and seeds the workflow, thus kicking off the process.

Figure 3. Kickoff via active polling
Figure 4. Event-driven kickoff through ESB

Using the sample code provided, let's examine in more detail the active polling kickoff versus the event-driven kickoff.

Active polling

Actively polling is the poor man's solution to kicking off a workflow process. The SequenceProcessor is flexible enough to make kickoff via polling work smoothly. Although not desirable, active polling shakes out as the logical choice in many situations where the time is not available for configuration and deployment of an event-driven subsystem.

Using Spring's ScheduledTimerTask, a polling scheme can be easily wired up. One drawback is an additional Activity that must be created to do the polling. This polling Activity must be designed to interrogate some entity—e.g., a database table, a pop mail account, or a Web service—and determine if new work is waiting to be attended to.

In the examples provided, the PollingTestCase class instantiates a polling-based workflow processor. Using a processor with active polling differs from an event-driven kickoff in that Spring favors the no-argument version of the doActivities() method. Conversely, in the case of an event-driven kickoff, the entity kicking off the processor provides seed data through the doActivities(Object seedData) method. Another polling drawback: resources are unnecessarily exercised repeatedly. Depending on the application environment, this resource drain may not be acceptable.

The following code example demonstrates an activity that uses active polling to control the workflow kickoff:

 
   public class PollForWork implements Activity 
	  { 
	public ProcessContext execute(ProcessContext context) throws Exception 
	   { 

//First check if work needs to be done boolean workIsReady = lookIntoDatabaseForWork(); 

   if (workIsReady) 
      { 
//The Polling Action must also load any seed data ((MyContext) 

   context).setSeedData(createSeedData());
  } 

else 

  { 

//Nothing to do, terminate the workflow process for this iteration 

((MyContext) context).setStopEntireProcess(true); } return context; 
	
  } 
	
} 

Additionally, the PollRates class, included with the unit tests in the sample code, provides a working example of active polling kickoff. PollRates simulates the repetitive check for falling airline rates.

Event-driven kickoff via ESB

Ideally, a thread containing the proper seed data would be available to kick off the workflow asynchronously. An example of this is a message received from a Java Message Service queue. A client listening on a JMS queue or topic would receive notification that processing should start in the onMessage() method. Then, the workflow processor bean would be acquired using Spring and the doActivities(Object seedData) method.

Using an ESB, the actual mechanism used to send a kickoff event can be eloquently decoupled from the workflow processor. The open source Mule ESB has the benefit of being tightly integrated with Spring. Any transport mechanism such as JMS, the JVM, or a POP3 mailbox could initiate event propagation.

Running continuously

Backend processes such as a workflow engine should be able to run continuously without intervention. Several options exist for running the Spring-based workflow standalone. A simple Java class with a main() method would suffice as demonstrated in the unit tests accompanying this article. A more reliable mechanism for deploying is to embed the workflow in some form of J2EE component. Spring has well supported integration with the J2EE-compliant webapp archive or war file. Deployment could also be achieved using a more proprietary deployable component such as the Java Management Extensions (JMX)-based service archive or sar file supported by the JBoss Application Server (for more information, see the JBoss homepage). As of JBoss 4.0, the sar file has been replaced by a format known as the deployer.

Example code

The example code, bundled in zip format, is best utilized with Apache Maven. The API can be found under the main source directory src/java. Three unit tests exist in the src/test directory, including SimpleSequenceTestCase, RateDropTestCase, and PoolingTestCase. To run all the tests, type maven test in a command shell and Maven will download all the necessary jar files before compiling and running. Actual XSL transformations will take place for two of the tests with results piped to the console. After successful execution of the test suite, you may wish to run the tests individually and watch output in real time. Try typing maven test:ui to pull up the graphical test runner, then select the test you want to run and watch the output in the console.

Summary

In this article, you have seen the categorization of workflow processes through design patterns, of which we focused on the Sequence pattern. Using interfaces, basic workflow components were modeled. By wiring up various interface implementations into Spring, a sequence workflow engine materialized. Finally, options for kickoff and deployment were discussed.

The simple workflow technique presented here is definitely not earth shattering or revolutionary. But, using Spring for general-purpose tasks like workflow is a good demonstration of the efficiencies gained by IoC containers. Eliminating the need for glue code, Spring makes adhering to object-oriented constraints less cumbersome.

I'd like to recognize Mikhail Garber, author of a nonrelated article in JavaWorld (see "Use Search Engine Technology for Object Persistence"). Mikhail was a key contributor, helping with the original idea of using Spring in a simple workflow capacity.

Steve Dodge specializes in building commercial software with J2EE-based open source frameworks. His development experience spans more than seven years and has worked on development projects for various governmental and commercial entities such as The United States Postal Service, The National Oceanic and Atmospheric Administration, EDS, and Verizon Wireless.

Learn more about this topic

This story, "Use Spring to create a simple workflow engine" was originally published by JavaWorld.

Copyright © 2005 IDG Communications, Inc.

1 2 Page 2
Page 2 of 2