Comments
Richard Davies wrote: The UK has a good crop of technology pioneers in cloud computing - for example ElasticHosts, FlexiScale, Flexiant, OnApp - and also some strong government initiatives such as G-Cloud. We will have to see whether this kind of technical leadership converts into swift mass-market adoption or not.
Cloud Expo on Google News

SYS-CON.TV
Cloud Expo & Virtualization 2009 East
PLATINUM SPONSORS:
IBM
Smarter Business Solutions Through Dynamic Infrastructure
IBM
Smarter Insights: How the CIO Becomes a Hero Again
Microsoft
Windows Azure
GOLD SPONSORS:
Appsense
Why VDI?
CA
Maximizing the Business Value of Virtualization in Enterprise and Cloud Computing Environments
ExactTarget
Messaging in the Cloud - Email, SMS and Voice
Freedom OSS
Stairway to the Cloud
Sun
Sun's Incubation Platform: Helping Startups Serve the Enterprise
POWER PANELS:
Cloud Computing & Enterprise IT: Cost & Operational Benefits
How and Why is a Flexible IT Infrastructure the Key To the Future?
Click For 2008 West
Event Webcasts
Using the Java Messaging Service with Enterprise JavaBeans
Using the Java Messaging Service with Enterprise JavaBeans

One unfortunate aspect of the many enterprise APIs and specifications that Sun has released over the last few years has been the lack of information about how some of these APIs interact with one another. In particular, two very useful specifications ­ the Java Messaging Service (JMS) and Enterprise JavaBeans (EJB) ­ have been released and already implemented individually by many application server vendors. What wasn't considered in this process, at least at this stage, is how the two would (or should) work together. Enterprise JavaBeans is a server-side component architecture, which provides remote, distributed, secure objects with built-in transaction support. JMS is a portable messaging service architecture and API that provides for persistent, point-to-point or publish/subscribe messaging with transaction support.

Communication with, or between, EJBs is a synchronous mechanism of one client method (perhaps another EJB) invoking a method on an EJB, with a possible return value. JMS, on the other hand, has both synchronous and asynchronous capabilities for sending messages between clients. It would seem that using JMS to pass asynchronous messages (or even method invocations) between EJBs would be a useful facility. Unfortunately, Sun has yet to tie these two specifications together and there is currently no standard mechanism to use JMS with EJBs (although there seems to be the promise of Sun delivering such a spec in the not-too-distant future).

In this article I'll show you how to circumvent this problem with an adapter-style delegation model that uses some of the inherent features of the BEA/WebLogic application server and its implementation of both JMS and EJBs. This model, while making use of a somewhat proprietary feature of the application server, can easily be extended if so desired to a more independent and portable mechanism by implementing it as a stand-alone Java service.

If you want to test the example code included with this article, I would recommend that you first obtain and install the latest release of the BEA/WebLogic application server (this article is based on version 4.5.1). You can download a free 30-day trial copy from BEA at www.bea.com.

The Java Messaging Service
The JMS is a set of interfaces implemented by vendors of message-oriented middleware (MOM), application servers and database servers that wish to support messaging within their products. JMS provides a simple, common API for client applications to implement code that uses portable messaging, against potentially any given number of underlying messaging systems. (Because JMS is designed to be portable, it's important to realize that as a result, if you're familiar with any given MOM product, it isn't certain that JMS will support every aspect of that product.)

The primary concept in JMS is that of Destinations. A Destination is nothing more than an association for message producers and message consumers. Destinations break down into two types, Topics or Queues. For the purposes of this article we'll discuss only Queues, which implement point-to-point messaging. (Using a Topic to support the implementation described in this article should be a fairly easy substitution, however.) Both Queues and Topics support persistence. An incoming message will be stored in a persistent Queue until a QueueReceiver connects to it and receives the message synchronously through a receive() call, or passes it to a registered MessageListener. This latter mechanism provides an asynchronous message delivery model. JMS also provides support for transactions in a very basic form through the standard Connection/Session creation mechanisms. Alternately, JMS provides an XA implementation that is by default transacted and will participate in the context of a distributed transaction. A full description of transaction support is beyond the scope of this article. If you're unfamiliar with the JMS, I recommend my tutorial "Using the Java Messaging Service with BEA/WebLogic" published in the January 2000 issue (JDJ, Vol. 5, issue 1).

Enterprise JavaBeans
EJBs are remote distributed server-side components that have built-in support for transactions and security. An EJB is a self-contained component that runs within the confines of an EJB container. The container, and its underlying server, are typically supplied by an application server provider. It's the duty of the container to manage any EJBs running within it by taking responsibility for:

  • Managing the state of an EJB
  • Instantiating, pooling, removing and activating the EJB
  • Making callbacks to the EJB to tell it to load or store its state (with container-managed persistence, the container can even manage the loading and storing of the EJB's state)
  • Thread safety (by default EJBs are single-threaded, and mustn't create their own threads)
Because EJBs are designed with inherent support for transactions, the container also manages the coordination of the EJB with an underlying Transaction Manager (the transaction may be a distributed transaction that in turn is coordinated with various resource managers for access to one or more databases).

Transaction management is therefore fairly transparent to EJB developers, requiring them to set a couple of DeploymentDescriptor attributes to specify how the EJB will participate in the context of a transaction (or even not at all). The DeploymentDescriptor allows the EJB to set certain parameters at the time it's deployed so the application server can change aspects of how the EJB is handled by the container (such as how it's pooled, how it participates in a transaction or its security attributes) without changing the EJB's code, or having to recompile it.

EJBs also provide a security model that can control access at the method level for any specific EJB. In this way you could have an EJB with five methods, four of which were available to all users and one of which was restricted to a manager only, or an administrator ­ constituting very fine-grained security access control for an EJB.

One final aspect of EJBs is that by default they're distributed components. In this sense they're remote and are accessed in the same way RMI objects are. In fact, the various EJB interfaces (EJBHome, EJBObject) extend the java.rmi.Remote interface and methods of the EJBObject-derived remote interface throw java.rmi.RemoteException. EJBs are typically registered with JNDI (WebLogic does this through the weblogic.properties file at startup). Access to the EJB is a JNDI lookup operation for an EJB's home interface, which then acts as a type of factory for creation or location of the actual EJB itself.

One important thing to remember with EJBs is that you're always dealing with a "remote" stub class, you're never accessing the actual EJB directly (that is, you're never directly accessing the class that actually implements the functionality provided by the EJB ­ usually referred to as the "bean" class). Access to the actual functionality of the EJB is through calls to the stub class (which implements the EJB's remote interface). The stub communicates with the bean class through the container. The container controls access to the bean class and manages calls to the EJB, usually within a transaction context. It is this aspect of EJBs, though ­ their distributed, remote nature ­ that leads us to the problem of using EJBs with the JMS.

The Problem: Using JMS with EJBs
The problem in trying to use JMS with EJBs derives from the way you access an EJB to perform a method invocation on the bean. Specifically, the problem concerns the fact that an EJB doesn't behave like a standard "daemon service" or remote object in the sense that it isn't continuously up and running and waiting for access. EJBs are available during an access, but at any point after the access ­ after a specific timeout period or when the last reference to a bean is released ­ it can be passivated and put back into an available pool of beans by the container. Remember that you never have access to the bean itself, but only to a client-side stub class that implements the EJB's remote interface. A reference to the stub doesn't guarantee that the bean is active on the server or available on it. (The bean may have been passivated due to a timeout, for example, or the object pool might be at its maximum.) The key point here is that the EJB isn't guaranteed to be constantly running and available simply because your code might have a reference to the EJB's remote interface.

On the messaging side, JMS provides a mechanism to send and receive messages to and from a Destination. Let's take the example of one specific Destination type, a Queue. You create a QueueConnection and QueueSession, and from the QueueSession you ultimately create a QueueSender or QueueReceiver. The QueueSender is used to send a JMS message to a Queue. Any QueueReceiver connected to the same Queue can retrieve incoming messages on the Queue synchronously or asynchronously. For a message to be delivered asynchronously, a QueueReceiver must have a registered MessageListener to which it can pass an incoming asynchronous message. An object that wishes to be notified of asynchronous messages must then implement the MessageListener interface and its single method onMessage(). Once this object is registered with the QueueReceiver for a specific Queue, any incoming message on that Queue will be passed to the onMessage() implementation of that object as a callback from JMS.

Sending a JMS message to a Queue is a simple matter for an EJB. When a method on an EJB is invoked, the bean can simply create the appropriate JMS Queue objects, retrieve the Queue from JNDI and ultimately send a specific JMS message to the Queue. But what happens if we want our EJB to receive a JMS message? At first glance it might seem that you could simply implement the MessageListener interface in your EJB's bean class, implement the onMessage() method and register this with a QueueReceiver. But this implementation violates one of the major rules of EJBs and is therefore illegal and potentially disastrous. Why?

It all comes back to two major points discussed above: an EJB bean class should never be accessed directly, but only through its remote interface; and the Container manages the availability of an EJB.

If you implement the MessageListener in the bean class, JMS is essentially calling directly into the EJB and not through the remote interface. Thus JMS is bypassing the container and directly making an invocation on the bean class. Because the container is managing not only the EJB but also transactions (as well as thread safety), it would be a potentially catastrophic operation if JMS were suddenly to call into your bean class directly while it's in the middle of a transaction or other operation. In addition, unless the EJB bean class was actually available, it wouldn't be possible to register the bean class with the QueueReceiver until the bean was in an instantiated state. (Also, depending on how such a scenario was coded, JMS might be calling into a bean instance while it was in the container's object pool, as well as calling into activated instances that were in communication with a client.) Figure 1 illustrates this kind of illegal use.

The Solution: WebLogic Startup Classes
The way to solve this problem is to use a delegation model. In the model I'm going to present we'll implement a delegator class (a kind of adapter) for receiving and forwarding JMS messages to an EJB. We can implement this delegation class using a proprietary feature of the WebLogic application server called "startup classes." A startup class is simply a Java class that implements the weblogic.common.T3StartupDef interface from the WebLogic packages.

A startup class is registered in the weblogic.properties file and, as the name implies, will be loaded by the WebLogic server upon startup and run within the application server's VM instance. The T3StartupDef interface defines one method called startup(), which is passed a String identifier and a Hashtable that contains any parameters you wish to pass to your startup class ­ these parameters are set in the weblogic.properties file. The startup() method is the equivalent of a main() method, in a sense, and it will be called by the WebLogic server when your startup class is instantiated.

Next we need to create a special Queue (see the WebLogic documentation for details on setting up the Queue for the WebLogic application server) in the WebLogic server for our incoming JMS messages. We'll use this special Queue when sending messages intended for an EJB via the startup class delegator. In turn, the startup class is set up to listen on this same Queue for JMS messages intended for an EJB. We'll use this model for two types of EJB access. The first is a direct delegation model in which we'll pass the incoming JMS message on to an onMessage() method in our example EJB. The second is an asynchronous method invocation on an EJB via a JMS message (see Figure 2). Both forms actually use the same underlying code, as you will see.

Using the Delegation Model
Our startup class should contain code within its startup() method that initializes JMS and implements the JMS MessageListener interface and its onMessage() method. Listing 1 shows the code for our JmsQueueManager class ­ this class implements all of the functionality required to create a JMS QueueConnection, QueueSession, QueueReceiver and QueueSender. It also provides utility methods that retrieve a Queue via JNDI and shuts down the JMS connection in its finalize() method.

The important method in JmsQueueManager is initializeJMS(). This initializes JMS, creates the JMS QueueConnection, QueueSession, retrieves the Queue through JNDI and creates the QueueSession and/or QueueReceiver.

We extend this base class in our WebLogic startup class. This gives our startup class all the JMS functionality it needs to manage a JMS Connection. Our startup class also implements the JMS MessageListener interface and its onMessage() method. Once JMS is successfully initialized through the base class code, any incoming JMS messages sent to our Queue will cause an invocation of the onMessage() method in the startup class. The onMessage() method, the core of the startup class, is where the actual delegation occurs. We do the delegation through the use of Java's reflection mechanism and by parsing out method names and parameters from the contents of a JMS message. The startup class is shown in Listing 2.

Asynchronous Method Invocation with JMS
The onMessage() method of the startup class extracts predefined parameters from an incoming JMS message. In the code listing this message is assumed to be a JMS MapMessage that can contain multiple name/value pairs. A value is stored in conjunction with a String "name." You look up the value by passing the String name to an appropriate method, based on the type of the value ­ for instance, "getString(String name)" will look for a String value based on "name." It uses the values of these parameters to obtain the EJBHome class, first. This is important since we need the EJBHome to either create or locate an EJB. Then, using the Java reflection mechanism, we utilize additional JMS message parameters to determine the type of parameters for two methods; the EJBHome's create() method (this could also support an EntityBean's findByPrimaryKey() method) and then the actual method to be invoked on the remote interface.

In the code listing I've hard-coded the String "names" for the MapMessage's values for clarity (these could be turned into "final static" constants). This shows how you can use a single JMS message to package all the information needed for the delegator so it can locate the EJBHome, use reflection to create the EJB and ­ if the remote interface stub class is successfully retrieved ­ invoke a method on the stub class passing in parameters from the MapMessage. Thus the delegation startup class is making asynchronous invocations against the EJB. The code for the ReceiverStartup class in Listing 2 shows how to do this.

This mechanism uses some support methods to obtain the Class of the parameters for both a create method and an EJB's remote interface method, and to determine and set the parameter's values. Once these have been created, the method is actually invoked through reflection.

Delegating the JMS Message
An important point to note is that we use the same block of code in onMessage() to invoke a method asynchronously on an EJB and to pass on a JMS message to an EJB.

The code in Listing 3 shows how we would do this. This is a simple client class that can be used to test our delegator. It creates two separate JMS messages. The first sets its parameter to type "message." Doing this instructs the ReceiverStartup onMessage() code to look for the method name in the remote interface stub, but to pass on the JMS message to the EJB's method (this method, of course, must take a parameter that is a JMS message). In this way the ReceiverStartup class performs what appears to be a simple pass through of the message to the EJB. The second message in the client code listing sends a message with multiple parameters that invokes a simple EJB method called testMethod() that takes an integer and String as parameters. Thus we have one block of code in the ReceiverStartup class that can be used for any asynchronous EJB invocation, including passing a JMS message on to the EJB itself (although you must add additional parameters to the message so that the EJB can be located).

Some additional features that could be added to the code would be dealing with return values using the JMSReplyTo property of a JMS message (not implemented in the code listings in this article ­ I leave you to investigate this for yourself). You could specify a "return value" Queue on which you could pass back a message with a unique identifier and the returned results from the method that was invoked. Also, in the code listings I use a JMS MapMessage that requires us to add the specific name/values that we'll need to locate the EJB and invoke a method on it. This could be enhanced by wrapping or extending the base JMS message classes to add methods to handle these unique name/values, while leaving the underlying JMS message alone.

Summary
There's little doubt that EJBs and JMS are both very useful and powerful enterprise technologies when used independently. Although Sun has yet to define how these two specifications should interact, the model presented here demonstrates one solution to the current problem developers face when trying to use these technologies together. It's my hope that the ideas presented in this article demonstrate the potential for using JMS and EJBs in the enterprise. I encourage you to experiment with the concepts presented and create your own EJB and JMS solutions.

About Scott Grant
Scott Grant is chief architect and lead developer for CascadeWorks, Inc., a San Francisco-based ASP
company providing B2B solutions. A Sun-certified Java developer with 15 years of diversified engineering experience, Scott previously pioneered Java enterprise e-service solutions at another Bay Area startup company.

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1

Latest Cloud Developer Stories
Rackspace Hosting, the service leader in cloud computing, on Thursday announced its acquisition of SharePoint911, an industry leader in SharePoint consulting, training, and "JumpStart" services within SharePoint. The unification of both companies provides capabilities to deliver ...
With Cloud Expo 2012 New York (10th Cloud Expo) now under four months away, what better time to start introducing you in greater detail to the distinguished individuals in our incredible Speaker Faculty for the technical and strategy sessions at the conference... We have techn...
Nimble, the social CRM platform has announced the launch of Nimble 2.0, billed as the “most social” CRM platform on the market today. Nimble was designed entirely with social CRM in mind and is the first social business platform that empowers companies with the ability to get clo...
2011 was a year of rapid adoption for public and private cloud services. Instant and on-demand server provisioning was the driving force behind the massive growth. On top, cloud server templates and script automation simplified application installation for simple and pre-defined ...
"Having been in the IT field for many years, I believe the cloud computing chapter in the industry is an exciting one and I am proud to be a part of it," said National Reconaissance Office (NRO) Chief Information Officer Jill T. Singer Tuesday, as it was announced that she was on...
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021

SYS-CON Featured Whitepapers
ADS BY GOOGLE