Chapter 43. Writing Handlers

Abstract

JAX-WS provides a flexible plug-in framework for adding message processing modules to an application. These modules, known as handlers, are independent of the application level code and can provide low-level message processing capabilities.

43.1. Handlers: An Introduction

Overview

When a service proxy invokes an operation on a service, the operation’s parameters are passed to Apache CXF where they are built into a message and placed on the wire. When the message is received by the service, Apache CXF reads the message from the wire, reconstructs the message, and then passes the operation parameters to the application code responsible for implementing the operation. When the application code is finished processing the request, the reply message undergoes a similar chain of events on its trip to the service proxy that originated the request. This is shown in Figure 43.1, “Message Exchange Path”.

Figure 43.1. Message Exchange Path

message exchange path between a client and a server

JAX-WS defines a mechanism for manipulating the message data between the application level code and the network. For example, you might want the message data passed over the open network to be encrypted using a proprietary encryption mechanism. You could write a JAX-WS handler that encrypted and decrypted the data. Then you could insert the handler into the message processing chains of all clients and servers.

As shown in Figure 43.2, “Message Exchange Path with Handlers”, the handlers are placed in a chain that is traversed between the application level code and the transport code that places the message onto the network.

Figure 43.2. Message Exchange Path with Handlers

handlers are placed on the message exchange path between the transport and the application layers

Handler types

The JAX-WS specification defines two basic handler types:

  • Logical Handler Logical handlers can process the message payload and the properties stored in the message context. For example, if the application uses pure XML messages, the logical handlers have access to the entire message. If the application uses SOAP messages, the logical handlers have access to the contents of the SOAP body. They do not have access to either the SOAP headers or any attachments unless they were placed into the message context.

    Logical handlers are placed closest to the application code on the handler chain. This means that they are executed first when a message is passed from the application code to the transport. When a message is received from the network and passed back to the application code, the logical handlers are executed last.

  • Protocol Handler Protocol handlers can process the entire message received from the network and the properties stored in the message context. For example, if the application uses SOAP messages, the protocol handlers would have access to the contents of the SOAP body, the SOAP headers, and any attachments.

    Protocol handlers are placed closest to the transport on the handler chain. This means that they are executed first when a message is received from the network. When a message is sent to the network from the application code, the protocol handlers are executed last.

    Note

    The only protocol handler supported by Apache CXF is specific to SOAP.

Implementation of handlers

The differences between the two handler types are very subtle and they share a common base interface. Because of their common parentage, logical handlers and protocol handlers share a number of methods that must be implemented, including:

  • handleMessage() The handleMessage() method is the central method in any handler. It is the method responsible for processing normal messages.
  • handleFault() handleFault() is the method responsible for processing fault messages.
  • close() close() is called on all executed handlers in a handler chain when a message has reached the end of the chain. It is used to clean up any resources consumed during message processing.

The differences between the implementation of a logical handler and the implementation of a protocol handler revolve around the following:

  • The specific interface that is implemented

    All handlers implement an interface that derives from the Handler interface. Logical handlers implement the LogicalHandler interface. Protocol handlers implement protocol specific extensions of the Handler interface. For example, SOAP handlers implement the SOAPHandler interface.

  • The amount of information available to the handler

    Protocol handlers have access to the contents of messages and all of the protocol specific information that is packaged with the message content. Logical handlers can only access the contents of the message. Logical handlers have no knowledge of protocol details.

Adding handlers to an application

To add a handler to an application you must do the following:

  1. Determine whether the handler is going to be used on the service providers, the consumers, or both.
  2. Determine which type of handler is the most appropriate for the job.
  3. Implement the proper interface.

    To implement a logical handler see Section 43.2, “Implementing a Logical Handler”.

    To implement a protocol handler see Section 43.4, “Implementing a Protocol Handler”.

  4. Configure your endpoint(s) to use the handlers. See Section 43.10, “Configuring Endpoints to Use Handlers”.

43.2. Implementing a Logical Handler

Overview

Logical handlers implement the javax.xml.ws.handler.LogicalHandler interface. The LogicalHandler interface, shown in Example 43.1, “LogicalHandler Synopsis” passes a LogicalMessageContext object to the handleMessage() method and the handleFault() method. The context object provides access to the body of the message and to any properties set into the message exchange’s context.

Example 43.1. LogicalHandler Synopsis

public interface LogicalHandler extends Handler
{
  boolean handleMessage(LogicalMessageContext context);
  boolean handleFault(LogicalMessageContext context);
  void close(LogicalMessageContext context);
}

Procedure

To implement a logical hander you do the following:

  1. Implement any Section 43.6, “Initializing a Handler” logic required by the handler.
  2. Implement the Section 43.3, “Handling Messages in a Logical Handler” logic.
  3. Implement the Section 43.7, “Handling Fault Messages” logic.
  4. Implement the logic for Section 43.8, “Closing a Handler” the handler when it is finished.
  5. Implement any logic for Section 43.9, “Releasing a Handler” the handler’s resources before it is destroyed.

43.3. Handling Messages in a Logical Handler

Overview

Normal message processing is handled by the handleMessage() method.

The handleMessage() method receives a LogicalMessageContext object that provides access to the message body and any properties stored in the message context.

The handleMessage() method returns either true or false depending on how message processing is to continue. It can also throw an exception.

Getting the message data

The LogicalMessageContext object passed into logical message handlers allows access to the message body using the context’s getMessage() method. The getMessage() method, shown in Example 43.2, “Method for Getting the Message Payload in a Logical Handler”, returns the message payload as a LogicalMessage object.

Example 43.2. Method for Getting the Message Payload in a Logical Handler

LogicalMessagegetMessage

Once you have the LogicalMessage object, you can use it to manipulate the message body. The LogicalMessage interface, shown in Example 43.3, “Logical Message Holder”, has getters and setters for working with the actual message body.

Example 43.3. Logical Message Holder

LogicalMessageSourcegetPayloadObjectgetPayloadJAXBContextcontextsetPayloadObjectpayloadJAXBContextcontextsetPayloadSourcepayload

Important

The contents of the message payload are determined by the type of binding in use. The SOAP binding only allows access to the SOAP body of the message. The XML binding allows access to the entire message body.

Working with the message body as an XML object

One pair of getters and setters of the logical message work with the message payload as a javax.xml.transform.dom.DOMSource object.

The getPayload() method that has no parameters returns the message payload as a DOMSource object. The returned object is the actual message payload. Any changes made to the returned object change the message body immediately.

You can replace the body of the message with a DOMSource object using the setPayload() method that takes the single Source object.

Working with the message body as a JAXB object

The other pair of getters and setters allow you to work with the message payload as a JAXB object. They use a JAXBContext object to transform the message payload into JAXB objects.

To use the JAXB objects you do the following:

  1. Get a JAXBContext object that can manage the data types in the message body.

    For information on creating a JAXBContext object see Chapter 39, Using A JAXBContext Object.

  2. Get the message body as shown in Example 43.4, “Getting the Message Body as a JAXB Object”.

    Example 43.4. Getting the Message Body as a JAXB Object

    JAXBContext jaxbc = JAXBContext(myObjectFactory.class);
    Object body = message.getPayload(jaxbc);
  3. Cast the returned object to the proper type.
  4. Manipulate the message body as needed.
  5. Put the updated message body back into the context as shown in Example 43.5, “Updating the Message Body Using a JAXB Object”.

    Example 43.5. Updating the Message Body Using a JAXB Object

    message.setPayload(body, jaxbc);

Working with context properties

The logical message context passed into a logical handler is an instance of the application’s message context and can access all of the properties stored in it. Handlers have access to properties at both the APPLICATION scope and the HANDLER scope.

Like the application’s message context, the logical message context is a subclass of Java Map. To access the properties stored in the context, you use the get() method and put() method inherited from the Map interface.

By default, any properties you set in the message context from inside a logical handler are assigned a scope of HANDLER. If you want the application code to be able to access the property you need to use the context’s setScope() method to explicitly set the property’s scope to APPLICATION.

For more information on working with properties in the message context see Section 42.1, “Understanding Contexts”.

Determining the direction of the message

It is often important to know the direction a message is passing through the handler chain. For example, you would want to retrieve a security token from incoming requests and attach a security token to an outgoing response.

The direction of the message is stored in the message context’s outbound message property. You retrieve the outbound message property from the message context using the MessageContext.MESSAGE_OUTBOUND_PROPERTY key as shown in Example 43.6, “Getting the Message’s Direction from the SOAP Message Context”.

Example 43.6. Getting the Message’s Direction from the SOAP Message Context

Boolean outbound;
outbound = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

The property is stored as a Boolean object. You can use the object’s booleanValue() method to determine the property’s value. If the property is set to true, the message is outbound. If the property is set to false the message is inbound.

Determining the return value

How the handleMessage() method completes its message processing has a direct impact on how message processing proceeds. It can complete by doing one of the following actions:

  1. Return true—Returning true signals to the Apache CXF runtime that message processing should continue normally. The next handler, if any, has its handleMessage() invoked.
  2. Return false—Returning false signals to the Apache CXF runtime that normal message processing must stop. How the runtime proceeds depends on the message exchange pattern in use for the current message.

    For request-response message exchanges the following happens:

    1. The direction of message processing is reversed.

      For example, if a request is being processed by a service provider, the message stops progressing toward the service’s implementation object. Instead, it is sent back towards the binding for return to the consumer that originated the request.

    2. Any message handlers that reside along the handler chain in the new processing direction have their handleMessage() method invoked in the order in which they reside in the chain.
    3. When the message reaches the end of the handler chain it is dispatched.

      For one-way message exchanges the following happens:

    4. Message processing stops.
    5. All previously invoked message handlers have their close() method invoked.
    6. The message is dispatched.
  3. Throw a ProtocolException exception—Throwing a ProtocolException exception, or a subclass of this exception, signals the Apache CXF runtime that fault message processing is beginning. How the runtime proceeds depends on the message exchange pattern in use for the current message.

    For request-response message exchanges the following happens:

    1. If the handler has not already created a fault message, the runtime wraps the message in a fault message.
    2. The direction of message processing is reversed.

      For example, if a request is being processed by a service provider, the message stops progressing toward the service’s implementation object. Instead, it is sent back towards the binding for return to the consumer that originated the request.

    3. Any message handlers that reside along the handler chain in the new processing direction have their handleFault() method invoked in the order in which they reside in the chain.
    4. When the fault message reaches the end of the handler chain it is dispatched.

      For one-way message exchanges the following happens:

    5. If the handler has not already created a fault message, the runtime wraps the message in a fault message.
    6. Message processing stops.
    7. All previously invoked message handlers have their close() method invoked.
    8. The fault message is dispatched.
  4. Throw any other runtime exception—Throwing a runtime exception other than a ProtocolException exception signals the Apache CXF runtime that message processing is to stop. All previously invoked message handlers have the close() method invoked and the exception is dispatched. If the message is part of a request-response message exchange, the exception is dispatched so that it is returned to the consumer that originated the request.

Example

Example 43.7, “Logical Message Handler Message Processing” shows an implementation of handleMessage() message for a logical message handler that is used by a service consumer. It processes requests before they are sent to the service provider.

Example 43.7. Logical Message Handler Message Processing

public class SmallNumberHandler implements LogicalHandler<LogicalMessageContext>
{
    public final boolean handleMessage(LogicalMessageContext messageContext)
    {
        try
        {
            boolean outbound = (Boolean)messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

            if (outbound)
            {
                LogicalMessage msg = messageContext.getMessage();

                JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
                Object payload = msg.getPayload(jaxbContext);
                if (payload instanceof JAXBElement)
                {
                    payload = ((JAXBElement)payload).getValue();
                }

                if (payload instanceof AddNumbers)
                {
                    AddNumbers req = (AddNumbers)payload;

                    int a = req.getArg0();
                    int b = req.getArg1();
                    int answer = a + b;

                    if (answer < 20)
                    {
                      AddNumbersResponse resp = new AddNumbersResponse();
                      resp.setReturn(answer);
                      msg.setPayload(new ObjectFactory().createAddNumbersResponse(resp),
                                                      jaxbContext);

                      return false;
                    }
                }
                else
                {
                   throw new WebServiceException("Bad Request");
                }
            }
            return true;
        }
        catch (JAXBException ex)
        {
            throw new ProtocolException(ex);
        }
    }
...
}

The code in Example 43.7, “Logical Message Handler Message Processing” does the following:

Checks if the message is an outbound request.

If the message is an outbound request, the handler does additional message processing.

Gets the LogicalMessage representation of the message payload from the message context.

Gets the actual message payload as a JAXB object.

Checks to make sure the request is of the correct type.

If it is, the handler continues processing the message.

Checks the value of the sum.

If it is less than the threshold of 20 then it builds a response and returns it to the client.

Builds the response.

Returns false to stop message processing and return the response to the client.

Throws a runtime exception if the message is not of the correct type.

This exception is returned to the client.

Returns true if the message is an inbound response or the sum does not meet the threshold.

Message processing continues normally.

Throws a ProtocolException if a JAXB marshalling error is encountered.

The exception is passed back to the client after it is processed by the handleFault() method of the handlers between the current handler and the client.

43.4. Implementing a Protocol Handler

Overview

Protocol handlers are specific to the protocol in use. Apache CXF provides the SOAP protocol handler as specified by JAX-WS. A SOAP protocol handler implements the javax.xml.ws.handler.soap.SOAPHandler interface.

The SOAPHandler interface, shown in Example 43.8, “SOAPHandler Synopsis”, uses a SOAP specific message context that provides access to the message as a SOAPMessage object. It also allows you to access the SOAP headers.

Example 43.8. SOAPHandler Synopsis

public interface SOAPHandler extends Handler
{
  boolean handleMessage(SOAPMessageContext context);
  boolean handleFault(SOAPMessageContext context);
  void close(SOAPMessageContext context);
  Set<QName> getHeaders()
}

In addition to using a SOAP specific message context, SOAP protocol handlers require that you implement an additional method called getHeaders(). This additional method returns the QNames of the header blocks the handler can process.

Procedure

To implement a logical hander do the following:

  1. Implement any Section 43.6, “Initializing a Handler” logic required by the handler.
  2. Implement the Section 43.5, “Handling Messages in a SOAP Handler” logic.
  3. Implement the Section 43.7, “Handling Fault Messages” logic.
  4. Implement the getHeaders() method.
  5. Implement the logic for Section 43.8, “Closing a Handler” the handler when it is finished.
  6. Implement any logic for Section 43.9, “Releasing a Handler” the handler’s resources before it is destroyed.

Implementing the getHeaders() method

The getHeaders(), shown in Example 43.9, “The SOAPHander.getHeaders() Method”, method informs the Apache CXF runtime what SOAP headers the handler is responsible for processing. It returns the QNames of the outer element of each SOAP header the handler understands.

Example 43.9. The SOAPHander.getHeaders() Method

Set<QName>getHeaders

For many cases simply returning null is sufficient. However, if the application uses the mustUnderstand attribute of any of the SOAP headers, then it is important to specify the headers understood by the application’s SOAP handlers. The runtime checks the set of SOAP headers that all of the registered handlers understand against the list of headers with the mustUnderstand attribute set to true. If any of the flagged headers are not in the list of understood headers, the runtime rejects the message and throws a SOAP must understand exception.

43.5. Handling Messages in a SOAP Handler

Overview

Normal message processing is handled by the handleMessage() method.

The handleMessage() method receives a SOAPMessageContext object that provides access to the message body as a SOAPMessage object and the SOAP headers associated with the message. In addition, the context provides access to any properties stored in the message context.

The handleMessage() method returns either true or false depending on how message processing is to continue. It can also throw an exception.

Working with the message body

You can get the SOAP message using the SOAP message context’s getMessage() method. It returns the message as a live SOAPMessage object. Any changes to the message in the handler are automatically reflected in the message stored in the context.

If you wish to replace the existing message with a new one, you can use the context’s setMessage() method. The setMessage() method takes a SOAPMessage object.

Getting the SOAP headers

You can access the SOAP message’s headers using the SOAPMessage object’s getHeader() method. This will return the SOAP header as a SOAPHeader object that you will need to inspect to find the header elements you wish to process.

The SOAP message context provides a getHeaders() method, shown in Example 43.10, “The SOAPMessageContext.getHeaders() Method”, that will return an array containing JAXB objects for the specified SOAP headers.

Example 43.10. The SOAPMessageContext.getHeaders() Method

Ojbect[]getHeadersQNameheaderJAXBContextcontextbooleanallRoles

You specify the headers using the QName of their element. You can further limit the headers that are returned by setting the allRoles parameter to false. That instructs the runtime to only return the SOAP headers that are applicable to the active SOAP roles.

If no headers are found, the method returns an empty array.

For more information about instantiating a JAXBContext object see Chapter 39, Using A JAXBContext Object.

Working with context properties

The SOAP message context passed into a logical handler is an instance of the application’s message context and can access all of the properties stored in it. Handlers have access to properties at both the APPLICATION scope and the Handler scope.

Like the application’s message context, the SOAP message context is a subclass of Java Map. To access the properties stored in the context, you use the get() method and put() method inherited from the Map interface.

By default, any properties you set in the context from inside a logical handler will be assigned a scope of HANDLER. If you want the application code to be able to access the property you need to use the context’s setScope() method to explicitly set the property’s scope to APPLICATION.

For more information on working with properties in the message context see Section 42.1, “Understanding Contexts”.

Determining the direction of the message

It is often important to know the direction a message is passing through the handler chain. For example, you would want to add headers to an outgoing message and strip headers from an incoming message.

The direction of the message is stored in the message context’s outbound message property. You retrieve the outbound message property from the message context using the MessageContext.MESSAGE_OUTBOUND_PROPERTY key as shown in Example 43.11, “Getting the Message’s Direction from the SOAP Message Context”.

Example 43.11. Getting the Message’s Direction from the SOAP Message Context

Boolean outbound;
outbound = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

The property is stored as a Boolean object. You can use the object’s booleanValue() method to determine the property’s value. If the property is set to true, the message is outbound. If the property is set to false the message is inbound.

Determining the return value

How the handleMessage() method completes its message processing has a direct impact on how message processing proceeds. It can complete by doing one of the following actions:

  1. return true—Returning true signals to the Apache CXF runtime that message processing should continue normally. The next handler, if any, has its handleMessage() invoked.
  2. return false—Returning false signals to the Apache CXF runtime that normal message processing is to stop. How the runtime proceeds depends on the message exchange pattern in use for the current message.

    For request-response message exchanges the following happens:

    1. The direction of message processing is reversed.

      For example, if a request is being processed by a service provider, the message will stop progressing toward the service’s implementation object. It will instead be sent back towards the binding for return to the consumer that originated the request.

    2. Any message handlers that reside along the handler chain in the new processing direction have their handleMessage() method invoked in the order in which they reside in the chain.
    3. When the message reaches the end of the handler chain it is dispatched.

      For one-way message exchanges the following happens:

    4. Message processing stops.
    5. All previously invoked message handlers have their close() method invoked.
    6. The message is dispatched.
  3. throw a ProtocolException exception—Throwing a ProtocolException exception, or a subclass of this exception, signals the Apache CXF runtime that fault message processing is to start. How the runtime proceeds depends on the message exchange pattern in use for the current message.

    For request-response message exchanges the following happens:

    1. If the handler has not already created a fault message, the runtime wraps the message in a fault message.
    2. The direction of message processing is reversed.

      For example, if a request is being processed by a service provider, the message will stop progressing toward the service’s implementation object. It will be sent back towards the binding for return to the consumer that originated the request.

    3. Any message handlers that reside along the handler chain in the new processing direction have their handleFault() method invoked in the order in which they reside in the chain.
    4. When the fault message reaches the end of the handler chain it is dispatched.

      For one-way message exchanges the following happens:

    5. If the handler has not already created a fault message, the runtime wraps the message in a fault message.
    6. Message processing stops.
    7. All previously invoked message handlers have their close() method invoked.
    8. The fault message is dispatched.
  4. throw any other runtime exception—Throwing a runtime exception other than a ProtocolException exception signals the Apache CXF runtime that message processing is to stop. All previously invoked message handlers have the close() method invoked and the exception is dispatched. If the message is part of a request-response message exchange the exception is dispatched so that it is returned to the consumer that originated the request.

Example

Example 43.12, “Handling a Message in a SOAP Handler” shows a handleMessage() implementation that prints the SOAP message to the screen.

Example 43.12. Handling a Message in a SOAP Handler

public boolean handleMessage(SOAPMessageContext smc)
{
  PrintStream out;

  Boolean outbound = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

  if (outbound.booleanValue())
  {
    out.println("\nOutbound message:");
  }
  else
  {
    out.println("\nInbound message:");
  }

  SOAPMessage message = smc.getMessage();

  message.writeTo(out);
  out.println();

  return true;
}

The code in Example 43.12, “Handling a Message in a SOAP Handler” does the following:

Retrieves the outbound property from the message context.

Tests the messages direction and prints the appropriate message.

Retrieves the SOAP message from the context.

Prints the message to the console.

43.6. Initializing a Handler

Overview

When the runtime creates an instance of a handler, it creates all of the resources the hander needs to process messages. While you can place all of the logic for doing this in the handler’s constructor, it may not be the most appropriate place. The handler framework performs a number of optional steps when it instantiates a handler. You can add resource injection and other initialization logic that will be executed during the optional steps.

You do not have to provide any initialization methods for a handler.

Order of initialization

The Apache CXF runtime initializes a handler in the following manner:

  1. The handler’s constructor is called.
  2. Any resources that are specified by the @Resource annotation are injected.
  3. The method decorated with @PostConstruct annotation, if it is present, is called.

    Note

    Methods decorated with the @PostConstruct annotation must have a void return type and have no parameters.

  4. The handler is place in the Ready state.

43.7. Handling Fault Messages

Overview

Handlers use the handleFault() method for processing fault messages when a ProtocolException exception is thrown during message processing.

The handleFault() method receives either a LogicalMessageContext object or SOAPMessageContext object depending on the type of handler. The received context gives the handler’s implementation access to the message payload.

The handleFault() method returns either true or false, depending on how fault message processing is to proceed. It can also throw an exception.

Getting the message payload

The context object received by the handleFault() method is similar to the one received by the handleMessage() method. You use the context’s getMessage() method to access the message payload in the same way. The only difference is the payload contained in the context.

For more information on working with a LogicalMessageContext see Section 43.3, “Handling Messages in a Logical Handler”.

For more information on working with a SOAPMessageContext see Section 43.5, “Handling Messages in a SOAP Handler”.

Determining the return value

How the handleFault() method completes its message processing has a direct impact on how message processing proceeds. It completes by performing one of the following actions:

Return true
Returning true signals that fault processing should continue normally. The handleFault() method of the next handler in the chain will be invoked.
Return false
Returning false signals that fault processing stops. The close() method of the handlers that were invoked in processing the current message are invoked and the fault message is dispatched.
Throw an exception
Throwing an exception stops fault message processing. The close() method of the handlers that were invoked in processing the current message are invoked and the exception is dispatched.

Example

Example 43.13, “Handling a Fault in a Message Handler” shows an implementation of handleFault() that prints the message body to the screen.

Example 43.13. Handling a Fault in a Message Handler

public final boolean handleFault(LogicalMessageContext messageContext)
{
  System.out.println("handleFault() called with message:");

  LogicalMessage msg=messageContext.getMessage();
  System.out.println(msg.getPayload());

  return true;
}

43.8. Closing a Handler

When a handler chain is finished processing a message, the runtime calls each executed handler’s close() method. This is the appropriate place to clean up any resources that were used by the handler during message processing or resetting any properties to a default state.

If a resource needs to persist beyond a single message exchange, you should not clean it up during in the handler’s close() method.

43.9. Releasing a Handler

Overview

The runtime releases a handler when the service or service proxy to which the handler is bound is shutdown. The runtime will invoke an optional release method before invoking the handler’s destructor. This optional release method can be used to release any resources used by the handler or perform other actions that would not be appropriate in the handler’s destructor.

You do not have to provide any clean-up methods for a handler.

Order of release

The following happens when the handler is released:

  1. The handler finishes processing any active messages.
  2. The runtime invokes the method decorated with the @PreDestroy annotation.

    This method should clean up any resources used by the handler.

  3. The handler’s destructor is called.

43.10. Configuring Endpoints to Use Handlers

43.10.1. Programmatic Configuration

43.10.1.1. Adding a Handler Chain to a Consumer

Overview

Adding a handler chain to a consumer involves explicitly building the chain of handlers. Then you set the handler chain directly on the service proxy’s Binding object.

Important

Any handler chains configured using the Spring configuration override the handler chains configured programmaticaly.

Procedure

To add a handler chain to a consumer you do the following:

  1. Create a List<Handler> object to hold the handler chain.
  2. Create an instance of each handler that will be added to the chain.
  3. Add each of the instantiated handler objects to the list in the order they are to be invoked by the runtime.
  4. Get the Binding object from the service proxy.

    Apache CXF provides an implementation of the Binding interface called org.apache.cxf.jaxws.binding.DefaultBindingImpl.

  5. Set the handler chain on the proxy using the Binding object’s setHandlerChain() method.
Example

Example 43.14, “Adding a Handler Chain to a Consumer” shows code for adding a handler chain to a consumer.

Example 43.14. Adding a Handler Chain to a Consumer

import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;
import java.util.ArrayList;
import java.util.List;

import org.apache.cxf.jaxws.binding.DefaultBindingImpl;
...
SmallNumberHandler sh = new SmallNumberHandler();
List<Handler> handlerChain = new ArrayList<Handler>();
handlerChain.add(sh);

DefaultBindingImpl binding = ((BindingProvider)proxy).getBinding();
binding.getBinding().setHandlerChain(handlerChain);

The code in Example 43.14, “Adding a Handler Chain to a Consumer” does the following:

Instantiates a handler.

Creates a List object to hold the chain.

Adds the handler to the chain.

Gets the Binding object from the proxy as a DefaultBindingImpl object.

Assigns the handler chain to the proxy’s binding.

43.10.1.2. Adding a Handler Chain to a Service Provider

Overview

You add a handler chain to a service provider by decorating either the SEI or the implementation class with the @HandlerChain annotation. The annotation points to a meta-data file defining the handler chain used by the service provider.

Procedure

To add handler chain to a service provider you do the following:

  1. Decorate the provider’s implementation class with the @HandlerChain annotation.
  2. Create a handler configuration file that defines the handler chain.
The @HandlerChain annotation

The javax.jws.HandlerChain annotation decorates service provider’s implementation class. It instructs the runtime to load the handler chain configuration file specified by its file property.

The annotation’s file property supports two methods for identifying the handler configuration file to load:

  • a URL
  • a relative path name

Example 43.15, “Service Implementation that Loads a Handler Chain” shows a service provider implementation that will use the handler chain defined in a file called handlers.xml. handlers.xml must be located in the directory from which the service provider is run.

Example 43.15. Service Implementation that Loads a Handler Chain

import javax.jws.HandlerChain;
import javax.jws.WebService;
...

@WebService(name = "AddNumbers",
            targetNamespace = "http://apache.org/handlers",
            portName = "AddNumbersPort",
            endpointInterface = "org.apache.handlers.AddNumbers",
            serviceName = "AddNumbersService")
@HandlerChain(file = "handlers.xml")
public class AddNumbersImpl implements AddNumbers
{
...
}
Handler configuration file

The handler configuration file defines a handler chain using the XML grammar that accompanies JSR 109 (Web Services for Java EE, Version 1.2). This grammar is defined in the http://java.sun.com/xml/ns/javaee.

The root element of the handler configuration file is the handler-chains element. The handler-chains element has one or more handler-chain elements.

The handler-chain element define a handler chain. Table 43.1, “Elements Used to Define a Server-Side Handler Chain” describes the handler-chain element’s children.

Table 43.1. Elements Used to Define a Server-Side Handler Chain

ElementDescription

handler

Contains the elements that describe a handler.

service-name-pattern

Specifies the QName of the WSDL service element defining the service to which the handler chain is bound. You can use * as a wildcard when defining the QName.

port-name-pattern

Specifies the QName of the WSDL port element defining the endpoint to which the handler chain is bound. You can use * as a wildcard when defining the QName.

protocol-binding

Specifies the message binding for which the handler chain is used. The binding is specified as a URI or using one of the following aliases: #\#SOAP11_HTTP, \##SOAP11_HTTP_MTOM, \##SOAP12_HTTP, \##SOAP12_HTTP_MTOM, or \#\#XML_HTTP.

For more information about message binding URIs see Chapter 23, Apache CXF Binding IDs.

The handler-chain element is only required to have a single handler element as a child. It can, however, support as many handler elements as needed to define the complete handler chain. The handlers in the chain are executed in the order they specified in the handler chain definition.

Important

The final order of execution will be determined by sorting the specified handlers into logical handlers and protocol handlers. Within the groupings, the order specified in the configuration will be used.

The other children, such as protocol-binding, are used to limit the scope of the defined handler chain. For example, if you use the service-name-pattern element, the handler chain will only be attached to service providers whose WSDL port element is a child of the specified WSDL service element. You can only use one of these limiting children in a handler element.

The handler element defines an individual handler in a handler chain. Its handler-class child element specifies the fully qualified name of the class implementing the handler. The handler element can also have an optional handler-name element that specifies a unique name for the handler.

Example 43.16, “Handler Configuration File” shows a handler configuration file that defines a single handler chain. The chain is made up of two handlers.

Example 43.16. Handler Configuration File

<handler-chains xmlns="http://java.sun.com/xml/ns/javaee"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://java.sun.com/xml/ns/javaee">
  <handler-chain>
    <handler>
      <handler-name>LoggingHandler</handler-name>
      <handler-class>demo.handlers.common.LoggingHandler</handler-class>
    </handler>
    <handler>
      <handler-name>AddHeaderHandler</handler-name>
      <handler-class>demo.handlers.common.AddHeaderHandler</handler-class>
    </handler>
  </handler-chain>
</handler-chains>

43.10.2. Spring Configuration

Overview

The easiest way to configure an endpoint to use a handler chain is to define the chain in the endpoint’s configuration. This is done by adding a jaxwxs:handlers child to the element configuring the endpoint.

Important

A handler chain added through the configuration file takes precedence over a handler chain configured programatically.

Procedure

To configure an endpoint to load a handler chain you do the following:

  1. If the endpoint does not already have a configuration element, add one.

    For more information on configuring Apache CXF endpoints see Chapter 17, Configuring JAX-WS Endpoints.

  2. Add a jaxws:handlers child element to the endpoint’s configuration element.
  3. For each handler in the chain, add a bean element specifying the class that implements the handler.

    If your handler implementation is used in more than one place you can reference a bean element using the ref element.

The handlers element

The jaxws:handlers element defines a handler chain in an endpoint’s configuration. It can appear as a child to all of the JAX-WS endpoint configuration elements. These are:

  • jaxws:endpoint configures a service provider.
  • jaxws:server also configures a service provider.
  • jaxws:client configures a service consumer.

You add handlers to the handler chain in one of two ways:

  • add a bean element defining the implementation class
  • use a ref element to refer to a named bean element from elsewhere in the configuration file

The order in which the handlers are defined in the configuration is the order in which they will be executed. The order may be modified if you mix logical handlers and protocol handlers. The run time will sort them into the proper order while maintaining the basic order specified in the configuration.

Example

Example 43.17, “Configuring an Endpoint to Use a Handler Chain In Spring” shows the configuration for a service provider that loads a handler chain.

Example 43.17. Configuring an Endpoint to Use a Handler Chain In Spring

<beans ...
  xmlns:jaxws="http://cxf.apache.org/jaxws"
  ...
  schemaLocation="...
    http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
    ...">
  <jaxws:endpoint id="HandlerExample"
                  implementor="org.apache.cxf.example.DemoImpl"
                  address="http://localhost:8080/demo">
    <jaxws:handlers> <bean class="demo.handlers.common.LoggingHandler" /> <bean class="demo.handlers.common.AddHeaderHandler" /> </jaxws:handlers>
  </jaws:endpoint>
</beans>