O'Reilly logo

Java Web Services: Up and Running by Martin Kalin

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

The Restlet Framework

Several web frameworks have embraced REST, perhaps none more decisively than Rails with its ActiveResource type, which implements a resource in the RESTful sense. Rails also emphasizes a RESTful style in routing, with CRUD request operations specified as standard HTTP verbs. Grails is a Rails knockoff implemented in Groovy, which in turn is a Ruby knockoff with access to the standard Java packages. Apache Sling is a Java-based web framework with a RESTful orientation.

The restlet framework adheres to the REST architectural style and draws inspiration from other lightweight but powerful frameworks such as NetKernel and Rails. As the name indicates, a restlet is a RESTful alternative to the traditional Java servlet. The restlet framework has a client and a service API. The framework is well designed, relatively straightforward, professionally implemented, and well documented. It plays well with existing technologies. For example, a restlet can be deployed in a servlet container such as Tomcat or Jetty. The restlet distribution includes integration support for the Spring framework and also comes with the Simple HTTP engine, which can be embedded in Java applications. The sample restlet in this section is published with the Simple HTTP engine.

The FibRestlet application reprises the Fibonacci example yet again. The service, published with the Simple HTTP engine, illustrates key constructs in a restlet. Here is the source code:

package ch04.restlet;

import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
import org.restlet.Component;
import org.restlet.Restlet;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Parameter;
import org.restlet.data.Protocol;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.data.Status;

public class FibRestlet {
    private Map<Integer, Integer> cache = 
       Collections.synchronizedMap(new HashMap<Integer, Integer>());
    private final String xml_start = "<fib:response xmlns:fib = 'urn:fib'>";
    private final String xml_stop = "</fib:response>";

    public static void main(String[ ] args) {
        new FibRestlet().publish_service();
    }

    private void publish_service() {
        try {
            // Create a component to deploy as a service.
            Component component = new Component();

            // Add an HTTP server to connect clients to the component.
            // In this case, the Simple HTTP engine is the server.
            component.getServers().add(Protocol.HTTP, 7777);

            // Attach a handler to handle client requests. (Note the
            // similarity of the handle method to an HttpServlet
            // method such as doGet or doPost.)
            Restlet handler = new Restlet(component.getContext()) {
                @Override
                public void handle(Request req, Response res) {
                    Method http_verb = req.getMethod();

                    if (http_verb.equals(Method.GET)) {
                        String xml = to_xml();
                        res.setStatus(Status.SUCCESS_OK);
                        res.setEntity(xml, MediaType.APPLICATION_XML);
                    }
                    else if (http_verb.equals(Method.POST)) {
                        // The HTTP form contains key/value pairs.
                        Form form = req.getEntityAsForm();
                        String nums = form.getFirstValue("nums");
                        if (nums != null) {
                            // nums should be a list in the form: "[1, 2, 3]"
                            nums = nums.replace('[', '\0');
                            nums = nums.replace(']', '\0');
                            String[ ] parts = nums.split(",");
                            List<Integer> list = new ArrayList<Integer>();
                            for (String next : parts) {
                                int n = Integer.parseInt(next.trim());
                                cache.put(n, countRabbits(n));
                                list.add(cache.get(n));
                            }
                            String xml =
                              xml_start + "POSTed: " + list.toString() + xml_stop;
                            res.setStatus(Status.SUCCESS_OK);
                            res.setEntity(xml, MediaType.APPLICATION_XML);
                        }
                    }
                    else if (http_verb.equals(Method.DELETE)) {
                        cache.clear(); // remove the resource
                        String xml =
                            xml_start + "Resource deleted" + xml_stop;
                        res.setStatus(Status.SUCCESS_OK);
                        res.setEntity(xml, MediaType.APPLICATION_XML);
                    }
                    else // only GET, POST, and DELETE supported
                        res.setStatus(Status.SERVER_ERROR_NOT_IMPLEMENTED);
                }};

            // Publish the component as a service and start the service.
            System.out.println("FibRestlet at: http://localhost:7777/fib");
            component.getDefaultHost().attach("/fib", handler);
            component.start();
        }
        catch (Exception e) { System.err.println(e); }
    }

    private String to_xml() {
        Collection<Integer> list = cache.values();
        return xml_start + "GET: " + list.toString() + xml_stop;
    }

    private int countRabbits(int n) {
        n = Math.abs(n); // eliminate possibility of a negative argument

        // Easy cases.
        if (n < 2) return n;

        // Return cached values if present.
        if (cache.containsKey(n)) return cache.get(n);
        if (cache.containsKey(n - 1) &&
            cache.containsKey(n - 2)) {
           cache.put(n, cache.get(n - 1) + cache.get(n - 2));
           return cache.get(n);
        }

        // Otherwise, compute from scratch, cache, and return.
        int fib = 1, prev = 0;
        for (int i = 2; i <= n; i++) {
            int temp = fib;
            fib += prev;
            prev = temp;
        }
        cache.put(n, fib);
        return fib;
    }
}    

As the source code shows, the restlet framework provides easy-to-use Java wrappers such as Method, Request, Response, Form, Status, and MediaType for HTTP and MIME constructs. The framework supports virtual hosts for commercial-grade applications.

The restlet download includes a subdirectory RESTLET_HOME/lib that houses the various JAR files for the restlet framework itself and for interoperability with Tomcat, Jetty, Spring, Simple, and so forth. For the sample restlet service in this section, the JAR files com.noelios.restlet.jar, org.restlet.jar, and org.simpleframework.jar must be on the classpath.

A restlet client could be written using a standard class such as HttpURLConnection, of course. The following client illustrates the restlet API on the client side, an API that could be used independently of the service API:

import org.restlet.Client;
import org.restlet.data.Form;
import org.restlet.data.Method;
import org.restlet.data.Protocol;
import org.restlet.data.Request;
import org.restlet.data.Response;
import java.util.List;
import java.util.ArrayList;
import java.io.IOException;

class RestletClient {
    public static void main(String[ ] args) {
        new RestletClient().send_requests();
    }

    private void send_requests() {
        try {
            // Setup the request.
            Request request = new Request();
            request.setResourceRef("http://localhost:7777/fib");

            // To begin, a POST to create some service data.
            List<Integer> nums = new ArrayList<Integer>();
            for (int i = 0; i < 12; i++) nums.add(i);
            
            Form http_form = new Form();
            http_form.add("nums", nums.toString());
            request.setMethod(Method.POST);
            request.setEntity(http_form.getWebRepresentation());

            // Generate a client and make the call.
            Client client = new Client(Protocol.HTTP);

            // POST request
            Response response = get_response(client, request);
            dump(response);

            // GET request to confirm POST
            request.setMethod(Method.GET);
            request.setEntity(null);
            response = get_response(client, request);
            dump(response);

            // DELETE request
            request.setMethod(Method.DELETE);
            request.setEntity(null);
            response = get_response(client, request);
            dump(response);

            // GET request to confirm DELETE
            request.setMethod(Method.GET);
            request.setEntity(null);
            response = get_response(client, request);
            dump(response);
        }
        catch(Exception e) { System.err.println(e); }
    }

    private Response get_response(Client client, Request request) {
        return client.handle(request);
    }

    private void dump(Response response) {
        try {
            if (response.getStatus().isSuccess())
                response.getEntity().write(System.out);
            else
                System.err.println(response.getStatus().getDescription());
        }
        catch(IOException e) { System.err.println(e); }
    }
}    

The client API is remarkably clean. In this example, the client issues POST and DELETE requests with GET requests to confirm that the create and delete operations against the service were successful.

The restlet framework is a quick study. Its chief appeal is its RESTful orientation, which results in a lightweight but powerful software environment for developing and consuming RESTful services. The chief issue is whether the restlet framework can gain the market and mind share to become the standard environment for RESTful services in Java. The Jersey framework has the JSR seal of approval, which gives this framework a clear advantage.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required