You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cxf.apache.org by "Glynn, Eoghan" <eo...@iona.com> on 2007/04/01 22:43:58 UTC

RE: [PROPOSAL] Client and Conduit changes

 

> -----Original Message-----
> From: Dan Diephouse [mailto:dan@envoisolutions.com]
> Sent: 30 March 2007 15:33
> To: cxf-dev@incubator.apache.org
> Subject: Re: [PROPOSAL] Client and Conduit changes
> 
> On 3/30/07, Glynn, Eoghan <eo...@iona.com> wrote:
> >
> >
> >
> > > -----Original Message-----
> > > From: Dan Diephouse [mailto:dan@envoisolutions.com]
> > > Sent: 30 March 2007 01:52
> > > To: cxf-dev@incubator.apache.org
> > > Subject: Re: [PROPOSAL] Client and Conduit changes
> > >
> > > On 3/29/07, Glynn, Eoghan <eo...@iona.com> wrote:
> > > >
> > > >
> > > >
> > > > > But where are you diverting it?
> > > >
> > > >
> > > > The diversion would be driven by an interceptor, to a target 
> > > > within the local process space.
> > > >
> > > >
> > > > > How do you want to divert?
> > > >
> > > >
> > > > By dynamically manipulating the trailing interceptor chain.
> > > >
> > > >
> > > > > Why?
> > > >
> > > >
> > > > To avoid unnecessary dispatch overhead where the target
> > > exists within
> > > > the client process space.
> > >
> > >
> > > Unnecessary dispatch overhead? By calling Conduit.open() and 
> > > close()? Are you just trying to avoid serialization?
> >
> >
> > Direct quote from my last mail ...
> >
> > 'The "its not really needed" case would occur when we detect during 
> > the dispatch that marshalling and transport involvement are
> not required.'
> 
> 
> 
> So clearly I'm not *just* talking about calls to Conduit.open() and
> > close() ...
> >
> > On an aside, an open() method doesn't exist in the Conduit
> API, but I
> > assume you mean here the ConduitInitiator.getConduit() call.
> 
> 
> Yes, my bad.
> 
> What I'm talking about is avoiding *any and all* overhead that would 
> be
> > unnecessary if the message is not leaving the current process space.
> > That overhead includes the getting the Conduit,
> 
> 
> Overhead in getting the Conduit happens only once at Client creation.

> And in the case of a local invocation it really results in just a call

> to new LocalConduit(), which I'm sure is not a bottleneck.
> 
> marshalling the message
> 
> 
> A Conduit doesn't imply marshalling. For instance, I've outlined how 
> we could use an ObjectBinding (which we'd want to write for either 
> case) with the local transport. Currently the local transport requires

> you write to the output stream, but this doesn't have to be so. I at 
> least fixed the input side so we can directly invoke a service, but 
> more changes are needed.
> 
> payload & headers,
> 
> 
> These are interceptors, and would be configured as part of the 
> binding. And hence in the local dispatch scenario they would not be 
> part of the Binding, and therefore would not be part of the 
> interceptor chain.
> 
> and possibly applying transformations such as
> > encryption or compression.
> 
> 
> These are up to the user to enable on their endpoint. I don't see why 
> these would be enabled if you're invoking a local endpoint.
> 
> This "overhead" that you're talking about seems completely unrelated 
> to the Conduit/Destination.


Sure, I get what the local transport does.

I'm talking about taking a different approach. That's allowed, right? 

The local transport implies, as I understand it, a "static replacement"
style of approach. So I specify a "local://" URI as the endpoint
address, or my application explicitly sets a LocalConduit instance on
the Client. Also I statically change my config or asserted polices to
exclude interceptors that apply transformations unecessary in the local
case, or change the interceptor impls to detect this case themselves.
Also I engage an ObjectBinding in some way. 

Now that's all very well. But a different idea would be to go more for
"adaptive diversion". 

Here the binding and interceptor chain would be set up exactly the same
way, regardless of whether the target is local or remote. Where the
target really is remote, then everything just works. If the target
happens to be instantiated within the local process space, then I want
to detect this and adapt accordingly, *without any static changes* (to
config, WSDL, policies, code, whatever). Then maybe the target migrates
to another container instance and everything reverts to work as before.

Now this sort of diverted dispatch is just one example where it would
make more sense to delay the Conduit retrieval. The same idea would
apply to any situation in which an interceptor may want to dynamically
re-route the message to a different target. 

CXF is intended to be a flexible framework. The user community is, or
hopefully will be, a broad church. So CXF will accommodate a diversity
of user-level approaches. Right?


> > *snip*
> > > >
> > > > And conversely, setting up the Conduit in the
> > > Client.invoke() is IMO
> > > > *too early* in general. We're only 100% sure we need a
> > > Conduit when we
> > > > get to a point in outbound interceptor chain that
> actually needs
> > > > to use a Conduit for something. This point is the 
> > > > MessageSenderInterceptor. So my proposal is to defer
> getting the
> > > > Conduit unless and until this point is reached.
> > >
> > >
> > > In general?
> >
> >
> > Yes, in general.
> >
> > In the sense that in many cases its OK to get the Conduit in 
> > Client.invoke(), but in other cases it doesn't make sense to do so.
> >
> > So in general its not the right thing to do.
> 
> 
> I don't see how that follows... In general it IS the right thing to do

> and in some use cases that you outline it may not be the right thing 
> to do. But I'm not convinced yet that we can't just create a conduit 
> in general and then not use it.


Lets not get bogged down in the semantics of the phrase "in general".
You obviously understand it to mean "in the usual case". Whereas I
intended to convey more the sense of "with full generality". An approach
does not have full generality if its appropriate for many scenarios, but
not appropriate for other (perhaps niche, but also valid) use-cases.

In any case, of course you can go away and create a conduit and then not
use it. But it's wasteful and unnecessarily constraining. So its clearly
not impossible to create an unused Conduit, just sub-optimal to do so.


> > > If we don't ultimately use this Conduit, this shouldn't be any 
> > > issue. Any resource intensive operations should be delayed until
> > > open() is called.
> >
> >
> > As it happens, that is the case with all our extant Conduit 
> > implementations.
> 
> 
> Now would be a good time to fix that.


I think you may have misunderstood me here. I'm saying all existing CXF
Conduit impls DO in fact delay the heavy-lifting until send() is called
(modulo config retrieval and lightweight tasks like URL creation).

So there's little to fix in that sense. 

My point was that we should not impose this
ConduitInitiator.getConduit() post-condition on all future transport
impls. It would be simpler and more robust for the runtime to just take
more care about when it calls getConduit().


> However, it may not be the case for all future Conduit 
> implementations,
> > and its certainly not part of the Conduit contract as-is.
> >
> > I could for example envisage a defensively-coded Conduit
> probing the
> > target upfront in its ctor so as to fail-fast if a
> connection would be
> > impossible to establish.
> 
> 
> This would be bad. What if the target doesn't exist yet because the 
> server isn't fully intialized. We shouldn't be checking for existance 
> until send() is actually called.
> 
> I can also envisage resources to be shared across Conduit instances
> > being set up in the initial ConduitInitiator.getConduit() call, as 
> > opposed to being deferred to the first Conduit.send().
> >
> > Of course we could spell out a requirement that a Conduit 
> > implementation doesn't do any heavy-lifting until the first send() 
> > occurs. But I could see potential transport authors thinking, why 
> > doesn't the CXF runtime just avoid making the
> > ConduitInitiator.getConduit() call if its not sure it needs
> the Conduit?
> 
> 
> Because we want to make ClientImpl.getConduit() available to people. 
> Seems like a simple enough reason to me.


So that the application can make direct programmatic configuration
changes to the Conduit? As opposed to driving this declaratively via the
Spring config or asserted (WS-)policies?

This sounds like a niche use-case, but in the spirit of accommodating
diversity, I think this style could be supported also. See below for a
specific proposal on how this could be achieved.


> Your arguments are often based on making life easier for potential
> > transport-writers.
> 
> 
> And transport users!
> 
> And here's a case where we can avoid imposing an
> > ambiguous post-condition on ConduitInitiator.getConduit(). By 
> > "ambiguous", I meaning adding javadoc like "don't do
> anything resource
> > intensive until Conduit.send() is called". Whether the transport 
> > author respects this is not verifiable (we're not coding in
> Eiffel),
> > also it could be open to mis-interpretation (e.g. would
> 'resource intensive'
> > include pulling in config values?).
> 
> 
> They can do some set up when the conduit is created. I don't think 
> transports will necessarily have that much over head providing they 
> aren't initializing connections. Since this only happens once when the

> Client is created it shouldn't be a big deal.
> 
> >
> > >
> > > My point is that a user should just be able to do
> > > client.getConduit() and change some transport settings. They 
> > > shouldn't have to explicitly create the Conduit though, which is 
> > > what your proposal does.
> > >
> > > What about just a ClientImpl.setInitializeConduit(false)?
> >
> >
> > That would be fine if the default for initializeConduit was
> false (as
> > I don't think the application should have to make an
> explicit API call
> > to get the correct, IMO, behavior).
> >
> > Also I guess you'd probably want to extend your <client>
> config bean
> > with an <initializeConduit> property (and similarly, I'd advocate 
> > false as the default value).
> 
> 
> I'm sorry, but I can't ever be +1 on this.  


Well a statement like that sortta makes any further discussion
pointless.

However my progress is blocked by this ... so to break the log-jam,
here's a proposal that will allow me the flexibility to do what I need
to do, while allowing you to keep your up-front creation of the Conduit
in the Client. 

So we apply the "strategy pattern" and allow for a configurable
ConduitInitiationStrategy to be used by the Client. This defaults to an
"eager upfront retrieval" strategy. And it allows me to plug in my
"deferred on-demand retrieval" strategy. Even in the on-demand case,
your Client.getConduit() API could force the retreival of the conduit.

So everyone's happy :)

Or?


> We need to have
> the Conduit created on the Client for the user by default.
>
>
> > > Yeah, but they're still going to look at the Conduit
> interface and
> > > wonder about what that method is. And on the other side
> of things,
> > > as a user of the Conduit interface you still need to understand 
> > > Conduit.getBackChannel(). And then if we don't go down
> the route of
> > > removing decoupled destinations from the Conduit, they'll
> also have
> > > to understand the ConduitPolicy interface.
> > >
> > > Do you see my point now?
> >
> >
> > I suppose it just doesn't seem like that big an issue to me, 
> > especially if we make it clear in the javadoc that getBackChannel() 
> > only needs to be overridden in very specific circumstances.
> >
> > Similarly, the transport-writer doesn't really have to
> worry about the
> > mechanics of the ConduitPolicy. Beyond knowing that it factors out 
> > some commonality, and they should extend in their config
> schema *if*
> > they need transport-specific conduit config.
> 
> 
> You're the one who wrote it though, so of course it makes sense :-). 
> There have been several other people though have noted that it is 
> overly complex, and I think we need to listen to them.
> 
> - Dan
> 
> 
> --
> Dan Diephouse
> Envoi Solutions
> http://envoisolutions.com | http://netzooid.com/blog
>