Hello,

it seems that it is not possible to have multiple JAX-RS servlets in one 
web.xml. Only the first one accessed becomes available, the others throw an 
exception and no jaxrs.* init parameters have any influence. I'm using CFX 
3.0.0.milestone2.

The situation:
I'm trying to deploy a RESTful service that consists of several quite 
independent parts. The parts are implemented using Apache Olingo (a library 
implementing the OData protocol), each part is actually a JAX-RS application, 
i.e. a separate servlet. My deployment provides all the parts in a single web 
application, i.e. all the parts are declared in the same web.xml. Here is the 
web.xml with the parts making troubles being commented out:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee";
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd";
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd";
    id="WebApp_ID" version="2.5">

    <servlet>
        <servlet-name>SessionServiceServlet</servlet-name>
        
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>

        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            
<param-value>net.atos.dirx.access.net.rest.services.session.SessionODataApplication</param-value>
        </init-param>
    </servlet>

    <!-- TODO: enable when working
      
    <servlet>
        <servlet-name>RequestServiceServlet</servlet-name>
        
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>

        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            
<param-value>net.atos.dirx.access.net.rest.services.authz.RequestODataApplication</param-value>
        </init-param>
    </servlet>
    -->

    <servlet-mapping>
        <servlet-name>SessionServiceServlet</servlet-name>
        <url-pattern>/sessioning/*</url-pattern>
    </servlet-mapping>

    <!-- TODO: enable when working
    
    <servlet-mapping>
        <servlet-name>RequestServiceServlet</servlet-name>
        <url-pattern>/authz/*</url-pattern>
    </servlet-mapping>
    -->
</web-app>


When the second servlet is uncommented, following exception can be observed:
org.apache.cxf.service.factory.ServiceConstructionException
        at 
org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:210)
        at 
org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet.createServerFromApplication(CXFNonSpringJaxrsServlet.java:446)
        at 
org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet.init(CXFNonSpringJaxrsServlet.java:93)
        at 
org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:512)
        ...
Caused by: org.apache.cxf.service.factory.ServiceConstructionException: There 
is an endpoint already running on /.
        at 
org.apache.cxf.jaxrs.JAXRSBindingFactory.addListener(JAXRSBindingFactory.java:85)
        at org.apache.cxf.endpoint.ServerImpl.start(ServerImpl.java:131)
        at 
org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:197)
        at 
org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet.createServerFromApplication(CXFNonSpringJaxrsServlet.java:446)
        at 
org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet.init(CXFNonSpringJaxrsServlet.java:93)
        at 
org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:512)
        ...


Behaviour from the user's point of view:
I wonder firstly why the servlet mapping is not respected and why there is any 
path conflict when the paths to the servlets neither overlap nor are ambiguous. 
But I can admit that it is necessary from technical reasons to provide an 
additional resolution parameter - like "jaxrs.address" seemed to be. 
Unfortunately, using it didn't change anything. Well, it's a pity - I tried 
then "jaxrs.application.address.ignore" set to true or false and annotating the 
JAX-RS application classes with @Path (otherwise I didn't use them, since I'm 
afraid of a conflict with Olingo's resource path management and the endpoint 
paths should be managed by the deployment descriptor in our case, if possible).

Stepping through the code:
The "jaxrs.address" parameter, which I think should be the proper way to 
resolve the path conflict, if the servlet mapping is not sufficient, 
unfortunately is completely ignored:
- CXFNonSpringJaxrsServlet.init() sets "address" field with the parameter 
value, but it is in the code branch that is not executed.
- Instead, createServerFromApplication() and subsequently createApplication() 
are called.
- Then createApplication() does set the "address" field, but only either to the 
path given by the application's annotation, or to "/". Hey, we've got here a 
fixed "/" string that is then complained about!

Well, being curious, I tried to employ annotations to see what happens then. I 
set the values to "sessioning" and "authz" that are used in the servlet 
mapping. This somewhat helped: both parts can be then accessed without errors. 
The values were concatenated with the mapping path - not nice (and I don't know 
how to avoid that), but I can understand that. What I don't understand well is 
that now four endpoints can be accessed:
/sessioning/sessioning/
/sessioning/authz/
/authz/sessioning/
/authz/authz/

It looks like all the JAX-RS servlets share something more than one would 
expect. I must say that it is pretty inconvenient, at least in this scenario 
when the servlets are supposed to be rather independent, just deployed via the 
same web.xml. Ideally, I would like to have only:
/sessioning/
/authz/

Exactly as specified by the servlet mapping. Is there any way to achieve this? 
And is the described behaviour a bug, or a feature?

Thanks for any comments!
Petr

Reply via email to