Thanks guys. Should I file a JIRA, or is there already one open on this?

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/**>
>>>>> JAXRS+Testing#JAXRSTesting-
>>>>>
>>>> **LocalTransport<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/**>
>>>>> src/test/java/org/apache/cxf/****systest/jaxrs/**
>>>>> JAXRSLocalTransportTest.java<h**ttp://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/**>
>>>> javax/ws/rs/container/****AsyncResponse.html<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
>

Reply via email to