> > Thanks guys. Should I file a JIRA, or is there already one open on this? > >> >> Please open the one, many thanks >
Filed CXF-4992. On Sun, Apr 28, 2013 at 11:25 AM, Sergey Beryozkin<[email protected]** >> >wrote: >> >> Hi Andrei >>> >>> On 28/04/13 13:45, Andrei Shakirin wrote: >>> >>> Looks like as a bug for me. >>>> What do you think, Sergey? >>>> >>>> You are right, it is a bug indeed with the way subresource proxies >>>> build >>>> >>> request URIs, we probably need to update that constructor a bit >>> >>> Thanks, 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/**<https://cwiki.apache.org/****confluence/display/CXF20DOC/**> >>>>>>> **<https://cwiki.apache.org/****confluence/display/CXF20DOC/**<https://cwiki.apache.org/**confluence/display/CXF20DOC/**> >>>>>>> **> >>>>>>> JAXRS+Testing#JAXRSTesting- >>>>>>> >>>>>>> >>>>>>> **LocalTransport<https://**cwi**ki.apache.org/<http://cwiki.apache.org/> >>>>>> <https://cwiki.**apache.org/ <https://cwiki.apache.org/>> >>>>>> >>>>> >>>>> JAXRS+confluence/display/****CXF20DOC/JAXRS+Testing#****JAXRSTesting- >>>>>> >>>>>>> >>>>>>> LocalTra >>>>>> >>>>> >>>>> JAXRS+nsport> >>>>>> >>>>>>> >>>>>>> http://svn.apache.org/repos/******asf/cxf/trunk/systests/** >>>>>>> jaxrs/****<http://svn.apache.org/repos/****asf/cxf/trunk/systests/jaxrs/****> >>>>>>> <http://svn.apache.**org/repos/**asf/cxf/trunk/**systests/jaxrs/**<http://svn.apache.org/repos/**asf/cxf/trunk/systests/jaxrs/**> >>>>>>> > >>>>>>> src/test/java/org/apache/cxf/******systest/jaxrs/** >>>>>>> JAXRSLocalTransportTest.java<**h**ttp://svn.apache.org/repos/****<http://svn.apache.org/repos/**> >>>>>>> asf/cxf/trun<http://svn.**apache.org/repos/asf/cxf/trun<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/****<https://jax-rs-spec.java.net/****nonav/2.0-SNAPSHOT/apidocs/**> >>>>>> <https://jax-rs-spec.java.**net/**nonav/2.0-SNAPSHOT/**apidocs/**<https://jax-rs-spec.java.net/**nonav/2.0-SNAPSHOT/apidocs/**> >>>>>> > >>>>>> javax/ws/rs/container/******AsyncResponse.html<https://** >>>>>> jax-rs-spec.java.ne<https://**jax-rs-spec.java.ne<https://jax-rs-spec.java.ne> >>>>>> > >>>>>> t/nonav/2.0- >>>>>> >>>>>> SNAPSHOT/apidocs/javax/ws/rs/****container/AsyncResponse.html> >>>>> >>>>> >>>>>> >>>>>> Sergey >>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>> >>> -- >>> Sergey Beryozkin >>> >>> Talend Community Coders >>> http://coders.talend.com/ >>> >>> Blog: http://sberyozkin.blogspot.com >>> >>> >> >
