You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 187 Next »

Unknown macro: {span}

JAX-RS (JSR-311)

Introduction

CXF supports JAX-RS (JSR-311), Java API for RESTful Web Services. JAX-RS standardizes the way RESTful services can be developed in Java.

CXF 2.3.0 supports JSR-311 API 1.1.
CXF 2.2.x supports JSR-311 API 1.0 .
CXF 2.3.0 and CXF 2.2.x have passed JAX-RS TCK 1.1 and TCK 1.0 respectively.

CXF 2.1.x supports JSR-311 API 0.8.

JAX-RS related demos are located under the samples/jax_rs directory.
This documentation will refer to JSR-311 API 1.1 .

Migration

Migrating from JAX-RS 0.8 to 1.0

The following major changes in 1.0 will most likely affect users migrating from 0.8

  • @ProduceMime and @ConsumeMime have been replaced with @Produces and @Consumes respectively
  • HttpHeaders has had some of its methods returning a string representation of Locale updated to return Locale instead

Migrating from 1.0 to 1.1

Existing JAX-RS 1.0 applications should run in CXF 2.3.0 without any problems.
There have been just few minor modifications at the JAX-RS API level :

  • @ApplicationPath has been introduced which JAX-RS Application implementations can be annotated with;
  • Request interface has been updated with a new evaluatePreconditions method with no input parameters - the existing applications which are already using the Request interface may need to be recompiled.

Maven dependencies

To incorporate JAX-RS, you will need:

   <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-frontend-jaxrs</artifactId>
      <version>2.3.0</version>
   </dependency>

This will in turn pull in other CXF modules such cxf-api, cxf-rt-core, cxf-rt-transports-http and cxf-rt-bindings-xml as well as the following 3rd-party dependencies:

1. javax.ws.rs/jsr311-api/1.1 (or 1.0 for CXF 2.2.x)

2. org.apache.abdera groupId : abdera-core, abdera-parser and abdera-extensions-json artifacts, version 1.1. Note that starting from CXF 2.3.0 the Abdera dependencies are optional.

3. org.springframework/spring-core/3.0.5-RELEASE (and other core Spring dependencies)

4. org.codehaus.jettison/jettison/1.2

5. org.apache.xmlbeans/xmlbeans/2.4.0

Please check the pom.xml for the list of cxf components used by the JAX-RS implementation. Snapshots are available from http://repository.apache.org/snapshots/org/apache/cxf/apache-cxf/

Setting up the classpath in Eclipse or Ant

If Maven is not used then the following jars need to be available at the runtime classpath.

For CXF 2.3.0:

  • cxf-2.3.0.jar
  • jsr311-api-1.1.jar
  • jaxb-impl-2.1.13.jar
  • jaxb-api-2.1.jar
  • geronimo-annotation_1.0_spec-1.1.1.jar
  • geronimo-activation_1.1_spec-1.1.jar
  • geronimo-servlet_3.0_spec_1.0.jar
  • commons-logging-1.1.1.jar
  • geronimo-stax_api_1.0_spec-1.0.1.jar
  • woodstox-core-asl-4.0.8.jar
  • stax2-api-3.0.1.jar
  • wsdl4j-1.6.2.jar
  • XmlSchema-1.4.5.jar
  • neethi-2.0.4.jar

For CXF 2.2.x the dependencies are similar :

  • cxf-2.2.12.jar
  • jsr311-api-1.0.jar
  • do not add stax2-api-3.0.1.jar
  • add wstx-asl-3.2.8.jar instead of woodstox-core-asl-4.0.3.jar
  • add saaj-api-1.3.jar

If Spring configuration is used then add spring.jar from the Spring distribution or the spring jars available in the CXF distribution. When creating client proxies from concrete classes the cglib-nodep-2.1_3.jar needs to be added. You do not need to add JAXB libraries if you do not use JAXB. If you depend on Jetty then you will also need to add Jetty 7 or Jetty 6 jars shipped with CXF 2.3.0 and 2.2.12 respectively.

We will work on reducing the set of required dependencies.
Please see the configuration sections below on how a spring dependency can be dropped.

CXF JAX-RS bundle

A standalone JAX-RS bundle is now available which may be of interest to users doing JAX-RS work only.

Understanding the basics

You are encouraged to read JAX-RS spec (html version) to find out information not covered by this documentation.

The JAX-RS introduces such terms as root resources, resource methods, sub-resources and sub-resource locators, message body readers and writers, etc.

Please see the JAX-RS Basics page for more information.

Support for data bindings

JAX-RS MessageBodyReader and MessageBodyWriter can be used to create data bindings for reading and writing the data in a number of different formats. Compliant JAX-RS implementations are expected to support JAXB-annotated beans, JAXP Source objects, InputStreams, etc.

In addition, CXF JAX-RS lets users reuse existing CXF DataBindings for working with JAXB, XBeans, Aegis and SDO.

Please see the JAX-RS Data Bindings page for more information.

Advanced Search Capabilities

Using query parameter beans provides for a way to capture all the search requirements which can be expressed by enumerating simple name/value pairs, example, a query such as '?name=CXF&version=2.3' can be captured by a bean containing setName and setVersion methods. This 'template' bean can be used in the code to compare it against all the available local data.

CXF JAXRS (since 2.3) supports another option for users to do the advanced search queries based on the Feed Item Query Language(FIQL). FIQL lets users express complex search expressions using an intuitive and URI friendly language.

For example, a query such as

?_search=name==CXF;version=ge=2.2

lets users to search for all the Apache projects with the name 'CXF' and the version greater or equals to '2.2'. The initial '=' separates the name of the query '_search' from the FIQL expression, while '==' and '=ge=' convey 'equals to' and 'greater or equals to' respectively.

More complex composite expressions can also be expressed easily enough.

Note that either '_search' or '_s' query has to be used to pass the FIQL expression.

To avail of this feature, a SearchContext can be injected into an application code and used to retrieve a SearchCondition representing the current FIQL query. This SearchCondition can be used in a number of ways for finding the matching data.

For example :

@Path("books")
public class Books {

private Map<Long, Book> books;
@Context
private SearchContext context;

 @GET
 public List<Book> getBook() {

   SearchCondition<Book> sc = searchContext.getCondition(Book.class);
   // SearchCondition#isMet method can also be used to build a list of matching beans
   List<Book> found = sc.findAll(books.values());
   return found;
 }
}

SearchCondition can also be used to get to all the search requirements (originally expressed in FIQL) and do some manual
comparison against the local data. For example, SearchCondition provides a utility toSQL(String tableName, String... columnNames) method which internally introspects all the search expressions constituting a current query and converts them into an SQL expression :

// find all conditions with names starting from 'ami' 
// and levels greater than 10 :
// ?_s="name==ami*;level=gt=10"
SearchCondition<Book> sc = searchContext.getCondition(Book.class);
assertEquals("SELECT * FROM table 
              WHERE 
              name LIKE 'ami%' 
              AND 
              level > '10'",
              sq.toSQL("table"));

Debugging and Logging

One can easily try from a browser how a given resource class reacts to different HTTP Accept or Accept-Language header values. For example, if a resource class supports a "/resource" URI then one can test the resource class using one of the following queries :

GET /resource.xml
GET /resource.en

The runtime will replace '.xml' or '.en' with an appropriate header value. For it to know the type or language value associated with a given URI suffix, some configuration needs to be done. Here's an example how to do it in Spring :


  <jaxrs:server id="customerService" address="/">
    <jaxrs:serviceBeans>
      <bean class="org.apache.cxf.jaxrs.systests.CustomerService" />
    </jaxrs:serviceBeans>
    <jaxrs:extensionMappings>
      <entry key="json" value="application/json"/>
      <entry key="xml" value="application/xml"/>
    </jaxrs:extensionMappings>
    <jaxrs:languageMappings/>
  </jaxrs:server>

CXF also supports a _type query as an alternative to appending extensions like '.xml' to request URIs :

GET /resource?_type=xml

Please see the Debugging and Logging page for more information on how to debug and log the service calls in CXF.

Logging

Many of the existing CXF features can be applied either to jaxrs:server or jaxrs:client. For example, to enable the logging of requests and responses, simply do:

<beans xmlns:cxf="http://cxf.apache.org/core" 
 xsi:schemaLocation="http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">
<jaxrs:server>
<jaxrs:features>
     <cxf:logging/>
</jaxrs:features>
<jaxrs:server>
</beans>

Please make sure an "http://cxf.apache.org/core" namespace is in scope.

Starting from CXF 2.3.0 it is also possible to convert log events into Atom entries and either push them to receivers or make available for polling.

Please see the Debugging and Logging page for more information.

ATOM logging

This feature is available since 2.3, as part of the cxf-rt-management-web component

CXF supports collecting log events, converting them to ATOM Syndication Format and either pushing to the client or making them available for polling. Logging is based on custom java.util.logging (JUL) handler that can be registered with loggers extending today's publishing protocols.

CXF JAXRS and JAXWS endpoints can avail of this feature.

Push Style

Push-style handler enqueues log records as they are published from loggers. After the queue size exceeds configurable "batch size", processing of collection of these records (in size of batch size) is triggered. Batch of log events is transformed by converter to ATOM element and then it is pushed out by deliverer to client. Both converter and deliverer are configurable units that allow to change transformation and transportation strategies. Next to predefined own custom implementations can be used when necessary – see examples. Batches are processed sequentially to allow client side to recreate stream of events.

Limitations: Reliability is not supported out of the box, however there is predefined retrying delivery strategy. Persistence is also not supported, any enqueued and undelivered log events are lost on shutdown. Definitions of delivery endpoints is static, subscription of callback URIs is not yet supported.

Spring configuration

In simplest case pushing ATOM Feeds can be declared this way:

   <bean class="org.apache.cxf.management.web.logging.atom.AtomPushBean" init-method="init">
       <property name="url" value="http://somewhere.com/foo/bar"/>
       <property name="level" value="ALL" />
   </bean>

Spring bean creates ATOM push handler and registers it with root logger for all log levels. This setup leads to logging everything CXF, Spring and others inclued. Since batch size is not specified default value of one is used - each event is packed up as single feed pushed out to specified URL. Default conversion strategy and default WebClient-based deliver are used.

More complex example shows how to specify non-root logger and define batch size:

   <bean class="org.apache.cxf.management.web.logging.atom.AtomPushBean" init-method="init">
       <property name="url" value="http://somewhere.com/foo/bar"/>
       <property name="logger" value="org.apache.cxf.jaxrs" />
       <property name="level" value="INFO" />
       <property name="batchSize" value="10" />
   </bean>

To push to client events generated by different loggers on different levels, "loggers" property must be used instead of pair "logger" and "level":

   <bean class="org.apache.cxf.jaxrs.management.web.atom.AtomPushBean" init-method="init">
       <property name="url" value="http://somewhere.com/foo/bar"/>
       <property name="loggers" value="
           org.apache.cxf:DEBUG,
           org.apache.cxf.jaxrs,
           org.apache.cxf.bus:ERROR,
           myNamedLogger:INFO" />
   </bean>

In example above, second logger does not have specified level, in such case default level of "INFO" is used.

In all above cases, when first delivery fails engine of ATOM push handler is shutdown and no events will be processed and pushed until configuration reload. To avoid this frequent case, retrial can be enabled:

   <bean class="org.apache.cxf.management.web.logging.atom.AtomPushBean" init-method="init">
       <property name="url" value="http://somewhere.com/foo/bar"/>
       <property name="logger" value="org.apache.cxf.jaxrs" />
       <property name="level" value="INFO" />
       <property name="retryPause" value="linear" />
       <property name="retryPauseTime" value="60" />
       <property name="retryTimeout" value="300" />
   </bean>

In this case for 5 minutes ("retryTimeout") after delivery failure there will be 1 minute pause ("retryPauseTime") repeated every time with same value ("retryPause" as "linear"). Instead of same pause time, "exponential" value of "retryPause" can be used - each next time pause time doubles. When timeout value is set to 0 retrying is infinite. In case of invalid or missing values defaults are used: for pause time 30 seconds and for timeout 0 (infinite). Instead of same pause time, "exponential" value of "retryPauseType" can be used - each next time pause time doubles. When timeout value is set to 0 retrying is infinite. In case of invalid or missing values defaults are used: for pause time 30 seconds and for timeout 0 (infinite).

Ultimate control is given by "converter" and "deliverer" properties. Either beans of predefined or custom classes can be used (see "Programming syle" chapter for more details). Example below shows custom class using different transport protocol than default:

   <bean id="soapDeliverer" ...
   ...
   <bean class="org.apache.cxf.management.web.logging.atom.AtomPushBean" init-method="init">
       <property name="deliverer">
           <ref bean="soapDeliverer"/>
       </property>
       <property name="loggers" ... />
   </bean>

Note that specifying custom deliverer cause ignoring "url" and "retryXxx" because underneath configuration replaces employed tandem of RetryingDeliverer and WebClientDeliverer with provided one.

When ATOM feeds must be delivered to more than one endpoint and additionally each endpoint is fed by different loggers simply use multiple ATOM push beans in Spring config:

   <bean id="atom1" class="org.apache.cxf.management.web.logging.atom.AtomPushBean" init-method="init">
       <property name="url" value="http://someplace.com/foo/bar"/>
       ...
   </bean>
   <bean id="atom2" class="org.apache.cxf.jaxrs.management.web.atom.AtomPushBean" init-method="init">
       <property name="url" value="http://otherplace.com/baz/blah"/>
       ...
   </bean>
   ....

Properties file

When CXF is used either without Spring or logging is configured with properties file, support for this type of configuration becomes handy. ATOM push handler supports "simple configuration" with properties file; simple means aligned to expressiveness of JUL configuration that is limited to cases, where each type of handler can be used only once and registered with root logger.

Set of properties is very similar to Spring configuration with following exceptions:

  • Properties specify classes of custom deliverers and converters, instead of instances.
  • Custom deliverer must have public constructor with the only String parameters; created instance will have passed URL of client.
  • Multiple client endpoints is not supported out of the box (cannot instantiate multiple handlers as in Spring)

Example:

 handlers = org.apache.cxf.management.web.logging.atom.AtomPushHandler, java.util.logging.ConsoleHandler
 .level = INFO
 ...
 org.apache.cxf.jaxrs.ext.management.web.AtomPushHandler.url = http://localhost:9080
 org.apache.cxf.jaxrs.ext.management.web.AtomPushHandler.batchSize = 10
 org.apache.cxf.jaxrs.ext.management.web.AtomPushHandler.deliverer = WebClientDeliverer 
 org.apache.cxf.jaxrs.ext.management.web.AtomPushHandler.converter = foo.bar.MyConverter
 org.apache.cxf.jaxrs.ext.management.web.AtomPushHandler.retry.pause = linear
 org.apache.cxf.jaxrs.ext.management.web.AtomPushHandler.retry.pause.time = 10
 org.apache.cxf.jaxrs.ext.management.web.AtomPushHandler.retry.timeout = 360
 ...

Programming style

In most complex cases direct programming using org.apache.cxf.jaxrs.ext.logging.atom package may be necessary. In this case AtomPushHandler class is main artifact and Deliverer and Converter interfaces and their implementations are necessary components.

Following example:

    Deliverer d = new WebClientDeliverer("http://somewhere.com/foo/bar");
    d = new RetryingDeliverer(d, 300, 60, true);
    Converter c = new SingleEntryContentConverter();
    AtomPushHandler h = new AtomPushHandler(1, c, d);    
    Logger l = Logger.getLogger("org.apache.cxf.jaxrs");
    l.setLevel(Level.INFO);
    l.addHandler(h);

is equivalent to Spring configuration:

   <bean class="org.apache.cxf.management.web.logging.atom.AtomPushBean" init-method="init">
       <property name="url" value="http://somewhere.com/foo/bar"/>
       <property name="logger" value="org.apache.cxf.jaxrs" />
       <property name="level" value="INFO" />
       <property name="retryPause" value="linear" />
       <property name="retryPauseTime" value="60" />
       <property name="retryTimeout" value="300" />
   </bean>

Poll Style

AtomPullServer acts as an Atom feed endpoint and makes all log events it has accumulated or read from some external storage available for polling.

Log events are made available in pages, that is a feed instance will list up to a configurable maximum number of entries and will also include atom links of types 'prev', 'next', 'first' and 'last', thus making it possible to browse through all the log records.

Spring configuration

When configuring AtomPullServer endpoints, one can set the 'loggers' property the same way as it is done for AtomPushBeans, for example :

   <bean class="org.apache.cxf.management.web.logging.atom.AtomPullServer" init-method="init">
       <property name="loggers" value="
           org.apache.cxf:DEBUG,
           org.apache.cxf.jaxrs,
           org.apache.cxf.bus:ERROR,
           myNamedLogger:INFO" />
       <property name="pageSize" value="30"/>
   </bean>

In addition to the 'loggers' property, a 'pageSize' property limiting a number of entries per page to 30 is also set (default is 40).

One can have a ReadWriteLogStorage bean injected into AtomPushBean if the log records have to be periodically offloaded from memory and persisted across restarts :

   <bean id="storage" class="org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPullSpringTest$Storage"/>

   <bean class="org.apache.cxf.management.web.logging.atom.AtomPullServer" init-method="init">
       <property name="loggers" value="org.apache.cxf.jaxrs" />
       <property name="maxInMemorySize" value="400"/>
       <property name="storage">
           <ref bean="storage"/>
       </property>
   </bean>

When a number of records in memory reaches 400 (default is 500) then the records will be offloaded into a provided storage and will be read from it after the restart or when a client has requested a relevant page. If no storage is available then after an in-memory limit is reached the oldest records will be discarded, one can set a maxInMemorySize property to a large enough value if needed.

Another option is to require a given AtomPullServer to read from the external read-only storage by registering a ReadableLogStorage bean. For example, very often, the runtime is already logging to some external file, thus AtomPullServer can be asked to read from this file only with the help of ReadableLogStorage, without AtomPullServer having to catch log events too.

Once AtomPullServer has been configured, it has to be registered as a service bean with the jaxrs endpoint so that Atom aware clients (blog readers, etc) can start polling it :

<jaxrs:server id="atomServer" address="/atom">
 <jaxrs:serviceBeans>
   <ref bean="atomPullServer"/>
 </jaxrs:serviceBeans>

 <jaxrs:providers>
  <ref bean="feed"/>
  <ref bean="entry"/>
 </jaxrs:providers>
</jaxrs:server>

<bean id="feed" class="org.apache.cxf.jaxrs.provider.AtomFeedProvider"/>
<bean id="entry" class="org.apache.cxf.jaxrs.provider.AtomEntryProvider"/>

Linking to Atom endpoints from CXF Services page

If you would like your users to find about the Atom feeds which are collecting log events from your endpoints then AtomPullServers will need to have a CXF bus injected, as well as be told about the address of the corresponding atom feed endpoint and of the jaxrs or jaxws endpoint :

<bean id="atomPullServer" class="org.apache.cxf.management.web.logging.atom.AtomPullServer" init-method="init">
<property name="loggers" value="org.apache.cxf.systest.jaxrs.JAXRSLoggingAtomPullSpringTest$Resource:ALL"/>
<property name="bus">
<ref bean="cxf"/>
</property>
<!-- this is a jaxrs:server/@adrress or jaxws:endpoint/@address of the endpoint generating the log events -->
<property name="endpointAddress" value="/resource"/>
<!-- this is a jaxrs:server/@address of the endpoint for which this atomPullServer bean is registered as a service bean -->
<property name="serverAddress" value="/atom"/>
</bean>

Filters

CXF suports filters. Often it's necessary to pre- or post-process some requests according to a number of requirements.
For example, a request like

GET /resource?_type=xml is supported by a CXF specific RequestHandler filter which modifies the CXF input Message
by updating one of its headers.

In some cases users can use the existing filter technologies such as Servler filters or Spring AOP proxies. In other cases, it can be handy
to write a CXF filter which will introspect the resource class, input or output message, the operation which was invoked and modify the request or response accordingly.

Here are the interface definitions :

public interface RequestHandler {
    
    Response handleRequest(Message inputMessage, 
                           ClassResourceInfo resourceClass);

}

The request handler implementation can either modify the input Message and let the request to proceed or block the request by returning a non-null Response.

A response filter implementation can get an access to OperationResourceInfo object representing a method to be invoked on a resource class :

OperationResourceInfo ori = exchange.get(OperationResourceInfo.class);

Use OperationResourceInfo in your filter with care. In principle a given request chain may have filters which may want to overwrite Accept or ContentType message headers which might lead to another method be selected. However if you know no such filters (will) exist in your application then you might want to check an OperationResourceInfo instance as part of your filter logic.

When modifying an input message, one would typically want to replace a message input stream or one of its headers, such as ContentType :

InputStream is = message.getContent(InputStream.class);
message.setContent(new MyFilterInputStream(is));
message.put(Message.ACCEPT_CONTENT_TYPE, "custom/media"); 
public interface ResponseHandler {
    
    Response handleResponse(Message outputMessage,
                           OperationResourceInfo invokedOperation, 
                           Response response);

}

The response handler implementation can optionally overwrite or modify the application Response or modify the output message. When modifying an output message, one may want to either replace an output stream before message body providers attempt to write to it or replace the actual response object :

// replace an output stream
OutputStream os = message.getContent(OutputStream.class);
message.setContent(new MyFilterOutputStream(os));

// replace an actual object
response.setEntity(new MyWrapper(response.getEntity()))
// or using a low-level Message api if needed
MessageContentsList objs = MessageContentsList.getContentsList(message);
if (objs !== null && objs.size() == 1) {
    Object responseObj = objs.remove(0);
    obj.add(new MyWrapper(responseObj));
}

Please see this blog entry for another example of when response filters can be useful.

Multiple request and response handlers are supported.

The implementations can be registered like any other types of providers :


<beans>
<jaxrs:server id="customerService" address="/">
    <jaxrs:serviceBeans>
      <bean class="org.CustomerService" />
    </jaxrs:serviceBeans>

    <jaxrs:providers>
      <ref bean="authorizationFilter" />
    </jaxrs:providers>
    <bean id="authorizationFilter" class="com.bar.providers.AuthorizationRequestHandler">
        <!-- authorization bean properties -->
    </bean>
</jaxrs:server>
</beans>

Difference between JAXRS filters and CXF interceptors

JAXRS runtime flow is mainly implemented by a pair of 'classical' CXF interceptors. JAXRSInInterceptor is currently at Phase.PRE_STREAM phase while JAXRSOutInterceptor is currently at Phase.MARSHAL phase.

JAXRS filters can be thought of as additional handlers. JAXRSInInterceptor deals with a chain of RequestHandlers, just before the invocation. JAXRSOutInterceptor deals with a chain of ResponseHandlers, just after the invocation but before message body writers get their chance.

Sometimes you may want to use CXF interceptors rather than writing JAXRS filters. For example, suppose you combine JAXWS and JAXRS and you need to log only inbound or outbound messages. You can reuse the existing CXF interceptors :

<beans>
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>

<jaxrs:server> 
 <jaxrs:inInterceptors>
     <ref bean="logInbound"/>
 </jaxrs:inInterceptors>
 <jaxrs:outInterceptors>
    <ref bean="logOutbound"/>
 </jaxrs:outInterceptors>
</jaxrs:server>

<jaxws:endpoint>
 <jaxws:inInterceptors>
     <ref bean="logInbound"/>
 </jaxws:inInterceptors>
 <jaxws:outInterceptors>
    <ref bean="logOutbound"/>
 </jaxws:outInterceptors>
</jaxws:endpoint>

</beans>

Reusing other CXF interceptors/features such as GZIP handlers can be useful too.

Overriding request and response properties

Now and then one needs to overwrite various request and response properties like HTTP method or request URI,
response headers or status codes. JAX-RS Response may be used to specify custom status and response headers but
it might be intrusive to use it in certain cases.

Here are some more examples.

Overriding HTTP method

There are 3 options available :
1. Use a _method system query like

> GET /books?_method=RETRIEVE

2. Register a custom RequestHandler filter which will replace the current method value keyed by
Message.HTTP_REQUEST_METHOD in a given Message.

3. Specify an HTTP header X-HTTP-Method-Override :

> POST /books
> X-HTTP-Method-Override : PATCH

For example, at the moment http-centric client API does not support arbitrary HTTP verbs except for those supported
by Java HTTPUrlConnection. When needed, X-HTTP-Method-Override can be set to overcome this limitation.

Overriding request URI

One can do it either from a CXF input interceptor (registered at the early phase like USER_STREAM) or from a RequestHandler filter, for example :

String s = m.get(Message.REQUEST_URI);
s += "/data/";
m.put(Message.REQUEST_URI, s);

Similarly, one can update request HTTP headers, by modifying a Message.REQUEST_HEADERS Message object which is a Map containing String and List of Strings entries.

Overriding response status code and headers

It is assumed here a user prefers not to use explicit Response objects in the application code.
This can be done either from a CXF output interceptor (phase like MARSHALL will do) or from a ResponseHandler filter, for example this code will work for both JAXRS and JAXWS :

public class CustomOutInterceptor extends AbstractOutDatabindingInterceptor {
    
    public CustomOutInterceptor() {
        super(Phase.MARSHAL);
    }

    public void handleMessage(Message outMessage) {
        Map<String, List<String>> headers = (Map<String, List<String>>)outMessage.get(Message.PROTOCOL_HEADERS);
        // modify headers  
    }    

At the moment it is not possible to override a response status code from a CXF interceptor running before JAXRSOutInterceptor, like CustomOutInterceptor above, which will be fixed.
The only option at the moment is to use a custom ResponseHandler which will replace the current Response object with another one containing the required status.

Ignoring JAXRS MessageBodyWriters

In some cases you may want to have a JAXRS Response entity which a given RequestHandler or ResponseHandler has produced to be directly written to the output stream. For example, a CXF JAXRS WADLGenerator RequestHandler produces an XML content which does not have to be serialized by JAXRS MessageBodyWriters. If you do need to have the writers ignored then set the following property on the current exchange in the custom handler :

message.getExchange().put("ignore.response.writers", true);

Custom invokers

Note This feature is not available in CXF 2.2.1

Using custom JAXR-RS invokers is yet another way to pre or post process a given invocation. For example, this invoker does a security check before delegating to the default JAXRS invoker. A custom invoker, like a request filter, has the access to all the information accumulated during the processing of a given call, but additionally, it can also check the actual method parameter values.

Custom invokers can be registered like this :

<beans>

<jaxrs:server address="/"> 
 <jaxrs:invoker>
   <bean class="org.apache.cxf.systest.jaxrs.CustomJAXRSInvoker"/>
 </jaxrs:invoker>
</jaxrs:server>

</beans>

Advanced HTTP

CXF JAXRS provides support for a number of advanced HTTP features by handling If-Match, If-Modified-Since and ETags headers. JAXRS Request context object can be used to check the preconditions. Vary, CacheControl, Cookies and Set-Cookies are also supported.

Support for Continuations

Please see this blog entry describing how JAXRS (and indeed) JAXWS services can rely on the CXF Continuations API. Currently, only Jetty based services can rely on this option.

Secure JAX-RS services

A demo called samples\jax_rs\basic_https shows you how to do communications using HTTPS.
Spring Security can be quite easily applied too (see "JAXRS and Spring AOP" section for some general advice).

Checking HTTP security headers

It is often containers like Tomcat or frameworks like Spring Security which deal with ensuring a current user is authenticated.
Sometimes you might want to deal with the authentication manually. The easiest way to do it is to register a custom invoker or RequestHandler filter
which will extract a user name and password like this (note it will work only for basic authentication requests only) :

public class AuthenticationHandler implements RequestHandler {

    public Response handleRequest(Message m, ClassResourceInfo resourceClass) {
        AuthorizationPolicy policy = (AuthorizationPolicy)m.get(AuthorizationPolicy.class);
        policy.getUserName();
        policy.getPassword(); 
        // alternatively :
        // HttpHeaders headers = new HttpHeadersImpl(m);
        // access the headers as needed  
        return null;
    }

}

SecurityManager and IllegalAccessExceptions

If java.lang.SecurityManager is installed then you'll likely need to configure the trusted JAXRS codebase with a 'suppressAccessChecks' permission for the injection of JAXRS context or parameter fields to succeed. For example, you may want to update a Tomcat catalina.policy with the following permission :

grant codeBase "file:${catalina.home}/webapps/yourwebapp/lib/cxf.jar" {
    permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};

Client API

JAX-RS 1.0 does not provide for the standard approach toward consuming pure HTTP-based services thus CXF JAX-RS provides a comprehensive support for developing RESTful clients by introducing 3 flavors of the client API : proxy-based, HTTP-centric and XML-centric.

Please see the JAX-RS Client API page for more information.

XPath and XSLT

XPath and XSLT are promoted and treated as first-class citizens in CXF JAX-RS. These technologies can be very powerful when generating complex data or retrieving data of interest out of complex XML fragments.

XPath support

XPath is supported on the server and client sides with the help of XMLSource utility class. Please see above how http-centric WebClients can use XPath, here is an example for the server side :

@Path("/root")
public class Root {
   @POST
   public void post(XMLSource source) {
       String value = source.getProperty("/books/book/@name");
   }    
}

Users have an option to hide XPath expressions, by registering an XPathProvider, either on client or server sides. For example :

XPathProvider provider = new XPathProvider();
provider.setGlobalExpression("/books/book[position() = 1]");
WebClient wc = WebClient.create("http://aggregated/data", Collections.singletonList(provider));
Book b = wc.get(Book.class);

XSLT support

XSLT is currently supported by XSLTJaxbProvider. This provider works in tandem with JAXB and can be used to produce pretty much any format, including non-XML ones. Likewise, it can be used to extract XML data out of incoming XML fragments, either on the client or server sides.

XSLTJaxbProvider can be configured to handle input or output data, scoped by media types if needed. For example, one may configure it such that one template handles "application/xml" formats only while the other one handles "application/json" writes only.

XSLTJaxbProvider uses an injected JAX-RS UriInfo to inject all the usual JAX-RS information like template or query parameters into a given XSLT template.

For example, given this resource method definition :

@Path("/root")
public class Root {
   @GET
   @Path("{id}") 
   public Book get(@PathParam("id") String id, @QueryParam("name") String name) {
       return getBook(id, name);
   }    
}

an XSLT template processing the JAXB-driven serialization of a Book instance will have parameters with name 'id' and 'name' injected.

Note that when XSLTJaxbProvider is used on the client side, it may not always be possible for template parameters be injected in cases when http-centric clients are used (as opposed to proxies). For example :

WebClient client = WebClient.create("http://books");
client.path("/store/1").get();

it is not possible to deduce that '1' represents a template parameter in the "/store/1" expression. However, one can use the following code instead if '1' needs to be available to XSLT templates :

WebClient client = WebClient.create("http://books");
client.path("/store/{id}", 1).get();

Redirection

CXF 2.2.5 supports redirecting to other servlet resources for a given request and/or response be completed.

With RequestDispatcherProvider

RequestDispatcherProvider is a JAXRS MessageBodyWriter which can redirect to JSP pages, named or default servlets. It can be used to serve all the responses from a given resource class or restricted to serving a limited set of classes only using a classResources map property. Note that this classResources property can also be used to specify the name of the key which JSP pages or other downstream servlets will use to access a response object.

At the moment, this provider is statically configured to support text/html content types, but it can be easily configured to support other content types if needed.

Please see this beans.xml. As you can see, it is possible to redirect to either to static resources such as book.html (possibly for providing some default response) or dynamic resources such as JSP pages. It is also possible to redirect to named servlets.

Note that the only required property is a 'requestPath' one and its value should start with a forward slash but it does not have to point to an existing web application resource such as book.html; it can also have values like "/other/services/", possibly in a combination with a 'dispatcherName' property.

Finally, a servletContextPath property can be used to have some other ServletContext (as opposed to the current one) be used for RequestDispatcher look-ups. If set then the current ServletContext.getContext(servletContextPath) will be used to get the needed ServletContext.

With CXFServlet

Please see the "Redirection" section on the Servlet Transport page.

Note that both CXFServlet and JAXRS RequestDispatcher provider can work together effectively on executing the redirection requests as described at that page.

If you have CXFServlet listening on "/" (thus effectively catching all the requests) and also would like to use RequestDispatcher, then make sure that a 'dispatcherName' property is also set, for example :

<bean id="dispatchProvider" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
    <property name="dispatcherName" value="jsp"/>
    <property name="resourcePath" value="/WEB-INF/jsp/test.jsp"/>
    <property name="scope" value="request"/>
</bean> 

If resources which are redirected to can be made public (i.e, moved out of /WEB-INF) then alternative option (instead of adding a 'dispatcherName' property to RequestDispatcherProvider and still have CXFServlet listening on '/') is to configure both RequestDispatcherProvider and CXFServlet to redirect to resources such as "/jsp/test.jsp".

Custom Redirection

One can borrow some of the code from RequestDispatcherProvider and do the custom redirection from CXF in interceptors or custom invokers, if you will try to do it then you will also need to set an AbstractHTTPDestination.REQUEST_REDIRECTED property with a 'true' value on a current input message.

Model-View-Controller support

XSLT

Please see this blog entry on how XSLTJaxbProvider can be used to generate complex (X)HTML views.

JSP

With the introduction of the RequestDispatcherProvider (see above) it is now possible for JAXRS service responses be redirected to JSP pages for further processing. Please see this beans.xml.

In addition to 'resourcePath' and 'dispatcherName' properties, one can set a 'scope' property which has two possible values, 'request' and 'session' with 'request' being the default value. It affects the way the JSP code can retrieve parameters passed to it by the RequestDispatcherProvider. If it is a 'request' scope then all the parameters are set as the attributes on the current HTTP request, if it is a session then they're set as the attributes on the current HTTP session.

RequestDispatcherProvider sets the following parameters :

  • JAXRS method response object, the name of this parameter is either a simple class name of this object (lower case) or a value retrieved from a beanNames map property using the fully qualified class name of this object.
  • All the path, query and matrix parameters which have been initialized during the method execution
  • "absolute.path", "base.path" and "relative.path" obtained from the current UriInfo

Support for Multiparts

Multiparts can be handled in a number of ways. CXF core runtimes provides an advanced support for handling attachments and CXF JAX-RS builds upon it.

Please see the JAX-RS Multiparts page for more information.

Service listings and WADL support

CXF JAX-RS now supports the auto-generation of WADL for JAX-RS endpoints.
Note that JAX-RS subresources are supposed to be late-resolved, so using annotated interfaces for subresources and a staticSubresourceResolution=true property will let the whole resource tree/graph be described in a generated instance. Schemas will be generated for JAXB-annotated types.

WADL instances for RESTful endpoints are available from {base endpointaddress}/services, in addition to SOAP endpoints if any. Note that you can override the location at which listings are provided (in case you would like '/services' be available to your resources) using
'service-list-path' servlet parameter, ex :

> 'service-list-path' = '/listings'

Going to the service listings page is not the only way to see the wadl instances, generally one can get it using a ?_wadl query.

For example, given

Base address : 'http://localhost:8080'
WAR name : 'store'
CXFServlet : '/books/*'
jaxrs:server/@address = '/orders'
jaxrs:server/@staticSubresourceResoulution = 'true'

and 2 root resource classes registered with this endpoint, say

@Path("/fiction") 
public class FictionBookOrders {
}
@Path("/sport") 
public class SportBookOrders {
}

then

> http://localhost:8080/store/books/orders?_wadl

will give you the description of all the root resource classes registered
with a given jaxrs:server endpoint, including all the subresources. While

> http://localhost:8080/store/books/orders/fiction?_wadl
> http://localhost:8080/store/books/orders/sport?_wadl

will give you all the info for FictionBookOrders and SportBookOrders respectively.

If you have many jaxrs:endpoints then visiting

> http://localhost:8080/store/books
> http://localhost:8080/store/books/services

will let you see all the WADL links.

Note that the media type for a ?_wadl response is set to 'application/vnd.sun.wadl+xml' which is something Firefox does not really
like unless some wadl plugin is registered. If an HTTP Accept header is set to 'application/xml' then Firefox will show it with no problems. Doing
'?_wadl&_type=xml' will ensure a WADL generator will see Accept being set set to 'application/xml'.

Documenting resource classes and methods in WADL

WADL documents can include doc fragments. Users may want to use Description annotations which can be attached to resource classes and methods.

Custom WADL providers

One can register a custom WADLGenerator as a jaxrs:provider. The custom generator can extend the default
org.apache.cxf.jaxrs.model.wadl.WADLGenerator or register a default one with one of the following properties set.

  • wadlNamespace : default is "http://wadl.dev.java.net/2009/02", the earlier one is "http://research.sun.com/wadl/2006/10".
  • singleResourceMultipleMethods : default is 'true', for example, if a resource class has multiple methods supported at the same path such as "/" (GET, POST, etc) then WADL will list them all as the child nodes of a single resource element.
  • useSingleSlashResource : default is false, for example, if you have a root resource class with a path "root" and a resource method with a path "" or "/" then a WADL resource representing the root will not have a child resource representing this resource method (it would do if a resource method had a more specific path such as "bar").

Representing external schemas and non JAXB types

By default, the WADL grammar section will be properly generated if resource methods accept or return JAXB types.

Even when you do use JAXB, the JAXB types may have been generated from the external schema so having WADLGenerator attempting to recreate the original schema may not work well. To have a generated WADL referencing the original schema(s) please set a 'schemaLocations' list property (programmatically or from Spring) :

WadlGenerator wg = new WadlGenerator();
wg.setSchemaLocations(Collections.singletonList("classpath:/book.xsd"));

In this case the grammar section will have the 'book.xsd' schema inlined. If this schema imports other schemas then the imports with relative URIs will be replaced by the absolute URIs based on the current endpoint's base address. For example, if the endpoint address is "http://somehost/bar" and the 'book.xsd' imports "foo/book1.xsd" then the published WADL will contain an "http://somehost/bar/foo/book1.xsd". At the moment a custom RequestHandler filter will have to be registered to serve resources such as "http://somehost/bar/foo/book1.xsd" which can 'calculate' which resource is required get the absolute request URI and comparing it with the base URI, possibly with the help of the injected JAXRS UriInfo context. Alternatively, resources such as book1.xsd may be served by CXFServlet itself (see the Redirection with CXFServlet)

TODO : add ignoreImports flag so that users can list root and imported schemas in "schemaLocations" and have them all inlined.

Note that the root schema such as "book.xsd" is inlined - you can have it referenced only by setting an 'externalLinks' list property. This will very well when the "book.xsd" is indeed available at some external URI, but this property can be used to avoid the local schemas being inlined. Moreover, using JAXB will not be required. The result will look like this :

<wadl:grammars>
<wadl:include href="http://books.xsd"/>
</wadl:grammars>

Note that "schemaLocations" and "externalLinks" properties differ in that the schemas referenced by the former one are inlined.

You can also customize the way schema elements are referenced. When WADLGenerator creates WADL representation elements (representing resource method input or output types) it will be able to link to schema elements provided a given type is actually a JAXB one, so the result may look like this :

<!-- 
  thebook2 element is declared in a schema inlined in or referenced from the grammar section
  prefix1 is bound to that schema's target namespace and is declared at the wadl:application element 
-->
<representation mediaType="application/xml" element="prefix1:thebook2"/>

If no JAXB is used then you can attach an XmlName annotation to method input or output types. Alternatively, you can register an instance of ElementQNameResolver with the WADLGenerator which will be used for creating wadl:representation/@element values.

Hiding links to JAXRS endpoints from the services page

In some cases you may not want the users to see the links to some of your JAXRS endpoints. For example, if you have an AtomPullServer endpoint collecting the log entries for a number of application endpoints, you may not want to the AtomPullServer endpoint being listed among the endpoints which the users are actually interested in. If so then adding an "org.apache.cxf.endpoint.private" boolean property with the value "true" will do the trick; note the same property can be used by jaxws endpoints.

Code Generation

Generating the client code at runtime

If you register an org.apache.cxf.jaxrs.ext.codegen.CodeGeneratorProvider with a jaxrs endpoint and issue a '_code' query to it then you will get back an XHTML page containing the link to a zipped client source code which you can download and start customizing.

Internally, before the code gets generated, WADL will be generated first. The archive will include JAXB generated classes from a WADL grammar section plus the proxy based client code for accessing root and sub resources. The WebClient based code can not be generated just yet but one can request that only a WADL grammar section is processed by adding a '_codeType=grammar' query and easily adding a WebClient-based code.

Here is how to get the archive programmatically :

WebClient wc = WebClient.create("http://localhost:9080/petstore");
XMLSource source = wc.query("_code").query("_os", getOs()).get(XMLSource.class);
String link = source.getValue("ns:html/ns:body/ns:ul/ns:a/@href",  
              Collections.singletonMap("ns","http://www.w3.org/1999/xhtml"));
// download a zip file          
WebClient wcZip = WebClient.create(link);
InputStream is = wcZip.accept("application/zip").get(InputStream.class);
// unzip and compile it

Please see a testPetStore test for more details.

Configuring JAX-RS services

JAX-RS services can configured programmatically, from Spring or using CXFNonSpringJAXRSServlet.

Please see the JAXRS Services Configuration page for more information.

Matching the request URI

There's a number of variables involved here.

Lets assume you have a web application called 'rest'. CXFServlet's url-pattern is "/test/*". Finally, jaxrs:server's address is "/bar".

Requests like /rest/test/bar or /rest/test/bar/baz will be delivered to one of the resource classes in a given jaxrs:server endpoint. For the former request be handled, a resource class with @Path("/") should be available, in the latter case - at least @Path("/") or more specific @Path("/baz").

The same requirement can be expressed by having a CXFServlet with "/*" and jaxrs:server with "/test/bar".

When both CXFServlet and jaxrs:server use "/" then it's a root resource class which should provide a @Path with at least "/test/bar" for the above requests be matched.

Generally, it can be a good idea to specify the URI segments which are more likely to change now and then with CXFServlets or jaxrs:server.

Combining JAX-WS and JAX-RS

Here's a beans.xml showing how to have a single service class supporting both SOAP and REST-based invocations at the same time with the help of JAX-WS and JAX-RS :

<?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"
  xmlns:jaxws="http://cxf.apache.org/jaxws"
  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
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">

  <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" />

  <!-- JAX-RS -->
  <jaxrs:server id="customerService" address="/">
    <jaxrs:serviceBeans>
      <ref bean="customerService" />
    </jaxrs:serviceBeans>
  </jaxrs:server>

  <!-- JAX-WS -->
  <jaxws:endpoint implementor="#customerService"
    address="/CustomerWorld" wsdlLocation="..."/>
  
  <bean id="customerService" class="demo.jaxrs.server.CustomerService" />
</beans>

Either contract-first or Java-first approach can be used for JAX-WS. JAX-RS annotations can be added to the existing service class. Some custom providers may need to be created, depending on the complexity of the method signatures.

When a WSDL-first approach is used then a document-literal-wrapped style may or may not be a good fit as the code generator unwraps all the types into a signature, for example :

public class CustomerService {
   public void doIt(String a, String b) {...};
}

By default JAX-RS may not be able to handle such methods as it requires that only a single parameter can be available in a signature that is not annotated by one of the JAX-RS annotations like @PathParam. So if
a 'String a' parameter can be mapped to a @Path template variable or one of the query segments then this signature won't need to be changed :

@Path("/customers/{a}")
public class CustomerService {
   public void doIt(@PathParam("a") String a, String b) {...};
}

Note that CXF Continuations API is supported for both JAXWS and JAXRS services.

Dealing with contexts

When combining JAXWS and JAXRS, one may need to access some context information as part of processing a given request. At the moment, CXF JAXRS does not offer a context implementation which can be used to access a request-specific information common for both JAXWS and JAXRS requests, in cases when the same methods are used to handle both JAXWS and JAXRS requests. Please use a JAXWS WebServiceContext and JAXRS contexts or CXF JAXRS composite MessageContext :

@Path("/customers")
@WebService
public class CustomerService {

   @Resource WebServiceContext jaxwsContext;
   @Resource MessageContext jaxrsContext;

   @WebMethod
   @POST
   public void doIt(String b) {
       isUserInRole();
   };

   private void isUserInRole() throws WebApplicationException {
       if (jaxwsContext.getSecurityContext() != null) {
           // soap invocation
           jaxwsContext.getSecurityContext().isUserInRole(theRole);
       } else {
           // http-only jaxrs one
           jaxrsContext.getSecurityContext().isUserInRole(theRole);
       }  
   }
}

Note that injected context instances (jaxwsContext and jaxrsContext) are in fact thread-local proxies hence they will not be equal to null even if they do not represent a given request. For example, jaxrsContext will not be equal to null even if it's not a JAXWS invocation which is being processed at the moment.

However, if say a (JAXWS or JAXRS) SecurityContext needs to be accessed then it will be set in, say, jaxwsContext only if it's a JAXWS/SOAP invocation. For this reason it can be handy using a composite CXF JAXRS MessageContext when accessing a JAXRS-specific context information when combining JAXWS and JAXRS as one can easily check if it's actually a JAXRS request by simply checking an individual context like SecurityContext or UriInfo for null.

Using individual contexts like JAXRS SecurityContext might be less attractive :

@WebService
public class CustomerService {
   @Resource WebServiceContext jaxwsContext;
   // @Resource can be applied too
   @Context SecurityContext jaxrsSecurityContext;  
}

as some methods of SecurityContext return boolean values so only throwing a runtime exception can reliably indicate that this context is actually not in scope.

Note that if you do not share the same service methods between JAXRS and JAXWS invocations then you can directly access corresponding contexts :

@Path("/customers")
@WebService
public class CustomerService {

   @Resource WebServiceContext jaxwsContext;
   @Resource MessageContext jaxrsContext;

   @WebMethod
   public void doItSoap(String b) {
       isUserInRole(jaxwsContext.getSecurityContext().getPrincipal());
   };

   @POST
   public void doItSoap(String b) {
       isUserInRole(jaxwsContext.getSecurityContext().getPrincipal());
   }

   private void isUserInRole(Principal p) throws WebApplicationException {
       ...  
   }
}

Another option is to avoid the use of contexts in the service code and deal with them in CXF interceptors or JAXRS filters. Sometimes it's possible to avoid the use of contexts altogether. For example, Spring Security can be used to secure a given service at an individual method level.

JAX-RS and Spring AOP

CXF JAX-RS is capable of working with AOP interceptors applied to resource classes from Spring.
For example :


<beans xsi:schemaLocation=" http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/aop  
  http://www.springframework.org/schema/aop/spring-aop.xsd 
  http://cxf.apache.org/jaxrs 
  http://cxf.apache.org/schemas/jaxrs.xsd">
  <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="bookservice" address="/">
	<jaxrs:serviceBeans>
          <ref bean="bookstore"/>
          <ref bean="bookstoreInterface"/>
        </jaxrs:serviceBeans>
   </jaxrs:server>
   <bean id="bookstore" class="org.apache.cxf.systest.jaxrs.BookStore"/>
   <bean id="bookstoreInterface" class="org.apache.cxf.systest.jaxrs.BookStoreWithInterface"/>

   <aop:config>
	<aop:aspect id="loggingAspect" ref="simpleLogger">
          <aop:before method="logBefore" pointcut="execution(* org.apache.cxf.systest.jaxrs.BookStore*.*(..))"/>
          <aop:after-returning method="logAfter" pointcut="execution(* org.apache.cxf.systest.jaxrs.BookStore*.*(..))"/>
        </aop:aspect>
   </aop:config>
   <bean id="simpleLogger" class="org.apache.cxf.systest.jaxrs.SimpleLoggingAspect"/>
</beans>

Note that some AOP configuration is applied to two JAX-RS resource classes. By default Spring uses JDK dynamic proxies every time a class to be proxified implements at least one interface or CGLIB proxies otherwise.

For example, here's how org.apache.cxf.systest.jaxrs.BookStoreWithInterface looks like :


public interface BookInterface {
    @GET
    @Path("/thosebooks/{bookId}/")
    @Produces("application/xml")
    Book getThatBook(Long id) throws BookNotFoundFault;
}

public class BookStoreWithInterface extends BookStoreStorage implements BookInterface {

    public Book getThatBook(@PathParam("bookId") Long id) throws BookNotFoundFault {
        return doGetBook(id);
    }

    @Path("/thebook")
    public Book getTheBook(@PathParam("bookId") Long id) throws BookNotFoundFault {
        return doGetBook(id);
    }
}

In this case Spring will use a JDK proxy to wrap a BookStoreWithInterface class. As such it is important that a method which needs to be invoked such as getThatBook(...) is part of the interface.

The other method, getTheBook() can not be dispatched to by a JAX-RS runtime as it's not possible to discover it through a JDK proxy. If this method also needs to be invoked then this method should either be added to the interface or CGLIB proxies have to be explicitly enabled (consult Spring AOP documentation for more details). For example :

<aop:config proxy-target-class="true"/>

Oneway invocations

Resource methods with an org.apache.cxf.jaxrs.ext.Oneway annotation will be invoked oneway with the original request returning 202 HTTP status. HTTP or JMS clients can also add a "OnewayRequest" header if adding Oneway annotations is not an option.

JMS Support

CXF has been designed such that multiple transports can be supported for a given endpoint. If you would like your JAXRS endpoint be capable of serving not only HTTP but also JMS requests then you need to specify a JMS transportId, example :

<jaxrs:server serviceName="s:BookService" transportId="http://cxf.apache.org/transports/jms" address="/">
 <jaxrs:serviceBeans>
   <bean class="org.apache.cxf.systest.jaxrs.JMSBookStore"/>
 </jaxrs:serviceBeans>
</jaxrs:server>

Additionally, JMS queue or topic configuration needs to be done, for example, please see this beans.xml. Please note how a serviceName attribute is used to specify a service QName for a jaxrs endpoint (default is {http://reverse.package.name}ServiceClassName), this service name is
used to configure a jms destination.

Here is the actual test.

Here are JMS properties which can help with matching a required method on the JAXRS endpoint :

  • "Content-Type" : default is "text/xml"
  • "Accept" : default is "/"
  • "OnewayMessage" : default is "false"
  • "org.apache.cxf.message.Message.REQUEST_URI" : default is "/"
  • "org.apache.cxf.message.Message.HTTP_REQUEST_METHOD" : default is "POST"

If JMS messages are sent to topic destinations then one has to either set a "OnewayMessage" property or ensure that target JAXRS methods are annotated with org.apache.cxf.jaxrs.ext.Oneway.

As far as REQUEST_URI is concerned, it is initially matched against a jaxrs:server/@address. So if REQUEST_URI is not set or set to "/" then jaxrs:server/@address has to be set to "/". If REQUEST_URI is set to "/bar/foo" and
jaxrs:server/@address is set to "/bar" then it will be '/foo' which will be used to find a root resource class and its method.

By referencing a bean such as 'org.apache.cxf.systest.jaxrs.JMSBookStore' from multiple jaxrs endpoints you can ensure that both HTTP and JMS requests are handled by the same service bean. In such cases you may want to use a CXF JAXRS specific ProtocolHeaders context which will let you get either HTTP or JMS headers.

RESTful services without annotations

One of the latest CXF JAX-RS extensions allows users to provide external models with the information which the runtime typically gets from JAX-RS annotations like @Path, @PathParam, @Consumes, @Produces, etc.
There might be a number of cases when it can be advantageous to describe how a given resource can be exposed as a RESTful service without actually modifying this resource. For example, when new dynamic interface implementations are registered, when no source code can be modified, when the cost of future updates (for ex, modifying the value of @Path annotations) is considered to be expensive, etc.

User model schema type is described in the jaxrs.xsd.

The top-level 'model' element can have 'resource' children elements. A 'resource' element describes a resource class which can be either a root resource class or a sub-resource one and it can have attributes describing 'path', 'produces' and 'consumes' values and it has a 'name' attribute which identifies a fully-qualified resource class.
A 'resource' element can have a number of 'operation' elements pointing to resource methods (with its 'name' attribute) and can have 'path', 'produces', 'consumes' and 'verb' (HTTP method) values. An 'operation' element which has no 'verb' attribute is treated as a sub-resource locator - a corresponding resource class has to be available in the model with its 'name' attribute matching the return type's name of this operation.
Every operation can have a number of 'param' elements. A 'param' element should have its 'name' attribute matching a corresponding parameter name in the class resource method. Its 'type' can have the following values : 'PATH', 'QUERY', 'CONTEXT', 'HEADER', 'MATRIX', 'COOKIE', 'FORM' or 'REQUEST_BODY'. Parameters corresponding to response types do not have to be described. It can also have 'defaultValue' and 'encoded' values being set.

Starting from CXF 2.3.2-SNAPSHOT a "oneway" attribute can also be applied to individual operations.

Here is an example :

<model xmlns="http://cxf.apache.org/jaxrs">
  <resource name="org.apache.cxf.systest.jaxrs.BookStoreNoAnnotations" path="bookstore"
    produces="application/json" consumes="application/json">
    <operation name="getBook" verb="GET" path="/books/{id}" produces="application/xml">
       <param name="id" type="PATH"/>
    </operation>
    <operation name="getBookChapter" path="/books/{id}/chapter">
       <param name="id" type="PATH"/>
    </operation>
    <operation name="updateBook" verb="PUT">
       <param name="book" type="REQUEST_BODY"/>
    </operation>
  </resource>
  <resource name="org.apache.cxf.systest.jaxrs.ChapterNoAnnotations">
    <operation name="getItself" verb="GET"/>
    <operation name="updateChapter" verb="PUT" consumes="application/xml">
        <param name="content" type="REQUEST_BODY"/>
    </operation>
  </resource>
</model>

This model describes two resources, BookStoreNoAnnotations and ChapterNoAnnotations. The BookStoreNoAnnotations resource has three resource operations, 'getBook', 'getBookChapter' and 'updateBook'. Note that the 'getBookChapter' operation element (described in the model) has no 'verb' attribute so runtime will identify it as a subresource locator.
The runtime will introspect the org.apache.cxf.systest.jaxrs.BookStoreNoAnnotations class and check the return types for both 'getBook' and 'getBookChapter' methods. BookStoreNoAnnotations.getBookChapter() method's return type is org.apache.cxf.systest.jaxrs.ChapterNoAnnotations so the model will be checked if it contains the resource element with the 'name' attribute equal to 'org.apache.cxf.systest.jaxrs.ChapterNoAnnotations'. After this resource has been found, the ChapterNoAnnotations class is recognized as a sub-resource and then its 'getItself' method is checked.

Additionally the BookStoreNoAnnotations resource declares that all its resource methods produce 'application/json' mediaTypes, while its 'getBook' method overrides its with its own 'produces' value. BookStoreNoAnnotations resource also has a 'consumes' attribute which requires all of the resource methods (such as 'updateBook') to consume "application/json" formats. The ChapterNoAnnotations 'updateChapter' resource operation requires 'application/xml' formats.

You can use a comma-seperated list of media type values if needed, for example, produces("application/xml;charset=utf-8,application/json") or consumes("application/xml;charset=utf-8,application/json").

Please also see this model file for an example. Providing this file will let all implementations of the interface described in this model instance be exposed as RESTful services supported by the JAX-RS runtime.

Configuration

A user model can be referenced in a number of ways. It can be embedded in a jaxrs:server endpoint definition or linked to through a jaxrs:server modelRef attribute as a classpath resource.

Please see this bean Spring configuration file, look at jaxrs server beans with 'bookservice6' and 'bookservice7' names.

Note that when registering a model from Spring you do not need to declare a jaxrs server serviceBeans section - the runtime will instantiate the beans itself. If you do need to inject certain properties into your service bean from Spring then you do need to declare a service bean too. In this case this bean will be instantiated twice - once by the runtime during the model introspection and once by Spring, however in the end it will be the bean created by Spring that will be used, the one created by the runtime will be removed.
You can avoid this double instantiation by having your model describing the interfaces which the actual root resource beans will implement. In this case only Spring will create a bean and the runtime will apply the model description to this injected bean. Note that if Spring proxifies your bean (for example by applying transaction aspects to it) then the model does have to describe an interface for a match between the model and the injected bean proxy to succeed.

Please have a look at this Spring bean. The jaxrs endpoint with id 'bookservice2' will have BookStoreWithNoAnnotations created twice but it will be the Spring created BookStoreWithNoAnnotations bean that will serve as a resource class instance. The jaxrs endpoint with id 'bookservice3' will have BookStoreWithNoAnnotationsImpl class instantiated only by Spring, with the model describing BookStoreWithNoAnnotationsInterface only that this class implements.

You can also register a model programmatically, for example :

JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
            sf.setAddress("http://localhost:9080/");
String modelRef = "classpath:/org/apache/cxf/systest/jaxrs/resources/resources2.xml";
sf.setModelRef(modelRef);

// or if you have interface classes described in the model already loaded, ex : OSGI
// sf.setModelRefWithServiceClass(modelRef, BookStoreNoAnnotationsInterface.class);

// register an actual bean only if the model describes interfaces
sf.setServiceBeans(new BookStoreNoAnnotationsImpl());

Please also see this system test for the example of how model beans like UserResource can be created and registered programmatically.

Similarly, you can register a user model on the client side, either from jaxrs:client or programmatically, example :

JAXRSClientFactoryBean cf = new JAXRSClientFactoryBean();
cf.setAddress("http://localhost:9080/");
String modelRef = "classpath:/org/apache/cxf/systest/jaxrs/resources/resources2.xml";
sf.setModelRef(modelRef);
BookStoreNoAnnotations proxy = cf.create(BookStoreNoAnnotations.class);

At the moment it is only possible to register a user model with CXFNonSpringJAXRSServlet using the latest 2.2.3-SNAPSHOT like the way it is done in this web.xml. See CXFServlet3 and CXFServlet4 servlet declarations. Note that CXFServlet4 registers a model containing interfaces so it also registers a BookStoreNoAnnotationsImpl service class.

The workaround is to create a custom servlet :

public class JAXRSUserModelServlet extends CXFNonSpringJaxrsServlet  {

@Override
public void loadBus(ServletConfig servletConfig) throws ServletException {

super.loadBus(servletConfig);

JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
String address = servletConfig.getInitParameter(SERVICE_ADDRESS_PARAM); //jaxrs.address
if (address == null) {
address = "/";
}
sf.setAddress(address);

// modelRef needs to start from 'classpath:', ex 'classpath:/WEB-INF/models/model1.xml
String modelRef = servletConfig.getInitParameter("user.model");
sf.setModelRef(modelRef);
sf.create();
}

Integration with Distributed OSGi

Distributed OSGi RI is a CXF subproject. DOSGi mandates how registered Java interfaces can be exposed
and consumed as remote services. DOSGi single and multi bundle distributions contain all the OSGI bundles required for a CXF endpoint be successfully published.

CXF JAX-RS implementations has been integrated with DOSGi RI 1.1-SNAPSHOT which makes it possible to expose Java interfaces as RESTful services and consume such services using a proxy-based client API.

Please see DOSGI Reference page ('org.apache.cxf.rs' properties) and a greeter_rest sample for more information. Note that this demo can be run exactly as a SOAP-based greeter demo as it registers and consumes a similar (but) JAX-RS annotated GreeterService. In addition, this demo shows how one can register and consume a given interface (GreeterService2) without using explicit JAX-RS annotations but providing an out-of-band user model description.

How to contribute

CXF JAX-RS implementation sits on top of the core CXF runtime and is quite self-contained and isolated from other CXF modules such as jaxws and simple frontends.

Please check this list and see if you are interested in fixing one of the issues.

If you decide to go ahead then the fastest way to start is to

  • do the fast trunk build using 'mvn install -Pfastinstall'
  • setup the workspace 'mvn -Psetup.eclipse' which will create a workspace in a 'workspace' folder, next to 'trunk'
  • import cxf modules from the trunk into the workspace and start working with the cxf-frontend-jaxrs module

If you are about to submit a patch after building a trunk/rt/frontend/jaxrs, then please also run JAX-RS system tests in trunk/systests/jaxrs :
> mvn install

  • No labels