Axis meets MOM

Reliable Web services with Apache Axis and MOM

Over the past few years, SOAP has become the de facto standard and backbone for enabling inter-application communication. For the most part, SOAP has been successful in realizing the promise of cross-platform, cross-language integration of devices and software applications that need to communicate.

The strength of SOAP is in its simplicity, flexibility, and its universal acceptability. It lays out simple rules and an XML language of communication between devices and software that need to interact. These rules have been established by the World Wide Web Consortium and backed by industry heavyweights such as IBM, Microsoft, BEA, HP, and Sun Microsystems.

Most existing Java or Enterprise JavaBeans (EJB) applications that cater to specific business functions do not support such SOAP-specific XML consumption and generation. When undertaking standards-based integration efforts, these applications need to talk the language of SOAP and XML. Hence, for business applications that provide critical business functions, a need exists for a bridge layer that can consume and generate SOAP-specific XML. Apache Axis is the open source platform that provides the bridge layer between your applications and SOAP-based Web service interactions.

The Apache Axis Java toolkit provides a thin layer of in-direction between the client wishing to speak SOAP and the server wishing to understand SOAP. The beauty of Axis is that the same toolkit can be used at both the client and server. When used by the client, the Axis toolkit serves as an intermediary between native Java and the underlying encoding of information sent to the server in SOAP XML format. When used to enable a server as a Web service, the toolkit's role reverses and serves as an intermediary between underlying SOAP XML encoding and native Java.

Most common SOAP-based Web services implementations are over the HTTP protocol. However, in implementations that require SOAP to be enabled over a protocol more reliable than HTTP, message-oriented middleware (MOM) is an obvious choice. In addition, the features of commercially available MOM, such as guaranteed message delivery, transactional support, encryption, high performance, and high availability, make the case for combining SOAP and MOM more compelling and appealing.

Axis implementation for HTTP-based SOAP is straightforward. However, enabling Axis over MOM has not always been easy. In this article, I examine key components that come bundled in Axis and introduce additional components that are needed to let Axis work with MOM.

Please refer to resources Resources for the basics on SOAP and Axis.

Benefits of MOM

MOM-based Web services are not suitable for all types of applications. Ideally, they are suited for interaction between applications within an organization or between organizations that require SOA (service-oriented architecture) implementations with service-based consumer and provider paradigms. For such implementations, a MOM-based architecture offers the following benefits:

  • For applications that do not require immediate response from the service consumer and have long-running service provider operations, the service consumer and provider can run on different threads via one way calls. Such calls allow consumers to place a service call and not wait for a response back from the service provider. The second benefit is that the service provider does not need to be available at the time the call is placed by the service consumer because MOM provides a store-and-forward mechanism that stores the call message until it is picked up by the service consumer.
  • Service providers can scale horizontally by adding more servers for listening to the same MOM queues. The service consumer will remain completely agnostic of such changes at the server.
  • Applications requiring guaranteed delivery can rely on the persistent capabilities of MOM, which ensure message delivery in the event of hardware and software crashes.

Axis and asynchronous Web services architecture

In this article, we use Axis as the plumbing for SOAP Web services at both the client and the server. Thus, Axis is responsible for processing information that flows between the client and the server. Let's take an example of a stock-quote Web service to understand how Axis can be enabled over MOM. Our stock-quote Web service provides a stock price for a stock symbol. It has a single function, getStockPrice(String stockSymbol), that accepts a stock symbol string as a parameter and returns back a price string. Communication of the stock-quote Web service between the client and server is completed by Axis via MOM. Various types of MOMs, such as IBM's MQSeries or Sonic Software's SonicMQ, can be used. The only MOM requirement is that queues created in these MOMs should be accessible in an enterprise Java application server via Java Message Service (JMS). For purposes of our discussion, we assume one such MOM, and I do not go into the specifics of enabling the queue access in MOM. Your enterprise Java application server and MOM documentation serves as the best source for such information.

Let's first understand the importance of each of the components involved in enabling Axis and the MOM-based Web services application before delving into how these components interact to achieve the needed functionality.

Axis over message-oriented middleware. Click on thumbnail to view full-sized image.

As shown in the figure above, StockQuoteServiceProxy, JMSSender, JMSReceive, and the client and server Axis engine are the key components. Let's understand these components and how they interact.

Step 1: Client invokes getQuote on StockQuoteServiceProxy

Let's look at Client below:

 

... public class Client { public static void main() throws Exception { String stockSymbol = "IBM";

// Initialize proxy StockQuoteServiceProxy serviceProxy = new StockQuoteServiceProxy();

// Invoke function String stockQuote = serviceProxy.getQuote(stockSymbol); System.out.println("Price of " + stockSymbol + " is " + stockSymbol); } } ...

As illustrated in the code above, a Java client invokes getQuote(String stockSymbol) on the StockQuoteServiceProxy class. The client is completely unaware of the underlying SOAP and MOM plumbing used to enable the service.

Step 2: StockQuoteServiceProxy constructs and invokes the Call object

The StockQuoteService at the server is a Web service and thus has a WSDL (Web Services Description Language) file that defines the calls that can be made on the service. Axis provides the WSDL2Java tool that generates client-side proxies. Please see Apache Axis WSDL2Java to learn more about that tool. WSDL2Java is used to generate the initial StockQuoteServiceProxy Java class. Obviously, the generated Java will not contain code that supplies the transport class JMSTranport to the Axis engine. Thus, we add the following line to modify the generated Java file: call.setTransport(new JMSTransport());. The StockQuoteServiceProxy primarily creates and sets appropriate values on the org.apache.axis.client.Call object. The org.apache.axis.client.Call object is a JAXRPC (Java API for XML-based Remote Procedure Call) dynamic invocation interface implementation of the Call interface:

 

... import org.apache.axis.client.*; import org.apache.axis.configuration.FileProvider; ... public class StockQuoteServiceProxy { ... public String getQuote(String stockSymbol) throws Exception { try { // Initialize client Axis service Service axisService = new Service(new FileProvider("client-config.wsdd"));

// Create and construct Call object call = (Call) axisService.createCall(); call.setUseSOAPAction(true); call.setSOAPActionURI(""); call.setOperationStyle("rpc"); call.setTargetEndpointAddress(new java.net.URL("target end point"));

// Transport is set to JMSTransport, which returns name of chain that handles // the transport using MOM call.setTransport(new JMSTransport());

// getQuote() accepts one parameter of type string call.addParameter(new javax.xml.namespace.QName("", "stockSymbol"), new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"), java.lang.String.class, javax.xml.rpc.ParameterMode.IN);

// getQuote() returns a string call.setReturnType(org.apache.axis.encoding.XMLType.AXIS_STRING);

// Construct the parameter array Object[] params = new java.lang.Object[] { stockSymbol};

// Finally, invoke the function String stockQuote = (String) call.invoke(params);

// invokeOneWay can be used for fire and forget calls //call.invokeOneWay(params)

return stockQuote; } catch (Exception exception) { ... } } }

When getQuote(String stockSymbol) is invoked on StockQuoteServiceProxy, it, as shown in the code above, initializes the Axis engine with the client-config.wsdd configuration file. It is highly recommended that the path of client.wsdd is externalized. QuoteServiceProxy then constructs the Call object. Since the getQuote() function accepts one parameter and returns a string, appropriate values are set on Call using addParameter() and setReturnType(), respectively. One of the key calls made by StockQuoteServiceProxy is setTransportType(). This call sets access to the class used for enabling Axis SOAP messages over MOM. Most of the code in StockQuoteServiceProxy is auto-generated by WSDL2Java; however, it does not set the transport type, so you will need to add setTransportType(). Also, if your application needs only one-way, fire- and forget-type calls by the client, invoke() will need to be changed to invokeOneWay().

The value returned by invoke() is passed by StockQuoteServiceProxy to the client.

Step 3: The Axis client engine locates JMSSender

The Axis engine locates JMSSender via the client-config.wsdd configuration file. JMSSender implements the standard Handler interface, and thus the Axis engine calls the invoke() function. This code is internal to Axis and not discussed here. Please see Resources for more on Axis internals.

The Axis client, org.apache.axis.client.Service, is Axis's JAXRPC dynamic invocation interface implementation of the Service interface. The org.apache.axis.client.Service comes bundled with the Axis toolkit. It provides the API for the proxy to access the Axis client functionality required to invoke Web services.

The client-config.wsdd used to initialize the Axis client and JMSTranport is a simple extension of the org.apache.axis.client.Transport Axis class. JMSTransport's constructor sets the transport chain's string name. Axis uses the JMSTransport class to get the transport chain's name. It then looks up values loaded from client-config.wsdd to locate the Handler Java class that is the transport plug-in. For our example, this transport plug-in is JMSSender, which does the grunt work of communicating with MOM.

The client.wsdd file is shown below:

 

<?xml version="1.0" encoding="UTF-8"?> <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

<handler name="JMSSender" type="java:JMSSender"> </handler> <transport name="JMSTransport" pivot="JMSSender"/> </deployment>

The JMSSender is a transport plug-in for Axis. It implements the org.apache.axis.Handler Axis interface by extending the org.apache.axis.BasicHandler class that comes bundled with Axis. JMSSender contains the code for connecting to MOM queues, setting the names of MOM queues on which the server should return the response, creating the MOM message that contains the SOAP envelope, and dropping the MOM message that contains the SOAP envelope. There after, JMSSender listens to the MOM queue for the server to respond. On receiving the response MOM message back from the server, it creates the corresponding Axis org.apache.axis.Message and passes it back to the Axis client.

The JMSSender relies on the JMS API, making it independent of MOM infrastructure. Each MOM vender, such as MQSeries or SonicMQ, has its own proprietary mechanism for enabling MOM queue access via JMS. To maintain continuity of our discussion, please refer to your MOM and application server documentation to enable MOM to be accessible via JMS.

Step 4: JMSSender locates the MOM queues and places the JMS message on MOM queue

Let's look at JMSSender:

1 2 Page 1
Page 1 of 2