Glynn, Eoghan wrote:
-----Original Message-----
From: Dan Diephouse [mailto:[EMAIL PROTECTED]
Sent: 20 March 2007 00:09
To: [email protected]
Subject: Re: [PROPOSAL] Client and Conduit changes
On 3/17/07, Glynn, Eoghan <[EMAIL PROTECTED]> wrote:
My position is that the Conduit should continue to hold to the
reference to, and manage the lifecycle of, the decoupled
response endpoint (DRE).
Without rehashing the entire thread, my reasons briefly are:
1. Separation of concerns
The DRE is an aspect of the transport and thus should be
created and
referenced from within the realm of the transport.
Then why aren't we creating other decoupled endpoints from
the transport layer?
Because the DRE is the only canonical back-channel IMO. By canonical, I mean you've got to have a back-channel for decoupled request/response MEPs to occur.
The faultTo on the other hand, is an added convenience provided by WS-A, but it
is not central to the normal decoupled request/response paradigm.
The acksTo is even less central, as its obviously used only for out-of-band RM
messaging.
In the normal case, the degrees of freedom presented by the faultTo and acksTo are not required by applications, i.e. they're happy to allow these default to be the same as the DRE.
In the less usual case where the application wants to set the faultTo and/or
acksTo to a different address, then it has to do a bit more work.
The fact that it is in the standard, means we should architecturally be
able to support it, no?
You can conceivably set up three different Destinations for an
"invocation", correct?
I'm not sure on the standard, but logically thinking:
A response message goes to either the Reply-To, or Fault-To but not both,
and an Ack-To goes regardless. Only in the cases where these headers are
not present does it default to the transport the message came in on,
correct?
So, that tells me that these Destinations are particular to the
"invocation" and not the transport.
This assumes a 1:1 association which isn't so.
Do you mean a 1:1 association between Conduits and Destinations?
I don't think it does necessarily, rather it depends on how the
DestinationFactory is implemented.
Currently DestinationFactory.getDestination() returns a brand new Destination each time, but it could be changed easily so that subsequent calls to getDestination() with the same EndpointInfo get back the same instance, possibly with a ref-count that's decremented in Destination.shutdown(). I think you suggested something similar yourself in the earlier thread.
I think the assumed association that's actually inappropriate is the one
between a Client and Destination, or even between a Client and Conduit. I won't
re-hash the reasons for this, as I'm guessing anyone reading this thread will
soon lose the will to live if either of us repeat ourselves any further :)
On the other hand, the purpose of the Client is to set up
interceptor chains
and dispatch the invocation. Such invocations may NOT
require a DRE,
or even a Conduit for that matter. Thus I think it
inappropriate for
the Client to be concerned with the creation of the DRE, and would
even go one step further and move the Conduit creation to the
MessageSenderInterceptor, so that a Conduit comes into
being only if it really is needed.
Then do you want to get rid of
Exchange.getConduit/getDestination or
Message.getConduit/getDestination as well?
I think there's a big difference here. Exchange/Message.getConduit() are just accessors. Client.getConduit() currently causes the creation of a Conduit.
Just because you
want to not require the conduit doesn't mean that there
shouldn't be conduit/destination properties on the Client.
This is completely orthogonal to the issue.
So how would a user suppress the Client's creation of a Conduit if its only
when the dispatch gets as far as some interceptor that the dispatch is diverted
in such as a way as to not require a Conduit? Note the Conduit is created
*up-front* by the Client, before InterceptorChain.doInterceptor() is called for
the outward dispatch.
Well, such is the nature of these interceptors. Who even says you need a
Message? :)
I guess it really depends on how you would want to adhere to an
underlying architecture.
When you are a Client, you are expecting the message to go over a
particular Conduit regardless. An interceptor may divert that for good
reason, but still the Client "intends" that particular Conduit, quite
possibly for trust/assurance issues.
If the purpose of this diversion is for local invocation, then perhaps
there should be a "local" Conduit that the message goes "over" but stays
in process?
2. Avoid forcing the usage of a Client instance
In general, if A is to be responsible for maintaining a
reference to
B, then its reasonable to expect that the existence of a B
implies the
existence of an A. Otherwise, in some cases an instance of
A will have
be artificially created, solely to manage the reference to B.
But if a DRE is in use, then the *only* other thing we're
guaranteed
also exists is the corresponding Conduit.
IMO we should neither require the usage of a Client instance to
mediate invocations, nor impose any undue burden on
applications that
choose to wire up the interceptor chains directly and
initiate dispatch themselves.
An example of an undue burden would be forcing such applications to
either always create the DRE *programmatically* via
DestinationFactory.getDestination(), or if they want the DRE to be
specified declaratively, to manage this configuration themselves.
Undue burden? Where is the undue burden?
The undue burden is NOT in driving the programmatic API. I agree the amount of
work there is roughly the same.
The problem is that there should be declarative mechanism as well as a programmatic API. The application doesn't necessarily want to hard-code the DRE address.
This declarative mechanism is currently provided by the Conduit configuration. Any application can take advantage of this, regardless of how the invocation is dispatched (whether via the Client, Dispatch, direct InterceptorChain.doIntercept(), whatever) because if it's a remote invocation, there's *always* going to be a Conduit instance involved.
You're proposing moving this config to hang off the Client instead. As a result
the application would be forced to either (a) use the Client in order to
declaratively specify the DRE, or (b) invent and manage its own config
mechanism. Makes sense, or?
Your approach:
Conduit conduit = conduitInitiator.getConduit(Endpoint);
ConduitPolicy policy = conduit.getConduitPolicy();
policy.setDecoupledEndpoint (replyToEPR);
conduit.setMessageObserver(myObserver);
My approach:
Conduit conduit = conduitInitiator.getConduit(Endpoint);
DestinationFactory destination =
destinationFactory.getDestination (replyToEPR);
destination.setMessageObser(myObserver);
conduit.setMessageObserver(myObserver); // if you need to
listen for back channel messages
It is arguably the SAME amount of work.
Agreed. See above though why this isn't the issue.
The benefit of the
latter is its consistent.
3. Suitability for JMS
In order to setup a Destination, JMS may require more
information than
can be easily shoe-horned into an EPR. Stuff like a JNDI provider,
ConnectionFactory username/password etc.
Now I don't accept the JMS as odd-man-out argument, especially when
most of the counter-examples wheeled out ( i.e. XMPP, TCP,
FTP) do not
currently even exist as CXF transports. I could just as
easily make up
a list of non-existent transports that suggests that the
URI-friendliness of HTTP is the exceptional case, but
obviously you'd
argue my list was hypothetical and proved nothing. And
you'd be right
:)
Neither does the "most people just use HTTP" line wash with
me. One of
the design centres of CXF is to be a multi-transport stack,
and that
in my book amounts to more than just paying lip-service to
non-HTTP transports.
Even if there isn't enough information in the JMS EPR to
completely set up a JMS endpoint, it doesn't mean its
completely useless. It can still be a nice way to hang onto
references of a JMS endpoint that I've set up earlier on.
For instance, a user could enter in the jms:// EPR in a
configuration screen. By calling
DestinationFactory.getDestination(epr) it would then retrieve
a previously configured instance of the JMS destination.
Sure that could work.
And my point along is that we would have to take some JMS-specific approach
like this, and thus lose one of the main purported benefits of your proposal,
i.e. that the mechanism for setting up the DRE is consistent across transports.
Also I'd like to respond quickly to a couple of specific
points that Dan
makes in his proposal:
"Right now if you want to create different endpoints for receiving
ReplyTos and FaultTos you have configure the ReplyTos using the
Conduit API and the FaultTos using the destination API.
Creating those
endpoints in different ways is bad IMO."
So how would this be any different under your proposal? Is the
implication that in addition to a Client.setAsynchronousEndpoint()
API, you'd also add
Client.setFaultToEndpoint() and Client.setAcksToEndpoint(), and
similarly expose <faultToEndpoint> and <acksToEndpoint> elements in
your proposed <client> bean?
If so, this would expose *way* too much of WS-A and WS-RM
semantics directly
in the Client, which should IMO be independent of such QoS
concerns.
The CXF WS-A and WS-RM layers were specifically designed to be
pluggable, so that they could slotted into the runtime
without impact
on the core APIs. I would be strongly against a move that
breaks this
... I mean, what next, Client.setSecurityPolicyToken()??
If on the other hand, if you're not suggesting polluting the
Client with
those aspects of WS-A & WS-RM, can you explain how your proposal
provides a consistent mechanism for specifying the faultTo & acksTo
vis-à-vis the replytTo?
No, I was more referring to scenarios where someone is not
using the Client.
The one you seem to be so concerned about in #1.
So regardless of whether:
(a) we hang the DRE config off the Conduit (as is currently the case) or the
Client (as you propose),
or
(b) the application chooses to use the Client or some other mechanism to
mediate the invocation
Would you agree that if the application wants to set the faultTo or acksTo to
some other address than the replyTo, then they would have to do so in a way
that's not consistent with whatever way the replyTo is set?
If so, I think the setting of the faultTo/acksTo is neutral to the argument,
and neither bolsters your case nor mine.
Hmmm, It seems that there are default defacto types of Destinations for
a particular Client. (Reply-To, Fault-To, Acks-To, whatever) These are
merely defaulted to the Conduit's Destination.
Perhaps, the Client is a MessageObserver to the Conduit's 1:1
Destination. When a Message comes in on the Conduit, the Client
MessageObserver dispatches that message depending on response message
headers (Reply, Fault, Ack, etc) to the appropriate Destination's
MessageObservers that was default/overridden on the Client.
When the Client makes the invocation, the ProtocolHeaders (Reply-To,
Fault-To, Ack-To, etc) before dispatching to the interceptors?
Cheers,
-Polar
Another point which I strongly disagree with:
"If all Conduits share the same code for setting up decoupled
destinations, that is a sign to me that we can take it out
of the Conduit."
I've never come across a design principle that suggests
having common
code in a common base class is a sign that such code should
be moved elsewhere.
In fact what purpose do common base classes serve, other than to
factor out commonality from sub-classes?
Base classes would be another solution to that problem. I
wasn't trying to say base classes are evil. I was trying to
say that the concept of a decoupled endpoint isn't critical
to the concept of a Conduit, and so I think it should be
taken out. Sometimes you can simplify the classes and then
incorporate more advanced concepts into another class. For
instance, in Microsoft's WCF, you have the IDuplexChannel
which extends the IInputChannel and IOutputChannel. I don't
think that is so outrageous really...
Agreed, not outrageous, just another way of doing it that happens to suit WCF.
/Eoghan