Restlet Cookbook - An Approach To Site Design (Recipe 1)
Posted: 09/27/2007 by Serge IlynThe beauty of the Restlet framework, among other things, is in its conduciveness to the object-oriented design. When you design and implement a Web application in Restlet, you do not think about "J2EE" patterns - you think about and use classic software design patterns. The main benefit is that you can focus more on user requirements instead of intricacies of a particular J2EE Web development framework. With Restlets, as with usual OOA/OOD process, you will go through a number of iterations while your understanding of the problem domain is growing. At the same time, you can exercise very good control over costs of your project; the result of your effort is a design tailored not only to user requirements but also to how much effort you want to invest in it. This recipe shows an approach to the design of a "visual" Web application using Restlets.
Not a surprise, the proposed design relies heavily on the Restlet Resource class (as defined in the Restlet API javadoc - an "intended conceptual target of a hypertext reference"). However, if you look at the Resource's API, you will see that it's not a good candidate for messing up with your domain specific data. This observation tells us that perhaps an Interface (or more than one) is needed to abstract such data. However, if you design a relatively simple site, you may conclude that you actually do not need a detailed abstraction of all your problem domain entities - after all, other than showing pages with some content, there is nothing else to do. This leads us to the idea of this type of Interface:
Example 1
public interface Pagable {
// ======== META CONTENT ============
String getHeadTitle();
String getMetaKeywords();
String getMetaDescription();
// ======== BODY CONTENT ========
String getCenterPane();
String getLeftPane();
String getRightPane();
String getFooter();
String getHeader();
// ======= ATTRIBUTES THAT MAY INFLUENCE THE WAY PAGE IS RENDERED ==========
String getLayout(); // one column, two column, etc.
int getPagenum();
...
}
I want to stress that the API above is not a domain data centric - instead it's a "layout" centric allowing potentially for a great deal of flexibility in how exactly page content can be shown. I could do this differently, but this flexibility seemed important to me, and that's why I opted for this approach. Another way to look at this is to keep in mind that most likely you will have to override the following Resource method to get the Resource's representation:
public Representation getRepresentation(Variant variant)
A Pagable instance makes the process (as I will show below in the Example 3) of obtaining the Resource's Representation more elegant.
If we continue with our little OOA/OOD, we'll quickly come to the conclusion that even a simple Web site may have different types of pages: for example, home page, content pages, pages with lists of resources (pages) available on the site. This tells me that perhaps an abstract class like AbstractPage implementing Pagable is in order. I do not provide any code here for the AbstractPage, but the idea is very simple. Let's say that most of your pages have the same footer. Instead of repeating the code in all Pagable implementations, we implement this code only once in our AbstractPage.
A specific instance of a Pagable is essentially a Java bean with an additional functionality that allows to set all its properties from the backend. The skeleton of a Pagable implementation - let's call it Page - can look something like this
Example 2
public class Page extends AbstractPage {
private String type;
private String pageID;
private String title;
private String description;
private long composedOn;
private String composedBy;
private long lastEdited;
// getters and setters
.....
// implementation of super class abstract methods
.....
public void buildFromBackend() {
// can rely, for example, on pageID to get back-end data
....
}
}
Now, let's see how the application Resources and Pagable implementations fit each other. Assuming that we have PageResource class with the Resource at the top of its hierarchy, the code may look like the following
Example 3
public class PageResource extends BaseHTMLResource {
protected Page page;
public PageResource(Context context, Request request, Response response) {
super(context, request, response);
String pageStringID = (String) request.getAttributes().get("page");
page = new Page();
page.setPageStringID(pageStringID);
}
public Pagable getPagable() {
return page; }
public Representation getRepresentation(Variant variant) {
Representation result = null;
if (variant.getMediaType().equals(MediaType.TEXT_HTML)) {
try {
page.buildFromBackend(getRequest());
result = new TemplateRepresentation
(findTemplateName(page.getLayout()), findFreeMarkerConfig(), getPagable(),
MediaType.TEXT_HTML);
}
catch (Exception ex) {
// process exception
}
}
return result;
}
}
An interesting line in the code above is the one where an instance of org.restlet.ext.freemarker.TemplateRepresentation (which is of the Representation type) is created - this illustrates how the Freemarker templet engine can be used with the Restlet framework. TemplateRepresentation constructor requires several arguments (all described in its API javadoc). The most interesting is the third argument - a dataModel Object used by Freemarker to set respective values into the template. Here is an example of the template:
Example 4
<html>
<head>
<title>${headTitle}</title>
<meta name="keywords" content="${metaKeywords}">
<meta name="description" content="${metaDescription}">
....
</head>
<body>
<div id="container">
<div id="header">${header}</div>
<div id="nav">${rightPane} </div>
<div id="content">${centerPane}</div>
<div id="footer">${footer}</div>
</div>
</body>
</html>
The ${xxx} is the Freemarker syntax that can be used to reference dataModel properties (where, as mentioned above, the dataModel is that third argument passed to TemplateRepresentation constructor). And if you look at the actual properties used in the example above you will see that these are properties of any type that implements the Pagable interface. As you can see a remarkably powerful and, at the same time, simple way of rendering HTML pages.
Also note that PageResource extends BaseHTMLResource where BaseHTMLResource has some methods factored out from various XXXResource classes. Here is one possible implementation of BaseHTMLResource:
Example 5
public abstract class BaseHTMLResource extends Resource {
public BaseHTMLResource(Context context, Request request, Response response) {
super(context, request, response);
getVariants().clear();
getVariants().add(new Variant(MediaType.TEXT_HTML));
}
public Application getApplication() {
return (Application) getContext().getAttributes().get(Application.KEY); }
public abstract Pagable getPagable();
public Object getAttribute(String key) {
return getContext().getAttributes().get(key); }
public void setAttribute(String key, Object value) {
getContext().getAttributes().put(key, value); }
}
Recent Blogs
Convergence of Technologies II: Restlets, Highslide Viewer & SlideShowPro for Flash How to use Restlets, Highslide Viewer & Slide Show Pro Flash component to generate slide shows and show them in pop-up iframes 08/14/2009
Convergence of Technologies: Restlets, Highslide Viewer & Google Maps API How to use Restlets, Highslide Viewer & Google Maps API to generate Google maps using links on Web pages and show them in pop-up iframes. 08/13/2009
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
more...