Restlet Development: Spring Integration

I’ve recently been working on a project that, like most, has several parts: a web site, a mobile app, a desktop app, and tying it all together, a server. Not being one to buck current trends, I’m building the server with a RESTful interface. Like all good programmers, I’m lazy and wanted to let existing libraries do the heavy lifting. I was looking for something Java-based that was simple to use, flexible, and scalable. I ended up using the Restlet library.

The greatest downside I’ve encountered is a lack of thorough documentation, especially with some of the extensions. There is documentation on the main Restlet site, as well as a few tutorials. But none of them seemed to adequately cover a couple of my requirements – Spring integration and using Amazon Web Services style security. The Restlet library provides support for both of these, but again, the docs aren’t particularly good. So as I work through some of these difficulties I thought it would be useful to others to document what I find in a series of posts. I’m making a few assumptions as well – mainly that you have some familiarity with RESTful architectures and Spring. Note that I’m NOT a Restlet expert! I’m just documenting my experiences. If you see anything wrong PLEASE let me know! That said, in this post I’ll start with demonstrating some Restlet basics and the Spring integration.

The sample code is available at GitHub.

This demo doesn’t really “do” anything very interesting. Here I’m mainly interested in the structure of the application, not the functionality. RESTful services are centered around resources, and this server manages a single type of resource, User.
There are several operations supported via RESTful URLs:

  • GET http://localhost:3000/users
Get the list of all users
Returns a JSON array of user objects
  • POST http://localhost:3000/users
Create a user.
Data is submitted in a form with the parameters “name”, “age”, and “favoriteFood”
Returns a JSON object of the new user, including the newly assigned ID
  • GET http://locahost:3000/users/{id}
Get the user with unique ID of {id}
Returns a JSON object of the user
  • PUT http://locahost:3000/users/{id}
Update the user with unique ID of {id} with values from the submitted form
Data is submitted in a form with the parameters “name”, “age”, and “favoriteFood”
No returned data
  • DELETE http://locahost:3000/users/{id}
Delete the user with unique ID of {id}

There isn’t really any error handling in this demo. In a real application you would likely return various HTTP return codes appropriate to the action. That’s fodder for a future installment.

In a Restlet app, you have one or more resource handlers that extend the org.restlet.resource.ServerResource class. There are a couple of approaches available for implementing these handlers. You can override some of the methods (e.g. get(), post()) from ServerResource. But newer (2.x and up) verions of Restlet define annotations that you use to indicate which of your methods implement which handlers, and optionally defining the the data representations expected and returned. The demo will use the annotation style.

Now for some actual code. We’ll start at the bottom with the User class, which is the resource we’re managing. No surprises here – it’s just a POJO:
package com.eddiesheffield.restlet.server.data;

public class User {
	private String name;
	private int age;
	private String favoriteFood;
	private int id;

	public User(int id, String name, int age, String favoriteFood) {
		this.id = id;
		this.name = name;
		this.age = age;
		this.favoriteFood = favoriteFood;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getFavoriteFood() {
		return favoriteFood;
	}

	public void setFavoriteFood(String favoriteFood) {
		this.favoriteFood = favoriteFood;
	}
}

The data storage for the User resource is provided by the UserRepository. In the demo this is simply a wrapper around a Map<Integer, User> mapping the unique user IDs to User instances and provides no long-term storage. In a real app, this would likely be talking to a database.
package com.eddiesheffield.restlet.server.data;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class UserRepository {
	private Map users;
	private int maxId = 0;

	public UserRepository() {
		this.users = new HashMap();
	}

	public User addUser(String name, int age, String favoriteFood) {
		maxId++;
		User user = new User(maxId, name, age, favoriteFood);
		users.put(user.getId(), user);

		return user;
	}

	public Collection getUsers() {
		return users.values();
	}

	public User getUser(int id) {
		return users.get(id);
	}

	public void deleteUser(int id) {
		users.remove(id);
	}

	public void saveUser(User user) {
		users.put(user.getId(), user);
	}
}
For handling the various requests, there are a couple of ServerResource implementations. UsersResource handles operations related to the collection of all User objects as a whole. UserResource handles operations on a single User object.
package com.eddiesheffield.restlet.server.resources;

import java.util.Collection;

import org.json.JSONArray;
import org.json.JSONObject;
import org.restlet.data.Form;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.restlet.resource.ServerResource;

import com.eddiesheffield.restlet.server.data.User;
import com.eddiesheffield.restlet.server.data.UserRepository;

public class UsersResource extends ServerResource {
	private UserRepository userRepository;

	public UsersResource(UserRepository userRepository) {
		this.userRepository = userRepository;
	}

	@Get
	public Representation getUsers() {
		Collection users = userRepository.getUsers();
		JSONArray ja = new JSONArray();
		for(User user : users) {
			JSONObject json = new JSONObject(user);
			ja.put(json);
		}
		return new JsonRepresentation(ja);
	}

	@Post("form")
	public Representation addUser(Form form) {
		String name = form.getFirstValue("name");
		Integer age = Integer.parseInt(form.getFirstValue("age"));
		String favoriteFood = form.getFirstValue("favoriteFood");

		User user = userRepository.addUser(name, age, favoriteFood);

		return new JsonRepresentation(user);
	}
}

package com.eddiesheffield.restlet.server.resources;

import org.json.JSONObject;
import org.restlet.data.Form;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.Delete;
import org.restlet.resource.Get;
import org.restlet.resource.Put;
import org.restlet.resource.ServerResource;

import com.eddiesheffield.restlet.server.data.User;
import com.eddiesheffield.restlet.server.data.UserRepository;

public class UserResource extends ServerResource {
	private UserRepository userRepository;

	public UserResource(UserRepository userRepository) {
		this.userRepository = userRepository;
	}

	@Get
	public Representation getUser() {
		Integer userId = Integer.valueOf((String)getRequestAttributes().get("userId"));
		User user = userRepository.getUser(userId);

		JSONObject json = new JSONObject(user);
		JsonRepresentation rep = new JsonRepresentation(json);
		return rep;
	}

	@Put("form")
	public void updateUser(Form form) {
		Integer userId = Integer.valueOf((String)getRequestAttributes().get("userId"));
		User user = userRepository.getUser(userId);

		String name = form.getFirstValue("name");
		Integer age = Integer.parseInt(form.getFirstValue("age"));
		String favoriteFood = form.getFirstValue("favoriteFood");

		user.setName(name);
		user.setAge(age);
		user.setFavoriteFood(favoriteFood);

		userRepository.saveUser(user);
	}

	@Delete
	public void deleteUser() {
		Integer userId = Integer.valueOf((String)getRequestAttributes().get("userId"));
		userRepository.deleteUser(userId);
	}
}
Tying it all together is the main Server class which loads the Spring configuration files, finds the top-level component, and starts the server.
package com.eddiesheffield.restlet.server;

import org.restlet.Component;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Server {
	public static void main(String[] args) throws BeansException, Exception {
		// load the Spring application context
		ApplicationContext springContext = new ClassPathXmlApplicationContext(
			new String[] { "applicationContext-resources.xml", "applicationContext-router.xml", "applicationContext-server.xml" });

		// obtain the Restlet component from the Spring context and start it
		((Component) springContext.getBean("top")).start();
	}

}
That’s it for the Java code. Now lets look at the Spring configuration files.
The first file (applicationContext-resources.xml) defines the beans that make up the data and resources. No real magic here if you’re familiar with Spring at all. We define userRepository, usersResource, and userResource beans. The userRepository needs no additional objects injected, and the resource beans use constructor autowiring to get the userRepository. The one interesting thing to note here is that the resource beans are defined with scope=”prototype” – this is important, and will be explained in a moment.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="userRepository" class="com.eddiesheffield.restlet.server.data.UserRepository">
	</bean>

	<bean id="usersResource" class="com.eddiesheffield.restlet.server.resources.UsersResource"
		scope="prototype" autowire="constructor">
	</bean>

	<bean id="userResource" class="com.eddiesheffield.restlet.server.resources.UserResource"
		scope="prototype" autowire="constructor">
	</bean>

</beans>
The next file (applicationContext-router.xml) defines the routing rules used by the server. Routing is handled by a router implementation specialized for use with Spring. The routing entries are defined in the attachments property. You can see that URLs of the form “/users” are routed to the usersResource bean and “/users/{userId}” requests are routed to userResource. This is where the “prototype” scope mentioned above comes into play. Restlet wasn’t really designed in a way that plays well with Spring “out of the box” so the Spring extension package is used to bridge the gap. Here we see the routes don’t go directly to the resource beans, but rather to a SpringFinder which uses the lookup-method to obtain new instances of the resources when required.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="root" class="org.restlet.ext.spring.SpringRouter">
		<property name="attachments">
			<map>
				<entry key="/users">
					<bean class="org.restlet.ext.spring.SpringFinder">
						<lookup-method name="create" bean="usersResource" />
					</bean>
				</entry>
				<entry key="/users/{userId}">
					<bean class="org.restlet.ext.spring.SpringFinder">
						<lookup-method name="create" bean="userResource" />
					</bean>
				</entry>
			</map>
		</property>
	</bean>

</beans>
The last configuration file (applicationContext-server.xml) defines the topmost component of the system configuring the protocol and port the server will listen on as well as the defaultTarget to pass requests to. In this case, “root” refers to the router bean.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="top" class="org.restlet.ext.spring.SpringComponent">
		<property name="server">
			<bean class="org.restlet.ext.spring.SpringServer">
				<constructor-arg value="http" />
				<constructor-arg value="3000" />
			</bean>
		</property>
		<property name="defaultTarget" ref="root" />
	</bean>

</beans>
Finally, for convenience, there’s a Maven pom.xml file included in the checkout to build the project and manage the dependencies.

Build the project with mvn clean install and you’ll end up with an executable jar in the target directory, along with all the dependent jars in target/lib. Start the server with java -jar target\RestletSpringServer-0.0.1-SNAPSHOT.jar and it should start up on port 3000.

For testing the server, I use the Advanced REST Client extension in Google Chrome. You should be able to find a similar tool for other browsers, or even standalone clients.
This entry was posted in Development and tagged , , , . Bookmark the permalink.

Leave a Reply