Friday, August 10, 2007

More than meets the eye, or JAX-WS and the not so obvious interfaces.

I really enjoy using JAX-WS I have only come to web services relatively recently but I have found the programming model to be relatively easy to use. Certainly removing the need to create n xml mapping files has made the developer's life much easier.

One problem I have with the design of JAX-WS it the way that you end up having to cast common objects to other helper interfaces. Now most of the implementation is done using proxies so in most debuggers you are going to have a hard time understanding the objects you are passed. Lets just knock up a quick method to list all the interfaces for a bit of debugging:

public class Util
    public static void dumpInterfaces(Class t)
       System.out.println("=== Interfaces for " + t.getSimpleName());
       List interfaces = new ArrayList();
       for (int i=0; i < interfaces.size(); i++) {
           Class it = interfaces.get(i);
           for (Class sp : it.getInterfaces()) {
               if (!interfaces.contains(sp))
       // List them out
       for (Class sp : interfaces)

    public static  void dumpMap(String name, Map map) 
        System.out.println("=== " + name);
        for(Map.Entry e : map.entrySet()) {
            System.out.println(e.getKey() + " : " + e.getValue());

On the server side lets take a look at what interfaces that might not otherwise be obvious, take this simple web service example:

public class Hello {
    private WebServiceContext context;
    public String sayHello(String name) {
        Util.dumpMap("Dumping message context properties",context.getMessageContext());        
        return "Hello " + name;

This gives the following output for the interfaces. The web service context is less interesting that the message context. This can be cast to SOAPMessageContext which can give you access to the original SOAP message along with the headers. This is an alternative to using Handlers in order to process headers.

=== Interfaces for WebServiceContextImpl
=== Interfaces for SOAPMessageContextImpl

The since the message context is also a map it is relatively easy to list all of the properties defined in there. Here is what I see when I run the service defined above. Part of the problem with JAX-WS is that these properties are extensible so it is hard to get a definitive list of all of them. Something for a future blog I think.

=== Dumping message context properties : {} : null : amespace= : Application1-Project1-webapp web-app : null : null : null : com.evermind.server.http.EvermindHttpServletRequest@109b23b : : {} : com.evermind.server.http.EvermindHttpServletResponse@1c0bec5 : {SOAPACTION=[""], CONNECTION=[Keep-Alive, TE], CONTENT-LENGTH=[202], USER-AGENT=[Oracle HTTPClient Version 10h], TE=[trailers, deflate, gzip, compress], ACCEPT-ENCODING=[gzip, x-gzip, compress, x-compress], CONTENT-TYPE=[text/xml; charset=ASCII], HOST=[localhost:8988], ECID-CONTEXT=[HIINUXQV`[YegG@DKKGSLNWWZZ[Zbef@BKCAGSLNS[TQ]} : POST : false

We can do something similar with the on the client side, so if we were to create a simple client:

public class Client {
    public Client() {
    public static void main(String argv[]) {
        HelloService hs = new HelloService();
        Hello h = hs.getHelloPort();
        BindingProvider bp = (BindingProvider)h;
        Util.dumpMap("Request context",bp.getRequestContext());
        Util.dumpMap("Response context",bp.getResponseContext());

We can see that the port is implemented using a proxy object that implement both the SEI and the BindingProvider interface. The BindingProvider interface is perhaps not that much of a secret, although I would have thought that a more usable design for the client generation would have seen the SEI extend this interface to make the programming model cleaner.

=== Interfaces for $Proxy12
=== Interfaces for SOAPBindingImpl
=== Request context : {}
=== Response context

It is worth noting that again there is a SOAP variant that you need to cast to in order to get all of the functionality available to you. Of course you have to be careful that you understand the context of your service. For example if you were to using the HTTP binding than the Binding object would of course be HTTP not SOAPBinding.

Finally where I have dumped out a the contents of a map, these represent the current state when running on an interim build of OC4J 11. As noted before there are many more properties that are available that can be added depending on what platform and extensions you are using.

Update: A nice summary document for the standard MessageContext and BindingContext parameters can be found here.

No comments: