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