Developers, Developers, Developers! Maksim Sorokin IT Blog

21Jul/11Off

Maven + Apache Felix + CXF: Creating a RESTful Webservice with CXF. A Simple String Example.

This is next post in Maven + Apache Felix + CXF + DOSGi series.

This is example is based on the sample application developed in previous post. Again, it is assumed here that you are using M2Eclipse plugin, if you want to run examples from Eclipse.

As usual, source is included in the end of the post.

First of, we need to download CXF DOSGi dependency in "felixLauncher" (refer to previous post) and put it to the "bundle" folder, so Apache Felix would know about CXF. Why CXF DOSGi? Because it contains all necessary dependencies inside. We will use single-bundle distribution in this case. So in artifactItems in maven-dependency-plugin (refer to previous post), define:

<artifactItem>
  <groupId>org.apache.cxf.dosgi</groupId>
  <artifactId>cxf-dosgi-ri-singlebundle-distribution</artifactId>
  <version>1.2</version>
</artifactItem>

Now we need to create a webservice code in our bundle. But first, we need to tell maven where to find JAX-RS annotations, so add this to the dependencies of test.bundle project:

<dependency>
  <groupId>org.apache.servicemix.specs</groupId>
  <artifactId>org.apache.servicemix.specs.jsr311-api-1.0</artifactId>
  <version>1.8.0</version>
</dependency>

Now create an interface MyService in test.bundle package in the test.bundle project:

package test.bundle;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("myService")
public interface MyService {

  @GET
  @Path("sayHello/{name}")
  @Produces(MediaType.TEXT_PLAIN)
  String sayHello(@PathParam("name") String name);
}

And implementation class MyServiceImpl in package test.bundle.internal:

package test.bundle.internal;

import test.bundle.MyService;

public class MyServiceImpl implements MyService {

  public String sayHello(String name) {
    return "Hello " + name;
  }
}

Actually, interface for a webservice may be even separated to a different bundle to enforce decoupling. But in this case we will just keep them together. But you may want to explicitly state, that test.bundle.internal is internal package and cannot be visible to outside. This can be done by explicitly exporting only visible packages through Export-Package in the manifest file. Since we are using Maven bundle plugin, we can also define Export-Package in manifest file generation part in pom.xml:

  <plugin>
	<groupId>org.apache.felix</groupId>
	<artifactId>maven-bundle-plugin</artifactId>
	<executions>
	  <execution>
		<id>generate-resources</id>
		<goals>
		  <goal>manifest</goal>
		</goals>
		<configuration>
		  <instructions>
			<Bundle-Name>${project.name}</Bundle-Name>
			<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
			<Bundle-Activator>test.bundle.internal.Activator</Bundle-Activator>
			<Export-Package>test.bundle</Export-Package>
		  </instructions>
		</configuration>
	  </execution>
	</executions>
  </plugin>

And also, do not worry about JAX-RS package imports in the manifest file -- they will be automatically generated by maven-bundle-plugin.

And the last changes we have to do -- is to register a webservice. This is done through the Activator. So modify Activator of test.bundle, so it would look like:

package test.bundle.internal;

import java.util.Dictionary;
import java.util.Hashtable;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

import test.bundle.MyService;

public class Activator implements BundleActivator {

  public void start(BundleContext context) throws Exception {
    Dictionary<String, String> restProps = new Hashtable<String, String>();

    restProps.put("service.exported.interfaces", "*");
    restProps.put("service.exported.configs", "org.apache.cxf.rs");
    restProps.put("service.exported.intents", "HTTP");
    restProps.put("org.apache.cxf.rs.address", "http://localhost:8080/");
    context.registerService(MyService.class.getName(), new MyServiceImpl(), restProps);
  }

  public void stop(BundleContext context) throws Exception {
    //
  }
}

Then run mvn clean install on "felixLauncher" and "test.bundle" projects. Afterwards, launch "felixLauncher" (refer to the first post in series).

Then you can query the REST webservice throught a browser:


http://localhost:8080/myService/sayHello/Max

And should see the following response:

Hello Max

Here are the zipped sources.

Comments (0) Trackbacks (0)

Sorry, the comment form is closed at this time.

Trackbacks are disabled.