users@jax-rpc.java.net

Re: Handling mustUnderstand Headers

From: Kevin Jones <kevinj_at_DEVELOP.COM>
Date: Thu, 02 Oct 2003 18:07:32 +0100

Bobby,

> I'll try to answer your other email about "no actor" here to save some
> inbox space. Even if you specify no roles in your xml files when
> generating the handlers, the special soap actor
> "http://schemas.xmlsoap.org/soap/actor/next" will be included for all
> soap intermediaries.

This is an RI thing right? As I understand the soap spec if there is no
actor the 'next' actor isn't assumed, in fact SOAP 1.2 explicitly adds a
new role "http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver"
and states

'Omitting the SOAP role attribute information item is equivalent to
supplying that attribute with a value of
"http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver".'
(http://www.w3.org/TR/soap12-part1/#soaprole)


> So you can't exactly have *no* role in a handler, but the question of
> your other email was then how to have the handler act as the ultimate
> recipient of the message. You can do this and circumvent the
> endpoint by
> having your handler return false from the handleRequest() method. This
> will skip the rest of the processing of the request,
> including the rest
> of the handler chain and the endpoint. You must still handle the
> response, except that now you need to manually create the response
> message since the endpoint won't do it. You can see it in
> action: throw
> an "if (true) return false;" at the top of your
> handleRequest() method.
> You will then see errors downstream in handleResponse or at the client
> since you're returning an unusual message -- in fact, you're returning
> the request if you do nothing else. But the endpoint won't be invoked.
> So this gives you a way to cut the endpoint out of the app at the
> handler level.

Sure, I understand that. I guess what I wanted was to have a handler and
the endpoint to act together as 'ultimate receiver', so that the handler
handles the 'no actor' headers and the endpoint does the message
processing.

> It would be easier in some cases if the runtime removed the
> element for
> you, but might be unduly limiting. The whole system of roles/actors,
> header names and mustUnderstand is used to determine whether
> or not the
> message will be processed or sent back with a MustUnderstand
> fault, but
> it doesn't affect what you actually do inside the handler.
> One specific
> case where this matters is if you have two handlers that are
> in the same
> role and both say that they understand the same header. In some cases,
> the first handler may want to let the header element go through
> unchanged (*), and in some cases it may want to detach it and
> then pass
> the message on. Obviously, there's no rule that says you have to be
> given a header that you declare that you understand. So while your
> handler declares that it understands headers and wants to handle ones
> targeted at certain roles, it is still up to the user to fufill the
> handler contract and do the right thing in the code.

I didn't expect the runtime to remove the header, I assumed that the
behaviour for 'no actor' handlers to be the same as the behaviour for
'actor' handlers. If I add a handler for a specific actor I need do
nothing in the handler to remove any mustUnderstand headers so long as I
explicitly return that header's QName from the getHeaders call, this
behaviour is different from a 'next' handler where I have to explicitly
detach the header even if I return the QName of that header from
getHeaders. i.e. for 'actor' handlers, returning the QName implicitly
marks the header as understood, for 'next' handlers returning the QName
isn't enough, the header also has to be removed.

> (*) That statement may sound like I'm contradicting my last email, but
> there is an allowance for it: The soap spec says that an intermediary
> should remove the header element that was targeted at it, but the spec
> allows for the concept of a contract between an intermediary and a
> following intermediary or endpoint to have a header with the same name
> in it (and the same content as well if you'd like). Here's the text:
> "[...] a recipient receiving a header element MUST NOT forward that
> header element to the next application in the SOAP message path. The
> recipient MAY insert a similar header element but in that case, the
> contract is between that application and the recipient of that header
> element." And if a header element just happens to be "similar" to
> itself, then the handler's job is easy...

Yes, this section has always made me smile :)

> I may be misunderstanding the question, so let me know if I am. If you
> set up a handler with no actor at all, it will still be an
> actor in the
> "next" role, and so all headers can be targeted at it either
> explicitly
> or implicitly (a header element with no actor in it is targeted at the
> "next" intermediaries). So you can have a handler that declares it
> understands a certain header and not declare that it's in any
> particular
> role.

See the point above about returning the QName from getHeaders

> It's still being returned back to the client as response (or
> fault), so
> the handler chain is still used. This can be pretty useful in
> some cases
> -- imagine that you want to encode/decode the message payload whether
> it's a good response or an error. You'll short-circuit the
> handler chain
> (in whatever direction the message is going) if either a
> handler returns
> false or throws an exception.

Except that again the processing of 'actor' headers is different from
'next' headers. 'Actor' headers never even get into the processing
chain if I have no handler declared as processing them. 'next' headers
always traverse the entire request and response chains even if I have a
chain associated with 'next' (no role attribute) and a handler in that
chain states that it processes the message (returns the QName from
getHeaders).

It seems to me that the processing is inconsistent. What I think it
should do (but what do I know) is this:

1. If there is a mustUnderstand header for an actor/role, look for a
chain to process that role and a handler (or handlers) to process that
message (via a call to getHeaders). If there is none don't enter the
chain instead throw an exception
2. If there is a mustUnderstand header with no actor/role, look for a
chain associated with 'no role' (the 'next' role) and a handler for that
message (via a call to getHeaders). if there is none, don't enter the
chain instead throw an exception

This relies on handlers behaving themselves of course, i.e. all handlers
get to see all headers so any handler in any chain can remove any header
so a 'down chain' handler even for a mustUnderstand header may not even
get to see the header, although this is always true regardless of the
processing model used :)

Thanks for answering the previous mails Bobby,

Kevin Jones
Developmentor
www.develop.com