Getting to know the Atom Publishing Protocol, Part 2: Put the Atom Publishing Protocol (APP) to work

Interact with deployed applications like weblogs or calendars

The previous installment in this series presented a brief walk-through of the Atom Publishing Protocol (APP). This article continues the introduction of the protocol by demonstrating how you can use it to interact with a number of real-world deployed applications.

As before, this discussion assumes you have an understanding of content syndication using the Atom 1.0 Syndication Format and a rudimentary understanding of HTTP. The examples are written in Java 1.5 and use a recent snapshot of the Apache Abdera open source Atom implementation currently under incubation by the Apache Software Foundation.

Share:

James Snell (jasnell@us.ibm.com), Software Engineer, EMC

Photo of James M SnellJames Snell is a member of IBM's WebAhead development lab focusing on the prototype development of pre-emerging software technologies and standards for IBM's own use. His research and development interests cover a broad range of current technology trends including Atom, AJAX, REST, Open Source, personal publishing systems, semantic Web and situational applications. He is an active committer to the Apache Abdera project, currently in incubation and tasked with the creation of a high-performance, functionally complete implementation of the Atom Syndication Format and Atom Publishing Protocol standards.


developerWorks Contributing author
        level

07 November 2006

Also available in Chinese Russian

Getting started

Before you begin, ensure that you have the current version of Apache Abdera installed. The source is available in the Apache Subversion repository at http://svn.apache.org/repos/asf/incubator/abdera/java/trunk. To retrieve the source, first ensure you have the subversion client and issue the command:

> svn co http://svn.apache.org/repos/asf/incubator/abdera/java/trunk

Once you download the source image, you can build Abdera using Ant version 1.6.5 or higher.

> cd trunk
> ant -f build/build.xml dist

After the build completes, the compiled jars and dependencies are located in a newly created dist directory. To run the examples, you need to have the following jars in your classpath:

Table 1. Jars required to run the examples
Abdera (dist)Dependencies (dist/lib)
  • abdera.client.0.2.0-incubating-SNAPSHOT.jar
  • abdera.core.0.2.0-incubating-SNAPSHOT.jar
  • abdera.parser.0.2.0-incubating-SNAPSHOT.jar
  • abdera.protocol.0.2.0-incubating-SNAPSHOT.jar
  • axiom-api-1.0.jar
  • axiom-impl-1.0.jar
  • commons-codec-1.3.jar
  • commons-httpclient-3.0.1.jar
  • commons-logging-1.0.4.jar
  • geronimo-activation_1.0.2_spec-1.1.jar
  • geronimo-javamail_1.3.1_spec-1.1.jar
  • log4j-1.2.12.jar
  • stax-1.1.2-dev.jar
  • stax-api-1.0.jar

Weblogs

In accordance with the charter of the IETF's Atom Publishing Format and Protocol Working Group, the Atom Publishing Protocol is designed for the primary use case of publishing and management of weblog entries. It should come as no surprise, then, that many blogging software providers such as Google, SixApart, and Roller have already started to roll out preliminary support for the protocol.

Google's Blogger Beta

In early August of 2006, Google announced a long-awaited update to its hosted weblogging service. Among a number of other features, the service now supports the use of the Atom Publishing Protocol to create and edit posts.

Creating a post is rather straightforward. The first thing you need to know is the URL of the Atom collection to which new entries will be sent. For Blogger, the Atom feed used to syndicate the content of blogs to feed readers and aggregators doubles as the Atom Publishing Protocol collection. To find the collection URI then, one needs only look at the alternate link in the header of their weblogs home page.

Listing 1. The header of my Blogger home page
<html>
  <head>
    <title>testing</title>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/>
    <meta content='true' name='MSSmartTagsPreventParsing'/>
    <meta content='blogger' name='generator'/>
    <link rel="alternate" type="application/atom+xml" 
      title="testing - Atom" 
      href="http://beta.blogger.com/feeds/7352231422284704069/posts/full" />
    <link rel="alternate" type="application/rss+xml" 
      title="testing - RSS" 
      href="http://beta.blogger.com/feeds/7352231422284704069/posts/full?alt=rss" />
    <link rel="service.post" type="application/atom+xml" 
      title="testing - Atom" 
      href="http://beta.blogger.com/feeds/7352231422284704069/posts/full" />
    ...

Once you know the address of the Atom feed, you can start to post entries to the blog. Listing 2 illustrates the sample post you are going to send:

Listing 2. A sample Blogger post
POST /feeds/7352231422284704069/posts/full HTTP/1.1
Host: beta.blogger.com
Content-Type: application/atom+xml
Content-Length: 349
Authorization: GoogleLogin auth={auth token}

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <id>urn:uuid:1332534422684714363</id>
  <title>Posting to Blogger</title>
  <author><name>James</name></author>
  <updated>2006-09-02T12:12:12Z</updated>
  <content type="xhtml">
    <div xmlns="http://www.w3.org/1999/xhtml">
      <p>This is an example post to the new blogger beta</p>
    </div>
  </content>
</entry>

In Listing 2, note several important things about the request. The first, and most important, is the Authorization header. Google's Atom Publishing Protocol-enabled services require the use of a proprietary authentication scheme that is, thankfully, not that difficult to implement. Second, Google's implementation requires that requests contain the Content-Length header. While seemingly insignificant, the fact that Content-Length is required carries the potentially significant side effect of requiring clients that send entries to the server also calculate the size of the posted request prior to sending it, making requests less efficient than they could be. Finally, the posted entry contains ID, author, and updated element values that Blogger completely ignores.

Step 1. Authenticating

The first step to posting to Blogger is to authenticate using the GoogleLogin authentication scheme. To do this, create a GoogleLogin utility class. This utility takes as input the user ID and password you use to access your Google account and the name of the service being accessed. In this case, the service name is "blogger."

Listing 3. The GoogleLogin scheme requires sending a simple HTTP POST to their authentication server
public final class GoogleLogin {
  ...
  public static String getAuth(
    Client client, 
    String service, 
    String id, 
    String pwd) {
    try {
      StringRequestEntity stringreq =
        new StringRequestEntity(getRequest(id,pwd,service));
      RequestOptions options = client.getDefaultRequestOptions();
      options.setContentType("application/x-www-form-urlencoded");
      ClientResponse response = client.post(URI, stringreq, options);
      String auth = read(response.getInputStream());
      response.release();
      return auth.split("\n")[2].replaceAll("Auth=", "auth=");
    } catch (Exception e) {}
    return null;
  }
  ...
}

Calling the GoogleLogin.getAuth(...) method with appropriate credentials yields an authorization token that you can use to authenticate requests to post or edit Blogger entries.

Step 2. Building the entry

The second step to posting to Blogger is to construct the Atom entry that you will post using Apache Abdera's Feed Object Model API:

Listing 4. Building the Blogger entry
Abdera abdera = new Abdera();
Factory factory = abdera.getFactory();
Entry entry = factory.newEntry();
entry.setId(FOMHelper.generateUuid());
entry.setUpdated(new java.util.Date());
entry.addAuthor("James");
entry.setTitle("Posting to Blogger");
entry.setContentAsXhtml(
  "<p>This is an example post to the new blogger beta</p>");

Step 3. Posting the entry

The final step is to send the entry off to the Blogger server:

Listing 5. Posting the entry to Blogger
Client client = new CommonsClient(abdera);
String auth = GoogleLogin.getAuth(
  client, "blogger", 
  "your@user.id", 
  "your.password");
    
RequestOptions options = client.getDefaultRequestOptions();
options.setAuthorization("GoogleLogin " + auth);
    
BaseRequestEntity bre = new BaseRequestEntity(entry, false);
    
Response response = client.post(
  "http://beta.blogger.com/feeds/7352231422284704069/posts/full", 
  bre, options);

if (response.getStatus() == 201) 
  System.out.println("Success!");
else 
  System.out.println("Failed!");

In Listing 5 you can see all of the elements coming together. First, the authentication token is retrieved and set in as a request option. Then, you use Abdera's BaseRequestEntity utility class as a wrapper for the entry to be posted to ensure that the required Content-Length header is properly calculated. And last, you post the entry to the URL of the Atom feed identified in the header of the Blogger home page. If the post was successful, the server should respond with a 201 HTTP status code.

Figure 1. Viewing the successful post in Blogger
Screenshot of the successful post in Blogger

Editing and deleting Entries

With the Atom Publishing Protocol, you can also edit and delete existing entries:

Listing 6. Updating an existing entry
String location = // get the URI of the entry to edit
    
Document<Entry> entry_doc = client.get(location).getDocument();
entry = (Entry) entry_doc.getRoot().clone();
entry.setTitle("This is the changed title");
    
response = client.put(
  location, new BaseRequestEntity(entry,false), options);
Listing 7. Deleting an entry
String location = // get the URI of the entry to delete

response = client.delete(location, options);

Roller Weblogger

Google is not the only blogging provider with plans to support the Atom Publishing Protocol, however. The popular open source Roller Weblogger package, used as the back end to several large corporate blogging networks such as Sun's http://blogs.sun.com site and IBM's internal Intranet blogging service, is currently in the process of being updated to support APP. With a couple of notable exceptions, the process of posting to Roller is the same as posting to Blogger:

Listing 8. An example Roller post
POST /app/myblog/entries HTTP/1.1
Host: example.org
Content-Type: application/atom+xml
Authorization: Basic {user:password}

<entry xmlns="http://www.w3.org/2005/Atom">
  <id>urn:uuid:4BA4E6A3334F88813011571535258641</id>
  <title type="text">Posting to Roller</title>
  <updated>2006-09-01T23:32:05.880Z</updated>
  <author><name>James</name></author>
  <content type="html">
    <p>This is an example post to Roller</p>
  </content>
</entry>

The key differences between the Roller Atom interface and Blogger's include the fact that Roller provides an APP Service Document for discovering available collections (as opposed to using alternate links in the blog home page) and that it uses the standardized Basic authentication scheme:

Listing 9. Posting to Roller
String start = "http://roller.example.org/app";
    
Abdera abdera = new Abdera();
Factory factory = abdera.getFactory();
Entry entry = factory.newEntry();
entry.setId(FOMHelper.generateUuid());
entry.setUpdated(new java.util.Date());
entry.addAuthor("James");
entry.setTitle("Posting to Roller");
entry.setContentAsHtml("<p>This is an example post to Roller</p>");
    
Client client = new CommonsClient(abdera);
client.addCredentials(
  start, null, null, 
  new UsernamePasswordCredentials(
    "username", "password"));
    
// Get the collection URI from the service document
Document<Service> service_doc = client.get(start).getDocument();
Service service = service_doc.getRoot();
Collection collection = 
  service.getWorkspaces().get(0)
    .getCollections().get(0);
String uri = collection.getHref().toString();
      
Response response = client.post(uri, entry);

if (response.getStatus() == 201) 
  System.out.println("Success!");
else
  System.out.println("Failed!");

Posting media resources

Another important feature of Roller's Atom Publishing implementation is support for uploading arbitrary media resources. For instance, to upload a podcast to your server, you simply replace the entry in the previous post with a request entity representing the MP3 to be uploaded:

Listing 10. Posting audio resources to a Roller Weblog
FileInputStream fis = new FileInputStream(
  "mypodcast.mp3");
InputStreamRequestEntity re = 
  new InputStreamRequestEntity(fis, "audio/mp3");
Client client = // init the client    
String uri = // get the collection uri
      
RequestOptions options = client.getDefaultRequestOptions();
options.setHeader("Title", "mypodcast.mp3");
    
Response response = client.post(uri, re, options);
    
if (response.getStatus() == 201)
  System.out.println("Success!");
else
  System.out.println("Failed!");

You can also use the Atom Publishing Protocol operations to update, delete, and list all of the resources that were uploaded to the server.

Calendar management

An important goal for the Atom Publishing Working Group has been to design a protocol that, while targeted primarily at the publishing of content to Weblogs, Wikis, and similar applications, can be used for a broad range of applications. Today Atom Publishing support is being explored for many applications that do not fit within the realm of blogging. One such example is Google's Calendar application.

Google Calendar

Google Calendar is a hosted calendar management service that provides users with the ability to manage public and private calendars with either a browser-based interface or the Atom Publishing Protocol:

Listing 11. A sample Atom post to Google Calendar
POST /calendar/feeds/default/private/full HTTP/1.1
Host: www.google.com
Authorization: GoogleLogin auth={auth}
Content-Length: 834
Content-Type: application/atom+xml

<entry xmlns="http://www.w3.org/2005/Atom"
  xmlns:gd="http://schemas.google.com/g/2005" >
  <category scheme="http://schemas.google.com/g/2005#kind" 
    term="http://schemas.google.com/g/2005#event" />
  <id>urn:uuid:421D94DE83D298A91211571550147641</id>
  <title type="text">Tennis with Beth</title>
  <content type="text">Meet for a quick lesson</content>
  <updated>2006-09-01T23:56:54.772Z</updated>
  <author><name>James</name></author>
  <gd:transparency value="http://schemas.google.com/g/2005#event.opaque" />
  <gd:eventStatus value="http://schemas.google.com/g/2005#event.confirmed" />
  <gd:where valueString="Rolling Lawn Courts" />
  <gd:when startTime="2006-09-01T23:56:54.932Z" 
    endTime="2006-09-01T23:56:54.932Z" /></entry>

It is important to note that Google Calendar is based on the same back-end Atom Publishing Protocol infrastructure as the new Blogger Beta. As with the Blogger example shown previously, Calendar uses the proprietary GoogleLogin authentication scheme and requires the Content-Length header. Also required are a number of extension elements in the Atom entry:

Listing 12. Building the Calendar Entry
Abdera abdera = new Abdera();
Factory factory = abdera.getFactory();
Entry entry = factory.newEntry();
entry.setId(FOMHelper.generateUuid());
entry.setUpdated(new java.util.Date());
entry.addAuthor("James");
entry.setTitle("New Calendar Event");
entry.setContentAsXhtml("<p>A new calendar event</p>");
    
entry.addExtension(TRANSPARENCY).setAttributeValue(
  "value", "http://schemas.google.com/g/2005#event.opaque");
entry.addExtension(EVENTSTATUS).setAttributeValue(
  "value", "http://schemas.google.com/g/2005#event.confirmed");
entry.addExtension(WHERE).setAttributeValue(
  "valueString", "Rolling Lawn Courts");
Element el = entry.addExtension(WHEN);
el.setAttributeValue("startTime", AtomDate.valueOf(new Date()).toString());
el.setAttributeValue("endTime", AtomDate.valueOf(new Date()).toString());

Once you build the entry, the rest is virtually identical to posting to Blogger:

Listing 13. Posting to Google Calendar
Client client = new CommonsClient(abdera);
String auth = GoogleLogin.getAuth(client, "cl", "username", "password"); 
RequestOptions options = client.getDefaultRequestOptions();
options.setAuthorization("GoogleLogin " + auth);
    
BaseRequestEntity bre = new BaseRequestEntity(entry, false);   
String uri = "http://www.google.com/calendar/feeds/default/private/full";    
Response response = client.post(uri, bre, options);
    
// calendar may return a 302 with a new URI to post to
if (response.getStatus() == 302) {
  uri = response.getLocation().toString();
  response = client.post(uri, bre, options);
}
    
if (response.getStatus() == 201) 
  System.out.println("Success!");
else
  System.out.println("Failed!");

An alternative approach

One of the challenges with Google's approach to calendar management with Atom is the fact that vendor-specific extensions to the entry are required. An alternative approach proposed by researchers at IBM® Lotus® is to use Atom's support for arbitrary media types to work with existing standardized calendar formats such as iCal and xCal:

Listing 14. Posting an xCalendar event to an Atom collection
POST /calendar HTTP/1.1
Host: example.org
Content-Type: application/calendar+xml
Content-Length: nnnn

<?xml version="1.0" encoding="UTF-8"?>
<vcalendar version="2.0"
  prodid="-//hacksw/handcal//NONSGML 1.0//EN">
 <vevent>
  <uid>19970901T130000Z-123401@host.com</uid>
  <dtstamp>20060901T130000Z</dtstamp>
  <dtstart>20060901T163000Z</dtstart>
  <dtend>20060901T164000Z</dtend>
  <summary>Tennis with Beth</summary>
  <class>PUBLIC</class>
 </vevent>
</vcalendar>

Once posted to the collection, the server creates an Atom Entry representing the posted event:

Listing 15. A calendar entry created by the Atom server
HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content-Length: nnn
Content-Type: application/atom+xml; charset="utf-8"
Content-Location: http://example.org/calendar/1.atom
Location: http://example.org/calendar/1.atom

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
 <title>Tennis with Beth</title>
 <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
 <updated>2006-09-01T18:30:02Z</updated>
 <author><name>James</name></author>
 <summary type="text">Tennis with Beth</summary>
 <link rel="alternate" type="text/calendar"
   href="http://example.org/calendar/1.ics" />
 <content type="application/calendar+xml"
   src=http://example.org/calendar/1.xml/>
 <link rel="edit" type="application/atom+xml"
   href="http://example.org/calendar/1.atom" />
 <link rel="edit-media" type="application/calendar+xml"
   href="http://example.org/calendar/1.xml" />
</entry>

Note that with this approach, no extensions to the Atom format are required and implementations can continue to work with existing calendaring formats.

Storing data

The Atom Publishing Protocol is also being explored as a general purpose front end API to a variety of data storage services. These include such things as document and content management services, software repositories, database servers, workflow and situational applications, and so on.

For example, Google recently announced a new beta version of their Google Base service designed to store arbitrary data for a broad range of application services:

Listing 16. An example post to Google Base
POST /base/feeds/items HTTP/1.1
Host: www.google.com
Authorization: GoogleLogin auth={auth}
X-Google-Key: key={key}
Content-Type: application/atom+xml
Content-Length: 632

<?xml version='1.0'?>
<entry xmlns="http://www.w3.org/2005/Atom"
  xmlns:g="http://base.google.com/ns/1.0">
  <id>urn:uuid:1215d395-cfb1-4faa-b1cd-12da123e3a7a</id>
  <category scheme="http://base.google.com/categories/itemtypes" 
    term="products"/>
  <title type='text'>Acme 2000 series laptop</title>
  <content type='xhtml'>
    <div xmlns='http://www.w3.org/1999/xhtml'>
      The fastest Acme Laptop yet...
    </div>
  </content>
  <link rel='alternate' type='text/html' 
    href='http://www.provider-host.com/123456789'/>
  <g:label>Computer</g:label>
  <g:label>Laptop</g:label>
  <g:label>fastest laptop</g:label>
  <g:item_type>products</g:item_type>
</entry>

Because of its flexible design and support for arbitrary media resources, the Atom Publishing Protocol holds significant promise as a general purpose data management API for the Web.

Looking ahead

This article presented a number of real-world Atom publishing implementations that are already deployed and in use by thousands of users. To support the examples provided, this article demonstrated the use of the open source Apache Abdera project to interact with various blogging, calendar, and data management services. The next installment of this series provides a detailed overview of the Apache Abdera project, including a walk-through of the Feed Object Model API and a range of features including XPath, XSLT transforms, content filtering, and XML Digital Signature support.


Download

DescriptionNameSize
Sample Eclipse Project with the example codex-atompp2-appexamples.zip46KB

Resources

Learn

Get products and technologies

  • IBM trial software: Build your next development project with trial software available for download directly from developerWorks.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=171342
ArticleTitle=Getting to know the Atom Publishing Protocol, Part 2: Put the Atom Publishing Protocol (APP) to work
publish-date=11072006