Looks like as a bug for me.
What do you think, Sergey?

Cheers,
Andrei.

> -----Original Message-----
> From: Adar Dembo [mailto:[email protected]]
> Sent: Samstag, 27. April 2013 04:27
> To: Sergey Beryozkin
> Cc: [email protected]
> Subject: Re: JAX-RS recursive dispatch?
> 
> Sergey,
> 
> Local transport certainly looks promising. I set it up with direct dispatch 
> and,
> as far as I can tell, it looks like the calling thread is also responsible 
> for method
> dispatch. That's awesome.
> 
> Now for the bad news. I got a toy example working with the WebClient API.
> The client-side code looks something like this:
> 
>       WebClient client = WebClient.create("local://api");
> 
> WebClient.getConfig(client).getRequestContext().put(LocalConduit.DIRECT_
> DISPATCH,
> Boolean.TRUE);
>       client.path("v1/clusters/not-a-valid-cluster");
>       client.get();
> 
> However, I can't get it working with the proxy-based client. My code looks
> like this:
> 
>     JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
>     bean.setAddress("local://api");
>     bean.setResourceClass(ApiRootResourceImpl.class);
>     ApiRootResource root = bean.create(ApiRootResourceImpl.class);
>     ClientConfiguration config = WebClient.getConfig(root);
>     config.getRequestContext().put(LocalConduit.DIRECT_DISPATCH,
> Boolean.TRUE);
>     config.getConduit();
> 
> root.getRootV1().getClustersResource().readCluster("not-a-valid-cluster");
> 
>  I keep getting an IllegalStateException with the message "Local destination
> does not have a MessageObserver on address /clusters". Note that this
> same code works correctly when the address is
> "http://localhost:<port>/api", so I don't suspect anything broken in either
> the client code or in my resource layout.
> 
> I've spent a fair amount of time debugging this and I think I've figured out
> what's going on. Every method call into the proxy (getRootV1(),
> getClustersResource(), and readCluster()) creates a new proxy for the
> corresponding subresource. That involves creating a new LocalClientState
> (see ClientProxyImpl.invoke() for details). Here is its constructor:
> 
>     public LocalClientState(URI baseURI) {
>         this.baseURI = baseURI;
>         String scheme = baseURI.getScheme();
>         if (!StringUtils.isEmpty(scheme) && scheme.startsWith(HTTP_SCHEME))
> {
>             this.currentBuilder = UriBuilder.fromUri(baseURI);
>         } else {
>             this.currentBuilder = UriBuilder.fromUri("/");
>         }
>     }
> 
> Because the baseURI in question begins with "local://", we end up in the
> 'else' statement, which resets our URI's path to '/'. In my case, the URIs for
> each subcall end up looking like "/", "/v1", and "/clusters" instead of
> "local://api", "local://api/v1", and "local://api/v1/clusters".
> 
> Later, during conduit selector preparation (called from inside
> ClientProxyImpl.doChainedInvocation, via createMessage()), we try to find a
> "compatible" conduit. We only have one conduit: a LocalConduit constructed
> during the call to config.getConduit() in the client code. The conduit is
> "compatible" if its endpoint's address matches the address in the message.
> And the address in the message is based on those partial URIs I described
> earlier. So what happens? The LocalConduit's endpoint's address is
> "local://api", but the address in the message is "/clusters". They don't 
> match,
> and findCompatibleConduit() fails. We then construct a new LocalConduit on-
> the-fly (see AbstractConduitSelector.getSelectedConduit()),
> but the LocalDestination that's created for it (by LocalTransportFactory)
> never gets an observer installed in it. The original LocalConduit (the one 
> that
> didn't match) has a destination with an observer; it was set up in
> ServerImpl.start().
> 
> Now, I was able to make forward progress by, using my debugger, modifying
> LocalClientState.currentBuilder in every proxy call to be an absolute path 
> like
> "local://api/...". At that point, the exception went away and the message
> was routed to the server. But then
> JAXRSInInterceptor.processMessage() failed to find the method to dispatch,
> so I suspect I broke something in the process.
> 
> So, am I crazy? Or do proxy-based clients not work correctly with a local
> transport? I'm using CXF 2.7.4.
> 
> 
> On Fri, Apr 26, 2013 at 1:58 AM, Sergey Beryozkin
> <[email protected]>wrote:
> 
> > On 26/04/13 09:48, Sergey Beryozkin wrote:
> >
> >> Hi,
> >> On 26/04/13 00:11, Adar Dembo wrote:
> >>
> >>> Thanks for the suggestion.
> >>>
> >>> Will using the WebClient in this way open a socket over the host's
> >>> loopback interface? Since I'm keeping a database transaction open
> >>> (via
> >>> Hibernate) during this time, it's important that 1. the latency in
> >>> the batch calls be minimal, and 2. the calls themselves be made by
> >>> the same thread as the one that serviced the batch endpoint. Can I
> >>> configure the WebClient in some way to get these guarantees?
> >>>
> >>>  I'm not sure we can have the current thread which invokes on the
> >> endpoint run that endpoint's own external call completely.
> >>
> >> Actually, if we get WebClient use CXF's Async HTTP Conduit (Apache
> >> HTTP Client based), using WebClient#async switch to JAX-RS 2.0
> >> AsyncInvoker (starting from CXF 2.7.0), then I guess we won't have a
> >> single thread involved, otherwise it should be a single thread. Dan,
> >> clarify please if it is not quite the case.
> >>
> >> I don't think we have any control over what happens at the socket
> >> level, unless... Are you dealing with the the same host outbound
> >> calls ? If yes
> >> - try using the local transport:
> >>
> >> https://cwiki.apache.org/**confluence/display/CXF20DOC/**
> >> JAXRS+Testing#JAXRSTesting-
> **LocalTransport<https://cwiki.apache.org/
> >> JAXRS+confluence/display/CXF20DOC/JAXRS+Testing#JAXRSTesting-
> LocalTra
> >> JAXRS+nsport>
> >>
> >> http://svn.apache.org/repos/**asf/cxf/trunk/systests/jaxrs/**
> >> src/test/java/org/apache/cxf/**systest/jaxrs/**
> >> JAXRSLocalTransportTest.java<http://svn.apache.org/repos/asf/cxf/trun
> >> k/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSLoca
> >> lTransportTest.java>
> >>
> >>
> >> Finally, on the server, try using JAX-RS 2.0 AsyncDispatch (best from
> >> CXF 2.7.4), that may help on its own, I'll work on documenting all
> >> 2.0 features asap.
> >>
> > Sorry, meant AsyncResponse:
> > https://jax-rs-spec.java.net/**nonav/2.0-SNAPSHOT/apidocs/**
> > javax/ws/rs/container/**AsyncResponse.html<https://jax-rs-spec.java.ne
> > t/nonav/2.0-
> SNAPSHOT/apidocs/javax/ws/rs/container/AsyncResponse.html>
> >
> >
> >> Sergey
> >>
> >

Reply via email to