Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Wiki Markup
{span:style=font-size:2em;font-weight:bold} JAX-RS : Services Configuration {span}

{toc}

h1. Configuring JAX-RS services programmatically

{code:java}
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setResourceClasses(CustomerService.class);
sf.setAddress("http://localhost:9000/");
sf.create();
{code}

A couple of things to note:
* The JAXRSServerFactoryBean creates a Server inside CXF which starts listening for requests on the URL specified.
* By default, the JAX-RS runtime is responsible for the lifecycle of resource classes, default lifecycle is per-request. You can set the lifecycle to singleton by using following line:
{code:java}
sf.setResourceProvider(BookStore.class, new SingletonResourceProvider(new BookStore()));
{code}
* If you prefer not to let the JAX-RS runtime handle the resource class lifecycle for you (for example, it might be the case that your resource class is created by other containers such as Spring), you can do the following:
{code:java}
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
CustomerService cs = new CustomerService();
sf.setServiceBeans(cs);
sf.setAddress("http://localhost:9080/");
sf.create();
{code}


h1. Configuring JAX-RS endpoints programmatically without Spring

Note that even though no Spring is explicitly used in the previous section, it is still used by default to have various CXF components registered with the bus such as transport factories. If no Spring libraries are available on the classpath then please follow the following example :

{code:java}
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setResourceClasses(CustomerService.class);
sf.setResourceProvider(CustomerService.class, new SingletonResourceProvider(new CustomerService()));
sf.setAddress("http://localhost:9000/");
BindingFactoryManager manager = sf.getBus().getExtension(BindingFactoryManager.class);
JAXRSBindingFactory factory = new JAXRSBindingFactory();
factory.setBus(sf.getBus());
manager.registerBindingFactory(JAXRSBindingFactory.JAXRS_BINDING_ID, factory);
sf.create();
{code} 

h1. Configuring JAX-RS services in container with Spring configuration file.

h2. web.xml

In web.xml one needs to register one or more CXFServlet(s) and link to an application context configuration.

h3. Using Spring ContextLoaderListener

{code:xml}
<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>WEB-INF/beans.xml</param-value>
	</context-param>

	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>

	<servlet>
		<servlet-name>CXFServlet</servlet-name>
		<display-name>CXF Servlet</display-name>
		<servlet-class>
			org.apache.cxf.transport.servlet.CXFServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>CXFServlet</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>
{code}

The application context configuration is shared between all the CXFServlets

h3. Using CXFServlet init parameters 

{code:xml}
<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
	<servlet>
		<servlet-name>CXFServlet1</servlet-name>
		<display-name>CXF Servlet1</display-name>
		<servlet-class>
			org.apache.cxf.transport.servlet.CXFServlet
		</servlet-class>
                <init-param>
                   <param-name>config-location</param-name>
                   <param-value>/WEB-INF/beans1.xml</param-value>
                </init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

        <servlet>
		<servlet-name>CXFServlet2</servlet-name>
		<display-name>CXF Servlet2</display-name>
		<servlet-class>
			org.apache.cxf.transport.servlet.CXFServlet
		</servlet-class>
                <init-param>
                   <param-name>config-location</param-name>
                   <param-value>/WEB-INF/beans2.xml</param-value>
                </init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>


	<servlet-mapping>
		<servlet-name>CXFServlet1</servlet-name>
		<url-pattern>/1/*</url-pattern>
	</servlet-mapping>

        <servlet-mapping>
		<servlet-name>CXFServlet2</servlet-name>
		<url-pattern>/2/*</url-pattern>
	</servlet-mapping>
</web-app>
{code}

Each CXFServlet can get a unique application context configuration. Note, no Spring ContextLoaderListener is registered in web.xml in this case.

h2. beans.xml

{code:xml}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jaxrs="http://cxf.apache.org/jaxrs"
  xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd">

  <!-- do not use import statements if CXFServlet init parameters link to this beans.xml --> 

  <import resource="classpath:META-INF/cxf/cxf.xml" />
  <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
  <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

  <jaxrs:server id="customerService" address="/service1">
    <jaxrs:serviceBeans>
      <ref bean="customerBean" />
    </jaxrs:serviceBeans>
  </jaxrs:server>

  <bean id="customerBean" class="demo.jaxrs.server.CustomerService" />
</beans>
{code}

h1. Configuring JAX-RS services in container without Spring

If you prefer, you can register JAX-RS endpoints without depending on Spring with the help of CXFNonSpringJaxrsServlet :

{code:xml}
<servlet>
 <servlet-name>CXFServlet</servlet-name>
 <display-name>CXF Servlet</display-name>
 <servlet-class>
   org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet
 </servlet-class>
 <init-param>
  <param-name>jaxrs.serviceClasses</param-name>
  <param-value>
    org.apache.cxf.systest.jaxrs.BookStore1
    org.apache.cxf.systest.jaxrs.BookStore2		      
  </param-value>
 </init-param>
 <init-param>
  <param-name>jaxrs.providers</param-name>
  <param-value>
    org.apache.cxf.systest.jaxrs.BookStoreProvider1
    org.apache.cxf.systest.jaxrs.BookStoreProvider2		      
  </param-value>
 </init-param>
 <!-- enables schema validation -->
 <init-param>
  <param-name>jaxrs.schemaLocations</param-name>
  <param-value>
    classpath:/WEB-INF/schemas/schema1.xsd
    classpath:/WEB-INF/schemas/schema2.xsd		      
  </param-value>
 </init-param> 
 <!-- registers CXF in interceptors -->
 <init-param>
  <param-name>jaxrs.inInterceptors</param-name>
  <param-value>
    org.apache.cxf.systest.jaxrs.CustomInInterceptor
  </param-value>
 </init-param> 
 <!-- registers CXF out interceptors -->
 <init-param>
  <param-name>jaxrs.outInterceptors</param-name>
  <param-value>
    org.apache.cxf.systest.jaxrs.CustomOutInterceptor
  </param-value>
 </init-param>
<load-on-startup>1</load-on-startup>
</servlet>
{code}
  
When service classes and providers are registered this way, the default life-cycle is 'singleton'. You can override it by setting a "jaxrs.scope" parameter with the value of 'prototype' (equivalent to per-request). 
By default, the endpoint address is "/". One can provide a more specific value using a "jaxrs.address" parameter.

If the referenced service classes are not annotated with JAX-RS annotations then an external user model can also be linked to :


{code:xml}
<servlet>
 <servlet-name>CXFServlet</servlet-name>
 <display-name>CXF Servlet</display-name>
 <servlet-class>
   org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet
 </servlet-class>
 <init-param>
  <param-name>jaxrs.serviceClasses</param-name>
  <param-value>
    org.apache.cxf.systest.jaxrs.BookStore
  </param-value>
 </init-param>
 <!-- link to the user model -->
 <init-param>
  <param-name>user.model</param-name>
  <param-value>
    classpath:/models/resources.xml
  </param-value>
 </init-param> 
 <load-on-startup>1</load-on-startup>
</servlet>
{code}

A more portable way to register resource classes and providers with CXFNonSpringJaxrsServlet is to use a JAX-RS Application [implementation|http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookApplication.java] :


{code:xml}
<servlet>
 <servlet-name>CXFServlet</servlet-name>
 <display-name>CXF Servlet</display-name>
 <servlet-class>
   org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet
 </servlet-class>
 <init-param>
  <param-name>javax.ws.rs.Application</param-name>
  <param-value>
    org.apache.cxf.systest.jaxrs.BookApplication	      
  </param-value>
 </init-param>
 <!-- 
    This parameter is recognized only starting from CXF 2.3.1
    @ApplicationPath value will be ignored if this parameter is set to true
 -->
 <init-param>
  <param-name>jaxrs.application.address.ignore</param-name>
  <param-value>true</param-value>
 </init-param>
<load-on-startup>1</load-on-startup>
</servlet>
{code}

Note that Application.getClasses() method returns a set of per-request resource class names. Application.getSingletons() returns a list of singleton resource and provider classes. 


h2. Attaching JAXRS endpoints to an existing Jetty server

Here is a code fragment showing how it can be done with the help of CxfNonSpringJaxrsServlet :

{code:java}
CXFNonSpringJAXRSServlet cxf = new CXFNonSpringJaxrsServlet();

...

ServletHolder servlet = new ServletHolder(cxf);
servlet.setInitParameter("javax.ws.rs.Application", "com.acme.MyServiceImpl");
servlet.setName("services");
servlet.setForcedPath("services");
root.addServlet(servlet, "/*");

{code}

h1. JAX-RS RuntimeDelegate and Applications

h1. ConfiguringIf you have a JAX-RS services programmatically with Spring configuration file. 

When using Spring explicitly in your codeApplication implementation available and would like to minimize the interaction with the CXF JAX-RS specific API, you may want to follow this exampleuse the JAX-RS RuntimeDelegate :

{code:java}
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]
                      {"/org/apache/cxf/jaxrs/spring/servers.xml"});

// 'simple' is the id of the jaxrs server bean
JAXRSServerFactoryBean sfb = (JAXRSServerFactoryBean)ctx.getBean("simple");
sfb.create();

import javax.ws.rs.ext.RuntimeDelegate;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;

RuntimeDelegate delegate = RuntimeDelegate.getInstance();
JAXRSServerFactoryBean bean = delegate.createEndpoint(new CustomApplication(), JAXRSServerFactoryBean.class);

// before CXF 2.3.1 :
// bean.setAddress("http://localhost:8080/services");

bean.setAddress("http://localhost:8080/services" + bean.getAddress());

Server server = bean.create();
server.start();
// and finally
server.stop();

{code}

Note that in in this case your Spring configuration file should import cxf-extension-http-jetty.xml instead of cxf-servlet.xml :

{code:xml}
<!--
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
-->
<import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml" />
{code}

h1. Lifecycle management

h2. From Spring

The singleton scope is applied to all service beans which are injected like this :

{code:xml}
<beans>
  <jaxrs:server id="customerService" address="/service1">
    <jaxrs:serviceBeans>
 the above code makes sure an @ApplicationPath value (if CustomApplication has this annotation) is taken into account.

h1. Configuring JAX-RS services programmatically with Spring configuration file. 

When using Spring explicitly in your code, you may want to follow this example :
{code:java}
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]
          <ref bean="customerBean" />
    </jaxrs:serviceBeans>
  </jaxrs:server>
  <bean id="customerBean" class="demo.jaxrs.server.CustomerService" />
</beans>
{code}

You can support prototypes by either using a beanNames attribute or schemaFactories element :

{code:xml}
<beans>
  <jaxrs:server id="customerService" address="/service1"
    beanNames="customerBean2 customerBean3">
    <jaxrs:serviceBeans>
      <ref bean="customerBean" />
    </jaxrs:serviceBeans>
    <jaxrs:serviceFactories>
      <ref bean="sfactory1" />
      <ref bean="sfactory2" /> 
    </jaxrs:serviceFactories> {"/org/apache/cxf/jaxrs/spring/servers.xml"});

// 'simple' is the id of the jaxrs server bean
JAXRSServerFactoryBean sfb = (JAXRSServerFactoryBean)ctx.getBean("simple");
sfb.create();
{code}

Note that in in this case your Spring configuration file should import cxf-extension-http-jetty.xml instead of cxf-servlet.xml :

{code:xml}
<!--
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
-->
<import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml" />
{code}

h1. Lifecycle management

h2. From Spring

The singleton scope is applied to all service beans which are injected like this :

{code:xml}
<beans>
  <jaxrs:server id="customerService" address="/service1">
    <jaxrs:serviceBeans>
      <ref bean="customerBean" />
    </jaxrs:serviceBeans>
  </jaxrs:server>
  <bean id="customerBean" class="demo.jaxrs.server.CustomerService" />
  <bean </beans>
{code}

You can support prototypes by either using a beanNames attribute or schemaFactories element :

{code:xml}
<beans>
  <jaxrs:server id="customerBean2customerService" classaddress="demo.jaxrs.server.CustomerService2"  scope="prototype"//service1"
    beanNames="customerBean2 customerBean3">
  <bean id="customerBean3" class="demo.jaxrs.server.CustomerService3"  scope="prototype"/> 

  <bean id="sfactory1" class="org.apache.cxf.jaxrs.spring.SpringResourceFactory"  <jaxrs:serviceBeans>
      <ref bean="customerBean" />
    </jaxrs:serviceBeans>
    <jaxrs:serviceFactories>
      <ref bean="sfactory1" />
     <property <ref namebean="beanNamesfactory2" value="customerBean4"/> 
    </bean>jaxrs:serviceFactories>
  </jaxrs:server>
  <bean id="sfactory2customerBean" class="org.apachedemo.cxf.jaxrs.springserver.SpringResourceFactoryCustomerService">
     <property name="beanName" value="customerBean5"/>
  </bean>

  <bean id="customerBean4customerBean2" class="demo.jaxrs.server.CustomerService4CustomerService2"  scope="prototype"/> 
  <bean id="customerBean5customerBean3" class="demo.jaxrs.server.CustomerService5CustomerService3"  scope="prototype"/> 
</beans>
{code}


h2. With CXFNonSpringJaxrsServlet

CXFNonSpringJaxrsServlet uses 'Singleton' as a default scope for service classes specified by a "jaxrs.serviceClasses" servlet parameter. It can be overridden by setting a "jaxrs.scope" parameter to a "prototype" value or by not using the "jaxrs.serviceClasses" parameter at all and registering a JAXRS Application implementation instead. Please see the section describing CXFNonSpringJaxrsServlet for more details.

CXFNonSpringJaxrsServlet can support singleton scopes for classes with constructors expecting JAXRS contexts, at the moment it can only inject ServletContext or ServletConfig contexts :

{code:java}
@Path("/")
public class SingletonResourceClass {
   public SingletonResourceClass(@Context ServletContext context, @Context ServletConfig context2) {}
}
{code} 

h2. Programmatically

{code:java}
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setResourceClass(CustomerService.class);
sf.setResourceProvider(new SingletonResourceProvider(new 
  <bean id="sfactory1" class="org.apache.cxf.jaxrs.spring.SpringResourceFactory">
     <property name="beanName" value="customerBean4"/>
  </bean>
  <bean id="sfactory2" class="org.apache.cxf.jaxrs.spring.SpringResourceFactory">
     <property name="beanName" value="customerBean5"/>
  </bean>

  <bean id="customerBean4" class="demo.jaxrs.server.CustomerService4" scope="prototype"/> 
  <bean id="customerBean5" class="demo.jaxrs.server.CustomerService5"  scope="prototype"/> 
</beans>
{code}


h2. With CXFNonSpringJaxrsServlet

CXFNonSpringJaxrsServlet uses 'Singleton' as a default scope for service classes specified by a "jaxrs.serviceClasses" servlet parameter. It can be overridden by setting a "jaxrs.scope" parameter to a "prototype" value or by not using the "jaxrs.serviceClasses" parameter at all and registering a JAXRS Application implementation instead. Please see the section describing CXFNonSpringJaxrsServlet for more details.

CXFNonSpringJaxrsServlet can support singleton scopes for classes with constructors expecting JAXRS contexts, at the moment it can only inject ServletContext or ServletConfig contexts :

{code:java}
@Path("/")
public class SingletonResourceClass {
   public SingletonResourceClass(@Context ServletContext context, @Context ServletConfig context2) {}
}
{code} 

h2. Programmatically

{code:java}
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setResourceClass(CustomerService.class);
sf.setResourceProvider(new SingletonResourceProvider(new CustomerService()));
sf.setResourceClass(CustomerService2.class);
sf.setResourceProvider(new PerRequestResourceProvider(CustomerService.class));
{code}

h2. PostConstruct and PreDestroy

Bean methods annotated with @PostConstruct and @PreDestroy annotations will be called as expected by the scope rules. 
Singleton}

h2. PostConstruct and PreDestroy

Bean methods annotated with @PostConstruct and @PreDestroy annotations will be called as expected by the scope rules. 
Singleton beans will have their postconstruct method called when the endpoint is created. If a given singleton resource instance was created by Spring then its predestroy method will also be called after, for example, the web application which uses it is about to be unloaded. At the moment singletons created by CXFNonSpringJaxrsServlet or programmatically will only have their postconstruct method (if any) called.  

Prototype beans will have their postconstruct method called when the endpoint is created. If a given singleton resource instance was created by Spring then its and predestroy method called before a resource method is invoked and immediately after the invocation has returned but before the response has actually been serialized. You can indicate that the predestroy method willhas alsoto be called after, for example, the web application which uses it is about to be unloaded. At the moment singletons created by CXFNonSpringJaxrsServlet or programmatically will only have their postconstruct method (if any) called.  

Prototype beans will have their postconstruct and predestroy method called before a resource method is invoked and immediately after the invocation has returned but before the response has actually been serialized. You can indicate that the predestroy method has to be called after the request has completely gone out of scope (that is after the response body if any has been written to the output stream) by adding an "org.apache.cxf.jaxrs.service.scope" property with the value set to "request".

You can also register a custom Spring resource factory by extending org.apache.cxf.jaxrs.spring.SpringResourceFactory or providing a more sophisticated implementation.

h1. Locating custom resources in web applications

Resources like schemas, custom XSLT templates and user models are typically referenced using a classpath: prefix. Thus one can add them to a WEB-INF/classes folder in a given web application.
Since CXF 2.2.3 one can put them directly under WEB-INF, for example into WEB-INF/xslt,  WEB-INF/schemas, WEB-INF/model and referencing them like 'classpath:/WEB-INF/xslt/template.xsl'.

h1. Multiple endpoints and resource classes

One can configure as many jaxrs:server endpoints as needed for a given application, with every endpoint possibly providing an alternative path to a single resource bean. Every endpoint can employ as many shared or unique resource classes as needed, and have common or different providers.  

 the request has completely gone out of scope (that is after the response body if any has been written to the output stream) by adding an "org.apache.cxf.jaxrs.service.scope" property with the value set to "request".

You can also register a custom Spring resource factory by extending org.apache.cxf.jaxrs.spring.SpringResourceFactory or providing a more sophisticated implementation.

h1. Locating custom resources in web applications

Resources like schemas, custom XSLT templates and user models are typically referenced using a classpath: prefix. Thus one can add them to a WEB-INF/classes folder in a given web application.
Since CXF 2.2.3 one can put them directly under WEB-INF, for example into WEB-INF/xslt,  WEB-INF/schemas, WEB-INF/model and referencing them like 'classpath:/WEB-INF/xslt/template.xsl'.

h1. Multiple endpoints and resource classes

One can configure as many jaxrs:server endpoints as needed for a given application, with every endpoint possibly providing an alternative path to a single resource bean. Every endpoint can employ as many shared or unique resource classes as needed, and have common or different providers.  

h1. Dynamic servlets and a single JAX-RS endpoint

In some advanced cases you may want to dynamically add new servlets (CXFServlet or CXFNonSpringJaxrsServlet) with all of them serving the same JAX-RS endpoints. In this case you most likely want to configure servlets so that the CXF endpoint address is not overridden :

{code:xml}
{code:xml}
<servlet>
 <servlet-name>CXFServlet</servlet-name>
 <display-name>CXF Servlet</display-name>
 <servlet-class>
     org.apache.cxf.transport.servlet.CXFServlet
 </servlet-class>
 <init-param>
    <param-name>config-location</param-name>
    <param-value>/WEB-INF/beans1.xml</param-value>
 </init-param>
 <init-param>
    <param-name>disable-address-updates</param-name>
    <param-value>true</param-value>
 </init-param>
 <load-on-startup>1</load-on-startup>
</servlet>
{code}

{code}