Hosting more than one service using CXF and Jetty

This is a logical “next post” to Hosting a CXF SOAP webservice in an existing Jetty instance.

Let’s look at what’s need to host more than one service using CXF from a running instance of Jetty.

Changes to our SOAP Service

We’re going to do this by hosting our original HelloWorld service (from the previous post) with a single line change and alongside it we’ll create a REST service.

So in the AppConfig from the previous post, rename getService to getSoapServer (or whatever you like) and the code should look like this

@Bean @DependsOn( "cxf" )
public Server getSoapServer() {
   JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
   factory.setServiceBean(new HelloWorldImpl());
   factory.setAddress("/soap");
   return factory.create();
}

Apart from the method name change, we’ve added a setAddress call with a relative path. If you recall from the previous post our Jetty server will run on port 9000, i.e. http://localhost:9000 but now our SOAP service will be on http://localhost:9000/soap/HelloWorld?wsdl.

Adding a REST Service

Update the pom.xml with the following, in the properties we’ll add

<json.version>1.1.0-M1</json.version>
<glassfish.version>1.0.4</glassfish.version>

and these dependencies

<dependency>
   <groupId>javax.json</groupId>
   <artifactId>javax.json-api</artifactId>
   <version>${json.version}</version>
</dependency>

<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-rs-extension-providers</artifactId>
   <version>${cxf.version}</version>
</dependency>

<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.json</artifactId>
   <version>${glassfish.version}</version>
</dependency>

Next we’ll create a simple REST service (I’ll actually duplicate the one from here).

So create a new Java class, mine’s named PeopleService and here’s the code

package com.putridparrot.core;

import javax.json.JsonArray;
import javax.json.Json;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/people")
public class PeopleService {
    @Produces({"application/json"})
    @GET
    public JsonArray getPeople() {
        return Json.createArrayBuilder()
                .add(Json.createObjectBuilder()
                        .add("firstName", "Brian")
                        .add("lastName", "Kernighan "))
                .add(Json.createObjectBuilder()
                        .add("firstName", "Dennis")
                        .add("lastName", "Ritchie "))
                .add(Json.createObjectBuilder()
                        .add("firstName", "Bjarne")
                        .add("lastName", "Stroustrup"))
                .build();
    }
}

within AppConfig, place the following

@Bean @DependsOn( "cxf" )
public Server getRestServer() {
   JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
   factory.setServiceBean(new PeopleService());
   factory.setProvider(new JsrJsonpProvider());
   factory.setAddress("/rest");
   return factory.create();
}

if you run the App.main, you should be able to navigate to http://localhost:9000/soap/HelloWorld?wsdl to get the SOAP service’s wsdl and http://localhost:9000/rest/people to get the results of the PeopleService call.

Just to complete the picture – the PeopleService is given a path to the REST calls. We’re simply returning JSON and so we annotate with the @Produces line. As we’re only support a GET call to this service we annotate @GET. Within the getPeople method we build up a JSON document and that’s all there is to it.