WaveCalender 14: Wave Extension Installer XML file creator

After a while of strenuous coding and testing, the developer is ready to make his/her work public. But one obstacle still remains for the developer and that is to make the Wave extension Installer.

The Wave extension installer is important as this simplifies the task in installing the app on wave. Because the developer aims his/her work for the public to use, the developer should make everything easy for the users to install and use his/her app. Imagine if you have to make your users learn a scripting language before they can use your app, chances are your users may grow tired of it and may missed the chance of using your app.

The Wave Extension Installer XML File Creator is an app specifically designed for developers to simplify their work on creating Wave Extension Installers. This app is built on Flex and using the wave-as-client ActionScript Library for Flex. This is a nice app to use for first time developers and to some because after all those strenuous coding and testing, developers may get lazy to create the wave extension installer. With this app, all you have to do is fill out the form, click “Done”, and copy the generated XML content. Just remember the app is bigger than a regular size blip so you may have to maximize your wavelet to fully view the app.

You can try out the app in this gadget XML URL: http://wave-as-client.googlecode.com/svn/trunk/example/wave_install_creator/web/wave_install_creator.xml

Bookmark and Share

Add-Robot

    A robot which can stores user favorite robots using the JDO data store and add them automatically to the wavelet when it was added as participant.

The basic features of this are to add, delete and view. When the user enter the command “#add.robots.save”
it’s save all the current robots in the wavelet and automatically list the current favorite robots. And when users enter “#add.robots.delete<space><robotname>” it will delete that specific robot in the favorite.

Add Robots Samples

 

This Is How We Do It

    First Create an app engine project name AddRobot and setup the environment for JDO and Robots

    It is easier if you’re going to use eclipse with Google plug-in cause some configuration there is auto generated.

To set up Wave Robots refer to:

http://code.google.com/apis/wave/extensions/robots/java-tutorial.html

To set up JDO refer to:

http://code.google.com/appengine/docs/java/gettingstarted/usingdatastore.html

    Now we are ready, after setting up the environment. We have to create a datastore where we can save our favorite robots. Be sure that you already have PersistenceManagerFactory (Refer to JDO site above). Now let’s Create a new class named Robots with properties id, username and robotname with a private identifier and should be annotated with @Persistent to tell DataNucleus to store them as properties of objects in the App Engine datastore. And id should be annotated with @PrimaryKey to set id as primary key. It should be look like this:

package com.google.addrobots.jdo;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Robots{
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;
    @Persistent
    private String userName;
    @Persistent
    private String robotsName;
    public Robots(String userName, String robotsName) {
        this.userName = userName;
        this.robotsName = robotsName;    
    }
    public Long getId() {
        return id;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getRobotsname() {
        return robotsName;
    }
    public void setRobotsname(String robotsName) {
        this.robotsName = robotsName;
    }
}

    Now let’s begin with the robot, create a servlet let say” AddRobbotServlet that extends the AbstractRobotServlet class (from the com.google.wave.api package) and implement the method processEvents() which accepts a RobotMessageBundle object. As the first functionality of add-robot is to add automatically all the favorite robot to the wavelet, so we need to implement the condition if bundle.wasSelfAdded(). If that returns true it will automatically add all favorite robots as participants of the wavelet, it should be like this:

package com.google.addrobots;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import com.google.addrobots.jdo.PMF;
import com.google.addrobots.jdo.Robots;
import com.google.wave.api.*;

@SuppressWarnings("serial")
public void processEvents(RobotMessageBundle bundle) {
    Wavelet wavelet = bundle.getWavelet();
    String creator = wavelet.getCreator();
 if(bundle.wasSelfAdded()) {           
    //Search if theres existing favorites robots and add it to participants
    PersistenceManager pm = PMF.get().getPersistenceManager();
    Query query = pm.newQuery(Robots.class,"userName == userNameParam");
     query.declareParameters("String userNameParam");
     List<Robots> bots=(List<Robots>) query.execute(creator);
     if(!bots.isEmpty()){
             for (Robots r : bots) {
                wavelet.addParticipant(r.getRobotsname());
        }
}
    pm.close();
Blip blip = wavelet.appendBlip();
                TextView textView = blip.getDocument();        
                //append new string to blip for confirmation
                textView.append("Favorite Robots has been added as participant");                  
             }
    }

    Then for the other adding and deleting command, we need to get what the users input in the blip so we need to use the event type blip submitted. Now we need to compare that words that the user enters on the blip. So were going to create again a condition filtering if the user input if #add-robots.save or #add-robots.delete in the blip. If the user enter #add-robots.save all the robots in the wavelet will be save as favorite that would be look like this:

for (Event e : bundle.getEvents()) {
    if (e.getType() == EventType.BLIP_SUBMITTED) {
    //get event blip
    Blip blip = e.getBlip();           
    TextView textView = blip.getDocument();
    //get blip text
    String strBlip = e.getBlip().getDocument().getText();
    String delimiter = " ";
    String[] temp = strBlip.split(delimiter);  
//#add-robots.save ivoked
    if(temp[0].trim().equals("#add-robots.save")|| temp[0].trim()=="#add-robots.save"){
    //delete existing robot first before adding new list
    //query to search robots
PersistenceManager pm = PMF.get().getPersistenceManager();
    Query query = pm.newQuery(Robots.class,"userName == userNameParam");
    query.declareParameters("String userNameParam");
    List<Robots> bots=(List<Robots>) query.execute(creator);
    if(!bots.isEmpty()){
        for (Robots g : bots) {
        //delete robots
        pm.deletePersistent(g);
        }
        }
//get all participant
List participant = wavelet.getParticipants();
    //get robot from participant check if with a host of appspot.com
    List<String> appspot = getAllAppspot(participant);
    textView.delete();
//save List to JDO
textView.append("All Robots here has been Saved To Favorites \n");
        for(String bot : appspot)
            {
Robots rob = new Robots(creator,bot);
        pm.makePersistent(rob);
            textView.append(bot+"\n");
            }
        pm.close();
        }

    Notice that we use Java String method split to get what the input we need from the blip. And notice also that we delete first all existing favorite robot before we add a new favorite, you can create other logic for that but for me that is much easier. Now for deleting our unwanted robot, we will again get the user input and compare if the input #add.robots.delete<space><robotname> then that specific robot with that name will be deleted. Now let’s continue with the code:

else if(temp[0].trim().equals("#add-robots.delete")|| temp[0].trim()=="#add-robots.delete"){
PersistenceManager pm = PMF.get().getPersistenceManager();
    Query query = pm.newQuery(Robots.class,"userName=='"+creator+"' && robotsName=='"+temp[1]+"'");
    List<Robots> bots=(List<Robots>) query.execute(wavelet.getCreator());
        if(!bots.isEmpty()){
            for (Robots g : bots) {
 //delete robots
pm.deletePersistent(g);
            wavelet.removeParticipant(temp[1]);
            }
            }
    textView.delete();
    textView.append(temp[1]+" Has Been Deleted");
    }else{   //some additional code here for other function
}  
    }
    }  
}

Now that’s it, we are finish with the robot servlet. Just read the code comments for its purpose. So it’s time to create a Servlet Mapping, you have to map this servlet to the URL path /_wave/robot/jsonrpc, edit the file war/WEB-INF/web.xml so that it looks like this:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
  <!-- Servlets -->
      <servlet>
        <servlet-name>AddRobots</servlet-name>
        <servlet-class>com.google.addrobots.AddRobbotServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>AddRobots</servlet-name>
        <url-pattern>/_wave/robot/jsonrpc</url-pattern>
    </servlet-mapping>
</web-app>

    And finally This robot needs a configuration file where we can configure the robot capability . From the Package Explorer, create a new folder named war/_wave/, then inside this folder create a file named capabilities.xml with the following contents:

<?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"/>
  </w:capabilities>
  <w:version>2</w:version>
</w:robot>

    As you can see, we use special event BLIP_SUBMITTED. This work whenever a blip is submitted so our robot can respond to this wave events. Now were done we can test now our robot, you can test your new robot by deploying it to App Engine, then adding it to a wave. Please refer again to the site above.

Bookmark and Share