Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

CXF includes an "HTTP binding" which makes it easy to build REST style services. The HTTP binding allows you to take any operation and map it to arbitrary URIs and HTTP verbs (i.e. GET, PUT, POST, DELETE).

Info

This binding has been deprecated and is likely to be removed from CXF in one of its future releases.

Convention based services

If you have a simple CRUD based Java class, CXF can try to build up a set of resources automatically for you with no annotations or configuration. This is best explained through an example. Lets take a look at a typical CRUD class:

Code Block
java
java
import javax.jws.WebService;

@WebService
public interface PeopleService {
  Collection<Person> getPeople();
  Person getPerson(long id);
  void addPerson(Person person);
  void updatePerson(long id, Person person);
  void deletePerson(long id);
}
Note
titleWebService Annotation

The @WebService annotation is required.

Using CXF's convention based mapping, a set of resources will be created and mapped to these operations.

...

That's straightforward enough. We see "get", we map it to a GET operation. Then people is extracted from the operation name and turned into a simple URI. Accessing http://server/peopleImage Removed would result in a document like so:

...

The same rules here as #2 and #4 except we're looking for "delete" and "remove" in the operation and mapping it to an HTTP DELETE.

Configuring the service

You can create a service which uses the HTTP binding by using JaxWsFactoryBean:

Code Block
java
java
JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
sf.setServiceClass(PeopleService.class);
sf.getServiceFactory().setWrapped(true);
sf.setBindingFactory(new HttpBindingInfoFactoryBean()setBindingId(HttpBindingFactory.HTTP_BINDING_ID);
sf.setAddress("http://localhost:9001/");

PeopleService peopleService = new PeopleServiceImpl();
sf.getServiceFactory().setInvoker(new BeanInvoker(peopleService));

Server svr = sf.create();

...

  • The JaxWsServerFactory bean creates a Server inside CXF which starts listening for requests on the URL specified.
  • The HttpBindingInfoFactoryBean is responsible for configuring bindingId specifies how your service operations get mapped to resources: in this case the http binding is used.
  • We're telling the ServiceFactory to work in "wrapped" mode. This just means that our xml documents will be wrapped with the operation name, allowing us to have multiple input parameters. More on this further down.

Java REST Annotations

The Java REST Annotations are annotations which provide information to CXF on how to map operations to arbitrary URI/HTTP verb combinations.

...

The URI parameters get mapped to the XML document according to its schema and the WSDL 2 rules. So if you access the URL /customers/123 CXF will actually synthesize an incoming XML document like this:

Code Block
xml
xml
<getCustomer><id>123<getCustomer><id>123</id></getCustomer>

The databinding layer will then convert this into the GetCustomer object. Lets move on to a more complex example - a PUT operation which updates the customer:

...

This will allow users to do a POST to the /customers URI with their document and add it to the collection of customers contained there.

Example with multiple arguments

To use multiple arguments, the @WebParam annotation has to be used to map the parameters of the url to the service parameters.
For example:

Code Block
java
java

@Get
@HttpResource(location="/customers/{first}/{last}") 
void findCustomer(@WebParam(name="first") String firstName, @WebParam(name="last") String lastName);

Configuring the Service

Configuration for JRA style services is exactly the same as the convention based services. However, in this example, the service is not in "wrapped" mode. So the configuration is slightly different as we don't need to explicitly set the wrapped setting:

Code Block
java
java
JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
sf.setServiceClass(CustomerService.class);
sf.setBindingFactory(new HttpBindingInfoFactoryBean());
sf.setAddress("http://localhost:9001/");

CustomerService customerService = new CustomerServiceImpl();
sf.getServiceFactory().setInvoker(new BeanInvoker(customerService));

Server svr = sf.create();

Configuring the service in container with Spring configuration file.

web.xml

Code Block
xml
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>

beans.xml

Code Block
xml
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: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/jaxws 
	http://cxf.apache.org/schemas/jaxws.xsd">

  <import resource="classpath:META-INF/cxf/cxf.xml"/>
  <import resource="classpath:META-INF/cxf/cxf-extension-http-binding.xml"/>
  <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
  
   <jaxws:endpoint id="userService"
		   implementor="org.apache.cxf.CustomerServiceImpl"
		   address="/customerService"
		   bindingUri="http://apache.org/cxf/binding/http">
       <jaxws:serviceFactory>
           <bean class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean">
               <property name="wrapped" value="true" />
           </bean>
       </jaxws:serviceFactory>
   </jaxws:endpoint>
	  
</beans>
Info
titleUseful Information

The JaxWsServiceFactoryBean is not resusable across various services.

Wrapped vs. Unwrapped Mode

In REST style services we can only send and receive one XML element. Wrapping is the process of wrapping the XML requests/responses with the operation names to allow multiple parameters to your operation. For instance, say we had an operation "Customer findCustomer(String name, String company)". It would not be valid to create an XML POST request like this:

...