Chapter 58. Implementing the Interceptors Processing Logic

Abstract

Interceptors are straightforward to implement. The bulk of their processing logic is in the handleMessage() method. This method receives the message data and manipulates it as needed. Developers may also want to add some special logic to handle fault processing cases.

58.1. Interceptor Flow

Figure 58.1, “Flow through an interceptor” shows the process flow through an interceptor.

Figure 58.1. Flow through an interceptor

interceptor1

In normal message processing, only the handleMessage() method is called. The handleMessage() method is where the interceptor’s message processing logic is placed.

If an error occurs in the handleMessage() method of the interceptor, or any subsequent interceptor in the interceptor chain, the handleFault() method is called. The handleFault() method is useful for cleaning up after an interceptor in the event of an error. It can also be used to alter the fault message.

58.2. Processing messages

Overview

In normal message processing, an interceptor’s handleMessage() method is invoked. It receives that message data as a Message object. Along with the actual contents of the message, the Message object may contain a number of properties related to the message or the message processing state. The exact contents of the Message object depends on the interceptors preceding the current interceptor in the chain.

Getting the message contents

The Message interface provides two methods that can be used in extracting the message contents:

  • public<T> TgetContentjava.lang.Class<T> format The getContent() method returns the content of the message in an object of the specified class. If the contents are not available as an instance of the specified class, null is returned. The list of available content types is determined by the interceptor’s location on the interceptor chain and the direction of the interceptor chain.
  • publicCollection<Attachment>getAttachments The getAttachments() method returns a Java Collection object containing any binary attachments associated with the message. The attachments are stored in org.apache.cxf.message.Attachment objects. Attachment objects provide methods for managing the binary data.

    Important

    Attachments are only available after the attachment processing interceptors have executed.

Determining the message’s direction

The direction of a message can be determined by querying the message exchange. The message exchange stores the inbound message and the outbound message in separate properties.[3]

The message exchange associated with a message is retrieved using the message’s getExchange() method. As shown in Example 58.1, “Getting the message exchange”, getExchange() does not take any parameters and returns the message exchange as a org.apache.cxf.message.Exchange object.

Example 58.1. Getting the message exchange

ExchangegetExchange

The Exchange object has four methods, shown in Example 58.2, “Getting messages from a message exchange”, for getting the messages associated with an exchange. Each method will either return the message as a org.apache.cxf.Message object or it will return null if the message does not exist.

Example 58.2. Getting messages from a message exchange

MessagegetInMessageMessagegetInFaultMessageMessagegetOutMessageMessagegetOutFaultMessage

Example 58.3, “Checking the direction of a message chain” shows code for determining if the current message is outbound. The method gets the message exchange and checks to see if the current message is the same as the exchange’s outbound message. It also checks the current message against the exchanges outbound fault message to error messages on the outbound fault interceptor chain.

Example 58.3. Checking the direction of a message chain

public static boolean isOutbound()
{
   Exchange exchange = message.getExchange();
        return message != null
               && exchange != null
               && (message == exchange.getOutMessage()
                   || message == exchange.getOutFaultMessage());
}

Example

Example 58.4, “Example message processing method” shows code for an interceptor that processes zip compressed messages. It checks the direction of the message and then performs the appropriate actions.

Example 58.4. Example message processing method

import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;

import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;

public class StreamInterceptor extends AbstractPhaseInterceptor<Message>
{

  ...

  public void handleMessage(Message message)
  {

        boolean isOutbound = false;
        isOutbound = message == message.getExchange().getOutMessage()
               || message == message.getExchange().getOutFaultMessage();

        if (!isOutbound)
        {
          try
          {
             InputStream is = message.getContent(InputStream.class);
             GZIPInputStream zipInput = new GZIPInputStream(is);
             message.setContent(InputStream.class, zipInput);
          }
          catch (IOException ioe)
          {
             ioe.printStackTrace();
           }
        }
         else
        {
         // zip the outbound message
        }
    }
  ...
}

58.3. Unwinding after an error

Overview

When an error occurs during the execution of an interceptor chain, the runtime stops traversing the interceptor chain and unwinds the chain by calling the handleFault() method of any interceptors in the chain that have already been executed.

The handleFault() method can be used to clean up any resources used by an interceptor during normal message processing. It can also be used to rollback any actions that should only stand if message processing completes successfully. In cases where the fault message will be passed on to an outbound fault processing interceptor chain, the handleFault() method can also be used to add information to the fault message.

Getting the message payload

The handleFault() method receives the same Message object as the handleMessage() method used in normal message processing. Getting the message contents from the Message object is described in the section called “Getting the message contents”.

Example

Example 58.5, “Handling an unwinding interceptor chain” shows code used to ensure that the original XML stream is placed back into the message when the interceptor chain is unwound.

Example 58.5. Handling an unwinding interceptor chain

@Override
public void handleFault(SoapMessage message)
{
  super.handleFault(message);
  XMLStreamWriter writer = (XMLStreamWriter)message.get(ORIGINAL_XML_WRITER);
  if (writer != null)
  {
    message.setContent(XMLStreamWriter.class, writer);
  }
}


[3] It also stores inbound and outbound faults separately.