Although Service-Oriented Architecture (SOA), in general, and Web services, in particular, have been envisioned to support a wide range of message exchange patterns, today?s reality is that the most productive implementations are based on request-response and one-way patterns. Simple, short-lived, request-response services like Credit Card Authorization, Calculate Tax, Get Item, Find Book, Check Stock, and so on, dominate the landscape.
There are multiple reasons for this situation. One, of course, is the fact that Web services are often implemented using unreliable, stateless transport protocols, specifically, HTTP. But, most importantly, some companies looking to conduct complex business transactions over the Web take too much of a "technology-dependent" view towards the issue, expecting Web services technologies and related vendor products to fully enable such efforts.
Standards bodies like OASIS and leading SOA vendors, such as IBM®, Microsoft®, Oracle, BEA, and many others, recognize the need for addressing a so-called "conversational" message exchange pattern that is the equivalent of real-life business transactions (or, series of operations that define a cohesive, multi-step interaction like in-order processing or insurance-quote processing) in Web service implementations. Subsequently, several Web services specifications have emerged ? WS-Addressing, WS-Resources and WS-Coordination, and WS-Transaction, for example. And, most importantly, the Business Process Execution Language (BPEL) 1.0 specification has incorporated many features of those new "WS-" standard proposals for handling complex business transactions. Nevertheless, unlike many security-related Web services standards, new standards and related vendor technologies to address Web service conversations have not been widely used. Moreover, in its current release, BPEL itself has significant shortcomings in this particular area.
Meanwhile, Web service designers are being challenged to meet the needs of more users, on more types of transport protocols (for example, HTTP, SNMP, and so on), on more types of client devices, and for all kinds of real-time interactions on the Web ? getting recommendations about best-suited products, for example, rather than just purchasing items online. Meeting such challenges will require routine attention to the design of services, perhaps even to the underpinnings of those services ? their components and object models.
One of the most effective ways of supporting complex business transactions is to use so-called activity-centered services ? services explicitly geared towards handling well-defined tasks or processes, and that do their job by maintaining the computational state of all the applications a specific activity uses.
Enter activity-centered services and active objects
Broadly speaking, activity-centered services are intended for carrying out a single activity that typically involves a number of different applications (or systems) and a lot of specific functionality and data presentation within each application. One of the main characteristics of active-centered services is that they provide execution guarantees, which are not limited to traditional ACID (atomicity, consistency, isolation, and durability) properties and might include timely constraints, state access flexibility, and multi-interaction transaction executions. Those guarantees might not only vary between applications, but also between transactions within an application, depending on properties of the transactional task, user preferences, and available system resources.
The sample scenario in Figure 1 (a travel reservation service that searches a large number of airlines to find the lowest price ticket) illustrates this. In this example, a client provides multiple sets of departure and destination information, and the service searches participating airlines for flight availability and prices. If flights are not available, then the client-service interaction must stop. Otherwise, the service provides a list of flights and prices back to the client. Then, if the client selects a particular flight from the list, the service asks the client to supply private information needed to complete the transaction, such as name, address, and credit card information. At this point, several tasks are performed. First, supplied information is verified according to security and credit card authorization rules, and the client is notified if there is a problem with the supplied information. If the private information is acceptable, the service tries to book the flight. If booking is successful, the customer itinerary record is created and its identifier is provided back to the client for future use by the traveler.
Figure 1. Sample scenario -- Finding the lowest fare
If you view the cited example from the computational level, the service is actually dealing with several distinct applications: requesting airline availability, verifying customer information, booking the flight, creating the itinerary, and so on. Thus, you can identify at least two levels of service abstraction, namely the high level of activities and the low level of application services manipulated by activities. I denote these service abstraction levels ? activity-centered (business) level and application (discrete) level, respectively. As you can see from the above example, activity-centered services introduce multiple, critical technical requirements, especially:
- Process-intensive methods invoked on a service should not block the entire process.
- Synchronized access to shared resources should allow for transparent serialization and scheduling.
- Services should be designed to leverage the parallelism (for example, in the example, there could be thousands of airline sites that need to be searched quickly).
At first, the concept of "activity-centered services" was defined within the Activity Service Framework specification submitted to OMG in response to OMG's call for specialized structuring mechanisms for Object Transaction Service (OTS). Recently, this concept is being re-introduced within the realm of Grid computing. Here, additional technical requirements were formulated, including:
- Activity-centered services should be able to respond to asynchronous events (for example, the ability to add dynamically a new party to a transaction; for instance, it might need to automatically monitor customer sessions at a Web-based storefront and proactively intervene, by enabling a customer representative to join the interaction).
- When composing activity-centered services, the composition engine must be able to receive asynchronous events and determine how and whether to impact participants in the service composition (this feature is one of the most important for BPEL engines).
- The infrastructure for activity-centered services must support communication and collaboration between services across time and space.
As a result, a generic object model for activity-centered services has emerged along these lines:
Listing 1. Activity-centered service object model
public interface Activity {
public ActivityId execute(ActivitySpecification actSpec,
ClientSpecification clientSpec,
RemoteEventListener callback)
throws RemoteException, ActivityException;
// other methods ...
|
A number of object models were proposed for implementing activity-centered services, the most interesting being the active object model. Unfortunately, several problems with this model prevent it from being widely adopted in the commercial setting. First, some are confused as to what an active object is; basically, too many different definitions of active objects are "floating" around. Second, some so-called "SOA experts" are preaching that "the active object pattern for distributed objects is way beyond the capabilities of Web services." Actually, such view is exaggerated. Sure, implementing active objects takes work, but such objects enable the building of concurrent applications, which is going to be highly applicable in the growing SOA movement. The industry has moved from tightly coupled RPC-style synchronous services, to loosely coupled asynchronous ones.
Grady Booch first introduced active objects in his 1990 book on Object Oriented Design with Applications. He defined active objects as objects having their own thread of control (or, self-powered). Since then, active objects have gained a substantial foothold in the Java™ mobile and real-time embedded development. Nevertheless, they can be equally successful for implementing conversational Web services in large-scale e-business applications. For these purposes, active objects should be specifically viewed as objects that are able, first, to concurrently run with respect to other objects running as part of a service, and, second (and most importantly), to maintain an internal state of the service during all the life cycle related to a certain client. Also, active objects are able to aggregate passive objects through composition relations.
In terms of implementations, an active object coincides with the following form:
Listing 2. Activity-centered service object class
class ActiveObject implements Runnable { private Thread activity;
public ActiveObject() {
activity = new Thread(?);
activity.start();
}
public void run() { ... }
}
|
Although structurally, there could be several active object representations, in the context of this article, the most appropriate is the model that includes the following seven components (as Figure 2 shows):
- Requester or Proxy ? provides an interface for invoking methods on an active object.
- Servant ? implements the active object corresponding to the interface of the requester and method requests the requester creates.
- Method Request ? contains the context information such as parameters, and represents a method call on the active object.
- Activation Queue ? maintains method requests pending for execution.
- Future ? stores the result of a method call on the active object.
- Scheduler ? inserts method requests into the activation queue.
- State Machine ? describes the behavior of the active object.
Figure 2. The active object model -- Class diagram
This article has gone into this in much depth, so let me reiterate some pain points you've seen thus far:
First, when dealing with active objects in SOA, the architectural paradigm is a strategy based on a concept that a service-oriented system has two distinct parts: object-oriented and service-oriented models.
The object-oriented model defines a system as a collection of sets of interacting active and passive objects. These objects comprise functions and data of the system. Then, building on the object-oriented model is the service-oriented model, in which the active objects are becoming networked objects that play a predefined role of service requesters or service providers. A service provider is an object that accepts messages from service requestors to execute an item of work ? a task or an activity.
Second, active objects are especially appealing to SOA from the long-term perspective because of the following:
- They address the large-scale partitioning and concurrency issues.
- They communicate as required to get the job done, encapsulating what to do, how to do it, and when to do it on their own schedule, and with clear "run to completion" semantics.
- They are very modular and are easy to schedule.
A practical approach for implementing active objects
Multiple approaches exist for implementing activity-centered services with active objects. Among the most straightforward and reasonably effective approaches is the one Figure 3 depicts.
Figure 3. Implementation example -- Structure
The cited approach has three distinct parts: a Service Access Layer (SAL) that processes messages, a Service Management Layer (SML) that provides dispatching and state management of services, and a Business Object Layer (BOL). Both SAL and SML implement an active object model. Business objects, implemented as EJBs, are playing the role of passive objects. Implementing passive objects as EJBs is preferred because it provides much better availability and scalability characteristics for the service.
At this time, I'll focus on specific design techniques for implementing the active object model. Unfortunately, given space limitation, I'll only cover the most important elements relevant to this article?s topic.
You can build SAL using the Apache Axis framework. Here, I am assuming that you have a basic understanding of the Axis architecture and how Axis works (see Resources for a link to the Axis Web site).
By choosing Axis, it becomes much easier to process messages and interconnect active objects using messages. Axis provides a number of important features that include handlers, chain, serializers, and deserializers. It allows for the creation of the appropriate MessageContext and passing the MessageContext into the invoke() method through the configured set of handlers, each of which can perform the necessary logic against the MessageContext.
The most important type of handler involved in implementing the active object model is the provider handler. A provider is a special Axis handler which handles incoming requests. Axis makes available a number of different providers. Which provider should be used for a given Web service can be specified upon deploying a new service. Axis' provider model is extensible, which means that you can plug in your own custom providers. Listing 3 shows a typical wsdd file used for deploying services into Axis. It shows that a custom provider will handle incoming requests:
Listing 3. Axis WSDD deployment example
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="LowestFareService" provider="java:LowestFareProvider" />
</deployment>"
|
As Figure 3 shows, the provider can be constructed to play a role of an asynchronous invocation handler that implements the Runnable interface. This interface processes various requests in the handler?s thread of control using a run() method. Also, the provider puts all the necessary information into a new EventMessage that is passed to the Manager, the entry point to SML. An EventMessage passes context information about a specific service invocation on the invocation handler such as method parameters and code, from the handler to the Manager running in a separate thread.
Event-type messages should not contain any SOAP-specific data. This will allow for a decoupling of the actual implementation of active objects from Axis and the SOAP protocol.
As Figure 3 shows, as soon as the provider receives the callback from the Manager, it creates a new SOAP response message that gets back to the Axis response flow, from where it will eventually be sent back to the client that invoked the service. The callback feature is one of the most important features of the provider. It takes the result of the onFuture() method (see the discussion of Figure 4) passed as a message and converts it to a SOAPMessage instance.
Figure 4 is a collaboration diagram that gives a rough graphical representation of the most important classes involved in SML:
- Manager- plays the role of Proxy of the active object model; using instances of EventMessage, the Manager determines service invocation requests that are placed into an Activation Queue. This queue keeps track of which service requests to execute.
- Dispatcher ? manages an Activation Queue of service requests that are pending execution; it decides which request to de-queue next and execute on a Service Delegate object that implements the request.
- Service Delegate ? encapsulates access to EJBs similar to the Business Delegate pattern introduced by Sun®?s J2EE Blueprints; defines the behavior and state that is being modeled as an active object; the Service Delegate is invoked when its corresponding service request is executed by the Dispatcher.
- Future - allows the Manager to obtain the results of service invocations after the Service Delegate finishes executing; the Future reserves space tore results from EJB invocations.
Figure 4. Implementation example -- Collaboration diagram
The Activation Queue is an event handling-type queue, which might collect events from multiple providers. The Dispatcher distributes them in first-in, first-out (FIFO) order. A vector can implement this queue, although more efficient implementations are based on using linked lists or piped streams. For putting arriving service requests into the queue, the Manager implements the pushRequest() method like:
public synchronized void pushRequest(Object eventMessage);
The pushRequest() can determine if the arriving event is intended for processing by a callback method. If so, it calls replyImmediate(), otherwise, the arriving event is pushed into the queue. Moreover, the Manager calls notify() to wake up the service delegate?s thread so that the arriving event can be processed. Then, it must wait until all futures are filled with results from the associated service delegate objects, but that happens in the background. In addition, the Manager might implement some sort of wait-loop inside like the following:
Listing 4. Wait-loop example
public synchronized Object get() {
while(futureResult==null) wait();
return futureResult;
}
|
You might be tempted to race to an opinion about this article ? perhaps thinking something along the lines of, "What you advocate here is a proprietary design instead of focusing on BPEL!" No question, using BPEL is the "easiest" implementation approach of activity-centered services. But today?s BPEL technologies are only in the beginning of the maturity cycle. They simply are not yet ready to handle some types of complex, large-scale applications like the example of the lowest airline fares service. Is the active object model a viable alternative? I strongly believe so, and the strategy based on such models presented in this article is key for connecting Web service-enabled applications within and across enterprises, with a set of features enabling management and monitoring of interactions between connected applications.
- The article Model-Driven Development of Resource-Constrained Embedded Applications (Janssen, T., Graham, W., developerWorks, December 2004) provides an overview of active object models.
- Check out the Apache Axis site.
- Lea, D., Concurrent Programming in Java: Design Principles and Patterns, Addison-Wesley, 1997, is a must-read for Java
developers interested in complex activity-centered transactions.

Mark M. Davydov, Ph.D., is an internationally-known expert in software engineering and systems architecture, including SOA. Dr. Davydov is the author of numerous highly acclaimed articles in computer-related publications. His 2001 book Corporate Portals and e-Business Integration -- A Manager's Guide, McGraw-Hill Professional Publishing, introduced many ideas that influenced the progression of Service-Oriented Architecture and the Web services model.




