Atom support
Project Zero provides Atom support
both implicitly and explicitly. This article describes the explicit support
that is available in the zero.atom extension.
Project Zero provides the following types of Atom support:
- Implicit support in the Zero Resource Model model-driven development
- Explicit support with Apache Abdera and an Atom renderer for simplified serialization
It is the explicit support, available with the zero.atom extension,
that is discussed in this article.
Adding zero.atom to
your application
To add zero.atom to your application,
start by adding the following line to the dependencies element in your config/ivy.xml file:
<dependency org="zero" name="zero.atom" rev="1.0+"/>
zero.atom does
not include XPath support for Abdera. You can add XPath support using the
standard
Abdera mechanisms.
Output handling: Atom renderer
The Atom renderer simplifies serialization
to Atom entry, feed, and service documents. Using a simple convention, the
renderer serializes Maps to entries and Map arrays
and List<Map> to feeds. The renderer also serializes Abdera
elements (Entry, Feed, and Service) for consistency.
The general syntax for invoking the Atom renderer within Groovy scripts is similar to the core renderers, as shown in the following example:
request.view = 'atom' request.atom.output = object render()
The following sections describe the specific behavior for various object types.
Rendering a Map as an Entry
A simple convention is used to convert a Map to an entry. This is shown
in the following sections that provide several examples in Groovy. An equivalent example in
PHP is shown in a later example.
Example: Rendering an Entry
The following example shows an entry rendered for a Groovy-based resource handler:
def onRetrieve(){
entry = [
// Required
id : '1',
title : 'title',
updated : new Date(0),
authorname : 'name',
content : 'content',
contenttype : 'TEXT',
// Optional
categorylabel : 'label',
categoryterm : 'term',
summary : 'summary',
summarytype : 'TEXT',
// Extensions
f1 : 'v1'
]
request.view = 'atom'
request.atom.output = entry
render()
}
The following Atom entry document is the result of the previous example:
<?xml version="1.0" encoding="UTF-8"?> <entry xmlns:zero="http://projectzero.com/namespace" xmlns="http://www.w3.org/2005/Atom"> <id>http://localhost:8081/resources/custom/1</id> <link href="http://localhost:8081/resources/custom/1" rel="edit"></link> <title type="text">title</title> <updated>1970-01-01T00:00:00.000Z</updated> <author><name>name</name></author> <content type="text">content</content> <summary type="text">summary</summary> <category term="term" label="label"></category> <zero:f1 xmlns:zero="http://projectzero.com/namespace">v1</zero:f1> </entry>
Example: Custom feed URI
By default, the request URI is used to construct the id and link values. The convention assumes that the request URI is of the form
<feedURI>/{id}
, which is probably correct in cases when dealing with resource handlers. In some situations (for example, indirect access from a script in the public folder), you can specify a value for
<feedURI>
by setting the /request/atom/feedUri property for the renderer, as shown in following Groovy syntax:
request.view = 'atom' request.atom.output = textEntry request.atom.feedUri = 'http://other.host.com/custom'
The following Atom entry document is the result of the previous example:
<?xml version="1.0" encoding="UTF-8"?> <entry xmlns:zero="http://projectzero.com/namespace" xmlns="http://www.w3.org/2005/Atom"> <id>http://other.host.com/custom/1</id> <link href="http://other.host.com/custom/1" rel="edit"></link> <title type="text">title</title> <updated>1970-01-01T00:00:00.000Z</updated> <author><name>name</name></author> <content type="text">content</content> <summary type="text">summary</summary> <category term="term" label="label"></category> <zero:f1 xmlns:zero="http://projectzero.com/namespace">v1</zero:f1> </entry>
Details about the entry conventions
Instances of Map are serialized by first forming equivalent Abdera Entry types, based on the mappings of properties to Atom elements shown in the following table.
| Required properties | |||
|---|---|---|---|
| Map Key | Expected Data Type | Atom element | Contents |
id |
int or String | atom:id | uri: http://{hostname:port}/...
{requestUri}/{id} |
| atom:link | uri: http://{hostname:port}/...
{requestUri}/{id} (rel=edit) |
||
title |
String | atom:title | text: {title} |
authorname |
String | atom:name of atom:author | text: {authorname} |
updated |
Date | atom:updated | date: {updated} |
contenttype |
String ("TEXT" or "HTML" or "XHTML") | atom:type of atom:content | text: {contenttype} |
content |
String | atom:content | text: {content} |
| Optional properties | |||
| Map Key | Expected Data Type | Atom element | Contents |
categoryterm |
String | atom:term of atom:category | text: {categoryterm} |
categorylabel |
String | atom:label of atom:category | text: {categorylabel} |
summary |
String | atom:summary | text: {summary} |
summarytype |
String ("TEXT" or "HTML" or "XHTML") | atom:type of atom:content | text: {summarytype} |
| Extensions | |||
| Map Key | Expected Data Type | Atom element | Contents |
{key} |
Object | simpleExtensionElement | text: {object}.toString() |
The Atom simpleExtensionElement XML element is appended
to the Atom entry with the following characteristics:
- element name
-
{key} - element namespace
-
"http://projectzero.com/namespace" - element name prefix
-
"zero" - element value:
-
{object}.toString
Rendering a List<Map> or Map array as a feed
A simple convention is used to convert List<Map> and Map arrays to a feed, as the examples in the following sections show.
Example: Rendering a feed
The following example shows a Groovy-based resource handler:
def onList() {
entry = [
// Required
id : '1',
title : 'title',
updated : new Date(0),
authorname : 'name',
content : 'content',
contenttype : 'TEXT'
]
request.view = 'atom'
request.atom.output = [entry]
render()
}
The following example shows the Atom feed document that is the result of the previous example.
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>http://localhost:8081/resources/custom</id>
<title type="text">http://localhost:8081/resources/custom</title>
<link href="http://localhost:8081/resources/custom" rel="self"></link>
<updated>1970-01-01T00:00:00.000Z</updated>
<entry>
<id>http://localhost:8081/resources/custom/1</id>
<title type="text">title</title>
<updated>1970-01-01T00:00:00.000Z</updated>
<author><name>name</name></author>
<content type="text">content</content>
<link href="http://localhost:8081/resources/custom/1" rel="edit"></link>
</entry>
</feed>
Example: Custom feed URI and title
The convention assumes that the request URI for a feed is the feed URI, which is used to construct entry elements (id and link) and feed elements (id, link, and title). This is probably suitable for cases involving resource handlers, but might not be correct for situations involving indirect access (for example, a resource served optionally using a script in the public folder). In such cases, you can specify the feed URI and title directly with additional properties to the renderer, as shown in the following Groovy syntax:
request.view = 'atom' request.atom.output = textEntry request.atom.feedUri = 'http://other.host.com/custom' request.atom.feedTitle = 'my feed'
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>http://other.host.com/custom</id>
<title type="text">my feed</title>
<link href="http://other.host.com/custom" rel="self"></link>
<updated>1970-01-01T00:00:00.000Z</updated>
<entry>
<id>http://other.host.com/custom/1</id>
<title type="text">title</title>
<updated>1970-01-01T00:00:00.000Z</updated>
<author><name>name</name></author>
<content type="text">content</content>
<link href="http://other.host.com/custom/1" rel="edit"></link>
</entry>
</feed>
Details about the feed conventions
Instances of List<Map> and Map arrays
are serialized in two steps. The first step is to form an Entry instance for each Map instance. The Feed instance is then the collection of the Entry objects and additional feed elements shown in the following table.
| Atom element | Contents |
|---|---|
| atom:id | uri: http://{hostname:port}/{requestUri} |
| atom:link | uri: http://{hostname:port}/{requestUri}
(rel=self) |
| atom:title | text: "http://{hostname:port}/{requestUri}" |
| atom:updated | most recent atom:updated value from entry list |
Input handling: Parsing Atom entry
Use the Abdera APIs to parse an incoming Atom entry (for example, in a POST body). This is shown in the following Groovy snippet example:
import org.apache.abdera.Abdera; ... Entry entry = Abdera.getNewParser().parse(request.input[]).getRoot();
The following example is a Java snippet:
import java.io.InputStream;
import org.apache.abdera.Abdera;
...
InputStream is = GlobalContext.<InputStream>zget("/request/input");
Entry entry = Abdera.getNewParser().parse(is).getRoot();
Atom handling in PHP
This section describes how to render Atom feeds and entries from your PHP script.
The PHP environment supports Atom by leveraging the IBM® WebSphere® sMash support for Atom.
Enabling PHP
To enable Atom/PHP support, add the following dependencies to the
ivy.xml file.
zero.php zero.atom
Atom renderer
The following code samples demonstrate the rendering of Atom entry and feed documents. Notice that two distinct types of date values are accepted in the updated field.
-
Timestamp : This is a numeric value representing the number of milliseconds
since the Unix epoch, which is defined as January 1 1970 00:00:00 GMT. Note that the
time()function returns the number of seconds since the epoch. - Date String : This is a string value representing a date. Acceptable values may include the date only ("1970-01-01") or the date and time ("1980-12-25 12:00:00"). For millisecond resolution, the Timestamp format should be used.
Atom entry document
<?php
$entry = array(
"id" => 1,
"title" => "A Good Title is Important",
"authorname" => "John Doe",
"updated" => time() * 1000, // milliseconds since the epoch
"contenttype" => "TEXT",
"content" => "Content is also important."
);
zput("/request/view","atom");
zput("/request/atom/output",$entry);
render_view();
?>
Atom feed document
<?php
// Rendering an Atom feed document.
$feed = array(
array(
"id" => 1,
"title" => "A Good Title is Important",
"authorname" => "John Doe",
"updated" => "1970-01-01", // date format
"contenttype" => "TEXT",
"content" => "Content is also important."
),
array(
"id" => 2,
"title" => "Bad Titles are Misleading",
"authorname" => "Jane Q. Sample",
"updated" => "1980-12-25 12:00:00", // date time format
"contenttype" => "TEXT",
"content" => "Content is also important."
)
);
zput("/request/view","atom");
zput("/request/atom/output",$feed);
render_view();
?>