dev@jax-ws.java.net

Re: Splitting Handler processing into two pipes

From: Kohsuke Kawaguchi <kohsuke.kawaguchi_at_sun.com>
Date: Fri, 23 Dec 2005 12:05:09 -0800

CC-ing Roberto to clarify the close method semantics.

Bobby Bissett - Javasoft wrote:
>> I'm also curious what aspect of handler processing makes such splitting
>> difficult. So if you could shed some light in this area, that would be
>> great.
>
> It would be a little ugly. Even without any exceptions or handlers
> returning false, consider the client receiving a response. First the
> soap handlers are called, then the logical handlers, then close() is
> called again on the soap handlers, then close() is called on the logical
> handlers. So we'd switch from one pipe to another 3 times during an
> inbound response or inbound one-way request (which can be even more
> complicated because we may not know that it's one-way until after the
> handlers execute). If there are any exceptions or if a handler returns
> false, then there are other situations where the switching occurs.

I see, so the close method of protocol handlers need to be invoked after
the processing of logical handlers are done?

I'm reading the relevant part of the spec, and I wonder if that's really
a requirement. If the goal is to let handlers clean up any per-MEP
resources, wouldn't it be OK to call the close method on protocol
handlers at the point where we won't be calling any of them any more?
--- namely when the processing leaves the protocol handler pipe?

Unless we expect someone to write both protocol handler and logical
handler that interacts with each other, I'm not sure why the close
method invocation timing matters.

> Give this a look:
> https://jax-ws-sources.dev.java.net/source/browse/jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/handler/HandlerChainCaller.java?rev=1.23&view=markup
> ..and search for the text "reverse" for example to see how many ways we
> can change direction.

Besides the timing of the close method, many of them seem to follow the
following pseudo-code:

class LogicalHandlerPipe {
   LogicalHandler handler;
   Pipe next;

   Message process(Message msg) {
     try {
       if(!handler.handleMessage(msg))
         return msg;
     } catch(ProtocolException e) {
       // so that handleFault is called for other handlers
       return new ExceptionFaultMessage(e);
     } catch(RuntiemException e) {
       // so that handleFault is *not* called for other handlers
       throw new WebServiceException(e);
     }

     msg = next.process(msg);
     if(!msg.hasProperty(NO_MORE_HANDLER_PROCESSING)) {
       try {
         if(!(msg.isFault()?
              handler.handleFault(msg):handler.handleMessage(msg))) {
           // aha, this is where it gets ugly! but how about ...
           msg.setProperty(NO_MORE_HANDLER_PROCESSING);
         }
       } catch(ProtocolException e) {
         msg.setProperty(NO_MORE_HANDLER_PROCESSING);
         return new ExceptionFaultMessage(e);
       } catch(RuntimeException e) {
         msg.setProperty(NO_MORE_HANDLER_PROCESSING);
         return new ExceptionFaultMessage(e);
       }
     }

     handler.close();

     return msg;
   }
}

(I made a simplification that I'm passing Message directly to handleXXX
methods, and I made another simplification that one handler occupies one
pipe, but neither is fundamental, I think.)

Is the above pseudo-code wrong in certain scenarios?


> It can be done, but we would need the pipes to be able to communicate
> with each other. For instance, they would need to be able to tell each
> other to call handleMessage, call handleFault, or "close your handlers
> and then tell me when you're done" depending on what was going on. The
> code in between the two pipes would need to pass this information along.
> It can be done, but may offset the "nice design" factor that you mention.

Having pipes to do private communications are OK; especially if those
pipes do need to interact, as in this case. Pipes can be created with
reference to each other. What I'd hate is that this significantly
complicates such pipe implementations.

I'm still hoping that my above pseudo-code works.

> As a possible alternative, see:
> https://jax-ws-sources.dev.java.net/source/browse/jax-ws-sources/jaxws-ri/rt/src/com/sun/xml/ws/handler/SOAPHandlerContext.java?rev=1.5&view=markup
>
> You see that it has methods for getting a SOAP or a logical message
> context. This class could keep a flag denoting whether the last request
> was soap or logical. If someone calls getSOAPMessageContext and the flag
> is set to "logical" (or vice versa), then you know you're between the
> two types of handlers and can execute some extra code. However, that may
> be one of the not-so-nice ways of which you have already thought.

No, I haven't realized that that's possible, and I haven't heard from
anyone else about this idea until now.

> As a side note, if the handler chain caller code looks a little
> unwieldy, check out the handler execution section of the spec for the
> details of what happens when. At one point, there were three types of
> handlers, not two, so there may be some separation in that file that
> isn't needed anymore but wasn't removed.

Thanks. Having both spec and code side-by-side helps me.

-- 
Kohsuke Kawaguchi
Sun Microsystems                   kohsuke.kawaguchi_at_sun.com