Skip to main content

Tubes in JAX-WS 2.1

Posted by jitu on February 2, 2007 at 10:41 AM PST




http-equiv="content-type">
tubes.html




Few months back,   href="http://weblogs.java.net/blog/kohsuke">Kohsuke
mentioned about href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/Tube.html">Tubes
in his blog href="http://weblogs.java.net/blog/kohsuke/archive/2006/08/jaxws_ri_goes_t.html">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 href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/message/Packet.html">Packets
in a sequential fashion". We converted all the JAX-WS processing units
to
Tubes(for e.g: mustunderstand processing is done in href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/protocol/soap/MUTube.html">MUTube,
invocation
of web sevice endpoints is done in href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/server/InvokerTube.html">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 href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/message/Message.html">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()).
  • href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/server/AsyncProvider.html">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 href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/Tube.html">Tube
    that adds custom header to response messages.
  2. Write a href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/TubelineAssembler.html">TubelineAssembler
    to include and postion the custom Tube in the tubeline.
  3. Write a href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/TubelineAssemblerFactory.html">TubelineAssemblerFactory
    that creates these TubelineAssembler instances.

Writing a href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/Tube.html">Tube

Usually, a href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/Tube.html">Tube
implementation would extend from
href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/helper/AbstractFilterTubeImpl.html">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 href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/helper/AbstractTubeImpl.html">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 href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/message/Message.html">Message
    from href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/message/Packet.html">Packet
    and adds a href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/message/Header.html">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 href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/NextAction.html">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 href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/helper/AbstractTubeImpl.html">AbstractTubeImpl's
    methods to create different href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/NextAction.html">NextAction
    return
    values. 

Writing a href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/TubelineAssembler.html">TubelineAssembler

To place our CustomTube in the tubeline, we need to write a href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/TubelineAssembler.html">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 href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/TubelineAssemblerFactory.html">TubelineAssemblerFactory

Next, we need to create href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/TubelineAssemblerFactory.html">TubelineAssemblerFactory
that knows how to create href="https://jax-ws-architecture-document.dev.java.net/nonav/doc21/com/sun/xml/ws/api/pipe/TubelineAssembler.html">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 href="http://weblogs.java.net/blog/jitu/archive/customtube.zip/customtube.zip">source
zip of the above code. In future, we will come up with an
easier way to plug-in a Tube.



Related Topics >>

Comments

Tubes in JAX-WS 2.1

Hi Jitendra Kotamraju:
As you can modify or acess the body messages in processRequest? How is possible?
Thanks.