Tuesday, December 21, 2010

Upload, serve and search images using GAE BlobStore-Example.

Note: Article below targets developers with GWT+GAE experience.
Overview
The intention is to use GAE BlobStore to serve and search uploaded images. It also uses MVP pattern to layout the application architecture.

Features
- Upload new images to GAE using BlobStore
- Tag images during upload. 
- Search images based on these tags
- View those images of-course!

Dependencies
- GWT 2.1, GAE SDK 1.3.8
- mvp4g 1.1.0, twig-persist-1.0.4

Code


The code does not have GAE and GWT jars. It only contains mvp4g and twig dependencies.


Description

The code in the above URL is an eclipse project using Google Plugin for Eclipse.
Import the project in eclipse.
Fix project dependencies if necessary to ensure the project compiles fine.
Right-Click the project in Package Explorer. 
Select "Run-As Web Application".

This should start the application in dev mode.
Browse the dev url.
http://127.0.0.1:8888/CompuroadImgTag.html?gwt.codesvr=127.0.0.1:9997


Code Descriptions
There are no unit tests currently. This example has sort of served its purpose, so i am not very compelled to add unit tests now.

ServeUpImageServlet: As the name suggests, it serves out the images that are currently in the BlobStore. It depends upon a url parameter "bk" (blob key) ie the id of the image in the BlobStore, to get/serve the image. 


ImgTaggingServiceImpl: This is a GWT-RPC remote service wired to the GWT UI which loads up the current images. The UI constructs img tag with src pointing  to ServeUpImageServlet with the appropriate bk.

BlobUploadServlet: Uploads the binary image and the tags. The image contents and tags are then "redirected" to PersistImgDataServlet to do the actual saving the blobstore.

Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(req);
This does the magic of getting the new blob key when images are uploaded.

PersistImgDataServlet: Persists the image data in a blob store. The data comes from BlobUploadServlet.

Hope someone finds this helpful.

Cheers,
Subhro.

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.