in Apache Fuse Cxf Interceptors Osgi ~ read.
Transparently Enriching Services with CXF Interceptors in OSGi

Transparently Enriching Services with CXF Interceptors in OSGi

Most Enterprise Architects will want to apply common to the Services in their corporation. Imagine logging, security, reliability, QoS policies, etc. [By the way, let's drop the word "Web" from Web Services when we speak about Apache CXF, as it's capable of doing so much more than just plain HTTP].

With most frameworks you'd typically end up creating lots of boilerplate code and documenting heavy guidelines so that developers know what rules to adhere to. The results are hefty deployment artefacts, developer productivity loss and a bunch problems whenever you need to change the common logic (because you may have several spots in code where to replicate that change!).

If you are using Apache CXF within OSGi, there's very good news for you! You have a powerful combination in your hands to apply magic behind the curtains on-the-fly every time a service is provisioned and de-provisioned in your OSGi environment!

In this post I will show you how to uncover this magic.

The use case

To illustrate the example, I'll take the Logging Feature from Apache CXF and establish a policy in my OSGi container so that the feature is automatically applied to all CXF Buses that get registered. Some background concepts:

  • CXF Feature: A feature in CXF is simply a grouping of CXF Interceptors. The LoggingFeature adds the LoggingInInterceptor and LoggingOutInterceptor to the interceptor chains in the bus.
  • CXF Bus according to the CXF docs: "The Bus is the backbone of CXF architecture. It manages extensions and acts as an interceptor provider. The interceptors for the bus will be added to the respective inbound and outbound message and fault interceptor chains for all client and server endpoints created on the bus (in its context)."
  • CXF Bus Registration: Every time a CXF bus is registered, by default CXF exports it as an OSGi Service to the OSGi Service Registry.
  • OSGi Service: an object that a bundle makes available to any other bundle in the OSGi container.

The solution

The solution is very simple and requires no advanced knowledge about OSGi nor digging into internals at all. All we need to do is create a new OSGi bundle that "listens" to new service registrations matching the org.apache.cxf.Bus interface.

With this solution, whenever a new CXF Bus comes to life via Apache CXF in the OSGi container, it will immediately get enriched to log all incoming requests and outgoing responses by a standard Java class with a single method that takes a CXF Bus as a parameter. As you can see, this class is completely ignorant of OSGi:

public class CXFBusListener {  
    private final static Logger LOG = LoggerFactory.getLogger(CXFBusListener.class);
    public void busRegistered(Bus bus) {
        LOG.info("Adding LoggingFeature interceptor on bus: " + bus);
        LoggingFeature lf = new LoggingFeature();
        // initialise the feature on the bus, which will add the interceptors
        lf.initialize(bus);
        LOG.info("Successfully added LoggingFeature interceptor on bus: " + bus);
    }
}

Now we'll ask OSGi to call us whenever a new service with interface org.apache.cxf.Bus appears in the container. I'll use OSGi blueprint for my IoC needs, so I create an XML file in OSGI-INF/blueprint with the following definition:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"  
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">

 <reference-list id="busListener" interface="org.apache.cxf.Bus" availability="optional">
  <reference-listener bind-method="busRegistered">
   <bean class="org.fusesource.examples.CXFBusListener" />
  </reference-listener>
 </reference-list>

</blueprint>  

And we're good to go!

Now install the bundle (make sure that the start level is lower than the CXF Services you will register later) and watch the log file for the log statements, as soon as you register new services (or if you have any existing ones already):

14:53:31,393 | INFO  | ExtenderThread-6 | CXFBusListener | 167 - cxf-transparent-interceptors - 0.0.1.SNAPSHOT | Adding LoggingFeature interceptor on bus: [email protected]  
14:53:31,397 | INFO  | ExtenderThread-6 | CXFBusListener | 167 - cxf-transparent-interceptors - 0.0.1.SNAPSHOT | Successfully added LoggingFeature  
interceptor on bus: [email protected]  

When you send a request to the Service, you will see the logging interceptors being "magically" applied even though you did not define them explicitly in the service:

-------------------------------------- 
14:56:59,732 | INFO | tp1597033892-218 | LoggingInInterceptor | - - | Inbound Message  
---------------------------- 
ID: 2  
Address: http://localhost:8181/cxf/HelloWorld  
Encoding: ISO-8859-1  
Http-Method: POST  
Content-Type: text/xml  
Headers: {Accept=[*/*], Content-Length=[236], content-type=[text/xml], Host=[localhost:8181], User-Agent=[curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5]}  
Payload: <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cxf="http://cxf.examples.servicemix.apache.org/"><soapenv:Header/><soapenv:Body><cxf:sayHi><arg0>Raul</arg0></cxf:sayHi></soapenv:Body></soapenv:Envelope>  
-------------------------------------- 
14:56:59,733 | INFO | tp1597033892-218 | LoggingOutInterceptor | - - | Outbound Message  
--------------------------- 
ID: 2  
Encoding: ISO-8859-1  
Content-Type: text/xml  
Headers: {}  
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHiResponse xmlns:ns2="http://cxf.examples.servicemix.apache.org/"><return>Hello Raul</return></ns2:sayHiResponse></soap:Body></soap:Envelope>  
-------------------------------------- 

And voilà!

Source code available here: https://github.com/raulk/cxf-transparent-interceptors.

NOTE: As Dan Kulp indicated in the original blog comments (now gone): "If using CXF 2.6.x, it can be even easier. By default with CXF 2.6.x, when a Bus is created by OSGi, it looks in the Service registry for any service that implements org.apache.cxf.feature.Feature and will automatically apply those to the bus. Thus, you don't need the CXFBusListener at all. Just register your feature as a service."

  • Email
  • Facebook
  • Twitter
  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket
comments powered by Disqus