CXF, Spring, and WS-Policy Internals
April 23rd, 2007As we near our CXF 2.0-RC release (we’re cutting it today hopefully!), I want to spend a bit more time on my blog talking about CXF, some of the unique things I think we’ve done, and why you should consider it for your projects. Consider this part 1 of n :-).
In CXF we’ve taken the philosophy that we want to leverage the containers and appservers that are out there. Our primary container that we support is Spring. We can also run without Spring, but then you miss out on some of the features.
One of the big new things in Spring 2 is its support for custom XML snippets, meaning we can mix and match any XML types inside a spring config. We’ve added support for configuring clients and servers via this mechanism. Here’s an example of what configuring a JAX-WS endpoint looks like:
<jaxws:endpoint id="helloWorld" class="com.acme.HelloWorld" addressing="http://localhost/helloworld"/>
We expanded this functionality to support various “features” which you can plugin to your service. Features are simply classes which can customize your Server/Client at load time. For instance, I wrote a simple logging feature:
<jaxws:endpoint id="helloWorld" class="com.acme.HelloWorld" addressing="http://localhost/helloworld">
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature"/>
</jaxws:features>
</jaxws:endpoint>
Notice that you can easily mix & match the Spring syntax and our own jaxws:endpoint syntax. This helps the user as they can leverage the Spring syntax they already know. It also helps developers as it makes creating extensions pretty easy - no XML parsing needed and no schemas need to be written.
CXF and WS-Policy
Before we continue, I’d like to explain a little bit about CXF supports WS-Policy. With WS-Policy I can assert various policies on my service - like that it needs to be using WS-Addressing or it should be using WS-ReliableMessaging. Within CXF there are two things associated with each type of assertion - an AssertionBuilder and a PolicyInterceptorProvider. The AssertionBuilder is responsible for building Assertions classes from XML. The Assertion class is from the Apache Neethi project which provides us with a nice API for working with WS-Policy.
The PolicyInterceptorProvider is where the magic comes in. It allows you to supply interceptors to the CXF message processing chain for whenver your policy is active. For instance, say you are writing support for the <UsingAddressing/> assertion. Then you can have a PolicyInterceptorProvider which provides WS-Addressing Interceptors which get added dynamically to the chain if the policy is active. This means you only have to configure WS-Policy - you don’t have to also configure your service’s interceptors for WS-Addressing.
Bringing together WS-Policy and Spring
The above lays a foundation for simple configuration via WS-Policy. All that you need to do is simply write an assertion for your service and it will get configured correctly (that is, the assertion’s interceptors will be added to interceptor chain).
This merges really well with the Feature framework. We wrote a WSPolicyFeature which understands <Policy> documents embedded inside your <jaxws:endpoint> definition.
<jaxws:endpoint id="helloWorld" class="com.acme.HelloWorld" addressing="http://localhost/helloworld">
<jaxws:features>
<wsp:Policy xmlns:wsp="http://www.w3.org/2006/07/ws-policy"
xmlns:wsam="http://www.w3.org/2007/01/addressing/metadata">
<wsam:Addressing>
<wsp:Policy />
</wsam:Addressing>
</wsp:Policy>
</jaxws:features>
</jaxws:endpoint>
Since this is still Spring, the <Policy> element becomes a WSPolicyFeature Spring bean which you can reference anywhere else inside your code. We simply use the Id attribute on the Policy. This makes it very easy to share Policy configurations across endpoints inside a spring file:
<jaxws:endpoint id="helloWorld" class="com.acme.HelloWorld" addressing="http://localhost/helloworld">
<jaxws:features>
<ref bean="AddressingPolicy"/>
</jaxws:features>
</jaxws:endpoint>
<wsp:Policy wsu:Id="AddressingPolicy"
xmlns:wsp="http://www.w3.org/2006/07/ws-policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsam="http://www.w3.org/2007/01/addressing/metadata">
<wsam:Addressing>
<wsp:Policy />
</wsam:Addressing>
</wsp:Policy>
You can of course do policy attachments and what not as well, but I’m just focusing on the Spring part of things for now.
More Spring Configuration Coolness
One of the other cool things about this is that we can also apply this configuration to an Endpoint I’ve created via the API through Spring’s AOP mechanisms. For instance, when you create a JAX-WS Endpoint, interally CXF calls into Spring and configures your Endpoint. It finds the appropriate <endpoint> definition using the service’s name. Here’s a sample of a configuration that could be applied to your service:
<jaxws:endpoint id="{http://my.service.namespace}ServicePort" createdFromAPI="true">
<jaxws:features>...</jaxws:features>
</jaxws:endpoint>
Closing Thoughts
All in all, this makes me much more likely to use WS-Policy than I ever thought I would be predisposed to before. I don’t have to write extra XML files and WS-Policy automatically configures features like Addressing, RM, and soon MTOM as well. Much of the credit here goes to Andrea Smyth for doing the WS-Policy layer the AOP configuration stuff. It all looks very cool!
April 23rd, 2007 at 5:36 am
Nice work indeed by Andrea and Fred in integrating Apache WSS4J and Apache Neethi for providing WS-Security and WS-Policy support.