The Source for Java Technology Collaboration
User: Password:



Jitendra Kotamraju

Jitendra Kotamraju's Blog

Tubes in JAX-WS 2.1

Posted by jitu on February 02, 2007 at 10:41 AM | Comments (5)

tubes.html
Few months back,  Kohsuke mentioned about Tubes in his blog JAX-WS RI goes truly asynchronous! That time, it was working only in prototypes. Now JAX-WS 2.1 runtimes completely works on Tubes. The javadoc for Tube says, "Tube is a basic processing unit that represents SOAP-level protocol handling code. Multiple tubes are often put together in a line, and act on Packets in a sequential fashion". We converted all the JAX-WS processing units to Tubes(for e.g: mustunderstand processing is done in MUTube, invocation of web sevice endpoints is done in InvokerTube etc). Most developers need not worry about creating Tubes but an advanced user or a middleware developer may care to do so. This is also a good alternative to writing Handlers while retaining the performance. But this approach is not portable as you would be using com.sun.xml.ws.api classes.

Advantages of Tubes

There are quite a few advantages in writing your own Tube for SOAP processing.
  • Tubes work on Message abstraction and has the efficient access to the payload. On the other hand, SOAP handlers wouldn't perform that well since they operate on DOM/SOAPMessages.
  • No thread need to be blocked any time and this result in high scalability. Asynchronous transport tubes can take full advantage of this aspect and scale better for asynchronous web service invocations(for e.g. Dispatch.invokeAsync()).
  • AsyncProvider endpoints scale well with asynchronous transports.
  • Request and response processing is decoupled and that means they could potentially be run by different threads.

Sample Tube to add SOAP headers

OK, say you need to add a custom header to all the SOAP response messages. To do this :
  1. Write a Tube that adds custom header to response messages.
  2. Write a TubelineAssembler to include and postion the custom Tube in the tubeline.
  3. Write a TubelineAssemblerFactory that creates these TubelineAssembler instances.

Writing a Tube

Usually, a Tube implementation would extend from AbstractFilterTubeImpl since there will be a next Tube in the processing tubeline. If your Tube is the last one in the processing tube line, it would extend from AbstractTubeImpl. Extending from these base classes is better as they provide good implementations for many methods. The javadocs provide complete information on all these things.
public class CustomTube extends AbstractFilterTubeImpl {

    protected CustomTube(Tube next) {
        super(next);
    }

    protected CustomTube(AbstractFilterTubeImpl that, TubeCloner cloner) {
        super(that, cloner);
    }

    public CustomTube copy(TubeCloner cloner) {
        return new CustomTube(this, cloner);
    }

    public NextAction processResponse(Packet packet) {
        Message message = packet.getMessage();
        if (message == null) {          // oneway
            return super.processResponse(packet);
        }
        HeaderList headers = message.getHeaders();
        QName adQName = new QName("test", "test");
        headers.add(Headers.create(adQName, "Advertisement"));
        return super.processResponse(packet);
    }

}
In the above CustomTube code
  • In the processResponse(), it gets the Message from Packet and adds a Header object.
  • Need to implement the correct copy() method. Eventhough, our Tube doesn't have any state, it needs to give a new instance since "next" tube may not be stateless. When the tubeline is copied, the copied instance is an independent tubeline without any shared tube instances among the tubelines. Also in the copy constructor, copy other instance data.
  • Need to return correct NextAction for processRequest() and processResponse() methods. The NextAction determines whether to proceed with the next Tube or processing needs to change direction etc. Use the base class AbstractTubeImpl's methods to create different NextAction return values. 

Writing a TubelineAssembler

To place our CustomTube in the tubeline, we need to write a TubelineAssembler. I pretty much copied from default assembler and added our tube in server's tubeline. This needs to be improved in our runtime so that tubeline assembly is simple and easy.

public class CustomTubeAssembler implements TubelineAssembler {   

public Tube createClient(ClientTubeAssemblerContext context) {
        Tube head = context.createTransportTube();
        head = context.createSecurityTube(head);
        head = context.createWsaTube(head);
        head = context.createClientMUTube(head);
        return context.createHandlerTube(head);
    }
    public Tube createServer(ServerTubeAssemblerContext context) {
Tube head = context.getTerminalTube();
head = new CustomTube(head);         // Add our custom tube
head = context.createHandlerTube(head);
        head = context.createMonitoringTube(head);
        head = context.createServerMUTube(head);
        head = context.createWsaTube(head);
        head = context.createSecurityTube(head);
        return head;
    }
}

Writing a TubelineAssemblerFactory

Next, we need to create TubelineAssemblerFactory that knows how to create TubelineAssemblers.
public class CustomTubelineAssemblerFactory extends TubelineAssemblerFactory {
    public TubelineAssembler doCreate(BindingID bindingID) {
        return new CustomTubeAssembler();
    }
}

JAX-WS runtime discovers TubelineAssemblerFactory using service finder mechanism. It looks for META-INF/services/com.sun.xml.ws.api.pipe.TubelineAssemblerFactory and loads the factory entry in that file. So we add com.jitu.CustomTubelineAssemblerFactory in the file META-INF/services/com.sun.xml.ws.api.pipe.TubelineAssemblerFactory

CustomTube in action

Let us create a jar customtube.jar with all the above classes and META-INF/services entry. The entries would look like:
META-INF/services/com.sun.xml.ws.api.pipe.TubelineAssemblerFactory
com/jitu/CustomTube.class
com/jitu/CustomTubeAssembler.class
com/jitu/CustomTubelineAssemblerFactory.class

If you put this jar in the classpath of the container, you would see there is an additional header in every SOAP response message
...
<S:Header><test xmlns="test">Advertisement</test> ...</S:Header>
...

You can download the source zip of the above code. In future, we will come up with an easier way to plug-in a Tube.






Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • I'm sorry but whoever came up with this class name:

    AbstractFilterTubeImpl

    needs to be slapped with the cluestick.

    Posted by: rickcarson on February 05, 2007 at 11:35 PM

  • Do you already have asynchronous transport implementations that leverage the tube/fibre design to its full extent? In DispatchImpl.invokeAsync, do you still need to submit a Future to an Executor when using asynchronous transport? I would expect that the tubeline would be able to do the callback in such a case.

    Posted by: bertr on February 14, 2007 at 03:10 AM

  • We do not have asynchronous transport on the client side. At present, we use HttpURLConnection which is synchronous. But on the server side, some projects are using asynchronous transport based on grizzly. Dispatch API specifies to create Future object, so there won't be any programming change.

    Posted by: jitu on February 15, 2007 at 12:51 PM

  • Is there any way to implement a 2-way SSL call in Jax-ws? (both ws consumer and provider are WLS 10.x instances). Is there any property where an SSLAdapter impl can be registered? It used to be there one: http://e-docs.bea.com/wls/docs100/javadocs/weblogic/wsee/jaxrpc/WLStub.html#SSL_ADAPTER

    Your sincerely
    carlo

    Posted by: cdrcdr on March 17, 2008 at 09:23 AM

  • Does it need to change CustomTube class if I want to use it in client side?

    Posted by: ozmn on April 03, 2008 at 06:00 AM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds