Tapestry for Nonbelievers
A new article by I. Drobiazko and R. Zubairov introduces v. 5 of the Apache Tapestry component-oriented web framework. The tutorial shows how to create a component and covers IoC in Tapestry and Ajax.
Tracking change and innovation in the enterprise software development community

Posted by Paul Brown on Sep 03, 2007 11:01 AM
Apache ODE ("Orchestation Director Engine") aims to produce an implementation of the WS-BPEL 2.0 ("Web Services Business Process Execution Language") standard suitable for embedding in a generic runtime context. ODE recently graduated from incubation to a fully-fledged top-level project and had its first release since leaving incubation. This note provides a nickel tour and teaser for ODE along with some BPEL concepts in the form of deploying and executing a simple process.
Fighter Jets and Agile Development at Lockheed Martin (Case study)
IBM software architect eKit: Grady Booch podcast, whitepapers, articles
RESTful todo list sample tutorial with Groovy & Project Zero
SpringSource Launches New Application Server without Java EE
Snapshots from SOA Governance: Artifacts, People, Processes, Repositories
The ODE philosophy on BPEL is that it is a language for describing how to implement a set of message-based communication capabilities in terms of state manipulation and messages exchanged with external services. Other than in this sentence and in the preceding paragraph, the word "business" will not appear, and there will be no talk of alignment with IT or other silliness — ODE is guilt-free (and gilt-free) technology like a web server or a database; what you do with it is up to you. No GUI, IDE, ESB, or other TLA (other than a little XML) is required. Implementing an orchestration engine is a tantalizing but daunting task, and ODE encapsulates the details of concurrency, durable continuation (also called dehydration/rehydration), reliability, and recovery. Perhaps most importantly, ODE is delivered as a component rather than a framework in the hope that it can serve as a baseline for developers looking to add orchestration functionality to their systems.
Where it's needed for clarity, I'll call out a specific version of BPEL, e.g., BPEL4WS 1.1, but otherwise, "BPEL" refers to WS-BPEL 2.0.
WS-BPEL 2.0 is part of the WS-* constellation of standards, but for better and worse, it is loosely coupled with the other standards, depending only on WSDL 1.1 and not on SOAP. (The only facet of that minimal coupling that is "worse" is that a number of other standards in domains where BPEL has useful applications, e.g., JBI and WSRF, depend on WSDL 2.0 instead of WSDL 1.1.) As such, a BPEL implementation is orthogonal and complementary to product categories like SOAP stacks, enterprise service buses, integration engines, etc. — just get WSDL parts to the engine and give the engine the infrastructure (e.g., state persistence and timer events) that it needs.
ODE realizes this minimal view through its integration layer abstraction. The ODE core uses an integration layer implementation to receive and deliver messages to external parties and to get access to resources such as threads. ODE includes integration layer implementations for Apache AXIS2 (ODE processes exposed as web services) and ServiceMix (ODE exposed as a JBI service engine), and a number of other implementations are under active development.
What is now WS-BPEL 2.0 has been almost six years in the making, four of them at OASIS. Here's a rough timeline for the standard and its forebears with links to the CoverPages for some older documents:
The four years at OASIS did BPEL quite a bit of good, with more than 300 clarifications, corrections, and enhancements thoroughly (if not sometimes too thoroughly) considered and resolved by the technical committee. The four years at OASIS also did BPEL quite a bit of good because many of the companies represented on the technical committee tried to implement or use the language. A point-by-point comparison is between BPEL4WS 1.1 and WS-BPEL 2.0 is probably only of interest to implementors, but here is a short (and non-exhaustive) list of highlights for anyone who ever tried to write a BPEL process by hand:
And the list could go on. The jury is out on just how BPEL processes are likely to get written, whether its via a higher-level notation like BPMN, a graphical notation that maps directly to BPEL, via model-driven means, directly in XML, or in some as yet unknown but closely related non-XML syntax.
Two of the more challenging aspects of implementing a BPEL engine are representing the state of an executing process and managing concurrency, and ODE uses a framework called Java Concurrent Objects ("Jacob") to address both. Jacob's approach is a practical combination of ideas from the actor model and process algebra approaches to concurrency and continuation.
Via Jacob, ODE represents the state of a BPEL process as a collection of objects (for lack of a more precise term) connected by channels for passing messages. In this context, a message is a lightweight, internal message – just a Java type – not the heavier WSDL messages that the engine sends and receives externally. When an object receives a message, it can create new channels and objects and send messages; concurrency is managed by consuming messages in a single-threaded fashion (on a per-process-instance basis).
The ODE wiki includes a tutorial on Jacob that covers both motivation and mechanics in terms of BPEL processes, and the Jacob module includes a variety of BPEL-specific and more examples, e.g., an implementation of the Sieve of Eratosthenes. Interested readers can compare the Jacob approach with the approach in Scala.
For a quick tour of ODE, let's get a simple process deployed and accessible as a web service via the AXIS2 integration layer. The tour is purposefully "low-fi" with only one tiny spritz of doodleware; nothing other than a commandline and an up-to-date JDK (5.0) is required.
Getting the example running requires the ODE WAR distribution and a relatively recent servlet container; both Tomcat and Jetty are known to work well. The Getting ODE wiki page has a link to a list of mirrors for the ODE 1.1 distribution. Here is a set of instructions for installing ODE with Jetty 6.1.5:
Or, in Unix commandline form, where "[MIRROR]" should be replaced with the suggested download mirror for ODE:
$ wget http://[MIRROR]/ode/apache-ode-war-1.1.zip
$ wget http://dist.codehaus.org/jetty/jetty-6.1.5/jetty-6.1.5.zip
$ mkdir work && cd work
$ jar xf ../apache-ode-war-1.1.zip
$ jar xf ../jetty-6.1.5.zip
$ mkdir jetty-6.1.5/webapps/ode
$ cd !$ && jar xf ../../../apache-ode-war-1.1/ode.war
As a getting-started example, consider a process that implements a collection of named counters, each with four operations available on a single port:
BPEL is inherently message-oriented, and I'm using the -> notation above to make sure that request/response isn't confused with RPC. The use of the term "operation" is inherited from WSDL, but its only meaning in a BPEL process is as metadata to use in determining which message-receiving activity (bpel:receive, bpel:pick, etc.) can accept a message.
The distinction between an instance of a process and the process itself merits a digression. In a BPEL engine, a process is a kind of prototype that defines how process instances evolve as messages are sent and received. Depending on the process definition, the BPEL engine is responsible for routing messages to specific instances based on correlation rules or creating new instances to receive messages. For the counter process, each named counter corresponds to a process instance, and the engine determines which instance (if any) should receive a message based on the name of the counter in the message.
Implementing the process in BPEL is straightforward but takes a bit of typing (just under 100 lines, nicely formatted) to produce the XML. Here are the BPEL process counter.bpel and accompanying WSDL counter.wsdl, where in the parts, operations, ports, partner links, and message properties (used to define correlations) are defined.
As discussed above, ODE only uses the abstract portion of the WSDL, i.e., binding and service definitions are ignored. The AXIS2 integration layer, however, will use the binding and service definitions to expose the process as a concrete web service addressable via SOAP and/or HTTP.
For a more condensed version, here is an outline in pseudocode:
receive init(s) and spawn an instance tagged with name = s
set counter = 0
thread 1:
while (true)
receive get(s) for s = name
reply with counter
thread 2:
while (true)
receive getAndIncrement(s) for s = name
reply with counter++
thread 3:
receive close(s) with s = name
die // instance only!
(The while(true) construct allows the get and getAndIncrement operations to be invoked arbitrarily many times.)
A few fragments of the BPEL are worth comment. First, the <bpel:import> element at the top of the process defintion tells ODE where to find the accompanying WSDL, i.e., in the same location as the BPEL:
<bpel:import importType="http://schemas.xmlsoap.org/wsdl/"
location="counter.wsdl"
namespace="http://example.com/bpel/counter" />
Next, and something's that a default first question on the ODE user mailing list, is the initialization of the counter variable:
<bpel:assign>
<bpel:copy>
<bpel:from>0</bpel:from>
<bpel:to>$counter.value</bpel:to>
</bpel:copy>
</bpel:assign>
BPEL requires that variables be initialized prior to use; the engine will generate a bpel:uninitializedVariable fault otherwise.
A graphical representation from the Eclipse BPEL editor helps illustrate the parallel structure of the process:
(The Lomboz 3.3RC1 Eclipse distribution includes integration between ODE and the Eclipse BPEL tooling.)
The ODE distribution includes a commandline wrapper for ODE's BPEL compiler, bpelc. The compiler provides a good sanity check for BPEL processes in the form of static analysis and a full set of cross-reference checks between the process and the imported WSDL and XML Schema. To be precise, the compiler turns raw BPEL XML into a normalized structure that in turn serves as the prototype for the process instances "executed" by the Jacob virtual machine. (The normalization phase takes care of creating any synthetic or implicit constructs needed at runtime, e.g., for compensation.)
For example, to compile the example counter.bpel process with counter.wsdl located in the same directory:
$ export PATH=`pwd`/work/apache-ode-1.1-war/bin:$PATH
$ bpelc ./counter.bpel
If the compiler detects an issue, it will output an error message with line number and other information. Passing a -v or -vv flag will produce more verbose output. As with many languages, not all BPEL processes that compile will run.
The compiler is also addressable programmatically, so it is possible to implement different front-ends that turn a custom language or graphical notation into either XML BPEL or the compiler's intermediate format (called the "O model") and then into the compiled form that the runtime accepts. Activity names, line numbers, and other information are preserved to allow mapping compilation errors or execution traces back to the source format.
Deploying the process in the ODE AXIS2 runtime requires one additional artifact (deploy.xml) that specifies how the BPEL process's partner links map to the ports of a concrete service:
<deploy xmlns="http://www.apache.org/ode/schemas/dd/2007/03"
xmlns:tns="http://example.com/bpel/counter">
<process name="tns:counter">
<active>true</active>
<provide partnerLink="operations">
<service name="tns:counter" port="port"/>
</provide>
</process>
</deploy>
In a separate terminal window, start up Jetty:
$ cd work/jetty-6.1.5
$ ./bin/jetty.sh run
And watch log messages roll by for a minute as it starts up; the last few messages should look something like:
INFO - GeronimoLog.info(79) | Process deployment polling started on path
/Users/prb/work/jetty-6.1.5/webapps/ode/WEB-INF/processes.
INFO - GeronimoLog.info(79) | ODE Service Engine has been started.
2007-08-30 00:59:59.761::WARN: Unknown realm: Test JAAS Realm
2007-08-30 00:59:59.830::INFO: Started SelectChannelConnector @ 0.0.0.0:8080
Create a copy of the deployment directory and move it into place:
$ mkdir /tmp/counter
$ cp counter.bpel counter.wsdl deploy.xml /tmp/counter
$ mv /tmp/counter jetty-6.1.5/webapps/ode/WEB-INF/processes
This should produce a bit of logging back in the Jetty window:
DEBUG - GeronimoLog.debug(66) | Created Axis2 service {http://example.com/bpel/counter}counter
DEBUG - GeronimoLog.debug(66) | Activated {http://example.com/bpel/counter}counter-1 myrole operations: EPR is org.apache.ode.bpel.epr.WSAEndpoint@b56444
DEBUG - GeronimoLog.debug(66) | Activated {http://example.com/bpel/counter}counter-1
DEBUG - GeronimoLog.debug(66) | Rehydrating process {http://example.com/bpel/counter}counter-1
INFO - GeronimoLog.info(79) | Activated process {http://example.com/bpel/counter}counter-1.
INFO - GeronimoLog.info(79) | Deployment of artifact counter successful: [{http://example.com/bpel/counter}counter-1]
DEBUG - GeronimoLog.debug(66) | Creating process DAO for {http://example.com/bpel/counter}counter-1 (guid=hqejbhcnphr2jtol7ojc0s)
The configuration of AXIS2 as shipped in the AXIS2 integration layer for Ode supports simple HTTP invocation of operations, so curl is all that's needed to interact with the process from the commandline. (Most *nix systems will include curl, and executables for Windows are available.) This sequence of commands creates a counter named "foo" and increments it twice:
$ curl http://localhost:8080/ode/processes/counter/init?name=foo
<axis2ns2:initResponse xmlns:axis2ns2="http://example.com/bpel/counter" />
$ curl http://localhost:8080/ode/processes/counter/get?name=foo
<axis2ns4:getResponse xmlns:axis2ns4="http://example.com/bpel/counter">
<value>0.0</value>
</axis2ns4:getResponse>
$ curl http://localhost:8080/ode/processes/counter/getAndIncrement?name=foo
<axis2ns6:getAndIncrementResponse xmlns:axis2ns6="http://example.com/bpel/counter">
<value>0.0</value>
</axis2ns6:getAndIncrementResponse>
$ curl http://localhost:8080/ode/processes/counter/getAndIncrement?name=foo
<axis2ns8:getAndIncrementResponse xmlns:axis2ns8="http://example.com/bpel/counter">
<value>1.0</value>
</axis2ns8:getAndIncrementResponse>
(This isn't RESTful in strict terms, since a GET is creating a resource, but using curl on the commandline beats cobbling together and POSTing SOAP messages!)
ODE includes instance and process management functionality addressable via the persistence layer, and in the AXIS2 integration layer, a number of the operations are exposed via web services. For example, to get a list of all deployed processes:
$ curl http://localhost:8080/ode/processes/ProcessManagement/listAllProcesses
Or, if you'd like something more legible, open it in a browser or pipe it through xmllint:
$ curl -s -o - http://localhost:8080/ode/processes/ProcessManagement/listAllProcesses | \
xmllint --format -
<ns:process-info-list xmlns:ns="http://www.apache.org/ode/pmapi/types/2006/08/02/">
<ns:process-info>
<ns:pid>{http://example.com/bpel/counter}counter-1</ns:pid>
; <ns:status>ACTIVE</ns:status>
<ns:version>1</ns:version>
[...]
And then to create and list a few instances:
$ curl -s http://localhost:8080/ode/processes/counter/init?name=bar
$ curl -s http://localhost:8080/ode/processes/counter/init?name=baz
$ curl -s http://localhost:8080/ode/processes/counter/init?name=qux
$ curl -s -o - http://localhost:8080/ode/processes/InstanceManagement/listAllInstances | \
xmllint --format -
<ns:instance-info-list xmlns:ns="http://www.apache.org/ode/pmapi/types/2006/08/02/">
<ns:instance-info>
<ns:iid>57</ns:iid>
<ns:pid>{http://example.com/bpel/counter}counter-1</ns:pid>
<ns:process-name xmlns:coun="http://example.com/bpel/counter">coun:counter</ns:process-name>
<ns:root-scope siid="58" status="ACTIVE" name="__PROCESS_SCOPE:counter" modelId="8"/>
[...]
This just scratches the surface of ODE, but it should reinforce the key takeaways of ODE's philosophical perspective on BPEL and packaging as a component.
ODE is open source, so the next step is to participate:
Paul Brown is a committer on the ODE project and entrepreneur looking at next big ideas. Paul can be reached at prb@mult.ifario.us.
The url to the article is wrong.
Thanks - fixed.
Any public list of projects using this engine in their solutions? /Dino
Dino, there's a very early list here: http://ode.apache.org/links.html However from the questions asked on our user and dev mailing lists I can tell you there's quite a few others. We just haven't asked people if we could list their projects there yet.
Hey, good article!
Hi! Nice article.
Looks like the the "close" operation is missing in bindings.
Following should be added after "init" operation.
A new article by I. Drobiazko and R. Zubairov introduces v. 5 of the Apache Tapestry component-oriented web framework. The tutorial shows how to create a component and covers IoC in Tapestry and Ajax.
In this interview, Burton Group consultant Pete Lacey talks to Stefan Tilkov about his disillusionment with SOAP, his opinion on REST, and addresses some of the perceived shortcomings REST vs. WS-*.
Jay Fields presents his concept of Business Natural Languages - a type of Domain Specific Languages geared towards being readable by domain experts.
Adoption and interest for Distributed Version Control Systems is constantly rising. We will introduce the concept of DVCS and have a look at 3 actors in the area: git, Mercurial and Bazaar.
Deborah Hartmann interviewed Segundo Velasquez about his experience as customer with an Agile team during the initial phase of software design of a product.
David Cooksey shows how to fine grained versioning to a ClickOnce deployment using an HttpHandler written with ASP.NET, making partial rollouts to a test audience much easier.
Windows workflow (WF) is an excellent framework for implementing business processes, but lacks support for human activities. This article describes a completely generic approach for changing this.
In this interview taken during OOPSLA 2007, Markus Voelter talks about the importance of documenting the software architecture, and gives some good and also bad examples on how it could be done.
6 comments
Reply