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


Reply via email to