Skip to main content

skip to main content

developerWorks  >  SOA and Web services  >

Web services programming tips and tricks: How to create a simple JAX-RPC handler

Measure the time it takes to execute a request

developerWorks
Document options

Document options requiring JavaScript are not displayed

Sample code


Rate this page

Help us improve this content


Level: Introductory

Andre Tost, Senior Certified IT Specialist, IBM Software Group
Russell Butek, Software Engineer, IBM Software Group

04 Nov 2003

When developing a Web service, typically you would not want to put Web service-specific code in the implementation. In many cases, you would take existing code and simply add another access layer to it, namely a way to invoke it via SOAP over HTTP. This means that the service implementation knows nothing about SOAP, it knows nothing even about XML, and it certainly doesn't matter that it is invoked from a client that sits in another process, on another machine, possibly on the other side of the world! While this is a well known advantage of Web services technology (that is, the possibility to invoke it across a network or the Internet), it also creates challenges. You may want to measure the response time of the server; you may have to encrypt a message before you can send it across the network; or you may want to charge a client for using your Web service each time it is invoked. Luckily, the JAX-RPC specification provides us with a feature that can help us do these things: handlers. Below, we will describe how you can build a simple handler that measures the time it takes to execute a particular request and log the result in a file.

JAX-RPC handler basics

JAX-RPC handlers allow you to intercept a SOAP message at various times during a service invocation. Handlers can exist on both the client and the server side. If you use JAX-RPC on the client side, you can have a handler process a SOAP request message right before it goes on the network, and you can process the response message before it is returned to the client. Similarly, you can intercept an incoming SOAP request message on the server before invoking the service implementation, as well as the outgoing response.

Several handlers can be combined into what is called a "handler chain". Each handler processes the SOAP message, which is then passed on to the next handler in the chain. The exact sequence in which this happens is configurable. We'll get back to this later.

To develop a JAX-RPC handler, you simply create a class that implements the javax.xml.rpc.handler.Handler interface. It has three methods to handle SOAP requests, responses and faults, respectively.

Handler lifecycle

Handlers are defined in the JAX-RPC specification. However, the "Enterprise Web Services" (JSR109) specification describes how they are used in a J2EE environment and adds some clarification to the way handlers are managed by the application server (see Resources for more information on this specification). In this article, we will assume that your Web service runs on a J2EE application server and hence we will follow the definitions of JSR109 as well as JAX-RPC.

Handlers are shared across multiple service invocations. In other words, they can store information that is only valid for a particular client or server instance. You can compare this to the way servlets are handled. When a new instance of a handler is created, its init() method is called. That allows you to set up things that you can use for multiple invocations. Before the handler is removed, the destroy() method is called, so that you can do cleanup in there. As a rule of thumb, however, you should avoid storing any state in a handler altogether.

Handler configuration

Handlers can be configured either programmatically or, in case you are running a J2EE application server, they are configured in the Web service deployment descriptor. Handlers and handler chains are defined on a per service basis. They can be defined in both the server and client side deployment descriptors. Listing 1 shows the deployment descriptor for our sample service, showing how a handler class called handler. PerformanceHandler is registered for the HelloWorld service:


Listing 1. Web service deployment descriptor with handler
   <webservices id="WebServices_1066491732483">
      <webservice-description id="WebServiceDescription_1066491732483">
         <webservice-description-name>HelloWorldService</webservice-description-name>
         <wsdl-file>WEB-INF/wsdl/HelloWorld.wsdl</wsdl-file>
         <jaxrpc-mapping-file>WEB-INF/HelloWorld_mapping.xml</jaxrpc-mapping-file>
         <port-component id="PortComponent_1066491732483">
            <port-component-name>HelloWorld</port-component-name>
            <wsdl-port id="WSDLPort_1066491732483">
               <namespaceURI>http://pack</namespaceURI>
               <localpart>HelloWorld</localpart>
            </wsdl-port>
            <service-endpoint-interface>pack.HelloWorld</service-endpoint-interface>
            <service-impl-bean id="ServiceImplBean_1066491732483">
               <servlet-link>pack_HelloWorld</servlet-link>
            </service-impl-bean>
            <handler id="Handler_1066493401322">
               <handler-name>handler.PerformanceHandler</handler-name>
               <handler-class>handler.PerformanceHandler</handler-class>
            </handler>
         </port-component>
      </webservice-description>
   </webservices>

Multiple handlers would be defined here to form a chain as mentioned above.

Storing state

If multiple handlers that are involved in one service invocation need to share information, they can do so by adding properties to the message context as it is passed from handler to handler. This message context will be available from the request to the response. In other words, we can use it to store information on an incoming request that we can reuse when the response comes back. We will get to this in our example later.



Back to top


Example: A service performance handler

Now let's look at how you can create a handler that measures the response time of your service implementation. We will assume that you have created a HelloWorld web service, which simply returns a String message. Listing 2 shows the code for the service implementation bean (you can find an EAR file with all the sources, including a test client in the Resources section):


Listing 2. Web service implementation class
public class HelloWorld {
	
	public String helloWorld(String message) {
		return "Hello "+message;
	}
}

The handler will be configured for the server that hosts the Web service. It will be invoked on both the request and the response message, so that we can measure the elapsed time.

Initializing the handler

As mentioned earlier, each handler must implement the javax.xml.rpc.handler.Handler interface. Or, you can make your life a bit easier by simply inheriting the javac.xml.rpc.handler.GenericHandler class, which provides default implementations for all the methods. For storing performance results, we use a class called Logger, which we set up in the init() method. You can find the source for the Logger class in the Resources section. Moreover, the application server passes a javax.xml.rpc.handler.HandlerInfo object into this method, which we need to cache as well (see Listing 3):


Listing 3. Handler implementation -- init and destroy
public class PerformanceHandler extends GenericHandler {

	protected HandlerInfo info = null;
	protected Logger logger = null;

	public void init(HandlerInfo arg) {
		info = arg;
		logger = Logger.getLogger("c://temp//HelloWorldServiceLog");
	}
	
	public void destroy() {
		try {
			logger.close();
		} catch (Exception x) {}	
	}		

Note that we close the Logger object when the handler instance is destroyed.

Handling requests and responses

Each handler implements the handleRequest method, which is invoked when a request message arrives, as shown in Listing 4.


Listing 4. Handler implementation -- the handleRequest method
	public boolean handleRequest(MessageContext context) {
		try {
			Date startTime = new Date();
			context.setProperty("startTime", startTime);
		} catch (Exception x) {
			// insert error handling here
			x.printStackTrace();
		}
		return true;
	}

Here you can see that we store the current time in the message context as a property called "startTime". The application server will guarantee that the same message context object is passed into the handleResponse method, so that we can measure the elapsed time there, as shown in Listing 5.


Listing 5. Handler implementation -- the handleResponse method
	public boolean handleResponse(MessageContext context) {
		try {
			Date startTime = (Date)context.getProperty("startTime");
			Date endTime = new Date();
			long elapsedTime = endTime.getTime()-startTime.getTime();
			logger.write("Elapsed time is "+elapsedTime+"\n");
		} catch (Exception x) {
			// insert error handling here
			x.printStackTrace();
		}
		return true;
	}

Now you can deploy your service. Make sure you have configured the handler as shown in the deployment descriptor above, and you can measure how long it takes to execute a service request.



Back to top


Summary

JAX-RPC defines a mechanism with which you can manage service invocations by intercepting request and response messages without having to change the actual service consumer or provider. In J2EE, you can configure handlers in a deployment descriptor, without writing any code, providing you with a powerful way of controlling SOAP messages as they pass through your system.




Back to top


Download

NameSizeDownload method
ws-tipjax2SOAPHandler.earHTTP
Information about download methods


Resources



About the authors

Andre Tost works as a Solution Architect in the WebSphere Business Development group, where he helps IBM's Strategic Alliance partners integrate their applications with WebSphere. His special focus is on Web services technology throughout the WebSphere product family. Before his current assignment, he spent ten years in various development and architecture roles in IBM software development, most recently for the WebSphere Business Components product. Originally from Germany, he now lives and works in Rochester, Minnesota. In his spare time, he likes to spend time with his family and play and watch soccer whenever possible. You can contact Andre at atost at us.ibm.com.


Russell Butek is one of the developers of IBM's WebSphere Web services engine. He is also IBM's representative on the JAX-RPC Java Specification Request (JSR) expert group. He was involved in the implementation of Apache's AXIS SOAP engine, driving AXIS 1.0 to comply with JAX-RPC 1.0. Previously, he was a developer of IBM's CORBA ORB and an IBM representative on a number of OMG task forces: the portable interceptor task force (of which he was chair), the core task force, and the interoperability task force. You can contact Russell at butek at us.ibm.com.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top