Regarding complexity of interceptors and phases, attached is a list of the 55 interceptors I found in the rt modules along with their phases and before/after requirements. If we are too strict about adding additional phases, managing the before/after dependencies within some phases can become difficult; I actually would like to see a SETUP out phase that comes before PRE_LOGICAL, or else be able to ensure a particular interceptor is the very first or last in its phase, e.g. by using special String constants ("ALL"), empty sets or similar.

Andrea.

Mulligan, Patrick wrote:

After watching this thread for a few days, all I can say is keep it as
simple as possible, and remember the 80/20 rule.  The phases are fine
(only saw that in hell2days for first time), and it sounds like this
onTermination has merit.
I think Dan's comment of " I'm worried about phase bloat, interceptor
bloat, and what it takes to understand how CXF works.." is a reasonable
concern.  Although the model may be infinitely powerful, if it gets too
crazy for the average layman, they will beg off and go use something
else.

-----Original Message-----
From: Dan Diephouse [mailto:[EMAIL PROTECTED] Sent: Tuesday, February 13, 2007 10:48 PM
To: [email protected]
Subject: Re: Proposal for chaning CXF Interceptor APIs. WAS: RE: When
should we close the handlers in CXF?

Comments inline...

On 2/12/07, Polar Humenn <[EMAIL PROTECTED]> wrote:

I agree that it would be a simpler semantic if we can have a chain
that
only contains the calling of handleMessage(message) and only traverses
on
one direction. But a second thought makes me to think about the trade
off we
have to make in order to achieve this: First we have to write
corresponding
ending interceptors for these need a terminal action, agreed it is not
a bit
deal to write more interceptors and more phases. Secondly and more
importantly, we have to make sure the ending interceptors are put in a
proper place, this is where trick plays. Its not that straightforward
and
easy to make mistakes to find a proper place in the chain for ending
interceptors.



Actually, this is where the phases come into play. Surprisingly I like
this architecture. I like this architecture especially over the CORBA
interceptor architecture, as that had no idea of ordering at all.

The phase thing is somebody's shear brilliance. I wish I had thought
of
it. It actually sections out ordering semantics for interceptor
execution. CORBA couldn't figure this out, so they PUNTED.

I say Fantastic! So, bloody-well use it! Don't pretend it doesn't
exist.
The only slight complication you speak of comes with interceptors that
are placed in the same phase. However,  there is some notable, if not
great mitigation strategy.


Thats bollocks. If people need more sophisticated ordering of their
"terminal actions" then they can write a separate interceptor. But a
large
number of outgoing interceptors need this type of support and I'd rather
not
see a plethora of interceptors there. This is too common of a case.
Phases
are meant to be more coarse coarse grained then UNMARSHAL_START and
UMARHSAL_END or SEND_START and SEND_END. We're dealing with multiple
protocols, bindings, and frontends here - I'd rather not see them become
too
centered around the JAX-WS SOAP case.


Things can get even worse if we have too many interceptors in a same
phase, I dont think addBefore and addAfter can handle complicate
ordering
cases.
I think if you lay out the phases with forethought, and state
requirements for each, I doubt that you'll really get more than one
interceptor per phase. However, the capability remains for those who
require it, and there is some mitigation for ordering among them.


If certain internal interceptors are required to be in special places,
then make the phases they reside on "protected" so that none, but the
designated "system" interceptors can be on that certain phase.


The point isn't to have only one interceptor per phase. Right now I
think
its too fine grained already with the pre and post phases. The idea of
phases was to just have distinct points where we can apply policy,
security,
users interceptors, etc.

As a side note, currently the way how interceptors order themselves is
not
ideal, as you already noticed:  "As far as the phases go, as far as I
can
tell so far, that the amount of phases and names of the phases are
configurable to the particular interceptor chain, and don't really
have much
"meaning" associated with them at the moment, except for the implicit
ordering and where some of the CXF internal interceptors are actually
placed." Someone wants to refactor this? ;-) Anyway, that will be
another
story.
Well, yes. The semantics for each phase are only suggestive by name,
but
you may lay down by documentation certain semantics or invariants on
phases to give developers a guide line of where they think they should
place their interceptors. And you can "protect" certain phases only to
hold certain known "system" interceptors.
To summarize, without onComplete(or onTerminate) the semantics does
look
simpler as the chain only flows on one direction,
I am glad you agree on that point.


It may be more simple theoretically, but not more simple practically.

but it leaves the burden of choosing a proper phase for ending
interceptors to developers,
Yes, they are developers, they are burdened. (Not as burdened as the
designers :))
thus subjects to human errors and obviously more work to do for
developers.
I see no problem with developers having to understanding the system.
And
if human errors are what you are worried about, I doubt that you are
going to stop those even in the other scenario.


I'm worried about phase bloat, interceptor bloat, and what it takes to
undestand how CXF works. If we go down the route of adding new phases, I
think that it complicates each one of those things.

The semantic itself can not guarantee the terminal action in an ending
interceptors is called in a place that is symmetric to its
corresponding
starting interceptors. E.g., the chain below
Interceptor A -> Interceptor B.Staring -> Interceptor C.Staring ->
Interceptor C.Ending -> Interceptor B.Ending
Developers are free to put interceptor C.Ending and Interceptor
B.Endinganywhere, the semantic does not enforce the ending interceptors
are called
in a symmetric position in the chain corresponding to their starting
interceptors.
Exactly! "Developers" are free to put the interceptors anywhere,
presumably they know what they are doing. You have to rely on that.
The
straight forward line through the interceptor chain is simple to
understand.


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?

For example, they can end up of having a chain:
Interceptor A -> Interceptor B.Staring -> Interceptor C.Staring ->
Interceptor B.Ending -> Interceptor C.Ending
This can be very wrong. Using onComplete released this burden, and I
don't see a chain with a traverse back phase on complete is that
complicate
in terms of semantics.
But this could also be very right, if it was the developer's
intention.
There are reasons for this seemingly "unsymmetrical" approach. Take
this
scenario:

Interceptor A starts ready a message header
Interceptor B.starting places a collection object on the message.
Interceptor C.starting handles replaces B's object with a wrapper
collection object

Other interceptors add to the collection object, which in turn
modifies
both B and C
objects simultaneously, of which C has an ongoing efficient
encryption.
Interceptor B.ending closes its collection object, produces a
integrity
hash on the original added objects.

Interceptor C.ending closes its collection object using the hash
produced by B creates a signature.

Interceptor D gets the collection object (which it assumes it knows
exists after B.ending, but doesn't really know about C at all) and
request that it be marshaled it into a message body

Interceptor A.ending writes the marshaled header and the marshaled
message body to the wire.

You can see that C.starting needs to come after B.starting because the
object wouldn't exist otherwise. You can also, C.ending needs to come
after B.ending, because B's object needs to get the close before
C.ending. Then and only then can C.ending assume it can close its
object
get the hash for the signature.

Now if B.ending threw a handling Fault, C.ending wont do anything
because it never got called. Then on handleFault, B.ending can clean
up
its object. Interceptor C.starting can relinquish copy object.
Interceptor B.starting can relinquish its object, Interceptor A, can
note that its intended message never went out. etc.

This is all pretty straight forward, the fault handing works as it
should
The only thing that has to be done is to be definitive with the
Phases,
and placing certain internal interceptors in certain phases.


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.

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.

Regards,
Dan


Attachment: interceptors.xhtml
Description: application/xhtml

Reply via email to