webOS Wiki: The merger of knowledge, mobile and cloud computing, part 1

By Frank Zammetti

wosWiki

Editor's note: Frank Zammetti is the author of "Practical Palm Pre webOS Projects," and an active member of the webOS developer community. If you've been looking for a good example of client-server development for webOS, then this Palm Developer Center exclusive tutorial is for you. Frank will take you through the basics of developing an application that "lives in the clouds", meaning it has a wbeOS component as well as a server-side component to it.

You can find the source code at Palm's Github repository.Enjoy!


Palm's webOS has provided developers a revolutionary new platform with which to exploit the full potential of today's powerful smartphones, and other mobile devices. The Internet provides a mechanism for creating distributed applications that is unparalleled in computing history. Like the perfect combination of peanut butter and chocolate, webOS and the Internet complement each other perfectly.

In this two-part article I'll show you how to build an application that lives "in the cloud" but that you can still take with you wherever you go. You'll learn about a number of topics including REST, DWR, data synchronization and more.

In the first half we'll look at the overall goals of the application and dive into the server side of the equation. In the second half we'll focus in on the webOS side of things and see how it all ties together.

Introduction

Nowadays, true "web applications" are very common. In this model, the application still largely runs on the server, but more and more of it is coming down to the client, still running in the browser of course. AJAX primarily has been the driver allowing us developers to make this shift. Mobile devices however have, to a large extent, brought us back to a model where applications live and run locally, coded for a specific mobile device.

Devices like the Palm Pre and Pixi, and more specifically, the webOS operating system, have changed the mobile application development game. With webOS we have something that's really a bit of a hybrid. When you write a webOS application, you are of course using all the same web technologies you use to build web applications, things like HTML, CSS and JavaScript, but the application is, like the old model, running locally.

You can take things further though: your application's data can live "out there", in the ether that is the Internet, as can some of the code that makes up your application. When this data and code in the cloud is combined with the code of the webOS application, you form a larger application that is distributed in nature. This is a very powerful model that opens up a lot of opportunities, but also introduces a lot of complexity.

This complexity can seem a bit overwhelming and fairly daunting at first, especially if you've done little work on applications of this nature. Getting over this hump is exactly what I'm here to help you do!

Who is this article for?

This article is for developers who already have some degree of experience writing webOS applications but who don't have as much experience writing applications with both a client and server component. It assumes you've already delved into webOS and can get a basic application up and running on your own. It assumes you have a decent grasp of HTML, CSS, and JavaScript, all of which are prerequisites for webOS development in general.

This article also assumes that you have at least a passing knowledge of Java. You don't have to be an expert by any stretch, but if you've never looked at Java then you may want to read a basic introductory tutorial before reading this article.

This article walks you through a complete, working webOS application that has a server-side component to it. That means you'll get exposure not only to the webOS code but also to the code running on the server. I'll walk you through its structure, the how's and why's of things, and in the process I'll talk about some of the general concerns you'll have to take into account. If you like to "learn by example," look at real code, tear it apart, and maybe even put it back together yourself a little differently, then this article is for you.

So, if that sounds right up your alley then strap yourself in as the train leaves the station!

The app, in a nutshell

One of the best creations of this whole "social networking" era we find ourselves in is the wiki. A wiki, in case you happen to be unfamiliar with the term, is a web site that is specially-designed from the ground up to be edited by people quickly, easily and without technical know-how. The application discussed in this article, which I've rather uncreatively called woswiki, allows you to create articles, and have articles link to other articles.

You can view and edit articles, and articles can have within them links to other articles that, when clicked, allow you to navigate to other articles on the wiki. You can always return to the "home" article, which is the first article you start out on when you access the wiki. You can edit the current article as well, if no other user is editing it at the moment.

If that's all this application did then it really wouldn't be anything more than a simplistic browser interface to a web site. To make it far more interesting though, it stores a copy of the wiki in a local database. This way, you can access the wiki even when you have no network connection! Further, you can still edit articles and add new ones on-the-go and your changes will be synchronized with the server later, and vice-versa: other users' changes will automatically be brought into your local copy.

This article is for webOS developers, but the webOS portion of the application, which is relatively simple, is only half the equation. We're going to have to talk a bit about the server-side of things first, and then how we'll hook the two together.

Java and Google App Engine

When you start to think about a cloud-based application, the first question to answer is where you're going to host the server portion of the application. Not everyone has their own server infrastructure where they can host an application. Application hosting like this typically costs money, requires management capabilities by you, and in most organizations represents a whole class of employees who are dedicated to such issues.

There are free options available, however. One of the simplest to work with is provided by Google, namely the Google App Engine, hereafter abbreviated as GAE. GAE is an application-hosting environment that lets you worry about your application and your code, not the infrastructure it runs on.

GAE provides to you a full dynamic web serving environment using common web technologies such as Python and Java. It provides a persistent data storage mechanism including features such as sorting, queries, and transactions. GAE also offers other infrastructure-type services such as security and load-balancing. GAE will scale up your application, that is, will bring in more server resources to handle a heavier load, as necessary and fully on-demand without your code doing a thing. For the most part, there are few limitations placed on what your application can or can't do.

I said earlier that using GAE was free, and that is true, but only to a certain an extent. You can sign up for GAE and run applications in it (up to ten) without paying a dime, that much is true. Google even gives you a fairly generous allotment of CPU usage, storage, bandwidth, and other considerations at no cost. Once you pass some thresholds however, you'll have to start paying. Still, for many uses, and certainly for the purposes of this article, the free GAE services are more than sufficient: 1GB of data storage, 1GB of bandwidth per day, and a decent helping of CPU time.

As mentioned, GAE allows you to run Python or Java-based applications, and the choice is just a personal preference kind of thing. I've chosen to go with Java because it's what I work in all day long, so I know it best. Have no fear, though, if you're not a Java guru, the code we're going to write here is fairly simple, and I've tried to write it in such a way that even people with very little Java experience can follow it. That means I haven't always done things in the most efficient way possible because I was more concerned with simplicity and readability. So, if you're an expert in Java, don't go too nuts if you notice things that you might not have done the way I have!

To work with GAE, you need two things. The first is the GAE SDK, and the second is a GAE account.

You can download the SDK here: http://code.google.com/appengine. The SDK gives you the command-line tools you need to develop GAE applications and run them in a full-featured local version of GAE. That way, you can develop your application, test it, and get it working just how you want before you even upload it to the real GAE.

When you go to the download page, you'll have a choice of downloads for multiple platforms (Windows, Mac, and Linux), and you'll also be able to choose between Python and Java support.

Before you rush off and start downloading anything, though, I need to tell you that there is also a GAE plug-in for Eclipse available, and that is in fact what you should download. This article is prefaced on doing both webOS and GAE development in Eclipse, so obviously if you don't yet have Eclipse installed you'll need to go do so (www.eclipse.org). You don't HAVE to use Eclipse of course, but I'll assume you are for our purposes here.

From this point on, I'm going to assume that you've installed both Eclipse and the GAE plug-in and SDK. The next step is to sign up for a GAE account. You can do this at the previously mentioned URL as well. If you already have an account with Google, say for Gmail, you'll simply link that account to GAE, and you're good to go. If you need to create a new account, that's very simple too; all the information you need is at the mentioned location. As with the plug-in, I'll assume you have an account set up and ready to go.

Creating a basic GAE application is a simple matter of running through the Web Application Project wizard that the plug-in provides.

You'll enter a name for your project, as well as a package for your code to live in. This package is typically in the form com.xxx.yyy, a reverse form of an Internet domain, such as com.etherient.woswiki, for example. This isn't a requirement though; you can put anything you like here.

You'll be asked if you want your application to use Google Web Toolkit (GWT). The woswiki application does not use GWT, so you should de-select that option. You'll have to be sure to tell the wizard you want to use GAE, and select the SDK you want to use if the wizard is aware of more than one version installed on your system.

Once the wizard completes you will have a basic, yet complete, working web application. To see it in action, right-click the project in the Navigator or Project Explorer pane, whichever you happen to have open, select Run As, and then select Web Application. If you have the Console pane open, you should see a message indicating that the server is running. Assuming you do, pop open your favorite web browser and load up the URL http://127.0.0.1:8080/. You'll be greeted with a simple welcome page indicating your application is up and running.

That gets the application running on the local development server, but it's not truly running in GAE itself. Getting your application there is a simple process. First, right-click the project again and look for the Google menu item. Select it and then select Deploy to App Engine. You'll need to assign an ID to the project, which you'll be prompted to do the first time you try to deploy the application. You can enter any ID that you want, but keep in mind that this is the ID that will identify your application going forward, so it should be something meaningful to you. When you're done doing that, the deploy dialog box will reappear, minus the error message, and you'll be able to deploy the application. You'll need to enter your password each time, but once you do, the deployment itself shouldn't take more than a few seconds. Once it indicates the deployment has succeeded, you'll be able to access your application on the Internet. The address you use will be in the form http://xxx.appspot.com/xxx where xxx is the ID you assigned to the application.

At any time, you can access the GAE administration console from the URL previously mentioned. Here you can see information about all your applications, things like usage statistics and such, and also control them (i.e., set them to be running or not) or even remove them. You can also deal with each application individually, as you can see here:

GAE console

The code for this article includes the full source and Eclipse project for the server portion of woswiki, so you won't have to go through the wizard yourself, but it's good to have an understanding of how to do so for when you want to write your own app.

At this point, you have all the tools you need to develop applications bound for the GAE, including the server side of the woswiki application. The next step is to talk about how we're going to connect the webOS portion of the application with the GAE-based server portion.

Communicating with the server: REST and DWR

These days, there are tons of choices when it comes to communicating with the server from a JavaScript-based application. In this application I've used two techniques, one because it's quite popular nowadays and the other because I feel it represents one of the best approaches for Java developers. Let's take a look at each in turn now.

REST

The first technique we're going to use in this application is referred to as REST, which stands for Representational State Transfer. REST is an architectural approach to providing web services, not a specific standard. The basic idea is that a given URL represents a resource, and a client can interact with that resource using standard HTTP methods such as PUT, GET, POST, and DELETE (which correspond to the well-known CRUD methods of Create, Retrieve, Update, and Delete).

As an example, let's say you want to provide access to a student resource on a school's web site. The URL might be as follows:

http://www.fakeschool.com/students/10thgraders/john_doe.json

If you access this URL with an HTTP method of GET, you will retrieve the student John Doe, who's in 10th grade, assuming he exists in the system. The format of the response in this case would be JSON, since that's the extension used. Some RESTful web services, as many people refer to this model as, allow you to request a response in XML, JSON, or other formats, while others don't give you the choice (in which case you might not have an extension there at all).

The response is a representation of the student resource, which is where the "state transfer" portion of REST comes from. Likewise, if you wanted to update an attribute of this student, you would POST back to the same URL, and the contents of the POST body would be the JSON for the student with the changes in it. To add a new student, you would use the HTTP PUT method and leave off the student name part of the URL; to delete the student, you would use the DELETE HTTP method without sending any content.

One thing to notice here is that the URL for a RESTful service refers to nouns, not verbs. For example, the URL doesn't include anything like getStudent?name=john_doe as in a typical non-REST URL. Instead, the HTTP method used is effectively the verb, the action to execute in other words, and the URL includes the noun, or the object (or type of object) that is being operated on. Also note that the HTTP methods used map to the basic CRUD operations of Create (PUT), Read (GET), Update (POST) and Delete (Delete).

What I'm describing is a typical way to implement REST. However, REST is a fairly loose idea and you can play around with the implementation in whatever way makes sense, although the basics should still look a lot like this.

DWR

REST is a pretty simple model for web services, and is gaining a lot of traction precisely because it is so simple! It's very easy to write clients using a variety of technologies, and creating RESTful service providers is no more difficult. It builds on the standards we all use every day (HTTP) and can make use of the same sorts of security mechanisms used in such environments.

But, if you inhabit the Java world as I do, there's an approach that many people, including myself, like a little more. It's a popular little open-source library called DWR.

DWR (http://getahead.ltd.uk/dwr), which stands for Direct Web Remoting, is a free, open source product from a small IT consulting group called Getahead, whose members are Joe Walker and Mark Goodwin. DWR is an interesting approach to AJAX that allows you to treat instances of Java classes running on the server as if they were local, that is, running within the web browser.

DWR is a Java-centric solution, unlike many of the popular AJAX libraries out there today. Some view this as a limitation, but I for one view it as a plus because it allows for capabilities that probably couldn't be provided in a cross-language way (at least, not without being much more difficult to use and maintain for the developers). Things like automatic data marshalling and less overall configuration come to mind as just two examples.

If you are familiar with the concept of RPC, or Remote Procedure Call, then you will recognize quickly that DWR is, essentially, a form of RPC. At a high level, the general concept of RPC can be visualized like this:

RPC

If we now try to map how DWR works, at a high level, into this diagram, we'd come up with something like this:

DWR mapped to RPC flow

In the DWR model, the calling "system" is JavaScript executing in the user's browser, and the target "system" are methods on instances of Java classes running on the server. Just like other forms of RPC, the code you write in JavaScript looks very similar to the code you'd write on the server to execute the same methods, with just a few minor differences.

To give you a brief example of what some actual code would look like in this model, consider the following simple class definition:

  public class Greeter {
    String sayHello(String inName) {
      return "Hello, " + inName;
    }
  }

Even if you're not a Java aficionado I suspect that code is fairly clear. It defines a simple class named Greeter which contains a single method, sayHello(). This method is passed a string, presumably a persons' name, and it returns a string saying hello to the person.

If you wanted to call this code via DWR from JavaScript running in the browser, assuming you'd already accomplished all the necessary setup, the following code is all it would take:

  Greeter.sayHello("Frank",
    function(response) {
      alert(data);
    }
  );

Hopefully you're right now thinking that's pretty darned elegant! Under the covers it's just an AJAX call of course, one with its own special syntax and mechanism, but the simplicity of the code, and the fact that just by looking at it you really can't tell whether Greeter is a local JavaScript object or a remote object, is the real beauty of it. (Greeter is in fact a JavaScript object that acts as a proxy for the remote object, so it's actually a bit of both!)

DWR offers all sorts of goodies that are easy to take for granted. To name just a few:

This last one is especially cool, as it allows you to pass information from the server to the client, in a push fashion. DWR then goes even further by allowing you to control the application running in the browser FROM THE SERVER! The woswiki application won't make use of that capability as it's a bit more of an advanced technique, but if you're intrigued, I highly recommend checking out DWR more. It is, in my opinion, one of the coolest AJAX libraries out there today for anyone doing Java development.

Which should you choose?

In this application I decided to use both REST and DWR because it's a learning example, but if you were developing your own application you would likely want to choose one or the other. How do you decide?

Well, the first question to ask is if you're going to be using Java on the server or not. If not then DWR is out right away and the decision is fairly easy. Nothing says you have to use a RESTful architecture, though. You could just as easily make up your own URL scheme, your own protocols for data transfers. Going with a RESTful design however means that the protocol is essentially already designed for you, assuming you don't fool around with it too much. It also means that if you may want to provide an API for others to access later, having built it the RESTful way will mean the API is basically already defined in a well-known way, which will make your life much easier down the road.

If you're using Java on the server though, my whole-hearted recommendation is to go with DWR. The code is just so much simpler to develop that I think the flexibility you arguably lose is more than offset by how quick and easy it is to develop. It's also worth noting that the code you write on the server-side turns out to be plain old Java, so you aren't tied to anything there, which is a big plus. Finally, the newer version of DWR, 3.0 (which at the time of this writing is not yet generally available and that's why I've used the most current generally available version) provides a method for exposing DWR-remotable classes via REST URLs. This means that with that version of DWR you can in fact have your cake and eat it too!

In the end though, the choice is yours, and you should examine both options (and any others that seem worth your time) and make the determination that best fits your needs and programming style.

webOS Wiki: The dissection begins!

Now that we've discussed the basics of GAE, REST, and DWR, it's time to start looking at the code of woswiki itself. We'll start our exploration with the server-side of the equation.

The server-side of things

You can get a feel for the overall structure of the application in this snapshot taken from Eclipse:

Server project directory tree

If you're familiar with Java webapps, then you'll quickly recognize this as a relatively normal application. The structure at the highest level is one the GAE plug-in produces, where the web content, HTML, JavaScript, CSS, and images are in the war directory and the Java source code is in the src directory. The settings directory is for Eclipse settings, so we'll skip that entirely.

In the src directory you'll see a hierarchy of directories starting with com, and inside that is etherient, and finally woswiki inside that. In that final directory (which corresponds to a Java package) there are five classes that make up the application:

At this point I'd like to point out that I'm largely going to skip describing any of the configuration files that make up this application, because that would delve a little too much into the Java-centric, and even environment-centric stuff that makes up the application. Rest assured that it's all pretty boilerplate in nature. In fact, it's generated by the application wizard and generally not something you need to touch. The jdoconfig.xml found in the META-INF directory, which allows you to configure JDO-related parameters, and log4.properties in the src directory, which is where logging-related configuration can be found, both fall in that category of things we're not going to go into in any detail.

The same is true of some of the files in the war branch, namely appengine-web.xml, which has GAE-specific configuration and logging.properties, which has some further logging-related configuration. We will discuss web.xml and dwr.xml however as understanding those is important, but we'll come back to them in just a moment.

There is an index.html file in the war directory. This is the default HTML page that will be served if you access the application via a web browser. It was only used during the development of this project, to give me a quick-and-dirty test harness for the server-side. It isn't used during normal operation of woswiki, and you could easily remove it to no ill effect.

You'll also find the WEB-INF directory under the war directory. This is a required directory that all Java webapps must have. In it you'll find a number of things, including a lib directory that contains libraries that the application needs to function. All of the JAR files you see there are necessary to use GAE and its facilities, and in fact all the JARs there were automatically added by the wizard.

In WEB-INF you'll also find the appengine-generated directory where GAE puts things like our database, once it has been created. In general, you don't have to worry or even think about what's in this directory, although it's useful to know about because if you need to clear out the database in a hurry, you can simply delete the two files in there and you'll start from scratch again.

Also in WEB-INF is the web.xml file. This, like WEB-INF itself, is required to have a functioning Java webapp. Let's look at its contents now:

  <?xml version="1.0" encoding="utf-8"?>
  <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
    <servlet>
      <servlet-name>dwr-invoker</servlet-name>
      <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
      <init-param>
         <param-name>debug</param-name>
         <param-value>true</param-value>
      </init-param>
    </servlet>
    <servlet>
      <servlet-name>rest-servlet</servlet-name>
      <servlet-class>com.etherient.woswiki.RESTServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>dwr-invoker</servlet-name>
      <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
      <servlet-name>rest-servlet</servlet-name>
      <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
      <welcome-file>index.html</welcome-file>
    </welcome-file-list>
  </web-app>

As you can see, it's a simple XML file, and even if you've never seen a web.xml file before I suspect a lot of it will make sense. There are two <servlet> elements which, quite naturally, tell the server about a servlet. A servlet is a specialized Java class that knows how to handle HTTP requests. Once you tell the server what servlet to use to service a given URL pattern, any requests coming in with a matching URL will be routed to the servlet to do whatever you want.

The first servlet defined is the DWR servlet. DWR is making plain HTTP-based AJAX calls under the covers, which in Java typically means there's a servlet sitting on the server to handle the requests, whatever those requests might actually look like (i.e., what content they contain). To define a servlet, you have to provide a name for it in the <servlet-name> element, as well as the fully-qualified name of the class that implements it in the <servlet-class> element. ("Fully-qualified" means you have to not only give it the name but the package it's in.)

This particular servlet, DwrServlet, is provided as part of the dwr.jar file in the lib directory (which is the one I had to add manually - the GAE application wizard doesn't know about DWR by default). In addition, when you name the class of the servlet you can optionally include one or more initialization parameters by adding an <init-param> element to the <servlet> element. The name of the parameter and its value are specified using <param-name> and <param-value> elements respectively. Here we have a parameter named debug set to a value of true.

The debug parameter is neat because it allows us to access a DWR-generated page by going to http://127.0.0.1:8888/dwr. The page you get will list all of the classes that you can make remote calls to, and will also give you simple forms to try them out right then and there! In addition, this page will tell you exactly what JavaScript files (and their URLs) to import into your pages to be able to use the remote classes, and finally it even provides solutions for some common problems that people face initially using DWR. It's a fantastic tool for working with DWR, and you get it all for free just by setting one little parameter! Note that in production, you'll want to turn that page off because it can be a security risk, but during development it's a huge help.

A second servlet, the RESTServlet, is defined as well. As its name implies, it will handle any REST-type calls we want to make to the server outside of DWR calls.

After the servlets are defined, you have to tell the server what URLs each should handle. You do this by adding a <servlet-mapping> element for each servlet. That element has two child elements: <servlet-name> specifies the name of the servlet you're mapping, and <url-pattern> is a pattern a URL must have to be routed to the specified servlet. Here we're simply saying that any URL with /dwr/* in it will be handled by the dwr-invoker servlet and any with /rest/* in it will go to the RESTServlet.

Configuring DWR

With the basic web application configuration out of the way, let's talk about how to configure DWR. This involves creating a dwr.xml file and placing it in WEB-INF. The contents of that file are as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC
  "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
  "http://getahead.org/dwr/dwr20.dtd">
<dwr>
  <allow>
    <convert match="java.lang.Exception" converter="exception" />
    <convert converter="bean" match="java.lang.StackTraceElement"/>
    <convert converter="bean" match="com.etherient.woswiki.Article" />
    <create creator="new" javascript="WikiDelegate">
      <param name="class" value="com.etherient.woswiki.WikiDelegate" />
    </create>
  </allow>
</dwr>

Once again, we're dealing with a simple XML file. By default, DWR will allow nothing to be remotable. Any class you want to expose for calls must be specified in dwr.xml (DWR also allows you to dispense with the dwr.xml file and use an annotation-based approach, but I find it to be a bit less flexible and less obvious than the XML approach). Inside the root <dwr> element there is an <allow> element. Simply stated, anything inside this element is something DWR is allowed to work with.

Configuring DWR comes down to two essential things: converters and creators. A converter tells DWR that it is allowed to marshal a given Java object to JavaScript, and vice-versa, and also how to do so. For example, here it's specified that the Exception class can be marshaled, and that the converter named exception should be used. A converter is just a bit of Java code that knows how to convert another object to and from JavaScript. DWR comes with a bunch of these converters, and you can write your own if you need to.

The most common converter used is the bean converter, here used to deal with the StackTraceElement class and the Article class. The bean converter expects that the class follows the JavaBean specification, which prescribes standard methods for accessing that data in instances of the class. As long as your class follows the guidelines, the bean converter can easily convert it to and from JavaScript.

In addition to converters, you have creators. Creators are how DWR knows how to create instances of a given remotable class. Here, we have the new creator used to create instances of the WikiDelegate class in the com.etherient.woswiki package. The new creator, as its name implies, simply creates a new instance of the class for each and every call made to one of its methods. Like converters, DWR comes with a host of creators, and you can create your own as well, but the vast majority of the time, the new creator is in fact what you want.

The javascript attribute on the <create> tag is also important as it specifies the name of the object in JavaScript that we will call methods on. In other words, assuming we import all the right JavaScript into our page, we'll find that there is an object named WikiDelegate available to our JavaScript that has methods we can call that mimics all the methods in the WikiDelegate class on the server. Calling the methods of that JavaScript object will result in a remote call to the server-side version of that method.

The <param> element, of which there can be more than one, gives DWR further information it needs to do its thing. Here, the parameter named class with the value com.etherient.woswiki.WikiDelegate tells DWR the name of the class to instantiate when remote calls come in.

Note that by default, all public methods on the WikiDelegate class are available for remoting. You can change this via further configuration if you wish, and in fact in general, DWR offers more configuration options than this, as you might imagine. For our purposes here though, we don't need anything more than this.

Support classes: Article, User and JDOUtil

First, we'll discuss three supporting players, three relatively simple classes that the two main classes that we'll look at later, RESTServlet and WikiDelegate, depend on. First up is the Article class, which naturally represents a wiki article. In Java parlance, this class would be referred to as a VO, short for Value Object. It's simply a class which has the primary purpose of being a container for information that models some entity. As such, it's quite simple:

package com.etherient.woswiki;

import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Article {

  @Persistent
  @PrimaryKey
  private String title;

  @Persistent
  private String articleText;

  @Persistent
  private String lastEditedBy;

  @Persistent
  private long lastEditedDateTime;

  @Persistent
  private String lockedBy;

  @Persistent
  private long lockedDateTime;

  public void setTitle(final String inValue) {
    this.title = inValue;
  }

  public String getTitle() {
    return this.title;
  }

  // MORE METHODS HERE

}

This class uses some JDO annotations to make the server aware of how to store object of this type in a database. JDO, which stands for Java Data Objects, is a simple, standard API for doing database access and is the way you use a database in an application running in GAE. The @PersistenceCapable annotation on the class itself tells the server that this class indeed can be stored in the database, and the identityType attribute set to a value of IdentityType.APPLICATION indicates that the unique key that identifies an object of this type is one of the fields it contains.

Speaking of the fields, there are six in this class:

Each of these fields has a @Persistent annotation so that JDO knows we want to store the value of that field (leaving it off makes the field essentially transient, i.e., its value only exists while the object itself exists in memory) and the title field additionally has the @PrimaryKey annotation on it to indicate this is the unique key field that identifies an Article object in the database.

Following the field definitions are a total of twelve methods, two for each field. These methods make the class adhere to the JavaBean specification in that the fields are all marked private so they cannot be accessed directly, and therefore need an accessor, or get*() method, and a mutator, or set*() method. I've only shown one set of methods for the title field to save some space here, but the rest look identical to these, aside from the data types.

I've also left out the toString() method. All Java classes by default have a toString() method so that you can do things like:

System.out.println(myObject);

This will implicitly execute toString() and dump the results to the stdout stream. However, the default implementation is fairly useless for most classes, as it just shows an internal identification number for the instance of the class. So, I've overridden the toString() method such that above line of code will dump a human-readable representation of the class to stdout. This is a really nice debugging technique if nothing else and you can feel perfectly free to take the toString() method and use it in your own code (it's designed so that you can drop it in any class without having to change it at all and it'll just work).

The User class is next, and it's even simpler than the Article class, but is of the exact same basic nature:

package com.etherient.woswiki;

import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class User {

  @Persistent
  @PrimaryKey
  private String username;

  @Persistent
  private String password;

  public void setUsername(final String inValue) {
    this.username = inValue;
  }

  public String getUsername() {
    return this.username;
  }

  public void setPassword(final String inValue) {
    this.password = inValue;
  }

  public String getPassword() {
    return this.password;
  }

}

I probably don't need to tell you that this class represents a wiki user. Interestingly, while the Article class is marshalable by DWR, User is not, because User is only used on the server to keep a record of the users in the database, hence there is no converter element for User in dwr.xml.

We'll see both the Article and User classes in action soon when we look at the RESTServlet and WikiDelegate classes, but before we do we have one more member of the supporting cast to look at, the JDOUtil class:

package com.etherient.woswiki;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public class JDOUtil {

  public static final PersistenceManagerFactory persistenceManagerFactory =
    JDOHelper.getPersistenceManagerFactory("transactions-optional");

}

You might be thinking that I surely must have left some code out, but I assure you, that's the complete class! When you work with JDO, all of your operations will be performed by calling methods of something called a PersistenceManager. To get an instance of a PersistenceManager to work with, you request one from a PersistenceManagerFactory. However, constructing the PersistenceManagerFactory the first time is a fairly expensive operation, so you really only want to have to do it once. That's where this class comes in. Its single field, persistenceManagerFactory, which references a PersistenceManagerFactory. Since the field is static, it will be initialized when the class is loaded, which happens as a result of the server starting up. (Technically it's a result of the JVM starting up, but let's not split hairs here!).

This initialization results in a call to the JDOHelper class's getPersistenceManagerFactory() method. The JDOHelper class is part of JDO itself. So, the net result is that when the server starts up, we'll incur that relatively expensive PersistenceManagerFactory construction up-front, and never again. Any class that needs a PersistenceManagerFactory can reference the field in this class, and that's precisely what both the RESTServlet and WikiDelegate classes will be doing, as we're about to see.

The RESTServlet

In this application, there are two RESTful functions that are implemented. The first is to verify that a wiki exists at a given URL (which the user enters when registering a new wiki with the application) which is done by accessing the URL http://127.0.0.1:8888/rest/woswiki, assuming you're running the application in the local development server, using the GET HTTP method (so it's a read operation to retrieve a woswiki, which here really just means retrieving the version of woswiki running). The second is to verify or add a user to the wiki and that uses a URL http://127.0.0.1:8888/rest/user/* where * is the username. Both of these requests are serviced by the RESTServlet class.

This class is a normal Java servlet, and rather than just list is all I'm going to break it into some more easily-digestible pieces, beginning with this chunk of code:

package com.etherient.woswiki;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.logging.Logger;
import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class RESTServlet extends HttpServlet {

  private static final Logger log =
    Logger.getLogger(RESTServlet.class.getName());

That's how the code begins: a bunch of imports for classes to deal with JDO, some basic Java I/O functions and some servlet-related classes. Then the class is defined and you'll note that it extends the HttpServlet class, which means it inherits a bunch of code so we don't have to write it all over again ourselves. Finally, a Logger is created. This is an object that allows us to write log messages to a log file, which you can access in the GAE application console if you wish.

Next we have two methods, doGet() and doPost(). As you can guess, they each process a request depending on which HTTP method is used. Let's look at doGet() first, which is pretty simple:

public void doGet(HttpServletRequest inRequest,
  HttpServletResponse inResponse) throws ServletException, IOException {

  log.info("doGet()");

  String requestURI = inRequest.getRequestURI();
  log.info("requestURI = " + requestURI);

  if (requestURI.indexOf("/woswiki") != -1) {

    log.info("Recognized woswiki noun");
    PrintWriter out = inResponse.getWriter();
    out.println("woswiki_1.0");

  }

}

After we write out a quick log message, we get the URI that was requested (the URL in other words) from the incoming request object. That URL is logged, and then we see if the string /woswiki is a part of the URL. If it is then we log that we recognized the noun and we write out the string "woswiki_1.0" to the response. This will be returned to the caller, which when we add a wiki in the application indicates that yes, there's a wiki at the specified URL, and that it's of the correct version. (Although the webOS portion of woswiki doesn't handle it, we could have code that allows us to have a newer version of either side, client or server, and deal with it... as it stands now, you simply won't be able to add a wiki that isn't of the appropriate version).

The doPost() method is next, and it handles the /user/* REST calls:

public void doPost(HttpServletRequest inRequest,
  HttpServletResponse inResponse) throws ServletException, IOException {

  log.info("doPost()");

  String requestURI = inRequest.getRequestURI();
  log.info("requestURI = " + requestURI);

  if (requestURI.indexOf("/user/") != -1) {

    log.info("Recognized user noun");

    String username = URLDecoder.decode(
      requestURI.substring(requestURI.lastIndexOf("/") + 1), "UTF-8"
    );
    String password = inRequest.getParameter("password");
    log.info("username = " + username);
    log.info("password = " + password);

    PersistenceManager persistenceManager =
      JDOUtil.persistenceManagerFactory.getPersistenceManager();
    User user = null;
    PrintWriter out = inResponse.getWriter();

    try {

      user = persistenceManager.getObjectById(User.class, username);
      log.info("User '" + username + "' retrieved from DB: " +
        user.toString());

      if (user.getPassword().equalsIgnoreCase(password)) {
        out.println("ok");
      } else {
        out.println("fail");
      }

    } catch (JDOObjectNotFoundException jonfe) {

      log.info("User '" + username + "' not in DB, so creating it now");
      user = new User();
      user.setUsername(username);
      user.setPassword(password);
      persistenceManager.makePersistent(user);

      out.println("ok");

    } finally {
      if (persistenceManager != null) {
        persistenceManager.close();
      }
    }

  }

}

There's a little more meat on them bones, but it's still not too complicated. Again, some basic logging kicks things off and the URI is retrieved. If the URI contains the string /user/ then the rest of the code kicks in (otherwise the response will be empty as the servlet doesn't know how to respond in that case). Next, we parse out the username by taking everything in the URI from the final / on, and decode it so that we have a plain old string, rather than the URL-encoded string we would have otherwise. The password will have been sent as a POST parameter, and the getParameter() method on the request object allows us to get at that easily.

With the username and password in hand it's time to see if the user is known to the wiki yet or not. To do so we first get a PersistenceManager instance from the JDOUtil.persistenceManagerFactory we talked about earlier. With a PersistenceManager in hand it's a simple matter of calling its getObjectById() method, passing it the username to look for and also the type of object we expect to get back (User in this case). If the user is found in the database, then JDO will kindly provide us with a User object with the username and password fields populated. We can then compare that password with the password that came in as part of the request. If it's correct then we write ok to the response; if not, fail is written out. The webOS portion of the app will respond to these as appropriate.

You'll notice that the call to getObjectById() was wrapped in a try...catch block. This is because that method can throw an exception, JDOObjectNotFoundException to be precise, to indicate that no User with the given username is found. When this happens, the user needs to be added to the wiki. To do so is simple: instantiate a new User object, set the username and password fields to the values passed in with the request, and then tell the PersistenceManager to save the User by calling its makePersistent() method, passing it the User object. In this case, the response to the caller is ok.

The finally block is code that executes regardless of anything that happens before it and its job is to close the PersistenceManager. Any save operation performed won't commit to the database until this is done, and it also cleans up resources so it's something that's got to get done.

With that, the two REST functions the app needs are handled. Now we can look at the core of the woswiki application as far as the server-side goes, and that's the code in the WikiDelegate class.

The DWR-exposed WikiDelegate class and its methods

The WikiDelegate class is the main code on the server that will be called via DWR. It's a POJO, which stands for Plain Old Java Object. This means that, as compared to the RESTServlet which uses things like request and extended HTTPServlet, WikiDelegate is a plain Java class, not extending anything (other than Object like all Java classes do) and not knowing anything about the fact that it's handling HTTP requests. This is a great feature of DWR, because it means that you can very easily unit test your DWR-remotable classes without them being in the webapp, or even running on a server. You can write a simple Java application that invokes their methods, and which you can even run from your OS's command line!

Like the RESTServlet, and like most of the webOS code that we'll look at later, I'll break WikiDelegate up into small bits to pick apart. It starts out not at all unlike the RESTServlet:

package com.etherient.woswiki;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.logging.Logger;
import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

public class WikiDelegate {

  private static final Logger log =
    Logger.getLogger(WikiDelegate.class.getName());

As previously mentioned, the class doesn't need to extend anything else, and the classes it imports for use are just some basic built-in (as in they come as part of standard Java) utility classes, and our JDO-related classes. This time we have a Query class, but we'll get to that in a bit. We also have a Logger instance like RESTServlet.

Now, each method in WikiDelegate, assuming we've configured DWR to be allowed to, can be called remotely from our webOS application. The first such method is getArticle(), and this is the one that will be called any time the user wants to view an article, or when they want to edit it:

public Article getArticle(final String inTitle, final String inUsername) {

  log.info("inTitle = " + inTitle);
  log.info("inUsername = " + inUsername);

  PersistenceManager persistenceManager =
    JDOUtil.persistenceManagerFactory.getPersistenceManager();

  Article article = null;

  try {

    article = persistenceManager.getObjectById(Article.class, inTitle);
    log.info("Article '" + inTitle + "' retrieved from DB: " +
      article.toString());

    if (inUsername != null) {
      log.info("Edit lock on article requested");
      boolean obtainLock = false;
      String lockedBy = article.getLockedBy();
      if (lockedBy == null) {
        log.info("Article NOT currently locked");
        obtainLock = true;
      } else {
        log.info("Article IS currently locked, checking user");
        if (lockedBy.equalsIgnoreCase(inUsername)) {
          log.info("Article locked by requesting user");
          obtainLock = true;
        } else {
          log.info("Article NOT locked by requesting user, seeing if " +
            "lock has expired");
          if ((new Date().getTime() -
            article.getLockedDateTime()) > (1000 * 60 * 5)) {
            log.info("Lock has expired, revoking lock");
            obtainLock = true;
          }
        }
      }

      if (obtainLock) {
        long lockedDateTime = new Date().getTime();
        log.info("Edit lock granted for article '" +
          inTitle + "' to user " + inUsername + " on " + lockedDateTime);
        article.setLockedBy(inUsername);
        article.setLockedDateTime(lockedDateTime);
        persistenceManager.makePersistent(article);
      } else {
        log.info("getArticle - Edit lock for article '" + inTitle + "' NOT " +
          "granted to user " + inUsername + " because it is already " +
          "locked by " + article.getLockedBy() + " on " +
          article.getLockedDateTime());
      }
    }

  } catch (JDOObjectNotFoundException jonfe) {

    log.info("Article '" + inTitle + "' not in DB, so creating it now");
    article = new Article();
    article.setTitle(inTitle);
    article.setArticleText("This is a new article.  Please edit me!");
    persistenceManager.makePersistent(article);

  } finally {
    if (persistenceManager != null) {
      persistenceManager.close();
    }
  }

  log.info("Returning: " + article.toString());
  return article;

}

The method takes in a title and a username and returns an Article object. First, it looks in the database and tries to retrieve an article with the specified name. If one is found then the next task is to determine if the caller wants to lock the article for editing. Only a single user may edit an article at a time of course, so if a username was passed in then the method takes that to mean the user wants to edit the article.

In this case, the lockedBy field of the Article object from the database is checked. If its value is null then the article is not currently locked so the user will be able to edit the article. The obtainLock variable is set to true, and this will be used later to lock the article for editing.

If lockedBy is not null however, meaning there's a username there and that user is, presumably, editing the article, the next thing to do is to see if the user that has the lock is the one requesting the lock. This can happen if the user started editing the article, shut down the webOS application, restarted it and went to edit the same article. There's no real harm in this - the code will simply allow the lock again.

Now, if the article is currently locked by someone other than the user requesting the lock, than we have to check if the lock has expired. This can happen if the user editing the article closes down the webOS application and doesn't go back to editing the article. The edit lock will expire after five minutes, so we check the lockedDateTime value on the Article object and if the current time is greater than that value plus five minutes, then the new user will be issued the edit lock.

After those few if statements that deal with the above logic, the obtainLock variable is checked. If it's true, then the lockedBy and the lockedDateTime fields on the Article object are updated to reflect the current time, and the new user editing the article and the Article object are written back to the database. If obtainLock is false then a log message is written out and that's the end of that!

If the JDOObjectNotFoundException is thrown as a result of trying to retrieve the requested Article from the database, then what the code does is create the Article and add it to the database. The way a typical wiki works is that you have a page, or article as I call it, and you edit it and add a link. When you view the article again and click the link you are requesting to view an article that hasn't been created yet. This is the case we're dealing with in this catch block. The Article is created, written to the database, and will be returned to the caller.

The same finally block we saw in RESTServlet is again executing to clean things up and make sure all database writes occur as expected. Finally, the Article object that was either retrieved from the database, or created new, is returned to the caller, including the new edit lock information, if applicable.

Following the getArticle() method is the listAll() method that returns a listing of all articles on the server:

public ArrayList
listAll(final boolean inFullDetails) { PersistenceManager persistenceManager = JDOUtil.persistenceManagerFactory.getPersistenceManager(); Query query = persistenceManager.newQuery(Article.class); Collection
articles = (Collection)query.execute(); if (inFullDetails == false) { for (Article a : articles) { a.setArticleText(null); a.setLastEditedBy(null); a.setLockedBy(null); a.setLockedDateTime(0); } } log.info("Returning " + articles.size() + " articles"); return new ArrayList(articles); }

The Query object is a JDO object that allows us to query objects of a given type. Here, since we want all the Article objects, there are no query criteria to be had; we just want 'em all! What we get back is a Collection, a list really, of Article objects. If the inFullDetails argument passed in is false, then we need to process each of those objects. We iterate over them and clear out all the fields except title and lastEditedDateTime. This is used by the background synchronization code that we'll see when we look at the webOS side of things. This is the only way this method would be called (the index.html test page that's part of the webapp uses it by passing true, but again, that page was used strictly during development). This is done is because we want to minimize the amount of information sent back from the client. However, the executeQuery() call on the Query object retrieved all the data, so we have to clear what we don't want before sending the Article objects back to the client. Speaking of sending them back to the client, that's the last line of code here: the collection of Articles is used to create a new ArrayList and that is what gets returned to the caller.

The next method found in the WikiDelegate class, and in fact the only other one, is the updateArticle() method:

  public Article updateArticle(final Article inArticle) {

    log.info("inArticle = " + inArticle);

    PersistenceManager persistenceManager =
      JDOUtil.persistenceManagerFactory.getPersistenceManager();

    Article article = null;
    try {
      article = persistenceManager.getObjectById(
        Article.class, inArticle.getTitle());
    } catch (JDOObjectNotFoundException jonfe) {
      log.info("Article '" + inArticle.getTitle() + "' not in DB, " +
        "so creating it now");
      article = new Article();
      article.setTitle(inArticle.getTitle());
    }

    if (article.getLockedBy() != null &&
      !inArticle.getLastEditedBy().equals(inArticle.getLockedBy())) {
      log.info("Editing user doesn't match locked user so not saving");
      return inArticle;
    }

    article.setLastEditedBy(inArticle.getLastEditedBy());
    article.setLastEditedDateTime(inArticle.getLastEditedDateTime());
    article.setLockedBy(null);
    article.setLockedDateTime(0);
    article.setArticleText(inArticle.getArticleText());

    persistenceManager.makePersistent(article);

    if (persistenceManager != null) {
      persistenceManager.close();
    }

    log.info("Save successful, returning: " + article.toString());
    return article;

  }

As you can see, updating an article is actually a little simpler than getting an article, which to my mind is a little bit counter-intuitive, but I digress. The method begins, much as getArticle() did, by using JDO to try to retrieve the article from the database. If the article isn't found, then a new one is created. This really shouldn't ever happen under normal conditions, but it avoids any possible errors occurring in the rest of the code without requiring a bunch of extraneous error-handling code.

Next, the lockedBy field is checked and if it isn't null, and if the lastEditedBy user doesn't equal the lockedBy user, then somehow a caller has tried to update an article they don't have an edit lock for, so the Article object is simply returned and the method aborts.

Assuming this condition is passed though, the lastEditedBy field is updated to reflect the user making the change, as is the lastEditedDateTime field to reflect the current date and time. The lockedBy and lockedDateTime fields are cleared so someone else can obtain a lock, and finally the articleText field is updated with the new content sent in by the caller. The Article is then saved to the database, the finally code kicks in to clean up and we're all done! The Article object is returned, all nice and updated, and the caller can do its things as appropriate.

Looking ahead

In the second half of this article we'll jump right into the webOS code, the client side of the woswiki equation. We'll see how that code makes use of the server code developed in this first part and how it all ties together to form a single coherent yet distributed application

So take a little break, grab a cup of coffee and meet me back here for the second half at your convenience!

-Frank W. Zammetti