A few “PAAS”ing thoughts

November 24, 2010 9 comments

Google App Engine has suddenly been thrown into spotlight with a critical piece written by Carlos Ble at his blog.

I got my share of mixed feelings while reading his post. Why, you may ask? I have been spending a better part of my free time digging into the Google App Engine, which is a PaaS platform that allows you to write web applications in either Java or Python. Heck, I have even combined all my findings and published them as a free eBook over here.

Should I get all defensive about Google App Engine and try and blast each of Carlos’ points. Actually not. I do not work for Google and neither does my company currently do any work in Google App Engine. All my investigations into Google App Engine has been purely out of my interest and my goal of discovering a good platform to help showcase some of my applications.

What Carlos has mentioned in his blog post should not be construed as a way to get more publicity or the fact that Google App Engine is completely useless. If a platform or product needs to be successful, it needs to have its healthy dose of people who love it, hate it, just about like it, just about manage to work with it and many more feelings in between. Google is not a stupid company, its engineers are smart too and anyone can easily conclude that they know much more about the shortcomings of their App Engine platform than Carlos or its users, like you and me.

If you have the time to go through Carlos’ post and the colorful comments that follow, one thing struck me in particular. The concept of Cloud Computing is not being bashed at all in totality. This model of computing is real and no one is debating that. Given that, it is important to look at the 3 flavors of Cloud Computing: IaaS, PaaS and SaaS. We will keep SaaS aside for the moment. IaaS and PaaS are clearly defined. You need computing resources (Storage, CPU, etc) and complete control to run whatever you want via your own application stack, go with IaaS. Amazon does a fantastic job over there. To anyone dealing with PaaS, it is clear that all vendors in that space mandate a programming model. There are no Ifs and Buts about it.

Let us dig into that a little. By mandating a Programming Model, the PaaS vendors are clearly telling you that your application needs to be written as per their software stack and the APIs that it makes available to you. You cannot just think about taking  your inhouse web application and deploying it on Google App Engine and think that it will work. No. Never. Unless it is a Servlet, doing “Hello World”. Every PaaS vendor addresses infrastructure by wrapping APIs around it. They give you APIs for Authentication, Data Storage, Caching, Messaging, Networking and much more. What does it mean? It means you have to retrofit your application to use those APIs to get maximum mileage out of the PaaS platform. This is because those APIs are closely tied into how the PaaS will provide you elasticity. Let us look at Database support. Since the beginning of time, Google App Engine does not support SQL database storage (I am not talking about its Enterprise edition that has MySQL support). This means that your data storage mechanism has to be written (or rewritten) to fit into the NoSQL like service that the Google Datastore provides. Does it have restrictions? Is there are paradigm shift in thinking to move to that? The simple answer is “Yes”. But which software in this world does not have restrictions? If it was that simple, the world would have needed only one programming language. Anyways, that’s not the point. The point is that you have to adjust as you move to a PaaS platform. PaaS platform mandate a programming model and you need to follow that. As you go through that, you need to modify your thinking first and then your code and measure, measure and measure constantly what is working and what is not? And keep adapting as per that. All companies do that with their products, especially public facing live applications and this is not different.

Will all applications fit within Google PaaS? You don’t need me to tell you that they will not. What is it particularly that I like about Google App Engine. For me, its biggest selling point has been the low cost to entry (don’t mistake that for zero cost of entry!). I have developed several Proof of Concept applications that demonstrate some idea in my head and hosted them all on Google App Engine. Some of the applications are still live and running today. I have a good feeling what works and what doesn’t and have adapted my applications. I find it works best for applications that you have the luxury of writing from scratch. I would be careful to simply assume that my enterprise apps can be hosted tomorrow as-is on its platform, for reasons described above.

I have talked to a lot of folks about Google App Engine. And I intentionally mention to them things like the 30-second limit for requests and the 1000-record limitation. I think when you mention this to any software engineer, the first reaction is akin to an electric shock and then the outpouring starts. Without even thinking about what application they are going to write, they claim this platform is not for them. Here are some of the remarks that I have heard from them in response to the above limitations : How could Google do something like this? A 30 second limit for requests? Do you know my application will need much more than that? What no SQL? What are you talking? Have you lost your mind? Is there even a thing like that? What happened to your education and those C.J.Date RDBMS primers? 🙂

All the above concerns are valid but my only response is that in a PaaS, it is a give and take relationship. You lose your full control over how you write things. In return you get the scalability for a fraction of the cost. You get your IT infrastructure managed without you even understanding it. Once you understand this symbiotic relationship, which is true in every other aspect of our life too, things settle down and then it does not look “cloudy” anymore (no pun intended!)

One more point. There are enough success stories for both Amazon (IaaS) and Google (PaaS). Ask any of them about their journey and there will be stories of pain, adjustments and finally making it work. There will be companies now, who will post their success stories with Google App Engine too to mitigate the bad press. But I personally don’t worry about that. What I am excited about is that this light started by Carlos, will result in more information coming out about Google App Engine and that includes stories from the trenches. I will be keeping my eyes open to scan resources that will spring up and learning more about the platform. Big Advantage to Google App Engine now, if they embrace the open nature of the comments and actually take up some of the limitations, that even they know about, on a war footing!

Finally I would like to conclude, that there is no point in telling people that you need to read the documentation and understand the platform completely before committing your resources to using the particular product or platform. This model does not scale anymore. It does not get you to the market faster anymore. And it goes very much against the fundamental notion of getting the Early Mover Advantage. Think about how many articles in the recent 1-2 years, that you have come across from even giants like Twitter and Facebook, publicly stating that technology X or Y did not work or scale for them, and hence they had to develop that infrastructure themselves or replace it with something better suited to them.  Are we expecting a Google or a Amazon to tell you, “Hey! You know what? Our platform really sucks if you want to do A,B,C.” They can give some general guidelines and best practices but everything else has to be discovered, shared and that is all Carlos is trying to say here. There will be only one winner in the end, the PaaS platform itself.

Long Live Cloud Computing! Long Live IaaS and PaaS!

Categories: Uncategorized

Architectural Considerations to move your product to GAE

July 29, 2010 Leave a comment

I wrote a blog post at my company’s site titled “Architecture considerations for software products on cloud”. Though the article is general in nature, I do feel that a lot of the points apply if you are planning to move your product to GAE.

Click here for the blog post.

Categories: Uncategorized

Project Management Principles via FIFA World Cup 2010

July 5, 2010 2 comments

This is slightly off topic and is present on my other blog. I present my summary of good Project Management vis-a-vis the FIFA World Cup 2010.

Link to Post :

Categories: Uncategorized

Public API Design Factors

If you have developed a successful application/service on Google App Engine, chances are that you are thinking of exposing your application/data for use by the public. That is excellent news since it is likely to allow mashup developers to integrate your application into an overall larger scheme of things. This blog post goes into what factors you need to address before you begin on your journey to create a public API.

The web has moved from its image of hosting web applications to that of a platform. A platform is primarily, a set of building blocks that you can combine in innovative ways to build your own application. One of the key factors that have driven the web towards the “platform” avatar has been the emergence of a large number of Public APIs based on Open Standards. A Public API in simple terms is exposing key pieces of your application for the consumption of other applications.

A Public API is an important piece of any web application today. Over the last 5 years, public APIs have proliferated and everyone from the big companies to the newest startup bets big on a public API. According to the premier API tracking site, The Programmable Web (http://www.programmableweb.com), there are currently 2033 APIs available for applications today [dated 21st June 2010]

What can we do with the Public APIs? Here are some of them:

  1. You can integrate a best of class functionality that is already being exposed by the Public API. For e.g. if you need to integrate Maps, simply integrate the Google Maps API. You do not need to reinvent the wheel.
  2. You can provide a complete different user experience (interface) to an existing service.
  3. You can utilize the Public API in a larger mashup that you are creating.
  4. You can create applications running on devices that the current provider of the Public API does not address. For e.g. you could write mobile applications running on the iPhone, Android, etc – which the Public API provider does not even provide.

Now that we have discussed some of the points about what one can do with a Public API, here are some points about potential benefits that a public API brings to your existing application.

A Public API gives access to your platform to a huge number of programmers/applications.

  1. Using open standards, they are able to build out applications using your API in ways that even the creators of the API could not have envisioned. And since the public APIs are usually built on Open Standards, they are integrated into a wide range of applications that run on hardware ranging from desktops to mobiles.
  2. In the current market scenario, programmers do not want to build something that is already exposed by the publicly available API and if the API is backed by a scalable and high available environment, they will adopt it.

This article now builds on the premise that you are convinced that a public API will help your already available service. The article now discusses important points that you must consider before you embark on coding out the public API. Each of these points focuses on a theme rather than the implementation details and they are listed in no particular order of importance.

REST v/s Web Services (SOAP)

These are the two predominant models of invoking your API: REST and Web Service. REST is being preferred by most applications today, primarily because of its simplicity and implicit mapping to operations like GET, PUT, POST, etc. It is fair enough to say at this point that you should expose your services via the REST way, even if you have a Web Services (SOAP) mechanism of exposing your services.

Response Data Format (XML, JSON)

Every API call results in data being returned to the calling application. The data could be a result contains data records or in case of update APIs, simply a response text indicating “success” or “failure”. Two formats are predominant here: XML and JSON format. Your API should be flexible that it will allow the caller to specify which format they would like the data response to be sent back. Several APIs of late have been adopting only JSON as the supported data format. The best option over here at this point in time should be to support both if possible.

Service Contract Description

A Service Contract of your API is extremely important. It clearly defines what features your public API provides. This includes:

  1. The different Services and their names
  2. How they are accessible
  3. Authentication mechanisms
  4. Method signature for each method in a Service
  5. Description of each parameter in a method

It is important that you take small steps in the initial release of your API. Do not expose all functionality at once. A preferred approach might be to expose a read-only API that first gives users access to your data and then introduce write-methods that allow users to save their information. Introduce newer methods/functionalities in later versions but release a fairly compact Service Contract in your initial versions. It will help you identify the chinks early enough and help to refactor the existing Service Contact and introduce newer ones.

API Authentication

One need not stress enough about how important it is to make your public API secure. You only want authenticated users to access your public API. There are various strategies and authentication/authorization standards emerging for you to begin with. The most common approach is to issue a API Key for any application that wants to use your public API. This API Key is provided on signing up and is to be provided with every request to your API by the calling application. You can then authenticate the key and also determine if the call is within acceptable Rate Limits (this is covered in a point later) that you have set per API Key.

An authentication standard OAuth is gaining widespread acceptance as a preferred way to allow users to first validate themselves with the Service Providers and then pass a token to the calling application that they have been validated. This removes the need for the calling application to store your users’ username/password with them. A large number of popular public APIs like Twitter have adopted this standard and you should have it on your radar.

Service Versioning

As your service evolves, the public API could also change to match the new features. You need to make sure that you do not break existing clients who have already binded to your existing public API. Enter versioning! Think about versioning your public API right from the first release. If you are using a REST like mechanism that inserting a version number like 1 or v1 might be a good start. With each version, specify clearly what is different, what the additional features are, etc.

Rate Limits

All public APIs should be free to exercise to increase their adoption in the initial phase. Unless you strongly feel that you need to have a paid public API right from Day 1, you should definitely make the public API free to use. However, it is important for it to make business sense at the end of the day. After all, computing resources do cost. An approach typically used by almost all companies is to build in Rate Limits (or Quota Limits) into their public API. Some examples include:

  1. 10,000 calls per day
  2. 1000 calls per hour
  3. 1 GB Free total disk space (This is required in scenarios where you also persist the objects in your cloud as part of the public API)

The rate limits are typically reset at regular intervals like an hour, daily, etc. In certain cases, where you also provide storage space, the disk space quota is fixed at an upper limit and is not typically reset.

No matter what your functionality is, defining the rate limits is important because you will need to build checks in your public API infrastructure.

At the same time, there is a clear possibility that if your application and consequently your public API, is huge successful, then there will be applications which will easily go past your rate limits. That is a good problem to solve. In those scenarios (and you should expect them), you need to think about any of two approaches:

  1. Selectively increase the rate limits for a particular application. You will first need to discuss the requirements with the original creators of the application.
  2. Provide a paid option, where the application buys the increased limit either in tiers that you have set up or on a pay-as-you-go service. The pay-as-you-go service is generally preferred because you may not get the high spikes every single day.

Documentation

It is important to support your public API with strong documentation. Pay attention to every aspect of the documentation. At the minimum, you must document the following clearly:

  1. End Points for different Architectural Styles (REST,WS) along with versioning.
  2. Define all services, methods (actions) and their parameters
  3. Provide sample request / response data formats for each method(action) in your service
  4. Document the error scenarios clearly along with Server side status codes

The best way to get started in documentation is to look at the documentation of existing public APIs. Pick one that suits you and stick to it. Several public APIs even have a RSS Feed about their API documentation to inform about any changes.

Helper Libraries

It is important to envelop your REST/Web Service calls into easy to use helper libraries. Helper Libraries target a number of client programming languages/platforms like Java, Python, Ruby, Javascript, .NET, etc. A Helper library gives a quick starting point to get someone exercising your public API within minutes or hours. A Helper library should address the following (recommended):

  1. Envelope the security calls (Authorization)
  2. Envelope the REST/WS calls and Data Format (XML, JSON) parsing.
  3. Optionally, return the results in Classes defined in the target high level language. For e.g. Java classes, etc.

Dedicated Public API Web page/site

It is strongly recommended to have a companion web site for your Public API. This companion website can serve as a one stop destination for all documentation related to your public API. It can also provide information like:

  1. Signing up for the API and getting issued an API Key
  2. Showcase applications / case studies of how people have used  your public API
  3. List official Helper libraries and contributed Helper libraries that make it easier to use your API.
  4. An API forum where users discuss your API and which your API support engineers can regularly monitor
  5. RSS Feeds that allow people to subscribe to API updates. Providing a “Sign up” for email updates to notify users is also recommended.

I hope this article gives a broad framework about the high level factors that you can consider your Public API release to support. Designing and Development can then commence much more smoothly. There are many other small details to consider, so please share your additional points in the comments for the benefit of all.

References

  1. ProgrammableWeb (http://www.programmableweb.com)
  2. Open APIs: State of the Market, May 2010. John Musser (http://www.slideshare.net/jmusser/pw-glue-conmay2010)
  3. OAuth Protocol Site : http://oauth.net/
Categories: Uncategorized Tags: , , , ,

Google Wave Programming Articles Update

May 31, 2010 1 comment

There were 2 articles posted in Google App Engine experiments blog.

1. Episode 7: Writing your First Google Wave Robot (https://gaejexperiments.wordpress.com/2009/11/04/episode-7-writing-your-first-google-wave-robot/)

2. Episode 11: Develop Simple Google Wave Robots using the WadRobotFramework (https://gaejexperiments.wordpress.com/2009/12/03/episode-11-develop-simple-google-wave-robots-using-the-wadrobotframework/)

I have updated both of these articles. The reasons for updating them are:

1. Google released a newer version of the Robots API : Version 2.0. They have recommended that all Robots written with the earlier API (which the articles covered) should be ported to use the new Version 2.0 API. The older API will be deprecated by end June.

2. WadRobotFramework (http://code.google.com/p/wadrobotframework) has also undergone an update to use the newer version 2.0 of the Robot API internally. Along with that, WadRobotFramework has also introduced several new features including a generator (so you almost end up writing as few lines as possible, the concept of obedience, etc.).

You will find both these articles updated at my new Blog (Google Wave Experiments) that is focused on Google Wave programming. Please find the articles over here:

Episode 1 : Writing your First Google Wave Robot using Robot API v2

Episode 2 : Writing a Wave Robot using WadRobotFramework

Hope you like the articles. I am looking forward to your feedback and want to know what you would like to see covered vis-a-vis Google Wave Programming so that I can conduct my experiments accordingly.

Categories: Uncategorized Tags: ,

Episode 16 : Using the Datastore API

March 17, 2010 8 comments

Welcome to Episode 16. In this episode we shall cover basic usage of the Datastore API in Google App Engine. The Datastore API is used to persist and retrieve data. Google App Engine uses the BigTable database as its underlying datastore and provides abstraction for using it via the Datastore API. There are currently two options available to developers i.e. via the Java Data Objects (JDO) and Java Persistence Architecture (JPA) APIs.

In this episode, we shall cover the following items:

  • Persist a simple record to the datastore using JDO. The intention is to limit it to a single record in this episode and not address relationships and complex structures. That could be the basis of future episodes.
  • Retrieve the persisted records by firing some queries. In the process, we shall see how to create parameterized queries and execute them.
  • Discuss some nuances about indexes and what steps you need to do to make sure that the same application that you use locally will work fine when deployed to the Google App Engine cloud.

The underlying theme will not be to present a comprehensive tutorial about the Datastore API. There are some excellent references available for that. The official documentation and well as the GAE Persistence Blog. The focus will be on getting up and running with the Datastore API ASAP and seeing it work when deployed to the cloud.

What we shall build

In this episode, we shall build the following:

  1. Create a simple Object that we shall persist to the underlying datastore. The Object will be a Health Report and will have about 4-5 attributes that we would like to save.
  2. Write the Save method that takes an instance of the above Health Report Record and persists it using the JDO API.
  3. Write a Search method that will query for several Health Reports using several filter parameters.
  4. Look at the datastore_indexes.xml file that is required when you deploy the application to the cloud.

Please note that the focus will be on the server side and not on building a pretty GUI. All server side actions will be invoked via a REST like request (HTTP GET) — so that we can test the functionality in the browser itself.

Developing our Application

The first thing to do is to create a New Google Web Application Project. Follow these steps:

1. Either click on File –> New –> Other or press Ctrl-N to create a new project. Select Google and then Web Application project. Alternately you could also click on the New Web Application Project Toolbar icon as part of the Google Eclipse plugin.
2. In the New Web Application Project dialog, deselect the Use Google Web Toolkit and give a name to your project. I have named mine GAEJExperiments. I suggest you go with the same name so that things are consistent with the rest of the article, but I leave that to you. In case you are following the series, you could simply use the same project and skip all these steps altogether. You can go straight to the Servlet Development section.
3. Click on Finish.

This will generate the project and also create a sample Hello World Servlet for you. But we will be writing our own Servlet.

Few things to note first:

Quite a few things are enabled for you by default as far as the database support is concerned. They are as follows:

a. Several JAR files are added to the CLASSPATH by default. Take a look and you will see several JARs *jpa*.jar, *datanucleus*.jar, etc.
b. In the src/META-INF folder, you will find a jdoconfig.xml file. There is a default Persistence Manager Factory class in that that we shall be using in the rest of the article. For the purposes of this article we do not need to do anything to this file.
c. GAEJ uses the DataNucleus library to abstract the BigTable store. The DataNucleaus library provides the JDO and JPA interfaces so that you do not have to deal with the underlying low level API. You will also find a logging.properties file present in war/WEB-INF folder. You will find several log levels mentioned for the DataNucleus classes. You can tweak them to lower levels like DEBUG/INFO to see more debug level statements of what happens when you are using these APIs. I have found it very helpful to set the debug levels to DEBUG/INFO especially when facing a problem.

PMF.java

The first class that we shall write is a simple utility class that shall get us the underlying Persistence Manager factory instance. This class is important since all other methods like saving a record, querying records, etc will work on the instance of the PersistenceManagerFactory.

The code is shown below and wherever we need an instance of the class, we shall simply invoke the get() method below:


package com.gaejexperiments.db;

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

public final class PMF {
private static final PersistenceManagerFactory pmfInstance =
JDOHelper.getPersistenceManagerFactory("transactions-optional");

private PMF() {}

public static PersistenceManagerFactory get() {
return pmfInstance;
}
}

HealthReport.java

Next is the Health Report. As mentioned in the beginning of the article, we shall be saving a Health Report record. The Health Report will have 4 attributes and they are explained below:

  1. Key : This is a unique key that is used to persist/identify the record in the datastore. We shall leave its implementation/generation to the Google App Engine implementation.
  2. PinCode : This is similar to a ZipCode. This is a string that shall contain the value of the zipcode (Area) where the Health Incident has occured.
  3. HealthIncident: This is a string value that contains the health incident name. For e.g. Flu, Cough, Cold, etc. In this simple application — we shall be concerned only with 3 health incidents i.e. Flu, Cough and Cold.
  4. Status : This is a string value that specifies if the record is ACTIVE or INACTIVE. Only records with ACTIVE status shall be used in determining any statistics / data reports. We shall set this value to ACTIVE at the time of saving the record.
  5. ReportDateTime : This is a  Date field that shall contain the date/time that the record was created.

Shown below is the listing for the HealthReport.java class. In addition to the above attributes and getter/setter methods for them, note the following additions to make sure that your class can be persisted using JDO.

1. We need to have a constructor that contains all the fields except for the Key field.
2. All fields that need to be persisted are annotated with the @Persistent annotation.
3. The class is declared as being persistable via the @PersistenceCapable annotation and we are leaving the identity to the Application.
4. The Primary Key field i.e. Key is declared via the @PrimaryKey annotation and we are using an available Generator for the ID instead of rolling our own.

package com.gaejexperiments.db;

import java.util.Date;
import com.google.appengine.api.datastore.Key;

import javax.jdo.annotations.IdGeneratorStrategy;
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 HealthReport {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;

private String pinCode;
@Persistent
private String healthIncident;
@Persistent
private String status;
@Persistent
private Date reportDateTime;

public HealthReport(String pinCode, String healthIncident,String status, Date reportDateTime) {
super();
this.pinCode = pinCode;
this.healthIncident = healthIncident;
this.status = status;
this.reportDateTime = reportDateTime;
}

public Key getKey() {
return key;
}

public void setKey(Key key) {
this.key = key;
}

public String getPinCode() {
return pinCode;
}

public void setPinCode(String pinCode) {
this.pinCode = pinCode;
}

public String getHealthIncident() {
return healthIncident;
}

public void setHealthIncident(String healthIncident) {
this.healthIncident = healthIncident;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public Date getReportDateTime() {
return reportDateTime;
}

public void setReportDateTime(Date reportDateTime) {
this.reportDateTime = reportDateTime;
}

}

PostHealthIncidentServlet.java

We shall now look at how to persist the above Health Record. Since we are not going to build a UI for it, we shall simply invoke a servlet (HTTP GET) with the required parameters. It would almost be like a FORM submitting these values to the Servlet. Before we write this Servlet code, let us look at how we will invoke it. Given below is a screenshot of the browser where I punch in the URL : http://localhost:8888/posthealthincident?healthincident=Flu&pincode=400101


As you can see, I am running the application on my local development server and invoke the servlet (which we shall see in a while) providing two key parameters healthincident and pincode. These two parameters are two key fields of the HealthReport class that we saw above. The other fields like ReportDateTime and Status are determined automatically by the application. Similarly the Key value of the record in the underlying datastore will be generated by App Engine infrastructure itself.

Let us now look at the PostHealthIncidentServlet.java code shown below:


package com.gaejexperiments.db;

import java.io.IOException;
import java.util.Date;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.*;
@SuppressWarnings("serial")
public class PostHealthIncidentServlet extends HttpServlet {
public static final Logger _logger = Logger.getLogger(PostHealthIncidentServlet.class.getName());

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}

public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
String strResponse = "";
String strHealthIncident = "";
String strPinCode = "";
try {

//DO ALL YOUR REQUIRED VALIDATIONS HERE AND THROW EXCEPTION IF NEEDED

strHealthIncident = (String)req.getParameter("healthincident");
strPinCode = (String)req.getParameter("pincode");

String strRecordStatus = "ACTIVE";

Date dt = new Date();
HealthReport HR = new HealthReport(strPinCode,
strHealthIncident,
strRecordStatus,
dt);
DBUtils.saveHealthReport(HR);
strResponse = "Your Health Incident has been reported successfully.";
}
catch (Exception ex) {
_logger.severe("Error in saving Health Record : " + strHealthIncident + "," + strPinCode +  " : " + ex.getMessage());
strResponse = "Error in saving Health Record via web. Reason : " + ex.getMessage();
}
resp.getWriter().println(strResponse);
}
}

The main points of the code are :

1) We extract out the HealthIncident and PinCode request parameters. We do not do any particular validations but you could do all of that depending on your application requirement.
2. We generate the two other field values i.e. Date (ReportDate) and Status (ACTIVE).
3. Finally, we create a new instance of the HealthReport class, providing the values in the constructor. And then call the DBUtils.saveHealthReport(…) method that persists the record to the underlying datastore.
4. We display back a successfull message if all is well, which is what was visible in the screenshot above.

Let us look at the DBUtils.java class now. Please note that we have simply separated out the code into this file but you can manage/partition your code in any which way you like.

DBUtils.java

The DBUtils.java source code is listed below. Focus first on the saveHealthReport() method which was invoked by our servlet earlier. The other method, we shall come to that later on in the article.

Key Points are :

1. The saveHealthReport() method first gets the instance of the PersistenceManager through the PMF.java class that we wrote earlier.
2. It simply invoke the makePersistent() method on it. The makePersistent() method will take as a parameter the object that you want to persist. In our case it is the HealthReport.java class instance that we have created in the servlet. This method will persist the record and in the process also assign it a unique key.
3. Finally, we need to close the PersistenceManager instance by invoking the close() method.

The entire code listing is shown below:

package com.gaejexperiments.db;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

public class DBUtils {
public static final Logger _logger = Logger.getLogger(DBUtils.class.getName());

//Currently we are hardcoding this list. But this could also be retrieved from
//database
public static String getHealthIncidentMasterList() throws Exception {
return "Flu,Cough,Cold";
}

/**
* This method persists a record to the database.
*/
public static void saveHealthReport(HealthReport healthReport)
throws Exception {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(healthReport);
_logger.log(Level.INFO, "Health Report has been saved");
} catch (Exception ex) {
_logger.log(Level.SEVERE,
"Could not save the Health Report. Reason : "
+ ex.getMessage());
throw ex;
} finally {
pm.close();
}
}

/**
* This method gets the count all health incidents in an area (Pincode/Zipcode) for the current month
* @param healthIncident
* @param pinCode
* @return A Map containing the health incident name and the number of cases reported for it in the current month
*/
public static Map<String, Integer> getHealthIncidentCountForCurrentMonth(String healthIncident, String pinCode) {
Map<String, Integer> _healthReport = new HashMap<String, Integer>();

PersistenceManager pm = null;

//Get the current month and year
Calendar c = Calendar.getInstance();
int CurrentMonth = c.get(Calendar.MONTH);
int CurrentYear = c.get(Calendar.YEAR);

try {
//Determine if we need to generate data for only one health Incident or ALL
String[] healthIncidents = {};
if (healthIncident.equalsIgnoreCase("ALL")) {
String strHealthIncidents = getHealthIncidentMasterList();
healthIncidents = strHealthIncidents.split(",");
}
else {
healthIncidents =  new String[]{healthIncident};
}

pm = PMF.get().getPersistenceManager();
Query query = null;

//If Pincode (Zipcode) is ALL, we need to retrieve all the records irrespective of Pincode
if (pinCode.equalsIgnoreCase("ALL")) {
//Form the query
query = pm.newQuery(HealthReport.class, " healthIncident == paramHealthIncident && reportDateTime >= paramStartDate && reportDateTime < paramEndDate && status == paramStatus");

// declare parameters used above
query.declareParameters("String paramHealthIncident, java.util.Date paramStartDate, java.util.Date paramEndDate, String paramStatus");
}
else {
query = pm.newQuery(HealthReport.class, " healthIncident == paramHealthIncident && pinCode == paramPinCode && reportDateTime >= paramStartDate && reportDateTime <paramEndDate && status == paramStatus");

// declare params used above
query.declareParameters("String paramHealthIncident, String paramPinCode, java.util.Date paramStartDate, java.util.Date paramEndDate, String paramStatus");
}

//For each health incident (i.e. Cold Flu Cough), retrieve the records

for (int i = 0; i < healthIncidents.length; i++) {
int healthIncidentCount = 0;
//Set the From and To Dates i.e. 1st of the month and 1st day of next month
Calendar _cal1 = Calendar.getInstance();
_cal1.set(CurrentYear, CurrentMonth, 1);
Calendar _cal2 = Calendar.getInstance();
_cal2.set(CurrentYear,CurrentMonth+1,1);

List<HealthReport> codes = null;
if (pinCode.equalsIgnoreCase("ALL")) {
//Execute the query by passing in actual data for the filters
codes = (List<HealthReport>) query.executeWithArray(healthIncidents[i],_cal1.getTime(),_cal2.getTime(),"ACTIVE");
}
else {
codes = (List<HealthReport>) query.executeWithArray(healthIncidents[i], pinCode, _cal1.getTime(),_cal2.getTime(),"ACTIVE");
}

//Iterate through the results and increment the count
for (Iterator iterator = codes.iterator(); iterator.hasNext();) {
HealthReport _report = (HealthReport) iterator.next();
healthIncidentCount++;
}

//Put the record in the Map data structure
_healthReport.put(healthIncidents[i], new Integer(healthIncidentCount));
}
return _healthReport;
} catch (Exception ex) {
return null;
} finally {
pm.close();
}
}
}

Assuming that your application is running, you can view the data records that are being persisted. If you navigate to http://localhost:<YourPort>/_ah/admin in your browser, you will see a screenshot similar to the one shown below:

The screen above shows the Entity types that are currently having some data records. In our case it is the HealthReport entity of which we have saved one record so far. If you click on the List Entities button, you can see the records that are currently persisted for the HealthReport Entity Type. A sample screenshot from my system after saving my first record is shown below:

Go ahead and populate a few more records in the database for different HealthIncidents like Cough, Cold, Flu (only). This is needed so that we can get some more data when we cover how to query persistent data in the next section.

ReportsServlet.java

Before we look at this servlet, let us look at the output that this servlet produces, so that it becomes easier to follow the code later. This is assuming  that you have added atleast 4-5 records using the /posthealthincident servlet that we covered above.

Shown below is the screenshot of the servlet output when I provide the following url:

http://localhost:8888/reports?type=HEALTHINCIDENTCOUNT_CURRENT_MONTH&healthincident=Flu&pincode=ALL
What we are asking for here is a report that gets all health incidents in the current month (type = HEALTHINCIDENTCOUNT_CURRENT_MONTH) for the healthincident = Flu and where pincode = ALL (irrespective of pincode)

Shown below is the screenshot of the servlet output when I provide the following url:

http://localhost:8888/reports?type=HEALTHINCIDENTCOUNT_CURRENT_MONTH&healthincident=ALL&pincode=ALL
What we are asking for here is a report that gets all health incidents in the current month (type = HEALTHINCIDENTCOUNT_CURRENT_MONTH) for the healthincident = ALL (irrespective of health incident which means all of them)  and where pincode = ALL (irrespective of pincode)

So what we have effectively done here is to query the set of Health Records that are present in our database using a variety of parameters (filters). In other words, if we take a SQL like aspect to it, we are saying something like this:

SELECT * FROM HEALTHREPORTS WHERE PINCODE = %1 AND HEALTHINCIDENT = %2 AND REPORTDATE >= %3 AND REPORTDATE < %4 AND STATUS = ACTIVE , etc.

The above SQL statement is just representative of the queries that we want to execute. So let us look at the code for the servlet first.

package com.gaejexperiments.db;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class ReportsServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/xml");
String strResult = "";
String strData   = "";
try {

String type = (String)req.getParameter("type");
if (type == null) {
strResult =  "No Report Type specified.";
throw new Exception(strResult);
}
else if (type.equals("HEALTHINCIDENTCOUNT_CURRENT_MONTH")) {
String strHealthIncident = (String)req.getParameter("healthincident");
String strPinCode = (String)req.getParameter("pincode");
Map<String,Integer> _healthReports = DBUtils.getHealthIncidentCountForCurrentMonth(strHealthIncident,strPinCode);
if (_healthReports == null) {
}
else {
Iterator<String> it = _healthReports.keySet().iterator();
while (it.hasNext()) {
String healthIncident = (String)it.next();
int healthIncidentCount = 0;
Integer healthIncidentCountObject = _healthReports.get(healthIncident);
if (healthIncidentCountObject == null) {
healthIncidentCount = 0;
}
else {
healthIncidentCount = healthIncidentCountObject.intValue();
}
if (healthIncidentCount > 0)
strData += "<HealthIncident><name>" + healthIncident + "</name>" + "<count>" + healthIncidentCount + "</count></HealthIncident>";
}
}
strResult = "<Response><Status>success</Status><StatusDescription></StatusDescription><Result>" + strData + "</Result></Response>";
}
}
catch (Exception ex) {
strResult = "<Response><Status>fail</Status><StatusDescription>"+ "Error in executing operation : " + ex.getMessage() + "</StatusDescription></Response>";
}
resp.getWriter().println(strResult);
}

} </pre>
<pre>

The Servlet code is straightforward:

1. Currently it has only one type of report i.e. HEALTHINCIDENTCOUNT_CURRENT_MONTH
2. Next we extract out the Pincode and the HealthIncident request parameter values.
3. Then we invoke the DBUtils.getHealthIncidentCountForCurrentMonth method. This takes two parameters : pincode and healthincident that we have got from above step.
4. The method will return us a map where each record in the map will contain the key (String) containing the healthincident name and the value containing the count of incidents reported for that month. So something like [ {“Flu”,”20″} , {“Cough”, “30”} ,  {“Cold”,”10″} ]
5. Finally we simply format that into a XML output so that it can be returned to the client. And this is the exact output that we see in the browser.

Analyzing the DBUtils.getHealthIncidentCountForCurrentMonth method

I reproduce here the method from the DBUtils.java class that was listed before:


/**
* This method gets the count all health incidents in an area (Pincode/Zipcode) for the current month
* @param healthIncident
* @param pinCode
* @return A Map containing the health incident name and the number of cases reported for it in the current month
*/
public static Map<String, Integer> getHealthIncidentCountForCurrentMonth(String healthIncident, String pinCode) {
Map<String, Integer> _healthReport = new HashMap<String, Integer>();

PersistenceManager pm = null;

//Get the current month and year
Calendar c = Calendar.getInstance();
int CurrentMonth = c.get(Calendar.MONTH);
int CurrentYear = c.get(Calendar.YEAR);

try {
//Determine if we need to generate data for only one health Incident or ALL
String[] healthIncidents = {};
if (healthIncident.equalsIgnoreCase("ALL")) {
String strHealthIncidents = getHealthIncidentMasterList();
healthIncidents = strHealthIncidents.split(",");
}
else {
healthIncidents =  new String[]{healthIncident};
}

pm = PMF.get().getPersistenceManager();
Query query = null;

//If Pincode (Zipcode) is ALL, we need to retrieve all the records irrespective of Pincode
if (pinCode.equalsIgnoreCase("ALL")) {
//Form the query
query = pm.newQuery(HealthReport.class, " healthIncident == paramHealthIncident && reportDateTime >= paramStartDate && reportDateTime < paramEndDate && status == paramStatus");

// declare parameters used above
query.declareParameters("String paramHealthIncident, java.util.Date paramStartDate, java.util.Date paramEndDate, String paramStatus");
}
else {
query = pm.newQuery(HealthReport.class, " healthIncident == paramHealthIncident && pinCode == paramPinCode && reportDateTime >= paramStartDate && reportDateTime <paramEndDate && status == paramStatus");

// declare params used above
query.declareParameters("String paramHealthIncident, String paramPinCode, java.util.Date paramStartDate, java.util.Date paramEndDate, String paramStatus");
}

//For each health incident (i.e. Cold Flu Cough), retrieve the records

for (int i = 0; i < healthIncidents.length; i++) {
int healthIncidentCount = 0;
//Set the From and To Dates i.e. 1st of the month and 1st day of next month
Calendar _cal1 = Calendar.getInstance();
_cal1.set(CurrentYear, CurrentMonth, 1);
Calendar _cal2 = Calendar.getInstance();
_cal2.set(CurrentYear,CurrentMonth+1,1);

List<HealthReport> codes = null;
if (pinCode.equalsIgnoreCase("ALL")) {
//Execute the query by passing in actual data for the filters
codes = (List<HealthReport>) query.executeWithArray(healthIncidents[i],_cal1.getTime(),_cal2.getTime(),"ACTIVE");
}
else {
codes = (List<HealthReport>) query.executeWithArray(healthIncidents[i], pinCode, _cal1.getTime(),_cal2.getTime(),"ACTIVE");
}

//Iterate through the results and increment the count
for (Iterator iterator = codes.iterator(); iterator.hasNext();) {
HealthReport _report = (HealthReport) iterator.next();
healthIncidentCount++;
}

//Put the record in the Map data structure
_healthReport.put(healthIncidents[i], new Integer(healthIncidentCount));
}
return _healthReport;
} catch (Exception ex) {
return null;
} finally {
pm.close();
}
}

I have attempted to provide comments so that you can follow the code but I will list down the important parts here:

1. We are going to deal with the following classes : PersistenceManager and Query from the javax.jdo package.
2. We get the PersistenceManager instance via the PMF.java class that we wrote earlier.
3. We are using the Query class here to first build the query. For e.g.
query = pm.newQuery(HealthReport.class, ” healthIncident == paramHealthIncident && reportDateTime >= paramStartDate && reportDateTime < paramEndDate && status == paramStatus”);

What this means is that we are creating a query instance where we wish to get all records for the HealthReport class. Additionally we are passing a criteria string. Notice that the lefthand side are the fields of the HealthReport class (healthIncident, reportDateTime, status) and the right hand side are parameters which will define and then pass the values for to execute the query.

4. We define the parameters next as shown below:
// declare parameters used above
query.declareParameters(“String paramHealthIncident, java.util.Date paramStartDate, java.util.Date paramEndDate, String paramStatus”);
5. Finally we use the query.executeWithArray(…) method which takes as parameter an array that contains all the values for the above parameters that you have declared.
6. The executeWithArray(…) will return a List<> of HealthReport class instances that you can then iterate through the populate your result. In our code, we simply compute the total number for each of the health incidents (Flu, Cough, Cold).

Servlet Configuration

To complete our Servlet development, we will also need to add the <servlet/> and <servlet-mapping/> entry to the web.xml file. This file is present in the WEB-INF folder of the project. The necessary fragment to be added to your web.xml file are shown below. Please note that you can use your own namespace and servlet class. Just modify it accordingly if you do so.

<servlet>
<servlet-name>PostHealthIncidentServlet</servlet-name>
<servlet-class>com.gaejexperiments.db.PostHealthIncidentServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>ReportsServlet</servlet-name>
<servlet-class>com.gaejexperiments.db.ReportsServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PostHealthIncidentServlet</servlet-name>
<url-pattern>/posthealthincident</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ReportsServlet</servlet-name>
<url-pattern>/reports</url-pattern>
</servlet-mapping>

Running the application locally

I am assuming that you have already created a new Google Web Application Project and have created the above Servlets, web.xml , etc. So assuming that all is well, we will run our application, by right-clicking on the project and selecting Run As –> Web Application. Launch the browser on your local machine and try out the URLs that we have covered so far like :

1. Adding a Health Report record :

http://localhost:8888/posthealthincident?healthincident=Flu&pincode=400101

2. Reports

http://localhost:8888/reports?type=HEALTHINCIDENTCOUNT_CURRENT_MONTH&healthincident=Flu&pincode=ALL

http://localhost:8888/reports?type=HEALTHINCIDENTCOUNT_CURRENT_MONTH&healthincident=ALL&pincode=ALL

Please replace the port 8888 with your local port number.

datastore_indexes.xml

If you run your application locally, you will notice that everything is working fine. However, if you deploy this application the Google App Engine, you will not get any results where you query the reports. Why is that? It is because there are no indexes defined for your application.

If you visit your Developer Console at http://appengine.google.com and for your particular application, you will find no indexes are defined for the Datastore indexes link as shown below:

What are these indexes ? Indexes are generated for every possible query that you fire in your program. This is Google’s way of retrieving your data results efficiently. However when you run in local mode, these indexes are generated for your automatically. If you look in war/WEB-INF directory, you will find a directory named appengine-generated. Inside this directory is a file that is constantly updated called datastore-indexes-auto.xml. The contents of this file for the reports that we have run so far is shown below:


<datastore-indexes>

<datastore-index kind="HealthReport" ancestor="false" source="auto">
<property name="healthIncident" direction="asc"/>
<property name="status" direction="asc"/>
<property name="reportDateTime" direction="asc"/>
</datastore-index>

<datastore-index kind="HealthReport" ancestor="false" source="auto">
<property name="healthIncident" direction="asc"/>
<property name="pinCode" direction="asc"/>
<property name="status" direction="asc"/>
<property name="reportDateTime" direction="asc"/>
</datastore-index>

</datastore-indexes>

As you can see, there are two indexes generated for the searches that we fired and each of them contains the parameters that we queried the Health Reports on.

To get your deployed application to function correctly, you will need to copy these indexes to a file named datastore_indexes.xml.

You  will need to place this file in the war/WEB-INF folder of your application project.

Now deploy your project again. On successful deploy, revist the Developer Console –> Datastore indexes. You will find that the indexes have got created and are buing built as shown below:

Wait for a while. The building process goes through your current data and then on completion, you will see the screen as shown below (A refresh needed!):

Try out the queries now on your deployed application and they should work fine. You can also manual create the datastore_indexes.xml file but the local development server has this nice feature of auto generating out for you, so that you dont end up making mistakes. But remember to upload the updated datastore_indexes.xml as part of  your deployment others the queries will silently fail.

Conclusion

We conclude this episode in which we covered how you can persist and query data using the JDO API. I hope that it has given you enough inputs to start incorporating persistence into your applications. It is by no means a simple exercise especially if you are coming in from a SQL world. Not everything SQL-like can be converted as is to a NoSQL world so refer to the several excellent sources available on the web in your persistence journey. I highly recommend the official documentation along with the GAE Persistence Blog mentioned at the beginning of the article.

Categories: Uncategorized Tags:

GAEJ Experiments eBook

March 9, 2010 Leave a comment

It has been about a week now that I have released the GAEJ Experiments eBook. I am pleased to announce that it has been downloaded around 3500 times this past week.

To recap, the GAEJ Experiments eBook contains

  • All 15 episodes published at the site
  • A Bonus Chapter 16: Using the Datastore API

I thank all readers and my friends who made production of the eBook possible.

Download the eBook and distribute. It is free of cost.

Download it here.

If you like the book and wish to donate, there is a Donate button on the right. All proceeds will be given 100% to http://www.kiva.org to a charity of my choice.

I thank you once again for your support and hope to continue with more experiments. Work on version 2.0 has already begun …

Cheers
Romin

Categories: Uncategorized

Episode 15: Using a CAPTCHA in your Google App Engine Application

February 22, 2010 4 comments

Welcome to Episode 15. In this episode, we shall cover how to incorporate a CAPTCHA in your application. The CAPTCHA solution that I will be demonstrating over here is the ReCAPTCHA project found here. To quote from its Wikipedia entry, a CAPTCHA is a type of challenge-response test used in computing to ensure that the response is not generated by the computer. Usually, one sees one or two words shown to us that we need to enter and they need to match before our request submission is accepted by the server.   

See it in Action

  

Let us first see the application that we shall be developing in its final form. The main screen is a dummy form that accepts one field and displays the CAPTCHA to the user as shown below:   

   

If the CAPTCHA response is entered correctly and the submit button is clicked, the response is sent to the server. The server side validates the CAPTCHA challenge-response and will display an “all is well” message as shown below:   

   

If the CAPTCHA response is not entered correctly, the server side will display an “all is not well” message as shown below:   

   

ReCAPTCHA Project

  

We shall be using the ReCAPTCHAProject present at http://recaptcha.net/. The ReCAPTCHAproject is comprehensive and provides support for a variety of server side platforms, hence I have gone with it. I do not have a particular preference for it, except that most people recommended this to me and hence I decided to try it out. I was able to integrate it easily and quickly into a recent App Engine application that is currently live, so I can vouch for its ease of integration and which is what I shall demonstrate in this experiment.
 
To get started with ReCAPTCHA, we need to do 2 things:   

1. Get your private/public keys for the site name hat your application will be running on.

  

Follow these steps:   

  1. First get yourself a ReCAPTCHAaccount. Go to http://recaptcha.net/whyrecaptcha.html and click on the Sign up Now! button.
  2. This will bring up a login form, but you click on the “New to reCaptcha? Sign up” link. Here you can register by giving a username/password/email . Click on the Sign up now button.
  3. On successful registration, you will signed in automatically and led to a Create a reCAPTCHA key page. Here you need to enter the site name that you will be using ReCAPTCHAon. Remember you can get ReCAPTCHAkeys for more than 1 site and you can manage it all from your account itself. For e.g. you can get a key for localhost since that will be what we need to test on first before deploying to the Google App Engine cloud. And then you will atleast need one based on the Application ID of your Google App Engine application. So for e.g. if my application ID is gaejexperiments, then my full site url is http://gaejexperiments.appspot.com. So you will need to enter gaejexperiments.appspot.com in the Domain form field.
  4.  Click on Create Key. For e.g. shown below is the series of screens that I got when I wanted keys for localhost. You will need to do the same if you wish to test the code first on your local system i.e. localhost.

  

    

Then when you click Create Key, you will be presented the Public Key and Private Key as shown below:   

   

Please note down the Public and Private Key since you will need to use them in your application. The usage is straightforward and mentioned on the screen and I will be repeat it here:   

  • Use the Public Key in your HTML page (Javascript) to communicate with the ReCAPTCHA server to get the challenge (image).
  • Use the Private Key in your server side Java code that will be used to communicate with the Server to verify the challenge + response submitted by the form in the above step.

2. Download the JAR file that we shall be using at the Server side to verify the CAPTCHA challenge and response.

  

To do the server side validation, you need to download a JAR  file that is available from the following url : http://code.google.com/p/recaptcha/downloads/list?q=label:java-Latest. Go to the URL and you shall be presented with a screen as shown below:   

   

The JAR file is required and it encapsulates all communication between our application and the ReCAPTCHA Servers.   

Download the zip file, expand it in  an appropriate folder and you will find the recaptcha4j-0.0.7.jar present in that.  We will need it later on to be referenced in your App Engine Eclipse Project.   

Developing our Application

  

The first thing to do is to create a New Google Web Application Project. Follow these steps:   

1. Either click on File –> New –> Other or press Ctrl-N to create a new project. Select Google and then Web Application project. Alternately you could also click on the New Web Application Project Toolbar icon as part of the Google Eclipse plugin.
2. In the New Web Application Project dialog, deselect the Use Google Web Toolkit and give a name to your project. I have named mine GAEJExperiments. I suggest you go with the same name so that things are consistent with the rest of the article, but I leave that to you. In case you are following the series, you could simply use the same project and skip all these steps altogether. You can go straight to the Servlet Development section.
3. Click on Finish.   

This will generate the project and also create a sample Hello World Servlet for you. But we will be writing our own Servlet.   

Add the recaptcha4j-0.0.7.jar file to your Project classpath

  

The recaptcha4j-0.0.7.jar file that we downloaded needs to be added to the runtime and compile time CLASSPATH of your App Engine Eclipse Project. Follow these steps:
a) Copy recaptcha4j-0.0.7.jar to the WEB-INF\lib folder of your project. This folder is present in the war sub folder of your main project structure.
b) Go to Project properties –> Java Build Path and reference the JAR file (recaptcha4j-0.0.7.jar) in the Java Build Path of your application as shown below:   

   

The Front end HTML form [captcha.html]

<html xmlns="<a href="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>" lang="en" xml:lang="en">
<head>
 <title>ReCaptcha Integration</title>
<script type="text/javascript" src="<a href="http://api.recaptcha.net/js/recaptcha_ajax.js%22%3E%3C/script">http://api.recaptcha.net/js/recaptcha_ajax.js"></script</a>>
<script type="text/javascript">
 function PreloadCaptcha() {
  showRecaptcha();
 }
   

function showRecaptcha() {
    Recaptcha.create("YOUR_PUBLIC_KEY", "dynamic_recaptcha_1", {
          theme: "white",
          callback: Recaptcha.focus_response_field
    });
  }  

 
 var xmlhttp;
 function submitFormData(name)
 {  

 //alert("Message");
 xmlhttp=null;
 if (window.XMLHttpRequest)
   {// code for IE7, Firefox, Opera, etc.
   xmlhttp=new XMLHttpRequest();
   }
 else if (window.ActiveXObject)
   {// code for IE6, IE5
   xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
   }
 if (xmlhttp!=null)
   {
   xmlhttp.onreadystatechange=state_Change;
   var url = "postformdata";
   var params = "name="+name+"&recaptcha_challenge_field=" + Recaptcha.get_challenge() + "&recaptcha_response_field="+Recaptcha.get_response();
   var status = document.getElementById("status");
   status.innerHTML = "<img src='img/ajax-loader.gif'><b>Submitting your data. Please wait...</b>";
   xmlhttp.open("POST",url,true);
   xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
   xmlhttp.setRequestHeader("Content-length", params.length);
   xmlhttp.setRequestHeader("Connection", "close");  
   xmlhttp.send(params);
   }
 else
   {
   alert("Your browser does not support XMLHTTP.");
   }
 }
 
 function state_Change()
 {
 if (xmlhttp.readyState==4)
   {// 4 = "loaded"
   if (xmlhttp.status==200)
     {
     // 200 = "OK"
    var status = document.getElementById("status");
    status.innerHTML = xmlhttp.responseText;;
    Recaptcha.reload();
    setTimeout(function() {
      status.innerHTML = "";
    }, 3000);   
     }
   else {
    var status = document.getElementById("status");
    status.innerHTML = xmlhttp.responseText;;
    Recaptcha.reload();
    setTimeout(function() {
      status.innerHTML = "";
    }, 3000);   
   }
   }
 }
 </script>
</head>  

<body onload="PreloadCaptcha()">
       <FORM NAME="dataform">
       <TABLE>
     <TR>
     <TD><b>Your name:</b></TD>
     <TD><INPUT NAME="txtName"/></TD>
     </TR>
     <TR>
     <TD colspan="2"><div id="dynamic_recaptcha_1"></div></TD>
     </TR>
     <TR>
                    <TD colspan="2"><INPUT type="button" value="Submit Data" name="btnSubmitData" onClick="submitFormData(txtName.value); return true"></TD>
                    </TR>
                    <TR>
     <TD colspan="2"><div id="status"/></TD>
     </TR>
       </TABLE>
       </FORM>
</body>
</html>  

Let us go through the important parts of the code:  

1. The first part to notice is that I have referenced the javascript file for the ReCAPTCHA code as shown :

<script type="text/javascript" src="http://api.recaptcha.net/js/recaptcha_ajax.js"></script>
 

2. There is a javascript function call being made on the load of the body (<body onload=”PreloadCaptcha()”>). This invokes the function showRecaptcha() that is shown below:

Recaptcha.create("YOUR_PUBLIC_KEY", "dynamic_recaptcha_1", {
          theme: "white",
          callback: Recaptcha.focus_response_field
    });

 

The Recaptcha class is available from the javascript file and we use the create method. The first parameter is the PUBLIC_KEY that you get when you registered at ReCaptcha for  your site name. If you are testing it locally, this will be the Public Key for your localhost site. The second parameter is a DIV element that is present in the form.

The create() method on successful invocation will populate the DIV element with the CAPTCHA challenge/response fields.

3. The rest of the code is standard AJAX stuff. The submit button invokes the submitDataForm()  that does the following: 

  • It will invoke the URL : /postformdata that will be our servlet that does the verification. The servlet code is discussed in the next section
  • It will form the request parameter string as shown below:
    var params = “name=”+name+”&recaptcha_challenge_field=” + Recaptcha.get_challenge() + “&recaptcha_response_field=”+Recaptcha.get_response();
  • Note the two fields : recaptcha_challenge_field and recaptcha_challenge_response_field. We get the two values from the Recaptcha class methods, get_challenge() and get_response() respectively. The get_challenge() is what was provided by the ReCAPTCHA Server and the get_response() is what was entered by the user.
  • Finally we do a POST to the server and collect the response. The response is that displayed in another DIV element “status”.

Please note that the code is just for demonstration purpose and may not represent the best practices or most efficient way of writing JavaScript, AJAX, etc.

The Servlet [PostFormDataServlet.java]

 

package com.gaejexperiments.captcha; 

import java.io.IOException; 

import javax.servlet.http.*; 

//RECAPTCHA
import net.tanesha.recaptcha.ReCaptchaImpl;
import net.tanesha.recaptcha.ReCaptchaResponse; 
@SuppressWarnings("serial")
public class PostFormDataServlet extends HttpServlet {
 
 public void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws IOException {
  resp.setContentType("text/plain");
  String strResponse = "";
  try {
   
/*
 * CAPTCHA CHECK
 *
 *
 */
   //First validate the captcha, if not -- just get out of the loop
   String challenge = (String) req.getParameter("recaptcha_challenge_field");
   String response = (String) req.getParameter("recaptcha_response_field");
   if ((challenge == null) || (response == null)) {
    throw new Exception("Your words did not match. Please try submitting again.");
   }
   
      String remoteAddr = req.getRemoteAddr();
      ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
     
      reCaptcha.setPrivateKey("YOUR_PRIVATE_KEY");
     
      ReCaptchaResponse reCaptchaResponse =
          reCaptcha.checkAnswer(remoteAddr, challenge, response);
     
      if (!reCaptchaResponse.isValid()) {
       //RECAPTCHA VALIDATION FAILED
       throw new Exception("Your words did not match. Please try submitting again.");
      }
   
      strResponse = "Your record has been accepted and you did a good job entering the two words. Thank you";
  }
  catch (Exception ex) {
   strResponse = "You record was not accepted. Reason : " + ex.getMessage();
  }
  resp.getWriter().println(strResponse);
 }
}

Let us go through the important parts in the code:  

1. Notice that we are importing  2 classes : net.tanesha.recaptcha.ReCaptchaImpl and net.tanesha.recaptcha.ReCaptchaResponse at the beginning. These are the implementation classes that encapsulate the verification with the ReCAPTCHA Server and the response from the ReCAPTCHA Server respectively.  

2. We first extract out the challenge and the response fields as passed by our form.  

String challenge = (String) req.getParameter("recaptcha_challenge_field");
String response = (String) req.getParameter("recaptcha_response_field");

3. We also need the Remote IP Address that is making the request.  

String remoteAddr = req.getRemoteAddr();

4. We then instantiate an instance of the ReCaptchaImpl class. We set the Private Key that we got during our registration for the site localhost. Please use your key over here. And then we make a call to their server by invoking the checkAnswer method. The checkAnswer method takes 3 parameters : challenge, response and the Remote Address.  

      ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
     
      reCaptcha.setPrivateKey("YOUR_PRIVATE_KEY");
     
      ReCaptchaResponse reCaptchaResponse =
          reCaptcha.checkAnswer(remoteAddr, challenge, response);

5. We will receive an instance of the ReCaptchaResponse class. We simply use a utility method isValid() to determine if the response entered for the challenge was correct. And depending on that we send back an appropriate response back to the browser, which is then displayed to the user.  

Servlet Configuration

To complete our Servlet development, we will also need to add the <servlet/> and <servlet-mapping/> entry to the web.xml file. This file is present in the WEB-INF folder of the project. The necessary fragment to be added to your web.xml file are shown below. Please note that you can use your own namespace and servlet class. Just modify it accordingly if you do so.   

<servlet>
<servlet-name>PostFormDataServlet</servlet-name>
<servlet-class>com.gaejexperiments.captcha.PostFormDataServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PostFormDataServlet</servlet-name>
<url-pattern>/postformdata</url-pattern>
</servlet-mapping>

Running the application locally

I am assuming that you have already created a new Google Web Application Project and have created the above Servlets, web.xml , etc. We shall be running this episode within our local development server only since the keys that I have used are for localhost. Before you deploy the application to the actual Google App Engine infrastructure using your Application ID, do remember to get yourself the appropriate public/private ReCAPTCHA keys for your site name.  

So assuming that all is well, we will run our application, by right-clicking on the project and selecting Run As –> Web Application. Launch the browser on your local machine and navigate to http://localhost:<YourLocalPort>/captcha.html  

Conclusion

In this episode, we saw how to incorporate a CAPTCHA in our Google App Engine application. Please remember that you will need to determine if you really need a CAPTCHA in your application. There are some good points mentioned in this article on various other techniques that can be used to address the same problems.   

Till the next episode ….

Categories: Uncategorized

Episode 14: Writing a Chrome Extension powered by App Engine

December 31, 2009 7 comments

Welcome to Episode 14. In this episode we shall cover how you can get started with writing Google Chrome Extensions. We shall also drive the Extension via our App Engine application. We have already seen in earlier episodes how your App Engine applications participated within Google Wave, Google Talk, etc. So this episode takes it further and shows how you can write a Google Chrome Extension whose data will be provided by our App Engine Application.

Google Chrome Extension

Google Chrome browser since its release has got a fair amount of developer mind share. Recently they addressed extensibility of the Chrome browser by announcing support for writing your own extensions. So the focus is now on the developer to take this extension mechanism, harness it and produce some great extensions that extend the capabilities of the browser. You can read here the official announcement for Extension support over here.

Google Chrome Dev Channel version

Note: The first thing that you need to do is download a copy of the Chrome Browser from their Dev Channel because extensions are currently supported there till they come into the mainstream release. So given that, make sure that you download that version of Google Chrome browser.

The Beta channel or the Dev channel is available at : http://www.chromium.org/getting-involved/dev-channel.

Depending on your Operation System, download the appropriate version and install it. To check that you have extension enabled correctly, launch the Chrome Browser and click on the Settings icon as shown below. You should see the Extensions menu item available.

It is a good idea to take a look at the existing Chrome Extensions gallery that lists several excellent extensions that you can start using today inside of your Google Chrome browser. The gallery is available at Gallery : https://chrome.google.com/extensions. This page also contains a link where you can submit your extension too for the world to use!

See it in Action

Let us see our Google Chrome Extension that we shall build in this episode. The extension is a simple Reminder application. It shows the current Reminders that you have set up for the month. All the data is saved and managed by our App Engine application and the Chrome Extension simply requests and fetches the data for the current month.

Shown below is the Chrome Browser screen with our Extension available as a little red icon in the Toolbar.

When we click the icon, it will fetch the reminders that I have setup in the current month (December) and display them as shown below:

Sounds good? We shall split up the details into two parts:

Part I : The first part will deal with developing/deploying our Server side application. This application will be deployed as a Google App Engine Java application. We shall keep the implementation simple and not do any database operations, etc. The focus is on the second part where we need to understand what it takes to get a simple Chrome Extension up and running, and which is powered by this Google App Engine application.

Part II: The second part will deal with how you can write a Google Chrome Extension. We will consider the bare minimum that you need to do to get your extension working. I will leave the design and look/feel aspects to you.

Alright then, let’s get started.

Developing our Java Web Application  : MyReminderApp

The first thing to do is to create a New Google Web Application Project. Follow these steps:

1. Either click on File –> New –> Other or press Ctrl-N to create a new project. Select Google and then Web Application project. Alternately you could also click on the New Web Application Project Toolbar icon as part of the Google Eclipse plugin.

2. In the New Web Application Project dialog, deselect the Use Google Web Toolkit and give a name to your project. I have named mine MyReminderApp. I suggest you go with the same name so that things are consistent with the rest of the article.

3. Click on Finish. This will generate the project and also create a sample Servlet named MyReminderAppServlet for you. We shall be modifying this Servlet code appropriately.

Design discussion

Now that the project template is ready, let me discuss in brief what we shall be building:

1. A simple Reminder App that contains a list of Reminders. Each Reminder is kept simple and has 3 attributed only: The day, month and the description. For e.g. [25,12,Christmas Day], [19,12,My Birthday], [1,1,New Year Day], [31,7,Pay Taxes] and so on.

2. So we will define a Reminder.java class that simply has getter/setters for the 3 attributes : day, month and description

3. We will then write a ReminderService.java class (A Singleton) that implements two simple functions:

  • ArrayList<Reminder> findRemindersByMonth(String month)
    This method returns the reminders for a particular month. We pass in “1” and we get reminders defined for January, etc.
  • ArrayList<Reminder> findCurrentMonthReminders()
    This method returns the reminders for the current month. The method determines which month is currently on and retrieves reminders for that month only. And this is precisely the method that will be invoked when our extension asks for the current reminders.

4. Finally, we shall modify the MyReminderAppServlet.java so that it implements a simple REST like interface for retrieving the reminders. If the request stream contains a parameter named month, then the reminders will be returned for that month by invoking the findRemindersByMonth method. If the request stream does not contain a parameter named month, then the current month reminders will be returned by invoking the findCurrentMonthReminders() method. The response will be returned in XML format.

Given next are the code listings, that should be straight forward to understand now:

Reminder.java

package com.reminderapp;

public class Reminder {

private String day;
private String month;
private String event;


public Reminder(String day, String month, String event) {
super();
this.day = day;
this.month = month;
this.event = event;
}
public String getDay() {
return day;
}
public void setDay(String day) {
this.day = day;
}
public String getMonth() {
return month;
}
public void setMonth(String month) {
this.month = month;
}
public String getEvent() {
return event;
}
public void setEvent(String event) {
this.event = event;
}
}

The Reminder class simply has 3 attributes : day , month and year. There are getter/setter for each of these attributes and a constructor that takes in all the 3 attributes. We are keeping at as String for now to keep things simple.

ReminderService.java

package com.reminderapp;

import java.util.ArrayList;
import java.util.Calendar;

public class ReminderService {

private static ReminderService _instance = null;

private ArrayList<Reminder> _reminderList = null;

private ReminderService() {
initializeData();
}

public static ReminderService getInstance() {
if (_instance == null) {
_instance = new ReminderService();
}
return _instance;
}

public ArrayList<Reminder> findRemindersByMonth(String month) {
ArrayList<Reminder> _results = new ArrayList<Reminder>();
for (Reminder reminder : _reminderList) {
if (reminder.getMonth().equals(month)) {
_results.add(reminder);
}
}
return _results;
}

public ArrayList<Reminder> findCurrentMonthReminders() {
ArrayList<Reminder> _results = new ArrayList<Reminder>();
String currentMonth = "" + (Calendar.getInstance().get(Calendar.MONTH)+1);
for (Reminder reminder : _reminderList) {
if (reminder.getMonth().equals(currentMonth)) {
_results.add(reminder);
}
}
return _results;
}

private void initializeData() {
_reminderList = new ArrayList<Reminder>();
Reminder R1 = new Reminder("1","1","New Year Day");
Reminder R2 = new Reminder("26","1","Republic Day");
Reminder R3 = new Reminder("15","8","Independence Day");
Reminder R4 = new Reminder("25","12","Christmas Day");
Reminder R5 = new Reminder("31","12","New Year Eve");

_reminderList.add(R1);
_reminderList.add(R2);
_reminderList.add(R3);
_reminderList.add(R4);
_reminderList.add(R5);

}

}

The ReminderService is a singleton class. And we are initializing some data here via the initializeData() call. We are not complicating things by using a database here but this is something that should ideally be there in a real application. As you can notice we add 5 sample records and for the current month i.e. December (12), we have two events. The two methods findRemindersByMonth and findCurrentMonthReminders are straightforward in which it goes through the reminderList and matches the records as appropriate.

MyReminderAppServlet.java

package com.reminderapp;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.http.*;

@SuppressWarnings("serial")
public class MyReminderAppServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/xml");
//resp.getWriter().println("Hello, world");

String month = (String)req.getParameter("month");
ArrayList<Reminder> _results = null;
if (month == null) {
_results = ReminderService.getInstance().findCurrentMonthReminders();
}
else {
_results = ReminderService.getInstance().findRemindersByMonth(month);
}

StringBuilder SB = new StringBuilder();
SB.append("<?xml version=\"1.0\"?>");
SB.append("<ReminderList>");
for (Reminder reminder : _results) {
SB.append("<Reminder>"+reminder.getDay()+"/"+reminder.getMonth()+" : " + reminder.getEvent()+"</Reminder>");
}
SB.append("</ReminderList>");
resp.getWriter().println(SB.toString());
}
}

Let us go through the code for the MyReminderAppServlet in brief:

1. It implements the doGet(…) method and inspects if a request parameter named month is passed or not.

2. If the month parameter is passed, its value is extracted and the findRemindersByMonth method is invoked. Else the findCurrentMonthReminders is invoked.

3. The result is then formatted into a simple XML structure and then it is returned back in the response stream.

Configuring the Servlet

We need to make sure that the entry for  <servlet/> and <servlet-mapping/> in the web.xml file. is there for MyReminderAppServlet. This file is present in the WEB-INF folder of the project. The necessary fragment to be added to your web.xml file are shown below.

<servlet>
<servlet-name>MyReminderApp</servlet-name>
<servlet-class>com.reminderapp.MyReminderAppServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyReminderApp</servlet-name>
<url-pattern>/myreminderapp</url-pattern>
</servlet-mapping>

Deploying the Application

To deploy the application, you will need to first create your Application ID. The Application Identifier can be created by logging in at http://appengine.google.com with your Google Account. You will see a list of application identifiers already registered under your account (or none if you are just getting started). To create a new Application, click on the Create Application button and provide the Application Identifier as requested. Please note this name down since you will be using it for deployment.

For e.g. I have registered an application identifier named itsareminder.

To deploy the application, follow these steps (they should be familiar to you now):

  1. Click on the Deploy Icon in the Toolbar.
  2. In the Deploy dialog, provide your Email and Password. Do not click on Deploy button yet.
  3. Click on the App Engine Project settings link. This will lead you to a dialog, where you need to enter your Application ID [For e.g. my Application Identifier itsareminder]
  4. Click on OK. You will be lead back to the previous screen, where you can click on theDeploy button. This will start deploying your application to the GAEJ cloud. You should see several messages in the Console window as the application is being deployed.
  5. Finally, you should see the message “Deployment completed successfully”.

Testing our Reminder Service

To test our Reminder Service, we can use the http://<AppId>.appspot.com/myreminderapp URL. You can replace it with your AppId and endpoint as appropriate to your application. For e.g. I have hosted it at http://itsareminder.appspot.com/myreminderapp and putting this in the browser returns me the Reminders that are set for the current Month i.e. Month of December. I get the following response XML:

<ReminderList><Reminder>25/12 : Christmas Day</Reminder><Reminder>31/12 : New Year Eve</Reminder></ReminderList>

Now that the development of the Reminder Service is complete, we can move on to the next part i.e. developing the Chrome Extension.

Developing the Reminder Service Chrome Extension

The official documentation on developing a Chrome Extension is quite good and you can refer it for more details. I will keep things to a minimum here and cover only what is required to get the Chrome Extension up and running. Follow these steps:

1. Create a folder on your machine. For e.g. I have created the following folder on my machine in C:\. It is c:\MyReminderExtension. All the necessary files that we create for the extension will reside in this folder.

2. To create an extension, we need at the minimum 3 files. The three files are an icon file for your extension. This icon will be visible in the toolbar as we saw earlier. The second file is a manifest file called manifest.json. The manifest provides important metadata about the extension like name,version, permissions, action, etc. And the final file is the html file in which you will keep the core of your extensions code written in Javascript.

3. So the first thing that I do is to create a manifest file for the extension. The manifest.json file for the Reminder Service is shown below:

{
"name": "My Reminder Extension",
"version": "1.0",
"description": "Reminders based on month",
"browser_action": {
"default_icon": "myreminder.png",
"popup": "reminder.html"
},
"permissions": [
"http://itsareminder.appspot.com/"
]
}

As you can see this is pretty simple. There is the standard name/version/description that you can give as per your preferences. The browser_action has two important attributes. The default_icon refers to the icon file that contains the icon for our extension. So this means that we will have the myreminder.png file present in the same folder. The popup attribute indicates which HTML file to be invoked when the icon is clicked. The permissions attribute indicates which domain the extension will be accessing to retrieve the data. In our case it is the http://itsareminder.appspot.com domain at which we hosted our application.

4. As shown above, we will create a file named myreminder.png in the same folder i.e. C:\MyReminderExtension.

5. Finally, we have the reminder.html file that will contain the code of the extension. It is listed below:


<style>
body {
min-width:200px;
overflow-x:hidden;
}

</style>

<script>
var req = new XMLHttpRequest();
req.open(
"GET",
"http://itsareminder.appspot.com/myreminderapp",
true);
req.onload = showReminders;
req.send(null);

function showReminders() {
var reminders = req.responseXML.getElementsByTagName("Reminder");

for (var i = 0, reminder; reminder = reminders[i]; i++) {
var reminderDIV = document.createElement("div");
reminderDIV.innerHTML = reminder.textContent;
document.body.appendChild(reminderDIV);
}
}

</script>

The code above is focussed around the <script> tag. It requires knowledge about AJAX and the XMLHttpRequest object along with some Javascript basics. The core pieces are mentioned below:

1. We use the XMLHttpRequest to make a call to our Reminder Service. The end point is where our servlet is present to serve the requests i.e. http://itsareminder.appspot.com/myreminderapp.

2. When we get the response XML, we call the showReminders() method. This method simply parses the <Reminder> tags and for each tag, it creates a <div> element in which the text content is the Reminder Event Text returned. Its appends each of the <div/> elements to the document.body as shown.

Simple isnt it? Now let us see how to install this extension into your Chrome browser to test it out.

Installing the Reminder Chrome Extension

At this point in time, I will assume that you have the following 3 files created in the C:\MyReminder folder:

  • manifest.json
  • myreminder.png
  • reminder.html

You could have created different files but just remember that you need the icon, manifest and your html file that implements the Chrome extension code.

Once you have that, follow these steps:

1. Launch Google Chrome Browser. You need to go the Extensions page that allows you to view the current extensions installed and from where you can either install new extensions/reload/uninstall,etc. There are two ways to go to that page:

  • In the address, type in chrome://extensions
  • From the settings option as mentioned in the start of this article, click on the “Extensions” menu option.

2. You should see a screen that looks something like this:

What this means is that there are no extensions currently installed in my Chrome browser. If there were any, they would be listed over here.

3. Click on the Load unpacked extension button. This will bring up a dialog box from where you can navigate to the folder where your extension files are present. In our case, it was the C:\MyReminderExtension and so I navigate to that and click on OK as shown below:

4. This will install the Chrome Extension in the browser as shown below:

5. Finally, we can test out the browser by clicking on the icon and it will display the list of Reminders for the current month.

If you have newer versions, all you need to do is simply click on Reload option for the extension. Alternately, you can also Uninstall and load it again.

Some points to note:

1. You have not completely installed this extension. What this means is that if you close the Chrome Browser and launch it again, this Extension will not be visible.

2. The next step would be to visit the official documentation at http://code.google.com/chrome/extensions/getstarted.html and also go to the gallery and submit your Extension. The gallery is present at : https://chrome.google.com/extensions and you will find a link to submit your extension. Click that and follow the steps to submit your extension. All you will need to provide from your side will be a ZIP file of the folder that we mentioned above.

Conclusion

This concludes the final episode of the year 2009. In this episode we covered how to write a Google Chrome Extension and power it via a Google App Engine application.

I hope that the new year takes you further into writing Cloud applications using Google App Engine. I will continue to explore tools/languages/APIs/extensions that work in coherence with the Google App Engine. The journey or might I say “Experiments” are far from over. Have a great 2010 and thanks for reading this blog. Its been a joy to share my experiments with all of you.

Categories: Uncategorized Tags:

Episode 13: Using the Blobstore Java API

December 18, 2009 7 comments

Welcome to Episode 13 of this series. It has been a while since the last episode and to compensate I thought why not cover something that has just been released. In keeping with that line, this episode will cover the recently released Blobstore API in the 1.3.0 release of the Google App Engine SDK.  

Using the Blobstore API, we shall cover how to build an application that mimics several sites that allow you to upload a picture and send a Tweet. The Tweet will then contain a link back to the image that you uploaded. Blobstore API now makes all this possible along with several other applications that you could envision like file sharing, document management, etc.  

What is the Blobstore API?

The Blobstore API allows your application to store blobs of information, where each blob can be upto 50MB in size. These blobs are typically large files like video and images. This is different from the datastore API that does not allow for saving objects upto this large size. The API documention for the Blobstore API is provided here.  

The Blobstore API provides two types of functions:  

  • An ability to upload and save the blob automaticallyThe BlobstoreService which is provided by the com.google.appengine.api.blobstore.BlobstoreService allows us to specify a URL where users can upload their large files. You can think of this url as the action element in the HTML form. The implementation at this URL is internal to the BlobstoreService. But what it does is significant. It will extract out the file contents that you uploaded and store it as a Blob in the database. Each blob that is stored in the database is associated with the a Blob Key. This Blob key is then provided to your url and you can then use the Blob Key to do anything within your application. In our case, we form a url that is tweeted to the users who can then view the picture that we uploaded.
  • An ability to serve or retrieve the blob.The BlobstoreService also provides an ability to serve or retrieve the blob that was saved successfully. It will provide the blob as a response that could then use as a source in an <img> element for example. All you need to do is provide it the Blob Key and the response stream and in return, it will provide the content properly encoded as per its type that you could then use.

It will be clear as we work out the application in the next few sections.  

Note: The Blobstore API is enabled in your application only if you enable “billing” for your applications. What this means is that you can try out the API with your local development server but if you deploy the same on the App Engine cloud, your application will not be able to use the API if it has not been enabled for “billing”. So keep that in mind before leaping with joy that your new application enabled with large file uploads, etc is now ready to start functioning in the cloud. In case you try to use any Blobstore APIs without enabling billing in your application, you will get a FeatureNotSupported exception and the text as: “The Blobstore API will be enabled for this application once billing has been enabled in the admin console.”  

Prerequisites

Google announced the release of version 1.3.0 of the App Engine SDK for both Python and Java. We need to set our development environment with this release of the SDK since the Blobstore API was released in this version.  

So the first thing that you need to do is to download the latest release 1.3.0 of the App Engine SDK and upgrade your Eclipse development environment with that. There are two ways you can do that:  

a. Use the Update features of Eclipse to download and install the latest SDK  

b. Download the SDK from the following link. Make sure you download the Java SDK. Further to the download, inside of your Eclipse IDE, go to Windows -> Preferences and then Google -> App Engine SDK. Click on Add and provide the path to the expanded 1.3.0 distribution on your machine.  

I had covered in detail how to upgrade your SDK for your Eclipse IDE when new releases come out. This was covered in Episode 5, in which we upgraded from 1.2.5 -> 1.2.6. Readers are advised to take a look at it in case they are not familiar. The process remains the same.  

Tweet My Picture in Action

The application that we are going to develop is called Tweet My Picture. There are several sites now that allow you to upload a picture to their site and then send a Tweet. The Tweet contains a simple description and the url to the picture. An example is TwitPic.  I thought the Blobstore API now actually makes an application of this kind way too easy to create, so why not demonstrate that. We will not be creating a polished looking application but rather demonstrating the API and showing that it works. Remember that all the instructions later on deploying and running this application will happen in the local development server and not the live App Engine site because I need to enable billing in order to utilize the Blobstore Service. But the best part is that the local development server works fine, so we can do our complete development and testing on it. Then you are the best judge of writing your own application that utilizes the Blobstore API and making it a billable application when you go live.  

Before we get down to code, we should see the end result.  

Assuming that I have started my local development server, I navigate to the index.jsp page that is shown below:  

This will display a simple page, where you provide the following information:  

  • Your Twitter UserId and Password
  • The image file that you wish to upload. Simply click the Choose File button and select a file to upload.

  

Then when you click the Upload Picture button, what happens is the following:  

1. The file contents that  you uploaded will be stored by the Blobstore API into the datastore automatically for you. It will provide you with the Blob Key for the blob that was saved.  

2. We use the Blob Key to create a simple Tweet message containing the link. And then we use Twitter4J to send the Tweet.  

3. Finally a page is displayed indicating the status of the Tweet, the Tweet contents and it also shows the image that you uploaded. This page is shown below:  

   

Now, switch to your Twitter client and you will notice that the Tweet has been posted. A sample screenshot is shown below.The url is pointing to the localhost but that is because I wish to do my testing locally and I have not enabled billing for my live application at the appspot.com domain.  

  

Clicking on the Tweet link, takes you back to an page that shows you the picture as below:  

  

Nice, isn’t it? Do not limit yourself only to this example. You can now start thinking on creating serious document management, file sharing, etc applications and use the App Engine infrastructure to host it. So let’s get coding now.  

Implementing Tweet My Picture

The first thing to do is to create a New Google Web Application Project. Follow these steps:  

1. Either click on File –> New –> Other or press Ctrl-N to create a new project. Select Google and then Web Application project. Alternately you could also click on the New Web Application Project Toolbar icon as part of the Google Eclipse plugin. Please make sure that you have installed the latest 1.3.0 version of the App Engine SDK and are using that as the API for this version. Shown below is the New Project screenshot where you should see an additional SDK 1.3.0 and need to select that.  

  

2. In the New Web Application Project dialog, deselect the Use Google Web Toolkit and give a name to your project. I have named mine GAEJExperiments. I suggest you go with the same name so that things are consistent with the rest of the article, but I leave that to you. In case you are following the series, you could simply use the same project and skip all these steps altogether. You can simply go to the next part i.e. the Servlet code.  

3. Click on Finish. This will generate the project and also create a sample Hello World Servlet for you. But we will be writing our own Servlet.  

Adding Twitter4J Jar to the Classpath and WEB-INF\lib folder

Since we will be using the excellent Twitter4J library for posting to Twitter, you need to download the latest version of the JAR file. Download it from here. I have used twitter4j-2.0.10.jar. You need to copy this file to the WEB-INF\lib folder of the project. Also add the JAR file to the Build Classpath of the Eclipse project.  

index.jsp

The first page is the index.jsp page. This is a simple page that will have a form that accepts the Twitter UserId/Password along with the file to be uploaded. The code is shown below. Just a quick note that all the JSP files will go into the war folder of the project.  

  

<%@ page import="com.google.appengine.api.blobstore.BlobstoreServiceFactory" %>
<%@ page import="com.google.appengine.api.blobstore.BlobstoreService" %>  

<%
    BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
%>
<html>
    <head>
        <title>Tweet My Picture</title>
    </head>
    <body>
        <img src="tweet.png"/>
        <h1>Tweet My Picture</h1>
        <hr/>
        <h2>Upload a picture and send an automatic Tweet</h2>
        <form action="<%= blobstoreService.createUploadUrl("/upload") %>" method="post" enctype="multipart/form-data">
            Twitter User Id : <input type="text" name="twitter_userid"/><br/>
            Twitter Password : <input type="p" name="twitter_password"/><br/>
            File :
            <input type="text" name="filename"/>
            <input type="file" name="myTweetPic"/>
            <input type="submit" value="Upload Picture"/>
        </form>
</html>  

 

Let us look at the main points in the code above:  

1. It has a HTML <form/> that accepts the twitter userid and password. We also have an  <input/> element of type file, that allows the user to select the file from his machine to be uploaded.  

2. The action attribute of the FORM is where you should pay attention. The Form action as you know submits the request parameters to a particular server side resource like a Servlet/JSP, etc. The action here is created via a helper function provided by the Blobstore API itself. Notice that first we are getting an instance of the Blobstore service via the BlobstoreServiceFactory as shown below:  

BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();  

Then we are using a helper function called blobstoreService.createUploadURL(“SUCCESS_PATH”) for the action. Let us spend some time on that since it is important and will help us understand what the BlobstoreService does behind the scenes.  

If you launch your local development server and navigate to the index.jsp page and do a view source on the HTML, you will find that the action that is generated by the createUploadURL(…) method looks something like this:  

action=”/_ah/upload/agp0d2VldG15cGljchsLEhVfX0Jsb2JVcGxvYWRTZXNzaW9uX18YEgw”. You may wonder where did our SUCCESS_PATH i.e. /upload go away. Let me explain:  

When you do an upload, the request hits an internal URL in the App Engine infrastructure that will do the following:  

1. The BlobstoreService implementation inside of AppEngine will extract out the Blob and save it for you automatically in the datastore. You do not have to do anything special. It does this for the all the Blobs that are present in the HTTP Request stream.  

2. On successfully saving these blobs into the stores, what it has with itself now are one or more name value pairs i.e. a Map. The name is the request parameter name for your blob. For e.g. in our index.jsp, the file that we uploaded had the name of myTweetPic i.e. the form element. And the value will be the Blob Key that you can use to retrieve the Blob. It will put this map into the Request stream i.e. it will augment the Request stream with this map and then invoke your SUCCESS_PATH url. The SUCCESS_PATH url is the end point or in our case the Servlet.  

This Servlet can then extract out each of the Blobs that were saved by inspecting the Map and do further action. In our case, we will be posting a link to Twitter. This ervlet is what we shall see next.   

Upload Servlet

The Upload Servlet code is listed below.  

package com.gaejexperiments.twitter;  

import java.io.IOException;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;  

import javax.mail.Session;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;  

import twitter4j.Status;
import twitter4j.Twitter;  

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;  

@SuppressWarnings("serial")
public class Upload extends HttpServlet {
 private final static Logger _logger = Logger.getLogger(Upload.class.getName());
 private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
   

    public void doPost(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {  

        Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(req);
        BlobKey blobKey = blobs.get("myTweetPic");  

        if (blobKey == null) {
            res.sendRedirect("/");
        }
        else {
         String strStatus = "";
         try {
          String twitter_userid   = (String)req.getParameter("twitter_userid");
          String twitter_password = (String)req.getParameter("twitter_password");
          _logger.info("UserId:"+twitter_userid + " , Password:"+twitter_password);
          Twitter twitter = new Twitter(twitter_userid,twitter_password);
          String strTweet = "Check out my picture at : " + "<a href="http://localhost:8888/viewpic.jsp?blob-key=&quot;+blobKey.getKeyString">http://localhost:8888/viewpic.jsp?blob-key="+blobKey.getKeyString</a>(); 
             Status status = twitter.updateStatus(strTweet);
             strStatus = "Successfully updated the status to [" + status.getText() + "].";
             _logger.info(strStatus);
         }
         catch (Exception ex) {
          strStatus = "Could not update Twitter Status : " + ex.getMessage();
          _logger.log(Level.WARNING,strStatus);
         }
         finally {
             res.sendRedirect("/submitpic.jsp?blob-key="+blobKey.getKeyString() + "&status="+strStatus);
         }
         }
    }
}

 

Let us go through the main points in the Upload Servlet code:  

1. The Servlet implementation is the doPost() method. This method was invoked by the Blobstore Service after the blobs were successfully saved in the datastore.  

2. As mentioned, the Blobstore Service augments the Request stream with a Map of successfully saved Blobs. It also provides a helper method that we can use to extract out this Map instance from the request stream. The code is shown below:  

Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(req);  

3. The next thing to do is to get the Blob Key for our saved Blob. The Blob Key is unique and will be used to retrieve the Blob as we shall see later on in the viewpic.jsp code. The Key that we will use is the same as the input parameter name for our file blob that we provided in the FORM i.e. index.jsp.   

BlobKey blobKey = blobs.get(“myTweetPic”);  

4. We do a simple check to verify if the blobKey instance is not null. If not, we create a status update for twitter giving a url that points to the viewpic.jsp page which is passed the blob-key request parameter as shown below:  

String strTweet = “Check out my picture at : ” + “http://localhost:8888/viewpic.jsp?blob-key=”+blobKey.getKeyString();   

5. Finally, we using Twitter4J to post out tweet using the twitter id and password that we provided.  

The status of our upload and tweet is then displayed by navigating to the submitpic.jsp page that simply shows the status and the picture that we uploaded.   

submitpic.jsp

This JSP file is invoked by our Upload Servlet to display the status of our Tweet to twitter and the image that we uploaded as discussed in the previous section. You will notice an interesting thing over here and that is the <img/> element. The source attribute of the <img/> element is a servlet residing at an endpoint /serve. All it needs is the blob-key request parameter. We shall see this servlet in a moment.  

<%@ page import="com.google.appengine.api.blobstore.BlobstoreServiceFactory" %>
<%@ page import="com.google.appengine.api.blobstore.BlobstoreService" %>  

<html>
    <head>
        <title>Tweet My Picture - Submission</title>
    </head>
    <body>
        <img src="tweet.png"/>
        <h1>Tweet My Picture</h1>
        <hr/>
        <h3>Submission Result: <%=request.getParameter("status")%></h3>
        <%
           String blobKey = (String)request.getParameter("blob-key");
           if (blobKey != null) {%>
                You uploaded : <br/>
       <img width="200" height="150" src="<%="<a href="http://localhost:8888/serve?blob-key=&quot;+blobKey">http://localhost:8888/serve?blob-key="+blobKey</a> %>">
           <%}%>
    </body>
</html>  

  

Serve Servlet

This Servlet uses another helper function of the BlobStoreService. The method is called serve and it takes two parameters as shown in the listing below. The blob Key and the HTTP response stream. Note that we pass it the Blob Key that we got after saving our blob. What the serve method will do is that it will automatically retrieve the Blob from the Datastore using the Blob Key that was provided to it. Once it retrieves the Blob successfully, it will take the content of the Blob, set the correct MIME types and insert that into the HTTP Response stream. You can the use the Response stream to assign it as a source for the HTML <img/> element. We did exactly that in the submitpic.jsp file and we do the same in the viewpic.jsp file that will be invoked when someone clicks on the Twitter post.  

  

package com.gaejexperiments.twitter;  

import java.io.IOException;  

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;  

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;  

@SuppressWarnings("serial")
public class Serve extends HttpServlet {
 private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
 
 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        BlobKey blobKey = new BlobKey(req.getParameter("blob-key"));
        blobstoreService.serve(blobKey, resp);
    }
}

  

viewpic.jsp

As discussed earlier, the Tweet that we post has the following format:  

Check out my picture at http://localhost:8888/viewpic.jsp?blob-key=A_BLOB_KEY  

This will invoke the viewpic.jsp file with a request parameter named blob-key which contains the Blob key value. So all we have to do i to create a <img/> element, whose source attribute will be served via the /serve endpoint as shown below. Simple isn’t it ?  

  

<%@ page import="com.google.appengine.api.blobstore.BlobstoreServiceFactory" %>
<%@ page import="com.google.appengine.api.blobstore.BlobstoreService" %>  

<%
    BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
    String blobKey = (String)request.getParameter("blob-key");
%>
<html>
    <head>
        <title>Tweet My Picture - View</title>
    </head>
    <body>
    <img width="200" height="150" src="<%="<a href="http://localhost:8888/serve?blob-key=&quot;+blobKey">http://localhost:8888/serve?blob-key="+blobKey</a> %>">
    </body>
</html>

   

Configuring the Servlets

We need to add both the Upload Servlet and the Serve Servlet with their appropriate entries for  <servlet/> and <servlet-mapping/> in the web.xml file. This file is present in the WEB-INF folder of the project. The necessary fragment to be added to your web.xml file are shown below.  

 <servlet>
  <servlet-name>Upload</servlet-name>
  <servlet-class>com.gaejexperiments.twitter.Upload</servlet-class>
 </servlet>
 <servlet>
  <servlet-name>Serve</servlet-name>
  <servlet-class>com.gaejexperiments.twitter.Serve</servlet-class>
 </servlet>
 <servlet-mapping>
  <servlet-name>Upload</servlet-name>
  <url-pattern>/upload</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
  <servlet-name>Serve</servlet-name>
  <url-pattern>/serve</url-pattern>
 </servlet-mapping>

  

Deploying the application

Since we are going to be running this application locally itself, we simply need to validate it against the local development server. Assuming that the development is complete, simply run the Web Application from your Eclipse IDE and using a browser, navigate to http://localhost:8888/index.jsp. In my case, the port is 8888, but it could be different for you.  

Please make sure that you are connected to the Internet and do have a valid Twitter userid and password.   

Refer to the section above on Tweet My Picture in action for the flow. I will not repeat it here again.  

An interesting thing that you could look at is to navigate to http://localhost:8888/_ah/admin console. Go to the DataStore viewer. If you have uploaded several images successfully, you will find instances of the Entity : __BlobInfo__ getting created. Click on the List Entities button to see the entities that you have uploaded so far. The ID/Name column is the Blob Key for your Blob. A sample screenshot from my development server instance is shown below:  

  

Conclusion

This brings the episode to an end. In this episode we saw the Blobstore API service that has been introduced in version 1.3.0 of the App Engine SDK. The Blobstore API service is experimental at this point in time and could change but it gives us enough today to see how to create application that require blobs of large sizes like video and images. This episode showed a simple implementation called Tweet My Picture but the possibilities are endless. Do keep in mind that if you have to use Blobstore Service in a live application hosted at the appspot.com domain, then you will need to enable “billing” for your application.  

Till the next episode, have fun with the Blobstore Service!

P.S: Just in case you were wondering… the picture of the lion was taken at a distance of 2 feet away from it in the National Park, Mumbai.

  • Design a site like this with WordPress.com
    Get started