RESTful Services JAX-RS 2.0

Exclusive offer: get 50% off this eBook here
Java EE 7 Developer Handbook

Java EE 7 Developer Handbook — Save 50%

Develop professional applications in Java EE 7 with this essential reference guide with this book and ebook

$35.99    $18.00
by Peter A. Pilgrim | September 2013 | Enterprise Articles Java

In this article by Peter A. Pilgrim, author of the book Java EE 7 Developer Handbook, we will cover the Java API for RESTful services otherwise abbreviated to JAX-RS. It was the year, 2000, when Roy Fielding published his PhD thesis entitled Representational State Transfer: an Architecture Style. Since its publication over the past decade there has been a rapid growth of interest, applications, and implementations of REST style interfaces and application.

Representational State Transfer

Representational State Transfer (REST) is a style of information application architecture that aligns the distributed applications to the HTTP request and response protocols, in particular matching Hypermedia to the HTTP request methods and Uniform Resource Identifiers (URI).

Hypermedia is the term that describes the ability of a system to deliver self-referential content, where related contextual links point to downloadable or stream-able digital media, such as photographs, movies, documents, and other data. Modern systems, especially web applications, demonstrate through display of text that a certain fragment of text is a link to the media.

Hypermedia is the logical extension of the term hypertext, which is a text that contains embedded references to other text. These embedded references are called links, and they immediately transfer the user to the other text when they are invoked. Hypermedia is a property of media, including hypertext, to immediately link other media and text.

In HTML, the anchor tag <a> accepts a href attribute, the so-called hyperlink parameter.

The World Wide Web is built on the HTTP standards, Versions 1.0 and 1.1, which define specific enumerations to retrieve data from a web resource. These operations, sometimes called Web Methods, are GET, POST, PUT, and DELETE. Representational State Transfer also reuses these operations to form semantic interface to a URI.

Representational State Transfer, then, is both a style and architecture for building network enabled distributed applications. It is governed by the following constraints:

  • Client/Server: A REST application encourages the architectural robust principle of separation of concerns by dividing the solution into clients and servers. A standalone, therefore, cannot be a RESTful application. This constraint ensures the distributed nature of RESTful applications over the network.
  • Stateless: A REST application exhibits stateless communication. Clients cannot and should not take advantage of any stored context information in the server and therefore the full data of each request must be sent to the server for processing.
  • Cache: A REST application is able to declare which data is cacheable or not cacheable. This constraint allows the architect to set the performance level for the solution, in other words, a trade-off. Caching data to the web resource, allows the business to achieve a sense of latency, scalability, and availability. The counter point to improved performance through caching data is the issue of expiration of the cache at the correct time and sequence, when do we delete stale data? The cache constraint also permits successful implementation providers to develop optimal frameworks and servers.
  • Uniform Interface: A REST application emphasizes and maintains a unique identifier for each component and there are a set of protocols for accessing data. The constraint allows general interaction to any REST component and therefore anyone or anything can manipulate a REST component to access data. The drawback is the Uniform Interface may be suboptimal in ease-of-use and cognitive load to directly provide a data structure and remote procedure function call.
  • Layered Style: A REST application can be composed of functional processing layers in order to simplify complex flows of data between clients and servers. Layered style constraint permits modularization of function with the data and in itself is another sufficient example of separation of concerns. The layered style is an approach that benefits load-balancing servers, caching content, and scalability.
  • Code-on-Demand: A REST application can optimally supply downloadable code on demand for the client to execute. The code could be the byte-codes from the JVM, such as a Java Applet, or JavaFX WebStart application, or it could be a JavaScript code with say JSON data. Downloadable code is definitely a clear security risk that means that the solution architect must assume responsibility of sandboxing Java classes, profiling data, and applying certificate signing in all instances. Therefore, code-on-demand, is a disadvantage in a public domain service, and this constraint in REST application is only seen inside the firewalls of corporations.

In terms of the Java platform, the Java EE standard covers REST applications through the specification JAX-RS and this article covers Version 2.0.

JAX-RS 2.0 features

For Java EE 7, the JAX-RS 2.0 specification has the following new features:

  • Client-side API for invoking RESTful server-side remote endpoint
  • Support for Hypermedia linkage
  • Tighter integration with the Bean Validation framework
  • Asynchronous API for both server and client-side invocations
  • Container filters on the server side for processing incoming requests and outbound responses
  • Client filter on the client side for processing outgoing request and incoming responses
  • Reader and writer interceptors to handle specific content types

Architectural style

The REST style is simply a Uniform Resource Identifier and the application of the HTTP request methods, which invokes resources that generate a HTTP response. Although Fielding, himself, says that REST does not necessarily require the HTTP communication as a networker layer, and the style of architecture can be built on any other network protocol.

Let's look at those methods again with a fictional URL (http://fizzbuzz.com/)

Method

Description

POST

A REST style application creates or inserts an entity with the supplied data. The client can assume new data has been inserted into the underlying backend database and the server returns a new URI to reference the data.

PUT

A REST style application replaces the entity into the database with the supplied data.

GET

A REST style application retrieves the entity associated with the URI, and it can be a collection of URI representing entities or it can be the actual properties of the entity

DELETE

A REST style application deletes the entity associated with the URI from the backend database.

The user should note that PUT and DELETE are idempotent operations, meaning they can be repeated endlessly and the result is the same in steady state conditions.

The GET operation is a safe operation; it has no side effects to the server-side data.

REST style for collections of entities

Let's take a real example with the URL http://fizzbuzz.com/resources/, which represents the URI of a collection of resources. Resources could be anything, such as books, products, or cast iron widgets.

Method

Description

GET

Retrieves the collection entities by URI under the link http://fizzbuzz.com/resources and they may include other more data.

POST

Creates a new entity in the collection under the URI http://fizzbuzz.com/resources. The URI is automatically assigned and returned by this service call, which could be something like http://fizzbuzz.com/resources/WKT54321.

PUT

Replaces the entire collection of entities under the URI http://fizzbuzz.com/resources.

DELETE

Deletes the entire collection of entities under the URI http://fizzbuzz.com/resources.

As a reminder, a URI is a series of characters that identifies a particular resource on the World Wide Web. A URI, then, allows different clients to uniquely identify a resource on the web, or a representation. A URI is combination of a Uniform Resource Name (URN) and a Uniform Resource Locator (URL). You can think of a URN like a person's name, as way of naming an individual and a URL is similar to a person's home address, which is the way to go and visit them sometime.

In the modern world, non-technical people are accustomed to desktop web browsing as URL. However, the web URL is a special case of a generalized URI.

A diagram that illustrates HTML5 RESTful communication between a JAX RS 2.0 client and server, is as follows:

REST style for single entities

Assuming we have a URI reference to a single entity like http://fizzbuzz.com/resources/WKT54321.

Method

Description

GET

Retrieves the entity with reference to URI under the link http://fizzbuzz.com/resources/WKT54321.

POST

Creates a new sub entity under the URI http://fizzbuzz.com/resources/WKT54321. There is a subtle difference here, as this call does something else. It is not often used, except to create Master-Detail records. The URI of the subentity is automatically assigned and returned by this service call, which could be something like http://fizzbuzz.com/resources/WKT54321/D1023

PUT

Replaces the referenced entity's entire collection with the URI http://fizzbuzz.com/resources/WKT54321 . If the entity does not exist then the service creates it.

DELETE

Deletes the entity under the URI references http://fizzbuzz.com/resources/WKT54321

Now that we understand the REST style we can move on to the JAX-RS API properly.

Consider carefully your REST hierarchy of resources

The key to build a REST application is to target the users of the application instead of blindly converting the business domain into an exposed middleware. Does the user need the whole detail of every object and responsibility in the application? On the other hand is the design not spreading enough information for the intended audience to do their work?

Servlet mapping

In order to enable JAX-RS in a Java EE application the developer must set up the configuration in the web deployment descriptor file. JAX-RS requires a specific servlet mapping to be enabled, which triggers the provider to search for annotated classes.

The standard API for JAX-RS lies in the Java package javax.ws.rs and in its subpackages. Interestingly, the Java API for REST style interfaces sits underneath the Java Web Services package javax.ws.

For your web applications, you must configure a Java servlet with just fully qualified name of the class javax.ws.rs.core.Application. The Servlet must be mapped to a root URL pattern in order to intercept REST style requests.

The following is an example code of such a configuration:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="false">
<display-name>JavaEE Handbook 7 JAX RS Basic
</display-name>
<servlet>
<servlet-name>javax.ws.rs.core.Application
</servlet-name>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application
</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>

In the web deployment descriptor we just saw, only the servlet name is defined, javax.ws.rs.core.Application. Do not define the servlet class. The second step maps the URL pattern to the REST endpoint path. In this example, any URL that matches the simplified Glob pattern /rest/* is mapped. This is known as the application path.

A JAX-RS application is normally packaged up as a WAR file and deployed to a Java EE application server or a servlet container that conforms to the Web Profile. The application classes are stored in the /WEB-INF/classes and required libraries are found under /WEB-INF/lib folder. Therefore, JAX-RS applications share the consistency of configurations as servlet applications.

The JAX-RS specification does recommend, but does not enforce, that conformant providers follow the general principles of Servlet 3.0 plug-ability and discoverability of REST style endpoints. Discoverability is achieved in the recommendation through class scanning of the WAR file, and it is up to the provider to make this feature available.

An application can create a subclass of the javax.ws.rs.core.Application class. The Application class is a concrete class and looks like the following code:

public class Application {
public Application() { /* ... */ }
public java.util.Set<Class<?>> getClasses() {
/* ... */ }
public java.util.Set<Object> getSingletons() {
/* ... */ }
public java.util.Map<String,Object> getProperties() {
/* ... */ }
}

Implementing a custom Application subclass is a special case of providing maximum control of RESTful services for your business application. The developer must provide a set collection of classes that represent JAX-RS end points. The engineer must supply a list of Singleton object, if any, and do something useful with the properties.

The default implementation of javax.ws.rs.core.Application and the methods getClasses() and getSingletons() return empty sets. The getProperties() method returns an empty map collection. By returning empty sets, the provider assumes that all relevant JAX-RS resource and provider classes that are scanned and found will be added to the JAX-RS application.

Majority of the time, I suspect, you, the developer will want to rely on annotations to specify the REST end points and there are Servlet Context listeners and Servlet Filters to configure application wide behavior, for example the startup sequence of a web application.

So how can we register our own custom Application subclass? The answer is just subclass the core class with your own class.

The following code explains what we just read:

package com.fizbuzz.services;
@javax.ws.rs.ApplicationPath("rest")
public class GreatApp extends javax.ws.rs.core.Application {
// Do your custom thing here
}

In the custom GreatApp class, you can now configure logic for initialization. Note the use of @ApplicationPath annotation to configure the REST style URL. You still have to associate your custom Application subclass into the web deployment descriptor with a XML Servlet name definition.

Remember the Application Configuration

A very common error for first time JAX-RS developers is to forget that the web deployment descriptor really requires a servlet mapping to a javax.ws.js.core.Application type.

Now that we know how to initialize a JAX-RS application, let us dig deeper and look at the defining REST style endpoints.

Mapping JAX-RS resources

JAX-RS resources are configured through the resource path, which suffixes the application path. Here is the constitution of the URL.

http://<hostname>:<port>/<web_context>/<application_path>/<resource_path>

The <hostname> is the host name of the server. The <port> refers to the port number, which is optional and the default port is 80. The <web_context> is the Servlet context, which is the context for the deployed web application. The <application_path> is the configuration URI pattern as specified in the web deployment descriptor @ApplicationPath or the Servlet configuration of Application type. The <resource_path> is the resource path to REST style resource.

The final fragment <resource_path> defines the URL pattern that maps a REST style resource. The resource path is configured by annotation javax.ws.rs.Path.

Test-Driven Development with JAX-RS

Let us write a unit test to verify the simplest JAX-RS service. It follows a REST style resource around a list of books. There are only four books in this endpoint and the only thing the user/client can do at the start is to access the list of books by author and title. The client invokes the REST style endpoint, otherwise known as a resource with an HTTP GET request.

The following is the code for the class RestfulBookService:

package je7hb.jaxrs.basic;
import javax.annotation.*;
import javax.ws.rs.*;
import java.util.*;
@Path("/books")
public class RestfulBookService {
private List<Book> products = Arrays.asList(
new Book("Sir Arthur Dolan Coyle",
"Sherlock Holmes and the Hounds of the Baskervilles"),
new Book("Dan Brown", "Da Vinci Code"),
new Book("Charles Dickens", "Great Expectations"),
new Book("Robert Louis Stevenson", "Treasure Island"));
@GET
@Produces("text/plain")
public String getList() {
StringBuffer buf = new StringBuffer();
for (Book b: products) {
buf.append(b.title); buf.append('\n'); }
return buf.toString();
}
@PostConstruct
public void acquireResource() { /* ... */ }
@PreDestroy
public void releaseResource() { /* ... */ }
static class Book {
public final String author;
public final String title;
Book(String author, String title) {
this.author = author;
this.title = title;
}
}
}

The annotation @javax.ws.rs.Path declares the class as a REST style end-point for a resource. The @Path annotation is assigned to the class itself. The path argument defines the relative URL pattern for this resource, namely/books.

The method getList() is the interesting one. It is annotated with both @javax.ws.rs.GET and @javax.ws.rs.Produces.

The @GET is one of the six annotations that conform to the HTTP web request methods. It indicates that the method is associated with HTTP GET protocol request.

The @Produces annotation indicates the MIME content that this resource will generate. In this example, the MIME content is text/plain.

The other methods on the resource bring CDI into the picture. In the example, we are injecting post construction and pre destruction methods into the bean.

This is the only class that we require for a simple REST style application from the server side. With an invoking of the web resource with a HTTP GET Request like http://localhost:8080/mywebapp/rest/books we should get a plain text output with list of titles like the following:

Sherlock Holmes and the Hounds of the Baskervilles
Da Vinci Code
Great Expectations
Treasure Island

So do we test this REST style interface then? We could use Arquillian Framework directly, but this means our tests have to be built specifically in a project and it complicates the build process. Arquillian uses another open source project in the JBoss repository called ShrinkWrap. The framework allows the construction of various types of virtual Java archives in a programmatic fashion.

Let's look at the unit test class RestfulBookServiceTest in the following code:

package je7hb.jaxrs.basic;
// import omitted
public class RestfulBookServiceTest {
@Test
public void shouldAssembleAndRetrieveBookList()
throws Exception {
WebArchive webArchive =
ShrinkWrap.create(WebArchive.class, "test.war")
.addClasses(RestfulBookService.class)
.setWebXML(
new File("src/main/webapp/WEB-INF/web.xml"))
.addAsWebInfResource(
EmptyAsset.INSTANCE, "beans.xml");
File warFile = new File(webArchive.getName());
new ZipExporterImpl(webArchive)
.exportTo(warFile, true);
SimpleEmbeddedRunner runner =
SimpleEmbeddedRunner.launchDeployWarFile(
warFile, "mywebapp", 8080);
try {
URL url = new URL(
"http://localhost:8080/mywebapp/rest/books");
InputStream inputStream = url.openStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream));
List<String> lines = new ArrayList<>();
String text = null;
int count=0;
while ( ( text = reader.readLine()) != null ) {
lines.add(text);
++count;
System.out.printf("**** OUTPUT ****
text[%d] = %s\n", count, text );
}
assertFalse( lines.isEmpty() );
assertEquals("Sherlock Holmes and the Hounds
of the Baskervilles", lines.get(0));
assertEquals("Da Vinci Code", lines.get(1));
assertEquals("Great Expectations", lines.get(2));
assertEquals( "Treasure Island", lines.get(3) );
}
finally {
runner.stop();
}
}
}

In the unit test method, shouldAssembleAndRetrieveBookList(), we first assemble a virtual web archive with an explicit name test.war. The WAR file contains the RestfulBookService services, the Web deployment descriptor file web.xml and an empty beans.xml file, which if you remember is only there to trigger the CDI container into life for this web application.

With the virtual web archive, we export the WAR as a physical file with the utility ZipExporterImpl class from ShinkWrap library, which creates the file test.war in the project root folder.

Next, we fire up the SimpleEmbeddedRunner utility. It deploys the web archive to an embedded GlassFish container. Essentially, this is the boilerplate to get to deliver a test result.

We, then, get to the heart of the test itself; we construct a URL to invoke the REST style endpoint, which is http://localhost:8080/mywebapp/rest/books. We read the output from the service endpoint with Java standard I/O line by line into a list collection of Strings. Once we have a list of collections, then we assert each line against the expected output from the rest style service.

Because we acquired an expensive resource, like an embedded Glassfish container, we are careful to release it, which is the reason, why we surround critical code with a try-finally block statement. When the execution comes to end of test method, we ensure the embedded GlassFish container is shut down.

Java EE 7 Developer Handbook Develop professional applications in Java EE 7 with this essential reference guide with this book and ebook
Published: September 2013
eBook Price: $35.99
Book Price: $59.99
See more
Select your format and quantity:

JAX-RS server-side endpoints

We have looked at a simple GET request on a JAX-RS simple resource. In order to create a useful business application, we need the other web request methods, namely POST, PUT, and DELETE.

JAX-RS common server annotation

JAX-RS defines annotations for defining server side REST style endpoint, which are found in the Java package javax.ws.rs.

The following is a table of these annotations:

Annotation

Description

@Path

Defines the relative URI path for the REST style Java class and configures where it is installed and mapped.

@GET

Defines a method on the Java class REST style resource to accept HTTP GET requests.

@POST

Defines a method on the Java class REST style resource to accept HTTP POST requests.

@PUT

Defines a method on the Java class REST style resource to accept HTTP PUT requests.

@DELETE

Defines a method on the Java class REST style resource to accept HTTP DELETE requests.

@HEAD

Defines a method on the Java class REST style resource to accept HTTP HEAD requests.

@TRACE

Defines a method on the Java class REST style resource to accept HTTP TRACE requests.

@PathParam

Defines a URI fragment parameter that permits the developer to extract from the REST request into the resource class. URI path parameters are extracted from the request URI, and the parameter name must match information found in the URI path template variables specified in the @Path class-level annotation.

@QueryParam

Defines a (CGI-style) query parameter that permits the developer to extract from the REST request.

@Consumes

Specifies MIME media representations that the REST style consumes from the client. Typically, this is useful for a REST style uploading application, which only accepts a certain media type of document.

@Produces

Specifies the MIME media representation that the REST style endpoint produces for the client.

@Provider

Specifies extra resource information that is useful for extending the capabilities of the JAX-RS runtime with custom features for your application. This annotation can be seen as a sort of factory object or virtual constructor for building filters, interceptors, and dynamic features.

Obviously, a Java method can only accept one of the HTTP request annotations. It is illegal, for instance, to annotate a single method with @GET and @POST; and the JAX-RS provider will generate an error.

Defining JAX-RS resources

Let's look at a more realistic example of JAX-RS service endpoint. We will develop a REST style endpoint that can accept a registered set of users. The service allows a client to register a user with a log-in name, first and last name, and a secret code. Admittedly, this service is contrived, however this shows how to implement a JAX-RS service completely and we will see how to test it thoroughly. The following table shows the REST style URI for the service:

URI

Purpose

<mywebapp>/rest/users

Refers to list of registered users

<mywebapp>/rest/users/pilgrimp

Refers to a specific user

<mywebapp>/rest/users/goslingj

Refers to another specific user

Where <mywebapp> is the placeholder for URL http://localhost/mywebapp/

The following code shows our data value class, User:

package je7hb.jaxrs.basic;
public final class User implements Comparable<User> {
private final String loginName, firstName, lastName,
secretName;
public User(String loginName, String firstName,
String lastName, int secretCode) {
this.loginName = loginName;
this.firstName = firstName;
this.lastName = lastName;
this.secretCode = secretCode;
}
public String getLoginName() { return loginName; }
public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public int getSecretCode() { return secretCode; }
@Override
public int compareTo(User ref) {
return loginName.compareTo(ref.loginName);
}
// hashcode(), equals(), toString() methods omitted
}

For storage of the user, we will rely on Singleton EJB, which is called UserRegistry. The following code explains it:

package je7hb.jaxrs.basic;
/* ... imports omitted */
@Singleton
@Startup
public class UserRegistry {
private ConcurrentMap<String,User> registeredUsers
= new ConcurrentHashMap<>();
public void addUser( User user ) {
registeredUsers.put( user.getLoginName(), user );
}
public void removeUser( User user ) {
registeredUsers.remove(user.getLoginName());
}
public User findUser( String loginName ) {
return registeredUsers.get(loginName);
}
public List<User> getUsers( ) {
List<User> users =
new ArrayList<>(registeredUsers.values());
Collections.sort(users);
return users;
}
@PostConstruct
public void postConstruct() { /* ... */ }
@PreDestroy
public void preDestroy() { /* ... */ }
}

As a reminder, this is a stateless session EJB, which is annotated with @Startup, because we want the bean instance to be immediately available as soon as the web application is deployed. We also annotate the class with @Singleton to ensure only the EJB instance is available for the entire application.

Now let's look at the following code of the REST style resource, which is implemented by the class called RegisteredUserResource:

package je7hb.jaxrs.basic;
import javax.ejb.*;
import javax.ws.rs.*;
@Path("/users")
@Stateless
public class RegisteredUserResource {
@EJB
private UserRegistry userRegistry;
@GET
@Produces("text/csv")
public String listUsers() {
StringBuilder buf = new StringBuilder();
for ( User user : userRegistry.getUsers()) {
buf.append( user.getLoginName()
+","+user.getFirstName()+",");
buf.append( user.getLastName()
+","+user.getSecretCode()+"\n");
}
return buf.toString();
}
@GET
@Path("{id}")
@Produces("text/csv")
public String getUser( @PathParam("id") String loginName ) {
User user = userRegistry.findUser(loginName);
if ( user == null ) {
return "";
}
StringBuilder buf = new StringBuilder();
buf.append( user.getLoginName()
+","+user.getFirstName()+",");
buf.append( user.getLastName()
+","+user.getSecretCode()+"\n");
return buf.toString();
}
@POST
@Path("{id}")
public void addUser( @PathParam("id") String loginName,
@FormParam("firstName") String fname,
@FormParam("lastName") String lname,
@FormParam("secretCode") int code )
{
User user = new User(loginName,fname,lname,code);
userRegistry.addUser(user);
}
@PUT
@Path("{id}")
public void amendUser( @PathParam("id") String loginName,
@FormParam("firstName") String fname,
@FormParam("lastName") String lname,
@FormParam("secretCode") int code )
{
User user = userRegistry.findUser(loginName);
if ( user == null ) {
throw new UnknownUserException(
"unknown login name: ["+loginName+"]");
}
else {
User user2 = new User(
user.getLoginName(), fname, lname, code );
userRegistry.addUser(user2);
}
}
@DELETE
@Path("{id}")
public void deleteUser(
@PathParam("id") String loginName) {
User user = userRegistry.findUser(loginName);
if ( user == null ) {
throw new UnknownUserException(
"unknown login name: ["+loginName+"]");
}
else {
userRegistry.removeUser(user);
}
}
}

The class implements all of the four HTTP web request methods. It is surprising that the JAX-RS resource, RegisteredUserResource, itself is written as a Stateless session EJB. The reason for this is to do with the progression of the initial JAX-RS specification 1.0 predated the Context and Dependency Inject and EJB instance facilities and at the time of writing was not clear JAX-RS 2.0 will work. Nonetheless, the procedure is solid and it is the intention of the standard JavaEE 7 to support JAX-RS, CDI and EJB injection.

The class RegisteredUserResource injects the singleton EJB UserRegistry and therefore can make use of the store. The class is annotated with the relative REST style URI path/users.

The listUsers() method has @Produces annotation that is different, text/csv stands for comma-separated values, which is a file format supported by popular spreadsheet programs such Microsoft Excel and Libre Office. Hence, this method generates comma-delimited output for each user in the registry.

The method getUser() introduces us to URI path variables. Variables are denoted with the braces ({ }). The annotation @PathParam("{id}") adds a variable to the current path and permits a method to be extracted from the URL template. This is the way to process a REST style by identifier and the annotation is applied to the method argument. This method attempts to find the User record by log-in name. If it can retrieve the object getUser(), it returns a CSV representation otherwise the output is empty text. This method is important for testing the REST resource as we shall see later.

In order to add a new user to the registry, there is @POST annotation on the addUser() method. Here is a new annotation @javax.ws.rs.FormParam, which specifically retrieves HTTP form parameters from the incoming request. They correspond directly with HTML Form submissions. The @FormParam requires the name of the form request parameter and we apply them to the method arguments. The JAX-RS implementation injects the form parameters and the identifier variable during invocation of the method. The addUser() method simply constructs a new User record and adds it to the registry. There is no side effect and output response rendered for a POST. The JAX-RS implementation will respond with a HTTP Response Code 200 on successful execution of the method.

The method amendUser() is almost the same as the addUser(), because it uses the same parameters with @PathParam and @FormParm annotations. The difference is the amendment assuming that a User record already exists in the registry. It saves a new version of the User record into the registry. The amendment is associated with the @PUT annotation and associated HTTP PUT requests.

The method deleteUser() is the last method and this annotated with the @Delete annotation and associated HTTP DELETE requests. This method only requires the path parameter to identifier the specify user to delete.

Prefer to specify the MIME type

You should seriously consider specifying the media type with @Produces for all methods of the REST resource, especially if you are passing multiple MIME types. If you write a custom resource method that can return more than one MIME content type with ResponseBuilder, then it is definitely helpful to the client to set media type.

You may be wondering about the custom exception UnknownUserException. If an arbitrary exception is raised during the JAX-RS request on the server side, then the client (or user) sees a HTTP Response 500 code (Forbidden). This is probably not the error you want users or developers to see.

The following is the code for the exception class:

package je7hb.jaxrs.basic; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.*; public class UnknownUserException extends WebApplicationException { public UnknownUserException(String message) { super( Response.status(Response.Status.NOT_FOUND). entity(message).type(MediaType.TEXT_PLAIN_TYPE).build()); } }

This custom exception extends the WebApplicationException exception. In the constructor, we make use of the JAX-RS Response builder object to generate a HTTP 404 error (NOT_FOUND), add our message string as the entity and set the media type to text/plain MIME content. This is the key to building custom JAX-RS messages, and I hope you will not see many of these error message in your applications.

Testing JAX-RS resources

The obvious way to test a JAX-RS resource, in a clean, concise, and solid way, is to deploy the resource to a container and then have a test harness that invokes each of the endpoints. By running inside a container we can have a high degree of confidence that the final code will run in a production environment.

Let us now look at how to write a test for all of these processes. The following is the code for the unit test RegisteredUserResourceTest. Be warned, it is fairly big for now:

package je7hb.jaxrs.basic; /* ... imports omitted */ public class RegisteredUserResourceTest { public static final String ROOT_RES_PATH = "http://localhost:8080/mywebapp/rest/users"; public static final String USER_RES_PATH = ROOT_RES_PATH+"/pilgrimp"; private static SimpleEmbeddedRunner runner; @BeforeClass public static void beforeAllTests() throws Exception { WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "testusers.war") .addClasses(RegisteredUserResource.class, /* . . . */ } /* ... */ @Test public void shouldAddOneUser() throws Exception { Map<String,String> params = new HashMap<String,String>() { { put("firstName", "Peter"); put("lastName", "Pilgrim"); put("secretCode", "19802014"); } }; List<String> output = makePostRequest( new URL(USER_RES_PATH), params); assertTrue(output.isEmpty()); List<String> lines = makeGetRequest( new URL(USER_RES_PATH) ); assertFalse(lines.isEmpty()); assertEquals("pilgrimp,Peter,Pilgrim,19802014", lines.get(0)); } /* ... */ }

The class RegisteredUserResourceTest is fairly involved and more than that code is devoted to creating the environment for the test. Having said all of that, the test does work.

The first part of the call is the refactoring of the ShrinkWrap packaging and the embedded container launch to the JUnit methods beforeAllTests() and afterAllTests(). These are static methods so that they are only invoked when the class is loaded, just before the series unit test method is executed and after the test has run in the class.

The unit test makes use of a utility class WebMethodUtils, which has a series of static methods to make HTTP request method calls to a remote server. The utility class uses the JDK classes, javax.net.URL, javax.net.HttpURLConnection also standard I/O.

The first test, the method shouldAddOneUser(), creates a HTTP POST request of a user with form data. A literal hash map collection is created with name and value pairs to simulate form request data. A HTTP POST request is made to the JAX RS Resource with the form parameters. This is the responsibility of the static call to makePostRequest() with the URL http://localhost:8080/mywebapp/rest/users/pilgrimp. There should be no output and there is an assertion for empty text. Next, the unit test method makes a call to makeGetRequest() with the same URL. We should expect the output from the REST style to be comma delimited as "pilgrim,Peter,Pilgrim,19802014", which of course the actual output matches to. In this way, we validate that information was stored by the JAX-RS service. The following code shows the validation:

@Test public void shouldAmendOneUser() throws Exception { shouldAddOneUser(); Map<String,String> params2 = new HashMap<String,String>(){ { put("firstName", "Pierre"); put("lastName", "Pilgrim"); put("secretCode", "87654321"); } }; List<String> output = makePutRequest( new URL(USER_RES_PATH), params2); assertTrue(output.isEmpty()); List<String> lines = makeGetRequest( new URL(USER_RES_PATH) ); assertFalse(lines.isEmpty()); assertEquals("pilgrimp,Pierre,Pilgrim,87654321", lines.get(0)); }

The second test method shouldAmendOneUser() follows a similar principle and it executes HTTP POST to insert the record followed by a HTTP PUT and then a HTTP GET. The test validates the operation of the PUT method by editing the user record from the client side. In this case, the first name is changed to Pierre and the secret code to a different number. The GET request validates the data has been changed by the endpoint. The following code shows what we just read:

@Test public void shouldDeleteOneUser() throws Exception { shouldAddOneUser(); List<String> output = makeDeleteRequest( new URL(USER_RES_PATH)); assertTrue(output.isEmpty()); List<String> lines = makeGetRequest( new URL(USER_RES_PATH) ); assertTrue(lines.isEmpty()); }

The third test method shouldDeleteOneUser() creates a HTTP POST method with a user and invokes the HTTP DELETE method. The GET request validates the data has been removed. The output text should be blank.

In the article's source code, you will see the fourth and final test method shouldAddTwoUsers()should verify that the JAX-RS Resource can maintain more than one User record. There, we create two different User records with HTTP POST web request. In this test method, we invoke the HTTP GET with the parent URL http://localhost:8080/mywebapp/rest/users and we validate the CSV output. The list of users is sorted by the login name, which you can see in the UserRegistry class, namely the getUsers() method.

Here is a little to the wise, the unit test, although it follows a Behavioral-Driven Design pattern, which is nice, is not the best way to achieve the result. We will see later how to achieve better testing with the JAX-RS Client API.

Path URI variables

As we have seen in the previous section, path variables are placeholders inside a URL template that represent a value that changes on the request. Path variables are denoted within brace characters for example, "/users/{id}". A Path variable can be a simple name or it can be a regular expression.

The Path variable as a simple name is defined by combination of alphabetic and numerical characters. In fact, the path variable can be any character apart from spaces, backslash and special terminal characters. The URI variable must match the regular "[^/]+?". For best practice, it is probably best to stick to the Java identifier syntax.

The following is an example of simple variable conventions:

@Path("/users/{username47}") public class ACMEUserResource { @GET @Products("text/xml") public String getUserList( ) { // username is null, so return a list collection /* ... */ } @GET @Products("text/xml") public String getUser (@PathParam("username47") String username ) { /* ... */ } }

In the example class we just saw, ACMEUserResource is annotated with a path URI template with one variable, which is called username47. There are two methods, namely, getUser() and getUserList(). The getUser() method accepts a single argument, a named path parameter /users/{username47}. JAX-RS will invoke this method if there is a matching URL request such as /users/jamesdean. On the other hand, if the incoming URL request was just defined as /users then JAX-RS, instead, will choose the getUserList() method, because the method does not require a path parameter.

Path variable can also be defined with custom regular expressions to further restrict the characters that can be matched. The following is an example of the same JAX-RS resource, where we restrict the match to lowercase and uppercase alphanumeric and underscore characters.

@Path("/users/{username47: [a-zA-Z_][a-zA-Z_0-9]*}") public class ACMEUserResource { /* ... */ }

A @Path value can have leading or trailing slash character (/). Given the regular expression, the JAX-RS runtime parses the template for matching URI path elements. In this case, username47 accepts a path element that can start with an underscore character. A path name can start with a leading or trailing slash character.

It is possible to have a URI path template with more than one variable. Each variable name must be surrounded with braces. The following is an example of a widget REST style resource for a warehouse business.

@Path("/widgets/{range}/{manufacturer}/{productId}") public class ACMEInventoryResource { @PathParam("range") private String range; @PathParam("manufacturer") private String manufacturer; @PathParam("productId") private String productId; /* ... */ }

This class ACMEInventoryResource accepts a resource with three variables and the JAX-RS provider will attempt to activate it on matching URL requests. The developer of this resource must take into account that perhaps one, two, or three of the parameters may or may not be selected.

JAX-RS annotations for extracting field and bean properties

JAX-RS has several annotations for extracting field and bean properties from in the incoming HTTP request. We have already seen some of them such as @PathParam, which extracts data from the URI template path and @FormParam, which extracts data from form request parameters.

JAX-RS has some additional annotations to extract further data from the HTTP request.

Annotation

Description

@Context

Injects JAX-RS context information into the class field and bean property of method parameter.

@CookieParam

Extracts data from cookies declared in the request header.

@FormParam

Extracts data from form request data in a POST and PUT request and where the content type is encoded with application/x-www-form-urlencoded.

@HeaderParam

Extracts the data value from a HTTP header parameter.

@MatrixParam

Extracts the data value from a URI matrix parameter.

@PathParam

Extracts the data value from a URI template parameter.r

@QueryParam

Extracts the data value from a URI query parameter, which is the same as the old fashion CGI query parameter.

@DefaultValue

Injects a default value into the class field and bean property of method parameter when the JAX-RS runtime cannot find an appropriate value.

Extracting query parameters

The annotation @javax.ws.js.QueryParam allows data values to be extracted from the query component of the incoming request URI, the web request.

Let us look at a JAX-RS resource that demonstrates the use of @QueryParam. The business case is a website that delivers job search for contractors and permanent staff. For this example, we show only the contract search for candidate. We allow contractors to search for jobs by minimum and maximum rate, the currency, and also allow the unit rate to be set. For example, contract can be set by hours per day, a daily rate, or sometimes a weekly rate.

The following is the code for the JobSearchService REST style resource:

@Path("/contracts") public class JobSearchService { @GET public String getJobs( @QueryParam("ccy") String ccy, @QueryParam("unitrate") String unitrate, @QueryParam("minrate") int minrate, @QueryParam("maxprice") int maxrate) { /*...*/ } }

The resource is invoked by a URI template matching the /contracts. The JAX-RS runtime calls the method getJobs() with a HTTP GET request. In order to fulfill the request the URI must be supplied with all of the expected query parameters.

The following URIs match this resource.

/contracts?ccy=GBP&unitrate=PER_DAY&minrate=250&maxrate=750 /contracts?maxrate=470&minrate=325&ccy=GBP&unitrate=PER_DAY /contracts?&unitrate=PER_HOUR&ccy=EUR&minrate=30&maxrate=90

It is an interesting note and a nice technique that query parameters can be combined with @DefaultValue annotations.

Extracting matrix parameters

Matrix parameters are a form of URI pattern that contains name and value pairs. The form of the URI is as follows "/something;param1=value1;param2=value2". The URI pattern contains name and value pair separated with an equal character (:) and the pairs delimited by the semi-colon character (;).

The following is an example of JAX-RS resource that makes use of @javax.ws.js.MatrixParam annotation:

@Path("/admin") public class ValuationService { @GET @Path("{customer}") public String getValue( @MatrixParam(«price») String price, @MatrixParam(«quantity») int quantity) { return String.format( "Customer [%s] want price [%s] at quantity: [%d]" customer, price, quantity ); } }

This class ValuationService responds to the URL pattern such as /admin/janet_fripps. The JAX-RS runtime provider will invoke this class given the matching URI and the method getValue().

For the URI pattern /admin/janet_fripps, the method generates the following text:

Customer janet_fripps wants price null at quantity null.

For the URI pattern /admin/janet_fripps;price=24.99, the method generates the following text:

Customer janet_fripps wants price 24.99 at quantity null.

For the URI pattern /admin/janet_fripps;price=24.99;quantity=12, the method generates the following text:

Customer janet_fripps wants price 24.99 at quantity 12.

For the alternative URI pattern: /admin/mark_webber;quantity=7;price=39.99, the method generates the following text:

Customer mark_webber wants price 39.99 at quantity 7.

Using default values

JAX-RS permits default values to be defined for path variable on the class field and bean property or method argument. The @javax.ws.rs.DefaultValue annotation specifies a default value, if the metadata is not present in the request.

The following is an example of the annotation in action:

@Path("/aston/{year}/{model}/{engine}") public class CarProductResource { @DefaultValue("2014") @PathParam("year") private String range; @DefaultValue("Solar") @PathParam("model") private String model; @DefaultValue("2155") @PathParam("engine") private int engineCc; /* ... */ }

This CarProductResource class is a fictional example resource for a British car manufacturer and it caters for the firm's idea of organizing their business of selling cars around the combination of year, model, and an engine size. Here, we have gone through the trouble of ensuring that all three parameters are always set to a value, even if one or more parameters are missing from the web request to the resource.

Extracting form parameters

JAX-RS extracts form parameters with the annotation @javax.ws.rs.FormParam. Form parameters are submitted from a web client and encoded by the browser in standard format. They are normally sent with a HTTP POST or PUT request.

We already have seen how to extract form parameters in the UserRegistry example earlier in this article. The following is this code again for perusal.

@Path("/users") @Stateless public class RegisteredUserResource { @POST @Path("{id}") @Consumes("application/x-www-form-urlencoded") public void addUser( @PathParam("id") String loginName, @FormParam("firstName") String fname, @FormParam("lastName") String lname, @FormParam("secretCode") int code ) { User user = new User(loginName,fname,lname,code); userRegistry.addUser(user); } /* ... */ }

The @Consumes annotation on the resource method, directly stipulates how this method will behave, the MIME content, it will only be triggered by the JAX-RS runtime to act on HTML form requests.

There is an alternative way to access form parameters generically. In this case, we do need the @Consumes annotation and must use the JAX-RS specific javax.ws.js.core.MultivaluedMap collection. The multi-value map is a map collection of keys to a list of values. Each dictionary key can map to more than one value, which is an allowed feature of the HTTP specification.

Here is an alternative implementation of the addUser() method that demonstrates the generic form parameter logic:

@Path("/users") @Stateless public class RegisteredUserResource { /* ... */ @POST @Path("{id}") @Consumes("application/x-www-form-urlencoded") public void addUser( @PathParam("id") String loginName, MultivaluedMap<String,String> formParams) { User user = new User( formParams.getFirst("firstName"), formParams.getFirst("lastName"), formParams.getFirst("secretCode")); userRegistry.addUser(user); } /* ... */ }

It is interesting to note, we call getFirst() to retrieve the value of the key from the multi-value map.

Field and bean properties

When the JAX-RS runtime instantiates a resource at runtime, it will also inject values into the fields of the resource and JavaBeans. It will inject values into method parameter before invocation of the matched resource method after URI path matching. The runtime will pay attention particularly to the following annotations: @CookieParam, @Context, @FormParam, @HeaderParam, @MatrixParam, @PathParam, @QueryParam.

The JAX-RS runtime perform injection at object creation time and therefore the annotations are checked for incompatible contextual scope, but the standard does not enforce the restriction, instead it recommends that the runtime warn the developer when the annotation is used in a problematic scope.

The following are the rules for the injection of parameter values:

  • The runtime will apply conversion for an object type V for which javax.ws.js.ext.ParamConverter is available via registered javax.ws.js.ext.ParamConverterProvider.
  • Injection applies automatically to primitive types.
  • Types that have a constructor with a single String argument.
  • Types that have a static method named valueOf() or fromString() with a single String argument and also return an instance of the type. If both methods are available, then for a non-enumerated type the runtime must choose valueOf(), otherwise for an enumerated type the runtime chooses fromString().
  • The type is a specific Java collection and a generic type List<T>, Set<T>, or SortedSet<T>.
  • For any of these injection values, the developer can choose to annotate the injection point with a @DefaultValue.

JAX-RS subresources

The JAX resource can delegate to subresource and this feature allows developers, designers, and architects to build modular REST style applications with better separation of concerns, higher cohesion, and reduced coupling.

A JAX-RS subresource is a class method annotated with @Path, which indicates that the method is a subresource method or a subresource locator. Resource classes are able to partially process a request and provide another subresource, which processes the remainder of the request. In short, this is all about delegation.

JAX-RS permits subresource to be fulfilled by location, where another delegate class fulfills the URI template match.

Resolution by a subresource location

Take for example, a fashion store business that maintains a number of key accounts, the designer houses. The main entry point into the REST style interface could be separated out into constituent parts. The following code shows two JAX-RS resource classes FashionStore and DesignerHouse:

@Path("/") public class FashionStore { @Path("/designers/{id}") public DesignerHouse getDesigner( @PathParam("id") int id ) { DesignerHouse house = houseData.findById(id) return house; } } public class DesignerHouse { @GET public String getDetails() { /*...*/ } @Path("/principal") public String getPrincipal() { /*...*/ } }

The root URI pattern @Path("/") matches the class FashionStore, and therefore this master resource behaves like the root of the entire REST style interface. This class may well have other responsibilities in true business applications.

Given an incoming request for a listed designer HTTP GET request, the FashionStore delegates to a subresource through the method getDesigner(). The method is annotated with @Path("/designers/{id}") and it returns a subresource object DesignerHouse.

JAX-RS runtime provider will see the DesignerHouse object that was returned and then proceed to process the remaining parts of incoming URI with that object. In the specification, this is called Subresource Resolution by Location. JAX-RS then proceeds to process HTTP GET request and invokes the getDetails() method and after this call completes, the process is complete.

Resolution by a subresource method

The alternative subresource resolution strategy makes the code part of the parent resource. The JAX-RS resource processes the HTTP request directly. This is known as the Subresource Resolution by Direct Method.

Let's add one more method to our fashion store example that will clarify resolution by direct method. There is a requirement for certain staff to get cashier information in order to deal with specific customer requests such returns of garment, collection, alterations, and other usual requests. All such staff must work with an authorized cashier information stamp for these daily tasks and audit.

The following code shows the additional subresource method:

@Path("/") public class FashionStore { @GET @Path("/staff/{domain}/{staffCode}") public String getCashierInfo( @PathParam("staffCode") String staffCode, @PathParam("domain") String domain ) { return cashierManagerService.findByCodeAndDomain( staffCode,domain) } }

The HTTP GET request /staff/2042/summerbys will cause the JAX-RS runtime to activate the method getCashierInfo().

Path resources and responses

Path URI and response are two sides of the same coin in the pure REST style. The REST style should ideally look like hypertext. Every addressable bit of information contains an address either explicitly through links and ID, or implicitly through the media type and its representation.

Generating a JAX-RS generic response

JAX-RS provides means to generate response generically. The abstract class javax.ws.js.core.Response is a contract object, which the developer uses to produce a generic response with metadata for the JAX-RS runtime provider. An application can extend this class directly or it can create an instance of Response object with the nested inner class javax.ws.js.core.Response.ResponseBuilder. Most applications tend to use the ResponseBuilder.

We have already seen an illustration of Response and ResponseBuilder in the custom UnknownUserException exception class. Go back and revisit the user registry example in Defining JAX-RS Resources, if you need to study.

Response builder

The Response class has several static methods that create and return a ResponseBuilder object.

To create an OK response, with HTTP Response code of 200, we can invoke the ok() method. We can also supply an entity of the response with the entity() method, which specifies the payload to send back to the client. We can set the MIME content of the entity too.

After configuring the ResponseBuilder, we then need to actually construct a response, which is sent to the client, by calling the build() method.

The following code shows a sample class that demonstrates some of the ways to build generic response outputs programmatically:

package je7hb.jaxrs.basic; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; public class SampleResponse { public Response generateSimpleOk() { return Response.ok().build(); } public Response generateSimpleOkWithEntity() { return Response.ok().entity("This is message") .type(MediaType.TEXT_PLAIN_TYPE).build(); } public Response generateSimpleOkWithEntityXml() { return Response.ok().entity("<msg>This ismessage</msg>") .type(MediaType.TEXT_XML_TYPE).build(); } public Response generateSimpleOkWithGermanyLang() { return Response.ok() .language(„de_de") .entity(„<msg>Einfaches boetschaft</msg>") .type(MediaType.TEXT_XML_TYPE).build(); } public Response generateUnauthorisedError() { return Response.status(Response.Status.UNAUTHORIZED) .build(); } public Response generateUnauthorisedWithEntityXml() { return Response.status(Response.Status.UNAUTHORIZED) .entity("<msg>Unauthorised</msg>") .type(MediaType.TEXT_XML_TYPE).build(); } }

In the SampleResponse class, we just saw, to avoid subtle literal string errors, note how we make use of the javax.ws.rs.core.MediaType. Static definitions of this class are used to set the MIME content as an argument to the response builder's type() method.

It is also possible to set the language and the character encoding of the response with methods language() and encoding(). Although not shown here, ResponseBuilder does have more additional methods in order to configure response headers, last modification date, expiration date and time, new cookies, and links for purpose of URI redirection.

MediaType class defines static constants, such as APPLICATION_JSON_TYPE, TEXT_PLAIN_TYPE, and TEXT_HTMLTYPE. The class also defines String equivalents of these, such as APPLICATION_JSON ("application/json"), TEXT_PLAIN ("text/plain"), and TEXT_HTML ("text/html").

This, then, is useful for setting the value @Produces and @Consumes in JAX-RS resource methods. For instance, we can write the code in the following way:

@GET @Produces(MediaType.TEXT_PLAIN) public String getList() { /* ...*/ return buf.toString(); }

Response status

The class javax.ws.js.core.Response.Status defines a set of enumeration values that correspond to the response code in the HTTP 1.1 communication standard. Refer to the following table:

Enumerated Constant

Code

Description

ACCEPTED

202

Request has been accepted, but the processing has not been completed.

BAD_GATEWAY

503

The server, while acting as a gateway or proxy, received an invalid response from the upstream server whilst attempted to fulfill the client's request (Since JAX-RS 2.0).

BAD_REQUEST

400

The server due to malformed syntax cannot understand the request. The client should not repeat the request.

CONFLICT

409

The request could not be completed due to a conflict with the current state of the resource. This is a useful state when two REST requests attempt to update the resource at the same time on a user defined transaction.

CREATED

201

The request was successful and the new resource was created.

FORBIDDEN

403

The server understood the request, but it is refusing to fulfill it. This response can be reported to the client to hint that the request is not secure without making it public why the request was denied.

GONE

410

The request resource is no longer available at the server and no forwarding address is known. Perhaps, REST style for deleting of the resource has already arrived in the inbox and the server knows somehow that resource has flag set: pending for deletion in the next 24 hours or so.

HTTP_VERSION_NOT_SUPPORTED

505

The server does not support, or refuses to support, the HTTP protocol that was used in the request message. (Since JAX-RS 2.0.)

INTERNAL_SERVER_ERROR

500

The server encountered an expected condition, which prevented it from fulfilling the request. A useful case for this system might be JAX-RS that cannot connect to external dependent service, for example, credit brokerage or order warehouse system.

LENGTH_REQUIRED

411

The server refuses to accept the request without a defined Content-Length value in the HTTP headers. (Since JAX-RS 2.0.)

METHOD_NOT_ALLOWED

405

The method in the Request-URI is not allowed for the resource identified by the Request-URI (Since JAX-RS 2.0)-an example of this might be an immutable resource of secure, static, or reputable constant source of information.

MOVED_PERMANENTLY

301

The requested resource has been assigned a new permanent URI and any other references to this resource should use the new URI.

NO_CONTENT

204

The server fulfilled the request, but does not need to return an entity body.

NOT_ACCEPTABLE

406

The resource identified by the request is only capable of generating response entities, which have content characteristics that are not acceptable with the headers sent in the request.

NOT_FOUND

404

The server has not found anything matching the Request URI. (Since JAX-RS 2.0.)

NOT_IMPLEMENTED

501

The server does not support the functionality required to complete the request. (Since JAX-RS 2.0.)

NOT_MODIFIED

304

If the client performed a conditional GET request and access is allowed, but the document has not been modified, the server should return this error. It is very rare that a REST application will make a conditional GET request.

OK

200

The request was successful.

PAYMENT_REQUIRED

402

The server blocked this request, because commercial payment is required (JAX-RS 2.0.)

PRECONDITION_FAILED

412

The precondition given in one or more of the request-header fields evaluated to be false when it was tested on the server. (Since JAX-RS 2.0.)

PROXY_AUTHENTICATION_REQUIRED

407

The client did not first authenticate itself with the proxy (JAX-RS 2.0.)

REQUEST_TIMEOUT

408

The client did not produce a request within the time that the server was prepared to wait. (JAX-RS 2.0.)-An easy example is a ticket reservation on an airplane.

REQUEST_URI_TOO_LONG

414

The server refuses to service request, because the Request-URI is longer than, the server is willing to interpret (JAX-RS 2.0.)

REQUEST_RANGE_NOT_ SATISFIABLE

416

The server refuses to process a request, if a the value in the Range request-header exceeds the constraints of the selected resource (JAX-RS 2.0.)

SEE_OTHER

303

This is HTTP redirection that informs the client to make alternative GET method on an alternative URI.

SERVICE_UNAVAILABLE

503

The server is currently unable to handle the request due to temporary overloading or maintenance of the server. The status implies that the temporary condition will be alleviated after some delay.

TEMPORARY_REDIRECT

307

The requested resource resides temporarily under a different URI.

UNAUTHORIZED

401

The requested resource requires user authorization.

UNSUPPORTED_MEDIA_TYPE

415

The server refuses to service the request, because the entity of the request is in a format not supported by the endpoint.

ResponseBuilder has several helpful functions to build a response. The Response object is supported in both server and client JAX-RS APIs. Users are encouraged to take advantage of the strong type safety by referencing static constants in Java class rather than loose literal strings.

Generic entities

Since Java has generics, how does JAX-RS take care of parameterized collection types? The answer is the runtime requires some help, because of type erasure.

In order to inform the runtime about a generic collection, there is a class, which developers can use, called javax.ws.rs.core.GenericEntity.

The following code shows a REST style planning resource that illustrates how to return a generic collection to the client.

@Plan("plans") public PlanningResource { @Path("{id}") @GET @Produces(MediaType.APPLICATION_JSON) public Response getPlanList( @PathParam("id") String id ) { List<Plan> plans = findPlanCollectionById(id); Collections.sort( plans new AscendingDateOrderComparator() ); GenericEntity entity = new GenericEntity<List<Plan>>(plans); return Response.ok(entity).build(); } }

The PlanningResource class has a resource method getPlanList(), which retrieves a list of business plans from a persistence store in the application. It sorts these Plan objects into ascending order and then wraps the list collections of plans in a GenericEntity. The method returns a response with the generic entity.

After the resource method returns the entity, the JAX-RS runtime will then take care of the rest of the response processing. The runtime applies a converter, if it was registered, to map each Plan entity object into the required media type "application/json" and the assembled response is sent over the wire to the client.

Return types

Resource methods are allowed to return void, Response, GenericEntity, or another Java type. These return types are mapped to the response sent to the client.

  • A void results in an entity body with a (NO_CONTENT) 204 status code.
  • A Response results in entity body mapped from the entity property inside. If the entity property is null then this generates a (NO_CONTENT) 204 status code. If the status property of the Response is not set, the runtime generates a (OK) 200 status code for the non-null entity code.
  • A GenericEntity results in an entity body mapped from the Entity property. If the return value of the Entity property is not null then the runtime generates a 200 status code. A null value for the Entity properties causes the runtime to generate a 204 status code.
  • For all other Java types, the runtime generates a status code if it is possible to map the result to a known MessageBodyWriter or default converter. If the runtime identifies this result, which is not-null, it returns a 200 status code otherwise it will generate a 204 status code. For an object instance that is an anonymous inner class, the JAX-RS runtime will, instead, use the superclass.

It is the responsibility of the developer to supply additional converters beyond the JAX-RS standard. They may do so through the @Provider annotation in order to register custom filters and entity interceptors.

Converting Entities to JSON

Java EE 7 provides the Java API for JSON Processing (JSON-P) to define a standard library to parse, generate, and query JSON. Out of the box this library does not supply readymade providers to JAX-RS. In the reference implementation under GlassFish, there does appear to be two classes called JsonStructureBodyReader and JsonStructureBodyWriter, which act as JAX-RS providers. If you are stuck for choice, alternatively, you can use GSON, which is a JSON library that many developers have had some success with. You will need to write a custom ReadInterceptor and WriteInterceptor implementation in order to integrate it into your application.

Hypermedia linking

Hypermedia linking is the ability for REST services to explicitly reference other endpoints in order to allow a client to navigate information. This capability is actually a constraint of fully REST application architecture and the term for it is Hypermedia as the Engine of Application State (HATEOS). The design of HATEOS system implies that a REST client requires only basic knowledge to interact with an application. The best way to understand this is to think of hyperlinks in HTML. A web browser knows that an HTML anchor element is a navigation point to another HTTP resource. If a user clicks on an anchor, this is instruction to surf to the next web page. The engine of application state for a web browser is the uniform access rule to a spider web of Internet HTTP servers. No special protocols are required beyond the norm.

JAX-RS 2.0 supports Hypermedia by allowing a RESTful server endpoint to add special linkage information to the headers of a HTTP Response. The information in the HTTP header is separate to the actual content. So the response can be anything such as JSON or XML or byte stream and the developer can add linkage information to it.

The class javax.ws.rs.core.Response.ResponseBuilder has a couple of methods link() and links(). These methods create instances of javax.ws.rs.core.Link, which is the class that encapsulates hypermedia links. A link() accepts a URI that references the target resource and parameter. A parameter is a relative name for the navigation link called rel or it can be code.

Link relations are descriptive attributes that associated with hyperlink and define the semantic meaning of the relationship between the source and destination resources. Link relations are used in HTML5 as the common cascading style sheet. The following line of code shows the same:

<link href="stylesheets/bootstrap.css" rel="stylesheet" />

In REST and JAX-RS 2.0 the rel parameter is retained in a hypermedia link. The Link class adds a title, type, and optional of map of key-value parameters.

To understand better, let's adapt the book RESTful endpoint with hypermedia links. We will start with a refactored class as shown in the following code:

@Path("/hyperbooks") public class RestfulBookServiceWithHypermedia { private List<HyperBook> products = Arrays.asList( new HyperBook(101,"Sir Arthur Dolan Coyle", "Sherlock Holmes and the Hounds of the Baskervilles"), new HyperBook(102,"Dan Brown","Da Vinci Code"), new HyperBook(103,"Charles Dickens","Great Expectations"), new HyperBook(104,"Robert Louis Stevenson","Treasure Island")); private final JsonBuilderFactory factory; public RestfulBookServiceWithHypermedia() { factory = Json.createBuilderFactory(null); } @GET @Path("{id}") @Produces({"application/json"}) public Response getProduct(@PathParam("id")int id) { HyperBook product = null; for ( HyperBook book: products ) { if ( book.id == id ) { product = book; break; } } if ( product == null) throw new RuntimeException("book not found"); return Response.ok(product.asJsonObject()) .link("http://localhost:8080/order/"+ id+"/warehouse", "stock") .build(); } // ... }

In this endpoint RestfulBookServiceWithHypermedia, we changed the URI from /books to /hypermedia for the type in order to avoid a conflict between resources. This class creates JsonBuilderFactory that we use later. We have given all the hypermedia books a new Java type HyperBook and they have a unique ID.

The method getProduct() maps to HTTP GET request and accepts a REST path parameter ID, which references the bookID. The code attempts to look up the product by the ID. If the product does exists, we convert the Hyperbook instance to a JSON representation with call to asJsonObject(). We use the JSON-P API from Java EE 7.

If it is not found in the list, then a RuntimeException exception is thrown. The key to the method is link() call that accepts an URI for the link header and a value for the rel parameter. The method generates a response header that looks like the following code:

header[Link] = <http://localhost:8080/order/101/warehouse>; rel="stock" header[Date] = Sun, 18 Aug 2013 17:38:33 GMT header[Content-Length] = 105 header[Content-Type] = application/json

The link relation is a navigation to a warehouse note on a particular order that has a rel name stock and the URI http://localhost:8080/order/101/warehouse. It is also possible to generate a collection of link headers for a given response. In order to achieve this aim, we need to invoke indirectly Link.Builder class.

Let's add one method to retrieve all the hypermedia books in our endpoint, the following code will explain how to do just that:

@GET @Produces({"application/json"}) public Response getProductList() { JsonObjectBuilder builder = factory.createObjectBuilder(); JsonArrayBuilder arrayBuilder = factory.createArrayBuilder(); List<Link> links = new ArrayList<>(); for ( HyperBook book: products ) { arrayBuilder.add( book.asJsonObject() ); links.add( Link.fromPath("http://localhost:8080/order/" + book.id + "/warehouse") .rel("stock") .build()); } builder.add("products", arrayBuilder.build()); return Response.ok(builder.build()) .links( links.toArray( new Link[]{})) build(); }

The method getProducts() maps also HTTP GET request, but without any parameter and returns a JSON array of all products, the hypermedia books. In order to create a collection of link relations, we use ArrayList<Link>.

For each hypermedia product, we iterate over all of them, we need a link relation builder. The static call Link.fromPath() instantiates a Link.Builder instance from a String. From there, we set rel parameter name using the rel() method and then obtain a Link instance by calling build().

At the same time when we are creating link relations, we create a JsonArray object. We obtain the JSON representation of the Hyperbook instance and add it to the JsonArray. The final part of the puzzle is, while building the response, the conversion of the ArrayList<List> to the Link[] primitive array for the links(Links… ) call.

The output for the HTTP Response headers looks something like this:

header[Link] = <http://localhost:8080/ordering/104/shipment>; rel="ship", <http://localhost:8080/ordering/103/shipment>; rel="ship", <http://localhost:8080/ordering/102/shipment>; rel="ship", <http://localhost:8080/ordering/101/shipment>; rel="ship" header[Date] = Mon, 19 Aug 2013 08:26:01 GMT header[Content-Length] = 314 header[Content-Type] = application/json

As you can observe the Links HTTP response is actually comma-delimited. The client-side JAX-RS 2.0 delivers this view resembles the following code extract:

@Test public void shouldRetrieveHyperbooks() throws Exception { WebTarget target = ClientBuilder.newClient() .target( "http://localhost:8080/mywebapp/rest/hyperbooks"); Response response = target.request().get(); // ... Set<Link> links = response.getLinks(); assertFalse(links.isEmpty()); for (Link link: links) { System.out.printf("link relation uri=%s, rel=%s \n", link.getUri(), link.getRel()); } assertEquals(200, response.getStatus()); }

From the unit test method shouldRetrieveHyperbooks(), we are using the JAX-RS 2.0 client side API that we will discuss, very soon, in the section. The important point in the code is retrieval of Link in a Set collection from the response. The client side can conveniently parse that set of link relations in the instance, which is very useful. From there, we can get access to the URI, parameter rel name, the type, and other parameters.

The output should appear as the following:

link relation uri=http://localhost:8080/ordering/103/shipment, rel=ship link relation uri=http://localhost:8080/ordering/102/shipment, rel=ship

This covers building a response. Let's now move to the client side.

JAX-RS client API

JAX-RS 2.0 introduces the client framework for the first time, which also supports callbacks and asynchronous request and response. The really nice feature of this API, improves on the writing invocations of the JAX-RS servers by hand. As you saw in the section called Test-Driven Development with JAX-RS, writing URL code and the I/O in standard Java can be, how can I say, laborious?

Synchronous invocation

The client API lies in the javax.ws.js.client package, which contains useful classes such as AsyncInvoker, Client, ClientBuilder, Entity, SyncInvoker and WebTarget.

The following table outlines the responsibilities of these classes.

Class

Description

AsyncInvoker

This is a Java interface that defines a uniform contract interface for asynchronous invocation.

Client

This is a Java interface that represents the contract of all clients, which are the main entry points to the client side API. The client defines a builder pattern for flexibility.

ClientBuilder

This is the abstract class for the Client API, which the developer configures in order to connect the request URI on the server side. The developer can optionally configure a client with SSL, security key store, and a hostname verifier.

ClientRequestContext

An interface that defines the contract for context data for the purpose of processing the client request.

ClientRequestFilter

An interface that defines the contract for a custom request filter. Implementations of this interface must be annotated with @javax.ws.rs.ext.Provider.

ClientResponseContext

An interface that defines the contract for context data for the purpose of processing the client response.

ClientResponseFilter

An interface that defines the contract for a custom response filter. Implementations of this interface must be annotated with @javax.ws.rs.ext.Provider.

Entity

A final class that encapsulates the message entity including the associate variant.

FactoryFinder

A final class for the JAX-RS time to find the implementation of the client framework.

Invocation

An interface that defines the contract for a client request invocation.

InvocationCallback

An interface that defines the contract callback that the client code implements to respond to events from processing the response.

ResponseProcessingException

An exception thrown if the JAX-RS runtime finds there is a problem in processing the response from the resource, which could be in an error in deserialization or failure to filter the entity.

SyncInvoker

The uniform interface to synchronous invocation.

WebTarget

Represents the resource target URI on the server side.

It is very straight forward to connect to resource URI using the JAX-RS Client API. The first class to examine is the javax.ws.js.client.ClientBuilder, which has a static method called newBuilder(). This method returns a ClientBuilder that the developer can configure independently with javax.net.ssl.SSLContext and also supply java.security.KeyStore for encryption. The overloaded methods on the client builder keyStore() and SSLContext() provide the configuration.

If your application is not using security at the moment through SSL, then you can invoke the static method newClient() and obtain a javax.ws.js.client.Client instance. With this object, you can configure the target, the resource URI that will be called with the method target(), which returns a javax.ws.js.client.WebTargetinstance.

With WebTarget, you configure additional path, query parameters, and matrix parameters. Invoking the method request() on the web target returns a javax.ws.js.client.Invocation.Builder instance.

Finally, as the developer, you get to invoke the request to the server, the remote resource URI with the call to get(), put(), post(), or delete().

On the face of it, going through this chain of object classes, might appear to be confusing and complicated, but actually it is quite an elegant design and a clear definition of separation of concerns. By the way, the Invocation.Builder interface is an extension of the javax.ws.js.client.SyncInvoker interface.

Let us rewrite the first unit test client that we saw for the book list to use this new JAX-RS client side API. The following is the new class RestfulBookServiceClientTest in its entirety:

package je7hb.jaxrs.basic; /* imports ommitted */ import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; public class RestfulBookServiceClientTest { private static SimpleEmbeddedRunner runner; private static WebArchive webArchive; @BeforeClass public static void assembleDeployAndStartServer() throws Exception { /* See the book's source code .. */ } /* ... */ @Test public void shouldRetrieveBookList() { WebTarget target = ClientBuilder.newClient() .target("http://localhost:8080/mywebapp/rest/books"); Response response = target.request().get(); assertNotNull(response); String text = response.readEntity( String.class ); String arr[] = text.split("\n"); assertEquals("Sherlock Holmes and the Hounds of the Baskervilles",
arr[0] ); assertEquals("Da Vinci Code", arr[1] ); assertEquals("Great Expectations", arr[2]); assertEquals( "Treasure Island", arr[3] ); } }

In this integration test RestfulBookServiceClientTest, we make use of ShinkWrap in order to create a virtual WAR file. We then launch an embedded GlassFish instance and deploy the WAR file to it. The new code is the ClientBuilder invocation, which creates a Client instance and then the WebTarget instance. The unit test invokes the request URI on the server and it retrieves a javax.ws.js.coreResponse object.

All we need to do with the response is retrieve the content and we do that by reading the entity as a String. Behind the scenes the method readEntity() opens java.io.InputStream and performs more or less the same code in the older unit test, except since the JAX-RS 2.0 does this, means that our code is much cleaner.

With the content as a Java String, we just split it to an array by the delimited new line characters and run the assertions to complete the test.

What happens if there is an issue with the server? The target resource at the URI fails to generate an OK response, HTTP Response Code 200. If there is an error the JAX-RS runtime will do its best to map the error code to an exception under the package javax.ws.js.ext. This package defines exceptions that correspond to the HTTP response error codes and the classes are named like BadRequestException, ForbiddenException, InternalServerErrorException and ServiceUnavailableException to name a few.

Asynchronous invocation

The client JAX-RS also has a means for generating an asynchronous request. Now this is potentially useful for building a type of non-blocking request and response architecture. The design of the JAX-RS API, again, makes this avenue remarkably simple.

Asynchronous client request can rely on a java.util.concurrent.Future or an Invocation callback method that the developer provides. Let's look at the Future option first.

The following is a new unit test RestfulBookServiceAsyncClientTest:

public class RestfulBookServiceAsyncClientTest { /* ... as before ... */ @Test public void shouldRetrieveBookListAsynchronously() throws Exception { WebTarget target =ClientBuilder.newClient() .target( "http://localhost:8080/mywebapp/rest/books"); Future<Response> future =target.request().async().get(); Response response = future.get(3, TimeUnit.SECONDS ); String text = response.readEntity(String.class); String arr[] = text.split("\n"); assertEquals("Sherlock Holmes and the Hounds ofthe Baskervilles",
arr[0]); assertEquals("Da Vinci Code", arr[1]); assertEquals("Great Expectations", arr[2]); assertEquals( "Treasure Island", arr[3]); } }

The essential difference in the asynchronous version compared to the synchronous one is the addition of the async() method call after the request() method. This method call returns an instance of javax.ws.js.client.AsyncInvoker. The difference with this type is all of the overloaded method calls on it such as get(), put(), post(), and delete() return Future objects, which means the request to the remote server does not block the calling Java thread.

In order to retrieve the response from the server wrap in the Future object, we invoke the get() method and in the unit test example we supply a timeout value. Of course, this call will block the calling Java thread during that duration, and then there is the possibility of the value being ready or not. Still, the call duration is useful for situations where you require some execution time limit, and once the Future has been retrieved it becomes immutable, you cannot reuse it. Instead, you must make another invocation of the web service.

The JAX-RS Client API provides another way to find out the response of an asynchronous invocation. The programmer, in this case, creates and supplies a callback object of the type InvocationCallback<Response>.

The following is a further example in the asynchronous unit test class:

public class RestfulBookServiceAsyncClientTest { /* ... as before ... */ private static class MyCallback implements InvocationCallback<Response> { public CountDownLatch ready = new CountDownLatch(1); public volatile String text = ""; public volatile Throwable failure = null; @Override public void completed(Response response) { text = response.readEntity( String.class ); ready.countDown(); } @Override public void failed(Throwable throwable) { failure = throwable; ready.countDown(); } } @Test public void shouldRetrieveBookListAsyncWithCallback() { WebTarget target =ClientBuilder.newClient() .target("http://localhost:8080/mywebapp/rest/books"); MyCallback callback = new MyCallback(); Future<Response> future =target.request().async().get(callback); try { callback.ready.await(3, TimeUnit.SECONDS); if ( callback.failure != null ) callback.failure.printStackTrace(System.err); assertNull(callback.failure); String arr[] = callback.text.split("\n"); assertEquals("Sherlock Holmes and the Hounds of "+"the
Baskervilles", arr[0] ); assertEquals("Da Vinci Code", arr[1] ); assertEquals("Great Expectations", arr[2]); assertEquals( "Treasure Island", arr[3] ); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } }

The class MyCallback implements the javax.ws.js.client.InvocationCallback interface. We use a java.util.concurrency.CountDownLatch so that we can ensure that this class is actually invoked by the JAX-RS run time in either the success or failure capacity. JAX-RS invokes the completed() method if the data is fully available. On an error, JAX-RS invokes the failed() method. In either case, we count down the latch to zero and record the salient information for later. It is important to note, that the callback executes on a different thread to the unit test method, which is why we must be careful in our concurrency synchronization. It is so very easy to get multi-threading badly wrong in Java.

The method shouldRetrieveBookListAsyncWithCallback() is largely the same as before. Instead, we invoke the invocation builder with get() call and pass an instance of our callback MyCallback to it. Incidentally, this call returns a future object, however we are not using it in this unit test method.

We await the countdown latch to hit zero inside the unit test method. When it does, we know that the callback has been invoked. If the callback was invoked because of failure, we print the stack trace to the standard error channel. On normal execution in the unit test method thread, we can retrieve the text string and perform the assertions.

This example does illustrate that may be a developer should separate the business model logic of validating data from the infrastructure of JAX-RS request and response.

Java EE 7 Developer Handbook Develop professional applications in Java EE 7 with this essential reference guide with this book and ebook
Published: September 2013
eBook Price: $35.99
Book Price: $59.99
See more
Select your format and quantity:

Asynchronous JAX-RS server side endpoints

JAX-RS 2.0 permits asynchronous generation of the output response in a manner that is similar to the Servlet 3.0 standard, in particular javax.servlet.AsyncContext. In order to achieve this in a REST style resource, somehow the JAX-RS must be informed that the resource method can be executed in another thread internally to the provider. The client does not need to know the exact details of where the method is invoked under the hood.

In order to inform the JAX-RS runtime, that a resource method generates asynchronous output, supply the annotation @javax.ws.rs.container.Suspended and also a new argument @javax.ws.rs.container.AsyncResponse. Yes, there is another JAX-RS sub-package called javax.ws.rs.container with classes and interfaces specifically for server-side containers.

In order to set a JAX-RS to fully asynchronous, the user must annotate the method with @javax.ejb.Asynchronous. Therefore, the JAX-RS resource has to be defined as a session EJB in Java EE 7, it can be either a stateless bean or a singleton.

The following is an example of another book REST style resource, but delivered as an asynchronous EJB:

package je7hb.jaxrs.basic; import javax.ejb.*; import javax.ws.rs.*; import javax.ws.rs.container.*; import javax.ws.rs.core.*; import java.util.*; @Path(«/async/books») @Stateless public class RestfulBookAsyncService { private List<Book> products = Arrays.asList( new Book("Miguel De Cervantes", "Don Quixote"), new Book("Daniel Defoe", "Robinson Crusoe"), new Book("Jonathan Swift", "Gulliver's Travels"), new Book("Mary Shelley", "Frankenstein"), new Book("Charlotte Bronte", "Jane Eyre")); @GET @Asynchronous @Produces(MediaType.TEXT_PLAIN) public void getList( @Suspended AsyncResponse asyncResponse) { final long SLEEP=500; final int N=10; try { for (int j=0; j<N; ++j ) { System.out.print("."); System.out.flush(); Thread.sleep(SLEEP); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(".\n"); StringBuffer buf = new StringBuffer(); for (Book b: products) { buf.append(b.title); buf.append('\n'); } Response response = Response.ok(buf.toString()).build(); asyncResponse.resume(response); } static class Book { public final String author; public final String title; Book(String author, String title) { this.author = author; this.title = title; } } }

Inside the RestfulBookAsyncService class, the getList() resource method is triggered on a HTTP GET request on the URI. We contrived in this method to delay the generation of the output with a thread sleep call, so that it is easy to study the output. As soon as the JAX-RS implementation detects the @Suspended invocation; it will pause the output of the response to client on AsyncResponse. It is the combination of the EJB @Asynchronous and @Suspended AsyncResponse that causes the fire-and-forget behavior on the server side.

After the deliberate delay, the getList() method builds the generic response and then passes it to the AsyncResponse instance with a call to resume(). This call signals to the runtime that the asynchronous response will be resumed.

If the method is not annotated with @Asynchronous, then the JAX-RS runtime executes in a synchronous fashion, but the AsyncResponse will be still suspended.

The output from the unit test produces the following result:

RestfulBookAsyncService#acquireResource() RestfulBookAsyncService.getList() thread: [Thread[http- listener(1),5,main]] retrieve list asynchronously ........... sending data back now on thread: [Thread[http-listener(1),5,main]] **** response=org.glassfish.jersey.client.ScopedJaxrsResponse@3ae4568d **** text=Don Quixote Robinson Crusoe Gulliver's Travels Frankenstein Jane Eyre

The extract sample of the output shows the invocation of the REST endpoint in the class RestfulBookAsyncService. In the working code, which you find in the source code and the website, we added @PostConstruct and @PreDestroy annotation methods. We also make use of the JAX-RS Client asynchronous API to invoke the resource in a unit test.

Let's move on to the filtering and interception of the resource and how the JAX-RS can do more advanced processing for your enterprise applications.

Why must I turn to EJB for full asynchronous operations?

At first glance, it does appear strange that for full asynchronous operation, a resource must be annotated as a session EJB (@Stateless or @Singleton) and the resource method requires a @javax.ejb.Asynchronous. Luckily, for us developers, Java EE containers treat EJB in a much smarter way than they did J2EE. A session EJB is no longer a monolithic behemoth of burden that it was once, modern Java EE servers are perfectly capable of creating thousands of EJB instances on the fly. There is no longer a need to even pool EJB instances as we once did! I do think, personally, that the EJB and CDI expert group missed a trick by not having an annotation for CDI @javax.annotation.Asynchronous.

If you prefer not use to EJB then you may want to investigate the Concurrency API.

JAX-RS providers

The JAX-RS 2.0 specification now standardizes extensions to the runtime that allow developers to write portable authentication, encoding and decoding, and logging without the vendor lock-in of proprietary code. JAX-RS provides an interceptor framework to handle advanced situations. The specification describes two styles of intercepted JAX-RS communication, namely, filtering and entity interceptors.

Filters are strikingly similar in concept to Java Servlet filters, especially in the way they can modify or process the incoming REST request and the response. Filters predominantly take care of HTTP Header information and they execute before and after request and response resource processing.

On the other hand, Entity Interceptors are designed for the manipulation of the payload data. They can be written to encrypt and decrypt the message body of a JAX-RS REST message. (If you have an Enterprise Messaging background, then the penny has already started to drop.)

Filters

JAX-RS filters are available on the client and the container APIs, the packages javax.ws.js.client and javax.ws.js.container.

JAX-RS filters

On the client side, there are two types of filter, namely the Java interface ClientRequestFilter and ClientResponseFilter. For each direction, there is a corresponding context interface ClientRequestContext and ClientResponseContext.

On the server side, there are two types of filter, namely the Java interface ContainerRequestFilter and ContainerResponseFilter. For each direction, there is a corresponding context interface ContainerRequestContext and ContainerResponseContext.

Let us look at the server side filter as a start.

Server-side filters

JAX-RS executes the ContainerRequestFilter filter before invoking the wrapped target resource. JAX-RS executes ContainerResponseFilter after invoking the wrapped target resource.

The category of ContainerRequestFilter is divided into two more filter styles. A filter can be pre-matching or post-matching. The default is the post-matching. Pre-matching filters are designed to modify request attributes and header attributes before the JAX-RS runtime perform path pattern matching on the URI resource.

In order to designate a ContainerRequestFilter is a pre-matching filter, the class must be annotated with @javax.ws.js.container.PreMatching.

If we wanted to copy the HTTP Header parameter User Agent and shadow it for a processing pipeline, we could write a filter in the following way:

package je7hb.jaxrs.basic; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.ws.rs.ext.Provider; import java.io.IOException; @Provider @PreMatching public class AddExtraUserAgentFilter implements ContainerRequestFilter { @Override public void filter(ContainerRequestContext context) throws IOException { String userAgent = context.getHeaderString("User-Agent"); if ( userAgent != null ) { context.getHeaders().putSingle( "X-User-Agent-Copy", userAgent ); } } }

The filter AddExtraUserAgentFilter is annotated as @javax.ws.js.ext.Provider. The class implements ContainerRequestFilter and the method filter(). We look up the header parameter by name from the supplied context. Since this agent usually is supplied by the client, we can make a copy of the parameter into a new header key and value pair called X-User-Agent-Copy.

If we wanted to, the flexibility of the JAX-RS API, allows us to change the User-Agent string. Since this filter is annotated with @PreMatching then the runtime will invoke this filter before proceeding with the URI path pattern matching phase and before the target resource is invoked.

Suppose we wanted to have a filter that automatically added an expiration time to the HTTP Response header for any JAX-RS Resource. We could write a container response filter like the following code:

package je7hb.jaxrs.basic; import javax.ws.rs.container.*; import javax.ws.rs.ext.Provider; /* ... imports omitted */ @Provider public class AutoExpirationDateFilter implements ContainerResponseFilter{ private static SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z"); @Override public void filter(ContainerRequestContext reqCtx, ContainerResponseContext resCtx) throws IOException { if ( reqCtx.getMethod().equals("GET")) { Date oneHour = new Date(System.currentTimeMillis() + 60* 1000 ); resCtx.getHeaders().add("Expires", formatter.format( oneHour)); } } }

In the class AutoExpirationDateFilter which implements the contract from ContainerResponseFilter, the filter() method accepts two context parameters and it is extremely useful to have access to both the request and response context objects.

We only add the expiration response header field for HTTP GET request, so in the method we can check this situation. With the response context, we add the expiration header with a properly formatted date and timestamp.

Client-side filters

Writing JAX-RS filters for the client side is a one step filter, because there is no URI path pattern matching occurring. The developer has a choice of two filter types, namely, ClientRequestFilter and ClientResponseFilter. The JAX-RS filter will invoke ClientRequestFilter just before the HTTP request is sent to the remote URI resource. Similarly, after the remote URI resource processes the data and sends back a response, then the JAX-RS runtime invokes ClientResponseFilter instance.

We shall now inspect the code for a useful bit of kit in our toolkit. What happens if we have problem with some production code involving JAX-RS? Would it not be nice to debug to a standard console (and perhaps later to a logging facility) the requests going from the client to the remote URI resource and reading the server response? It would be nice to have a master client that we can travel around the business and validate the communication is functioning correctly between the client and server.

So the following is the basis of a debuggable logger for JAX-RS client, albeit incomplete:

package je7hb.jaxrs.basic; import javax.ws.rs.client.*; import javax.ws.rs.ext.Provider; /* ... imports omitted */ @Provider public class DebugClientLoggingFilter implements ClientRequestFilter, ClientResponseFilter { @Override public void filter(ClientRequestContext reqCtx) throws IOException { System.out.printf("**** DEBUG CLIENT REQUEST ****\n"); System.out.printf("uri: %s\n", reqCtx.getUri()); if ( reqCtx.getEntity() != null ) { System.out.printf("entity: %s\n", reqCtx.getEntity().getClass().getName() + "@" + Integer.toHexString(System.identityHashCode
( reqCtx.getEntity()))); } System.out.printf("method: %s\n", reqCtx.getMethod()); System.out.printf("mediaType: %s\n", reqCtx.getMediaType()); System.out.printf("date: %s\n", reqCtx.getDate()); System.out.printf("language: %s\n", reqCtx.getLanguage()); for (String name: reqCtx.getHeaders().keySet()) { System.out.printf("header[%s] => %s\n", name, reqCtx.getHeaderString(name) ); } for (String name: reqCtx.getCookies().keySet()) { System.out.printf("cookie[%s] => %s\n", name, reqCtx.getHeaderString(name) ); } System.out.printf("**** END CLIENT REQUEST ****\n\n"); } // ... incoming filter method }

This class DebugClientLoggingFilter implements both the client request and response filters. As you can see the two different context objects ClientRequestContext and ClientResponseContext provide a wealth of information.

From the client, we are able to find out the request URI, the entity, the method, media type, language, headers, and cookies. Similarly, from the server we can debug the status, status code, response length, the date, headers, and cookies.

Once the remote endpoint has serviced the request, we expect a response, which can also be filtered. The following is the other incoming implementation filter method:

@Override public void filter(ClientRequestContext reqCtx, ClientResponseContext resCtx) throws IOException { System.out.printf("**** DEBUG CLIENT RESPONSE ****\n"); System.out.printf("status: %s\n", resCtx.getStatus()); System.out.printf("status info: %s\n", resCtx.getStatusInfo()); System.out.printf("length: %s\n", resCtx.getLength()); System.out.printf("mediaType: %s\n", resCtx.getMediaType()); System.out.printf("date: %s\n", resCtx.getDate()); System.out.printf("language: %s\n", resCtx.getLanguage()); for (String name: resCtx.getHeaders().keySet()) { System.out.printf("header[%s] => %s\n",name, resCtx.getHeaderString
(name) ); } for (String name: resCtx.getCookies().keySet()) { System.out.printf("cookie[%s] => %s\n", name, resCtx.getHeaderString(name) ); } System.out.printf("**** END CLIENT RESPONSE ****\n\n"); }

We have access to the response header, content type, length, data, and also cookies. To find out more information, it is worth your while examining the API in detail for both ClientRequestContext and ClientResponseContext.

To configure the filter from the unit test, we set up the ClientBuilder in the following way:

@Test public void shouldRetrieveBookList() throws Exception { WebTarget target = ClientBuilder.newClient() .register(new DebugClientLoggingFilter()) .target("http://localhost:8080/mywebapp/rest/async/books"); Future<Response> future = target.request().async().get(); /* ... */ }

DebugClientLoggingFilter is registered on the builder object.

The following is a screenshot of the unit test in action:

If you are going to unit test the server response in an application, why would you not choose the JAX-RS client side library? It is a no brainer.

We shall move on to entity interceptors.

JAX-RS interceptors

Inceptors handle message bodies, the actual payload of the request and response to the remote JAX-RS resource. Entity interceptors are executed in the call stack frame as their corresponding reader or writer, which means there are involved in the same Java thread.

There are two types of interceptors, namely, javax.ws.rs.ext.ReaderInterceptor and javax.ws.rs.ext.WriterInterceptor. The reader interceptor is designed to wrap around the execution of the javax.ws.rs.ext.MessageBodyReader types. The writer interceptor is designed to wrap around the execution of javax.ws.rs.ext.MessageBodyWriter.

Why would developers want to create an interceptor? One circumstance may be to provide encryption and destruction around a particular resource type of data. Another idea would be generate secure digital signatures for any type of output.

Here is an example of both ReaderInterceptor and WriterInterceptor that performs AES encryption and decryption:

package je7hb.jaxrs.basic; import javax.crypto.*; import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.*; import java.io.*; @Provider public class AESCipherInterceptor implements ReaderInterceptor, WriterInterceptor{ private final AESCipher cipher; public AESCipherInterceptor() throws Exception { final byte[] salt ={ 1,2,4,8,16,32,64,-64,-32,-16,-8,-4,-2,-1}; final String password = «java1995»; cipher = new AESCipher(password, salt); } @Override public Object aroundReadFrom( ReaderInterceptorContext context ) throws IOException, WebApplicationException { InputStream old = context.getInputStream(); context.setInputStream( new CipherInputStream( old, cipher.getDecryptCipher())); try { return context.proceed(); } finally { context.setInputStream(old); } } @Override public void aroundWriteTo( WriterInterceptorContext context ) throws IOException, WebApplicationException { OutputStream old = context.getOutputStream(); context.setOutputStream( new CipherOutputStream( old, cipher.getEncryptCipher())); try { context.proceed(); context.getHeaders().add("X-Encryption", "AES"); } finally { context.setOutputStream(old); } } }

I should say immediately as a professional developer you never expose the security credentials to hacking in source code. The password and salt would be securely obtained by proper means through a secure channel.

In order to be truly secure in the communication, first, you could make the connection protocol SSL. Second, ensure the plain text of the password is never passed in the stream and share the password verbally, orally in a face-to-face meeting. Third, generate the salt using javax.security.SecureRandom. Share the salt in an out-of-band communication between the server and the client in an initial hand shaking mechanism.

The annotation @Provider is applied to the interceptor class AESCipherInterceptor and therefore JAX-RS server side runtime becomes aware of its existence.

The class AESCipherInterceptor uses a helper class AESCipher to delegate the business of configuration key generator, cipher streams and the business of configuring AES in secure Java. This leaves the two implementation methods aroundReadFrom() and aroundWriteTo() relatively free of clutter.

The style of programming for both of these methods follows that of Aspect Oriented Programming (AOP). We temporarily replace the input or output stream, before invoking the target in the context. After the invoked method returns we restore the previous stream. We must surround the invocation with a try-finally block to ensure the restoration always happens regardless of the normal or abnormal termination of the target method.

We add an additional header to the response output in the aroundWriteTo() method.

The following is the code for the delegate class, AESCipher:

package je7hb.jaxrs.basic; /* ... imports omitted */ public class AESCipher { private final KeyGenerator keyGen; private final Cipher encryptCipher, decryptChipher; public Cipher getEncryptCipher() { return encryptCipher;} public Cipher getDecryptCipher() { return decryptCipher;} public AESCipher( String passwordText, final byte[] salt ) throws Exception {keyGen = KeyGenerator.getInstance("AES"); final char[] password = passwordText.toCharArray(); SecretKeyFactory factory = SecretKeyFactory.getInstance( "PBKDF2WithHmacSHA1"); KeySpec spec = new PBEKeySpec( password, salt, 65536, 128); SecretKey tmp = factory.generateSecret(spec); SecretKey aesKey = new SecretKeySpec( tmp.getEncoded(), "AES"); encryptCipher = Cipher.getInstance( "AES/CBC/PKCS5Padding"); IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded()); encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey, ivParameterSpec); decryptCipher = Cipher.getInstance( "AES/CBC/PKCS5Padding"); decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec); } public byte[] encrypt( String plainText ) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream,encryptCipher); try { cipherOutputStream.write(plainText.getBytes()); cipherOutputStream.flush(); cipherOutputStream.close(); return outputStream.toByteArray(); } catch (Exception e) { e.printStackTrace(System.err); return null; } } public String decrypt( byte[] cipherText ) { ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayInputStream inputStream = new ByteArrayInputStream(cipherText); CipherInputStream cipherInputStream = null; try { cipherInputStream = new CipherInputStream(inputStream, decryptCipher); byte[] buf = new byte[1024]; int bytesRead; while ((bytesRead = cipherInputStream.read(buf)) >= 0) { output.write(buf, 0, bytesRead); } cipherInputStream.close(); return new String(output.toByteArray()); } catch (Exception e) { throw new RuntimeException(e); } } }

The AESCipher utilizes the Java Cryptography Extension (JCE) API in order to security encrypt and decode an array of bytes to and from a String. The details of these API calls are out-of-scope for this article. Oracle has a good site to find out more information http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136007.html. I recommend the following book Beginning Java Security by David Hook.

We shall move on to binding filter and interceptors and how a developer can control which JAX-RS resources are matched to these types.

Binding filter and interceptors

As it stands, the AESCipherInterceptor class from previous section has a global binding. This means it will be invoked for all JAX-RS Resources in the application! We most likely do not want to encryption and decryption for all of the REST style resources in our application.

A filter or entity interceptor can be associated with a resource class or method by declaring a new binding annotation in the spirit of the Context and Dependency Injection (CDI). Annotations for association are declared with the JAX-RS meta-annotation @javax.ws.js.NameBinding.

We can create a custom annotation for denoting resources that need secure encryption. The following code is a new annotation called @Encrypt:

@NameBinding @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(value = RetentionPolicy.RUNTIME) public @interface Encrypt { }

This is a runtime annotation and it can only be applied to class types or methods.

Now we can bind this annotation to the interceptor by applying to the class in the following way:

@Encrypt @Provider public class AESCipherInterceptor implements ReaderInterceptor, WriterInterceptor { /* ... as before as */ }

To complete the puzzle, we only need to apply the custom annotation to methods in a REST style resource that we want to protect. Following is a particular class, called SensitiveResource, which demonstrates the principle:

@Path("/docs") public class SensitiveResource { @Encrypt @GET @Path("{id}") @Produces("text/plain") public SensitiveDocument retrieve(@PathParam("id") String file ) { /*...*/ } @Encipher @POST @Path("{id}") @Consumes(MediaType.MULTIPART_FORM_DATA) public SensitiveDocument store(@PathParam("id") String file, @FormParam("file") InputStream inputStream ) { /*...*/ } }

The method retrieve() in this REST style endpoint is annotated with @Encrypt. The JAX-RS provider will work out that this particular HTTP GET request on this resource is bound to the AESCipherInterceptor. The write interceptor will be invoked after the resource generates the response, which causes the response to be encrypting before the JAX runtime sends the result back to the client.

The resource method store() is triggered on HTTP POST request and also annotated with the @Encrypt method. This informs the runtime to bind an instance of the AESCipherInterceptor to the resource method. The read interceptor will be invoked first to decrypt the input stream before invoking the resource method, which results in the HTML Form encoded to be decrypted. Note that we must also annotate the resource method with @Consume tag, which stipulates the single HTML form parameter is a MIME multipart form upload.

Dynamic binding

There is still one other way to configure binding to a resource. Whereas the @NameBinding annotation means the configuration is a static means for a dynamic or runtime application of behavior that we cannot use this feature. Luckily, JAX-RS 2.0 provides an additional interface javax.ws.js.container.DynamicInterface.

The dynamic interface is designed for the registration of post-matching providers during a JAX-RS application initialization at the time of deployment. There is one single interface to implement called configure() and it takes two arguments, namely javax.ws.js.container.ResourceInfo and javax.ws.js.core.FeatureContext.

Let us write a new configuration feature class AESCipherDynamicFeature, which supports dynamic binding. Following is the new code snippet:

@Provider public class AESCipherDynamicFeature implements DynamicFeature @Override public void configure(ResourceInfo resourceInfo,FeatureContext config ) { if ( SensitiveResource.class.isAssignableFrom(resourceInfo.
getResourceClass() &&resourceInfo.getResourceMethod() .isAnnotationPresent(GET.class)) { config.register( new AESCipherInterceptor() ); } } }

The class must be annotated with the @Provider in order to be successfully scanned by the JAX-RS runtime. Once the runtime discovers the new feature and it can see that the class is a type of DynamicFeature then the runtime invokes configure() method. We verify the resource that we want to protect is the target, and we also check the REST style resource method is the correct one to apply this interceptor. Is this resource method the HTTP GET request method? When these conditions are true, then we use the FeatureContext instance to configure and associate an instance of the interceptor with the resource.

Summary

The REST style API is improved in Version 2.0 for Java EE 7. In this article, we covered the essentials of Representational State Transfer, the architectural style of the application.

We saw how to write REST style endpoints for collections of entities and how that progresses to single entities. REST is about the design of URI patterns and templates. We learnt how to configure the servlet mapping for JAX-RS applications.

We built a sample JAX resource endpoint with the HTTP request protocols GET, PUT, POST, and DELETE. We applied the corresponding annotations: @GET, @PUT, @POST, and @DELETE. We mapped URL fragments to JAX-RS server side resources and subresources with the @Path annotation. We configure dynamic behavior through path variable and we are able to extract values from the URI template; and now we can also extract data using the various annotations, such as @QueryParam, and @FormParam.

JAX-RS sub-resources can be configured by location or directly in the same resource. We saw that architecting resources into sub-resources is preferred as best practice, because it separates concerns and leads to better modularity in the code base for the long term; therefore reducing the technical debt and high maintenance.

We explored the new Client API in JAX-RS 2.0 and witnessed how it can help unit test to RESTful endpoints. We understood how to write asynchronous input and output application to leverage another JAX-RS 2.0 feature.

JAX-RS resources have the option to generate custom response using the ResponseBuilder and Response classes. We revealed that JAX-RS Provider instances are the key to extending the runtime and the door to writing custom functionality through server or client side filter, or the entity interceptors.

Resources for Article :


Further resources on this subject:


About the Author :


Peter A. Pilgrim

Peter A. Pilgrim is the 91st Oracle Java Champion, an independent contractor, a professional software developer and designer. Peter is an honors degree graduate of London South Bank University in 1990. He had already secured a Master's degree course for September 1991, but then instead elected to live and work in Germany for a few years in order to beat off the then, economic recession. He spent productive years at a joint-venture company developing spectroscopic scientific software in Fortran 77, C, Solaris, and X Windows.

After four years abroad Peter returned to London and continued his career in the industry with more C, C++, and UNIX development. He then leapt at a chance to get into investment banking with Deutsche Bank in 1998. It was at Deutsche Bank a week after joining them that Peter discovered Java was the next best thing since sliced bread, when a colleague dropped out of a programming Java training course.

As the substitute person, Peter realized this peculiar Java language and platform was the future and the answer. Peter applied his studies to his day job and learnt Java applets, then Java Swing and switched over to the server side with Java Servlets with web applications involving the Struts framework.

In 2004, Peter created the JAVAWUG user group in London for the burgeoning development community who were interested in web development on the Java EE. What started as the Struts Networking Users Group in London quickly expanded to lot of other areas. The JAVAWUG ran for six years until 2010. He built a reputation for travelling to Java technology conferences in the US and Europe and being heavily involved in the wider community. He spoke at several developer conferences including QCon London, ACCU, Devoxx, Devoxx UK, and JavaOne. In 2007, Peter was elected to the Sun Microsystems' Java Champions program. Today, Peter A. Pilgrim is a well-known specialist in Java Enterprise Edition (Java EE) technology, focused on the server-side and the implementation of electronic commerce. Peter has built professional Java EE applications for Blue-chip companies and top-tier investment and retail banks including Lloyds Banking Group, Barclays, UBS, Credit Suisse, Royal Bank of Scotland, and LBi. He is also a fan of Agile practices and Test Driven Development. Peter, currently, lives in South London with his long-term partner Terry, who is a Scottish Diva, business communication coach, and a singer—her voice is phenomenal.

Peter writes a blog at http://www.xenonique.co.uk/blog/ and is on Twitter as peter_pilgrim.

Books From Packt


Java EE 6 Cookbook for Securing, Tuning, and Extending Enterprise Applications
Java EE 6 Cookbook for Securing, Tuning, and Extending Enterprise Applications

Java EE 5 Development with NetBeans 6
Java EE 5 Development with NetBeans 6

Java EE Development with Eclipse
Java EE Development with Eclipse

 Java EE 6 with GlassFish 3 Application Server
Java EE 6 with GlassFish 3 Application Server

Java EE 5 Development using GlassFish Application Server
Java EE 5 Development using GlassFish Application Server

Java EE 6 Development with NetBeans 7
Java EE 6 Development with NetBeans 7

Java 7 JAX-WS Web Services
Java 7 JAX-WS Web Services

Java 7 Concurrency Cookbook
Java 7 Concurrency Cookbook


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
1
i
U
Y
F
g
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software