Enterprise beans and other business services need a way to be activated asynchronously.
When a client needs to access an enterprise bean, it first looks up the bean's home object. The client requests the Enterprise JavaBeans (EJB) component's home to provide a remote reference to the required enterprise bean. The client then invokes business method calls on the remote reference to access the enterprise bean services. All these method calls, such as lookup and remote method calls, are synchronous. The client has to wait until these methods return.
Another factor to consider is the life cycle of an enterprise bean. The EJB specification permits the container to passivate an enterprise bean to secondary storage. As a result, the EJB container has no mechanism by which it can provide a process-like service to keep an enterprise bean constantly in an activated and ready state. Because the client must interact with the enterprise bean using the bean's remote interface, even if the bean is in an activated state in the container, the client still needs to obtain its remote interface via the lookup process and still interacts with the bean in a synchronous manner.
If an application needs synchronous processing for its server-side business components, then enterprise beans are an appropriate choice. Some application clients may require asynchronous processing for the server-side business objects because the clients do not need to wait or do not have the time to wait for the processing to complete. In cases where the application needs a form of asynchronous processing, enterprise beans do not offer this capability in implementations prior to the EJB 2.0 specification.
The EJB 2.0 specification provides integration by introducing message-driven bean, which is a special type of stateless session bean that offers asynchronous invocation capabilities. However, the new specification does not offer asynchronous invocation for other types of enterprise beans, such as stateful or entity beans.
In general, a business service such as a session or entity bean provides only synchronous processing and thus presents a challenge to implementing asynchronous processing.
The EJB 2.0 specification introduces a message-driven bean as a stateless session bean, but it is not possible to invoke other types of enterprise beans asynchronously.
Use a Service Activator to receive asynchronous client requests and messages. On receiving a message, the Service Activator locates and invokes the necessary business methods on the business service components to fulfill the request asynchronously.
The ServiceActivator is a JMS Listener and delegation service that requires implementing the JMS message listener-making it a JMS listener object that can listen to JMS messages. The ServiceActivator can be implemented as a standalone service. Clients act as the message generator, generating events based on their activity.
Any client that needs to asynchronously invoke a business service, such as an enterprise bean, may create and send a message to the Service Activator. The Service Activator receives the message and parses it to interpret the client request. Once the client's request is parsed or unmarshalled, the Service Activator identifies and locates the necessary business service component and invokes business methods to complete processing of the client's request asynchronously.
The Service Activator may optionally send an acknowledgement to the client after successfully completing the request processing. The Service Activator may also notify the client or other services on failure events if it fails to complete the asynchronous request processing.
The Service Activator may use the services of a Service Locator to locate a business component. See "Service Locator" on page 368.
Figure 9.9 represents the class relationships for the Service Activator pattern.
Participants and Responsibilities
Figure 9.10 shows the interactions between the various participants in the Service Activator pattern.
The client requires an asynchronous processing facility from the business objects participating in a workflow. The client can be any type of application that has the capability to create and send JMS messages. The client can also be an EJB component that needs to invoke another EJB component's business methods in an asynchronous manner. The client can use the services offered by the Service Locator pattern to look up or create EJB components, JMS services, and JMS objects, as necessary.
The Request is the message object created by the client and sent to the ServiceActivator via the MOM. According to the JMS specification, the Request is an object that implements the javax.jms.Message interface. The JMS API provides several message types, such as TextMessage, ObjectMessage, and so forth, that can be used as request objects.
The ServiceActivator is the main class of the pattern. It implements the javax.jms.MessageListener interface, which is defined by the JMS specification. The ServiceActivator implements an onMessage() method that is invoked when a new message arrives. The ServiceActivator parses (unmarshals) the message (request) to determine what needs to be done. The ServiceActivator may use the services offered by a Service Locator (see Service Locator) pattern to look up or create Business Service components such as enterprise beans.
BusinessObject is the target object to which the client needs access in an asynchronous mode. The business object is a role fulfilled by either a session or entity bean. It is also possible that the BusinessObject is an external service instead of an entity bean.
Entity Bean Strategy
Both session and entity beans can fulfill the role of a BusinessObject. When J2EE applications implement a Session Fašade pattern to provide coarse-grained access to entity beans and to encapsulate the workflow, then the session bean from the Session Fašade fulfills the BusinessObject role.
In simple applications with minimal workflow, an entity bean may fulfill the BusinessObject role. However, for complex workflow involving multiple entity beans and other business objects, the ServiceActivator typically interacts with a Session Facade which encapsulates such workflow.
Session Bean Strategy
When a session bean fulfills the role of the BusinessObject, the business requirements determine whether the bean should be stateful or stateless. Since the client for the BusinessObject is a ServiceActivator that activates the BusinessObject on receiving a new message, the workflow to process the message can define whether the bean should be stateful or not. In most cases, a message delivery simply activates a single method in the BusinessObject that delegates the processing of the message within. A stateless session bean can be used in these cases. If the ServiceActivator needs to invoke multiple methods in the BusinessObject or to work with more than one BusinessObject to fulfill the processing requirements for a message, it may be useful to consider a stateful session bean to retain state between multiple invocations. See "Stateless Session Facade Strategy" on page 296 and "Stateful Session Facade Strategy" on page 297.
ServiceActivator Server Strategy
The most straightforward strategy for implementing the listener or ServiceActivator is as a standalone JMS application that listens and processes JMS messages.
An alternative is to implement the ServiceActivator as a service of the application server. This may make it easier to manage the ServiceActivator, because it uses the application server features to monitor the ServiceActivator state and to start, restart, and stop the ServiceActivator as needed, either manually or automatically.
Enterprise Bean as Client Strategy
The Client can be any client, including another enterprise bean that requires asynchronous processing from the enterprise bean. When integrating legacy applications to the J2EE platform, it is logical to choose Java application clients to act as the message generators based on the activity in the legacy system. The ServiceActivator can receive messages and perform the necessary enterprise bean invocations to process the request from the legacy system.
Consider an order processing application where the customers shop online and the order fulfillment process happens in the background. In some cases, order fulfillment may be outsourced to a third-party warehouse. In such cases, the online store needs to invoke these fulfillment services asynchronously. This is an example that demonstrates usage of point-to-point (PTP) messaging to accomplish asynchronous processing. However, using publish/subscribe messaging would be similar, except that Topic is used instead of a Queue. Choosing which method to use, PTP or publish/subscribe, depends on the business and application requirements, and hence is outside the scope of this pattern.
The class diagram with only the relevant methods for this example is shown in Figure 9.11.
The code excerpt shown in Example 9.7 demonstrates a sample Service Activator implementation. This is the class that can be instantiated in an application server or run in a stand-alone server, as explained in the Service Activator Server strategy.
Example 9.7 Order Service Activator
The sample session facade code responsible to dispatch orders to this asynchronous service is shown in the code excerpt in Example 9.8. The Service Activator client can be a session bean that implements the Session Fašade pattern to provide order processing services to the online store application. When the session bean's createOrder() method is called, after successfully validating and creating a new order, it invokes sendOrder() to dispatch the new order to the backend order fulfillment service.
Example 9.8 Session Facade as Client for Service Activator
The JMS code can be separated into a different class so that it can be reused by different clients. This JMS delegate class is shown as OrderSender in the Example 9.9 code listing.
Example 9.9 OrderSender: Used to Dispatch Orders to Queue