Apache Neethi is the WS-Policy framework for Axis2. Building on top of it would have the advantage that we don't have to re-implement any of the policy normalization and merge logic. The downside however is its dependency on the Axis2 object model. But Neethi is a very small project (< 20 files), so picking up some the ideas and implementing similar functionality in CXF seems an acceptable solution.

In any case, actual client and server side support for WS-Policy in runtime and code-generators is not part of the Neethi project and more deeply embedded in Axis: stub code generation incl. for example startSequence(), generation of configuration files to engage specific modules. This will be different in CXF, where I envision the WS-Policy framework in CXF - like other WS-* components - to be interceptor based Roughly, this is how I can see it work:

Client Side

At the client side, a PolicyEvaluationInterceptor will be added as one of the first interceptors to the chain. Its purpose will be to:

  • determine the effective policy for the underlying operation.
  • look at the different alternatives, check if a list of AssertionBuilderFactories corresponding to the alternative's assertions is available, and choose one the alternatives for which this is the case (default: the first alternative).
  • for the selected alternative, use the AssertionBuilderFactories to obtain an AssertionBuilder for each of the required assertions, and ask the AssertionBuilder to contribute its interceptors to the chain (AssertionBuilder will extend the InterceptorProviderInterface).

Server Side

On the server side, as long as we are dealing with service and endpoint specific policies, this is very similar. The PolicyEvaluationInterceptor at the begin of the inbound chain on the server side will also take care of adding any further interceptors to ensure that the requirements associated with the assertions of the effective policy are met. Although it is possible that such interceptors are subsequently removed, I'd say we can disregard that possibility for now. Maybe some time later we can make certain types of interceptors 'unremoveable'.

It gets more complicated when we consider operation or even message policies. As we have determined the operation (and its parts) only after unmarshalling, we can calculate the effective policy for the operation/message also only at this point. On the other hand, at this point we must have already executed some of the policy related interceptors, i.e. all those that read headers like the addressing and RM SOAP interceptors. Another complicating factor is that in the case of multiple policy alternatives the server has no direct knowledge about which alternative was actually chosen by the client.
The first problem can be worked around by preemptively adding the interceptors for all AssertionBuilders for the policy vocabulary used by the endpoint are added to the chain: Generalizing the definitions in the WS-Policy specification we can define the vocabulary of an endpoint to be the merged vocabulary of the policies of its operations. Example: the RM interceptors would be added to the chain even if only some of the operations on the endpoint should be reliable, and these interceptors should be made robust w.r.t. to the absence of associated headers (respective changes required in the currently implemented addressing and RM interceptors are trivial) - they simply pass the message through.
We can weaken this to initially only add such interceptors if they belong to one of the pre-MARSHALLING phases, e.g. in that case the RMSoapInterceptor. Other interceptors can be added at a later stage, [once the operation is known and according to policy vocabulary used for that operation or message.
Finally, we can only determine which requirements have been asserted at the end of the interceptor chain: the execution of an interceptor alone is not enough, nor is the presence of specific headers (although for well designed policies this should be enough). It is possible that we have to look at the header (or even message) content to check for a specific assertion. So, in order to decide at the end of the chain if everything that should have been asserted actually was asserted, we need to keep track of what was asserted by the individual interceptors. How can we do this?
At the end of the inbound chain, a PolicyVerificationInterceptor first of all computes the effective policy for that operation/message. It then iterates backwards over all interceptors executed thus far and checks which of them implement the AssertionBuilder interface, and thus can decide if the requirement for a particular assertion has been met. The candidates get then passed the set of assertions of the types known to them and return the subset of these assertions that they can assert. Now, the PolicyVerificationInterceptor can decide if all required assertions for any of the effective policy's alternatives are supported. If this is not the case, the interceptor throws an Exception.
This process can be sped up by initialising a message property with an empty list of AssertionBuilders, to which each interceptor that wants to participate in the final decision process can contribute itself (avoiding the instanceof AssertionBuilder).
The transport may be included in this decision process if it also implements the AssertionBuilder interface (see discussions on cxf-dev on class #1/class #2 assertions) (here the type check cannot be avoided though).

Supported Versions

There are several versions of the WS-Policy Framework and WS-Policy Attachment specifications out there at the moment:

September 2004:

Web Services Policy Framework
Web Services Policy Attachment

These are superseded by Version 1.2 published in April 2006:

Web Services Policy 1.2 - Framework
Web Services Policy 1.2 - Attachment

and Version 1.5 published as working draft in September 2006:

Web Services Policy 1.5 - Framework
Web Services Policy 1.5 - Attachment

CXF supports Version 1.5 (but will not initially include support for WSDL 2.0 attachments). Version 1.2 is the one supported by Neethi.

APIs

The following are tentative suggestions for the APIs as part of the CXF policy framework.

AssertionBuilder

The AssertionBuilder API is a concept from Neethi (slightly modified below as):

public interface AssertionBuilder {
   // build an Assertion object from a given xml element
   Assertion build(Element element);
  // return the schema type names of assertions understood by this builder
  Collection<QName> getSupportedTypes();
}

AssertionBuilder implementations are loaded by the <Spring container> and register themselves with the AssertionBuilderRegistry, which is a Bus extension.

Assertor

public interface Assertor {
  // return the subset of assertions that this assertor can assert
   List<Assertion> assert(List<Assertion> candidates);
}

This API would be used in the PolicyVerificationInterceptor to check which of the assertions have been asserted in order to decide if any of the policy alternatives of the effective policy is supported.
Interceptors like the RM interceptor would implement this interface, but also perhaps some transports.

AssertionInterceptorProvider

This is simply an extension of the InterceptorProvder interface:

public interface AssertionInterceptorProvider extends InterceptorProvider {
}

As with AssertionBuilders, concrete AssertionInterceptorProviders are loaded by the <Spring container> and register themselves with the AssertionInterceptorProviderRegistry, is a Bus extension.
This API would be used by the PolicyEvaluationInterceptor to dynamically add interceptors according to the needs of the effective policy (client side) or according to the potential needs (server side - as mentioned above we cannot determine the effective policy until after the operation has been determined).

All APIs must be made available in the api module.

WS-Policy vs. Configuration

Some of the schema types currently used in configuring the http and jms transports may be used as assertions. One advantage would be these types do not have to extend wsdl:tExtensibilityElement any mor. Instead the content of these elements could be verified by their respective assertion builders. Also, the types can be used much more flexibly as assertions than as extension elements registered for say the wsdl:port element only (as assertions, they can be attached to the port type or the port, the service, and even appear outside of wsdl in PolicyAttachment elements). The preferred (but not mandatory) transition would be from:

<service name="GreeterService">
    <port binding="tns:GreeterSOAPBinding" name="GreeterPort">
        <http:address xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" location="http://localhost:9020/SoapContext/GreeterPort"/>
        <http-conf:client xmlns:http-conf="http://cxf.apache.org/transports/http/configuration" ReceiveTimeout="60000"/>
    </port>
</service>

to:

<service name="GreeterService">
    <port binding="tns:GreeterSOAPBinding" name="GreeterPort">
        <http:address xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" location="http://localhost:9020/SoapContext/GreeterPort"/>
        <wsp:Policy>         
            <http-conf:client xmlns:http-conf="http://cxf.apache.org/transports/http/configuration" ReceiveTimeout="60000"/>
        <wsp:Policy>
    </port>
</service>

or:

<definition...>
    ...
    <service name="GreeterService">
        <port binding="tns:GreeterSOAPBinding" name="GreeterPort">
            <http:address xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" location="http://localhost:9020/SoapContext/GreeterPort"/>
        </port>
    </service>
</definition>

<wsp:PolicyAttachment>
    <wsp:AppliesTo>
           <wsp:URI>http://cxf.apache.org/testutils/wsdl/greeter_control.wsdl#wsdl.port(GreeterService/GreeterPort)</wsp:URI>
    </wsp:AppliesTo>
    <wsp:Policy>         
            <http-conf:client xmlns:http-conf="http://cxf.apache.org/transports/http/configuration" ReceiveTimeout="60000"/>
        <wsp:Policy>
</wsp:PolicyAttachment> 

with the PolicyAtachment element being defined in some external document.

  • No labels