Sunday, December 23, 2007

Quick Dive into CXF

REST
REST is no longer a new term, you are probably falling too far behind if you haven't yet heard of it. Daniel Diephouse, the creator of XFire (who is also now a Software Architect of MuleSource) wrote an interesting article about REST and SOA not too long ago, he sees REST as the next big trend in SOA.

If you are into this and if you are a Java guy, you may also be aware of the JSR 311 - The JavaTM API for RESTful Web Services and the Jersey (implementation). You would have also been told that Apache Axis 2.0 and Apache CXF (Celtic XFire) supports REST.

The rest of the blog entry, I will be sharing about how I toyed around with CXF, after taking a quick glance at it and learned how easy using it to write a Web-/REST- service.

Get a POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelversion>4.0.0</modelversion>
<groupId>sandbox</groupId>
<artifactId>apache-cxf</artifactId>
<version>2007.12.18</version>

<properties>
<cxf.version>2.1-incubator-SNAPSHOT</cxf.version>
<spring.version>2.0.6</spring.version>
</properties>

<repositories>
<repository>
<id>apache.incubating.releases</id>
<name>Apache Incubating Release Distribution Repository</name>
<url>http://people.apache.org/repo/m2-incubating-repository</url>
</repository>
<repository>
<id>apache.snapshot.releases</id>
<name>Apache Snapshot Release Distribution Repository</name>
<url>http://people.apache.org/repo/m2-snapshot-repository</url>
</repository>
</repositories>

<dependencies>

<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>

<!-- Depending on your requirements you may need more or less modules from cxf -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-core</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-simple</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- REST!! -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-databinding-aegis</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-local</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-jms</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-management</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-common-utilities</artifactId>
<version>${cxf.version}</version>
</dependency>
<!--dependency>
<groupId>jersey</groupId>
<artifactId>jersey</artifactId>
<version>0.4-ea</version>
</dependency-->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>0.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
<scope>test</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>

</project>


Write the Code
Once you have built the project into your favourite IDE, start writing the code:
  1. A service interface

  2. A service implementation

  3. A Java main class


package sandbox.cxf.api;
import javax.jws.WebParam;
import javax.jws.WebService;

import sandbox.cxf.resources.Author;
import sandbox.cxf.resources.Message;

@WebService(name = "sampleService")
public interface SampleService {

public Message getEcho(@WebParam(name="input") String string);
...
}

package sandbox.cxf.services;
import javax.jws.WebService;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.UriParam;
import javax.ws.rs.UriTemplate;

import sandbox.cxf.api.SampleService;
import sandbox.cxf.resources.Message;

@UriTemplate("/sampleService")
@WebService(endpointInterface="sandbox.cxf.api.SampleService", serviceName="defaultSampleService")
public class DefaultSampleService implements SampleService{

@HttpMethod("GET")
@UriTemplate("/echo/{input}")
public Message getEcho(@UriParam("input") String string){

System.out.println("Echoing message of " + string);

Message message = new Message();
message.setBody(string);

return message;
}
...
}


No *.properties or *.xml crap, this is how quickly you can configure and boot a SOAP and REST service:

SampleService sampleService = new DefaultSampleService();

JaxWsServerFactoryBean wsServerfactoryBean = new JaxWsServerFactoryBean();
wsServerfactoryBean.setServiceClass(SampleService.class);
wsServerfactoryBean.setAddress("http://localhost:8081/sampleService");
wsServerfactoryBean.setServiceBean(sampleService);
wsServerfactoryBean.create();

JAXRSServerFactoryBean restServerFactoryBean = new JAXRSServerFactoryBean();
restServerFactoryBean.setResourceClasses(Message.class);
restServerFactoryBean.setBindingId(JAXRSBindingFactory.JAXRS_BINDING_ID);
restServerFactoryBean.setServiceBeans(sampleService);
restServerFactoryBean.setAddress("http://localhost:8082/");
restServerFactoryBean.create();


Add logging interceptors if you want some logging and debugging:

wsServerfactoryBean.getInInterceptors().add(new LoggingInInterceptor());
wsServerfactoryBean.getOutInterceptors().add(new LoggingOutInterceptor());


Try Now
Once you have done the above, try to access the services via browser, e.g.

REST: http://localhost:8082/sampleService/echo/foobar
<message>  <body>foobar</body>
</message>


SOAP: http://localhost:8081/sampleService/getEcho?input=foobar
<soap:envelope soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:body>
<ns1:getechoresponse ns1="http://api.cxf.sandbox/">
<ns2:message ns2="http://api.cxf.sandbox/">
<body>foobar</body>
</ns2:Message>
</ns1:getEchoResponse>
</soap:Body>
</soap:Envelope>


Isn't that quick? ;-)

- yc

2 comments:

britt said...

Thanks for writing this, it was very helpful.

There is one typo that prevents you from cutting and pasting the pom you provided. Some of the tags need to be camel-cased like artifactId instead of artifactid.

Thanks again.

Yuen-Chi Lian said...

Thanks for pointing that out. The cases were probably changed by spelling checker, I didn't notice! :-)

- yc