[ 
https://issues.apache.org/jira/browse/CXF-4992?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Sergey Beryozkin resolved CXF-4992.
-----------------------------------

    Resolution: Fixed
    
> proxy sub-resources creating wrong request URIs with non-HTTP transports
> ------------------------------------------------------------------------
>
>                 Key: CXF-4992
>                 URL: https://issues.apache.org/jira/browse/CXF-4992
>             Project: CXF
>          Issue Type: Bug
>          Components: JAX-RS
>    Affects Versions: 2.7.4
>            Reporter: Adar Dembo
>            Assignee: Sergey Beryozkin
>             Fix For: 2.8.0, 2.5.11, 2.6.8, 2.7.5
>
>
> I was experimenting with direct dispatch local transport and ran into an 
> issue with proxy-based clients.
> Here's my working WebClient-based client code:
> {code}
> 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();
> {code}
> Here's my broken proxy-based client code:
> {code}
> 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");
> {code}
> What breaks? I get an IllegalStateException with the message "Local 
> destination does not have a MessageObserver on address /clusters". Note that 
> the proxy-based client code works correctly when the address is 
> "http://localhost:<port>/api", so I don't suspect anything broken in either 
> the 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:
> {code}
> 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("/");
>     }
> }
> {code}
> 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.
> I asked about this on the cxf-users mailing list 
> (http://cxf.547215.n5.nabble.com/JAX-RS-recursive-dispatch-td5726752.html). 
> The consensus was that this is a real bug, and likely affects other non-HTTP 
> transports like JMS.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to