Glynn, Eoghan wrote:
-----Original Message-----
From: Polar Humenn [mailto:[EMAIL PROTECTED] Sent: 19 March 2007 14:25
To: [email protected]
Subject: Re: [PROPOSAL] Client and Conduit changes

I've got a couple of CXF architectural questions.

Must be a Client in order for there to be an invocation request/response/fault/ack protocol?


Nope, a Client is not currently required for an invocation to occur.
An "invocation" or  "sending a Message"?

I would classify an "invocation" as an abstract element that is composed of by two other abstract elements, a "request" and a "response" that are correlated with each other.

It would appear that the Client is the object in CXF that performs invocations. (i.e. sends a "request" and collects the "response" realized as CXF Messages.

The "request" messages seems to get sent out over a Conduit, which is an abstract element that seems to suggest a "connection" to a particular server (for lack of a better word).

In this model, the "response" can come back by some other means (protocol, address, connection orientation, etc), and as a result of being by any other means, the response quite possibly completely uncorrelated, except for the thing that correlates the request and resposne, ie. the Client.

So, I surmise if you are going to do "invocations" in CXF, you get the Client to do the work of the correlation of request and response. Therefore The Client should be setting the "response" endpoints (Destination? BackChannel? DecoupledEndpoint?), shouldn't it?

Your description of the JAX-WS Dispatch stuff being used means that CXF is used underneath where the Client would use it. So if there is a correlation of request and response by JAX-WS Dispatch its implementation should be taking care of it. So, why isn't it using a Client?

Right now, I see the Conduit as a one way tunnel in which a Message is sent from a client to any server. I assume that abstract element on which Messages are received is a "Destination".

These two things are only very loosely coupled at best, and the fact that a response may come back on the same underlying transport (i.e. URLConnection) is merely coincidence.

From what I can gather, is that a Client composes an invocation by placing a "request" Message on a Conduit, through a bunch of special interceptors, and receives a correlated "response" message by picking it up off a predetermined Destination (listen point? Queue?).

You want these two things to be correlated at the outset so that addressing information can be injected into the message headers (in the case of http). Right?

If the JAX-WS Dispatch doesn't use a client, then what does it use? If it's suppose to correlate its own responses, then perhaps it's operating at a lower level and has to do more of the work the client does.

We discussed a couple of these scenarios in the "Client API, EPRs" thread, 
specifically where the JAX-WS Dispatch mechanism is used, or where the application wires 
together the interceptor chains itself.



Does the client that send the invocation request get notified of the response, fault, or ack?


Whatever the MessageObserver is set on the Conduit gets to process the 
response(s).
This is a lower level mechanism that notices the messages and gets them to go somewhere to get processed. Should this really be a thing some application code should be using?

Cheers,
-Polar
This *may* be the Client instance. Or something else entirely.


How are the responses (many?) are correlated to the client invocation.

Zero, or 1 depending on the MEP (whether oneway or twoway).

There's also the issue of partial responses (lets not go there on the detail, you can look in the archive for lengthy discussions on this subject). But there
Is there actually an object called a "Request" that does this correlation? Should there be?

When I send a "reply-To" or "fault-To" or "ack-To" property is that on single message? Or is it on a single connection (for many messages)? What is the request/response correction based on? Is there an object in CXF that represents it, or is that done by the Client, the Conduit, or something else?

Cheers,
-Polar

Glynn, Eoghan 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 concernsApache CXF - logged to http://dev.rectang.com/logs/codehaus/%23cxf/

The DRE is an aspect of the transport and thus should be
created and referenced from within the realm of the transport.
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.
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.
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.
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?
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?
Cheers,
Eoghan

-----Original Message-----
From: Dan Diephouse [mailto:[EMAIL PROTECTED]
Sent: 16 March 2007 22:20
To: [email protected]
Subject: [PROPOSAL] Client and Conduit changes

For those of you who haven't been following the long discussion Eoghan and I have been having, I'm going to take a moment to summarize my proposal here. I consider it rather important. If we don't reach any consensus on the proposal (it sucks/doesn't suck) or if Eoghan & I are the only ones who participate, I'll probably start a vote. So do
your communal
duty and participate so I don't have to do that! :-)

I propose the following:

1. API to set an Asynchronous EndpointReference I believe
we should
create a simple method on the Client which allows the user
to specify
the asynchronous endpoint that they wish to have used for
decoupled
responses:

Client.getAsynchronousEndpoint(EndpointReferenceType epr);

The Client would check to see if this EPR was set. If so, it would call DestinationFactory.getDestination(epr) for the EPR and use that as the asynchronous destination. This would result in a
standard way to
automatically set up the decoupled destination when using the API.

While it has been said that this isn't generic enough for JMS, I don't agree. First, I believe that JMS will eventually get a self contained IRI format which can be stuck in an EPR. We could even create our own proprietary format. Second, JMS is an edge case. There are other transports beside just JMS and
HTTP, like
XMPP or TCP or FTP which work just fine with URIs. JMS is the odd ball in the sense that historically it has needed stuff
outside the
EPR.

2. Access to the Conduits and Destinations I would like to add the following methods to the Client:

void setConduit(Conduit) - this allows a user to easily specify an alternate Conduit. void setAsynchronousDestination(Destination) - this allows
a user to
easily specify a decoupled endpoint. It's address would be
used for
WS-Addressing interactions. If no Async destination
exists, then the
Client will only listen on the Conduit.
Destination getAsynchronousDestination() - utility method
to easily
get the asynchronous destination

3. Client.close();
We need a way to shutdown the decouled endpoints (regardless of whether or not #1 & #2 are adopted). I think there is pretty good conensus we need a
Client.close() method which will do this. It will call
getConduit().close() and getAsynchronousDestination().shutdown().

(Ideally we'd like to be able to shut down RM at this same
time. I'm
going to guess that this would require the addition of a client lifecycle interface which allows RM to listen for Client.close(). This is an issue no matter which route we go though, so I'll defer this conversation for another
thread)

4. Remove the setup of decoupled destinations from inside
the Conduit
Currently, the Conduits are responsible for setting up the
decoupled
destinations. We've already got a perfectly good API for creating destinations, lets use it! Creating another API to create
decoupled
destinations introduces inconsistencies into our APIs.
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.

Putting in decoupled destinations inside the Conduit also makes it more complex for transport writers or people trying to
understand the
API. IMO, people intuitively expect this to be outside the Conduit class.

5. Client Configuration
I would propose that we make the decoupled destination
configuration
part of the Client

<jaxws:client id="...SomePort">
  <jaxws:asynchronousEndpoint>
    <wsa:Address>http://my.decoupled/endpoint</wsa:Address>
  </jaxws:asynchronousEndpoint>
</jaxws:client>

<jaxws:client id="...SomePort">

<jaxws:asynchronousDestination><http:destination...></jaxws:as
ynchronousDestination>
</jaxws:client>

As an added bonus, we can now wire together clients and
destinations
however we want. I wouldn't *have* to create a <conduit> config element with the port name inside it.
Instead I could simply do:

<jaxws:client id="...SomePort">
<jaxws:conduit> <http:conduit... /> </jaxws:conduit> </jaxws:client>

It also creates a central place to embed Client configuration
- such as enabling MTOM or configuring WS-*:
<jaxws:client id="...SomePort">
   <jaxws:conduit>...</jaxws:conduit>
   <jaxws:binding mtomEnabled="true">
     <jaxws:requestContext>
<map><entry key="javax.xml.ws.session.maintain" value="true"/></map>
     </jaxws:requestContext>
   </jaxws:binding>
   <jaxws:features>
     <wsrm:reliability timeout="10000" .../>
   </jaxws:features>
</jaxws:client>

Users could still use the <http:conduit id="PORT"/> syntax if they wanted to though.

(Note: I haven't written the jaxws:client Spring schema
yet, but its
on my todo list. The feature stuff will hopefully be part of my commit with
WS-Security)

6. Bring back Destination.getDestination(EndpointReferenceType)
This method would be needed for the API that I propose in #1.

7. Make the JAX-WS dispatch use the client.

----

In summary:
a) This simplifies the API. We've created an API to set up
decoupled
endpoints easily. We've reduced the complexity inside Conduits and have avoided introducing new complexity onto the Conduit
interface to
specify a decoupled destination.

b) It creates a consistent API for working with decoupled
endpoints.
There is no reason to go writing a new API for setting up
decoupled
endpoints - which is only used sometimes.

c) Dependency Injenction: By putting the Conduit &
Destination on the
Client we've made it much friendlier to people using
Spring or other
DI containers.

d) Improved configuration: I think the jaxws:client is a
more natural
place to setup the conduit and destination configuration
as opposed
to nesting the destination configuration inside the conduit.

e) Setting up decoupled destinations is not the job of the conduit IMO. We're giving Conduits a dual task unnecessarily. 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 of course would be volunteering to do all this work.
--

Alternatives: While Eoghan can elaborate, I believe he
would rather
see 1. The decoupled endpoint remain part of the conduit.
He views a
decoupled endpoint as part of the Conduit contract.
2. An API on the Conduit to set up the decoupled endpoint like so:
Client.get(Conduit.class
).getClientPolicy().setDecoupledEndpoint(EndpointReferenceType)
3. The Client.getConduit/setConduit methods go away and have the Conduit be an optional part of the Client 4. No Client.setAsynchronousDestination method. 5. Keep the decoupled endpoint configuration as part of
the conduit
instead of the client.

Regards,
- Dan

--
Dan Diephouse
Envoi Solutions
http://envoisolutions.com | http://netzooid.com/blog


Reply via email to