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 00:05:52 GMT


> -----Original Message-----
> From: Dan Diephouse [mailto:dan@envoisolutions.com] 
> Sent: 15 March 2007 21:12
> To: cxf-dev@incubator.apache.org
> Subject: Re: Client API, EPRs
> 
> On 3/15/07, Glynn, Eoghan <eoghan.glynn@iona.com> wrote:
> >
> >
> >
> > Dan,
> >
> > There are a bunch of orthogonal issues becoming conflated in this 
> > discussion.
> >
> > So I'm going to take a step back and try disentangling the 
> following:
> >
> > 1. transport-specific versus generic mechanism to set the decoupled 
> > response endpoint (DRE)
> >
> > 2. policy-driven (either specified via XML config or 
> programmatically) 
> > versus some other API to set the DRE
> >
> > 3. cardinality of the DRE, i.e. one-per-something (Conduit 
> or Client), 
> > or unlimited
> >
> > 4. association of the DRE with the Conduit or the Client instance
> >
> > 5. lifecycle mgmt of the DRE, or how to trigger a shutdown
> >
> > 6. explicit application creation and shutdown of DREs
> >
> >
> > Dealing with each issue in turn, here's my position:
> >
> > 1. If its claimed a proposed new mechanism for setting the DRE is 
> > superior to the existing mechanism by virtue of its 
> genericity, then I 
> > don't think its unreasonable to expect it be really generic, as 
> > opposed to sortta generic except for 'edge-case' 
> transports. If some 
> > transport specifics are required, lets at least try to 
> dove-tail these 
> > with the general mechanism as neatly as possible.
> 
> 
> I would propose just letting users set an EPR and then 
> resurrecting DestinationFactory.getDestination(EPR). In this 
> case its up to the transport to understand the EPR. Its a 
> generic mechanism. JMS may not work right away, but we can 
> make it work eventually.
> 
> If you have any other ideas feel free to share them.


Well I've already shared my ideas, see point #2 of my last mail.


> 2. Since we already control transports via policies specified 
> either in
> > XML config or programmatically, then for consistency it makes sense 
> > IMO to stick with this model. We could genericize the 
> policy by moving 
> > the DecoupledEndpoint attribute to a new ConduitPolicy and 
> having the 
> > existing HTTPClientPolicy pick it up from there by type extension. 
> > Other transports would also extend ConduitPolicy with their 
> own client 
> > policy type if necessary and could I guess add any additional info 
> > they need (thus neatly solving the JMS issue). The generic 
> > ConduitPolicy could be exposed via the AbstractConduit. Then 
> > programmatic approach (as used for example in the RM 
> SequenceTest) could then also become generic (i.e.
> > call AbstractConduit.getConduitPolicy() as opposed to
> > HTTPConduit.getClient() to get a hold of the policy object).
> 
> 
>  -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?

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).

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
B) A Client shouldn't IMO imply the existence of a Conduit
C) A DRE does imply the existence of a Conduit

This seems to me a complete logical justification for referencing the
DRE from the Conduit.

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. 

To make this approach work, we'd probably also need some sort of scheme
whereby the Client.close() calls InterceptorChain.close() which
traverses the chain call Intercptor.close() on each. For the
MessageSenderInterceptor this would involve an interaction with the
ConduitInitiator to cause it to close the cached Conduit, if its not
also being used by some other Client.


> 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'm not 100% sure that it should setDecoupledEndpoint. Other 
> options are setAsynchronousEndpoint or setReplyTo)
> 
> Also, I would like to be able to do:
> 
> Client c = ...
> c.setDestination(myDestination);
> c.invoke(...);
> c.close();
> 
> I don't think it makes sense to have two ways to specify a 
> decoupled endpoint (i.e. one hidden inside the Conduit and 
> one in which the destination is looked up).
>
> 4. I would favour continuing to associate the DRE with the Conduit as
> > opposed to the Client, because a) the DRE is 
> transport-level concern 
> > IMO
> 
> 
> I disagree. Transports (i.e. Conduits) are a tool to do 
> decoupled interactions.


Sure, Conduits are a tool to do remote interactions.

But as I pointed out above, neither a Conduit (nor a decoupled
Destination) is necessarily required for an invocation to occur. Hence
the question of whether either of these should be referenced from the
Client.

 
> Putting the DRE inside the conduit results in
> a) API complexity. Moving the destination outside of the 
> conduit makes it more straightforward to write Conduits and 
> also easier to specify DREs for interactions. You also need 
> to introduce even more complexity by adding the ConduitPolicy class.
> b) Inconsistency - If people have to set up a Destination 
> manually when they use per-request addressing settings, I 
> don't see why we should have a different API for setting up 
> decoupled destinations when you're setting up a DRE for the 
> life time of a Client.
> 
> and b) there may not even be a Client instance involved in 
> mediating the
> > invocation (e.g. when using the JAX-WS Dispatch mechanism).
> 
> 
> The JAX-WS Dispatch should be using the Client.  I have an 
> open JIRA for this I thought... (I fixed the Provider side of 
> things but ran out of time on the Dispatch end)


Pity there's no big "generate code" button in JIRA :)


> 5. The lifecycle management is much easier to deal with if the
> > cardinality is limited as per #3. As I said before I'm 
> happy with your 
> > suggested explicit Client.close() API (which would presumably call 
> > down to Conduit.close()).
> 
> 
> +1 to limiting it to per Client. If people are doing something more 
> +complex
> they get to manage it themselves.
> 
> 6. The application should IMO be free to set a replyTo for a DRE *not*
> > created by CXF, for example if that DRE is controlled by the some 
> > third party, or if the application explicitly calls
> > DestinationFactory.getDestination() itself and is prepared 
> to handle 
> > the shutdown when its done. Not sure if your comment "I'm 
> -1 to having 
> > two mechanisms to do the same exact same thing" indicates 
> disagreement 
> > on this point(?)
> >
> >
> I agree we should add a mechanism to tell CXF not to create a 
> decoupled endpoint. The best thing would be if CXF could see 
> that the user specified their own destination:
> 
> Client client = ...;
> client.setDestination(myDestination);
> 
> In this case they wouldn't have to set an EPR, it could just 
> figure out the EPR from Destination.getAddress();
> 
> Also, If I specify an EPR and a Destination already exists 
> for that EPR, CXF should be able to just use that. 
> DestinationFactorys aren't holding on to the Destinations 
> they create which I think is bad. If they do hold on to them, 
> when I call getDestination() it should just reuse the one 
> that is already there. 


Agreed on getDestination() caching and return a preexisting one if poss.

Similarly for ConduitInitiator.getConduit() as I suggest above.

/Eoghan

Mime
View raw message