Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Clarified interceptor documentation a bit. Anybody sees any mistakes, please correct.

...

Interceptors are the fundamental processing unit inside CXF. When a service is invoked, an InterceptorChain is created and invoked. Each interceptor gets a chance to do what they want with the message. This can include reading it, transforming it, processing headers, validating the message, etc.

Interceptors are relevant for used with both CXF clients and CXF servers. When a CXF client invokes a CXF server, there is an outgoing interceptor chain for the client and an incoming chain for the server. When the server sends the response back to the client, there is an outgoing chain for the server and an incoming one for the client. Additionally, the service will create a separate error handling interceptor chain in the case of SOAPFaults.

Some examples of interceptors inside CXF include:

  • SoapActionInterceptor - Processes the SOAPAction header and selects an operation if its it's set.
  • StaxInInterceptor - Creates a Stax XMLStreamReader from the transport input stream.
  • Attachment(In/Out)Interceptor - Turns a multipart/related message into a series of attachments.

InterceptorChains are divided up into Phases. Each phase contains may contain many interceptors. On the incoming chains, you'll have the following phases:

...

Code Block
java
java
public interface InterceptorProvider {

    List<Interceptor> getInInterceptors();

    List<Interceptor> getOutInterceptors();

    List<Interceptor> getOutFaultInterceptors();

    List<Interceptor> getInFaultInterceptors();
}

To get add an interceptor added to the an interceptor chain, you'll want to add it to one of the Interceptor Providers.

...

Writing and configuring an Interceptor

The CXF distribution is shipped with a demo called configuration_interceptor , this demo which shows you how to develope an develop a user interceptor and add configure the interceptor into the its interceptor chain through configuration.

Writing an Interceptor

Writing an interceptor is relatively simple. Your interceptor needs to extend from either the AbstractPhaseInterceptor or some one of its sub-classes many subclasses such as AbstractSoapInterceptor. Extending from AbstractPhaseInterceptor allows your interceptor to access the methods of the Message class interface. For example, AttachmentInInterceptor is used in CXF to turn a multipart/related message into a series of attachments. It looks like below:

...

Extending from sub-classes of AbstractPhaseInterceptor allows your interceptor to access more specific information than those in the Message classinterface. One of the sub-classes of AbstractPhaseInterceptor is AbstractSoapInterceptor, extending from AbstractSoapInterceptor makes . Extending from this class allows your interceptor being able to access the SoapMessage class which contains SOAP headers and version etcSOAP?header and version information of the SoapMessage class. For example, SoapActionInInterceptor is used in CXF to parse the SOAP action, as a simplified version looks like of it shows below:

Code Block
java
java
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.cxf.binding.soap.Soap11;
import org.apache.cxf.binding.soap.Soap12;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.model.SoapOperationInfo;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.OperationInfo;

public class SoapActionInInterceptor extends AbstractSoapInterceptor {

    public SoapActionInInterceptor() {
        super(Phase.READ);
        addAfter(ReadHeadersInterceptor.class.getName());
        addAfter(EndpointSelectionInterceptor.class.getName());
    }

    public void handleMessage(SoapMessage message) throws Fault {
        if (message.getVersion() instanceof Soap11) {
            Map<String, List<String>> headers = CastUtils.cast((Map)message.get(Message.PROTOCOL_HEADERS));
            if (headers != null) {
                List<String> sa = headers.get("SOAPAction");
                if (sa != null && sa.size() > 0) {
                    String action = sa.get(0);
                    if (action.startsWith("\"")) {
                        action = action.substring(1, action.length() - 1);
                    }
                    getAndSetOperation(message, action);
                }
            }
        } else if (message.getVersion() instanceof Soap12) {
          ...........
        }
    }

    private void getAndSetOperation(SoapMessage message, String action) {
        if ("".equals(action)) {
            return;
        }

        Exchange ex = message.getExchange();
        Endpoint ep = ex.get(Endpoint.class);

        BindingOperationInfo bindingOp = null;

        Collection<BindingOperationInfo> bops = ep.getBinding().getBindingInfo().getOperations();
        for (BindingOperationInfo boi : bops) {
            SoapOperationInfo soi = (SoapOperationInfo) boi.getExtensor(SoapOperationInfo.class);
            if (soi != null && soi.getAction().equals(action)) {
                if (bindingOp != null) {
                    //more than one op with the same action, will need to parse normally
                    return;
                }
                bindingOp = boi;
            }
        }
        if (bindingOp != null) {
            ex.put(BindingOperationInfo.class, bindingOp);
            ex.put(OperationInfo.class, bindingOp.getOperationInfo());
        }
    }

}

You may also want to specify what phase your interceptor is will be included in. To do this, you can simply set the phase:

...

Adding interceptors through configuration

//TODO add the configuration file informationThe configuration file page provides examples on using configuration files to add interceptors.

Adding MyInterceptor to the bus:

Code Block
java
java
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cxf="http://cxf.apache.org/core"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">

    <bean id="MyInterceptor" class="demo.interceptor.MyInterceptor"/>

    <!-- We are adding the interceptors to the bus as we will have only one endpoint/service/bus. -->

    <cxf:bus>
        <cxf:inInterceptors>
            <list>
                <ref bean="MyInterceptor"/>
            </list>
        </cxf:inInterceptors>
        <cxf:outInterceptors>
            <list>
                <ref bean="MyInterceptor"/>
            </list>
        </cxf:outInterceptors>
    </cxf:bus>
</beans>

You start your server using For embedded Jetty-based web services, the configuration file can be declared by starting the service with the -Dcxf.config.file=server.xml to specify option. See the server configuration section on the configuration file page for information on specifying the file for servlet WAR file-based web service implementations.

Adding MyInterceptor to your client:

Code Block
java
java
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:http="http://cxf.apache.org/transports/http/configuration"
       xsi:schemaLocation="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">

    <http:conduit name="{http://apache.org/hello_world_soap_http}SoapPort9001.http-conduit">
      <http:client DecoupledEndpoint="http://localhost:9990/decoupled_endpoint"/>
    </http:conduit>

    <bean id="MyInterceptor" class="demo.interceptor.MyInterceptor"/>

    <!-- We are adding the interceptors to the bus as we will have only one endpoint/service/bus. -->

    <bean id="cxf" class="org.apache.cxf.bus.CXFBusImpl">
        <property name="inInterceptors">
            <list>
                <ref bean="MyInterceptor"/>
            </list>
        </property>
        <property name="outInterceptors">
            <list>
                <ref bean="MyInterceptor"/>
            </list>
        </property>
    </bean>
</beans>

You To specify the client-side configuration file, start your client using the -Dcxf.config.file=client.xml to specify the configuration fileoption.