<document>
<localtoc/> <s1>

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.

</s1> <deftable>
Interface for the hello service.
The main service implementation.
The response object that wraps specialized responses.
The payload of a response.
An error payload.
A payload of group information.
A payload of profile information.
A payload of photo information.
A payload of user information.
Lists the classes to be used by JAXB
Configures the environment
Client JSP
</deftable>

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.

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.

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: <url>http://api.flickr.com/services/rest/?method=flickr.people.findByUsername&api_key=XXX&username=foo</url>.

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

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

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

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.

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.

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.

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.

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.

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.

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.

<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:

FlickrError FlickrGroups FlickrPerson FlickrPhotos FlickrResponse FlickrUser

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.

</document>