|
|
|
Atom support
Zero provides Atom support in two forms:
- Implicit support in the Zero Resource Model model-driven development
- Explicit support with Apache Abdera and an Atom renderer for simplified serialization
This page describes the latter, which is available in the zero.atom extension.
Adding zero.atom to your application
You must resolve a dependency in order 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+"/>
If you're using Eclipse, then the dependency is automatically resolved when you save the modified ivy.xml file. Steps to resolve from the command line are outlined on the dependencies page.
Advanced Abdera supports XPath as an alternative to Feed Object Model navigation, but zero.atom does not include XPath support for Abdera. You may 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:
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.
Example: Rendering an Entry
Example: 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()
}
Resultant Atom entry document
<?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 /{id}, which is probably correct in cases when dealing with resource handlers. If some situations (e.g. indirect access from a script in the public folder), you can specify a value for by setting the /request/atom/feedUri property for the renderer, as shown in Groovy syntax:
request.view = 'atom'
request.atom.output = textEntry
request.atom.feedUri = 'http://other.host.com/custom'
The resultant Atom entry document:
<?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 upon the following mappings of properties to Atom elements.
| 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 |
{key} | Object | simpleExtensionElement | text: {object}.toString() |
The Atom simpleExtensionElement is an XML element 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 and Map array to a feed.
Example: Rendering a feed
Example: 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()
}
Resultant Atom feed document
<?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 situation involving indirect access (e.g. a resource served optionally via a script in public folder). In such cases, you can specify the feed URI and title directly with additional properties to the renderer, as shown in 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 array 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:
| 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 (e.g. in a POST body):
Example: Groovy snippet
import org.apache.abdera.Abdera;
...
Entry entry = Abdera.getNewParser().parse(request.input[]).getRoot();
Example: 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();
|