Okay, I'm going to reply to my own message, because after a coffee I
have come to some nirvana about this issue.
The reason you want an onFinish() call is to address the subchain
problem. In one of the emails below it is stated:
A. MessageSenderInterceptor: call conduit.close(message) after
the complete chain has been traversed.
I presume that you want A.handleMessage() to be called to do some things
(like install more interceptors) and then after everything has been done
to the message, you want A.onFinish() called to call conduit.close(message).
My basic question is, why isn't the conduit.close(message) called in a
separate interceptor's handleMessage() call?
Why is there a need for onFinish() at all? If we say that interceptors
*should* be stateless (except for the state saved on the message), then
we should just have one forward moving interceptor chain, calling just a
handleMessage() on each. Yeah, you have to be a little more prudent with
saving state on the message map to get done what you want to do, but
that was the suggestion, was it not?
I still believe that doIntercept(), and the doInterceptInSubchain calls
should be eliminated.
That will also reduce the number of calls needed to get the message out,
such as opposed to calling onFinish on interceptors that don't care. And
it reduces stack space as none gets to call doIntercept() and wait for
it to return.
One should look at the interceptor Phases, and declare certain
invariants should hold for each phase (giving the phases some definite
meaning). For example in the SEND phase, the message is guaranteed to
have been totally sent, and any interceptors in that phase should
require this event to happen.
Cheers,
-Polar
Polar Humenn wrote:
Liu, Jervis wrote:
You are right in saying statelessness is only a sufficient condition.
But I would say it is recommended that the CXF interceptors are
implemented as statelessness unless the developer are fully aware of
the implication of writing a stateful interceptor as our current
interceptor calling semantics are not enough to guarantee thread
safety in this case.
Exactly, so the call semantics have to be nailed down, documented and
adhered to. What are the intended invariants on each call?
....
I don't like the idea of an onFinish(Message) because it requires me
to *wait* in my interceptor to make sure that my message popped out
the other end. The handleFault() which is the result of an
interceptor thrown Fault, gives me the "exception" to my
*assumption* that the message will pop out the other end. Assuming
messages make it out or in is the most abundant normal case.
onFinish() was proposed to address the subchain issue, i.e., we want
the interceptor has the capability to register some sort of terminal
actions with the InterceptorChain to be executed when the chain
traversal is complete, more details on this discussion can be found
from [1] [2] [3]. onFinish is not designed to address fault handling
issues.
Okay, so I read what was below. I was not yet familiar with the
subChain semantics, but now I am getting it. I see some problems with
the subChain semantics (which are below), and I almost grasp what you
are looking for, which may alleviate my concerns, so please correct
me if am totally off base.
The goal of an outbound message is to get from the application to the
wire,
Application ----> Wire
is it not? Interceptor traversal happens on that arrow. An interceptor
chain is NOT *finished* until that message is out on the wire, (unless
some fault occurs). Correct?
Application ---- InterceptorChainTraversal ----> Wire
The basic requirement you are looking for is to have some backward
actions planned after the chain is traversed in one direction to do
some clean up, or write end messages, trade output streams, in the
backward direction. Correct?
I understand from your explanation of the SoapOutHandler interceptor
in [1], than on the proposed onFinish() call that the message hasn't
yet been written to the wire, but is about to be written (after adding
ending tags, etc). Finally the at the end the MessageSenderInterceptor
calls the "conduit.close(message)", which I presume actually writes
the message out on the wire.
I surmise that the interceptor chain is NOT *finished* at the last
interceptor in the chain, because the intended goal of the interceptor
chain is to get the message out on the wire, and that has not been
achieved.
I believe you really want is to describe a two phase interceptor
traversal to *complete* the chain. I realize the the execution trace
would be the same, yet the proverbial semantics are subtly different
(maybe suggesting different name for the operations).
For an interceptor chain of A,B,C,D we would get the following execution.
Application ---- A, B, C, D, D, C, B, A -> Wire
Is this the trace you intend? I suggest on the backward trace that the
interceptor is still "handling" the message. Therefore, I would
suggest different names.
interface Interceptor<T extends Message> {
void handleMessageP1(T message);
void handleMessageP2(T message);
// fault handing is another topic.
}
Where P1 and P2 distinguish the "forward" phase and the "backward"
phase of message handling, respectively. Suggestions?
Now, for my concerns about the subchain logic;
The doInterceptInSubChain and finishSubChain is a way for two
interceptors to communicate (that coordinated with each other), yet
have the unknowing possibly of being subverted by other injected
interceptors in unfortunate places that call doInterceptSubChain and
finishSubChain as well, and thereby two seemingly coordinated
interceptors are mis-coordinated.
I surmise that this approach will eliminate the need
for"doInterceptSubChain" and "finishSubChain" calls, and also will
eliminate ability to call "doIntercept" for anything but the CXF
internal processing (i.e. interceptors cannot call it).
As far as the fault handling is concerned, I agree with you that our
current fault handling logics are bit confusing. This has been raised
by Eoghan couple months ago, see [4]. Can I suggest we separate this
thread into two topics? One is the proposal of adding onFinish() into
interceptor interface, which is to address subchain and terminal
actions issues. One is about the fault handling. For the former, I
would like to see if there are any objections? If there is no
different voice, at least we can start working on this and keep our
discussion for the later going until it is fully baked.
I agree. We should discuss on another thread.
Cheers,
-Polar
[1].
http://mail-archives.apache.org/mod_mbox/incubator-cxf-dev/200701.mbox/[EMAIL PROTECTED]
[2].
http://mail-archives.apache.org/mod_mbox/incubator-cxf-dev/200701.mbox/[EMAIL PROTECTED]
[3].
http://mail-archives.apache.org/mod_mbox/incubator-cxf-dev/200701.mbox/[EMAIL PROTECTED]
[4]
http://mail-archives.apache.org/mod_mbox/incubator-cxf-dev/200611.mbox/[EMAIL PROTECTED]
Unfortunately, after a discussion with Eoghan, I find that some
interceptor chains are just not completed. If that is the case, when
or if would you call "onFinish()"?
I would suggest:
void handleMessage(Message m) throws Fault;
void handleFault(
Message m, String phase, String interceptor, Fault f
);
naming the phase and interceptor that threw the particular fault.
or maybe even
class InterceptorFault {
String phase; String interceptor; Fault fault;
}
void handleFault(
Message m, List<InterceptorFault> faults
) throw Fault;
which allows handleMessage to throw a fault, and handleFault() to
throw Faults, but is given a list of faults and the names of
interceptors that throw them back along the way. The chain collects
Faults and adds the faults to the list.
Cheers,
-Polar
Liu, Jervis wrote:
Hi Polar, comments in-line.
Cheers,
Jervis
-----Original Message-----
From: Polar Humenn [mailto:[EMAIL PROTECTED]
Sent: 2007?2?7? 6:05
To: [email protected]
Subject: Re: Proposal for chaning CXF Interceptor APIs. WAS: RE:
When should we close the handlers in CXF?
I'm still trying to find out how this interceptor stuff works. So
forgive me if I seem naive. :-[
You say CXF interceptors are stateless. Are you saying that
"statelessness" is a requirement to be a CXF interceptor?
Or are you
saying that the processing interceptors that are currently used in
CXF are stateless and that's all that need to be supported?
I can definitely see a use case for CXF interceptors maintaining
state.
A simple one is an outbound message counter. The interceptor
increments a counter on handleMessage() assuming the message makes
out the end (has no way of knowing). So the interceptor must
decrement its
counter on
handleFault() because that tells the interceptor that the message
never made it out the end because of some interceptor downstream
in the chain.
Once interceptors are created (eg, in
SoapBindingFactory.java), their instances are shared across all
interceptor chains and threads. Interceptors have to be stateless
for the sake of thread safe. If you really have to have some states
that you want to be shared among interceptors, you can put them into
Message.
So, if I have this right, what you are proposing is to alter the
semantics, and only call this onFinish() method on the unwind
chain when the message makes finally makes it out the end of the
chain.
This changes the semantics quite a bit. With the
handleFault approach
one can assume that the message will be successful in
negotiating the
chain *unless* it is told otherwise, (handleFault), which leads to
optimistic processing. The latter onFinish() approach
requires me to
*wait* to see *if* the message was successful, which is a
pessimistic, possibly more expensive approach.
It seems to me, that "fault" processing is the exceptional case,
and one should be able to assume optimistic processing, unless
told otherwise.
Actually what has been proposed does not change the
semantics a lot. We only want to do two changes:
1. Remove handlerFault(). The reason for this has been
presented in the previous discussion, just quoted again below:
"However, the difference is CXF interceptors are not designed to
hook in user logic as these JAX-WS handlers do, thus handleFault is
not needed in CXF interceptors (correct me if I am wrong, but I
believe this is the purpose that JAX-WS handlers's handleFault
method designed for. I.e., when a known exception -
ProtocolException occurs, handleFault() gives handler developer a
hook to clean up sth, for example, roll back a transaction, this is
different from what close() is supposed to do. The latter is
designed to clean things up under a succeeded situation). For any
Runtime exceptions thrown by interceptors, we just wrap it as soap
exception then dispatch it back calling handleMessage."
2. Add a onFinish(Message) or onComplete(Message) method
(using name DanD suggested): this method is called in a reversed
direction when chain completes, can be used to remove the sub-chain
or interceptor re-entrance. For example, SoapOutInterceptor can use
onComplete to write the end element of SoapBody SoapEnvelop, this
way SoapOutInterceptor does not need to wrap its following
interceptors in a sub chain.
Thoughts?
The other thing I don't get, is what constitutes an Inbound Fault
Message as opposed to an Inbound Message? Why does this make a
difference in Interceptors of inbound and outbound messages?
Cheers,
-Polar
Dan Diephouse wrote:
Could I offer just once suggestion? Could we rename the
postHandleMessage to
onFinish(Message) or onComplete(Message)?
- Dan
On 2/6/07, Unreal Jiang <[EMAIL PROTECTED]> wrote:
Hi,
Looks like there has no opponent for jervis' proposal, I will
create a
jira task for this proposal and sign it me.
Cheers
Unreal
"Liu, Jervis" <[EMAIL PROTECTED]> wrote:
________________________________
From: Dan Diephouse [mailto:[EMAIL PROTECTED]
Sent: Tue 1/23/2007 1:02 AM
To: [email protected]
Subject: Re: Proposal for chaning CXF Interceptor APIs.
WAS: RE: When
should we close the handlers in CXF?
On 1/22/07, Liu, Jervis wrote:
Hi, I would like to summarize what we have been
discussed in this
thread
(including Eoghan's proposal posted last Oct [1]) regarding
Interceptor
API
changes. Any comments would be appreciated.
Currently our Interceptor APIs look like below:
public interface Interceptor {
void handleMessage(T message) throws Fault;
void handleFault(T message);
}
Also in the interceptor chain, we have a notion of sub-chain or
interceptor chain reentrance by calling
message.getInterceptorChain
().doIntercept(message)
or message.getInterceptorChain().doInterceptInSubChain(message).
The main issues we have with the current implementation are:
1. Fault handling. See Eoghag's email [1]
2. Sub-chain reentrance. See previous discussion in this thread.
We propose to change Interceptor API as below:
public interface Interceptor {
void handleMessage(T message) throws Fault;
void handleFault(T message);
void close(T message);
}
handleFault(T message) method is used to process fault message
(which is
done by handleMessage() in fault-chain currently).
I'm not sure I understand how you want to use this. I
guess I could
see
two
ways
1. Remove In/OutFault interceptors and call
handleFault
on the In/Out
interceptors. I don't know that mapping works especially
well though.
2. Don't call handleFault on in/out interceptors, but
only on the
in/outFault interceptors - this would mean, for example,
that the
logic
from
Soap11OutFaultInterceptor would be moved from the
handleMessage to
handleFault.
Can you be more specific about what you mean?
Sorry, after rethinking about this, I've changed my mind
slightly, so
here
is the idea:
CXF Interceptor API will be similiar to JAX-WS API,
section 9.3.2.1.
Throw ProtocolException or a subclass This indicates that
normal message
processing should cease.
Subsequent actions depend on whether the MEP in use requires a
response to
the message currently
being processed or not:
Response: Normal message processing stops, fault message
processing
starts. The message direction
is reversed, if the message is not already a fault message
then it is
replaced with a fault message4,
and the runtime invokes handleFault on the next handler or
dispatches
the
message (see
section 9.1.2.2) if there are no further handlers.
No response: Normal message processing stops, close is
called on each
previously invoked handler
in the chain, the exception is dispatched (see section 9.1.2.3).
Throw any other runtime exception This indicates that
normal message
processing should cease. Subse-
quent actions depend on whether the MEP in use includes a
response to
the
message currently being
processed or not:
Response: Normal message processing stops, close is
called on each
previously invoked handler in
the chain, the message direction is reversed, and the
exception is
dispatched (see section 9.1.2.3).
No response: Normal message processing stops, close is
called on each
previously invoked handler
in the chain, the exception is dispatched (see section 9.1.2.3).
However, the difference is CXF interceptors are not
designed to hook in
user logic as these JAX-WS handlers do, thus handleFault
is not needed
in CXF interceptors (correct me if I am wrong, but I
believe this is
the purpose that JAX-WS handlers's handleFault method
designed for.
I.e, when
a known exception - ProtocolException occurs,
handleFault() gives
handler
developer a hook to clean up sth, for example, roll back a
transaction,
this is different from what close() is supposed to do. The
latter is
designed to clean things up under a succeeded
situation). For any
Runtime
exceptions thrown by interceptors, we just wrap it as soap
exception
then
dispatch it back calling handleMessage.
So here is the change we need to make:
1. Add a postHandleMessage() into Interceptor interface
2. Remove handleFault() method from Interceptor
interface. Or we can
still keep it for a while until we are absolutely sure we
wont need
this method, but I presume there is nothing we need to
do in this
method.
3. We will NOT add a close() method into Interceptor
interface, as
CXF interceptors are stateless, there is no resources
need to be
closed.
public interface Interceptor {
void handleMessage(T message) throws Fault;
void postHandleMessage(T message);
}
When an interceptor chain ends normally, we need to call
postHandleMessage() on each previously traversed
interceptor in a
reversed
direction.
When a fault occurs on the in-bound chain, an exception
will be thrown
from the interceptor, after catching the exception in
PhaseInterceptorChain, we unwind the current chain by calling
postHandleMessage() on each previously traversed
interceptor and
then jump
to the out-fault-chain, calling handleMessage() on each
interceptor
with
the fault message.
Any thoughs?
close(T message) method is called on a reverse direction
at the end of
interceptor chain or when a fault or exception occurs.
Take the fault
handling case as an example, below is how handleFault
and close work
together
+1 to close() - Although I think Eoghan has a good point
about the
ordering
not necessarily being the same. I think we need to do a
little bit
more
digging before we can know whether or not sub chains can
be removed.
when a fault occurs on the in-chain, we unwind the
current chain by
calling
close() on each previously traversed interceptor and
then jump to the
out-fault-chain, calling handleFault() on each
interceptor with the
fault
message.
Close method is also used to remove the sub-chain
reentrance. See the
SOAPHandlerInterceptor example I posted previously.
Cheers,
Jervis
[1]
http://mail-archives.apache.org/mod_mbox/incubator-cxf-dev/200
611.mbox/[EMAIL PROTECTED]
ublin.emea.iona.com%3e
--
Dan Diephouse
Envoi Solutions
http://envoisolutions.com | http://netzooid.com/blog
---------------------------------
Access over 1 million songs - Yahoo! Music Unlimited.