cxf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Glynn, Eoghan" <eoghan.gl...@iona.com>
Subject RE: Client API, EPRs
Date Fri, 16 Mar 2007 10:08:51 GMT
 

> -----Original Message-----
> From: Dan Diephouse [mailto:dan@envoisolutions.com] 
> Sent: 16 March 2007 01:24
> To: cxf-dev@incubator.apache.org
> Subject: Re: Client API, EPRs
> 
> On 3/15/07, Glynn, Eoghan <eoghan.glynn@iona.com> wrote:
> >
> >
> > >
> > >
> > >  -1: as I stated in my other email, there isn't any reason to put 
> > > the DRE inside the conduit.
> > >
> > > It is much more straightforward to put the Destination on 
> the Client 
> > > and and have the Client shutdown both the Conduit & DRE. Its 
> > > completely unncessary to introduce yet more complexity into our 
> > > transport APIs for this.
> >
> >
> > Obviously my -1 to your -1 :)
> >
> > It's a separation of concerns thing. The DRE is IMO an 
> aspect of the 
> > transport. Thus it is best managed within the realm of the 
> transport.
> >
> > It's also an existence issue. First we're not guaranteed to 
> even have 
> > a Client instance. Apart from the JAX-WS Dispatch example, 
> which fair 
> > enough could might someday be rebased on the Client (though 
> the return 
> > value handling is a bit different, a List in the Client's 
> case, but a 
> > single Object of type Source or SOAPMessage for the 
> Dispatch). But do 
> > we really want to _require_ that a Client is always used? 
> Suppose the 
> > app just wants to throw together some special-purpose interceptor 
> > chain and kick off the dispatch directly itself. Do we want to 
> > disallow this approach, or force the app to directly manage the DRE 
> > itself in that case?
> 
> 
> Is that hard for them to do a  
> destinationFactory.getDestination(epr)? I don't think so. 


Well I do think so :)

The problem is not the complexity of a making a call to
DestinationFactory.getDestination() per se. 

It's the fact of either always having to make this call
programmatically, or else manage a configuration mechanism so the DRE
may be specificied declaratively (in config) if the application doesn't
set it explicitly.

I hope you're not suggesting that we *only* support setting the DRE
imperatively, i.e. via a programmatic API?

Assuming you're not, then obviously we'd need the option of pulling the
DRE in from config. But what would this config policy be associated
with? 

The Client? Well maybe there's no Client as I've pointed out. 

Some other abstraction that's gratuitously added to the mix just to make
this work?

Why not just pick it up from the Conduit? We already have an established
Conduit configuration, and we can always be sure a Conduit will  exist
whenever it makes sense to set a DRE. 


> WS-Addressing interceptors will still work fine even though 
> there is no client. Its the same case as if they wanted a 
> different FaultTo or AcksTo.


WS-A is not the issue here.


> If they wanted, they could even create a DecoupledConduit 
> class which transparently manages the underlying Conduit & 
> Destination. But this logic shouldn't be in the normal low 
> level conduits though.


I've already suggested putting it into the AbstractConduit. Would that
address your issue with it being in the low-level Conduits?

 
> And related to both the existence argument and SoC, I'm 
> thinking we may
> > not even need a Conduit instance at all when mediating an 
> invocation. 
> > An example would be an optimized form of dispatch where a 
> client-side 
> > interceptor can short-circuit out the whole marshalling/transport 
> > thing and instead handle the request directly. So creating 
> the Conduit 
> > from
> > Client.invoke() seems premature. Which leads me to think 
> that the idea 
> > of the MessageSenderInterceptor creating the conduit, that you 
> > proposed in another with discussion with Polar as an 
> alternate way of 
> > handling the Message.ENDPOINT_ADDRESS override, may in fact be the 
> > proper way to go in *all* cases (if the 
> ConduitInitiator.getConduit() 
> > were to take responsibility for caching pre-existing 
> Conduits with the 
> > same EndpointInfo & target).
> 
> 
> Are you saying you just want to pass of the request object or 
> whatever to something else and avoid the any kind of 
> serialization or transport? That is completely possible right 
> now. Just make a Conduit which understands
> Message.getContent(Object.class) and write an ObjectBinding 
> which doesn't do any databinding. The APIs were made to 
> handle *any* representation and if they can't handle one we 
> should be changing those APIs instead of trying to make 
> Conduits optional. I'm strongly against removing the Conduit 
> off the client. Its really handy for manipulating the 
> Conduit's configuration, providing a different Conduit or the like.


The Conduit's configuration could be just as easily manipulated via the
EndpointInfo as I've suggested.

And as far as I can see, its *impossible* as things currently stand for
a different Conduit instance to be provided to the ClientImpl by a
JAX-WS application. That's because the ClientImpl.initedConduit field is
protected and may only be set externally via the ctor, which is called
in jaxws.ServiceImpl.getPort() outside the direct control of the
application.

So that's hardly really handy.

Also the choice of ConduitInitiator is driven by
EndpointInfo.getTransportID(). As explained above, a JAX-WS app can't
avoid the usage of the ConduitInitiator to get the Conduit, i.e. can't
provide an alternative Conduit implementation upfront. And the
transportID on the EndpointInfo is currently fixed on creation.

Of course we could change things so that the JAX-WS client could do
something like:

 
ClientProxy.getClient(proxy).getEndpoint().getEndpointInfo().setTranspor
tID("foo:bar");

so that an alternative ConduitInitiator was used instead of the one
provided by full-blown transport. 

Or instead allow it to provide an different Conduit instance with
something like:

  ClientProxy.getClient(proxy).setConduit(new AlternateConduit());

But I wouldn't agree that this sort of jiggery-pokery to artificially
ensure that there's a Conduit present (that does effectively nothing
anyway) is better than just allowing the outgoing interceptor chain not
to involve a Conduit in the first place if one is not required.

However the issue of whether the existance of Client implies the
existance of a Conduit is slightly tangential to the main questions:

1. must we force Client to exist in order for an invocation to be
mediated? 

2. if not, must the application take responsibility for retrieving the
DRE from config?

3. if not, what other component manages the DRE config?

 
> But if there's a DRE involved, then there's also necessarily 
> a Conduit,
> > as we've agreed that the decoupled transport must be the 
> same as the 
> > outgoing.
> >
> > To summarize:
> > A) An invocation doesn't imply the existence of Client
> 
> 
> Not that hard to set up a response destination .


As I've said above, not hard in the simplistic case, where its done
programmatically by the application.

But surely we also need to support the declarative approach, where this
is driven from config?

In that case we need *something* to hang the config off. 

 
> B) A Client shouldn't IMO imply the existence of a Conduit
> 
> 
> IMO a Client should always have a Conduit.


I don't agree. In situations where a Conduit wouldn't add any value, I
find it hard to see why we must force one to exist, only to do nothing
useful.


> C) A DRE does imply the existence of a Conduit
> 
> 
> Sure, but that doesn't mean it should be in the Conduit :-)


I can't think of a better place for it, short of requiring the existence
of a Client. 

The only bullet-proof existence relation we have is that for a DRE to
make sense we MUST have a Conduit.

 
> This seems to me a complete logical justification for referencing the
> > DRE from the Conduit.
> 
> 
> I disagree. :-)
> 
> And we could actually go one step further than what's currently there
> > and completely decouple the Client from any direct interaction with 
> > the transport, by removing the reference even to the Conduit, and 
> > setting this up from the MessageSenderInterceptor instead.
> 
> 
> No need to.
> 
> 
> 
> > 3. My main issue was to avoid a proliferation of
> > > automatically launched
> > > > DREs, as the responsibility for the lifecycle mgmt of 
> these DREs 
> > > > should be the responsibility of CXF. Fair enough, the 
> DRE shutdown 
> > > > isn't done properly currently, but it would be a tractable
> > > problem to
> > > > do so, by virtue of the cardinality being limited to
> > > one-per-Conduit.
> > > > My whole point was that we shouldn't move to a scenario 
> where for 
> > > > example the application setting a replyTo on an
> > > AddressingProperties
> > > > instance set in request context would cause CXF to
> > > automatically launch a new listener.
> > > > The problem here of course is that allowing a 
> per-request setting 
> > > > would facilitate the application causing many listeners to
> > > be created
> > > > by CXF, without a good way for the CXF runtime to know 
> when these 
> > > > should be shutdown. I take it from your comments in more
> > > recent mails
> > > > on this thread that this is not the sort of mechanism
> > > you're looking
> > > > for, correct?
> > >
> > >
> > > I just want to do :
> > >
> > > Client c = ...
> > > c.setDecoupledEndpoint(myEPR);
> > > c.invoke(...);
> > > c.close();
> >
> >
> > How about this instead:
> >
> > Client c = ...
> > c.getPolicy(ConduitPolicy.class).setDecoupledEndpoint(myEPR);
> > c.invoke(...);
> > c.close();
> >
> > From the point-of-view of the application, both approaches look and 
> > smell very similar.
> >
> > Then internally, we'd implement the Client.getPolicy() API something
> > like:
> >
> >   public <T> T getPolicy(Class<T> type) {
> >       return
> > endpoint.getEndpointInfo().getTraversedExtensor(type.newInstance(),
> > type);
> >   }
> >
> > ... ensuring that getTraversedExtensor() caches up the 
> policy instance 
> > so that its available to the Conduit when its first created 
> during the 
> > message dispatch.
> 
> 
> I still don't see why all these gymnastics are necessary.


By gymnastics, do you mean
"c.getPolicy(ConduitPolicy.class).setDecoupledEndpoint(myEPR)" versus
"c.setDecoupledEndpoint(myEPR)"?

Its only one extra API call for the app to make. Hardly a quantum leap
in terms of complexity.

Cheers,
Eoghan




Mime
View raw message