Hi
On 29/04/13 16:34, Adar Dembo wrote:
Thanks guys. Should I file a JIRA, or is there already one open on this?

Please open the one, many thanks

Sergey


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