Jose Sandoval Google
 Resume     Book     Software     Drawings     Home     Subscribe to RSS feed Search Web Search josesandoval.com

REST in Java (Restlet demo)
Monday, September 29, 2008

Abstract: in this entry I talk about a REST example in Java using the Restlet framework. You can download the running application together with the source code.

I was looking for REST implementations for Java web servers and found a couple of descent APIs. The one I found the easiest to work with (for what I need) is the Restlet framework. It's very light, well documented, and it's open sourced.

The Restlet framework can be used in two modes: first, as a standalone web service (not discussed here, but very cool); second, as a Servlet extension (discussed here, and also very cool).

The framework's documentation has a couple of introductory examples, but the first one is too simple and the second one introduces an XML structure that confused me (yes, I'm easily confused). Therefore, I wrote this entry and its accompanying demo for my sake and anyone else looking into the Restlet framework.

My intention here is to create a simple REST application that is more realistic than the intro apps (I mean, how many "Hello, World!" programs can you write?). I have to warn you, however, that I will not discuss the benefits of using REST as a web service architecture; I will not fully discuss what REST is--I'm assuming you already know; and, finally, I will not explain how to use the full Restlet API--I only talk about the Servlet extension mode.

The application
As with any software application, we need to have requirements. In this case I define the following:
  1. We have 2 types of resources, HTML and PDF, that we need to access via a web server (this word resource will become clear as we go along).
  2. We want to access these resources using REST. For example, all HTML resources are to be accessed via the user friendly link of

    .../html/RESOURCE_ID

    Similarly, all PDF resources are to be accessed with

    .../pdf/RESOURCE_ID.
You may be wondering why I need to access these resources this way and not directly with a regular web address. The answer to this question falls under the why of REST and I said I wasn't going to fully discuss it. I should, at least, give you a small taste of the REST philosophy and only say that these resources don't necessarily exist as physical objects in specific locations. A resource can be built from many parts of a system at run time: a database or multiple web services, for instance.

Whenever I talk about REST I give the example of a news story. Think for a moment of a CNN news story: a story is not just an HTML file together with a few images; a CNN resource contains images, text, movies, polls, and related content that are being gathered from many different sources. When you request

cnn.com/news/2010-10-10/Obama/

you don't just want a web page, you want a complete resource.

So, what's the different between accessing a resource with this URI

cnn.com/news/2010-10-10/Obama/

and this URI

cnn.com/news/getStory.jsp?date=2010-10-10&topic=Obama

To the end user, there is no difference: as a reader you see the same story, and it obviously works, as we've been accessing data the web this way for more than a decade now. (Note that a reader could be another machine accessing this resource to do something with it, e.g., store it in a cache server.) To the software developer, however, the differences are many and come back to the essence software engineering. On the one hand, with the latter, you give away implementation details (in this case I made it a Java server app). On the other hand, if your implementation changes, any bookmarks or cache systems are immediately broken--say we go from JSP to ASP: our link now looks like

cnn.com/news/getStory.asp?date=2010-10-10&topic=Obama

Imagine, one letter change making such a big difference and breaking so many things.

Does REST care about implementation details? For a system designed with a REST architecture in mind the implementation details don't matter. REST serves resources and a request to

cnn.com/news/2010-10-10/Obama/

will always be a valid resource (given that it's coded correctly, of course). The implementation is hidden and it will always work no matter if the response is implemented in Java, C, C++, or pigeon carriers. A resource is a resource is a resource (assume Gertrude Stein cared about REST).

The software implementation
To make this application work in any Java web server with the Restlet framework, we need 6 things, which I break into steps below: (1) the HTML and PDF objects; (2) the Application, which is a derived Restlet class; (3) an HTML Resource, which is also a derived Restlet class; (4) a PDF Resource, which is the same as (3), except that it's specific to a PDF resource; (5) the web.xml modification needed to connect the framework to the Servlet engine; and (6), the required libraries that you will need to make everything work.

Step 1 - The HTML and PDF resources
For this demo, I have 1 HTML file and 1 PDF file. I separated this step here because these items don't have to be physical things on a server: they could be generated somehow. The somehow is up to the architecture of the system. Therefore, you must decide first how the resources need to be generated. For simplicity, I decided to make these resources actual files in the OS.

Step 2 - Restlets
The guts of a REST layer using Restlet is the derived Application class. I mean that you need to extend org.restlet.Application and override the Application.createRoot() method.

createRoot() creates a Router object with the context of the application (the context here is the object that points to the running web application). You can look up at the API for the full details of what a Router is. For this example, however, think of the Router object as the entrance to our resource serving layer.

Note the 3 lines of code:

Router router = new Router(getContext());
router.attach("/pdf/{itemName}", PDFResource.class);
router.attach("/html/{itemName}", HTMLResource.class);


We have 2 resource types: HTML and PDF.

We're telling the REST layer to access these items via the URI of .../pdf or .../html. {itemName} is a directive telling the code that it will be an id of some kind and it's assumed the resource class knows what to do with it: created it, read it, modified it, or deleted it.

The full implementation of my class looks like:
package com.josesandoval.rest;

import org.restlet.Application;
import org.restlet.Context;
import org.restlet.Restlet;
import org.restlet.Router;

public class RestServiceApplication extends Application {

public RestServiceApplication(Context parentContext) {
super(parentContext);
}

@Override
public synchronized Restlet createRoot() {
Router router = new Router(getContext());
router.attach("/pdf/{itemName}", PDFResource.class);
router.attach("/html/{itemName}", HTMLResource.class);

return router;
}
}


Steps 3 and 4 - HTML and PDF Resources
The HTMLResource and PDFResource classes are where things happen.

A full REST implementation is one that lets resources to be accessed, created, modified, and deleted. In my case, to simplify things, I only need the access part; hence, my resources are not fully RESTful, as I only override one method of the Restlet framework: getRepresentation().

My HTMLResource class looks like:
package com.josesandoval.rest;

import org.restlet.Context;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.FileRepresentation;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.Variant;

public class HTMLResource extends Resource {
private String itemName;

public HTMLResource(Context context, Request request,
Response response) {
super(context, request, response);

itemName = (String) getRequest().
getAttributes().get("itemName");
getVariants().add(new Variant(MediaType.TEXT_HTML));
}

@Override
public Representation getRepresentation(Variant variant) {
if (MediaType.TEXT_HTML.equals(variant.getMediaType())) {
return new FileRepresentation(
"/assets/html/" + itemName + ".html",
MediaType.TEXT_HTML, 3600);
}

return null;
}
}


Note that I'm getting the resources directly from the OS. The files live under the /assets/ directory. The PDFResource class looks exactly the same, except where the string 'HTML' is you find 'PDF' instead; and, of course, the MediaType.TEXT_HTML changes to MEDIA_TYPE.APPLICATION_PDF.

Step 5 - web.xml
With everything coded, I need a way to tell my web server to interact with the REST layer. The Restlet framework includes a Servlet hook up that you need to configure before deploying your app.

This hookup is a simple edit to your web.xml file. For my example, the file looks like:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<!-- This is my Restlet application. -->
<context-param>
<param-name>org.restlet.application</param-name>
<param-value>com.josesandoval.rest.
RestServiceApplication</param-value>
</context-param>

<!-- This should always be here for Restlet stuff. -->
<servlet>
<servlet-name>RestletServlet</servlet-name>
<servlet-class>com.noelios.restlet.ext.servlet.
ServerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
</web-app>


Nothing surprising here. What's more, you can probably use this same web.xml file for your own applications, but you need to change the context-param element to look for your own Application class.

Step 6 - The required libraries
As you've seen, it's a very light layer because everything has been abstracted out and all the heavy lifting is already done for you. Therefore, your code needs the following 3 jar files:

org.restlet.jar
com.noelios.restlet.jar
com.noelios.restlet.ext.servlet_2.4.jar
(this is 2.5 for Restlet 1.1)

The Running app
There is more about the Restlet framework that I haven't covered; however, this example should give you a real taste of what it's like to implement a RESTful web service. This example can be extended to do real things. For example, your resources don't have to come from the OS in the form of a file. You could talk to other services to get these resources.

I hope you download the war file and play with the source code; you will have to change your file locations, but everything works right off the box.

And these are the RESTful calls of this demo:

http://www.sandoval.ca:8080/RestService2/html/jose

http://www.sandoval.ca:8080/RestService2/pdf/jose

A big disclaimer applies here: this example doesn't have any validation or error code handling. A real application has to have validation and error checking.


10:03 PM | 2 comment(s) |

Comments:

Good, clear application. i have a problem .. can you please help me..

i am actually planning send information from a JSP to a resource. in the web.xml as we are asking to invoke ServerServlet for every action (/*), even when the welcome page or any web page created request it is going to the RESTlet resource and trying to locate a mapping for this HTML which is not defined there..
How i can invoke the HTML or JSP page directly which will request a resource to invoke GET or POST for me..?
By Blogger Narayana, at 2:05 AM


I don't think I fully understand what you are trying to do, but you may need to deploy 2 applications: one with RESTlet and one the other content.


This page is powered by Blogger. Isn't yours?

Guestbook
© Jose Sandoval 2004-2009 jose@josesandoval.com