 | Level: Intermediate James Snell (jasnell@us.ibm.com), Software Engineer, IBM
07 Nov 2006
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.
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
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 | Description | Name | Size | Download method |
|---|
| Sample Eclipse Project with the example code | x-atompp2-appexamples.zip | 46KB | HTTP |
|---|
Resources Learn
-
Atom Publishing Protocol specification: Read the details of this new standard for content publishing and management.
-
Atom Syndication Format specification: Get the details on this XML-based document format that describes feeds that syndicate Web content such as weblogs and news headlines to Web sites and directly to user agents.
- The HTTP v1.1 specification: Read about the Hypertext Transfer Protocol (HTTP) protocol that the Atom Publishing Protocol leverages.
-
HTTP response status codes: Learn the standard Status-Code, including which methods it can follow and any required metainformation for the response.
-
Editing the Web: Detect concurrent updates using HTTP entity tags.
-
Apache Abdera project: Develop Atom-enabled Java applications.
-
Wordpress Weblog: Add Atom Publishing Protocol support to your Weblog.
-
Google's implementation: Learn about the Google Data APIs that use the Atom Publishing Protocol.
-
Roller blogging server: Check out this open source Java blog software.
-
IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
-
XML technical library: See the developerWorks XML Zone for a wide range of technical articles and tips, tutorials, standards, and IBM Redbooks.
-
developerWorks technical events and webcasts: Stay current with technology in these sessions.
Get products and technologies
-
IBM trial software: Build your next development project with trial software available for download directly from developerWorks.
Discuss
About the author  | 
|  | James 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. |
Rate this page
|  |