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: Proposal for Decoupling and Issues with CXFServlet
Date Tue, 16 Jan 2007 12:06:16 GMT
 
> -----Original Message-----
> From: Dan Diephouse [mailto:dan@envoisolutions.com] 
> Sent: 15 January 2007 23:17
> To: cxf-dev@incubator.apache.org
> Subject: Re: Proposal for Decoupling and Issues with CXFServlet
> 
> Hi Eoghan,
> 
> I would say your characterizations about me desiring the WS-A 
> layer to manage the transports correct. I'm not sure that I 
> see what the big problem with this is though from your 
> message. So I want to take a look at your objections to 
> moving the decoupling out of the transport layer:

OK, let me explain further where the problems lie as I see it ... 

> 1. This would require configuration to be in the WS-A layer 
> instead of the transport layer
> 
> Putting this in the WS-A layer would be overly complex as you 
> imply. But that isn't our only option. Most likely we would 
> want this configured as part of the Client/Server. Which is 
> how most frameworks do this actually.
> For example, I would create a Client with a ReplyTo EPR of 
> http://some/url.
> Most frameworks even make this part of the Client interface - 
> client.setReplyTo(new EPR(...));
> 
> This really doesn't add any complexity - if anything it 
> simplifies. Right now people need to create a separate 
> configuration snippet which is not only specific to the 
> transport, but also to the client. For example:
> 
> <bean 
> name="{http://apache.org/hello_world_soap_http}SoapPort.http-conduit"
> abstract="true">
> 
> This bean is specific to both HTTP and a specific client 
> port. To me it would be more intuitive to just embed their 
> ReplyTo in an existing client configuration, rather than 
> require a separate bean.
> 
> <bean name="{http://apache.org/hello_world_soap_http}SoapPort"
> abstract="true">
>   <replyTo>htp://localhost/some/url</replyTo>
>    ... other configuration values which already exist are here </bean>
> 
> Not saying that should be the exact syntax, but I think it 
> makes my point.

My argument isn't based on complexity versus simplicity, rather on proper separation of concerns.

My position is that the decoupled response endpoint is an aspect of the transport, not an
aspect of the Client or the WS-A layer. Hence it should be configured as such.

Lets do a quick gedanken experiment, and consider what your proposal would look like in a
non-trivial case. 

Say I want to configure a decoupled replyTo, but my client is running on a resource-poor platform
so I need to ensure that the embedded HTTP listener consumes no more than 5 threads when servicing
the incoming decoupled responses. Here's the sort of thing we'd end up with ... (Don't worry
about the precise config syntax, its off the top of my head, so may be slightly off base)

<bean name="{http://apache.org/hello_world_soap_http}SoapPort" abstract="true">
   <replyTo>http://localhost:9000/some/url</replyTo>
</bean>

<!-- a bunch of other config stuff -->

<bean name="org.apache.cxf.transport.http.JettyServerEngine.9000" abstract="true">
   <property name="listener">
       <value>
           <http-conf:listener>
               <MaxThreads>5</MaxThreads>
           </http-conf:listener>
       <value>
   </property>
</bean>

Lets concentrate on what we've got here essentially ... two displaced, yet intimately related,
elements of config. This will end up being error-prone in practice.

For example, consider what happens when I hit a port clash with some other developer also
running CXF demos against port 9000 on the same host? I need to change my decoupled response
endpoint to listen on say 9001 instead. In order to do so, I need to remember to change two
displaced elements of config (the client-level replyTo and the transport-level listener).
Chances are I forget to change the latter, and my 5 thread restriction is no longer honored.

A contrived example? Well maybe so, but it demonstrates a general point ... related stuff
should be instantiated/managed/configured together.

> 2. WS-A wouldn't be knowledgable about whether or not a 
> ReplyTo EPR is cabable of being used
> 
> "From the physical contract (e.g. the target portType in the 
> WSDL), WS-A would have no way of knowing that the server-side 
> would even be capable of responing using such a replyTo EPR."
> 
> Just because there is not currently a WSDL extension that 
> enables this scenario, doesn't mean that it shouldn't be 
> supported. What if I want to receive a message via HTTP and 
> respond via SMTP? So I would consider not being able to have 
> a ReplyTo with a different transport a problem with the current code.
> 
> Second, if we do move decoupling support out of the transport 
> layer, this certainly doesn't change any functionality we 
> have now. It only expands our functionality!
>
> (The only thing I can think of that this would make hard is a 
> scenario where a user doesn't create a ReplyTo EPR and we're 
> supposed to create a non-anonymous one for them. I'm not sure 
> that we even support this now - do we? If we wanted to 
> support this we could add a Destination.getDestination() 
> method to automatically create a destination on a EPR of its choice.)

Ouch, hoist by my own petard :)

I intended the different-transport-in-replyTo argument to demonstrate the fragility of your
scheme, whereas you're probably thinking ... wow, this would give us extra flexibility!

But is it worth having a 'feature' that just *might* work if all the ducks line up?

Remember we'd have *no way of knowing* that the server-side is capable of understanding and/or
acting upon a replyTo EPR for any other transport apart from that advertized in the target
EPR or WSDL portType or whatever.

Even if we had an inkling that the server-side stack might support say JMS as well as HTTP
(regardless of fact that the target portType specifies only a HTTP URI), there's no standard
JMS URI scheme as yet ... so even if our suspicion that the server-side is JMS-aware turns
out to be correct, we still don't know if it understands whatever non-standard JMS URI we
cook up for the replyTo.

Even if we thought we were certain that the stack used on the server-side supports the different
replyTo transport and definitely understands the URI scheme, we still can't be sure if this
particular instance of the server-side stack is configured/deployed in such a way as to be
capable of doing anything with the replyTo. For example it may have a pluggable architecture,
and we'd have no way of knowing if the required transport plugin was available. It could instead
be a minimal deployment hosted by say a servlet container, without support for any non-essential
features or transports. 

The point is that all we have to go on is the physical contract exposed by the server-side,
e.g. the WSDL. If we jump to any conclusions not directly supported by this contract, we're
acting ultra vires ... and while it *may* work, its just as likely to blow up in our face.


Now the WS-A spec doesn't explicitly require that the outbound and inbound transports match.
But I would argue that practical considerations support such a de facto restriction.

And CXF isn't the only WS engine to take this position ... Axis2 does also (see http://mail-archives.apache.org/mod_mbox/ws-axis-user/200605.mbox/%3C05668670AA9BAD4695A071CED7A496D201BFDE45@mclean.sra.com%3E)

 
> 3. Partial responses require transport specific semantics 
> (from an earlier
> message)
> 
> As we've already discovered on the other thread, this isn't 
> actually true.
> We can just return with the default one way response code - 
> 200. 

I'm sounding like a broken record now, but yet again, I must point out that partial responses
may be required for twoways as well as oneways (I spelt out the reasons for this at length,
and then some, in the thread "Identification of Partial Responses").

So just because Systinet uses the 200 response code for partial response to oneways, it doesn't
mean we can just fall back to 200 for all partial responses, specifically it would make no
sense for the partial response to a twoway. Again, I explained this before.

> Even if we desired a special transport semantics this 
> could be done more cleanly via an RMDestination interface 
> which allowed customization in a well contained method. It 
> doesn't follow that we need partial responses in the 
> transport layer because we would need to add transport 
> specific semantics just as we wouldn't put SOAP in the 
> transport layer.

Again I don't see this as being any cleaner, in fact the opposite. I feel sure that calling
the separate interface "RMDestination" will cause a LOT more confusion. 

Why? Because it gives the false impression that the reliability logic is hosted in the transport.
Remember "RMDestination" is label given by the RM spec to the endpoint that receives &
ACKs incoming reliable messages. The receiver-side "reliability envelope" extends up and including
the RMD, but no further ... once the message has been ACKed by the RMD, its no longer within
the domain of WS-RM and may in fact be lost before the implementor up-call occurs. Giving
the impression that this window for message loss extends from the transport upwards on the
server-side would be completely wrong.

OK, you say, lets call it RMTransport instead. But again I'd consider this to be misleading.
The transport isn't tied to RM, instead it just happens to provide a generic service, the
sending of partial responses. The only user of this service currently happens to be RM, but
that's the extent of the relationship between RMTransport/Destination and RM.

/Eoghan
 
> --
> 
> In summary, I'm not sure that I see any reasons why we should 
> keep decoupling in the transport layer. And as I've said 
> there are many reasons to move it out
> - It simplifies transport writing
> - It follows the principle of least astonishment [1]. I would 
> not expect as a transport writer to have to worry about 
> WS-A/RM while writing a transport
> - RM semantics should be in the RM module. This is the same 
> policy we have for everything else - i.e. SOAP
> - Our HTTP decoupling is dependent on specific 
> implementations (i.e. the client is dependent on Jetty)
> - ReplyTo on alternate transports aren't supported
> 
> Regards,
> - Dan
> 
> 1. http://en.wikipedia.org/wiki/Principle_of_least_astonishment
> 
> On 1/15/07, Glynn, Eoghan <eoghan.glynn@iona.com> wrote:
> >
> >
> > > > Are you objecting just to the HTTPConduit having a reference to 
> > > > the ServerEngine, or to the presence of a ServerEngine 
> instance in 
> > > > the client-side runtime?
> > > >
> > > > If the latter, how would the client-side arrange to receive
> > > decoupled
> > > > responses without some sort of HTTP listener being launched
> > > in-process?
> > > > Shouldn't this client-side HTTP listener re-use the
> > > server-side logic?
> > > > Or are you thinking that the client-side should only embed
> > > a minimal
> > > > HTTP listener (like nanoHTTPD)?
> > >
> > > Sorry if I wasn't clear. I'm objecting to maintaining the server 
> > > side connection in the client code. And vis a versa.
> > > Instead of registering the Client MessageObserver like this:
> > >
> > > Destination d = conduit.getBackChannel(); // this sets up a back 
> > > channel via the JettyHTTPServerEngine.getForPort(...)
> > > method d.setMessageObserver(client);
> >
> > Well that's not the way things work currently on the client-side.
> >
> > We do not set a separate MessageObserver on the back-channel 
> > destination, whether decoupled or not.
> >
> > Instead, the MessageObserver already set for the Conduit is 
> implicitly 
> > also used for the back-channel. The ClientImpl just provides a 
> > *single* MessageObserver, and the response messages are 
> delivered to 
> > this regardless of whether they arrived on the back-channel of the 
> > outgoing client->server connection or on a separate 
> server->client connection.
> >
> > The idea is that only the transport needs to be aware that it's 
> > configured in decoupled mode.
> >
> > The WS-A layer just asks the transport for a back-channel URI. If 
> > something non-null is returned, this is encoded as the 
> wsa:replyTo in 
> > the outgoing message. Otherwise the fallback is the anonymous URI.
> >
> > I think we've a different understanding of what the primary task of 
> > the WS-A layer is, and where the division of responsibilities 
> > vis-à-vis the transport lies.
> >
> > My understanding is that job of the WS-A layer is to gather 
> together 
> > the information relating to addressing, and to encode this in the 
> > out-going message. Some of this information is in the domain of the 
> > transport, such as the backchannel address, and the 
> transport should 
> > drive the creation of this. WS-A in my view simply provides 
> a standard 
> > transport-independent way of encoding transport-specific 
> information. 
> > In my view, the WS-A layer is is the aggregator, not the instigator.
> >
> > You on the other hand, I think, see the WS-A layer in the driving 
> > seat, causing the transport to create a particular back-channel. Is 
> > that a fair characterization?
> >
> > > Just doing this instead:
> > >
> > > Destination d = destinationFactory.getDestination(replyToEPR);
> > > d.setMessageObserver(client);
> > >
> > > This would mean that any HTTP Destination could be used with any 
> > > HTTP Conduit. It also simplifies the code as the http 
> > > conduits/destinations don't need to worry about each other.
> > > Is there a reason this wouldn't be possible?
> >
> > Not impossible, just not the best way of doing it IMO.
> >
> > For a start it would probably involve the WS-A layer being 
> configured 
> > with the replyTo EPR (instead of the transport, as is 
> currently the case).
> >
> > In such a scenario, how would WS-A validate that the 
> replyTo EPR even 
> > makes any sense vis-à-vis the outgoing transport? Supposing for 
> > example WS-A is configured with a JMS replyTo EPR, when the target 
> > endpoint is HTTP-based. From the physical contract (e.g. the target 
> > portType in the WSDL), WS-A would have no way of knowing that the 
> > server-side would even be capable of responing using such a 
> replyTo EPR.
> >
> > > > >    -  As I mentioned above, RM has HTTP specific
> > > semantics and those
> > > > >    should be contained inside the RM module. This is the
> > > same policy
> > > > > we have
> > > > >    with things like the SOAP binding. This does not mean
> > > it has to
> > > > > be hardcoded
> > > > >    into the partial response logic. The RM module 
> could discover 
> > > > > different
> > > > >    transport specific logic. i.e. we could have an 
> RMTransport 
> > > > > interface
> > > > >    which has something like a "void 
> > > > > setupPartialResponse(Message)" method.
> > > >
> > > > Would this RMTransport be like a sub-interface of Destination, 
> > > > that the RM layer would down-cast to as required?
> > > >
> > > > If so, any wouldn't transport that we're likely to want to
> > > run RM over
> > > > would have to implement RMTransport as opposed to
> > > Destination, so that
> > > > we end up in effect with as much (or as little, 
> depending on your 
> > > > point of view) RM pollution of the transport as before?
> > > >
> > >
> > > I think it could be done one of two ways. The first is as you 
> > > mention. I would imagine in this case the RMTransport interface 
> > > would become part of the API module. The second would be 
> to make it 
> > > its own independent interface which is discovered like the 
> > > transports currently are. The first is probably easier.
> > >
> > > I don't think it would be equivalent to the current code. 
> It would 
> > > be in one well contained method, and isn't run unless we 
> are doing a 
> > > partial response in RM. It would also not need to be implemented 
> > > unless a transport needed to support customizing a 
> partial response 
> > > - i.e. an HTTP 202 accepted response status. JMS wouldn't need to 
> > > implement anything.
> > > Completely optional. Also my motivation for doing so would be not 
> > > only to remove the partial response handling, but also the 
> > > decoupling support built into the HTTP transport as well (for 
> > > reasons I won't repeat...)
> >
> > Yep, there's an argument alright for allowing a transport 
> opt out of 
> > the whole partial response mechanism if its incapable of providing 
> > those semantics.
> >
> > But this could be achieved more simply via some 
> distinguished return 
> > from Destination.backChannel(), e.g. just return null if the 
> > partialResponse parameter is non-null. As things currently 
> stand, WS-A 
> > would be tolerant to this and will simply avoid sending the 
> partial response in this case.
> >
> > > > > Furthermore, I'm really not a fan of B, which makes me
> > > less inclined
> > > > > to like A.  Why?
> > > > >
> > > > >    - Encapsulating the decoupling logic complicates
> > > transports: For
> > > > >    instance, methods we've added for encapsulation of the
> > > decoupling
> > > > > include:
> > > > >    Conduit.getBackChannel(), Destination.getBackChannel(),
> > > > >    ConduitInitiator.getConduit(EndpointInfo,
> > > EndpointReferenceTarget).
> > > >
> > > > Well, I guess we could simplify things a bit by 
> factoring out the 
> > > > logic related to partial response into a separate 
> sub-interface of 
> > > > Destination (assuming that's what you intended with the
> > > suggested RMTransport).
> > > >
> > >
> > > I'm suggesting we
> > > - remove the Conduit.getBackChannel()
> > > - make Destination.getBackChannel() have no arguments and only 
> > > return the anonymous back channel
> > > - remove the Conduit.getConduit(EndpointInfo,
> > > EndpointReferenceTarget) method
> > >
> > > This would move the decoupling support out of the HTTP layer and 
> > > into the WS-A layer. That is the WS-A layer would be 
> responsible for 
> > > creating a non anonymous ReplyTo conduit, setting up a decoupled 
> > > Client destination, etc.
> >
> > I disagree with this division of responsibility between WS-A and 
> > transport. See above for reasoning.
> >
> > > > I'm not sure I understand how you'd intend to get away without 
> > > > worrying about a decoupled Destination on the 
> client-side ... how 
> > > > would the client be capable of receiving decoupled responses?
> > > >
> > >
> > > I'm not trying to get rid of the decoupled Destination.
> > > Simply trying to move the decoupling logic elsewhere. 
> Does the above 
> > > help explain what I mean better?
> >
> > Yep, I see where you're going, but don't agree :)
> >
> > Cheers,
> > Eoghan
> >
> 
> 
> 
> --
> Dan Diephouse
> Envoi Solutions
> http://envoisolutions.com | http://netzooid.com/blog
> 

Mime
View raw message