Magic with JMS, MDBs, and ActiveMQ in GeronimoUnderstand the symbiotic relationship between Geronimo and the ActiveMQ JMS engine |
Level: Intermediate Sing Li (westmakaha@yahoo.com), Author, Wrox Press 12 Jul 2005 Apache Geronimo is the workhorse open source Java™ 2 Platform, Enterprise Edition (J2EE) 1.4 server container with an open framework that's ready to host a variety of existing servers and services. ActiveMQ is a proven best-of-breed, open source Java Messaging Service (JMS) engine with a Swiss-army-knife arsenal of features and connectivity options. When you marry the two, magic happens! Sing Li takes you on a grand tour of this symbiotic relationship, providing example code to help you get started writing JMS applications and creating message-driven beans (MDBs) with Geronimo immediately. The JMS API is an integral part of the J2EE platform, enabling message-based communications between loosely coupled components. Messages can be sent and received throughout the J2EE stack between clients, Web-tier components, business-tier Enterprise JavaBeans (EJBs), and Enterprise Information System (EIS)-tier services. These messages are sent asynchronously, where the sender continues with other application logic once the message is sent, and a message broker is responsible for delivering the message on behalf of the sender. Messages can be sent and received between specific endpoints (sender and recipients), or passed anonymously between producer(s) and consumer(s) using a publish/subscribe interaction model. Within the J2EE framework, components communicating through JMS can leverage the security and transaction capabilities provided by the container. Geronimo supports this vital API by integrating an open source project called ActiveMQ. This article explores the ActiveMQ integration within Geronimo. You'll see how Geronimo benefits from the integration and how ActiveMQ's capabilities are enhanced when hosted inside Geronimo. A hands-on example, which you can download from this article, reveals how to code clients and Geronimo components that communicate through JMS. Another example shows you how to create versatile MDBs within Geronimo. ActiveMQ: a best-of-breed, open source JMS implementation ActiveMQ is a mature and feature-rich JMS server, or message broker in JMS terminology. Housed at Codehaus (see Resources), ActiveMQ supports a large variety of transports (such as TCP, SSL, UDP, multicast, intra-JVM, and NIO) and client interactions (such as push, pull, and publish/subscribe). With a sizable existing user base, the ActiveMQ server can work in a completely stand-alone state, independent of any container (J2EE or otherwise), or in conjunction with a J2EE server host, such as Geronimo. When operated within Geronimo, ActiveMQ provides support for MDBs, which are EJBs that consume JMS messages. The asynchronous nature of JMS enables MDBs to be activated on demand by the container to perform work within the J2EE server on behalf of clients. Geronimo benefits greatly from ActiveMQ's rich client support. Unlike session or entity EJBs, MDBs are not called through rigid EJB interfaces. Instead, a client can invoke MDB services by simply sending a JMS message to a destination. This significantly simplifies the coding of clients that consume EJB-based services. In fact, Geronimo inherits the ability to provide services to non-J2EE clients -- those supported by the stand-alone ActiveMQ server.
Wrapping the ActiveMQ message broker in a GBean The ActiveMQ message broker is designed to be embeddable. Geronimo takes advantage of this capability. By providing a GBean container that wraps an embedded message broker, the ActiveMQContainerGBean is created. Other components of the ActiveMQ message broker are also wrapped as GBeans, as you will see shortly. Figure 1 illustrates how the ActiveMQContainerGBean embeds the ActiveMQ message broker. Figure 1. The ActiveMQContainerGBean By wrapping the ActiveMQ message broker in a GBean, the broker's life cycle can now be managed through Geronimo. Specifically, you can deploy, start, and manage instances of ActiveMQ message brokers using Geronimo deployer and management tools. The configurable properties of the message broker are exposed as GBean properties. In Figure 1, the ActiveMQContainerGBean wraps the ActiveMQ message broker and provides life cycle management and configuration services. In addition to life cycle and configuration support, Geronimo provides the persistence support for durable messages. The current ActiveMQ server configuration uses the default Derby RDBMS instance to handle persistence. The default J2EE server assembly supplied by Geronimo has an instance of the ActiveMQ message broker integrated. This assembly starts the message broker when the server is started, typically using the command line:
To see how this instance is configured, examine the system-activemq-plan.xml deployment plan in the plan directory of the Geronimo source code distribution. You'll see how the ActiveMQContainerGBean and other related ActiveMQ components are configured. Listing 1 shows the relevant segment in this deployment plan. Listing 1. Configuring the ActiveMQContainerGBean in the system-activemq-plan.xml deployment plan
In Listing 1, the first GBean sets up the ActiveMQ message broker. The GBean has an attribute with a reference to a persistence adapter, and points to the second GBean. The second GBean wraps an instance of the ActiveMQ in-memory cache. This second GBean references ActiveMQ's persistence component for long-term persistence. The third GBean wires a JDBC datasource for the persistence, pointing to the SystemDatasource -- a Derby RDBMS instance. The last two GBeans set up the following two transports for accessing the message broker:
If you ever need to change the configuration of this instance, you can modify this system-activemq-plan.xml file and then redeploy the org/apache/geronimo/ActiveMQServer configuration.
Accessing the message broker through JCA 1.5 resource adapter An application component (such as a servlet, JSP, or EJB) utilizing JMS must access the message broker through a library that implements the JMS API. This API is provided by Geronimo. To implement this API in a way that will work with any JMS provider (such as a message broker), Geronimo supports the J2EE Connector (JCA) 1.5 specification. The JCA 1.5 specification details the contracts required between the application server (Geronimo) and the resource adapter (RA) -- a driver supplied by ActiveMQ. (See Resources for an article on JCA 1.5.) Managed application components hosted in Geronimo access the ActiveMQ message broker only through this RA. This is another major benefit that ActiveMQ brings to the table -- it has a ready-for-integration JCA 1.5-compliant RA implementation. Figure 2 shows the ActiveMQ JCA 1.5-compliant RA. Figure 2. The ActiveMQ JCA 1.5-compliant RA In Figure 2, you can see that the ActiveMQ RA interacts with Geronimo’s security and transaction system through well-defined JCA 1.5 system contracts. The ActiveMQ RA supports both outbound connections (JMS calls out to the message broker), and inbound connections (ActiveMQ-originated calls call into MDBs). For outbound connections, the message-sending application can enroll the JMS provider (ActiveMQ in this case) as a part of a distributed transaction, perhaps involving another resource manager (such as an RDBMS). For inbound connections, typically activating MDBs, the transaction is started by Geronimo. In the current JCA 1.5 specification, and in the Geronimo implementation, inbound connections do not interact with the container’s security subsystem. The WorkManager contract is part of JCA 1.5. It allows an RA to submit work to the application server for execution. This allows the server -- Geronimo -- to have control over the thread management and work distribution for a compliant RA. In the case of ActiveMQ, this feature is used to manage threads for the inbound connections. For more information on this feature, read "JCA 1.5, Part 3: Message inflow" (developerWorks, June 2005). Listing 2 shows a fragment of the system-jms-plan.xml deployment plan. This plan configures the components for an RA instance, as detailed for a deployment descriptor in the JCA 1.5 specification. In the ActiveMQ RA case, these components include an RA implementation class, an outbound connection factory, topics, and queues (administered objects). The deployment plan in Listing 2 configures the following:
If you need to modify this default configuration of the JMS RA (for example, to add another queue), you'll need to make the appropriate changes in the system-jms-plan.xml deployment plan. To make any change effective, first undeploy the org/apache/geronimo/SystemJMS configuration, and then redeploy it. For other deployment plans where you can configure instances of ActiveMQ RAs, see the sidebar Deploying ActiveMQ RAs.
A J2EE application client, supported by Geronimo's Client Application Container, can have access to the ActiveMQ message broker. Figure 3 shows some client access configurations.
Figure 3. J2EE and non-J2EE client access to message broker The top configuration in Figure 3 shows a J2EE client application accessing an RA deployed in the client scope. This RA instance is configured to access the message broker located at the server. The second configuration in Figure 3 shows another J2EE client with an RA deployed in the client scope, but accessing a message broker instance deployed also at the client. (This can be useful in disconnected operations -- notebook computers that occasionally connect to the enterprise network.) In the third configuration, a non-J2EE client's access to the ActiveMQ message broker can be direct through any configured transport. The hands-on example demonstrates how to create such a stand-alone, non-J2EE ActiveMQ application client.
Creating a JMS application: a servlet producer with native ActiveMQ consumer This first example shows how a servlet can communicate with an external non-J2EE application through JMS. The example uses the global server-scoped queue called SendReceiveQueue (see Listing 2). It consists of a JMS message sender (producer), and a JMS message receiver (consumer). The producer is a servlet, called SenderServlet, that runs inside Geronimo. The consumer is a stand-alone ActiveMQ client that does not use Geronimo for JMS support. Figure 4 shows the interactions in this example. Figure 4. SenderServlet with ActiveMQ receiver application In Figure 4, the application flow is as follows:
The Web application source code for this example is in the war_only directory of the code download (see the Download section below Resources). The client code is in the mqclient subdirectory. If you just want to try out the example, you can find the sender.war archive in the war_only/dist subdirectory. Just deploy the following application archive on your Geronimo server:
Use Access the data entry servlet through a browser using the URL http://localhost:8080/sender/sendform.cgi. Enter a text message into the field, and click Send. Notice that the ActiveMQ client receives and prints out the message immediately. View Listing 3 to see some of the code for SendServlet.java. You can find the complete source in the war_only/src directory. In Listing 3, the servlet generates the input form on an HTTP GET request and handles form submission on an HTTP POST request. The actual The Listing 4. JNDI mapping and resource reference in web.xml
In Listing 4, the <message-destination-ref> maps the name dwSendReceiveQueue to the system scoped queue through a <message-destination-link> subelement. Unfortunately, the J2EE 1.4 specification does not support a <resource-link> subelement inside a <resource-ref> element in web.xml. As a result, you must use the actual resource name for the connection factory (DefaultActiveMQConnectionFactory), or you will have to create a custom deployment plan (such as geronimo-web.xml) to map the reference. Coding the ActiveMQ message receiver client The receiver is a native ActiveMQ client; it does not use any Geronimo client support. It accesses the ActiveMQ message broker hosted in Geronimo using the TCP transport and the URL tcp://localhost:61616. Partial source code to this client, JMSReceiver, is shown in Listing 5. You can see the complete source code in the war_only/clientsrc directory. Listing 5. JMSReceiver.java -- a non-J2EE JMS messages receiver client
In Listing 5, the JMSReceiver is completely free of J2EE code. There is no need to perform JNDI lookup or destination mapping, because the ActiveMQ native library performs the equivalent actions automatically. Coding this non-J2EE message consumer is straightforward, using a mix of JMS API and ActiveMQ support library. Coding of a J2EE message consumer, with Geronimo's support, is also simple. The next example shows the construction of a useful J2EE message consumer: an MDB that adds product categories to the Really Big Pet Store example.
Creating an MDB for data update The second hands-on example shows the construction of an MDB. This example uses the same SendServlet code as in the first example, but the message consumer is now an MDB inside the same enterprise application (bundled in the same EAR). Figure 5 illustrates the operation of this example. Figure 5. Operation of the MDB example The example uses code from the article, "Geronimo! Part 2: Tame this J2EE 1.4 bronco" (developerWorks, May 2005). The article includes more information on the operation of the Really Big Pet Store. In Figure 5, the operation of the original Web application is left intact. Shoppers use a browser to access the store's JSP-based user interface. The StoreController servlet fetches the product categories information using the CategoriesBean has been modified to use a new helper class, called The MDB is called CategoriesMDB. This EJB is activated when a message is placed into the SendReceiveQueue. CategoriesMDB extracts the message content and uses it to add a product category to In a production environment, the The code for SenderServlet is almost identical to the version in the first example. See ear_ejb/src/SenderServlet.java for complete source. The code for CategoriesMDB is shown in Listing 6. You can find complete source at ejb/CategoriesMDB.java. Listing 6. CategoriesMDB -- consuming JMS messages and add category
The MDB code is simple. The highlighted lines in Listing 7 are where the work is performed. When a JMS message is received at the queue, Geronimo will:
You need to configure the MDB with the associated JMS destination (or queue) in the deployment descriptor, ejb-jar.xml. See an example of this in Listing 7. In Listing 8, the SendReceiveQueue is associated with MDB through an <activation-config> subelement in the <message-driven> element. To select the JMS RA that will be used, create a custom openejb=jar.xml similar to Listing 8. Listing 8. Custom deployment plan, openejb-jar.xml, to select JMS RA
In Listing 8, the default system-scoped RA is selected by name using the <resource-link> element. See the sidebar Parent configuration and class loading for information on the need for a geronimo-application.xml deployment plan. To try out this example, deploy the reallybigpet.ear application, located in the ear_ejb/dist directory. To access the store, point your browser to http://localhost:8080/ReallyBigPetStore/store.cgi. To access the category add form, point your browser to http://localhost:8080/ReallyBigPetStore/sendform.cgi.
ActiveMQ provides quintessential JMS service for Geronimo, while Geronimo provides ActiveMQ with JDBC-based persistence, life cycle management (through JCA 1.5 compliance), security, transaction, and work management. This symbiotic relationship allows Geronimo users to enjoy the best of both worlds: access to standardized J2EE 1.4 JMS and MDB facilities enhanced by ActiveMQ's rich transports and client support.
The author would like to sincerely thank David Jencks from the Geronimo team for his expert assistance during the review of this article.
|
联系客服