Recent Blogs
Ambimorphic, Mobile Configurations for Lamport Clocks After years of technical research into Smalltalk, with close cooperation with MIT Computer Science and Artificial Intelligence Laboratory (CSAIL) and its SCIgen, we have been able to show the construction of link-level acknowledgements. As a result, we propose an analysis of A* search, which we call Volt. 10/02/2008
Restlets and HTTP Sessions (Recipe 9) This recipe discusses some options in available to Web site developers using Restlet API to emulate traditional HttpSession's 07/31/2008
Restlet Cookbook - Delving into handleGet() and handlePost() (Recipe 8) This posting provides related examples that illustrate at least some simple things you may do with several handleX() methods where X may stand for various types of calls. 07/30/2008
Restlet Cookbook - How to enable SSL (Recipe 7) How to enable SSL on Restlet Web sites wihtout knowing too much keys, encryption, SSL and such. 07/29/2008
Restlet Cookbook - Using Filters in Restlet Applications (Recipe 6) This recipe contains code snippets illustrating the use of Filters in Restlet applications 03/09/2008
Restlet Cookbook - How to Create Virtual Hosts in Restlet Applications (Recipe 5) This recipe contains a code snippet for creating virtual hosts 02/24/2008
Popular HTML Escape Codes Here is a table of HTML escape codes for most frequently used symbols. If you use HTML, sooner or later you will find this table useful. 12/29/2007
Restlet Cookbook - Access Log (Recipe 4) This recipe describes access Logging using Restlet framework 11/09/2007
Restlet Cookbook - Form Submission and Processing (Recipe 3) This recipe describes a typical form submission using Restlet framework 10/15/2007
Restlet Cookbook - Site Application (Recipe 2) This recipe describes a possible way to code a Restlet Web site application 10/04/2007
more...
Restlet Cookbook - Site Application (Recipe 2)
Posted: 10/04/2007 by Serge IlynPerhaps I should have started my "Restlet cookbook" series with this recipe since it describes the way you may code your main application class. Its main() method is called when you start your Web application. The reason I did not do this is that the first recipe deals with two most important cornerstones of the Restlet framework - Resource and Representation classes. Recipe 2 shows the plumbing of various framework concepts to create a real life Web site.
In particular, from this recipe you may learn the following things:
- How to extend the framework Application class to create your own Web application.
- How to create and setup an instance of the framework's Component class which effectively starts the services you are up to.
- One of the possible ways to take care of many other things you will need in your application.
- How to resolve URLs and setup routing to the Resource's you want to show on the Web.
- Some minor but nonetheless very important tricks in coding your routing logic.
First, an important disclaimer - if your are not familiar at all with Restlet framework, I strongly recommend that you go first through the Restlet official tutorial which is a part of the Restlet Web site documentation section. Not only you will find explanations of all most important framework concepts and APIs, but this section also has many examples that clarify those concepts and show their usage in various situations.
The skeleton of the code that I use as a key element of this recipe is in Listing 1 at the bottom of the page. Essentially, it's an implementation of the class Naviquan (which also symbolizes the fact that this recipe is close to real life and not just an academic exercise). It extends the Restlet Application class (again, read Restlet documentation to understand why). In its main method a Restlet Component is started with a Naviquan instance attached to its default host. One of the important things here is that this component is set to provide services via HTTP protocol on port 80, and, at the same time this component will be able to access the server file system.
Now, let's look at the Naviquan constructor. Several things happen here - some of them have little to do with the Restlet framework itself. However, since we want a recipe close to real life, we need to acknowledge that certain things should happen in a Web application. So, one of the options (not necessarily the best) is simply to put them onto the Naviquan's constructor.
One of such things is the pool of sessions created to make communication with the back-end more efficient. One of the "secrets" here is that I am not using any RDBMS as back-end but rather rely on a solution that allows me to avoid completely all ORM headaches. Still, similar to a RDBMS connection pool, I create a session pool that will allow me quickly, when I need, to check-out (and later check-in) sessions with the back-end engine to get data needed. This functionality is encapsulated in the SessionPool class which I do not discuss since it's a back-end specific thing and not relevant anyway for this recipe. There are some other not very relevant things I brought just to show how various application elements can be assembled - I am talking about building some site infrastructure with methods like buildNavigatorCategories() and buildHome(). Or, it can be anything else you may need for your Web site.
In Recipe 1, I talked briefly about Restlet integration with Freemarker template engine - remarkably powerful combination. Since Freemarker stuff needs some configuration, it can be done in Naviquan constructor as well. For simplicity, I just made this configuration static (as well SessionPool I mentioned above).
The last thing to talk about is the createRoot() method. You may be wondering why is this method and what/who calls it. Well, the "default" answer is found above - read documentation! But since this one of the most important things in how Restlet framework functions, I will add some brief comments. First, it's an abstract method in the Application class, and since we extend this class we ought to implement it. Second, according to the Restlet API javadoc for this method, it "creates a root Restlet that will receive all incoming calls." Finally, the javadoc description for the whole class gives us a hint how this method is called: "This class is both a descriptor able to create the root Restlet and the actual Restlet that can be attached to one or more VirtualHost instances. "
About createRoot() implementation. Here, I would like to point to the following two important things. Once a Router (which is also of the Restlet type) is created, you can start attaching URL templates to it - that's where "friendly" URLs come from! Also, this "attaching" allows for associating particular Resource's with URLs. For example, in the code below the "/page/{page}" URL template is associated (using appropriate API) with the PageResource class - this is the same PageResource we designed in Recipe 1. As you can see this way of routing resources creates a very elegant and simple way of coding your Web application.
Of course, in real ilfe, things tend to get more complicated. And the createRoot() implementation in Listing 1 deals with one of those things. What happens here is that when the root URL is used (like http://www.naviquan.com/) you certainly want to serve your site home page. With Restlet framework you would attach something like HomeResource (extending Resource) to such URL pattern. Now, how about URLs like http://www.naviquan.com/robots.txt ? Alas, unless you have some tricks in your pockets, all you get will be ... the home page. To deal with issues like this, to set routing correctly, you need to refine your settings. The use of attachDeafult() and setMatchingMode() APIs as shown in the listing does the job. (This tip was kindly suggested by Jerome Louvel on the Restlet discussion board - another very useful resource in your wonders through the Restlet universe).
Listing 1
package com.naviquan.rest;
import java.io.*;
import java.util.*;
import java.util.logging.*;
import org.restlet.*;
import org.restlet.data.*;
...
/**
* Title: Naviquan RESTFUL Test
* @version 1.0
*/
public class Naviquan extends Application {
...
public static Configuration freeMarkerConfig;
private static SessionPool pool;
public static void main(String ...args) throws Exception {
// Create a component with an HTTP server connector
Component component = new Component();
...
component.getServers().add(Protocol.HTTP, 80);
component.getClients().add(Protocol.FILE);
// Attach the application to the default host and start it
component.getDefaultHost().attach("", new
Naviquan(component.getContext()));
component.getContext().getLogger().getLogger("com.naviquan.rest.Naviquan").setLe
vel(Level.WARNING);
component.start();
}
public Naviquan(Context context) {
super(context);
try {
...
// initialize pool of back-end sessions
HashMap poolInitMap = new HashMap();
poolInitMap.put(Constants.POOL_INIT_SIZE, Constants.POOL_INIT_SIZE_VALUE);
poolInitMap.put(Constants.POOL_MAX_SIZE, Constants.POOL_MAX_SIZE_VALUE);
poolInitMap.put(Constants.POOL_GROW_BLOCK,
Constants.POOL_GROW_BLOCK_VALUE);
poolInitMap.put(Constants.POOL_CREAT_WAIT_TIME,
Constants.POOL_CREAT_WAIT_TIME_VALUE);
pool = new SessionPool(true);
pool.init(poolInitMap);
// get navigator categories
String[] categoriesStringArray = buildNavigatorCategories();
...
Home home = buildHome();
...
// configure FreeMarker FREEMARKER_TEMPLATE_LOCATION
freeMarkerConfig = new Configuration();
freeMarkerConfig.setDirectoryForTemplateLoading(new
File(Constants.FREEMARKER_TEMPLATE_LOCATION));
freeMarkerConfig.setTemplateUpdateDelay(Constants.FREEMARKER_TEMPLATE_UPDATE_DEL
AY);
freeMarkerConfig.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG
_HANDLER);
freeMarkerConfig.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
freeMarkerConfig.setDefaultEncoding("ISO-8859-1");
freeMarkerConfig.setOutputEncoding("UTF-8");
freeMarkerConfig.setLocale(Locale.US);
}
catch (Exception ex) {
ex.printStackTrace();
}
}
...
/** createRoot */
public Restlet createRoot() {
Directory directory = new Directory(getContext(),
Constants.STATIC_FILE_LOCATION);
Router router = new Router(getContext());
router.attach("/",
HomeResource.class).getTemplate().setMatchingMode(org.restlet.util.Template.MODE
_EQUALS);
router.attachDefault(directory);
...
// Add a route for page resource
router.attach("/page/{page}", PageResource.class);
router.attach("/page/{page}/{pagenum}", PageResource.class);
...
return router;
}
private static String[] buildNavigatorCategories() throws Exception { ... }
public static Home buildHome() throws Exception { ... }
}