[ 
https://issues.apache.org/jira/browse/CXF-2997?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12910352#action_12910352
 ] 

Ate Douma commented on CXF-2997:
--------------------------------

Hi Sergey, thanks for the reply.

Too bad but your solution doesn't work for us, for two reasons:

a) Defining multiple endpoint definitions only is feasible if all potential 
endpoint addresses would be known upfront (and are just a few).
But for our application this won't work as we have a potentially unlimited 
number of endpoint addresses, which also can be created/added at runtime (after 
CXF startup).
Our application provides a REST api on top of a hierarchical (path based) 
repository of resources.
>From the initially incoming request (pathinfo) we first determine the longest 
>path matching an existing "resource" within our repository. The remainder of 
>the pathinfo (suffix) is (assumed to be) the target REST api destination.
Once this is determined we create a requestwrapper and modify the servlet path 
to represent our actual repository resource and the remainder as new pathinfo 
for the CXFServlet, and finally we forward to the CXFServlet.
To make this work, of course we only can use a single server entrypoint address 
for all possible CXF requests.
Defining all potential entrypoint addresses upfront is furthermore technically 
impossible as new repository resources can be created any time.
So far it all worked pretty well, with non-overlapping requests that is, but 
now it fails miserably when different "resource paths" are accessed 
concurrently. 

b) To make things even more complicated, our application furthermore can be 
accessed from unknown amount of hosts (well: they are "known" but also can be 
dynamically added at runtime). 
So, just using a single CXFServlet mapping with multiple endpoint definitions 
still won't work, even if we only had a few fixed endpoint addresses.
As you can already test with the example application I uploaded, even going 
through the same endpoint but with a different hostname screws up the internal 
state.
When executing the following requests in order:

  1) http://127.0.0.1:8085/one/myservice/lock (browser window 1)
  2) http://localhost:8085/one/myservice/uris (browser window 2)
  3) http://127.0.0.1:8085/one/myservice/unlock (browser window 1)

the following output is the result (browser window 2):

  BaseUri on entry: http://localhost:8085/one/
  BaseUri on exit : http://127.0.0.1:8085/one/

So, I think we'll need a real fix to solve concurrent requests with overlapping 
destinations.
I've already looked and searched in both the users and dev mailing list but 
haven't been able yet to find the (old) patch you are referring to.
I'm willing to spend time investing this further and come up with a new patch 
if needed, but any help and pointer to this "old issue+patch" would be very 
welcome!

Regards,

Ate

> CXF JAX-RS not thread safe when accessing multiple destinations concurrently 
> -----------------------------------------------------------------------------
>
>                 Key: CXF-2997
>                 URL: https://issues.apache.org/jira/browse/CXF-2997
>             Project: CXF
>          Issue Type: Bug
>          Components: JAX-RS, Transports
>    Affects Versions: 2.2.10
>            Reporter: Ate Douma
>            Priority: Blocker
>         Attachments: cxf-rest-test.tar.gz
>
>
> If a (single) JAX-RS service is invoked concurrently for different 
> destinations, the CXF ServletController and ServletTransportFactory 
> implementations override the current Destination state between these 
> invocations.
> I have created a simple test web application using Spring to expose this 
> problem.
> My example ServiceImpl.java looks like:
> @Path("/myservice/")
> @Produces("application/xml")
> public class ServiceImpl {
>   volatile boolean locked;
>   @GET
>   @Path("/uris")
>   @Produces("text/plain")
>   public String getUris(@Context UriInfo uriInfo) {
>     StringBuilder uris = new StringBuilder("BaseUri on entry: 
> "+uriInfo.getBaseUri().toString()).append("\n");
>     try {
>       while (locked) {
>         Thread.sleep(1000);
>       }
>     }  
>     catch (Exception x) {}
>     return uris.append("BaseUri on exit : " + 
> uriInfo.getBaseUri().toString()).append("\n").toString();
>   }
>     
>   @GET
>   @Path("/lock")
>   @Produces("text/plain")
>   public String lock() {
>     locked = true;
>     return "locked";
>   }
>   @GET
>   @Path("/unlock")
>   @Produces("text/plain")
>   public String unlock() {
>     locked = false;
>     return "unlocked";
>   }
> And in my web.xml I defined two CXFServlet mappings as follows:
>     <servlet-mapping>
>         <servlet-name>CXFServlet</servlet-name>
>         <url-pattern>/one/*</url-pattern>
>     </servlet-mapping>
>     <servlet-mapping>
>         <servlet-name>CXFServlet</servlet-name>
>         <url-pattern>/two/*</url-pattern>
>     </servlet-mapping>
> Finally, in Spring ApplicationContext.xml I setup the jaxrs server like this:
>     <jaxrs:server id="myService" address="/">
>         <jaxrs:serviceBeans>
>             <ref bean="serviceImpl" />
>         </jaxrs:serviceBeans>
>         <jaxrs:extensionMappings>
>             <entry key="xml" value="application/xml" />
>         </jaxrs:extensionMappings>
>     </jaxrs:server>
>     <bean id="serviceImpl" class="service.ServiceImpl" />
> As can be seen from the ServicesImpl.java, I used a trick to temporarily 
> "lock" and "unlock" a call to /myservice/uris from another request using 
> /myservice/lock and /myservice/unlock.
> Without locking, a call to http://localhost:8085/one/myservice/uris produces 
> the expected following result:
>   BaseUri on entry: http://localhost:8085/one/
>   BaseUri on exit : http://localhost:8085/two/
> However, if I first call http://localhost:8085/one/myservice/lock, then 
> http://localhost:8085/one/myservice/uris (blocked), and finally 
> http://127.0.0.1:8085/two/myservice/unlock (note the different hostname 
> 127.0.0.1 and servletPath /two) I get the following result:
>   BaseUri on entry: http://localhost:8085/one/
>   BaseUri on exit : http://127.0.0.1:8085/two/
> Clearly, UriInfo.getBaseURI() isn't thread safe as is shown above.
> After debugging a bit the current (CXF 2.2.10) implementation of the 
> ServletController and ServletTransportFactory, it looks like the 
> ServletController.updateDests(HttpServletRequest) method and the 
> ServletTransportFactory as a whole don't maintain resolved Destination state 
> isolated per request.
> Our CXF (JAX-RS) application exposes the same REST service to be called from 
> many different addresses (hosts) as well as upfront unknown servlet paths, 
> this really is a blocking issue.
> To be more concrete, we have to use a request wrapper to dynamically "mount" 
> the same rest service for different urls (its a front end for a unlimited 
> hierarchical resources repository). 
> Is there an easy way to protect JAX-RS service interactions from concurrent 
> invocations, e.g. by using special configurations, or is this indeed a 
> serious bug which will have to be fixed first? 

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to