Accessing External REST Services with Resin
Resin 3.1

Documentation
Examples
Changes

Quercus
Database
Amber
EJB
SOA/ESB
IoC
JMS
Servlet
JMX
Hessian
Security

Simple Service
Configuring a service with JAXB
An ESB client
Flickr REST
JAX-WS example
An ESB client
SOA/ESB
JAX-WS example

Resin offers simplified access to external REST-based services. This example shows how to access a subset of the flickrTM API.

Demo

Resin's Service-Oriented Architecture (SOA) allows not only easier deployment of web services via SOAP, REST, and Hessian, but also simplified client access to external services. Traditionally, using REST services as a client required developers to write potentially complex libraries. URL construction and parsing returned XML data can often be clumsy and time-consuming to do manually.

Resin's SOA and JAXB simplify these tasks. This tutorial shows an example for a subset of the flickrTM API.

Files in this tutorial

WEB-INF/classes/example/FlickrAPI.javaInterface for the hello service.
WEB-INF/classes/example/FlickrImpl.javaThe main service implementation.
WEB-INF/classes/example/data/FlickrResponse.javaThe response object that wraps specialized responses.
WEB-INF/classes/example/data/FlickrPayload.javaThe payload of a response.
WEB-INF/classes/example/data/FlickrError.javaAn error payload.
WEB-INF/classes/example/data/FlickrGroups.javaA payload of group information.
WEB-INF/classes/example/data/FlickrPerson.javaA payload of profile information.
WEB-INF/classes/example/data/FlickrPhotos.javaA payload of photo information.
WEB-INF/classes/example/data/FlickrUser.javaA payload of user information.
WEB-INF/classes/example/data/jaxb.indexLists the classes to be used by JAXB
WEB-INF/resin-web.xmlConfigures the environment
demo.jspClient JSP

Writing a REST Client

Many companies now offer web services externally to be used as components in third-party applications. These services often have REST, SOAP, and/or XML-RPC interfaces. SOAP and XML-RPC are standards and have somewhat well-defined access methods for clients. REST on the other hand is about being able to use the properties of HTTP to design a custom interface. Thus clients are often difficult to write because each service requires specialization. Unlike the case of SOAP where WSDLs allow automated construction of client stubs, REST-based services essentially defy standardization. While Resin's SOA does not offer automated client construction, it does make the task easier.

The example in this tutorial shows how to access a subset of the flickrTM image sharing service API. This API is well-designed and consistent which allows very clean client construction.

REST Client Architecture

The REST client architecture in Resin can be thought of as a stack. At the top of the stack is the client, which calls methods on a proxy. That proxy then constructs the calls to the external REST service. Complex objects that are sent to the service use JAXB to marshal from Java objects to XML. The request is then processed by the service and a response is sent. The response is unmarshalled from XML to Java using JAXB and returned to the client by the proxy.

REST Bindings

A REST interface can be thought of as a binding between an HTTP request and a method invocation. All the portions of the HTTP request (the path information, the query, headers, and POSTed data) can be used to construct the method call.

In the case of the flickrTM API, the method binding is straightforward and uses the query data almost exclusively. For example, there is a method, flickr.people.findByUsername, that takes two arguments, an api_key and a username. The api_key allows flickrTM to track and manage usage while the username is used to find a user's id. The method name and these two arguments are used to construct a URL to perform the REST operation: http://api.flickr.com/services/rest/?method=flickr.people.findByUsername&api_key=XXX&username=foo.

The data returned by the service uses a simple XML format. In this case, the service might return the following:

<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
  <user nsid="12345678901@N01">
    <username>foo</username> 
  </user>
</rsp>

The next section shows how to construct a Java client interface to construct these URLs and decode the responses.

Annotated Client Interface

An annotated Java class or interface is used to access a REST service as a client. In this example, only JAX-WS annotations are used, so those developers already familiar with JAX-WS can leverage their experience to construct certain types of REST interfaces.

FlickrAPI.java
package example;

import javax.jws.*;
import example.data.*;

public interface FlickrAPI
{
  @WebMethod(operationName="flickr.people.findByEmail")
  public FlickrResponse
  findByEmail(@WebParam(name="api_key") String api_key,
              @WebParam(name="find_email") String find_email);

  @WebMethod(operationName="flickr.people.findByUsername")
  public FlickrResponse
  findByUsername(@WebParam(name="api_key") String api_key,
                 @WebParam(name="username") String username);

  @WebMethod(operationName="flickr.people.getInfo")
  public FlickrResponse
  getInfo(@WebParam(name="api_key") String api_key,
          @WebParam(name="user_id") String user_id);

  @WebMethod(operationName="flickr.people.getPublicGroups")
  public FlickrResponse
  getPublicGroups(@WebParam(name="api_key") String api_key,
                  @WebParam(name="user_id") String user_id);

  @WebMethod(operationName="flickr.people.getPublicPhotos")
  public FlickrResponse
  getPublicPhotos(@WebParam(name="api_key") String api_key,
                  @WebParam(name="user_id") String user_id,
                  @WebParam(name="extras") String extras,
                  @WebParam(name="per_page") int per_page,
                  @WebParam(name="page") int page);
}

In this interface, there are five methods, each annotated with @WebMethod. The operationName field is overloaded here to give the REST method name. The method parameters are all annotated with @WebParam. The name field gives a key name for the argument. Resin uses this interface to construct URLs sent to a service. By default, the method name is sent in the query using "method" as the key. This is customizable using the annotations @RestMethod and @RestService, but for this example, no customization is needed.

When a client calls one of the methods in the interface above, Resin automatically constructs a URL, makes the request, and decodes the response. Notice that the return value of all the methods above is FlickrResponse. This class is a JAXB-annotated class that wraps all the responses sent from the service. The next section shows how to construct the JAXB-annotated classes for easy access to response data.

JAXB-Annotated Response Classes

Even though flickrTM uses a custom XML format for responses, it is easy to construct simple JAXB-annotated classes for these responses, even without schema! First notice that the responses all have a wrapper element, <rsp>. This wrapper is represented by a FlickrResponse object in this example.

FlickrResponse.java
package example.data;

import javax.xml.bind.annotation.*;

@XmlRootElement(name="rsp")
public class FlickrResponse {
  @XmlAttribute public String stat = "ok";
  @XmlAnyElement(lax=true) public FlickrPayload payload;

  public String toString()
  {
    return "FlickrResponse[stat=" + stat + ", payload=" + payload + "]";
  }
}

Notice the @XmlRootElement annotation on the class. This annotation sets the the element name to rsp. Next, there is a status field which is an attribute in the element. JAXB simply uses the field name in this case to set the attribute when the @XmlAttribute annotation is present. Finally, the payload is annotated with @XmlAnyElement. This annotation is necessary since FlickrPayload is an interface. @XmlAnyElement allows the marshalling of an interface or abstract class. The lax property allows JAXB to use known classes to unmarshal an interface or class. How to let JAXB know about such class is covered at the next section.

FlickrPayload is an empty interface, used only for typing in this example. FlickrUser implements FlickrPayload and is the response payload used by the flickr.people.findByEmail and flickr.people.findByUsername methods. The XML response from the section "REST Bindings" above corresponds to this class.

FlickrUser.java
package example.data;

import javax.xml.bind.annotation.*;

@XmlRootElement(name="user")
public class FlickrUser implements FlickrPayload {
  @XmlAttribute public String nsid;
  @XmlElement public String username;

  public String toString()
  {
    return "FlickrUser[nsid=" + nsid + ", username=" + username + "]";
  }
}

The FlickrUser class is somewhat simpler than the FlickrResponse example above in that it only has a root element, <user>, a single attribute, nsid, and a single child element, <username>. The attribute and child element here are both simply strings. FlickrPhotos is a more complex class with a variable number of child elements.

FlickrPhotos.java
package example.data;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement(name="photos")
public class FlickrPhotos implements FlickrPayload {
  @XmlAttribute public int page;
  @XmlAttribute public int pages;
  @XmlAttribute public int perpage;
  @XmlAttribute public int total;

  @XmlElement(name="photo") public List<Photo> photos = new ArrayList<Photo>();

  public static class Photo {
    @XmlAttribute public String id;
    @XmlAttribute public String owner;
    @XmlAttribute public String secret;
    @XmlAttribute public int server;
    @XmlAttribute public String title;
    @XmlAttribute public int ispublic;
    @XmlAttribute public int isfriend;
    @XmlAttribute public int isfamily;

    public String toString()
    {
      return "Photo[id=" + id + ", " +
                   "owner=" + owner + ", " +
                   "secret=" + secret + ", " +
                   "server=" + server + ", " +
                   "title=" + title + ", " +
                   "ispublic=" + ispublic + ", " +
                   "isfriend =" + isfriend + ", " +
                   "isfamily=" + isfamily + "]";
    }
  }

  public String toString()
  {
    StringBuilder sb = new StringBuilder();
    sb.append("FlickrPhotos[page=" + page + ", ");
    sb.append(             "pages=" + pages + ", ");
    sb.append(             "perpage=" + perpage + ", ");
    sb.append(             "total=" + total + ", ");
    sb.append(             "photos=(");

    for (Photo photo : photos) {
      sb.append(photo.toString());
      sb.append(' ');
    }

    sb.append(")]");

    return sb.toString();
  }
}

Here there are four attributes of the root element and a list of child elements representing the photos. Each photo has a set of attributes as well. By default, JAXB serializes lists as unadorned sequences of elements. For example, a FlickrPhotos object with two photos might have the following XML:

<rsp stat="ok">
  <photos total="2" perpage="10" pages="1" page="1">
    <photo isfamily="0" isfriend="0" ispublic="1" title="Our wedding"
           server="2" secret="x123456" owner="12345678901@N01" id="3041"/>

    <photo isfamily="0" isfriend="1" ispublic="0" title="Best friends"
           server="1" secret="y123456" owner="12345678901@N01" id="3042"/>
  </photos>
</rsp>

The remaining payload classes, FlickrError, FlickrGroups, and FlickrPerson, are annotated similarly.

Client configuration

A REST client is configured using the <web-service-client> tag, just like with SOAP and Hessian clients. The only difference is that the URL must use the "rest:" prefix. The Resin SOA connects to the service using the given URL and places a proxy instance into JNDI. Any clients may access the service then by doing a JNDI lookup, then calling methods on the returned object.

resin-web.xml
<web-service-client jndi-name="rest/flickr">
  <url>rest:${webApp.url}/flickr/rest/</url>
  <interface>example.FlickrAPI</interface>
  <jaxb-package>example.data</jaxb-package>
</web-service-client>

Notice the <jaxb-package> tag. In order for JAXB to marshal and unmarshal objects, it must know all the classes it might encounter. There are two ways to inform JAXB about the classes: either by a list of package names or an explicit list of classes. In this example, all of the classes that JAXB will use are in the package example.data, so the <jaxb-package> tag is the easiest way. The <jaxb-package> tag may be used multiple times to add classes from several packages. (It is also possible to use multiple <jaxb-class> tags to list the classes explicitly.)

Simply listing a <jaxb-package> may not be appropriate in all cases. In fact in this example, notice that FlickrPayload is simply an empty interface and is not JAXB-annotated. Thus JAXB should load only those classes in the example.data package that are annotated. The JAXB standard specifies that a file named "jaxb.index" will be read by JAXB whenever a package is given. This file should be placed in the package directory. The list of classes should be relative to the package, without a .java or .class suffix, and should be separated by newlines. For this example, the jaxb.index is the following:

jaxb.index
FlickrError
FlickrGroups
FlickrPerson
FlickrPhotos
FlickrResponse
FlickrUser

Testing the interface

An example implementation of the service is provided here for testing purposes only. It returns sample data upon receiving REST requests and does not actually store or display images. Because setting up a REST service is covered in another tutorial, only the client side of the REST connection is explained fully here.

The demonstration JSP simply looks up the proxy interface in JNDI, then calls the methods with sample queries. The calls and their results are printed.

flickr is a trademark of Yahoo! Inc.

Demo


An ESB client
SOA/ESB
JAX-WS example
Copyright © 1998-2006 Caucho Technology, Inc. All rights reserved.
Resin ® is a registered trademark, and Quercustm, Ambertm, and Hessiantm are trademarks of Caucho Technology.