Before proceeding ahead into this chapter, we assume that you know how to write a RESTful web service in Java. I will show you how to use CXF on top of this JAX-RS (Java API for RESTful Web Services) . We will create a web service that maintains a list of latest movies. When the user requests a movie, he specifies the movie ID in his request, the server will locate the movie and return it to the client. In our trivial case, we will simply return the movie name to the client and not the actual binary MP4 file. So let us start creating a JAX-RS application.
We will declare an XML root element called Movie for storing the id and the name for a given movie. The element is declared in a file called Movie.java. The contents of the file are shown here −
//Movie.java package com.howcodex.cxf.jaxrs.movie; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "Movie") public class Movie { private long id; private String name; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Note the use of XmlRootElement tag to declare the XML element for the Movie tag. Next, we will create a service that holds the list of movies in its database.
To store the list of movies we use Java supplied Map that stores the key-value pairs. If the list is large, you will use an external database storage which will also be easier to manage. In our trivial case, we will store only five movies in our database. The code for the MovieService class is given below −
//MovieService.java package com.howcodex.cxf.jaxrs.movie; import java.util.HashMap; import java.util.Map; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; @Path("/movieservice/") @Produces("text/xml") public class MovieService { long currentId = 123; Map<Long, Movie> movies = new HashMap<>(); public MovieService() { init(); } @GET @Path("/movie/{id}/") public Movie getMovie(@PathParam("id") String id) { long idNumber = Long.parseLong(id); return movies.get(idNumber); } final void init() { Movie c1 = new Movie(); c1.setName("Aquaman"); c1.setId(1001); movies.put(c1.getId(), c1); Movie c2 = new Movie(); c2.setName("Mission Imposssible"); c2.setId(1002); movies.put(c2.getId(), c2); Movie c3 = new Movie(); c3.setName("Black Panther"); c3.setId(1003); movies.put(c3.getId(), c3); Movie c4 = new Movie(); c4.setName("A Star is Born"); c4.setId(1004); movies.put(c4.getId(), c4); Movie c5 = new Movie(); c5.setName("The Meg"); c5.setId(1005); movies.put(c5.getId(), c5); } }
Note that we use the following two annotations to specify the URL path for our movie service and its return type −
@Path("/movieservice/") @Produces("text/xml")
We use the @GET and @Path annotations to specify the URL for the GET request as follows −
@GET @Path("/movie/{id}/")
The movie database itself is initialized in the init method, where we add five movie items to the database.
Our next task is to write a server application.
To create a server, we use CXF supplied JAXRSServerFactoryBean class.
JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
We set its resource classes by calling the setResourceClasses method.
factory.setResourceClasses(Movie.class); factory.setResourceClasses(MovieService.class);
We set the service provider by calling the setResourceProvider method.
factory.setResourceProvider(MovieService.class, new SingletonResourceProvider(new MovieService()));
We set the desired publish address by calling the aetAddress method −
factory.setAddress("http://localhost:9000/");
Finally, we publish the server by calling the create method on the factory instance.
factory.create();
The entire code for the server application is given below −
//Server.java package com.howcodex.cxf.jaxrs.movie; import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider; public class Server { public static void main(String[] args) throws Exception { JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean(); factory.setResourceClasses(Movie.class); factory.setResourceClasses(MovieService.class); factory.setResourceProvider(MovieService.class, new SingletonResourceProvider(new MovieService())); factory.setAddress("http://localhost:9000/"); factory.create(); System.out.println("Server ready..."); Thread.sleep(5 * 60 * 1000); System.out.println("Server exiting ..."); System.exit(0); } }
Here we have included the final version of pom.xml below −
<?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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.howcodex</groupId> <artifactId>cxf-jaxrs</artifactId> <version>1.0</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <profiles> <profile> <id>server</id> <build> <defaultGoal>test</defaultGoal> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.6.0</version> <executions> <execution> <phase>test</phase> <goals> <goal>java</goal> </goals> <configuration> <mainClass> com.howcodex.cxf.jaxrs.movie.Server </mainClass> </configuration> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>3.3.0</version> </dependency> </dependencies> </profile> <profile> <id>client</id> <build> <defaultGoal>test</defaultGoal> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <executions> <execution> <phase>test</phase> <goals> <goal>java</goal> </goals> <configuration> <mainClass> com.howcodex.cxf.jaxrs.movie.Client </mainClass> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> <dependencies> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxrs</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <version>2.1.5</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.7</version> </dependency> </dependencies> </project>
Writing the RS client is trivial. We simply create a URL object and open its stream. We use CXF supplied IOUtils class to copy the contents of input stream to a local stream.
URL url = new URL("http://localhost:9000/movieservice/movie/1002"); try (InputStream instream = url.openStream(); CachedOutputStream outstream = new CachedOutputStream()) { IOUtils.copy(instream, outstream); }
The entire code for the client application is given below −
//Client.java package com.howcodex.cxf.jaxrs.movie; import java.io.InputStream; import java.net.URL; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.io.CachedOutputStream; public class Client { public static void main(String[] args) throws Exception { URL url = new URL("http://localhost:9000/movieservice/movie/1002"); try (InputStream instream = url.openStream(); CachedOutputStream outstream = new CachedOutputStream()) { IOUtils.copy(instream, outstream); String str = outstream.getOut().toString(); System.out.println(str); } } }
Run the server using the following command in the command-line window −
mvn -Pserver
Now, you will see the following message on the console −
INFO: Setting the server's publish address to be http://localhost:9000
Now, open your browser and type the following URL −
http://localhost:9000/movieservice/movie/1002
You will see the following in the browser window.
You may invoke the service by using a Java client application that we have developed by running the following command in a separate command-line window.
mvn -Pclient
You will see the following output −
<?xml version="1.0" encoding = "UTF-8" standalone="yes"?> <Movie><id>1002</id><name>Mission Imposssible</name></Movie>
CXF samples provides several examples on how to use CXF with JAX-RS. The interested readers are encouraged to study these samples.