Help The Victims of the 8.9 Earthquake in Japan by Spreading Awareness and Aid. Visit http://goo.gl/wjZQz to donate. /* ]]> */
 

Welcome to Episode 12 of the series. This episode is an extension of the earlier episode where we saw how to write Simple Google Wave Robots using the WadRobotFramework. I strongly recommend that  you have completed the earlier episode and have got comfortable with the WadRobotFramework since this episode builds on the earlier one.

To recap, the WadRobotFramework distinguishes between 2 kinds of Robots and I summarize it again over here.

Simple Robots : These robots we covered in the earlier episode and saw how you can write a simple robot to react to a blip by appending a new blip (BlipAppenderRobot) or even modify the Blip Text (BlipModifierRobot).

Advanced Robots : These are of main focus in this article and I reproduce from the earlier episode the text so that you understand what Advanced Robots are first. The definition of Advanced Robots is per the WadRobotFramework and it is not meant to indicate this is the final definition of it.

Advanced Robots are those that can react to instructions ( or commands) in the Blips. Here are some samples of Advanced Robots and how they would react to commands from Blips:

1. A character Counting Advanced Robot:

Your submitted Blip Text contains : “Here is some text in the blip. Please count the length of this message for me.” {mycountingrobot:count}.

You can write an advanced Robot (mycountingrobot) that knows how to count the length of the message. So it gets notified when it there is a instruction (count) in the Blip. Your Advanced Robot can then count out the characters and then either append or modify a blip as needed.

2. A Tweeting Robot:

Your submitted Blip Text contains the following text : “{mytweetingrobot:tweet} Some text to tweet”

You can write an advanced Robot (mytweetingrobot) that knows how to tweet the message to Twitter. So it gets notified when it there is a instruction (tweet) in the Blip. Your Advanced Robot can then append a blip or modify a blip saying that the message has been tweeted.

The best part of it all is that you could combine all of this into a single Robot that can respond to one or more commands. For example, take a look at Today’s Special Robot (see http://ppandhi.wordpress.com/2009/11/08/todays-special-robot/) that can respond to more than one command. It can give you the quotes, day in history, word of the day, cricket score, your daily horoscope by simply responding to the command that you type in.

So for example, you could write a robot and give it commands like this:

1. {myrobot:doCommand1}

2. {myrobot:doCommand2}

3. {myrobot:doCommandN} and so on.

In this article, we are going to see exactly how to achieve the above command Robot that will delegate its work to different workers who are responsible for executing the command i.e. doing the work.

Let us get a few definitions in place first:

1. The Command Robot: This is the main class of your Robot and you need to extend the org.wadael.waverobotfrmwrk.advanced.WithWorkersRobot. You need to have an identifier for your robot, which is a unique ID for your Robot. Let us call it GAEJRobot.

2. Each Command Robot is capable of following instructions or commands. These instructions are executed by the Workers.

3. A Worker is a Command implementation that performs a certain logic. For e.g. fetching a stock quote, getting a word of a day, sending a Tweet, sending an email, etc. Each worker will indicate what instruction or command it obeys.

As an example, say you want to write an Advanced Robot class (WithWorkersRobot) whose identifier is named GAEJRobot that can responds to the following two commands:

a. SendTweet
b. GiveWordOfTheDay

So, you will implement two Workers and register (add) them to the GAEJRobot class. The two worker classes will be :

  • SendTweetWorker which says that listens to an instruction named tweet and it will implement its core logic in the doWork() method.
  • GiveWordOfTheDayWorker which says that it listens to an instruction named wotd and it will implement its core logic in the doWork() method.

Now, in your Wave Conversation, you can give the following text in the Blip (of course after adding the Robot as a participant).

1. {GAEJRobot:tweet}

2. {GAEJRobot:wotd}

Voila! The WadRobotFramework will then do the heavy lifting for you. It roughly works as follows:

  • When you submit a Blip, it will scan the Blip Text for the identifier and see if it matches itself.
  • If yes, it will scan out the instructions and invoke the doWork() method of the Worker Robot that implements the instruction.

This is not all. The WadRobotFramework has thought about parameters that you may need to pass to your Robot. For e.g. consider the following fictitious instruction that you need to give to a Stock Quote Robot.

{StockQuoteRobot:getquote GOOG} or {StockQuoteRobot:getquote GOOG,MSFT,ADBE,ORCL,IBM}

In short the format is as follows:

{RobotIdentifier:Instruction<space>[parameters]}

So in the above two examples the parameter GOOG and the parameter string “GOOG,MSFT,ADBE,ORCL,IBM” will be passed to the doWork() method of your RobotWorker that has registered with the Advanced Robot and who implements the getquote instruction. Please read this last statement clearly with the highlighted words as the key pieces required to build out an Advanced Robot.

Simple yet powerful and it opens up a wide range of Robots that you can start writing today. So let me get started and demonstrate the basic flow to get an Advanced Robot up and running which can accept 1 or more instructions. The Robot does not do anything specific except for simply demonstrating the flow. Readers are expected to extend it with their ideas brimming inside their minds.

To understand what we will build, it helps to take a look at the running robot as shown below:

You will notice that I have added my robot called MyAdvancedRobot. The identifier for the Robot is GAEJRobot and the Robot has two workers (Worker1 and Worker2)  registered with it, which implement the instructions  command1 and command2 respectively.

Now when I submit the text {GAEJRobot:command1} , the doWork() method of the Worker1 is invoked. It simply accepts the command and prints out that it received the command with no parameters passed to it.

Similarly, look at the wave conversation below:

Here I give the command2 to the GAEJRobot and I am also passing a string of parameters. When I click the Done button, the doWork() method of the Worker2 is invoked. It simply accepts the command and prints out that it received the command with the parameter string. Now, it could have processed the parameters and performed its logic accordingly. This demonstrates how the wiring is done by WadRobotFramework to make your life easier in writing Advanced Google Wave Robots.

Let us start writing code now. I will assume that you are fairly conversant now with the typical project structure and requirements of writing a Google Wave Robot. If not, I suggest that you first go through these tutorials in the following order:

  • Episode 7 : Writing your First Google Wave Robot
  • Episode 11: Develop Simple Google Wave Robots using the WadRobotFramework

Project Setup

Create a New Project or use the same project MyGoogleWaveRobot that we used in the earlier Episode 11.

If you are creating a New project, then please make sure that you download all the JARs from the following two locations:

http://code.google.com/p/wave-robot-java-client/downloads/list

The web page when you navigate to the above URL is shown below:

ep7-6

Download all the above files to your machine.

The WadRobotFramework JAR file is available at the following location :

http://code.google.com/p/wadrobotframework/downloads/list

The web page when you navigate to the above URL is shown below:

Download the JAR file to your machine. Once you have downloaded the 5 JAR files, make sure that they are copied to the WEB-INFlib folder of your project and that the Project Build Path is also setup with the JAR files as shown below:

Writing the Advanced Robot : MyAdvancedRobot.java

The first step is to create a Java class. Call it MyAdvancedRobot.java. The source code is listed below:

 

package com.gaejexperiments.waverobot;

import org.wadael.waverobotfrmwrk.advanced.WithWorkersRobot;

public class MyAdvancedRobot extends WithWorkersRobot {

public MyAdvancedRobot() {
super();
//This will process 'command1'
addRobotWorker(new Worker1());

//This will process 'command2'
addRobotWorker(new Worker2());
}

@Override
public String getRobotIdentifier() {
return "GAEJRobot";
}

@Override
protected String getUsage() {
return "Advanced Robot commands : command1 and command2";
}

@Override
protected String getRobotSelfIntroduction() {
return "I am an Advanced Robot";
}

}

 

Let us dissect the code now:

1. Our Advanced Robot class MyAdvancedRobot extends the WithWorkersRobot class, which is required for creating the Advanced Robots with the WadRobotFramework.

2. The WithWorkersRobot class constructor uses a method called addRobotWorker(…) to add one or more workers to it. Remember each worker will execute or do its job as per the instruction that it obeys. So we are going to have two workers : Worker1 and Worker2 which we are adding to our AdvancedRobot. We will get to the listing of the Worker1 and Worker2 later but it is sufficient to keep in mind, that Worker1 class will perform the work required with command1 instruction is given in the Blip and Worker2 class will perform the work required when command2 instruction is given in the Blip. To recap, as you add more workers, you will need to add them here in the constructor using the addRobotWorker method.

3. The getRobotIdentifier() method is used to return the string that is the unique identifier of your Robot. This is used to distinguish Robots in the same Wave. The identifier if you recollect is going to be used by the other participants in the wave to give instructions to your Robot. As mentioned, the format in the Blip to give an instruction to your robot will be like this:

{RobotIdentifier:Instruction<space>[parameters]}

Each Instruction is implemented by a Worker. For e.g. command1 will be implemented by Worker1 and command2 will be implemented by Worker2.

So to invoke Worker1, we have to say {GAEJRobot:command1} in the Blip and submit it. Hence we return GAEJRobot in the getRobotIdentifier() method and this will be the unique way in which we identify this Robot

4. The getUsage() method is used to return a string that will be displayed to the participant when they type /help in the start of the Blip. This is useful to give a list of possible instructions that your Advanced Robot implements. In our case here, we are implementing two instructions and hence we have returned some string. But you can give an elaborate help string stating detailed command text, sample parameters, etc.

5. Finally, we have the getRobotSelfIntroduction() method. This is not mandatory but it is nice to announce to the particpants when you (Robot) gets added to the wave as a participant. Simply return a String that you would like to announce to the other (existing) participants in the Wave.

Implementing the Workers

We are now going to implement the Workers i.e. Worker1 and Worker2. The code is identical for both of them and it is listed below:

Worker1.java

 

package com.gaejexperiments.waverobot;

import org.wadael.waverobotfrmwrk.advanced.RobotWorker;

import com.google.wave.api.Blip;
import com.google.wave.api.Event;
import com.google.wave.api.RobotMessageBundle;

public class Worker1 implements RobotWorker {

public String getInstruction() {

return "command1";
}

public boolean doWork(RobotMessageBundle bundle, Blip blip, Event evt, String params) {
blip.getDocument().append("Robot Worker 1 got the command with parameter string : " + params);
return true;
}

public String getDescription() {
return "Robot Worker 1";
}
}

 

Worker2.java

 

package com.gaejexperiments.waverobot;

import org.wadael.waverobotfrmwrk.advanced.RobotWorker;

import com.google.wave.api.Blip;
import com.google.wave.api.Event;
import com.google.wave.api.RobotMessageBundle;

public class Worker2 implements RobotWorker {

public boolean doWork(RobotMessageBundle bundle, Blip blip, Event evt, String params) {
blip.getDocument().append("Robot Worker 2 got the command with parameter string : " + params);
return true;
}

public String getDescription() {
return "Robot Worker 2";
}

public String getInstruction() {

return "command2";
}

}

 

Let us go through the code of one of them and you will be able to understand it:

1. To recap, a Worker implements an instruction or a single command. Each Worker class needs to implement the RobotWorker interface in the WadRobotFramework.

2. It needs to implement the getInstruction() method which returns a String. This is the instruction that the Worker will obey or perform. In our case, the command1 is being done by Worker1 class and the command2 is being done by Worker2 class respectively.  So when someone submits {GAEJRobot:command1} in the Blip, the doWork() implementation of the Worker1 class will be invoked and if they submit {GAEJRobot:command2} in the Blip, the doWork() implementation of the Worker2 class will be invoked.

3. It needs to implement the doWork() method. This method is the heart or the main implementation of the Worker. Here you will place all your processing logic. Notice that since this is an Advanced Robot, it is assumed that you would even like to make use of the Google Wave API classes directly. So you are passed in instances of RobotMessageBundle, Blip and Event classes. The last parameter passed is params and it represents any parameters passed to the robot.

You will notice in the implementation that we have done for the Worker, that we simply Append to the Blip Text saying that the Worker got its command and notice that we also print out the Parameter String. So if you logic depends on the values of the parameters passed, you can parse out the parameters here itself and perform your logic.

That is all we need to do as far as writing Java code is concerned. Of course we have the other mandatory files that we need to create, which we will cover quickly now:

Configuring the MyAppenderRobot in web.xml

We need to add the MyAdvancedRobot in 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.

 

<servlet>
<servlet-name>MyAdvancedRobot</servlet-name>
<servlet-class>com.gaejexperiments.waverobot.MyAdvancedRobot</servlet-class>
</servlet>
<servlet>
<servlet-name>MyRobotProfileServlet</servlet-name>
<servlet-class>com.gaejexperiments.waverobot.MyRobotProfileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyAdvancedRobot</servlet-name>
<url-pattern>/_wave/robot/jsonrpc</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyRobotProfileServlet</servlet-name>
<url-pattern>/_wave/robot/profile</url-pattern>
</servlet-mapping>

 

Notice that we also have the ProfileServlet configured here, which is a good and recommended thing to have for your Robot. The ProfileServlet class is covered in the next section.

ProfileServlet.java

The implementation is straightforward and contains the ApplicationId that I have used for my AdvancedRobot. You can replace it with your id.

 

package com.gaejexperiments.waverobot;

import com.google.wave.api.ProfileServlet;

public class MyRobotProfileServlet extends ProfileServlet {

@Override
public String getRobotAvatarUrl() {
return "http://myinfoagent.appspot.com/_wave/myimage.jpg";
}

@Override
public String getRobotName() {
return "MyAdvancedRobot";
}

@Override
public String getRobotProfilePageUrl() {
return "http://myinfoagent.appspot.com";
}

}

 

Creating the MyAdvancedRobot capabilities.xml files

We need an additional file to describe the capabilities of the Robot that we have written. This file is called the capabilities.xml and it needs to reside in a certain location. You need to create a _wave directory inside of the war directory of your project. The location of this file is  war/_wave directory.

You will need to create the _wave directory and create the capabilities.xml file over there. The capabilities file shown below is pretty straightforward and is shown below:

 

<?xml version="1.0" encoding="utf-8"?>
<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">
<w:capabilities>
<w:capability name="BLIP_SUBMITTED" content="true" />
</w:capabilities>
<w:version>1</w:version>
</w:robot>

 

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 myinfoagent.

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 myinfoagent]
  4. Click on OK. You will be lead back to the previous screen, where you can click on the Deploy 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”.

MyAdvancedRobot in Action

Your application is going to be available at the http://yourapplicationid.appspot.com. In my case, the application is available at http://myinfoagent.appspot.com.

You can test for the presence of your robot capabilities file by simply typing in the following:

http://yourapplicationid.appspot.com/_wave/capabilities.xml [Replace yourapplicationid with the Application ID that you have] and you should see the capabilities.xml file being served up.

To test out the Robot, you need to launch the Google Wave client and login in with your account by going to http://wave.google.com. On successful login, you will be inside the Wave client from where you can create a new wave by clicking on the New Wave link. I then add the myinfoagent@appspot.com, which is our AdvancedRobot to the Wave as a participant as shown below:

 

On addition, the AdvancedRobot will announce itself to the Participants. This is the method getRobotSelfIntroduction() that we implemented in the MyAdvancedRobot.java class. The output is shown below:

Now, we type in the message /help in the beginning of the Blip and submit it as shown below:

When submitted, the method getUsage() of the MyAdvancedRobot class is invoked and it displays the commands and any help instruction that you provided in there.

The next thing we do is give a command to the first Worker as shown below and click on the Done button.

This will invoke the doWork() method on the Worker1 class since this class has indicated that it implements command1 as mentioned in the getInstruction() method of the class. The response of the Worker is shown below:

As you can see we did not pass any parameters to it, so it printed out null.

Now, let us invoke the second Worker as shown below and notice that we are passing parameters to it now:

When we click on Done, the doWork() method on the Worker2 class since this class has indicated that it implements command2 as mentioned in the getInstruction() method of the class. The response of the Worker is shown below:

Notice that the parameter string was now passed and successfully displayed. You can easily parse out the String and perform your logic.

Conclusion

This concludes the 2-part tutorial on creating Simple and Advanced Robots using the WadRobotFramework. The framework takes away much of the API that you need to know to get going with the Wave API and instead lets you focus on the core of our Robot logic. The framework is still is its early stages and would do with some feedback from you.

Till the next episode, just Smile and Wave!

 

 

Welcome to Episode 11 of this series. We saw in earlier Episode # 7, how you can write a Google Wave Robot. Please go through that tutorial to get familiar with the basics. This episode will be focused on writing a Google Wave Robot using a framework called the WadRobotFramework. This framework aims to help you develop your Robot quickly so that you can focus on the logic of your Robot, while letting the framework do the heavy lifting. Sure, you can do your programming with the Google Wave Robot API as explained in Episode 7, but this framework as we shall see wraps the details nicely so that you get to focus on your Robot logic.

What is the WadRobotFramework?

The WadRobotFramework is available at http://code.google.com/p/wadrobotframework. This framework is the work of  Jerome BATON, who has stated that the goal of the framework is to make writing Google Wave Robots in Java much simpler.

The framework goes ahead and defines two kinds of Robots: Simple and Advanced.

Simple Robots

Simple Robots are typically those that can react to a new Blip. This kind of Robots simply wait till a Blip is submitted. And on submission of the Blip, they will append a message to the Blip. It could be as simple as just analyzing the text of the blip and appending some new information or simply a fun sort of a Robot, which simply prints a random message.

An example of a this is shown below and which we will build in this episode:

In the above wave, there are two participants (myself and the Robot). The Robot announces itself when it is added to the Wave. Additionally, whenever I submit a Blip (for e.g. Hello), it simply appends a new blip with some text.

Simple Robots are also those that can modify the Blip Text instead of appending a new blip. For e.g. They could read the blip text and filter out the profanities, do automated spell checks or simply add some information to the existing Blip Text itself. In other words, it modifies the Blip Text.

Shown below is an example of a Simple Robot that modifies the Blip Text:

In the above wave, there are two participants (myself and the Robot). The Robot announces itself when it is added to the Wave. Additionally, whenever I submit a Blip (for e.g. Hello), it simply modifies the Blip Text by mentioning when I submitted the Blip text.

There is also a 3rd thing that the Simple Robots could do, which is very useful too. They can act in a stealth manner and simply do their work quietly. For e.g. whether you wish to write a Robot that appends a Blip or modifies a submitted Blip, you can simply chose not to append or modify but instead get the Blip text and do your work quietly. For e.g. count the words in the background, etc.

The WadRobotFramework also supports Advanced Robots, which are particularly interesting and will be covered in the Next Episode.

Advanced Robots are those that can react to commands in the Blips. Here are some samples of Advanced Robots and how they would react to commands from Blips:

1. A character Counting Advanced Robot:

Your submitted Blip Text contains : “Here is some text in the blip. Please count the length of this message for me. {mycountingrobot:count}”.

You can write an advanced Robot (mycountingrobot) that knows how to count the length of the message. So it gets notified when it there is a command (count) in the Blip. Your Advanced Robot can then count out the characters and then either append or modify a blip as needed.

2. A Tweeting Robot:

Your submitted Blip Text contains the following text : “{mytweetingrobot:tweet}

You can write an advanced Robot (mytweetingrobot) that knows how to tweet the message to Twitter. So it gets notified when it there is a command (tweet) in the Blip. Your Advanced Robot can then append a blip or modify a blip saying that the message has been tweeted.

The best part of it all is that you could combine all of this into a single Robot that can respond to one or more commands. For example, take a look at Today’s Special Robot (see http://ppandhi.wordpress.com/2009/11/08/todays-special-robot/) that can respond to more than one command. It can give you the quotes, day in history, word of the day, cricket score, your daily horoscope by simply responding to the command that you type in. With the WadRobotFramework, we shall see in the next episode how you can write such an Advanced Robot that responds to different commands. If you cannot wait, take a look at the documentation at the site (Advanced Robots).

Since this episode will be focusing on Simple Robots, let us recap what we know so far:  The WadRobotFramework supports Simple Robots in two flavours: The BlipAppenderRobot and the BlipModifierRobot. The BlipAppenderRobot is used to simply append to a Blip. The BlipModifierRobot is used to modify a submitted Blip.

Simple, isnt it? Lets develop and deploy our Simple Robots using the WadRobotFramework.

Create a New Project

We need to create a New Project first. Follow the steps below:

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 MyGoogleWaveRobot and I suggest you go with the same name so that things are consistent with the rest of the article (but if you wish to name it something else, that is fine too). The Screenshot is shown below:

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. So I suggest that you can delete the Servlet Java class and the mappings made in the web.xml or you can leave it for now since we are going to write our own.

Adding Google Wave Robot JAR files and WadRobotFramework JAR file to your Project Path

Since we are going to be writing a Wave Robot, we need some additional files on the client side. These additional files (JAR files) are required for the additional Wave API’s and also for deployment in your WEB-INFlib folder, so that they are correctly deployed and available to the run-time engine. These JAR files do not ship along with the Google Eclipse plugin, so you will need to download them for a website. The Google code website for the JAR files is:

http://code.google.com/p/wave-robot-java-client/downloads/list

The web page when you navigate to the above URL is shown below:

ep7-6

Download all the above files to your machine.

The WadRobotFramework JAR file is available at the following location :

http://code.google.com/p/wadrobotframework/downloads/list

The web page when you navigate to the above URL is shown below:

Once you have downloaded the files, follow these steps to setup your Project Build Path and runtime correctly.

1. Copy all the 5 JAR files to the WEB-INFlib folder of your Eclipse Project. After copying you should see the files as shown in the project hierarchy below:

2. Right-click on the Project in the Project Hierarchy. Select Properties and then Java Build Path. Click on Add JARs and then select the 5 JAR files from your Project WEB-INFlib folder.

3. Your Project Build Path should like the screenshot below.

Click on OK to proceed. This completes your Build Path setup with the Google Wave Robot JAR and WadRobotFramework JAR files.

Writing the Simple Robot: MyAppenderRobot : MyAppenderRobot.java

Let us first create our Simple Robot Java class based on the WadRobotFramework. This Simple Robot is the one that will react to a new Blip. So all we will do is to make the robot append to the blip, when the blip is submitted. The Robot demonstrated here will be straightforward and you can easily modify it to make it react in your own way.

As discussed, this is known as the BlipAppenderRobot and so all we need to do is to extend the BlipAppenderRobot class in the WadRobotFramework and provide our simple implementation.

The steps are straightforward and given below. All we need to do is write our class that extends the org.wadael.waverobotfrmwrk.simple.BlipAppenderRobot class and provide an implementation for the getTextToAppend method.

Follow these steps:

1. Create a new Java class within the same package. The New Java Class dialog is shown below. I have named the class MyAppenderRobot as shown below. Click on the Browse button to select a Super Class.

2. In the Superclass Selection dialog shown below, type the word BlipAppenderRobot (some part of it is also OK as the screenshot shows below) in the Choose a type field as shown. This will bring up the correct Matching items i.e. org.wadael.waverobotfrmwrk.simple.BlipAppenderRobot. Click on OK.


This will generate the code and you simply replace it with the following code listing given below:

 

package com.gaejexperiments.waverobot;

import org.wadael.waverobotfrmwrk.simple.BlipAppenderRobot;

public class MyAppenderRobot extends BlipAppenderRobot {

@Override
protected String getTextToAppend(String msg) {
return "I am appending some text too";
}

@Override
protected String getRobotSelfIntroduction() {
return "I am the Appender Robot";
}

}

 

Let us go through the code now:

1. We have extended the BlipAppenderRobot since all we want to do in this Robot is to react to the blip and append our own Blip

2. All we need to do as part of extending the BlipAppenderRobot class is to implement the getTextToAppend method. This method gets passed one parameter msg that is the blip text that was submitted. So in all essence, you could inspect what the text was in the blip submitted and then react to it.  The implementation simply returns the string that it wants to append. The WadRobotFramework’s BlipAppenderRobot will take care of creating a Blip and appending it to the current blip.

3. We also implement an optional method named getRobotSelfIntroduction. This method returns a string and  you can return something that identifies the addition of your Robot to the Wave. So when your Robot is added as a participant and if you have implemented the getRobotSelfIntroduction method, then it will display this message out. It is sort of announcing to the other wave participants about your presence.

That is all there is to implemented the MyAppenderRobot. If you would have studied the earlier tutorial on writing a Google Wave Robot, you would have noticed that the WadRobotFramework has done away with all the Event processing that you had to handle yourself and also shielded you from methods that you need to know to create a blip and append to it.

Configuring the MyAppenderRobot in web.xml

We need to add the MyAppenderRobot  in 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.

 

<servlet>
<servlet-name>MyAppenderRobot</servlet-name>
<servlet-class>com.gaejexperiments.waverobot.MyAppenderRobot</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyAppenderRobot</servlet-name>
<url-pattern>/_wave/robot/jsonrpc</url-pattern>
</servlet-mapping>

 

In the above fragment, you will note that url-pattern /_wave/robot/jsonrpc has to be mapped to the Robot Servlet that you have written. This is because the Google Wave system will invoke this url to communicate with your Robot using its protocol.

Creating the MyAppenderRobot capabilities.xml files

We need an additional file to describe the capabilities of the Robot that we have written. This file is called the capabilities.xml and it needs to reside in a certain location. You need to create a _wave directory inside of the war directory of your project. The location of this file is  war/_wave directory.

You will need to create the _wave directory and create the capabilities.xml file over there. The capabilities file shown below is pretty straightforward and is shown below:

 

<?xml version="1.0" encoding="utf-8"?>
<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">
<w:capabilities>
<w:capability name="BLIP_SUBMITTED" content="true" />
</w:capabilities>
<w:version>1</w:version>
</w:robot>

 

There are two elements of interest over here.

The <capability> element is of particular interest and we have registered for the BLIP_SUBMITTED event. This is important because it informs Google Wave that whenever a BLIP is submitted by a participated, then our Robot needs to be notified of it. The WadRobotFramework will notify the Robot by invoking the getTextToAppend method.

The other element is the <version> element. If you change any capabilities in your robot, then it is recommended that before you deploy, you change the version value over here, so that Google Wave can detect that there is a newer version and hence it can then query for your modified capabilities if any.

Writing our MyAppenderRobot Profile Servlet (not required but nice)

This is not a required step but it would be good practice to do so to make your Robot look more professional. A Profile Servlet is used to tell the following about your Robot:

1. A Name for your Robot

2. A custom image for  your Robot

3. A profile page for your Robot (a URL)

If you provide these, then the Google Wave client is able to retrieve them and set it for your Robot when it is added as a participant. This makes the Robot look more professional.

This profile information needs to be provided by you by writing a Profile Servlet. The Profile Servlet is nothing but extending the com.google.wave.api.ProfileServlet class and providing simple implementations for the overwritten methods.

Follow these steps to write the Profile Servlet:

1. Create a new Java class within the same package. Name the classs MyRobotProfileServlet and mention the Superclass as com.google.wave.api.ProfileServlet class. Click on OK.

2. This will generate a MyRobotProfileServlet.java file.

The simplest way to generate the stubs for the required methods would be to go to Source –> Override/Implement Methods. This will bring up the dialog box as shown below and you only need to select the 3 methods to override as shown:

ep7-14

Click on OK. This will generate the stubs, which you can then overwrite with the code shown below. The code is easy to understand, all we are doing is providing values for the Name, Avatar(Image) and the Profile Page URL. Note that for the Avatar, we are providing a file myimage.jpg present in the WAR/_wave folder. You will need to copy an appropriate image file for yourself and make sure that it is physically copied to the folder locally in your Eclipse project before you deploy your application.

I have used my AppId as myinfoagent but you can replace it with your AppId.

 

package com.gaejexperiments.waverobot;

import com.google.wave.api.ProfileServlet;

public class MyRobotProfileServlet extends ProfileServlet {

@Override
public String getRobotAvatarUrl() {
return "http://myinfoagent.appspot.com/_wave/myimage.jpg";
}

@Override
public String getRobotName() {
return "MyRobot";
}

@Override
public String getRobotProfilePageUrl() {
return "http://myinfoagent.appspot.com";
}

}

Configuring the Profile Servlet

We need to add the Profile Servlet <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.

 

<servlet>
<servlet-name>MyRobotProfileServlet</servlet-name>
<servlet-class>com.gaejexperiments.waverobot.MyRobotProfileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyRobotProfileServlet</servlet-name>
<url-pattern>/_wave/robot/profile</url-pattern>
</servlet-mapping>

In the above fragment, you will note that url-pattern /_wave/robot/profile has to be mapped to the Profile Servlet that you have written. This is because the Google Wave system will invoke this url to get hold of your profile.

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 myinfoagent.

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 myinfoagent]
  4. Click on OK. You will be lead back to the previous screen, where you can click on the Deploy 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”.

MyAppenderRobot in Action

Your application is going to be available at the http://yourapplicationid.appspot.com. In my case, the application is available at http://myinfoagent.appspot.com.

You can test for the presence of your robot capabilities file by simply typing in the following:

http://yourapplicationid.appspot.com/_wave/capabilities.xml [Replace yourapplicationid with the Application ID that you have] and you should see the capabilities.xml file being served up.

To test out the Robot, you need to launch the Google Wave client and login in with your account by going to http://wave.google.com. On successful login, you will be inside the Wave client from where you can create a new wave by clicking on the New Wave link. When you do that, currently you are the only participant (myself) as shown in the screen below:

Click on the + sign next to your icon and you can add one or more participants as shown below:

NOTE : Your Google Wave Robot is going to be available at <YOURAPPLICATIONID>@appspot.com , hence I have added myinfoagent@appspot.com as that was my application id. But you can replace it with your application id.

If all goes well, you will see your Robot added as a participant (with the icon and all, since the Profile Servlet is invoked behind the scenes by the Google Wave system). It announces itself and this was done via the implementation that we provided in the getRobotSelfIntroduction method.

Now I type a message “Hello” as shown below and click on the Done button, the BLIP_SUBMITTED event is fired and our Robot gets the event i.e. the getTextToAppend method is invoked on our Robot Java class. The method simply appends a blip as shown below:

Writing another Simple Robot: MyBlipModifierRobot : MyBlipModifierRobot.java

We saw how easy it was to create our Simple Robot that simply appended a blip to the wave conversation when a blip was submitted. Let us now write another Simple Robot that will modify the Blip Text when the blip is submitted.

As discussed, this is known as the BlipModifierRobot and so all we need to do is to extend the BlipModifierRobot class in the WadRobotFramework and provide our simple implementation.

The steps are straightforward and given below. All we need to do is write our class that extends the org.wadael.waverobotfrmwrk.simple.BlipModifierRobot class and provide an implementation for the modifyBlipText method.

Follow these steps:

1. Create a new Java class within the same package. Name it  MyBlipModifierAppenderRobot as shown below and mention the superclass as org.wadael.waverobotfrmwrk.simple.BlipModifierRobot

This will create the MyBlipModifierRobot.java file and you can replace it with the following source:

 

package com.gaejexperiments.waverobot;

import java.util.Date;
import org.wadael.waverobotfrmwrk.simple.BlipModifierRobot;

public class MyBlipModifierRobot extends BlipModifierRobot {

@Override
protected String modifyBlipText(String originalBlipText) {
return originalBlipText + " [You typed this at :" + new Date().toString() + "]";
}

@Override
protected String getRobotSelfIntroduction() {
return "I am the Blip Modifier Robot";
}

}

 

Let us go through the code now:

1. We have extended the BlipModifierRobot since all we want to do in this Robot is to modify the Blip that was submitted.

2. All we need to do as part of extending the BlipModifierRobot class is to implement the modifyBlipText method. This method gets passed one parameter originalBlipText that is the blip text that was submitted. So in all essence, you could inspect what the text was in the blip submitted and then modify it as needed .  The implementation above appends the text “You typed this at [DateTimeStamp]” to the originalBlipText and simply returns that string. The WadRobotFramework’s BlipModifierRobot will take care of modifying the Blip Text.

3. We also implement an optional method named getRobotSelfIntroduction. This method returns a string and  you can return something that identifies the addition of your Robot to the Wave. So when your Robot is added as a participant and if you have implemented the getRobotSelfIntroduction method, then it will display this message out. It is sort of announcing to the other wave participants about your presence.

That is all there is to implemented the MyBlipModifierRobot. If you would have studied the earlier tutorial on writing a Google Wave Robot, you would have noticed that the WadRobotFramework has done away with all the Event processing that you had to handle yourself and also shielded you from methods that you need to know to create a blip and append to it.

Configuring the MyBlipModifierRobot in web.xml

We need to add the MyBlipModifierRobot  in 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.

 

<servlet>
<servlet-name>MyBlipModifierRobot</servlet-name>
<servlet-class>com.gaejexperiments.waverobot.MyBlipModifierRobot</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyBlipModifierRobot</servlet-name>
<url-pattern>/_wave/robot/jsonrpc</url-pattern>
</servlet-mapping>

 

If you wish to check out this Robot in action, you can do so with the same project. Simply replace the previous Robot’s (MyAppenderRobot) servlet entries with the one shown above. And deploy the application following the same steps in the Deploying the Application section. Leave the Profile Servlet and the capabilities.xml file as is because the same applies in this case too.

Once you deploy the MyBlipModifierRobot, you should see it in action as shown below. The first screen shows the MyBlipModifierRobot announcing itself and then the second screen shows how it modified the blip text that I submitted by appending the TimeStamp to it.

Conclusion

This concludes Episode 11 of the series. We saw how easy it was to write Simple Google Wave Robots using the WadRobotFramework. Several Google Wave Robots that are out there simply do one of the things that we have seen in this episode i.e. modify a blip’s contents or append a blip in reaction to a blip submitted. You can get going with such Robots by using this framework which hides you from the underlying Google Wave API.

In the next episode, we shall see how to write an Advanced Google Wave Robot that can implement several commands. Till then, unleash those Simple Robots!

In the Superclass Selection dialog shown below, type the word AbstractRobot (some part of it is also OK as the screenshot shows below) in the Choose a type field as shown. This will bring up the correct Matching items i.e. com.google.wave.api.AbstractRobotServlet. Click on OKep7-8

 

Welcome to Episode 10. In this episode, we shall cover the experimental Task Queue Service in Google App Engine. This is an experimental service, which means that it could undergo change in its core functionality from all respects like methods, package names, etc. In any case, we can safely expect that it shall get confirmed in some form or the other in a future release of the Google App Engine.

This episode is sort of a natural progression on our last episode, which covered the Cron Service. To reiterate, the Cron Service was used for background jobs that you wish to perform outside of a user request. They are not typically initiated by a user but instead configured by your application to perform certain periodic tasks like summary reports at end of the day, daily backups, etc. The Task Queue Service provides a facility to process tasks in the background which are :

  • Typically initiated by the user.
  • They can be created internally by the application also to break down a background job into smaller tasks.

Some of the examples of performing a Task in the background include:

1. A user signs up at the website and submits his/her information. On receiving the request, a simple message is displayed back to the user that his/her subscription request has been received and they will hear soon about the status. At the same time, a task can be created that can process this users request, perform some verification and then send out an email to the user if the subscription is setup successfully. So you could have done either of the following:

  • Receive the user details and create a Task. This single task will take care of creating the required records in the database and send out an email.
  • Receive the user details and create a Task. This task will simply create a record in the database and then create another task to send out an email.
  • And so on.

2. An online shopping site could accept the order from a buyer. A task is then created in the system that will process the order. As part of the order processing, once shipping is done, another task is told to update the shipping status. Similarly when the logistics provider gives updates on the shipment locations, a task could be launched to update the shipment route of the package.

To summarize, any background (asynchronous) task can be launched when a user initiates the event or when an application or business event occurs. All these tasks are put into one or more user defined or default queues and are executed by the Google App Engine infrastructure on behalf of your application.

What does a Task constitute? What is a Queue ? Who executes it ?

The official documentation of Tasks is excellent and I suggest reading that in detail. In this episode I will cover just about enough for you to get started on Tasks and then dig deeper into them depending on your needs. So let us first understand what is the basic information that I need let the Google App Engine know about my task. I will take the liberty here to describe all the key concepts via an example that we will build in this application.

We wish to implement the following flow in our application:

1. A user wishes to sign up for your newsletter by providing an email id in a web form provided at our site.
2. The user enters the email id and clicks on sign up (a button).
3. The request is sent to a Servlet that accepts the email id and creates a Task. The response is sent back to the user thanking them for their interest.
4. The Task is then executed independently by the Google App Engine infrastructure and our code inside the Task i.e. checking if the email id is used, etc is verified and then an email is sent.

So, as you can see we have decoupled the background task (in step 4) from the sign up process (step 1, step 2 & step3).

It should now be straightforward to define the key elements:

1. Task : This is the unit of work that we wish to perform. In fact, the actor that will be performing this task is Google App Engine. So when we create a Task, we need to provide a standard way for the Google App Engine to invoke tasks and pass them their payload. It should now be straightforward to see that when we create a task, all we need to tell GAEJ is the URL (where to invoke the task) and the parameterized payload (data). This can be done in a standard fashion that you know. The URL is nothing but the servlet URL that will invoke the servlet that implements the Task. And the parameterized data is nothing but request parameters passed into your servlet so that it can execute accordingly. The data in this case will be nothing but the email id of the user who wants to sign up for your newsletter.

2. Queue : All Tasks when they are created are placed in a queue. They are then executed by the Google App Engine. To help us manage and categorize our tasks, you can define your queues by giving them appropriate names. For e.g. myqueue, emailqueue, etc. What this helps you to do is to place your tasks in the appropriate queue. Few points to note about queues (refer to the documentation for finer details):

  • All queues in your application are defined in a file named queue.xml that is present in the WEB-INF folder of your application.
  • Each queue has a unique name and you can control the rate at which tasks are executed in this queue by the Google App Engine. If you do not specify a rate, then the default rate is 5 tasks/second.
  • There is a default queue for your application named ‘default’ and if you can chose to add your tasks to the default queue. Alternately, you can add them to your application defined queue.

I believe this should be sufficient for us to begin developing a simple flow that will demonstrate how to define a task queue, create a task and then see it getting executed by the Google App Engine.

Task Queue in Action

The diagram below shows what we will implement in the next few sections. The use case is that of an user that wishes to subscribe to our newsletter and how we shall break up the process into the request processing and then the task processing.

Let us break down the above flow into the steps given below and what we shall be developing at each step:

1. In Step 1, the user visits a web page and enters his/her email id to sign up for the newsletter. We shall not be developing a web page over here to keep things simple. Instead we shall be testing it out by directly invoking a servlet that accepts the email id of the user. This is the same thing that you would have normally done  by hooking up the action of the HTML form to that of this servlet.

2. In Step 2, we will be looking at a Servlet whose existence is to do some verification and then create a Task for background processing. This servlet (GAEJCreateTaskServlet) will create a Task in a queue called subscription-queue. As we covered earlier, to create a Task, we need to provide two pieces of information to the Google App Engine so that it can execute it. They are the URL and the Data. The URL (/gaejsignupsubscriber) is going to be that of a Servlet (GAEJSignupSubscriberServlet) that shall be doing the core task. And the data will be what the servlet needs to complete the task. In our case, the data is the emailid request parameter.

3. In Step 3, Google App Engine automatically scans the queues for any tasks that are queued up and picks them up for execution. In our case, it will find a Task instance and execute it by invoking the URL (/gaejsignupsubscriber) and passing it the relevant data i.e. emailid

4. Finally in Step 4, our Servlet (GAEJSignupSubscriberServlet) is invoked and it will complete its task. To keep things simple in our example, it will currently only print out a message. But it should be obvious that core logic associated with the task would have gone into the Servlet here. For our specific case, it would have involved checking if the user has not signed up already, creating a database record and then sending off a welcome email.

Implementing the above flow

To summarize the above steps in terms of what we have to code, here is the list:

1. Code the GAEJCreateTaskServlet that will accept the request parameter and create a Task instance in the subscription-queue.

2. Code the GAEJSignupSubscriberServlet that will be invoked by Google App Engine automatically. We will currently only print out a log statement because the intent is to demonstrate the whole sequence.

3. Configure our queue (subscription-queue) in a file named queue.xml. This file needs to be placed in the WEB-INF folder of your application.

4. Configure our GAEJCreateTaskServlet and GAEJSignupSubscriberServlet in the web.xml file.

Finally, we can execute our application and use the local development server to see the application in action. Users can optionally even deploy it to the Google App Engine cloud if they wish.

So let us get started.

GAEJCreateTaskServlet.java

This servlet accepts our request for subscription. We shall invoke it via the following url : http://appurl/gaejcreatetask?emailid=XYZ.

 

package com.gaejexperiments.taskqueue;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.*;

import com.google.appengine.api.labs.taskqueue.Queue;
import com.google.appengine.api.labs.taskqueue.QueueFactory;
import com.google.appengine.api.labs.taskqueue.TaskOptions;

@SuppressWarnings("serial")
public class GAEJCreateTaskServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {

String strCallResult = "";
resp.setContentType("text/plain");
try {
//Extract out the To, Subject and Body of the Email to be sent
String strEmailId = req.getParameter("emailid");

//Do validations here. Only basic ones i.e. cannot be null/empty

if (strEmailId == null) throw new Exception("Email Id field cannot be empty.");

//Trim the stuff
strEmailId = strEmailId.trim();
if (strEmailId.length() == 0) throw new Exception("Email Id field cannot be empty.");
//Queue queue = QueueFactory.getDefaultQueue();
Queue queue = QueueFactory.getQueue("subscription-queue");
queue.add(TaskOptions.Builder.url("/gaejsignupsubscriber").param("emailid",strEmailId));
strCallResult = "Successfully created a Task in the Queue";
resp.getWriter().println(strCallResult);
}
catch (Exception ex) {
strCallResult = "Fail: " + ex.getMessage();
resp.getWriter().println(strCallResult);
}
}

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

 

The code listed below is straightforward to understand. It does the following:

1. Extracts out the request parameter (emailid) and does some basic validation on it.

2. It gets a handle to the subscription-queue through the following statement:

Queue queue = QueueFactory.getQueue("subscription-queue");

3. It adds a Task to the above queue by providing a Task URL (/gaejsignupsubscriber) and Data (emailid parameter). It uses a helper class TaskOptions.Builder to help create the instance of the task. As you can see it provides a url and then the param. The task is created by invoking the add method on the queue.

queue.add(TaskOptions.Builder.url("/gaejsignupsubscriber").param("emailid",strEmailId));

4. For the readers information, I have shown a commented out line

//Queue queue = QueueFactory.getDefaultQueue();

which shows how to get the handle to the default queue in case you wish to place your tasks in the default queue itself.

5. Do not that all the Task Queue classes are experimental and are present in the com.google.appengine.api.labs.taskqueue package. This could change in the future.

GAEJSignupSubscriberServlet.java

This servlet contains the core task logic. This will be invoked by Google App engine if it finds any tasks present in the subscription-queue. If any tasks are there, it will pick them up and invoke the URL mentioned in the Task and pass to it the data present in the Task instance.  The code shown below is straightforward, it simply logs a statement saying that it got invoked and it also logs the email id.

 

package com.gaejexperiments.taskqueue;

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

import javax.servlet.ServletException;
import javax.servlet.http.*;

@SuppressWarnings("serial")
public class GAEJSignupSubscriberServlet extends HttpServlet {
private static final Logger _logger = Logger.getLogger(GAEJSignupSubscriberServlet.class.getName());
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {

String strCallResult = "";
resp.setContentType("text/plain");
try {
String strEmailId = req.getParameter("emailid");
_logger.info("Got a Signup Subscriber Request for Email ID : " + strEmailId);
//
// PUT YOUR TASK CODE HERE
//
strCallResult = "SUCCESS: Subscriber Signup";
_logger.info(strCallResult);
resp.getWriter().println(strCallResult);
}
catch (Exception ex) {
strCallResult = "FAIL: Subscriber Signup : " + ex.getMessage();
_logger.info(strCallResult);
resp.getWriter().println(strCallResult);
}
}

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

}

 

queue.xml

All queues are configured in a file named queue.xml. Google App Engine provides a default queue. This queue is aptly named “default“. But in case you need to define your own queues, which is what we are going to do, we need to define them in a file called queue.xml. This file is placed in the WEB-INF directory of your application. You can also override settings of the default queue by defining it in the file and providing your own values.

Take a look at the queue.xml shown below:

<?xml version="1.0" encoding="UTF-8"?>
<queue-entries>
<queue>
<name>default</name>
<rate>5/s</rate>
</queue>
<queue>
<name>subscription-queue</name>
<rate>5/s</rate>
</queue>
</queue-entries>

In the above configuration, you will find that we have defined our own queue named “subscription-queue”. There is also another element that we have defined for the <queue> called <rate>. This element determines the rate at which you tell Google App Engine to execute tasks. If you do not specify a rate, then the default execution rate is 5 tasks per second. In the above file, we have provided the expression as “5/s”, which reads as 5 per second. Other examples of <rate> expressions are 1000/d (One thousand per day), etc. I suggest to read up the documentation for more examples.

You will also find that we have defined the default queue and we can change the rate if we want. But I have left it as is.

Please make sure that the above file (queue.xml) is present in the WEB-INF folder at the time of deploying the application.

Configuring the Servlets (web.xml)

We 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. We are defining here both our servlets.

<servlet>
<servlet-name>GAEJCreateTaskServlet</servlet-name>
<servlet-class>com.gaejexperiments.taskqueue.GAEJCreateTaskServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>GAEJSignupSubscriberServlet</servlet-name>
<servlet-class>com.gaejexperiments.taskqueue.GAEJSignupSubscriberServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GAEJSignupSubscriberServlet</servlet-name>
<url-pattern>/gaejsignupsubscriber</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>GAEJCreateTaskServlet</servlet-name>
<url-pattern>/gaejcreatetask</url-pattern>
</servlet-mapping>

Task Execution in Action

I am assuming that you have already created a new Google Web Application Project and have created the above Servlets, web.xml and queue.xml respectively. For a change, we shall be running this episode within our local development server only.

So assuming that all is well, we will run our application, by right-clicking on the project and selecting Run As –> Web Application. Once you see the following message shown below, then the local server is ready to accept requests.

Nov 24, 2009 5:11:33 AM com.google.apphosting.utils.jetty.JettyLogger info
INFO: jetty-6.1.x
Nov 24, 2009 5:11:40 AM com.google.apphosting.utils.jetty.JettyLogger info
INFO: Started SelectChannelConnector@127.0.0.1:8080
The server is running at http://localhost:8080/

Follow the steps given below:

1. Launch the browser on your local machine and navigate to http://localhost:8080/_ah/admin. This is the administrative console of the local development server.

2. Click on Task Queues to view the current task queues that are configured in your application. You should see the screen shown below, which shows that we have configured two task queues: default and subscription-queue.

You will notice that both of the queues currently do not have any tasks since we have not created any.

3. The next step is to create a task in the subscription-queue. To do that, all we need to do is invoke the following url :

http://localhost:8080/gaejcreatetask?emailid=romin@rocketmail.com

This invokes our GAEJCreateTaskServlet that we have configured. It will create the sample task in the subscription-queue and we will see a message as shown below in the browser:

“Successfully created a Task in the Queue”

4. Click on the Task Queues link again, you will find that there will now be 1 task listed in the subscription-queue as shown below:

5. Click on the subscription-queue link. This will display the task instance as shown below:

6. Since this is the development server, no automatic execution of tasks (this will occur in Google App Engine cloud) will take place and you have to run them manually, by clicking on the Run button. Click that. It will display that there are no more tasks present if the task executes successfully.

7. To check that our task has executed successfully, we can visit the Console tab in Eclipse and you will see the success log as shown below:

Moving on

In this episode, we saw how to split up a process into individual tasks and assign them to the Google App Engine for execution. What we have demonstrated here is a simple flow and the specifics of the configuration. I encourage you to try it out in your applications and as an exercise deploy it to the Google App Engine and monitor it there via the Administration Console.

Do keep in mind that this API is experimental and is likely to change drastically. At the same time, if you have any feedback, it would be nice to pass it along to the Google App Engine team.

Till the next episode, Happy Multitasking!

 

Welcome to Episode 9. In this episode, we shall be looking at how you can run background tasks in your GAEJ Application. By background Task, I mean any piece of code that you would like to run at a scheduled time and independent of the user interaction.There are several examples of such tasks. For e.g. :

  • Hourly/Daily/Weekly/Monthly backup of data
  • End of the day report generation to report any errors, transactions, etc.
  • Sending an email at the end of the day (or once a day) with some information to subscribers. For e.g. News sites.

If you have written a few web applications, you would definitely have come across more scenarios like that.

In this episode, we shall cover the following:

  1. What is a Cron Job?
  2. How to schedule a Cron Job?
  3. Write a simple Cron Job that prints a single statement
  4. Configure, execute and monitor the Cron Job execution

Let’s go!

What is a Cron Job? When would you need one?

I will use information liberally from Wikipedia over here to explain some of the core concepts. You can refer to the Cron page at Wikipedia if you want.

The word ‘cron’ is short for Chronograph. A Cron is a time-based job scheduler. It enables our application to schedule a job to run automatically at a certain time or date. A Job (also known as a Task) is any module that you wish to run. This module can perform system maintenance or administration, though its general purpose nature means that it can be used for other purposes, such as connecting to the Internet and downloading email.

Examples include:

  • Taking a daily backup of data via a scheduled task and moving the file to another server. (Runs once daily)
  • Sending an email every week to your subscribers. (Runs once weekly)
  • Clearing the log files at the end of every day (Runs once daily)
  • Remind yourself of a wonderful weekend coming up, every Friday at 5:00 PM (Runs once a week on a Friday at 5:00 PM)

The Google App Engine provides a service called the Cron Service that helps us do two fundamental things:

  1. Allows your application to schedule these tasks.
  2. Execute these tasks based on their schedule.

What does a Cron Job look like? And how do I schedule one?

A Cron Job is nothing but a URL that is invoked by the Google App Engine infrastructure at its scheduled execution time. To write a Cron Job, you need to do the following:

1. Write a Java Servlet and configure it in the web.xml. Note down the URL where the servlet can be invoked. The URL is the <url-pattern> mentioned in the <servlet-mapping> for your Servlet configuration in web.xml. For e.g.  the URL is the <url-pattern> element specified in the segment of the web.xml that is shown below:

 

<servlet>
<servlet-name>GAEJCronServlet</servlet-name>
<servlet-class>com.gaejexperiments.cron.GAEJCronServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>GAEJCronServlet</servlet-name>
<url-pattern>/cron/mycronjob</url-pattern>
</servlet-mapping>

 

2. Create a cron.xml file that specifies one or more Cron Jobs (Scheduled Tasks) that you want to execute. A sample for the above Cron Job is shown below:

<?xml version="1.0" encoding="UTF-8"?>
<cronentries>
<cron>
<url>/cron/mycronjob</url>
<description>Put your Cron Job description here</description>
<schedule>Put Cron Job Schedule here</schedule>
</cron>
</cronentries>

The cron.xml file tells Google App Engine about the Cron Jobs that are scheduled by your application. This file resides in the WEB-INF directory of your application and is copied to the App Engine cloud when you deploy the application. The following points are important about the cron.xml file:

  1. Each Cron Job configured in your application is defined in a <cron/> element. So there can be one or more <cron/> elements.
  2. The above <cron/> element has the following 3 elements that defines the Job.
    • <url/> specifies where the Google App Engine can invoke your Cron Job. This is nothing but the Servlet URL that you defined in the web.xml file that we saw earlier.The Servlet URL will point to your Servlet which contains the Cron Job implementation.
    • <description/> is a simple text based description of what your Cron Job does. It does not influence any aspect of the execution and is used for display purposes when you look at your application configuration via the App Console.
    • <schedule/> is the time when your Job has to be executed. This is where you specify if your job is to be run daily, once every hour, on Friday at 5:00 PM, etc. It is completely dependent on when you wish to execute this job. However, you must follow some rules and they are specified in the documentation on Scheduling Format. I strongly recommend you to read it up to understand various ways of specifying the schedule. Some of the examples are: “every 1 minute”, “every 12 hours”, “every friday 17:00″ and so on.

Develop a simple Cron Job

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 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.

GAEJCronServlet.java

Our Cron Job is going to be very simple. It is simply going to print out a statement in the log file that says that it is getting executed. The Cron Service of Google App Engine automatically will invoke this Servlet when its scheduled time to execute has arrived. So all we need to do is code out Servlet. The code is shown below:

 

package com.gaejexperiments.cron;

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

import javax.servlet.ServletException;
import javax.servlet.http.*;

@SuppressWarnings("serial")
public class GAEJCronServlet extends HttpServlet {
private static final Logger _logger = Logger.getLogger(GAEJCronServlet.class.getName());
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {

try {
_logger.info("Cron Job has been executed");

//Put your logic here
//BEGIN
//END
}
catch (Exception ex) {
//Log any exceptions in your Cron Job
}
}

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

 

The code is straightforward to understand. It has doGet() and doPost() methods. And you will find in the doGet() method, that we simply log with an INFO level, that the Cron Job has been executed. In fact, your actual Job implementation should go in here as indicated by the comments. So whether you are invoking a backend database, or sending a consolidated email report, etc should all go in here.

All that remains is to now tell the App Engine via configuration about your Servlet (via web.xml) and create the cron.xml file in which you will mention your Cron Job.

Configure the Cron Job

As mentioned, we need to configure the Servlet in the web.xml and also specify it in the cron.xml file. Let us look at that now:

Configuring the Servlet

We 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>GAEJCronServlet</servlet-name>
<servlet-class>com.gaejexperiments.cron.GAEJCronServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>GAEJCronServlet</servlet-name>
<url-pattern>/cron/gaejcronjob</url-pattern>
</servlet-mapping>

 

Specifying the Cron Job (cron.xml)

The cron.xml for our application will contain only one Cron Job. And here we specify the Servlet URL along with the schedule. Notice that I have chosen to execute this Cron job every 2 minutes. But you are free to experiment if you like with different Schedule Formats. This files needs to be created in the WEB-INF folder of your project.

<?xml version="1.0" encoding="UTF-8"?>
<cronentries>
<cron>
<url>/cron/gaejcronjob</url>
<description>GAEJExperiments Cron Job that simply announces that it got invoked.</description>
<schedule>every 2 minutes</schedule>
</cron>
</cronentries>

Deploy the Application

To deploy the application, follow these steps (they should be familiar to you now. I am assuming that you already have the Application ID with you):

  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 gaejexperiments]
  4. Click on OK. You will be lead back to the previous screen, where you can click on the Deploy 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”.

We can now check if the Google App Engine got our Cron Job correctly configured and verify if it is getting executed at the schedule that we have configured it to.

Monitoring the Cron Job

You can use the App Engine console to verify if your Cron Job is executing well or not. To do that, perform the following steps:

  1. Go to http://appengine.google.com and log in with your account.
  2. You will see a list of applications registered. Click on the application that you just deployed. In my case, it is gaejexperiments.
  3. When you click on a particular application, you will be taken to the Dashboard for that application, which contains a wealth of information around the requests, quotas, logs, versions, etc.
  4. Verify that the Cron Jobs that you specified in the cron.xml have been configured successfully for the application by clicking Cron Jobs, visible under Main. For our application that we deployed, here is the screen shot from the App Engine console:ep9-1

You will notice that the Cron Job has not yet run as the console indicates. Every time that the job is executed, this column is updated with the last date time stamp that the Job executed along with its status. Since we have configured our Job to run every 2 minutes, I waited for 2 minutes and then the job executed itself and when I refreshed the Cron Jobs page, the status was updated as shown below:

ep9-2

You can also click on the Logs link. This will display the application log. And all your application log statements that you code using the Logger class can be visible here. By default, the severity level is set at ERROR and we can change that to INFO and you should be able your log statements that had the log level of INFO. This was the log level at which we had logged the statement in our Java Servlet (Cron Job). Shown below is a screen shot of the log when the Cron Job was fired once.

ep9-3

Conclusion

This concludes Episode 9 of this series in which you learn how to schedule tasks in your Google App Engine applications. These background tasks that can be scheduled at a certain time and which are executed by the Cron Service are an indispensable part of several web applications that are deployed today. If you ever wish to do repeated tasks in your application without any user intervention like sending emails, crawling web sites, taking database backups, etc, then writing a Cron Job and scheduling it for execution is a key feature that you can utilize while deploying your application to Google App Engine.

There is a lot more to Cron Jobs and I suggest to read up the documentation.

Till the next episode, Happy Scheduling!

 

Welcome to Episode 8. In this episode, we shall cover an important service that is provided in the Google App Engine. The service is called Memcache and is used allow applications to manage their data in a cache.

What is a Cache and why do we need one?

As per the Wikipedia definition, a cache is a temporary storage area where frequently accessed data can be stored for rapid access. Once the data is stored in the cache, it can be used in the future by accessing the cached copy rather than re-fetching or recomputing the original data.

The decision to use a cache in your application should come after carefully determining which operations would be benefit from it. Look at the following scenarios:

1. If you have stored information in a database and which is not updated frequently, then it might make sense to put some of that information in a cache so that if multiple requests come for the same data then you can simply look up the memory cache and retrieve it from there, rather than make repeated database calls that are expensive (and which may return the same data).

2. If you invoke external web services and you determine that the same data could be requested, then a cache would help here too to avoid expensive network calls.

There is a lot of material available on the use of a cache in software applications and I suggest reading from those sources to arrive at a good caching design in your applications. We shall keep our discussion here limited to a simple use case of using Memcache, which is a Caching Service provided by Google App Engine and how to implement it quickly in your application.

Before we begin (Important!)

We will be introducing MemCache in an existing application that we have written. This was the Dictionary Service Application that we implemented in Episode 4. I strongly urge you to read up that episode and understand what the application was about and have that project ready to make changes accordingly.

To recap, our GAEJ Dictionary application is shown below:

1. Navigate to http://gaejexperiments.appspot.com/dictionary.html. This will show a page as shown below:

s2

2. Enter the word that you wish to lookup the definition for in a dictionary and it will return you the result as shown below:

s3

Introducing a Cache

The request/response flow for the above Dictionary application is explained below via the diagram shown:

CacheEpisode1

The steps were as follows:

1. The user makes a request to the GAEJ Experiments application by sending a request for the word.

2. The GAEJ Dictionary Service Servlet receives the Request and makes a call to an External Dictionary Service hosted at (http://services.aonaware.com/DictService/DictService.asmx).

3. The Response from the Dictionary Service i.e. the definition of the word is received by the GAEJ Dictionary Service Servlet.

4. The Response is sent back to the user application.

The flow is straightforward and typically found in most applications. Now, what happens if several users make a request for the same word? As per the application flow, each request from the user will result in a call to an external service for the definition, irrespective of whether it was the same word or not. This is wasteful in terms of network resources and the application response too. Coupled with the fact that the definition of a word is not going to change overnight :-) , it would be nice to return back the definition from the GAEJExperiments application itself, if the word definition had been looked up already. Enter a cache!

So, what we are introducing in our application flow now is a cache called GAEJ Dictionary Cache and the modified application flow is shown below:

CacheEpisode2

The steps now would be as follows:

1. The user makes a request to the GAEJ Experiments application by sending a request for the word.

2. The GAEJ Dictionary Service Servlet receives the Request and checks if the word and its definition is already present in the Cache. If it is present in the Cache, then we short circuit and go to Step 6.

Optional Steps (3,4,5)
3. If the Servlet does not find the definition in the Cache, then it makes a call to the External Dictionary Service hosted at (http://services.aonaware.com/DictService/DictService.asmx).

4. The Response from the Dictionary Service i.e. the definition of the word is received by the GAEJ Dictionary Service Servlet.

5. The Servlet puts the word and its definition in the Cache, so that future requests to determine if the word/definition is present in the Cache are fulfilled.

6. The Response is sent back to the user application.

To summarize, we introduced the Cache that functions as follows:

  • All word definitions looked up from the External Service are placed in the Cache.
  • If a word is already present in the Cache, then it is returned from the Cache itself and an external network call is saved.

The Memcache Service API

A cache is typically implemented as a Map. A Map is a generic data structure that contains a key and its value. You look up the Cache by specifying the key and if it is found, then the value associated with that key is returned. What I am describing here is an over simplification of what a Cache is. There is a lot more to a Cache implementation then just putting a value and getting a value. But we shall keep it simple here.

The Memcache Service API is simple enough to use and there is good documentation available on it here. The Memcache Service implements JSR-107 (JCache Interface). The JCache classes are present in the javax.cache package and that it what you will use.

At a high level, all you need to do is follow these steps:

1. Get a handle to the Cache implementation:

The snippet of code to do that (reproduced from the Documentation) is shown here:

 

import java.util.Collections;
import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.CacheFactory;
import javax.cache.CacheManager;

Cache cache;

try
{
CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
cache = cacheFactory.createCache(Collections.emptyMap());
}
catch (CacheException e)
{
// ...
}

 

The code is simple. We get a handle to the CacheFactory instance and then create a Cache. Notice that we are creating a Map i.e. an empty Map. Once we have the Map, then all we need to do is play around with the (key,value) pairs.

2. Put a value or get a value from the Cache

Shown below is how we would use the cache in a simple manner. We invoke the put(key,value) method on the javax.cache.Cache instance. Similarly, to extract a value, we need to invoke the cache.get(key) value. It will return us the value if found, which we can then typecast to the appropriate class.

 

String key;      // The Word
String value;    // The Definition of the Word

// Put the value into the cache.
cache.put(key, value);

// Get the value from the cache.
value = (String) cache.get(key);

 

GAEJDictionaryCache.java

Let us first discuss a utility class that I have written that encapsulates the Caching API. I have made this class a singleton and it is called GAEJDictionaryCache. The source code is shown below:

 

package com.gaejexperiments.networking;

import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.CacheFactory;
import javax.cache.CacheManager;

public class GAEJDictionaryCache {
public static final Logger _log = Logger.getLogger(GAEJDictionaryCache.class.getName());

private static GAEJDictionaryCache _instance;
private Cache cache;

private GAEJDictionaryCache() {
try {
CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
cache = cacheFactory.createCache(Collections.emptyMap());
}
catch (CacheException e) {
//Log stuff
_log.log(Level.WARNING, "Error in creating the Cache");
}
}

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

public String findInCache(String word) {
if (cache.containsKey(word)) {
return (String)cache.get(word);
}
else {
return null;
}
}

public void putInCache(String word, String definition) {
cache.put(word,definition);
}
}

 

Let us discuss the key parts of the code:

  1. The Singleton design pattern should be obvious over here and the application needs to use the getInstance() method to obtain a handle to this singleton.
  2. The constructor of this class is private and called only once. In that an instance of the Cache is created.
  3. There are two utility methods written : findInCache and putInCache.
  4. The application invokes findInCache by providing a key value. If the key is found, the value is written via the cache.get(key) method. For our dictionary application, the key is the word that you wish to look up the definition for.
  5. If the application wants to put a key,value record into the Cache, then it invokes the putInCache(…) method that takes the key and the value. For our dictionary application, the key is the word and the value is the definition of the word.

By encapsulating the MemCache Service API in this fashion, you can create a reusable class that takes care of Cache API details. You could then improve upon this class and provide advanced Cache features and APIs and reuse it in all your future GAEJ applications.

Modifying the Original GAEJDictionaryService.java class

All that remains now is for us to modify the existing GAEJDictionaryService.java class by introducing the appropriate cache usage. The modified code is shown below and I suggest to look at the comment //MEMCACHE to make it easier for you to see what I have changed.

 

package com.gaejexperiments.networking;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.URL;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

@SuppressWarnings("serial")
public class GAEJDictionaryService extends HttpServlet {
public static final Logger _log = Logger.getLogger(GAEJDictionaryService.class.getName());
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {

String strCallResult = "";
resp.setContentType("text/plain");
try {

//Extract out the word that needs to be looked up in the Dictionary Service
String strWord = req.getParameter("word");

//Do validations here. Only basic ones i.e. cannot be null/empty
if (strWord == null) throw new Exception("Word field cannot be empty.");

//Trim the stuff
strWord = strWord.trim();
if (strWord.length() == 0) throw new Exception("Word field cannot be empty.");

//MEMCACHE
//First get a handle to the Cache
GAEJDictionaryCache _cache = GAEJDictionaryCache.getInstance();

//Determine if the value is present in the Cache
String strWordDefinition = _cache.findInCache(strWord);

//If the word/definition is present in the Cache, return that straightaway, no need for external network call
if (strWordDefinition != null) {
//Return the definition
_log.info("Returning the Definition for ["+strWord+"]"+" from Cache.");
strCallResult = strWordDefinition;
}
else {
_log.info("Invoking the External Dictionary Service to get Definition for ["+strWord+"]");
//Make the Network Call
String strDictionaryServiceCall = "http://services.aonaware.com/DictService/DictService.asmx/Define?word=";
strDictionaryServiceCall += strWord;
URL url = new URL(strDictionaryServiceCall);
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
StringBuffer response = new StringBuffer();
String line;

while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();

strCallResult = response.toString();

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(strCallResult.toString())));

XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("//Definition[Dictionary[Id='wn']]/WordDefinition/text()");

Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
strCallResult = nodes.item(i).getNodeValue();
}

//MEMCACHE
//Need to check depending on your logic if the values are good
//Currently we will assume they are and put it in the cache
//For e.g. if the word is not found, the Dictionary Service gets the word back.
//So you could use that logic if you want.
_cache.putInCache(strWord, strCallResult);
}

resp.getWriter().println(strCallResult);

}
catch (Exception ex) {
strCallResult = "Fail: " + ex.getMessage();
resp.getWriter().println(strCallResult);
}
}

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

}

 

Let us discuss the modified flow in brief:

  1. We first extract out the word request parameter and do some basic validation to make sure that it is not empty.
  2. We get the handle to the Cache by calling our utility class that we just wrote.
    //First get a handle to the Cache
    GAEJDictionaryCache _cache = GAEJDictionaryCache.getInstance();
  3. We check if the word is present in the cache. The findInCache method will return null if not found.
    //Determine if the value is present in the Cache
    String strWordDefinition = _cache.findInCache(strWord);
  4. If the definition is returned from the cache, then we simply return that and no network call is made.
  5. If the definition is not found, then the network call is made, the response stream is parsed out for the definition. And the most important step is to put this definition in the cache, so that the findInCache(…) method will get the definition, the next time another request for the same word is made.

    _cache.putInCache(strWord, strCallResult);

Try it out

You can try out the modified Dictionary Service application at: http://gaejexperiments.appspot.com/dictionary.html. The first time that you search for a word, it might take some time to get back the definition but once present in the cache, it is returned much faster. Do note, that if the same word has been looked up by another user, then the word and its definition will be present in the cache.

Cache Design considerations

A cache if implemented well will save your application from repeated resource intensive operations and also improve application response times significantly. Of course, simply putting in a cache comes with risks. Some of the factors, you need to take into consideration are:

1. Determine precisely which operations in your application would benefit from a cache.

2. Analyse if the data that you are putting in a cache changes frequently or not. If it changes frequently, then it might negate the benefits of a cache.

3. Control the size of the cache and prevent it from becoming too large or unmanageable. The way we have implemented it, the cache will keep growing and we are leaving it to the App Engine run time to truncate our cache due to memory limitations if any.

4. Take into consideration several other factors like what is an interval across which you want to refresh the cache, cache expiration policies, etc.

In short, monitoring the cache and tuning its parameters is required from any production worthy application.

Moving on

This brings Episode 8 to an end. Hope you enjoyed reading it.

Dictionary Application in Action

In order to maintain a consistent style across the episodes so far, let us first watch the application in action to better understand what we will be building over here. Follow these easy steps:

  1. Navigate to http://gaejexperiments.appspot.com. This will result in a page as shown below:s1
  2. Click on Dictionary Service link. This will lead you to a page shown below:s2
  3. Enter any word that you wish to lookup in the dictionary and click on Lookup Dictionary. For e.g. engine. This will display the meaning of the word as shown below:s3
 

Please note that this article uses the older version of the Robot API. A newer release (version 2.0) of the Robot API is out and is recommended by Google. An updated article that uses the new Robot API version 2.0 is published here.

Welcome to Episode 7 of this series. Hope that the series has been interesting for you so far. In this episode, we plan to jump onto the Google Wave bandwagon. Google Wave, as you must have heard is a collaborative messaging platform from Google. A Wave is a collaboration between several participants (humans and non-humans) using threaded conversations/documents/gadgets to achieve their task. The task could be as simple as chatting among themselves to figure out where to dine tonight to as complex as achieving a Return Order process between a purchaser and seller.

I will not delve into the specifics of Google Wave and will assume that you have a high level idea of what it is. In fact, a great online book has just been released that covers Google Wave in depth. I strongly recommend you to read it if you want to look into Google Wave in detail. The book is named The Complete Guide to Google Wave and you can read it here.

What does this episode cover?

In this episode, we are going to look at how you can write a Google Wave Robot using the Google plugin in Eclipse. We will then deploy it and host this robot in the Google App Engine cloud. This Robot is then live and can be added to any Wave and participate in the conversation.

It helps to see the final result before we start out. Even if you do not understand whats going on, just bear with me. So here is the screenshot:

ep7-17

Let us dissect this screen and in the process, I can hopefully explain to you some Google Wave terminology in a straightforward manner without too many details. The main points are:

1. What you see in the screen above is a Google Wave that me (the person with the photo created). A Wave is a collaboration between one or more participants (human or Robots).

2. Since we need participants to make it meaningful, you can add one or more of them. All you need to do is click the + sign that you see on the top. And  you can add one or more participants who are also signed up for Wave. In this case, my Robot GAEJ Application is hosted at http://gaejrobot.appspot.com and so I can add gaejrobot@appspot.com as a participant.

3. On adding the Robot participant, Google wave system pulls up its profile (image, etc) and adds it as a participant in the Wave that I created.

4. The Robot can receive events and it can respond to them. We shall see how to write them later (source code!!), but at this point it is enough to understand that the Robot can choose what events to listen to as the Wave collaboration happens and it can then react to them. So in the case of my GAEJ Robot, I have specified that I am interested in knowing when participants come and leave the Wave and when someone has submitted a message.

5. So you can see that the GAEJ Robot was notified when it was added to the Wave, so in response to that it printed out the message “Hi! Your GAEJExperiments Bot…..” at the bottom. Similarly, when I finished typing the message (Hello GAEJ Robot), the GAEJ Robot got notified. It then took the message and along with some metadata like ID and Creator Name, it simpy echoed back what I typed.

Hope this makes things clear. But a few more terms first : Wave, Wavelet and Blip. Let me keep it simple. In the above example, the Wave was the entire container. A Wave consists of one or more Wavelets. A Wavelet can be thought of as a threaded conversation that can go on within the wave (both public and private). And each Wavelet consists of one or more messages known as a Blip. A Blip is the actual message that was typed and submitted by the user. So when I typed “Hello GAEJ Robot” above, it was a Blip.

I have simplified things a bit here but even if things are not clear at this point, do not worry. Once you get your code working, things will fall in place.

A final note above Google Wave Extensions. Extensions are the mechanism by which you can extend Google Wave by adding your own creations. Extensions are of two types : Gadgets and Robots. Gadgets are like mini-applications that run within the Google Wave client. They can be typically thought of as a UI which several participants can share at the same time. A Robot is a full blown participant in the Wave. It can be aware of most things happening in the Wave by subscribing to Events. It also has a lot of potential to modify things in the Wave like messages, etc. This article focuses on writing a Robot. If you are interested in a good summary of Google Wave Extensions and some key differences between a Gadget and a Robot, read it here.

OK, so enough of theory. Let us get down to coding. If you are new to developing with the Google Plugin for Eclipse, please read the earlier episodes to setup your environment (Episode 1 and Episode 5)

Create a New Project

We need to create a New Project first. Follow the steps below:

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 MyFirstGoogleWaveRobot and I suggest you go with the same name so that things are consistent with the rest of the article. The Screenshot is shown below:

ep7-1

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. So I suggest that you can delete the Servlet Java class and the mappings made in the web.xml or you can leave it for now since we are going to write our own.

The directory structure for your project should now look like this.

ep7-2

Adding Google Wave Robot JAR files to your Project Path

Since we are going to be writing a Wave Robot, we need some additional files on the client side. These additional files (JAR files) are required for the additional Wave API’s and also for deployment in your WEB-INFlib folder, so that they are correctly deployed and available to the run-time engine. These JAR files do not ship along with the Google Eclipse plugin, so you will need to download them for a website. The Google code website for the JAR files is:

http://code.google.com/p/wave-robot-java-client/downloads/list

The web page when you navigate to the above URL is shown below:

ep7-6

Download all the above files to your machine. Once you have downloaded the files, follow these steps to setup your Project Build Path and runtime correctly.

1. Copy all the 4 JAR files to the WEB-INFlib folder of your Eclipse Project. After copying you should see the files as shown in the project hierarchy below:

ep7-4

2. Right-click on the Project in the Project Hierarchy. Select Properties and then Java Build Path. Click on Add JARs and then select the 4 JAR files from your Project WEB-INFlib folder as shown below and click on OK.

ep7-5

3. Your Project Build Path should like the screenshot below.

ep7-51

Click on OK to proceed. This completes your Build Path setup with the Google Wave Robot JAR files.

Writing the Google Wave Robot Servlet : MyFirstGoogleWaveRobot.java

Let us first create our Robot Java class. The steps are straightforward and given below. All we need to do is write our class that extends the com.google.wave.api.AbstractRobotServlet class and provide an implementation for the processEvents method.

Follow these steps:

1. Create a new Java class within the same package. The New Java Class dialog is shown below. I have named the class MyFirstGoogleWaveRobot as shown below. Click on the Browse button to select a Super Class.

ep7-7

2. In the Superclass Selection dialog shown below, type the word AbstractRobot (some part of it is also OK as the screenshot shows below) in the Choose a type field as shown. This will bring up the correct Matching items i.e. com.google.wave.api.AbstractRobotServlet. Click on OK

ep7-8

This will generate the code as shown below in your Eclipse IDE.

ep7-9

Simply overwrite it with the code shown below:

 

package com.gaejexperiments.waverobot;

import com.google.wave.api.AbstractRobotServlet;
import com.google.wave.api.Blip;
import com.google.wave.api.Event;
import com.google.wave.api.EventType;
import com.google.wave.api.RobotMessageBundle;
import com.google.wave.api.TextView;
import com.google.wave.api.Wavelet;

public class MyFirstGoogleWaveRobot extends AbstractRobotServlet {

@Override
public void processEvents(RobotMessageBundle bundle) {
Wavelet wavelet = bundle.getWavelet();
if (bundle.wasSelfAdded()) {
Blip blip = wavelet.appendBlip();
TextView textView = blip.getDocument();
textView.append("Hi! Your GAEJExperiments Bot is waiting for your command...");
}

for (Event e: bundle.getEvents()) {
if (e.getType() == EventType.BLIP_SUBMITTED) {
//Get the Blip that was submitted
Blip blip = e.getBlip();

//Extract out MetaData information like ID and the creator of the Blip
String strBlipMetaData = "Blip Id : " + blip.getBlipId() + " , " + "Blip Creator : " + blip.getCreator();

//Extract out the text that was entered in the blip
String strBlipText = "You typed : " + blip.getDocument().getText();

//Echo that out by creating a child within the submitted blip
blip.createChild().getDocument().append(strBlipMetaData + "rn" + strBlipText);
}
}
}
}

 

Let us discuss the main points of the source code:

1. A Robot class needs to extend the com.google.wave.api.AbstractRobotServlet class

2. The only method that you need to implement to get going is the processEvents() method as shown above in the code. In this method, all we need to do is process the Events that we are interested in and take some action.

3. What we want our Robot to do is to announce itself to everyone when it is added to the Wave. This event is also pumped into the processEvents method but the API provides us a nice convenient method to detect if we have been added to the Wave via the bundle.wasSelfAdded() method. The code snippet is shown below:

 

public void processEvents(RobotMessageBundle bundle) {
Wavelet wavelet = bundle.getWavelet();
if (bundle.wasSelfAdded()) {
Blip blip = wavelet.appendBlip();
TextView textView = blip.getDocument();
textView.append("Hi! Your GAEJExperiments Bot is waiting for your command...");
}

//...Rest of processEvents method
}

 

So the first thing we are doing is determining if we (i.e. the Robot has been added to the Wave. If yes, we need to add a message to the Wavelet (Threaded Conversation). Remember a message is known as a Blip. So we append a new Blip to the current wavelet. And now we need to set the message text for the Blip. To do that, we need to get the handle to a TextView for the Blip and then we append our Text to it. As simple as that.

4.  Then we have the main Events loop in which we navigate through the events that are pumped into the loop by the Google Wave system. The code snippet is shown below:

 

for (Event e: bundle.getEvents()) {
if (e.getType() == EventType.BLIP_SUBMITTED) {
//Get the Blip that was submitted
Blip blip = e.getBlip();

//Extract out MetaData information like ID and the creator of the Blip
String strBlipMetaData = "Blip Id : " + blip.getBlipId() + " , " + "Blip Creator : " + blip.getCreator();

//Extract out the text that was entered in the blip
String strBlipText = "You typed : " + blip.getDocument().getText();

//Echo that out by creating a child within the submitted blip
blip.createChild().getDocument().append(strBlipMetaData + "rn" + strBlipText);
}
}

 

If the EventType is BLIP_SUBMITTED i.e. someone has submitted a message, then we first get the handle to the Blip. The Blip is not just the Text but a lot of other useful metadata. I simply demonstrate here two kinds of information about the blip, a BlipId and a Blip Creator. The blip creator is the name of the participant that created this blip. Then as we saw, we get to the Text of the Blip, by getting a handle on the getDocument() and then the getText() method. This gives us the text that was typed by the creator of the Blip. Finally, I insert a child Blip inside the Blip so that it looks like a response to that blip within the Google Wave. The response is nothing but a text appended with the metadata extracted and the echoing of the text that the creator typed.

Using this boiler plate of code, you can do your own thing. You could interpret commands given in a Blip by anyone and execute them and append the responses to their Blip. You could look up data on Amazon or any other web site if given the ISBN. The possibilities are limitless if you wish to modify the above code and make your Robot do something else.

That is all to writing a Robot but we still have some configuration to do to let Google Wave know that we have a Robot running in our GAEJ Application. And we will do that through the standard servlet entries in the web.xml file along with new XML configuration file that you need for the Robot called the capabilities.xml file.

Configuring the Robot Servlet

We need to add the Robot Servlet <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.

<servlet>
<servlet-name>MyFirstGoogleWaveRobot</servlet-name>
<servlet-class>com.gaejexperiments.waverobot.MyFirstGoogleWaveRobot</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyFirstGoogleWaveRobot</servlet-name>
<url-pattern>/_wave/robot/jsonrpc</url-pattern>
</servlet-mapping>

In the above fragment, you will note that url-pattern /_wave/robot/jsonrpc has to be mapped to the Robot Servlet that you have written. This is because the Google Wave system will invoke this url to communicate with your Robot using its protocol.

Creating the Robot capabilities.xml files

We need an additional file to describe the capabilities of the Robot that we have written. This file is called the capabilities.xml and it needs to reside in a certain location. You need to create a _wave directory inside of the war directory of your project. The location of this file is shown below under the war/_wave directory.

ep7-10

You will need to create the _wave directory and create the capabilities.xml file over there. The capabilities file shown below is pretty straightforward. Two items are of interest. One is the a <capability> element for each EVENT that you wish your Robot get notified about. If you go back to the Source code of our Robot, you will notice that we were primarily interested in two events:

1. BLIP_SUBMITTED : Take a look at the source code. You will find that we checked for this event in our Events Loop and once a Blip (Message) was available, we extracted information and sent back a child Blip.

2. WAVELET_PARTICIPANTS_CHANGED: Take a look at the source code. This event was fired and we used a convenience method called bundle.wasSelfAdded() to find if we were added. In fact, you can put in an if else clause and catch this event in the Events loop too to get notified whenever anyone joins or leaves the Wave.

Now that it is clear that we need these two events, we subscribe to them by specifying the events in the capabilities.xml document. Any other events (Look at the com.google.wave.api.EventType class) that you are interested in should be mentioned here, otherwise your robot will not get notified about them. The other element is the <version> element. If you change any capabilities in your robot, then it is recommended that before you deploy, you change the version value over here, so that Google Wave can detect that there is a newer version and hence it can then query for your modified capabilities if any.

<?xml version="1.0" encoding="utf-8"?>
<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">
<w:capabilities>
<w:capability name="WAVELET_PARTICIPANTS_CHANGED" content="true" />
<w:capability name="BLIP_SUBMITTED" content="true" />
</w:capabilities>
<w:version>1</w:version>
</w:robot>

Writing our Robot Profile Servlet (not required but nice)

This is not a required step but it would be good practice to do so to make your Robot look more professional. A Profile Servlet is used to tell the following about your Robot:

1. A Name for your Robot

2. A custom image for  your Robot

3. A profile page for your Robot (a URL)

If you provide these, then the Google Wave client is able to retrieve them and set it for your Robot when it is added as a participant. This makes the Robot look more professional.

This profile information needs to be provided by you by writing a Profile Servlet. The Profile Servlet is nothing but extending the com.google.wave.api.ProfileServlet class and providing simple implementations for the overwritten methods.

Follow these steps to write the Profile Servlet:

1. Create a new Java class within the same package. The New Java Class dialog is shown below. I have named the class GAEJRobotProfileServlet as shown below. Click on the Browse button to select a Super Class.

ep7-18

2. In the Superclass Selection dialog shown below, type the word ProfileServlet in the Choose a type field as shown. This will bring up the correct Matching items i.e. com.google.wave.api.ProfileServlet class. Click on OK.

ep7-19

3. This will generate a GAEJRobotProfileServlet.java file.

The simplest way to generate the stubs for the required methods would be to go to Source –> Override/Implement Methods. This will bring up the dialog box as shown below and you only need to select the 3 methods to override as shown:

ep7-14

Click on OK. This will generate the stubs, which you can then overwrite with the code shown below. The code is easy to understand, all we are doing is providing values for the Name, Avatar(Image) and the Profile Page URL. Note that for the Avatar, we are providing a file myimage.jpg present in the WAR/_wave folder. You will need to copy an appropriate image file for yourself and make sure that it is physically copied to the folder locally in your Eclipse project before you deploy your application. You should also replace the word gaejerobot in the source code below with your Application ID.

 

package com.gaejexperiments.waverobot;

import com.google.wave.api.ProfileServlet;

public class GAEJRobotProfileServlet extends ProfileServlet {

@Override
public String getRobotAvatarUrl() {
return "http://gaejrobot.appspot.com/_wave/myimage.jpg";
}

@Override
public String getRobotName() {
return "GAEJ Robot";
}

@Override
public String getRobotProfilePageUrl() {
return "http://gaejrobot.appspot.com";
}

}

 

Configuring the Profile Servlet

We need to add the Profile Servlet <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.

<servlet-name>GAEJRobotProfileServlet</servlet-name>
<servlet-class>com.gaejexperiments.waverobot.GAEJRobotProfileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GAEJRobotProfileServlet</servlet-name>
<url-pattern>/_wave/robot/profile</url-pattern>
</servlet-mapping>

In the above fragment, you will note that url-pattern /_wave/robot/profile has to be mapped to the Profile Servlet that you have written. This is because the Google Wave system will invoke this url to get hold of your profile.

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 gaejrobot.

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 gaejrobot]
  4. Click on OK. You will be lead back to the previous screen, where you can click on the Deploy 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”.

GAEJ Robot in Action

Your application is going to be available at the http://yourapplicationid.appspot.com. In my case, the application is available at http://gaejrobot.appspot.com.

You can test for the presence of your robot capabilities file by simply typing in the following:

http://yourapplicationid.appspot.com/_wave/capabilities.xml [Replace yourapplicationid with the Application ID that you have]

For e.g. when I navigate to the following url (http://gaejrobot.appspot.com/_wave/capabilities.xml)  for my robot application, I get the capabilities xml as shown below, which means that the robot is ready and serving if all is right.

<w:robot>
<w:capabilities>
<w:capability name="WAVELET_PARTICIPANTS_CHANGED" content="true"/>
<w:capability name="BLIP_SUBMITTED" content="true"/>
</w:capabilities>
<w:version>1</w:version>
</w:robot>

To test out the Robot, you need to launch the Google Wave client and login in with your account by going to http://wave.google.com. On successful login, you will be inside the Wave client from where you can create a new wave by clicking on the New Wave link as shown below:

ep7-11

When you do that, currently you are the only participant (myself) as shown in the screen below:

ep7-12

Click on the + sign next to your icon and you can add one or more participants as shown below:

ep7-13

NOTE : Your Google Wave Robot is going to be available at <YOURAPPLICATIONID>@appspot.com , hence I have added gaejrobot@appspot.com as that was my application id. But you can replace it with your application id.

If all goes well, you will see your Robot added as a participant (with the icon and all, since the Profile Servlet is invoked behind the scenes by the Google Wave system). Since the Robot got added, it received a WAVELET_SELF_ADDED Event and since we had coded our Robot Servlet to receive that event and print out the greeting message, you see the message saying “Hi! Your GAEJExperiments Bot …..”. The message is shown twice at this point since there is some bug in the Google Wave system at this point in time but if it does not seem to go away, you can ignore this event and still continue to process the BLIP_SUBMITTED event. (This issue has been fixed by Google now, at least it seems to be working fine for me)

ep7-15

Next I start typing a message “Hello GAEJ Robot” as shown below. But note that I have still not pressed the Done button. Till the Done button is pressed, the BLIP_SUBMITTED is not fired.

ep7-16

Once I click on the Done button, the BLIP_SUBMITTED event is fired and our Robot Servlet gets the event. On receiving the event, it simply prints out some metadata and echoes back the messag

That is all there is to writing a Google Wave Robot. The example here is not useful as such but the intent of the article is to make sure you get your Robot running and have the right setup in place. Several examples are available over the web in which talented programmers are writing Robots that do clever stuff. Just look around and get inspired.

Going back in Time

In Episode 2 of this series, we discussed how to write a XMPP Bot that you could add as a friend in XMPP Chat clients like Google Talk, Spark, etc. That bot is not ready to be added to a Google Wave since it does not implement the end-points that are discussed here i.e. /_wave/robot/jsonrpc, etc. So all you will need to do is to follow the steps outlined here and provide these Servlet implementations along with the end-points and capabilities file. Just add them to your previous project and redeploy your Google App Engine application. You should then have a Bot that is both XMPP compliant and also Google Wave compliant.

Parting notes

Google has posted some excellent documentation on Wave extensions over here and I recommend them to be read. Key among them is the design aspects about the extensions which are covered here. It is important to add a parting note that Google Wave is about collaboration. Collaboration is a process in which participants join each other and engage in doing something. And if your Robot is to participate in a collaboration then you need to think out well in advance how it will collaborate with the other participants and how it can add value to the process. It has to do something that brings meaning and utility to the collaboration. Of course one can write a fun Robot or a pretty much useless Robot that I have demonstrated here, but the key thing to take away is the immense power that a Robot could play in a collaborative process. Imagine a Robot querying a backend system and fetching a Purchase Order or an Order just placed at a website. Think of a recruiter asking a Robot to pull up interview slots from a backend system and then presenting that to the candidate to choose. The possibilities are endless and it should be an exciting journey ahead to see the Robots that people come up with.

Till the next episode…as the Skipper of the Penguins in the great Madagascar movie said, “Just Smile & Wave, Boys. …. Smile & Wave!!”

P.S:

1. Google Wave has been thrown open to a lot of developers and I hope that you have received an invite already. In case you do not, I still have a few invites to give away. Just write an email to me and I shall send across the invite. First come, First served.

2. (Update: 5-Nov-09): The issue of the Blip message “Hi! Your GAEJ Experiments Bot is waiting…..” arrival message appearing twice has been fixed by Google. So you should no longer see that message appearing twice.

2. In the Superclass Selection dialog shown below, type the word ProfileServlet in the Choose a type field as shown. This will bring up the correct Matching items i.e. com.google.wave.api.ProfileServlet class. Click on OK.

ep7-19

 

Welcome to Episode 6 of this series. In this episode, we will learn how your Google App Engine Java (GAEJ) Application can receive incoming email.

In an earlier episode of this series, we have covered how to use the Email Service of GAEJ to send out emails from your application. At that point in time, we were using version 1.2.5 of the AppEngine SDK. That version did not provide support for handling incoming email. Since then a newer version of the AppEngine SDK for Java 1.2.6 has been released. And one of the nice features of this new release is support for incoming email in your application. What it means is that anyone can send an email to your GAEJ hosted application, it can receive an email and then you can process and perform some business logic with that as required.

Prerequisites

Before we move on, it is important that you have a working setup of the environment and are comfortable with developing a new project using the Google Eclipse plugin. If not, please go through earlier episodes that contained detailed setup information along with a few development episodes like using Email Service, using the URL Fetch service, etc.

The most important prerequisite is to make sure that you have upgraded your Eclipse environment to the latest AppEngine SDK i.e. 1.2.6. Please go through the following : Episode 5: Upgrading to Google App Engine 1.2.6

A quick check: To make sure that you  have version 1.2.6 of the SDK installed, do the following:

1. In your Eclipse IDE, go to Window –> Preferences.
2. Navigate to Google –> App Engine
3. You should see version 1.2.6 of the SDK installed. And make sure that it is the default one by selecting it. By selecting it, it will be added to the Build Path of your Google Web Application projects. And we need the latest SDK since it will have support for the Incoming Email feature.

Receiving Email Feature

App Engine now supports incoming email in your applications. Read the official documentation here. Your applications can now receive email and you can parse out the email and determine any business logic that needs to be processed. This opens up a whole new range of applications where you can fulfill requests and send information from your application by allowing users to simply send an email from their favourite email client. Think of it as a Instant Message itself that your application can receive and react to it. We had seen in an earlier episode how through XMPP Support, we can write our own Agent that can receive XMPP messages directly and respond to them. Now with version 1.2.6 of the SDK, the same functionality has got extended to email too. And the best part about it is the consistency with which Google has implemented it.

The steps to follow to receive an email is identical to the ones required to receive XMPP messages:

1. Configure your application to receive incoming email by configuring the Mail Service

2. Write and configure a servlet to receive email

3. Once the application is deployed, anyone can send an email to SomeID@YourApplicationId.appspotmail.com. SomeID is any id like test, admin, support,etc. It is just an id. And YourApplicationId is the application id of your hosted Google App Engine application.

Let us look at each of the above points in detail now. But before we begin, create a New Google Web Application Project (If you wish you can continue to use an existing project to add the incoming Email support, which is what I have done personally, but the choice is yours) . Follow these steps to create a new project:

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.
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.

Configuring the incoming Email Service

This is straightforward and all you need to do is add the following element to the appengine-web.xml file. The appengine-web.xml file as you know is specific to the Google Java Web Application project and is used for configuring certain services. You need to configure the Incoming Email Service so that your application is enabled to receive it, being one of them. It is found in the warWEB-INF folder of your Web Application Project. The XML fragment to add at the end but before the </appengine-web-app> element

<inbound-services>
<service>mail</service>
</inbound-services>

Configure and code a Java Servlet that will receive the incoming Message

All Email messages to your application are delivered via POST to following URL path in your application: /_ah/mail/ as per the Google AppEngine documentation. So you will need to configure the servlet like the following snippet in the web.xml file, present in the warWEB-INF folder of your Web Application Project.

We 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>emailhandler</servlet-name>
<servlet-class>com.gaejexperiments.email.GAEJReceiveEmailServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>emailhandler</servlet-name>
<url-pattern>/_ah/mail/*</url-pattern>
</servlet-mapping>

<security-constraint>
<web-resource-collection>
<url-pattern>/_ah/mail/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>

 

In the above snippet, you will find the fixed URL path /_ah/mail/* configured as the <url-pattern/>. And then I have a Java Servlet class com.gaejexperiments.email.GAEJReceiveEmailServlet as the <servlet-class>. The security constraint has been added so that in case anyone invokes your url directly, then only Google Account authenticated users will be able to do that.

Now, all we have to do is write our Servlet. As mentioned, the incoming Email messages will be POSTed to our Servlet, so we need a simple doPost(…) implemented in our Servlet. The code is shown below:

 

package com.gaejexperiments.email;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletException;
import javax.servlet.http.*;

@SuppressWarnings("serial")
public class GAEJReceiveEmailServlet extends HttpServlet {
public static final Logger _log = Logger.getLogger(GAEJReceiveEmailServlet.class.getName());

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {

try {

Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage message = new MimeMessage(session, req.getInputStream());

//Extract out the important fields from the Mime Message
String subject = message.getSubject();

_log.info("Got an email. Subject = " + subject);

String contentType = message.getContentType();
_log.info("Email Content Type : " + contentType);

printParts(message);
//Parse out the Multiparts
//Perform business logic based on the email
}
catch (Exception ex) {
_log.log(Level.WARNING, "Failure in receiving email : " + ex.getMessage());
}
}

private static void printParts(Part p) throws IOException, MessagingException {
Object o = p.getContent();

if (o instanceof String) {
System.out.println("This is a String");
System.out.println((String)o);
}
else if (o instanceof Multipart) {
System.out.println("This is a Multipart");
Multipart mp = (Multipart)o;

int count = mp.getCount();
for (int i = 0; i < count; i++) {
printParts(mp.getBodyPart(i));
}
}
else if (o instanceof InputStream) {
System.out.println("This is just an input stream");
InputStream is = (InputStream)o;
int c;
while ((c = is.read()) != -1)
System.out.write(c);
}
}

}

 

Let us discuss the main parts of the code:

1. We have a doPost() method that gets invoked by the Google App Engine when an email is received.

2. In the doPost() method, we build out the email message (a instance of class MimeMessage) using the javax.mail.* classes as shown below:

Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage message = new MimeMessage(session, req.getInputStream());

3. We extract out key attributes from the Message like subject, content type, etc.

 

//Extract out the important fields from the Mime Message
String subject = message.getSubject();
_log.info("Got an email. Subject = " + subject);

String contentType = message.getContentType();
_log.info("Email Content Type : " + contentType);

 

4. We have a utility method printParts(), that helps simply print out the contents of the message. But you could explore the Java Mail API to parse out the multiparts as required and then incorporate your business logic.
5. To help debug our Servlet, we have put in some log statements along with System Out statements, which we shall look for to verify that the Application did receive email.

Finally, we have used the INFO level to log if the message was sent out successfully or not, so we will have the change the logging level by modified the logging.properties file present in the warWEB-INF folder. The necessary line after modification is shown below:

# Set the default logging level for all loggers to INFO
.level = INFO

Deploying our 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 gaejexperiments.

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 gaejexperiments]
  4. Click on OK. You will be lead back to the previous screen, where you can click on the Deploy 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 Application

To test our application, send an email from any mail client to an address within your application. As explained below, the email address to be used is shown below:

SomeID@YourApplicationId.appspotmail.com

For e.g. my Application Id is gaejexperiments, so I can send email to any of the following:

  • test@gaejexperiments.appspotmail.com
  • user1@gaejexperiments.appspotmail.com
  • and so on…

Once the email has been sent successfully from a Google Mail Account or Yahoo Mail or Outlook/Thunderbird, etc – you can use the App Engine console to verify if your application received the email or not. To do that, perform the following steps:

  1. Go to http://appengine.google.com and log in with your account.
  2. You will see a list of applications registered. Click on the application that you just deployed. In my case, it is gaejexperiments.
  3. When you click on a particular application, you will be taken to the Dashboard for that application, which contains a wealth of information around the requests, quotas, logs, versions, etc. This will be a subject of a future episode but for now, it is sufficient to say that you can come over here to monitor the health of your application and also to analyze what is going on.
  4. Click on the Logs link as shown in the screenshot below:console1
  5. This will display the application log. And all your application log statements that you code using the Logger class can be visible here.
  6. By default, the severity level is set at ERROR and we can change that to DEBUG, the lowest level and you should be able your log statements that had the log level of INFO. This was the log level at which we had logged statements like Received an Email, etc in our Java Servlet, so that is what we need to check for.
  7. If you see the statements, it means that the message has been received. Shown below is a screen shot of the log for a message that I sent.console2

Once this mechanism is in place, it means that your application has been correctly setup and deployed for receiving email messages. You can now build in business logic on what you need to do when an email is received.

Hope you had a good time reading this episode. The next episode I plan to extend an existing episode in which we built an XMPP Bot and deployed it on the Google App Engine. I plan to extend the bot to support the collaboration tool Google Wave, so that your bot can participate in a Wave conversation too. Till then, happy GAEJ’ing!

 

If you have been following this blog, the version of the Google App Engine SDK was 1.2.5. Recently Google announced a release 1.2.6 of its App Engine SDK.

I think you should upgrade to the latest version since it a very cool feature that resonates with an earlier episode titled Episode 3: Using the GAEJ Email Service. That episode covered using the Email Service that allows you to send an email from your GAEJ application. The latest release 1.2.6 of the App Engine SDK for Java allows you to receive incoming emails too in your application. And that will be the topic in the next episode, so I thought it is best that I mention here that it is time to upgrade to version 1.2.6 of the App Engine SDK.

Here are a few steps and points to note to upgrade to version 1.2.6 of the SDK. I am assuming that all your development/deployment is being done via the Google App Engine plugin for Eclipse since that is what we have used throughout this series. Here are the steps:

1. Launch the version of Eclipse that you have been using so far for the GAEJ development.

2. Go to Window –> Preferences. And then click on Google –> App Engine. You can see the version of the App Engine SDK and most likely it is 1.2.5

3. Stay in Preferences and go one level higher in the tree on the left to Google. You will see a tiny checkbox that mentions “Notify me about updates”. If you have this selected, then you should have already got a notification status in the status bar in Eclipse, somewhere in the bottom of the screen. It looks something like this:

scr1

Clicking on this link would bring up a dialog that looks like the one shown below:

scr2

Depending on your version of Eclipse, you might see a different message and maybe the menu options might be slightly different but the process is a standard one in Eclipse to update your plugins.

4. Even if you had deselected the option to Notify about updates, the process to upgrade the plugin/SDK to the latest version 1.2.6 is the same. Go to Help –> Check for Updates in the main menu. This is for version 3.5 of Eclipse that I use (Galileo version).

This will bring up a dialog and show all your installed components/plugins in Eclipse that have a newer version (update) for you to install. A sample screenshot from my Eclipse setup is shown below:

scr3

5. Select only the Google specific upgrades. You should be able to see the version 1.2.6 of the SDK shown as above. Click on the Next button. This will confirm the updates as shown below:

scr4

Click on Next, accept all the terms as shown below and proceed with Finish appropriately.

scr5

This will download, install the update to the SDK. I recommend to restart Eclipse as prompted.

Post Installation Steps

The following two steps are very important in order to start using the latest version correctly. This is what worked for me and I am not sure if there are other things that are still required but this two steps should suffice for now:

1. Make sure that all your projects moving forward use version 1.2.6 of the SDK. This is not mandatory but required if you wish to use the new features available in version 1.2.6. To do this, go to Window –> Preferences. Click on Google –> App Engine as shown below:

scr6

In this screen, you are seeing only only entry for the version 1.2.6 of the SDK. Normally you will see more than one (the older 1.2.5 SDK) will also be shown and it will be the default selected one. You are not seeing it over here in my setup, because I deleted it and am using only 1.2.6 of the SDK as shown. Select and you will find that as mentioned in the dialog above, the checked SDK will be used by default for newly created projects.

2. Google App Engine SDK also ships with a development server that you can use for local testing. We will be using it in the next episode. You can simply right click any project in the project hierarchy and select Run As –> Web Application to launch your GAEJ application in the development server. The development server is automatically started as you will notice in the console window and you can access your application at http://localhost:8080. But an additional step now needs to be performed to help the development server start. This has got added since version 1.2.6 – it looks like that. Follow the next steps to get this correctly setup.

3. Select the project you want to run in the Project Hierarchy on left. Right click it and select Run As –> Run Configurations… as shown below:

scr7

4. This will bring up the Run Configuration as shown below. Notice the Error message displayed which I have highlighted in Yellow.

scr8

5. So all you need to do is add the VM Argument that they are mentioning. Simply copy the string starting from -javaagent to the end. And paste it in the VM Arguments field in the same dialog as shown below:

scr9

You will find that the error message will go away. You can click Run now to execute the Web Application. The server will be able to start successfully now.

This completes the upgrade of your Google plugin to version 1.2.6 of the SDK.

Upcoming Episode

Make sure that you have version 1.2.6 of the SDK setup as mentioned in this episode. The next episode coming in a day will show how your Google App Engine applications can receive incoming emails, which is one of the newly enabled features of version 1.2.6 of the SDK. Till then, happy upgrading!

 

 

Welcome to Episode 4 of GAEJ Experiments. In this episode, we will learn how your GAEJ Application can invoke external URLs and get data back from them. In the process we will build a fully capable Dictionary Application. While it may not be a complete application, it will demonstrate just about enough how you can integrate external services into your application.

This episode is particularly important given the fact that there are hundreds of public APIs now available out there on the web, which your application can integrate. I strongly recommend visiting The Programmable Web that catalogs hundreds of Web APIs that are available today and which you can integrate into your application.

Dictionary Application in Action

In order to maintain a consistent style across the episodes so far, let us first watch the application in action to better understand what we will be building over here. Follow these easy steps:

  1. Navigate to http://gaejexperiments.appspot.com. This will result in a page as shown below:s1
  2. Click on Dictionary Service link. This will lead you to a page shown below:s2
  3. Enter any word that you wish to lookup in the dictionary and click on Lookup Dictionary. For e.g. engine. This will display the meaning of the word as shown below:s3

Behind the Scenes

Let us understand how the above application is working. The key points to note in the flow are given below:

  1. The dictionary page shown in step 2 above is a simple HTML form page. The only user input needed in this step is the word that you wish to look up in the dictionary.
  2. On click of the Lookup Dictionary button, a Servlet is invoked in our GAEJ Application. The Servlet will utilize the GAEJ URL Fetch Service to invoke an external Dictionary Service.
  3. The Dictionary Service is hosted at a site called http://services.aonaware.com/DictService/DictService.asmx . One of the service operations is Define and you can try it out here. It supports a REST style interface (GET/POST) for invoking it, so that makes our task simple. Give it a try here to better understand what we are integrating or simply punch in the following in your browser: [code language="java"]

    http://services.aonaware.com/DictService/DictService.asmx/Define?word=trial

    [/code]

  4. This service takes in a word and returns us a XML Response which contains the meaning of the word in several dictionaries. We parse out the dictionary meaning and return that back to the client (HTML form).
  5. The HTML form that renders the meaning as shown in the screen above.

URL Fetch Service

The core piece that we will be utilizing in our application here is an ability to invoke external URLs. This is provided by the URL Fetch service of the Google App Engine. It allows us to invoke any external URL and receive the data from the URL. At a high level, usage of the URL Fetch service is pretty simple and a boiler plate code is shown below: [Most details have been omitted]

 

try {
URL url = new URL(PUT_EXTERNAL_URL_HERE);
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));

String line;
StringBuffer responseData = new StringBuffer();

//Read the entire response in this loop
while ((line = reader.readLine()) != null) {
responseData.append(line);
}
reader.close();

//Process the data from the responseData StringBuffer
//Might involve Parsing the XML or JSON Response format, etc.

}
catch (Exception e) {
//...
}

 

This is pretty much standard Java code and it involves opening an inputstream to the external URL and collecting the response in a local variable. You can then decide what to do with the response data received. For e.g. most external services provide a XML or JSON formatted response, which you may have to parse out and then proceed with your application logic.

In our Dictionary Application here, we will be receiving a XML response, which we will simply parse out and return back to the HTML client.

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.

The Front end HTML form [dictionary.html]

Create a new HTML file in the war directory of your application. In that directory, you will find an index.html that is generated for you. So you can either use index.html or generate a new HTML file as I have done. Name this file as dictionary.html and code it as shown below:

The first thing that we will do is to code out a simple HTML form that takes a single parameter as an input. This parameter is the word that we need to lookup in the dictionary. We will use a bit of AJAX here to dynamically call our servlet and display the response that we get.

 

<html>
<head>
<script type="text/javascript">
var xmlhttp;
function lookupDictionary(word)
{
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 = "/gaejdictionaryservice?word="+word;
xmlhttp.open("GET",url,true);
xmlhttp.send(null);
}
else
{
alert("Your browser does not support XMLHTTP.");
}
}

function state_Change()
{
if (xmlhttp.readyState==4)
{// 4 = "loaded"
if (xmlhttp.status==200)
{
// 200 = "OK"
document.getElementById('DictionaryServiceResponse').innerHTML=xmlhttp.responseText;
}
else
{
alert("Problem looking up Dictionary Service :" + xmlhttp.statusText);
}
}
}
</script>
</head>

<body>
<h2>Dictionary Lookup </h2>
<hr/>
<h3>(Powered by Aonaware <a href="http://services.aonaware.com/DictService/">Dictionary Service</a>)</h3>
<hr/>
<p>
<b>Lookup meaning of word:</b><input type="text" id="word"></input>
</p>
<p><b>Meaning :</b>
<br /><span id="DictionaryServiceResponse"></span>
</p>

<button onclick="lookupDictionary(word.value)">Lookup Dictionary</button>

</body>

 

Here are some key points from the code above. For most web programmers it is pretty much standard stuff:

  1. We have a single input field HTML element with an id named word. There is a button with a label Lookup Dictionary, on click on which, we invoke a Javascript function called lookupDictionary, passing in the word value.
  2. The lookupDictionary method builds up the standard XMLHttpRequest object that we shall use to send our request across. The request url is /gaejdictionaryservice with a single parameter named word, which contains the value of the word that we need to lookup in the dictionary.
  3. Note that /gaejdictionaryservice is our servlet endpoint that we will be seeing in the next section. This servlet will take it the word parameter, and use the URL Fetch Service to invoke the external Dictionary API and return us back the response.
  4. The response when returned is inserted into the span element named DictionaryServiceResponse in the above HTML form to display the response received.

Next we shall code the heart of our application a servlet named GAEJDictionaryService.

Coding the GAEJDictionaryService Servlet [GAEJDictionaryService.java]

Create a new Servlet in your Project as shown below. I have created the GAEJDictionaryService.java in the package com.gaejexperiments.networking. You can choose a package of your choice.  The code is straightforward and is listed below:

 

package com.gaejexperiments.networking;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.URL;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

@SuppressWarnings("serial")
public class GAEJDictionaryService extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {

String strCallResult = "";
resp.setContentType("text/plain");
try {
//Extract out the word that needs to be looked up in the Dictionary Service
String strWord = req.getParameter("word");

//Do validations here. Only basic ones i.e. cannot be null/empty
if (strWord == null) throw new Exception("Word field cannot be empty.");

//Trim the stuff
strWord = strWord.trim();
if (strWord.length() == 0) throw new Exception("Word field cannot be empty.");

String strDictionaryServiceCall = "http://services.aonaware.com/DictService/DictService.asmx/Define?word=";
strDictionaryServiceCall += strWord;
URL url = new URL(strDictionaryServiceCall);
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
StringBuffer response = new StringBuffer();
String line;

while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();

strCallResult = response.toString();

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(strCallResult.toString())));

XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("//Definition[Dictionary[Id='wn']]/WordDefinition/text()");

Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
strCallResult = nodes.item(i).getNodeValue();
}

resp.getWriter().println(strCallResult);

}
catch (Exception ex) {
strCallResult = "Fail: " + ex.getMessage();
resp.getWriter().println(strCallResult);
}
}

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

}

 

Let us go over the key points in the code above:

  1. I have provided both GET and POST handlers in the servlet and the POST handler simply invokes the GET handler here.
  2. Then we parse the request parameters for the word parameter that we need to look up in the dictionary (word) and we do some basic validation to make sure that it is not empty.
  3. The Dictionary Service that we plan to use is available at the following URL: [code language="java"]

    http://services.aonaware.com/DictService/DictService.asmx/Define?word=[YOUR_WORD_HERE]

    [/code]

  4. In the above URL, you need to provide the word. So what we do in the code is to simply append the word request parameter that was passed.
  5. Next, we use the URL Fetch Service as discussed earlier to collect the entire response.
  6. The response returned to use is in XML format and the service returns us the meaning of the word based on 6 dictionaries. We will be using just one of those dictionaries WordNet 2.0 which is the 3rd definition in the XML. I suggest that you punch in the following url to understand what we will be parsing out here. I have used the word ‘engine’ here.
    http://services.aonaware.com/DictService/DictService.asmx/Define?word=engine
  7. Finally we use XPath. I intentionally used this to demonstrate how easy it is to use XPath to extract out the element text that we are interested in. You are free to choose an alternative way of extracting out the text value. You could use standard SAX/DOM parsing too if you wish. Whatever you are comfortable with will suffice for the example.
  8. We first build the Document object by using the standard DocumentBuilderFactory and DocumentBuilder classes.
  9. Then on the Document object doc, we evaluate the XPath expression. The XPath expression is //Definition[Dictionary[Id='wn']]/WordDefinition/text().
  10. The XPath expression given above can be read as following. First consider the //Definition[DictionaryId ='wn']] which means that find all definitions anywhere in the document which have a child element named DictionaryId whose value is ‘wn’. This is the Definition that we are interested in extracting.
  11. Once that is found, comes the rest of the XPath expression, which says that for that Definition element found, get a child element named WordDefinition and extract out its text() value. This is returned as a collection of Text nodes.
  12. Finally, we iterate through the Text Nodes and get the value which we then send back as a response.
  13. I suggest that if you are still having a problem following the code, try out the URL as mentioned in step 6, study the XML and then the XPath expression will become clear. The rest of the code is standard XML/XPath code from the Java SDK.

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>GAEJDictionaryService</servlet-name>
<servlet-class>com.gaejexperiments.networking.GAEJDictionaryService</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GAEJDictionaryService</servlet-name>
<url-pattern>/gaejdictionaryservice</url-pattern>
</servlet-mapping>

Deploying and running your 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 gaejexperiments.

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 gaejexperiments]
  4. Click on OK. You will be lead back to the previous screen, where you can click on the Deploy 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”.

This means that you application is ready to serve. Depending on whether you used index.html or dictionary.html, you should be able to access your application at the following url:

http://<YourAppId>.appspot.com/dictionary.html

or

http://<YourAppId>.appspot.com/index.html

Type in a word and check if the meaning is being returned.

Moving forward

In this episode, we have seen how to utilize the URL Fetch Service provided by the Google App Engine. This service provides us with a convenient way to access external services that can be integrated into our application. Creating Mashup applications would be straightforward with the URL Fetch Service.

You can integrate other external services, RSS feeds in this fashion. Just give it a try.

Till the next episode, good bye and happy coding!

 

I received a good comment on my second post, where we saw how to write your own XMPP Bot and deploying it on the Google App Engine for Java (GAEJ).

It asked whether one can communicate to another Jabber account from the XMPP Bot hosted on the GAEJ. The confusion arose because I covered the usage of Google Talk, which is an IM client itself. And it looked from my post that you can only use Google Talk as the client to talk the XMPP agent that you wrote.

The short answer is that yes, even if you are using another Instant Messaging (IM) client like Spark or Pidgin, it is possible to communicate to the XMPP bot that you have written and which is running inside the GAEJ cloud.

However, it turned out that I made a mistake in writing the code for the XMPP bot. The Google App Engine XMPP documentation clearly states that you can communicate to any other Jabber ID but it is not possible for their infrastructure to check for the presence of a Jabber ID on another network except their Google Talk network. This is fair enough. By presence, we are simply trying to see if the user is online or not.

So , we had some code in our XMPP bot that we saw earlier, which went something like this. This code fragment was at the very end when we are sending back the echo for our Agent.

if (xmpp.getPresence(fromJid).isAvailable()) {
SendResponse status = xmpp.sendMessage(replyMessage);
messageSent = (status.getStatusMap().get(fromJid) == SendResponse.Status.SUCCESS);
}

What we are doing here is that we are checking for the presence of another JabberID i.e. making sure that is online before sending the message. This works fine on the Google Network but not on other XMPP Networks like Jabber.org. So for e.g. our bot Jabber Id was gaejxmpptutorial@appspot.com. And if the Jabber Id which is talking to it is someid@jabber.org, then it will not be possible for your bot running inside of the Google network to determine if someid@jabber.org is online or not. As a result of this, the code will never enter the block and the message does not get sent.

So, all you have to do to send the message across to another network is to remove the check for the isAvailable() condition and simply call the sendMessage(…) method.

I have verified this by doing the  following:

  1. Used another IM client instead of Google Talk. I used the IM client called Spark
  2. I have an account at jabber.org which I used to login as shown below in the Spark IM client:post4-3
  3. I added gaejxmpptutorial@appspot.com as a contact in Spark IM client.post4-1
  4. I sent a chat message across to the gaejxmpptutorial bot and got back the echo as shown below:post4-2

Hope this clarifies that it is possible to communicate to your bot over XMPP from other XMPP Servers. Let me know if any of you are still having issues and I welcome your comments.

© 2012 iRomin Suffusion theme by Sayontan Sinha