And the idea that onTermination() is called after the chain has been
invoked
is just as simple to understand. Are you telling me that a developer
can't
understand that a method is executed at the end of the chain?
But I'm confused, onTermination() isn't called at the "end" of the
chain. The first call to an onTermination() method is in the "middle" of
the chain. That's because you are still "handling" the message in
onTermination() calls of the interceptors. For instance, in the outgoing
interceptor phase chain, the message isn't guaranteed to pop-out at the
end of the chain, it pops out at the beginning of the chain!
Let's take the MessageSenderInterceptor. This interceptor is placed at
the "PREPARE_SEND" Phase. Looking at its current implementation there is
a Chain.doIntercept() call. I will assume that it is the split where
handleMessage and onTermination() will now exist.
handleMessage will call conduit.send(message);
(which basically readies the message to get handled by other
interceptors,
in the PRE_STREAM, etc. phases.)
onTermination will call conduit.close(message);
(which closes the OutputStream, i.e. flushes the final buffers
writing data to the wire, guaranteeing that the message has been sent.)
So, my basic question is, and what is confusing to me, is why is
conduit.close(message) called in the PREPARE_SEND phase? Shouldn't it
logically be called in the "SEND" Phase, which is the *last* outgoing phase?
And what if that onTermination() call got an IOException on the
OutputStream.close(). (The message really cant be said it made it out to
the wire. None of the interceptors after the PREPARE_SEND phase will get
notified.
First, there is no handleFault, it needs to be removed. If there is a
fault, an interceptor can detect it in onTermination and correct for it
there.
I disagree. The handleFault and handleMessage are complementary.
HandleFault is there to unwind the actions the previous interceptors
took in handleMessage.
From what I can gather from the proposal, this onTermination() method
*always* gets called whether a fault happened or not, in order, back
down the chain regardless. But there is no chance to unwind or undo any
actions taken if an "earlier" interceptor onTermination() throws a fault.
A.handleMessage() action A.
B.handleMessage() action B.
C.handleMessage() action C.
D.handleMessage() action D.
D.onTermination() action D'
C.onTermination() throw Fault.
B.onTermination() does what?
A.onTermination() does what?
So let me get this straight, since C.onTermination() throws a Fault,
then interceptor D will not get any notification that the message never
made it through the chain? Since D.onTermination() has already been
called and long forgotten?
Second, I think your example is more theoretical than real. If someone
needs
more control over the termination actions, they can always write a second
interceptor. There is nothing about onTermination() that prevents that.
I gave you a very real example that does parallel ongoing encryption.
The bookend interceptors are staggered because of lifecyle issues.
A.starting needs to create an object.
B.starting needs to "use" A's object.
A.ending needs to "close" it's object.
B.ending operates on A's "finalized" object.
And really, is there is anything wrong with a little theory? :)
With onTermination() each interceptor will get called twice even if the
interceptor doesn't need or want to do anything with the onTermination()
call. That is a wasted call, and leads to unavoidable inefficiencies.
Cheers,
-Polar
Regards,
Dan