认识 Atom 发布协议,第 2 部分: 应用 Atom 发布协议

准备开始

首先要保证安装了 Apache Abdera 的当前版本。源代码可以从 Apache Subversion 资料库http://svn.apache.org/repos/asf/incubator/abdera/java/trunk 下载。要检索源代码,需要安装 subversion 客户机并使用下面的命令:

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

下载源代码的镜像之后就可以用 Ant version 1.6.5 或更高版本构建 Abdera 了。

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

构建完成后,编译后的 jar 和 dependency 放在新建的 dist 目录中。要运行这些例子,需要在类路径中添加下列 jar:

表 1. 运行例子需要的 jar
Abdera (dist) Dependency (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

Weblog

根据 IETF Atom Publishing Format and Protocol 工作组的章程,Atom 发布协议(Atom Publishing Protocol)的设计目标主要用于发布和管理 weblog 记录。毫不奇怪,随后很多 blogging 软件提供商如 Google、SixApart 和 Roller 已经开始初步支持该协议。

Google 的 Blogger Beta

2006 年 8 月初,Google 宣布将对其提供的网络日记服务进行期待已久的升级。服务新增加的一个特性就是支持使用 Atom 发布协议创建和编辑公告。

创建公告非常简单。首先需要知道新记录所要发送到的 Atom 集合的 URL。对于 Blogger 来说,Atom 提要用于连锁 blog 的内容组成 Atom 发布协议集合供提要阅读器和聚合器使用。因此要确定集合的 URI,只要查看 weblog 主页头部的替代链接即可。

清单 1. Blogger 主页的头部

  
    testing
    
    
    
    
    
    
    ...

知道 Atom 提要的地址之后就可以向博客上发表记录了。清单 2 显示了要发送的贴子示例:

清单 2. Blogger 贴子
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}



  urn:uuid:1332534422684714363
  Posting to Blogger
  James
  2006-09-02T12:12:12Z
  
    

This is an example post to the new blogger beta

清单 2 中的请求有几点需要注意。首先也是最重要的是 Authorization 头部。Google 中支持 Atom Publishing Protocol 的服务要求使用一种私有的身份验证方法,所幸的是,实现起来并不麻烦。其次,Google 的实现要求请求中包含 Content-Length 头部。虽然看起来似乎无关紧要,但要求使用 Content-Length 带来了一个明显的副作用,即向服务器发送记录的客户机在发送之前必须计算请求的大小,因而降低了请求的效率。最后,发出的记录包含了 Blogger 将完全忽略的 ID、author 和 updated 元素。

第 1 步. 身份验证

向 Blogger 发送帖子的第一步是用 GoogleLogin 身份验证方法进行身份验证。为此需要创建 GoogleLogin 工具类。该工具需要输入访问 Google 帐户的用户 ID 和口令以及要访问的服务名称。该例中的服务名称为“blogger”。

清单 3. GoogleLogin 身份验证方法需要向身份验证服务器发送简单的 HTTP POST 请求
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;
  }
  ...
}

用适当的证书调用 GoogleLogin.getAuth(...) 方法将得到一个身份验证标记,可用于验证发表或者编辑 Blogger 记录的请求。

第 2 步. 创建记录

向 Blogger 发帖子的第二步是用 Apache Abdera 的 Feed Object Model API 创建发送的 Atom 记录:

清单 4. 创建 Blogger 记录
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(
  "

This is an example post to the new blogger beta

");

第 3 步. 发表记录

最后一步是把记录发送到 Blogger 服务器上:

清单 5. 向 Blogger 发送记录
Client client = new CommonsClient(abdera);
String auth = GoogleLogin.getAuth(
  client, "blogger", 
  "[email protected]", 
  "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!");

在 清单 5 中可以看到把上述各步骤都结合起来了。首先检索得到身份验证标记并作为请求选项设置。然后使用 Abdera 的 BaseRequestEntity 工具类作为记录的包装器,以保证正确地计算所需 Content-Length 头部。最后将记录发送到 Blogger 主页头部给出的 Atom 提要 URL。如果成功发布,服务器将返回 201 HTTP 状态码。

图 1. Blogger 中成功发帖
认识 Atom 发布协议,第 2 部分: 应用 Atom 发布协议_第1张图片

编辑和删除记录

通过 Atom 发布协议也可编辑和删除已有的记录:

清单 6. 更新已有的记录
String location = // get the URI of the entry to edit
    
Document 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);
清单 7. 删除记录
String location = // get the URI of the entry to delete

response = client.delete(location, options);

Roller Weblogger

但 Google 并不是惟一准备支持 Atom 发布协议的博客提供商。流行的开放源码 Roller Weblogger 包是很多大型公司博客网络的后端,如 Sun 的 http://blogs.sun.com 网站和 IBM 的内部 Intranet 博客服务,目前正准备升级以便支持 APP。除了一两处值得一提的区别外,向 Roller 上发贴基本上与 Blogger 相同:

清单 8. Roller 发帖的例子
POST /app/myblog/entries HTTP/1.1
Host: example.org
Content-Type: application/atom+xml
Authorization: Basic {user:password}


  urn:uuid:4BA4E6A3334F88813011571535258641
  Posting to Roller
  2006-09-01T23:32:05.880Z
  James
  
    

This is an example post to Roller

Roller Atom 接口和 Blogger 的主要区别是 Roller 提供了 APP Service Document 来发现可用的集合(而不是在 blog 主页中使用的替代链接),另外 Roller 使用的是标准 Basic 身份验证方案:

清单 9. 向 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("

This is an example post to Roller

"); Client client = new CommonsClient(abdera); client.addCredentials( start, null, null, new UsernamePasswordCredentials( "username", "password")); // Get the collection URI from the service document Document 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!");

发布媒体资源

Roller Atom Publishing 实现的另一个重要特性是支持上传任意的媒体资源。比方说,向服务器上传播客只需要将上例中的记录替换为代表要上传的 MP3 的请求实体:

清单 10. 向 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!");

还可以用 Atom 发布协议操作来更新、删除和列出上传到服务器上的所有资源。

日历管理

Atom Publishing 工作组的一个重要目标就是要设计这样一种协议,该协议虽然主要针对向 Weblog、Wiki 及类似应用程序发布内容,但也能用于其他多种应用程序。目前对 Atom Publishing 的支持已经延伸到很多不属于博客的应用程序。一个例子就是 Google 的 Calendar 应用程序。

Google Calendar

Google Calendar 是一种托管的日历管理服务,让用户能够通过基于浏览器的界面或者 Atom 发布协议管理公共或个人的日程表:

清单 11. Google Calendar 的 Atom 贴子
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


  
  urn:uuid:421D94DE83D298A91211571550147641
  Tennis with Beth
  Meet for a quick lesson
  2006-09-01T23:56:54.772Z
  James
  
  
  
  

需要注意的是,Google Calendar 和新的 Blogger Beta 一样都基于相同的后端 Atom 发布协议基础设施。和前面的 Blogger 例子一样,Calendar 也使用私有的 GoogleLogin 身份验证方法,也要求 Content-Length 头部。此外 Atom 记录中还需要一些扩展元素:

清单 12. 建立 Calendar 记录
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("

A new calendar event

"); 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());

建立记录后,剩下的就与向 Blogger 发贴基本一样了:

清单 13.发布到 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!");

另一种方法

Google 日历管理所采用的 Atom 方法面临的一个挑战是记录中需要使用厂商专用的扩展。IBM® Lotus® 的研究人员提出了一种替代方法,即利用 Atom 支持任何媒体类型这个特点使用现有的标准日历格式如 iCal 和 xCal:

清单 14. 向 Atom 集合发送 xCalendar 事件
POST /calendar HTTP/1.1
Host: example.org
Content-Type: application/calendar+xml
Content-Length: nnnn



 
  [email protected]
  20060901T130000Z
  20060901T163000Z
  20060901T164000Z
  Tennis with Beth
  PUBLIC
 

发送到集合后,服务器创建表代表该事件的 Atom Entry:

清单 15. Atom 服务器创建的日历项
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



 Tennis with Beth
 urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a
 2006-09-01T18:30:02Z
 James
 Tennis with Beth
 
 
 
 

请注意,这种方法不需要对 Atom 格式做任何扩展,实现可以继续使用已有的日历格式。

存储数据

还有人尝试使用 Atom 发布协议作为一种通用的前端 API 实现各种数据存储服务。其中包括文档和内容管理服务、软件资料库、数据库服务器、工作流和情景应用程序等等。

比如,Google 最近宣布新的 Google Base 服务 beta 版本将为各种应用程序服务存储任意数据:

清单 16. 发布到 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



  urn:uuid:1215d395-cfb1-4faa-b1cd-12da123e3a7a
  
  Acme 2000 series laptop
  
    
The fastest Acme Laptop yet...
Computer Laptop fastest laptop products

由于灵活的设计以及对任意媒体资源的支持,Atom 发布协议有望成为一种通用 Web 数据管理 API。

结束语

本文介绍了一些实际的 Atom 发布实现,这些实现已经部署并被成千上万的用户使用。为了支持文中的例子,本文使用开放源码的 Apache Abdera 项目示范了与各种博客、日历和数据管理服务的交互。本系列文章的下一篇将详细介绍 Apache Abdera 项目,包括对 Feed Object Model API 与各种特性(如对 XPath、XSLT 转换、内容筛选和 XML 数字签名的支持)的介绍。

你可能感兴趣的:(Abdera,apache,Project)