cxf-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Ate Douma (JIRA)" <j...@apache.org>
Subject [jira] Commented: (CXF-2997) CXF JAX-RS not thread safe when accessing multiple destinations concurrently
Date Thu, 16 Sep 2010 22:15:35 GMT

    [ 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.


Mime
View raw message