Restlet Quickstart

The Restlet framework is one of the possible options to provide Restful web services in Java. In many framework comparison, Restlet is criticized for being a little bit difficult to understand as well as to perform slightly worse than competing frameworks (e.g. Apache Wink, Jersey, …) (Sangeetha, 2011). However, Restlet is also a very flexible framework and it is very lightweight, in that it has very few dependencies to heavyweight components, for instance servlet containers. This enables Restlet to play nicely with a number of technologies including Google Android, Google App Engine and Google Web Toolkit applications.

The tutorials on the Restlet homepage appear to be a bit confusing and outdated. Therefore, I have assembled a little example to get started with Restlet in a few traceable steps.

Add Maven Dependency

Restlet offers a wealth of different editions and optional extensions and it is a little bit difficult to determine the right Maven dependencies. For this basic scenario, we want to run a little server deployed as local Java application. For this purpose, the ext.simple extension is required (here I use the latest milestone release 2.1-M7 – the examples should also work with later releases although this is not guaranteed)


<dependency>

<groupId>org.restlet.jse</groupId>

<artifactId>org.restlet</artifactId>

<exclusions>

<exclusion>

<groupId>org.osgi</groupId>

<artifactId>org.osgi.core</artifactId>

</exclusion>

</exclusions>

<version>2.1-M7</version>

</dependency>

<dependency>

<groupId>org.restlet.jse</groupId>

<artifactId>org.restlet.ext.simple</artifactId>

<version>2.1-M7</version>

</dependency>

In addition, the Restlet repository must be specified


<repositories>
<repository>
<id>maven-restlet</id>
<name>Public online Restlet repository</name>
<url>http://maven.restlet.org</url>
</repository>
</repositories>

<span style="color: black;">

Create a Small Standalone Server

If these dependencies are established, the following server can be implemented:


import org.restlet.Component;
import org.restlet.data.Protocol;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
import org.restlet.routing.Router;

public class RestletServerTest extends ServerResource {

public static void main(final String[] args) throws Exception {
// Create a new Component.
final Component component = new Component();

// Add a new HTTP server listening on port 8182.
component.getServers().add(Protocol.HTTP, 8182);

final Router router = new Router(component.getContext().createChildContext());

router.attach("/test", RestletServerTest.class);

// Attach the sample application.
component.getDefaultHost().attach("/restlet", router);

// Start the component.
component.start();
}

@Override
@Get
public String toString() {
return "hello, world";
}

}

Execute this application and open http://localhost:8182/restlet/test. You should see the message ‘hello, world’.

Provide a Domain Object

In order to provide a domain object, a few more steps need to be undertaken. First, we need to specify the domain object:


import java.io.Serializable;

public class Person implements Serializable {

private static final long serialVersionUID = 1L;

public String name;
public int age;

public Person(final String name, final int age) {
super();
this.name = name;
this.age = age;
}

}

Secondly, we need an interface and a ServerResource implementation for the service, which provides the domain object. The interface does not need to extend any other interface but must use the GET, PUT, DELETE annotations provided by Restlet.


import org.restlet.resource.Get;

public interface PersonResource  {

@Get
public Person retrieve();

}
<pre>

The ServerResource implementation must extend ServerResource and implement the interface PersonResource:


import org.restlet.resource.ServerResource;

public class PersonServerResource extends ServerResource implements PersonResource {

private static volatile Person person1 = new Person("Peter", 40);

@Override
public Person retrieve() {

return person1;
}

}
<pre>

Finally, the main routine starting the server needs to be altered. Also, a little client is added, which reads out the domain object from the server:


import org.restlet.Component;
import org.restlet.data.Protocol;
import org.restlet.resource.ClientResource;
import org.restlet.routing.Router;

public class RestletServerTest  {

public static void main(final String[] args) throws Exception {
// Create a new Component.
final Component component = new Component();

// Add a new HTTP server listening on port 8182.
component.getServers().add(Protocol.HTTP, 8182);

final Router router = new Router(component.getContext().createChildContext());

router.attach("/person", PersonServerResource.class);

// Attach the sample application.
component.getDefaultHost().attach("/restlet", router);

// Start the component.
final Thread t = new Thread() {

@Override
public void run() {
try {
component.start();
} catch (final Exception e) {
e.printStackTrace();
}
super.run();
}

};

t.run();

final ClientResource cr = new ClientResource("http://localhost:8182/restlet/person");

final PersonResource resource = cr.wrap(PersonResource.class);
final Person person = resource.retrieve();

System.out.println(person.name);

}

}
<pre>

The domain object is serialized using the Java Serialization mechanism. We can also navigate to http://localhost:8182/restlet/person using a web browser. However, only a binary file will be downloaded by the server. Restlet does provide extensions to provide the domain objects serialized as in RDF, XML and JSON format.

Emulate a RPC Call Using Domain Objects

Apart from reading domain (and writing using PUT) domain objects, Restlet can easily be used to implement a kind of remote procedure calls (RPC) or functionality similar to Java Remote Method Invocation (RMI). Such calls being made over Restlet do not only have the advantage of running cleanly over HTTP but are also rather performant when compared to remote invocations building on XML serializations (Java Serialization, although slow, is often faster than XML Serialization) such as used by XML-RPC or SOAP/WDSL based web services.

First we change the PersonResource Service description and define a POST service, which makes a copy of a person object.

import org.restlet.resource.Post;

public
interface PersonResource {

@Post
public Person copy(Person p);

    

}

Next we change the implementation of the service:

import org.restlet.resource.ServerResource;

public
class PersonServerResource extends ServerResource implements PersonResource {

    

    @Override

    public Person copy(final Person p) {

        return p;

    }

    

}

And finally change the main method. Note here too that here we run the server and client as part of a unit test (so add JUnit dependency to your pom). This highlights how easy it is to build (almost) fully blown integration tests based on Restlet, which in addition execute very fast.


import org.junit.Assert;
import org.junit.Test;
import org.restlet.Component;
import org.restlet.data.Protocol;
import org.restlet.resource.ClientResource;
import org.restlet.routing.Router;

public class RestletServerTest  {

@Test
public void test_server() throws Exception {
// Create a new Component.
final Component component = new Component();

// Add a new HTTP server listening on port 8182.
component.getServers().add(Protocol.HTTP, 8182);

final Router router = new Router(component.getContext().createChildContext());

router.attach("/person", PersonServerResource.class);

// Attach the sample application.
component.getDefaultHost().attach("/restlet", router);

// Start the component.
final Thread t = new Thread() {

@Override
public void run() {
try {
component.start();
} catch (final Exception e) {
e.printStackTrace();
}
super.run();
}

};

t.run();

final ClientResource cr = new ClientResource("http://localhost:8182/restlet/person");

final PersonResource resource = cr.wrap(PersonResource.class);
final Person originalPerson = new Person("Peter", 20);
final Person copiedPerson = resource.copy(originalPerson);

Assert.assertFalse(originalPerson == copiedPerson);

Assert.assertTrue(originalPerson.name.equals(copiedPerson.name));

System.out.println(copiedPerson.name);

}

}
<pre>

Resources

Restlet Documentation Hello World Application in JavaSE

22 thoughts on “Restlet Quickstart

  1. Thanks for writing this cool tutorial! I’ve listed it on our community tutotials web page:
    http://wiki.restlet.org/community/167-restlet.html

    Note that for simple tests, you can directly attach a ServerResource to a Server instance, without using a full Component. Of course you don’t get any special features such as virtual hosts and services.

    Finally, we are always looking for talented authors to improve our user guide.

    Best regards,
    Jerome

    1. Hi Jerome,

      thanks for your comment and for the Restlet framework 🙂 It’s a pleasure to test complex services without the need to start up some Java EE behemoth.

      Kind regards,

      Max

  2. It’s a shame no-one can provide anything other than a static one-object return which is little better than Hello World. Besides the fact that the examples on the Restlet website don’t compile out-of-the-box and there is no decent explanation of what is required on the classpath. I can see how useful this thing would be – problem is it’s been designed by a geek who thinks everyone is up to his level of understanding! Poor documentation and poor examples – either Hello World or so complex that a beginner can’t understand.

    This is 2011, not 1991. Considering how long this project has been around I find it astounding that the extent examples in blogs are so poor and just seem to copy off each other.

    Why don’t you provide an example with an ArrayList of objects to GET from with a selector? So far in 2 days trawling the internet I haven’t found a single example that has anything more than one static object being returned.

    Now a full example with a proper datastructure – THAT would be useful.

    1. Hi David,

      thanks for your comment. I do agree with you that the documentation for Restlet is very confusing in places! I tried to provide another possible starting point for engaging with the framework.

      Although the post only shows a few features, I wanted to highlight the flexibility of the framework. To address your concerns, the Person class defined above might be simple in the give example but you can replace it with any complex class of your choice. The only constraint is that the types of all attributes of the class (and the attributes’ attributes in turn, etc.) must implement java.io.Serializable. However, if you use the XStream provider you might be able to circumvent this restriction.

      I have used Restlet successfully to sent object trees with literally hundreds of objects. However, don’t try to use ArrayList in the signature of your services. In my case, that led to unfriendly unsupported media type exceptions 🙂 . However, if you wrap the ArrayList in a plain serializable class all should be fine (you could, for instance, in the example above, add an ArrayList attribute to the Person class).

      Max

  3. David Fielding,

    If they provide a full working example of a canonical webapp like the Seam petstore with step by step tutorial, then who’s going to buy the Restlet in Action book?

    On the other hand, if you can’t figure out the API from basic examples provided, then you’re probably not cut out to be a developer, and just stick to pottery making.

  4. First iwould like to thank you for this amazing example but i would like to ask about the extention of the file in result what is the part of code responsible of it or how can i change the result to HTML for example?
    thank you in advance.

    1. Thanks 🙂 !

      The article describes a bare bones example using only Javas built-in synchronization. You can use the various Restlet extensions to render objects into different representations eg XStream (http://wiki.restlet.org/docs_2.0/13-restlet/28-restlet/264-restlet.html). I think you just add the extension to your project and the resource should be rendered as XML (but not too sure)

      However, if you want to output HTML it might be the build your own resource: router.attach(“/test”, [your custom resource].class). Overwrite ServeResource to build your own resource: http://www.restlet.org/documentation/2.0/jse/api/org/restlet/resource/ServerResource.html. Overwrite get() to output your custom HTML.

  5. Hi Max,
    How will a client running on one JVM get the person object from a restlet webservice that is running on a different JVM?
    To start – Person class would have to be defined on both the tiers.
    An example would be wonderful.

    Thanks,
    Pankaj

    1. Hi Pankaj,
      that’s a good question! I think it is to some degree answered within the post but not very clearly.

      Check the code right at the end of the post. You can split this code into two parts and run one part in one JVM (or Java program) and the other part in another JVM. In particular, the following code could run on the client JVM:

      final ClientResource cr = new ClientResource(“http://localhost:8182/restlet/person”);
      final PersonResource resource = cr.wrap(PersonResource.class);
      final Person originalPerson = new Person(“Peter”, 20);
      final Person copiedPerson = resource.copy(originalPerson);

      whereas everything before could run on a server JVM. You are right, the Person and PersonResource classes would have to be available on both client and server. Hope this helps!

  6. Hi Max, Thank you very much for providing this tutorial!
    but I have a problem, when I run the class and lauch the browser with http://localhost:8182/restlet/test, nothing happen i dont’ know why, I tried also with the first example of the book reslet in action (Client and server) and i have this error [A recoverable error was detected (1000), attempting again in 2000 ms.] how can i resolve this

  7. many thanks for this tutorial . but, I have an error when I run this program
    org.restlet.service.ConverterService toRepresentation
    WARNING: Unable to find a converter for this object : com.third.example.restlet.Person@4e4574df

    cloud you plz help me in solving this problem?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s