First application

Introduction

This first application illustrates how to develop a Restlet application that combines several editions of the Restlet Framework : GAE, GWT, Android and Java SE. It explains the benefits of annotated Restlet interfaces and of the ConverterService that offers transparent serialization between Restlet representations and Java objects, usable between a server application and several kind of clients.

Table of contents

  1. Requirements
  2. Scenario
  3. Archive content
  4. Common classes
  5. GAE server part
  6. GWT client
  7. Android client
  8. Java SE client

Requirements

It is based on the following editions of the Restlet Framework : Google App Engine (GAE), Google Web Toolkit (GWT) and Android. It has been tested with the following environments:

  • Restlet Framework 2.0 (latest snapshot from 04/23/2010)
  • Google App Engine (GAE) 1.2.1 to 1.3.0
  • Google Web Toolkit (GWT) 1.7 to 2.1 (probably previous versions as well)
  • Android 1.6 to 2.1 (probably previous versions as well)

Each edition of the Restlet Framework you use must be downloaded as a separate Zip or Windows installer file from this page.

Scenario

The server application is hosted on the Google App Engine (GAE) platform. For the sake of simplicity it serves only one resource named "contact", with the following characteristics:

  • its relative URI is "/contacts/123"
  • it supports the GET, PUT and DELETE methods.
  • it represents a simple "contact" object.

The "contact" object has the following attributes:

  • firstname
  • lastname
  • age
  • home address (actually an instance of a "Address" class): line1, line2, zipcode, city and country

 This resource will be requested fro several kind of clients:

  • GWT client page
  • Android application
  • Java SE client

Archive content

The full source code is available here: serializationFullSource. (application/force-download, 10.0 MB, info)

It contains the full source code of three Eclipse projects with:

  1. Project that contains both the GAE server and the GWT client code
  2. Project that contains the source code of the Android client
  3. Project that contains the source code of the Java SE client

Common classes

The following classes are available on the three project. They are used by the server and the clients in order to produce the serialized representation of the Contact object and to deserialize incoming representations.

  • Contact
  • Address
  • ContactResource.

ContactResource is an interface annotated with Restlet annotations:

public interface ContactResource {
    @Get
    public Contact retrieve();

    @Put
    public void store(Contact contact);

    @Delete
    public void remove();
}

It represents the contract passed between the client and the server.

GAE server part

We propose to host the server application on the GAE platform. The server project relies on the following JAR files:

  • org.restlet.jar: core archive (GAE edition)
  • org.restlet.ext.gwt.jar: GWT server-side extension to convert Java objects to a GWT-specific serialization format (GAE edition)
  • org.restlet.ext.servlet: Servlet extension to deploy the Restlet application in GAE (GAE edition)
  • org.restlet.ext.jackson: Jackson extension used to generate JSON representations of the contact resource (GAE edition)

The server-side resource implements the annotated interface.

/**
 * The server side implementation of the Restlet resource.
 */
public class ContactServerResource extends ServerResource implements ContactResource {

   private static volatile Contact contact = 
        new Contact("Scott", "Tiger", new Address("10 bd Google", null, "20010", "Mountain View", 
                    "USA"), 40);

    @Delete
    public void remove() {
        contact = null;
    }

    @Get
    public Contact retrieve() {
        return contact;
    }

    @Post
    public void store(Contact contact) {
        ContactServerResource.contact = contact;
    }
}

This resource is then exposed by the server application:

    @Override
    public Restlet createInboundRoot() {
        Router router = new Router(getContext());
        getConnectorService().getClientProtocols().add(Protocol.FILE);

        // Serve the files generated by the GWT compilation step.
        Directory dir = new Directory(getContext(), LocalReference.createFileReference(new File("war/")));
        router.attachDefault(dir);
        router.attach("/contacts/123", ContactServerResource.class);

        return router;
    }

GWT client part

The GWT client relies only on the core Restlet JAR (org.restlet.jar) provided in the GWT edition.

In order to get the Contact object, a proxy class is required. This is an interface that inherits on a specific interface (delivered by the GWT edition of the Restlet Framework):

public interface ContactResourceProxy extends ClientProxy {
    @Get
    public void retrieve(Result<Contact> callback);

   @Put
    public void store(Contact contact, Result<Void> callback);

    @Delete
    public void remove(Result<Void> callback);
}

This interface looks like the ContactResource interface, expect that it adds a callback to each declared methods, due to the asynchronous nature of the GWT platform and the underlying AJAX mechanism offered by web browsers.

The type of the callback is not limited to the Result interface of the Restlet Framework, it can also be the usual AsyncCallback interface provided by GWT. Thus it allows you to easily migrate an existing GWT-RPC code base to GWT-REST with Restlet.

Then, the following code allows you to request and handle the Contact resource:

ContactResourceProxy contactResource = GWT.create(ContactResourceProxy.class);

// Set up the contact resource
contactResource.getClientResource().setReference("/contacts/123");
contactResource.getClientResource().getClientInfo().getAcceptedMediaTypes().add(new
Preference<MediaType>(MediaType.APPLICATION_JAVA_OBJECT_GWT));

// Retrieve the contact
contactResource.retrieve(new Result<Contact>() {
    public void onFailure(Throwable caught) {
        // Handle the error
    }

    public void onSuccess(Contact contact) {
        // Handle the contact, for example by updating the GWT interface
        // Contact fields
        cTbFirstName.setText(contact.getFirstName());
        cTbLastName.setText(contact.getLastName());
        cTbAge.setText(Integer.toString(contact.getAge()));
    }
});

Here is a screenshot of the GWT client page once the user has clicked on the GET button.

serialization-gwt-screenshot
Click to enlarge

In order to update the contact, simply complete your contact object and invoke the "store" method as specified by the proxy interface:

contactResource.store(contact, new Result<Void>() {
    public void onFailure(Throwable caught) {
        // Handle the error
    }

    public void onSuccess(Void v) {
        // Display a dialog box
        dialogBox.setText("Update contact");
        textToServerLabel.setText("Contact successfully updated");
        dialogBox.center();
        closeButton.setFocus(true);
    }
});

Android client part

The Android client project relies only on the core Restlet JAR (org.restlet.jar) provided by the Android edition of the Restlet Framework.

The contact object will be serialized between the GAE server and the Android client (in both directions) using the standard Java serialization process. No additional interface is required except the ContactResource interface furnished by the server.

// Initialize the resource proxy.
ClientResource cr = new ClientResource("http://restlet-example-serialization.appspot.com/contacts/123");
ContactResource resource = cr.wrap(ContactResource.class);

// Get the remote contact
Contact contact = resource.retrieve();

In order to update the client, simply use this instruction:

resource.store(contact);

Here is a screenshot of the Android user interface.

serialization-android-screenshot

Java SE client

Get the full Contact object

The same code used on the Android application allows you to get the full Contact object:

ClientResource cr = new ClientResource("http://restlet-example-serialization.appspot.com/contacts/123");
// Get the Contact object
ContactResource resource = cr.wrap(ContactResource.class);
Contact contact = resource.retrieve();

if (contact != null) {
    System.out.println("firstname: " + contact.getFirstName());
    System.out.println(" lastname: " + contact.getLastName());
    System.out.println("     nage: " + contact.getAge());
}

  This code produces the following ouput on the console:

firstname: Scott
 lastname: Tiger
      age: 40

Get a JSON representation

In case the Contact class is not available, you can still retrieve a JSON representation by setting the client preferences when retrieving the resource's representation:

cr.get(MediaType.APPLICATION_JSON).write(System.out);

which produces the following output:

{"age":40,"firstName":"Scott","homeAddress":{"country":"USA","city":"Mountain View","line1":"10 bd Google","line2":null,"zipCode":"20010"},
"lastName":"Tiger"}
Comments (5)