2010-03-18

Using UserPref with URL content type gadgets

Following on from my previous post I needed to add a user preference to my gadget. By following the documentation here my previous example changed to be something like this:
<?xml version="1.0" encoding="UTF-8"?>
<Module> 
      <ModulePrefs 
            height="100" 
            title="My Simple Gadget" 
            description="Test gadget" 
            author="Anonymous" 
            author_email="anonymous+gg@gmail.com"/>
      <UserPref 
            name="profileId" 
            display_name="Profile ID" 
            datatype="string" 
            urlparam="id" 
            required="true"/> 
      <Content 
            type="url" 
            href="http://yourappid.appspot.com/gadget.html" /> 
</Module>

Note that I used the urlparam attribute so that the querystring used to fetch the gadget content would be something like
http://yourappid.appspot.com/gadget.html?id=123.

My GWT code could now read this userpref like this:
public void onModuleLoad() {
    String id = Window.Location.getParameter("id");
    . . . .

Unfortunately there is a minor issue with this. It seems that some gadget containers ignore the urlparam attribute. When the gadget is hosted in the iGoogle home page it works fine but in Blogger and some other places the id parameter was not coming through in the querystring. Instead you get something like like
http://yourappid.appspot.com/gadget.html?up_profileId=123
Basically the UserPref name prefixed with up_. This meant a minor change to the GWT code:
public void onModuleLoad() {
    String id = Window.Location.getParameter("id");
    if (id == null) {
        id = Window.Location.getParameter("up_profileId"); 
    }
    . . . .

UPDATE:
It seems that Google have broken the URL type gadgets. The parameters are no longer sent in the URL to the server! See this iGoogle Developer blog post

This makes the above code rather useless. I'll be working on a new version...

UPDATE 2:
According to this forum post the problem has been fixed temporarily. I think the advice is to use HTML content type gadgets if you want to use UserPrefs. Shame.

UPDATE 3:
URL type gadgets are back for good! See this post. To summarize:
I've been talking with developers on the iGoogle team about the best way to go forward here and it looks like keeping UserPrefs in the query string for type url gadgets is the thing to do.

2010-02-27

Simple Google Gadget on GAE

I've just found how easy it is to create Google Gadgets and host them on App Engine. All you need to do is create a simple page in your App Engine application to be the content of the gadget and then host a URL content type gadget specification that points to that page.

Your Gadget specification will look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<Module> 
      <ModulePrefs 
            height="100" 
            title="My Simple Gadget" 
            description="Test gadget" 
            author="Anonymous" 
            author_email="anonymous+gg@gmail.com"/> 
      <Content 
            type="url" 
            href="http://yourappid.appspot.com/gadget.html" /> 
</Module>

In my case I'm using a very simple GWT application. Make sure that it looks good at 300 pixels wide. The height can vary but don't make it too tall because people are less likely to install it if it takes up too much space.

The URL content type approach allows you to make a normal web page using any tools you like and you can debug it like any normal page.

To put it all together simply save your gadget spec into the war directory of your GAE application and deploy it so it's available on a URL like this: http://yourappid.appspot.com/gadgetspec.xml

Now you can test it in the iGoogle Sandbox which (after you've signed up) allows you to test unpublished gadgets. Add this developer gadget to make life easy.

When you're happy with it submit your gadget and you're done.

2009-12-17

Using Google Collections

I'm sure this is "Old hat" to a lot of people but I just watched these two videos on Google Collections: Part 1, Part 2. The MultiMap is definitely something I could have used many times in the past, and I will use it from now on!

I decided to convert a couple of static final maps in my App Engine project to Immutable ones instead. Previously I was using this method to create and initialise maps:
public static final Map<String, Calendar> iterations = new HashMap<String, Calendar>() {{
  put(TEAM_A, new GregorianCalendar(2009,9,5));
  put(TEAM_B, new GregorianCalendar(2009,8,15));
  put(TEAM_C, new GregorianCalendar(2009,7,21));  
 }};


Now I have this:
public static final Map<String, Calendar> ITERATIONS = 
  new ImmutableMap.Builder<String, Calendar>().
  put(TEAM_A, new GregorianCalendar(2009,9,5)).
  put(TEAM_B, new GregorianCalendar(2009,8,15)).
  put(TEAM_C, new GregorianCalendar(2009,7,21)).
  build();