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:
| Abdera (dist) | Dependencies (dist/lib) |
|---|---|
|
|
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.
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.
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.
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>");
|
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

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);
|
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!");
|
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.
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 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!");
|
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.
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.
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.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample Eclipse Project with the example code | x-atompp2-appexamples.zip | 46KB | HTTP |
Information about download methods
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
- Participate in the discussion forum.
- XML zone discussion forums: Participate in any of several XML-centered forums.
- developerWorks blogs: Get involved in the developerWorks community.

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.
Comments (Undergoing maintenance)





