Friday, September 24, 2010

GWT+Restlet CRUD application

A client the following requirements

"Build a web based client entry tracking application with API support on Google App Engine"
I followed the usual route of doing a preliminary use case analysis and out came the top level idea of the project. The use case were:
- CRUD Client entry
- Auth using google UserService
- REST based API to expose "Client Entry" as a resource.

The technology platform/libraries choosen to implement the above system:
- Eclipse with Google Plugin
- Google App Engine SDK 1.3.7
- GWT 2.1M3 for client application
- Restlet 2.0.x for REST implementation
- MVP4G for MVP implementation in GWT.

Current application can be browsed here http://cloudresidentapi.appspot.com/

The first thing i did was to put a class diagram which reflects the entire application domain model. See a snapshot below.

I am using StartUML diagraming tool to do the UML diagram above.

I divided the project into 2 major parts. 
- The API part, which will allow any user with proper credentials to access the entries and its details in XML or JSON. 
The urls should be of the form http://someserver/myapp/api/entries to get all the entries
For getting individual entry http://someserver/myapp/api/entries/{clientname}
where, {clientname} is variable to identify the client by just his/her name.

- The client part, that  uses the api for various  operations on the entities


First I proceeded on to build the REST api that will be used by the client app. Using Google plugin, build a google web application, making sure of the various framework versions. Add the Restlet jars in WEB-INF/lib dir of the web application.

To do all the CRUD operations i made 2 Resources (as per the Restlet API).
EntitiesResource and EntityResource. Below is the relevant code.

The Restlet application class to manage the resource and its URL mappings

MyApplication.java


@Override
public Restlet createInboundRoot() {
System.setProperty("javax.xml.transform.TransformerFactory", "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");

Router r=new Router(getContext());
//r.attachDefault(HelloResource.class);

r.attach("/hello", HelloResource.class);
r.attach("/entries",EntriesResource.class);
r.attach("/entries/{entry}",EntryResource.class);


MapVerifier mv=new MapVerifier();
mv.getLocalSecrets().put("scott", "tiger".toCharArray());

ChallengeAuthenticator ca=new ChallengeAuthenticator(getContext(), ChallengeScheme.HTTP_BASIC, "Hello resource gaurd");
ca.setVerifier(mv);
ca.setNext(r);


return ca;

}


The web.xml servlet mappings pointing to the MyApplication class.


<servlet>
  <servlet-name>RestletServlet</servlet-name>
  <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
  <init-param>
      <param-name>org.restlet.application</param-name>
      <param-value>com.anansu.api.MyApplication</param-value>
  </init-param>
  </servlet>
  <servlet-mapping>
      <servlet-name>RestletServlet</servlet-name>
      <url-pattern>/api/*</url-pattern>
  </servlet-mapping>



The implementation of EntitiesResource.java,
This is to respond to url like
http://someserver/myapp/api/entries

@Get("xml")
public Representation toXml(){

DomRepresentation dr=null;
try {
dr = new DomRepresentation(MediaType.TEXT_XML);
Document d=dr.getDocument();

Element r = d.createElement("items");
d.appendChild(r);
for (Entry item : getItems().values()) {
Element eltItem = d.createElement("item");

Element eltId=d.createElement("id");
eltId.appendChild(d.createTextNode(String.valueOf(item.getId())));
eltItem.appendChild(eltId);

Element eltName = d.createElement("name");
eltName.appendChild(d.createTextNode(item.getName()));
eltItem.appendChild(eltName);

Element eltEmail = d.createElement("email");
eltEmail.appendChild(d.createTextNode(item.getEmail()));
eltItem.appendChild(eltEmail);

Element eltMsg=d.createElement("msg");
eltMsg.appendChild(d.createTextNode(item.getMessage()));
eltItem.appendChild(eltMsg);

r.appendChild(eltItem);
}
d.normalizeDocument();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return dr;
}


EntityResource.java
Responds to url like http://someserver/myapp/api/entries/jack


@Get
public Representation toJson(){
JsonRepresentation jr=new JsonRepresentation(this.entry);

return jr;
}

Notice that one this output is in JSON and not in XML.

Before implementing the POST, i needed to make a web form to actually POST the client info to the API. So i then proceeded to make the GWT client.
First i selected a design template and then proceeded on make the UiBinder version of the design template.