Chapter 59. Configuring Endpoints to Use Interceptors

Abstract

Interceptors are added to an endpoint when it is included in a message exchange. The endpoint’s interceptor chains are constructed from a the interceptor chains of a number of components in the Apache CXF runtime. Interceptors are specified in either the endpoint’s configuration or the configuration of one of the runtime components. Interceptors can be added using either the configuration file or the interceptor API.

59.1. Deciding where to attach interceptors

Overview

There are a number of runtime objects that host interceptor chains. These include:

  • the endpoint object
  • the service object
  • the proxy object
  • the factory object used to create the endpoint or the proxy
  • the binding
  • the central Bus object

A developer can attach their own interceptors to any of these objects. The most common objects to attach interceptors are the bus and the individual endpoints. Choosing the correct object requires understanding how these runtime objects are combined to make an endpoint. As per the design, each cxf related bundle has its own cxf bus. Hence, if the interceptors are configured in the bus and the service at the same Blueprint context is imported or created into another bundle, the interceptor won’t be processed. Instead you can configure the interceptors directly into the JAXWS client or endpoint in the imported service.

Endpoints and proxies

Attaching interceptors to either the endpoint or the proxy is the most fine grained way to place an interceptor. Any interceptors attached directly to an endpoint or a proxy only effect the specific endpoint or proxy. This is a good place to attach interceptors that are specific to a particular incarnation of a service. For example, if a developer wants to expose one instance of a service that converts units from metric to imperial they could attach the interceptors directly to one endpoint.

Factories

Using the Spring configuration to attach interceptors to the factories used to create an endpoint or a proxy has the same effect as attaching the interceptors directly to the endpoint or proxy. However, when interceptors are attached to a factory programmatically the interceptors attached to the factory are propagated to every endpoint or proxy created by the factory.

Bindings

Attaching interceptors to the binding allows the developer to specify a set of interceptors that are applied to all endpoints that use the binding. For example, if a developer wants to force all endpoints that use the raw XML binding to include a special ID element, they could attach the interceptor responsible for adding the element to the XML binding.

Buses

The most general place to attach interceptors is the bus. When interceptors are attached to the bus, the interceptors are propagated to all of the endpoints managed by that bus. Attaching interceptors to the bus is useful in applications that create multiple endpoints that share a similar set of interceptors.

Combining attachment points

Because an endpoint’s final set of interceptor chains is an amalgamation of the interceptor chains contributed by the listed objects, several of the listed object can be combined in a single endpoint’s configuration. For example, if an application spawned multiple endpoints that all required an interceptor that checked for a validation token, that interceptor would be attached to the application’s bus. If one of those endpoints also required an interceptor that converted Euros into dollars, the conversion interceptor would be attached directly to the specific endpoint.

59.2. Adding interceptors using configuration

Overview

The easiest way to attach interceptors to an endpoint is using the configuration file. Each interceptor to be attached to an endpoint is configured using a standard Spring bean. The interceptor’s bean can then be added to the proper interceptor chain using Apache CXF configuration elements.

Each runtime component that has an associated interceptor chain is configurable using specialized Spring elements. Each of the component’s elements have a standard set of children for specifying their interceptor chains. There is one child for each interceptor chain associated with the component. The children list the beans for the interceptors to be added to the chain.

Configuration elements

Table 59.1, “Interceptor chain configuration elements” describes the four configuration elements for attaching interceptors to a runtime component.

Table 59.1. Interceptor chain configuration elements

ElementDescription

inInterceptors

Contains a list of beans configuring interceptors to add to an endpoint’s inbound interceptor chain.

outInterceptors

Contains a list of beans configuring interceptors to add to an endpoint’s outbound interceptor chain.

inFaultInterceptors

Contains a list of beans configuring interceptors to add to an endpoint’s inbound fault processing interceptor chain.

outFaultInterceptors

Contains a list of beans configuring interceptors to add to an endpoint’s outbound fault processing interceptor chain.

All of the interceptor chain configuration elements take a list child element. The list element has one child for each of the interceptors being attached to the chain. Interceptors can be specified using either a bean element directly configuring the interceptor or a ref element that refers to a bean element that configures the interceptor.

Examples

Example 59.1, “Attaching interceptors to the bus” shows configuration for attaching interceptors to a bus' inbound interceptor chain.

Example 59.1. Attaching interceptors to the bus

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cxf="http://cxf.apache.org/core"
       xmlns:http="http://cxf.apache.org/transports/http/configuration"
       xsi:schemaLocation="
       http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
       http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  ...
  <bean id="GZIPStream" class="demo.stream.interceptor.StreamInterceptor"/>

  <cxf:bus>
    *<cxf:inInterceptors>
      <list>
        <ref bean="GZIPStream"/>
      </list>
    </cxf:inInterceptors>*
  </cxf:bus>
</beans>

Example 59.2, “Attaching interceptors to a JAX-WS service provider” shows configuration for attaching an interceptor to a JAX-WS service’s outbound interceptor chain.

Example 59.2. Attaching interceptors to a JAX-WS service provider

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xmlns:wsa="http://cxf.apache.org/ws/addressing"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

  <jaxws:endpoint ...>
    *<jaxws:outInterceptors>
      <list>
        <bean id="GZIPStream" class="demo.stream.interceptor.StreamInterceptor" />
      </list>
    </jaxws:outInterceptors>*
  </jaxws:endpoint>
</beans>

More information

For more information about configuring endpoints using the Spring configuration see Part IV, “Configuring Web Service Endpoints”.

59.3. Adding interceptors programmatically

59.3.1. Approaches to Adding Interceptors

Interceptors can be attached to endpoints programmatically using either one of two approaches:

  • the InterceptorProvider API
  • Java annotations

Using the InterceptorProvider API allows the developer to attach interceptors to any of the runtime components that have interceptor chains, but it requires working with the underlying Apache CXF classes. The Java annotations can only be added to service interfaces or service implementations, but they allow developers to stay within the JAX-WS API or the JAX-RS API.

59.3.2. Using the interceptor provider API

Overview

Interceptors can be registered with any component that implements the InterceptorProvider interface shown in The interceptor provider interface.

The interceptor provider interface

package org.apache.cxf.interceptor;

import java.util.List;

public interface InterceptorProvider
{
    List<Interceptor<? extends Message>> getInInterceptors();

    List<Interceptor<? extends Message>> getOutInterceptors();

    List<Interceptor<? extends Message>> getInFaultInterceptors();

    List<Interceptor<? extends Message>> getOutFaultInterceptors();
}

The four methods in the interface allow you to retrieve each of an endpoint’s interceptor chains as a Java List object. Using the methods offered by the Java List object, developers can add and remove interceptors to any of the chains.

Procedure

To use the InterceptorProvider API to attach an interceptor to a runtime component’s interceptor chain, you must:

  1. Get access to the runtime component with the chain to which the interceptor is being attached.

    Developers must use Apache CXF specific APIs to access the runtime components from standard Java application code. The runtime components are usually accessible by casting the JAX-WS or JAX-RS artifacts into the underlying Apache CXF objects.

  2. Create an instance of the interceptor.
  3. Use the proper get method to retrieve the desired interceptor chain.
  4. Use the List object’s add() method to attach the interceptor to the interceptor chain.

    This step is usually combined with retrieving the interceptor chain.

Attaching an interceptor to a consumer

Attaching an interceptor to a consumer programmatically shows code for attaching an interceptor to the inbound interceptor chain of a JAX-WS consumer.

Attaching an interceptor to a consumer programmatically

package com.fusesource.demo;

import java.io.File;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;

import org.apache.cxf.endpoint.Client;

public class Client
{
  public static void main(String args[])
  {
    QName serviceName = new QName("http://demo.eric.org", "stockQuoteReporter");
    Service s = Service.create(serviceName);

    QName portName = new QName("http://demo.eric.org", "stockQuoteReporterPort");
    s.addPort(portName, "http://schemas.xmlsoap.org/soap/", "http://localhost:9000/EricStockQuote");

    quoteReporter proxy = s.getPort(portName, quoteReporter.class);

    Client cxfClient = (Client) proxy;

    ValidateInterceptor validInterceptor = new ValidateInterceptor();
    cxfClient.getInInterceptor().add(validInterceptor);

    ...
  }
}

The code in Attaching an interceptor to a consumer programmatically does the following:

Creates a JAX-WS Service object for the consumer.

Adds a port to the Service object that provides the consumer’s target address.

Creates the proxy used to invoke methods on the service provider.

Casts the proxy to the org.apache.cxf.endpoint.Client type.

Creates an instance of the interceptor.

Attaches the interceptor to the inbound interceptor chain.

Attaching an interceptor to a service provider

Attaching an interceptor to a service provider programmatically shows code for attaching an interceptor to a service provider’s outbound interceptor chain.

Attaching an interceptor to a service provider programmatically

package com.fusesource.demo;
import java.util.*;

import org.apache.cxf.endpoint.Server;
import org.apache.cxf.frontend.ServerFactoryBean;
import org.apache.cxf.frontend.EndpointImpl;

public class stockQuoteReporter implements quoteReporter
{
  ...
  public stockQuoteReporter()
  {
    ServerFactoryBean sfb = new ServerFactoryBean();
    Server server = sfb.create();
    EndpointImpl endpt = server.getEndpoint();

    AuthTokenInterceptor authInterceptor = new AuthTokenInterceptor();

    endpt.getOutInterceptor().add(authInterceptor);
  }
}

The code in Attaching an interceptor to a service provider programmatically does the following:

Creates a ServerFactoryBean object that will provide access to the underlying Apache CXF objects.

Gets the Server object that Apache CXF uses to represent the endpoint.

Gets the Apache CXF EndpointImpl object for the service provider.

Creates an instance of the interceptor.

Attaches the interceptor to the endpoint;s outbound interceptor chain.

Attaching an interceptor to a bus

Attaching an interceptor to a bus shows code for attaching an interceptor to a bus' inbound interceptor chain.

Attaching an interceptor to a bus

import org.apache.cxf.BusFactory;
org.apache.cxf.Bus;

...

Bus bus = BusFactory.getDefaultBus();

WatchInterceptor watchInterceptor = new WatchInterceptor();

bus..getInInterceptor().add(watchInterceptor);

...

The code in Attaching an interceptor to a bus does the following:

Gets the default bus for the runtime instance.

Creates an instance of the interceptor.

Attaches the interceptor to the inbound interceptor chain.

The WatchInterceptor will be attached to the inbound interceptor chain of all endpoints created by the runtime instance.

59.3.3. Using Java annotations

Overview

Apache CXF provides four Java annotations that allow a developer to specify the interceptor chains used by an endpoint. Unlike the other means of attaching interceptors to endpoints, the annotations are attached to application-level artifacts. The artifact that is used determines the scope of the annotation’s effect.

Where to place the annotations

The annotations can be placed on the following artifacts:

  • the service endpoint interface(SEI) defining the endpoint

    If the annotations are placed on an SEI, all of the service providers that implement the interface and all of the consumers that use the SEI to create proxies will be affected.

  • a service implementation class

    If the annotations are placed on an implementation class, all of the service providers using the implementation class will be affected.

The annotations

The annotations are all in the org.apache.cxf.interceptor package and are described in Table 59.2, “Interceptor chain annotations”.

Table 59.2. Interceptor chain annotations

AnnotationDescription

InInterceptors

Specifies the interceptors for the inbound interceptor chain.

OutInterceptors

Specifies the interceptors for the outbound interceptor chain.

InFaultInterceptors

Specifies the interceptors for the inbound fault interceptor chain.

OutFaultInterceptors

Specifies the interceptors for the outbound fault interceptor chain.

Listing the interceptors

The list of interceptors is specified as a list of fully qualified class names using the syntax shown in Syntax for listing interceptors in a chain annotation.

Syntax for listing interceptors in a chain annotation

interceptors={"interceptor1", "interceptor2", ..., "interceptorN"}

Example

Attaching interceptors to a service implementation shows annotations that attach two interceptors to the inbound interceptor chain of endpoints that use the logic provided by SayHiImpl.

Attaching interceptors to a service implementation

import org.apache.cxf.interceptor.InInterceptors;

@InInterceptors(interceptors={"com.sayhi.interceptors.FirstLast", "com.sayhi.interceptors.LogName"})
public class SayHiImpl implements SayHi
{
  ...
}