Get a handle on the JAX-WS API's handler framework

Learn how to use the handler framework in your Web services projects

The handler framework in the Java API for XML Web Services (JAX-WS) allows applications to address cross-cutting and/or system-level concerns by opening the service and client runtimes for applications to plug in modular components. Reusability of these components across the services portfolio is one obvious benefit that this framework brings to service delivery. This mechanism also allows the separation of the most fundamental concerns of application software in Web services development, effectively abstracting the system service into handlers and leaving the clients and services to focus on business logic.

In this article, I describe how the JAX-WS handler framework works and demonstrate, with examples, how to work with some of its most useful features.

There are currently two JAX-WS specification versions: 2.0 and 2.1. Bundled with the Java Platform, Standard Edition 6.0 (Java SE) release is version 2.0. Since the 2.1 version does not modify the handler framework in any major way and its reference implementation is still in beta, I base our expositions in this article on version 2.0. In addition, instead of using Java SE 6.0, we develop our examples with JDK 1.5.0_09 and use the JAX-WS 2.0 reference implementation. The initial Java SE 6.0 release lacks the Web service tools (probably a bug) and, therefore, has no advantage for our purposes.

Notes about the example application

I refer to the example application frequently in this article; therefore, let me introduce it briefly up front. In the download provided in Resources, there are four simple Eclipse projects:

  • jaxws-handler: Includes most of the handlers to be used. In addition, the Ant tasks in the build file help to package these handlers into a jar file (handlers.jar) and distribute this jar for other projects' reference.
  • jaxws-handler-service: The Web service provider, simulating a credit card authorization service.
  • jaxws-handler-client1: A standard client for the credit card authorization service, developed with the help of the wsimport tool.
  • jaxws-handler-client2: A Dispatch-based client for the credit card authorization service.

Here is the WSDL (Web Services Description Language) for the Web service (CardService) in jaxws-handler-service:

<definitions xmlns:tns="http://cardservice.handler.jaxws.company.com/service" 
   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
   xmlns="http://schemas.xmlsoap.org/wsdl/" 
   xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
   xmlns:ns1="http://cardservice.handler.jaxws.company.com/creditcard" 
   xmlns:ns2="http://cardservice.handler.jaxws.company.com/exception" 
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
   targetNamespace="http://cardservice.handler.jaxws.company.com/service" 
   name="CardService">
    <types>
        <schema targetNamespace="http://cardservice.handler.jaxws.company.com/service"
            xmlns="http://www.w3.org/2001/XMLSchema">
            <import schemaLocation="CreditCardAuthorization.xsd" namespace="
                http://cardservice.handler.jaxws.company.com/creditcard" id="ns1"/>
            <import schemaLocation="FaultInfo.xsd" namespace="http://cardservice.
                handler.jaxws.company.com/exception" id="ns2"/>
        </schema>
    </types>
    <message name="AuthorizePayment">
        <part name="parameters" element="ns1:AuthorizationRequest"/>
    </message>
    <message name="AuthorizeStatus">
        <part name="result" element="ns1:AuthorizationStatus"/>
    </message>
    <message name="CardServiceException">
        <part name="FaultInfo" element="ns2:FaultInfo"/>
    </message>        
    <portType name="CardServicePortType">
        <operation name="authorizePayment">
            <input message="tns:AuthorizePayment"/>
            <output message="tns:AuthorizeStatus"/>
            <fault name="CardServiceException" message="tns:CardServiceException"/>
        </operation>
    </portType>
    <binding name="CardServiceBinding" type="tns:CardServicePortType">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="authorizePayment">
            <soap:operation soapAction="tns:authorizePayment"/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
            <fault name="CardServiceException">
                <soap:fault name="CardServiceException" use="literal"/>
            </fault>
        </operation>
    </binding>
    <service name="CardService">
        <port name="CardServicePort" binding="tns:CardServiceBinding">
            <soap:address location="http://localhost:8484/creditcard/CardService"/>
        </port>
    </service>
</definitions>

It refers to two XML schema files. One is CreditCardAuthorization.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
   xmlns:tns="http://cardservice.handler.jaxws.company.com/creditcard" 
   xmlns:xs="http://www.w3.org/2001/XMLSchema" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   targetNamespace="http://cardservice.handler.jaxws.company.com/creditcard">
            <complexType name="CreditCard">
                <sequence>
                    <element name="cardNumber" type="string"/>
                    <element name="ccvNumber" type="string"/>
                    <element name="billingAddress" nillable="true" type="tns:Address"/>                    
                </sequence>
            </complexType>
            <complexType name="Address">
                <sequence>
                    <element name="addressLine1" nillable="true" type="string"/>
                    <element name="addressLine2" nillable="true" type="string"/>
                    <element name="city" nillable="true" type="string"/>
                    <element name="state" nillable="true" type="string"/>
                    <element name="zip" nillable="true" type="string"/>
                </sequence>
            </complexType>
            <complexType name="CardUser">
                <sequence>
                    <element name="firstName" nillable="true" type="string"/>
                    <element name="lastName" nillable="true" type="string"/>
                </sequence>
            </complexType>
            <element name="AuthorizationRequest">
                <complexType>
                <sequence>
                    <element name="CreditCard" nillable="true" type="tns:CreditCard"/>
                    <element name="CardUser" nillable="true" type="tns:CardUser"/>
                </sequence>
                </complexType>
            </element>            
            <element name="AuthorizationStatus">
                <complexType>
                <sequence>
                    <element name="authorizationToken" nillable="true" type="string"/>
                    <element name="authorized" type="boolean"/>
                    <element name="errorCode" type="int"/>
                </sequence>
                </complexType>
            </element>    
   </schema>

The other is FaultInfo.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
   xmlns:tns="http://cardservice.handler.jaxws.company.com/exception" 
   xmlns:xs="http://www.w3.org/2001/XMLSchema" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   targetNamespace="http://cardservice.handler.jaxws.company.com/exception">
    <element name="FaultInfo">
       <complexType>
          <sequence>
             <element name="faultMessage" nillable="true" type="string"/>
          </sequence>
          </complexType>
    </element>
</schema>

To build the Web service using those two contracts, we customize the schemas for JAXB (Java Architecture for XML Binding) binding with custom-schema-cc.xml and custom-schema-ex.xml, respectively, and customize the WSDL with custom-wsdl.xml. We use those files as binding input for the wsimport tool to generate portable Web service artifacts. Those customizations map the target namespaces of schemas to various Java class packages. The actual implementation of the Web service is provided in the class com.company.jaxws.handler.cardservice.CreditCardServiceImpl, whose implementation of the Web service operation authorizePayment() provides authorization results based on random numbers.

The final Web service is deployed in Apache Tomcat 5.5.4. To run the Web service properly in Tomcat, we must copy the jars in the lib directory of the reference implementation to the ${CATALINA_HOME}/shared/lib directory.

Let's also talk a bit about the handlers here. This is a list of all the handlers from the jaxws-handler project:

  • ClientAuthenticationSOAPHandler: Sets a userid and password pair to the SOAP header, and should be deployed at the client side only.
  • ServiceAuthenticationSOAPHandler: Retrieves the userid and password pair from the SOAPHeader, and should be deployed at the service side only.
  • ClientPerformanceMonitorLogicalHandler: Measures the time that a message exchange takes from entering this handler (inbound) to returning (outbound). The time includes those exchanges taken by a round-trip network, service execution, and possibly other handlers at the client and service sides. It should be deployed at the client side.
  • ServicePerformanceMonitorLogicalHandler: Measures the time that a message exchange takes from entering this handler (inbound) to returning (outbound). The time includes those exchanges taken by service execution and possibly other handlers at the service sides. It should be deployed at the service side.
  • EnvelopeLoggingLogicalHandler: Logs the whole SOAP message and may be deployed at either the service side or client side.
  • HTTPHeaderLoggingLogicalHandler: Logs the HTTP request headers and is deployed at the service side, when the binding protocol is HTTP.
  • JAXPPayloadLoggingLogicalHandler: Demonstrates how to retrieve the message payload using javax.xml.transform.Source. It can be deployed at either the service or client side.

Another handler, JAXPPayloadLoggingLogicalHandler, demonstrates how to retrieve the message payload using a JAXB context. This handler is located in jaxws-handler-service because it depends on CardService's domain objects.

ClientAuthenticationSOAPHandler and ServiceAuthenticationSOAPHandler should be deployed in pairs at the client and service sides, respectively.

A final note about the organization of those projects: By separating the example application into four units, I try to follow what would actually happen in reality while developing Web service applications with JAX-WS, particularly when the handler framework is needed. I hope this makes it easier for readers to understand the different deployment approaches on the server and client sides, and the different client models. In addition, I also hope this helps to emphasize that handlers should be generic and do not have to be attached to a specific Web service.

With this preparation, I now turn to the main topic of this article and begin with the types of handlers that JAX-WS 2.0 supports.

Logical and protocol handlers

JAX-WS specifies two types of handlers:

  • Protocol handlers are specific to a protocol and may access or change the protocol-specific aspects of a message
  • Logical handlers are protocol-agnostic and act only on the payload of a message

The only protocol handler interface defined in JAX-WS is javax.xml.ws.handler.soap.SOAPHandler.

Figure 1 depicts the class hierarchy directly associated with handlers:

Figure 1. Handler Interfaces in JAX-WS 2.0. Click on thumbnail to view full-sized image.

MessageContext is an important concept in JAX-WS, and from the above diagram, we can see it is particularly so when developing handlers.

Message contexts

MessageContext is the information carrier among client, client runtime, and the handlers associated with a message exchange on the client side, and service, service runtime, and service-side handlers on the server side. It contains information about the message and the context of the message exchange, such as information related to the binding protocol.

The following diagram depicts the message context class hierarchy in JAX-WS:

Figure 2. Message context interfaces in JAX-WS 2.0. Click on thumbnail to view full-sized image.

A MessageContext may be injected into the service implementation class to provide or consume message-exchange context information. LogicalMessageContext and SOAPMessageContext are inputs to LogicalHandler and SOAPHandler, respectively.

JAX-WS defines the following standard properties in the MessageContext interface:

  • MESSAGE_OUTBOUND_PROPERTY (Boolean): The message direction—true for outbound messages, false for inbound. Handlers may use this property to determine if the processing is on an outbound or inbound message.
  • INBOUND_MESSAGE_ATTACHMENTS (java.util.Map): Attachments to an inbound message. These can be used to acquire the attachments in inbound message.
  • OUTBOUND_MESSAGE_ATTACHMENTS (java.util.Map): Attachments to an outbound message. A proxy can use these to send attachments not described through WSDL MIME binding.

In the attachment-related maps, the key is the MIME Content-ID, and the value is a DataHandler for the attachment data.

The following properties are specific to the HTTP protocol and are available only in HTTP-based bindings:

  • HTTP_REQUEST_METHOD (java.lang.String): The name of the HTTP method with which a request is made; for example, GET, POST, or PUT.
  • HTTP_REQUEST_HEADERS (java.util.Map): The HTTP headers for the request message.
  • QUERY_STRING (String): The HTTP query string for the request message.
  • PATH_INFO (String): Extra path information associated with the request URL. This information follows the base url path, but precedes the query string.
  • HTTP_RESPONSE_CODE (java.lang.Integer): The HTTP response status code for the last invocation.
  • HTTP_RESPONSE_HEADERS (java.util.Map): The HTTP response headers.

In JAX-WS 2.0, developers can use QUERY_STRING and PATH_INFO properties to support REST-style (Representational State Transfer) Web services.

The properties below are specific to endpoints with HTTP-based binding, running inside a servlet container:

  • SERVLET_CONTEXT (javax.servlet.ServletContext): The ServletContext object of the Web application that contains the Web endpoint.
  • SERVLET_REQUEST (javax.servlet.http.HttpServletRequest ): The HTTPServletRequest object associated with the request currently being served.
  • SERVLET_RESPONSE (javax.servlet.http.HttpServletResponse): The HTTPServletResponse object associated with the request currently being served.

The following properties are optional and might be presented only if the binding has information about WSDL metadata:

  • WSDL_DESCRIPTION (java.net.URI): A resolvable URI that may be used to obtain access to the WSDL for the endpoint.
  • WSDL_SERVICE (javax.xml.namespace.Qname): The name of the service being invoked.
  • WSDL_PORT (javax.xml.namespace.Qname): The name of the port to which the current message is addressed.
  • WSDL_INTERFACE (javax.xml.namespace.Qname): The name of the port type to which the current message belongs.
  • WSDL_OPERATION (javax.xml.namespace.Qname): The name of the WSDL operation with which the current message is associated.

The namespace of those QNames is the target namespace of the WSDL.

Developers may also define application-specific properties in the message context to share states between client/service and handlers.

MessageContext.Scope is an enum defining property scope. Properties scoped as APPLICATION are visible to handlers, client applications, or service endpoint implementations; those scoped as HANDLER are only visible to handlers.

To check the scope of a property in MessageContext, we can use MessageContext.Scope getScope(String name). And the following method can set or change a property's scope: void setScope(String name, MessgeContext.Scope scope).

1 2 3 Page 1