Sample standalone applications accessing Google Base data API feeds

Introduction

The Google Base data Java Client Library offers a nice object oriented abstraction for accessing the Google Base data API. However, if you prefer to interact with the Google Base data API servers directly, here are a few examples that will start you up.

This document assumes you know Java programming (including some basic knowledge of Http connections and SAX parsers) and that you are familiar with Google Base concepts. You need to understand the following concepts before you can take full advantage of the sample applications:

This tutorial consists of stepping through 5 examples. The first example shows how to connect to a Google Base data API feed and query data. The second example extends this by showing how to parse the result and extract data of interest from the feed. The third example introduces authentication and demonstrates how to display your own items, rather than querying snippets. The fourth example demonstrates how to insert your own item into Google Base, while the last example shows how to update a previously inserted item.

Query Example 1 - query the Google Base data API and display the result

QueryExample1 is a simple Java application that runs from the command line. It performs an unauthenticated query on the public snippets feed (/feeds/snippets) and it dumps the query response to the console (it won't look pretty!).

Running QueryExample1

Edit QueryExample1.java and fill in the Compile and run the example using your favorite editor, or using the command line:
    javac sample.gbase/basic/QueryExample1.java
    java sample.gbase/basic/QueryExample1
  
The output (conveniently formatted) will look like:
    <feed>
      <id>http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets</id>
      <updated>2006-08-22T14:14:11.984Z</updated>
      <title type="text">Items matching query: cars [item type : products]</title>
      <link rel="alternate" type="text/html" href="http://base.google.com"/>
      <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets"/>
      <link rel="self" type="application/atom+xml" href="http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets?key=ABQ...9P2Y4A&bq=cars+%5Bitem+type+%3A+products%5D"/>
      <link rel="next" type="application/atom+xml" href="http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets?start-index=26&max-results=25&key=ABQ...9P2Y4A&bq=cars+%5Bitem+type+%3A+products%5D"/>
      <generator version="1.0" uri="http://base.google.com">GoogleBase</generator>
      <openSearch:totalResults>278120</openSearch:totalResults>
      <openSearch:itemsPerPage>25</openSearch:itemsPerPage>
      <entry>
        <id>http://0.baseapitest.googlebase-api.jc.borg.google.com.:31911/base/feeds/snippets/10062394959501653657</id>
        <published>2006-06-30T21:45:12.000Z</published>
        <updated>2006-07-28T00:58:14.000Z</updated>  
        ...
  

Stepping through the QueryExample1 code

At the very beginning we define the url of the feed we are connecting to and the query that we are going to run:

  private static final String SNIPPETS_FEED = "http://base.google.com/base/feeds/snippets";

  private static final String QUERY = "cars [item type : products]";
  
Feel free to change the query to a more relevant or interesting one. Take a look at the Google Base Query Language description if you need some inspiration.

After opening a connection on the snippets feed, we grab the connection's input stream, and dump its content to the output, character by character:

   HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
   InputStream inputStream = httpConnection.getInputStream();
    
    int ch;
    while ((ch=inputStream.read()) > 0) {
      System.out.print((char)ch);
    }
 
In the main method, all we do is create a QueryExample1 instance, and invoke its displayItems method:
 public static void main(String[] args) throws IOException, SAXException,
          ParserConfigurationException {
    new QueryExample1().displayItems();
  }

Query Example 2 - query the Google Base data API, parse the result and display the titles of returned data items

One major problem with QueryExample1 is that it simply dumps the items returned for the query to the console, and the result is barely readable. In any real life application the query result would need to be parsed, interpreted and relevant information should be extracted and displayed to the user. In QueryExample2 we demonstrate a possible way of doing this by using a SAX parser to extract each data item's title from the result, and display it to the console. Some very basic understanding of how SAX parsers work is necessary in order to fully understand this example.

One might argue that for this task we don't even need a SAX parser. We could just search for all <title> tags in the result and display the characters that they enclose. Unfortunately, that wouldn't work, as the Atom response also has a <title> tag, which is the title of the feed:

    <feed>
       ...
       <title type="text">Items matching query: cars [item type : products]</title>
      ...
      <entry>
        ...
        <title type='text'>Great care for sale</title>
        ...  
  
Atom does not mandate that the feed's <title> tag should appear at a specific position inside the feed, so we need to make sure we only display the <title> tags which are sub-elements of an <entry> tag.

RunningQueryExample2

Compile and run the example using your favorite editor, or using the command line:
    javac sample.gbase/basic/QueryExample2.java
    java sample.gbase/basic/QueryExample2
  
The output will look like:
    Item 1: Johnny Lightning MUSCLE CARS R8 1967 Chevelle SS
    Item 2: Johnny Lightning MUSCLE CARS USA 2005 Ford GT
    ...
    Item 25: The Cars movie Hinged tool Box Toy Organize lunch RARE
  

Stepping through the QueryExample2 code

Just as in the previous example, we first send the query to the Google Base data API server, and obtain an inputStream containing the response:

    URL url = new URL(SNIPPETS_FEED + "?bq=" + 
        URLEncoder.encode(QUERY, "UTF-8"));
    HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
    InputStream inputStream = httpConnection.getInputStream();

We then use a standard SAX parser to parse the result. We obtain a SAXParser instance using a SAXParserFactory:

    SAXParserFactory factory = SAXParserFactory.newInstance();
    SAXParser parser = factory.newSAXParser();
We then parse the result inputStream using DisplayTitlesHandler, our custom SAX event handler:
    parser.parse(inputStream, new DisplayTitlesHandler());

DisplayTitlesHandler is derived from the no-op SAX parser, org.xml.sax.helpers.DefaultHandler. The logic inside DisplayTitlesHandler is pretty simple: we keep a stack of the currently open XML tags and print all character data when we are inside a <title> tag with a <entry> parent. The insideEntryTitle flag is turned on each time we are inside a <entry><title> pair:

    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
      if (qName.equals("title") && xmlTags.peek().equals("entry")) {
        insideEntryTitle = true;
        System.out.print("Item " + ++itemNo + ": ");
      } 
      xmlTags.push(qName);
    }
Since startElement is invoked each time the SAX parser encounters an opening XML tag, we switch on insideEntryTitle only if the currently parsed opening tag is <title> and the tag on the top of the stack is <entry> . We are also printing here the "Item no: " messages, rather than in the characters method, as characters can be called multiple times for different chunks of the title's character data.

The endElement method is invoked each time an XML tag closes. All we need to do here is to remove the closing XML tag from the stack and, in case the removed XML tag was an entry's title, flip insideEntryTitle to false and go to a new line in the console, in preparation for printing out the next title:
    public void endElement(String uri, String localName, String qName) throws SAXException {
      xmlTags.pop();
      if (insideEntryTitle) {
        insideEntryTitle = false;
        System.out.println();
      }
    }
The characters method is invoked when the parser encounters character data inside an XML element. If we are inside the <title> tag, that is, if the insideEntryTitle flag is on, we display the current characters: length characters from the ch array, starting with start. As noted earlier, we can't use println here to get to a new line, as characters can be invoked multiple times for different chunks of the same title:
   public void characters(char[] ch, int start, int length) throws SAXException {
      if (insideEntryTitle) {
        System.out.print(new String(ch, start, length));
      }
    }
In the main method, all we do is create a QueryExample2 instance, and invoke its displayItems method:
 public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException {
    new QueryExample2().displayItems();
  }

Query Example 3 - Introducing authentication. Querying your own items using the items feed.

The previous two examples demonstrated how to query the Google Base data API public feeds, also known as snippets. Snippets are accessible to anyone without authentication. The downside is that snippets are the "indexable" version of the items and can slightly differ from the original items. It can also take a while for a newly inserted or updated item to show up in the snippets feed. Therefore, if you need to change your own items, the Google Base data API server exposes the customer-specific "items" feed. This feed is very similar to the "snippets" feed, except that:

Read here more about the characteristics of the "items" feed. You will need a Google Account email and password in order to run this example. If you don't have a Google Account, sign up for one here.

QueryExample3 connects to your "items" feed, and dumps your items to the console, just as in QueryExample1. If you don't have any items in Google Base yet, use InsertExample to insert one, or go to the Google Base Provider Frontenac and insert one.

Running QueryExample3

  1. Edit QueryExample3.java and make the following changes:
  2. Compile and run the example using your favorite editor, or the command line:
        javac sample.gbase/basic/QueryExample3.java
        java sample.gbase/basic/QueryExample3
      
    
  3. The output will look like:
        <?xml version='1.0' encoding='UTF-8'?>
        <feed>
          <id>http://base.google.com/base/feeds/items</id>
          <updated>2006-08-22T12:00:00.000Z</updated>
          <title type="text">Items matching query: [customer id(int):1870031]</title>
          ...
      
    

Stepping through the QueryExample3 code

As opposed to the previous examples, here we need to obtain an authorization token by authenticating with the Google Accounts server. We then use this authorization token to invoke displayMyItems:

 public static void main(String[] args) throws IOException {
    QueryExample3 queryExample = new QueryExample3();
    String token = queryExample.authenticate();
    new QueryExample3().displayMyItems(token);
  }

We authenticate using authentication for installed applications. The authentication procedure is simple. We make a POST request to AUTHENTICATION_URL:

  private static final String AUTHENTICATION_URL = "https://www.google.com/accounts/ClientLogin";
The POST request is constructed in makeLoginRequest, and it looks like this:
    // POST /accounts/ClientLogin HTTP/1.0
    // Content-type: application/x-www-form-urlencoded
    // Email=johndoe@gmail.com&Passwd=north23AZ&service=gbase&source=Insert Example
makeLoginRequest sends the request to the Google Accounts server and returns the response as a String. A successful response will have the following structure:
    //      HTTP/1.0 200 OK
    //      Server: GFE/1.3
    //      Content-Type: text/plain 
    //      SID=DQAAAGgA...7Zg8CTN
    //      LSID=DQAAAGsA...lk8BBbG
    //      Auth=DQAAAGgA...dk3fA5N
authenticate first obtains the authentication response from makeLoginRequest and stores it in postOutput:
   String postOutput = null;
    try {
      URL url = new URL(AUTHENTICATION_URL);
      postOutput = makeLoginRequest(url);
    } catch (IOException e) {
      System.out.println("Authentication error: " + e.toString());
    }
It then tokenizes postOutput, and returns the next token after "Auth", or null if the token is not found:
   StringTokenizer tokenizer = new StringTokenizer(postOutput, "=\n ");
    String token = null;
    
    while (tokenizer.hasMoreElements()) {
      if (tokenizer.nextToken().equals("Auth")) {
        if (tokenizer.hasMoreElements()) {
          token = tokenizer.nextToken(); 
        }
        break;
      }
    }


The items are displayed in displayMyItems, which is very similar to displayItems in QueryExample1, except that it injects the authorization token in the Http header (as in this example):

   connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);

Insert Example - Adding your own item to Google Base.

The previous examples demonstrated how to query the Google Base data API server, both for snippets (unauthenticated feeds) and for items (authenticated feeds, containing a specific customer's items). Let's demonstrate now how to add to Google Base all the cool stuff you have, so that the world can see it. Again, you will need a Google Account email and password in order to run this example. If you don't have a Google Account, sign up for one here.

In this example we will connect to your "items" feed, and do an Http POST operation (as opposed to GET, used for querying) to add a new item. The item to be added is encoded in Atom format, and is defined a String constant:

  private static final String DATA_ITEM = 
        "<?xml version=\'1.0\'?>\n" + 
        "<entry xmlns=\'http://www.w3.org/2005/Atom\' xmlns:g=\'http://base.google.com/ns/1.0\'>\n" + 
        "  <category scheme=\'http://base.google.com/categories/itemtypes\' term=\'Products\'/>\n" + 
        "  <g:item_type type=\'text\'>Products</g:item_type>\n" + 
        "  <title type=\'text\'>My cool car is for sale</title>" +
        "  <content type=\'xhtml\'>Light pink, yellow seats.</content>" +
        "</entry>";
It's a very simple item, consisting only of an item type ("products", in our case), a title and a content (description). Feel free to change these fields to contain your personalized items or to add new attributes and labels (use the responses dumped by QueryExample1 and QueryExample3 as an inspiration for adding new attributes).

Running InsertExample

  1. Edit InsertExample.java and make the following changes:
  2. Compile and run the example using your favorite editor, or the command line:
        javac sample.gbase/basic/InsertExample.java
        java sample.gbase/basic/InsertExample
      
    
  3. The output will look like:
        Obtained authorization token: DQAAAGgA...dk3fA5N
        <?xml version='1.0' encoding='UTF-8'?>
        <entry>
        <id>http://base.google.com/base/feeds/items/16024998325761524417</id>
        <published>2006-08-23T15:18:55.184Z</published>
        <updated>2006-08-23T15:18:55.184Z</updated>
        <category scheme="http://base.google.com/categories/itemtypes" term="Products"/>
        <title type="text">My cool car is for sale</title>
        <content type="xhtml">Light pink, yellow seats.</content>
        <link rel="self" type="application/atom+xml" href="http://base.google.com/base/feeds/items/16024998325761524417"/>
        <link rel="edit" type="application/atom+xml" href="http://base.google.com/base/feeds/items/16024998325761524417"/>
        <g:item_type type="text">Products</g:item_type>
        </entry> 
      
    

Stepping through the InsertExample code

We use the same feed as in QueryExample3.java to insert the item:

  private static final String ITEMS_FEED = "http://base.google.com/base/feeds/items";
Authentication is also performed as in QueryExample3, using makeLoginRequest to request an authorization token and authenticate to parse the authentication response. The insertion of the new data item is done in postItem, which connects to the items feed:
    HttpURLConnection connection = (HttpURLConnection)(new URL(ITEMS_FEED)).openConnection();
Once the connection is created, we need to set its properties: the Http request method, the content type of the information that is being posted, the authorization header:
    connection.setRequestMethod("POST");
    connection.setRequestProperty("Content-Type", "application/atom+xml");
    connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token);
We then obtain the output stream of the connection and dump DATA_ITEM into it:
    OutputStream outputStream = connection.getOutputStream();
    outputStream.write(DATA_ITEM.getBytes());
    outputStream.close();
The rest of the method is already familiar: we obtain the response code and print out to the console the contents of the input stream corresponding to the response code.

Update Example - Modifying your Google Base items.

The previous examples demonstrated how to query the Google Base data API server both for authenticated and unauthenticated feeds and how to insert a new item. We will combine this knowledge in order to demonstrate how to update an already existing item. Again, you will need a Google Account email and password in order to run this example. If you don't have a Google Account, sign up for one here. This example does not introduce important new concepts, but rather uses all the essentials that have been presented in the previous examples: we will authenticate, insert an item, and then update the inserted item by adding a new label to it.

Running UpdateExample

  1. Edit UpdateExample.java and make the following changes:
  2. Compile and run the example using your favorite editor, or the command line:
        javac sample.gbase/basic/UpdateExample.java
        java sample.gbase/basic/UpdateExample
      
    
  3. The output will look like:
        Obtained authorization token: DQAAAGgA...dk3fA5N
        Posting item:
        <?xml version='1.0'?>
        <entry xmlns='http://www.w3.org/2005/Atom' xmlns:g='http://base.google.com/ns/1.0'>
          <category scheme='http://base.google.com/categories/itemtypes' term='Products'/>
          <g:item_type type='text'>Products</g:item_type>
          <title type='text'>My cool car is for sale</title>
          <content type='xhtml'>Light pink, yellow seats.</content>
        </entry>
    
        Updating item: http://base.google.com/base/feeds/items/18020038538902937385  
    
        <?xml version='1.0' encoding='UTF-8'?>
        <entry>
          <id>http://base.google.com/base/feeds/items/18020038538902937385</id>
          <updated>2006-08-23T16:20:21.601Z</updated>
          <category scheme="http://base.google.com/categories/itemtypes" term="Products"/>
          <title type="text">My cool car is for sale</title>
          <content type="xhtml">Light pink, yellow seats.</content>
          <link rel="self" type="application/atom+xml" href="http://base.google.com/base/feeds/items/18020038538902937385"/>
          <link rel="edit" type="application/atom+xml" href="http://base.google.com/base/feeds/items/18020038538902937385"/>
          <g:item_type type="text">Products</g:item_type>
        </entry>
    

Stepping through the UpdateExample code

The main method of UpdateExample provides a good outline of the example's structure:

 public static void main(String[] args) throws MalformedURLException, IOException {
    UpdateExample updateExample = new UpdateExample();
    String token = updateExample.authenticate();
    System.out.println("Obtained authorization token: " + token);
  
    System.out.println("Posting item:\n" + DATA_ITEM);
    String itemUrl = updateExample.extractItemUrlFromResponse(
        updateExample.postItem(token));
    
    System.out.println("Updating item: " + itemUrl);
    String updateResponse = updateExample.updateItem(token, itemUrl);
    System.out.println(updateResponse);
  }
Just like in the previous examples, we start by authenticating and obtaining an authorization token using the authenticate method:
    String token = updateExample.authenticate();
We then insert DATA_ITEM using postItem:
   String itemUrl = updateExample.extractItemUrlFromResponse(
        updateExample.postItem(token));
In the line above, we pass the output of the post operation toextractItemUrlFromResponse (rather than dumping it out to the console), which extracts the inserted item's id:
      <id>http://base.google.com/base/feeds/items/18020038538902937385</id>
We assume that the item's id is surrounded by the first <id></id> tags; this is true for the Google Base data API servers, but it's not enforced by the Atom protocol. See how the title gets parsed in Query Example 2, for a superior approach on parsing the item's title.

Once DATA_ITEM is successfully inserted, we replace it with NEW_DATA_ITEM using updateItem. Updating an item is very similar to inserting a new one - in fact so similar that both operations can be performed by the same method: makeHttpRequest. makeHttpRequest receives as parameters the authorization token, the url to connect to, the item to be inserted or posted, the http method to use (this will be POST for inserting, and PUT for deleting) and the response code to expect in case of a successful operation (HTTP_CREATED in case of insert, HTTP_OK in case of update). Thus, postItem will contain a simple invocation to makeHttpRequest:

    public String postItem(String token) throws IOException {
      return makeHttpRequest(token, ITEMS_FEED, NEW_DATA_ITEM, "POST", HttpURLConnection.HTTP_CREATED);
    }
  
Similarly, updateItem invokes makeHttpRequest with slightly different parameters:
    public String updateItem(String token, String itemUrl) throws MalformedURLException, IOException {
      return makeHttpRequest(token, itemUrl, NEW_DATA_ITEM, "PUT", HttpURLConnection.HTTP_OK);
    }