This tutorial will guide you through the following concepts:
This assumes that you have some familiarity with Atom and AtomPub, but you will probably still get value out of the tutorial if you do not.
In this tutorial we're going to walk through how to build an Atom Publishing Protocol service using Abdera's concepts of Providers and CollectionAdapters. If you remember your AtomPub basics, you'll recall that AtomPub services are organized in a hierarchical way such that we have:
Abdera provides some classes which map to these concepts:
AtomPub Concept |
Abdera Classes |
Description |
---|---|---|
Service |
Provider |
Providers provide the implementation of an AtomPub service. In general you should be able to just use the DefaultProvider which we will be using it as we construct our service. |
Workspace |
WorkspaceInfo & WorkspaceManager |
The WorkspaceInfo class provides metadata about your workspace for the services document. The WorkspaceManager provides a way for you to list out the workspaces in a service. |
Collection |
CollectionAdapter |
A CollectionAdapter is where your business logic will lie and allows you to implement the basic GET/DELETE/POST/etc operations for an AtomPub Collection. |
Abdera comes with a class called the AbstractEntityCollectionAdapter. This class provides a simple "fill in the blanks" approach so that you can easily map your concepts to an AtomPub collection. The idea is that you have an entity class which represents each individual entry. For instance, if you were writing a blog, you would have a BlogEntry class which backs the entry. Or in our case of an employee directory, it would be an Employee class. Abdera will then provide some template methods which you fill in to give Abdera the necessary metadata.
Our Atom Collection is going to be a simple store of employees which can be added to, deleted from, updated, etc. To get started, we must first build our Employee class:
The ID is going to be used as a unique identifier for our Employee so that even if the employee's name changes, we can tie it to a previous atom entry and track the changes. The updated date will be used for our Atom feed, so that consumers know if there were changes and when they occurred.
Now we need to create our CollectionAdapter:
The first thing we'll do is provide a hashmap to store our Employees in. Typically this will be a database or some other type of backend store. To keep things simple, we're going to store employees in a Map according to their employee id.
Next up, we need to implement some methods which provide some basic metadata about our collection such as the feed author, the feed ID, and the feed title:
The ID in getId(RequestContext) must be a unique identifier for your feed. The idea is that even if your feed location changes, or someone is redistributing your feed, the feed reader can use this ID to identify that two feeds are the exact same. For information on how to construct feed IDs and why they matter, its recommend that you use this article on how to create feed ids.
The next step is to implement the methods which provide some basic metadata about our entries:
Walking through this we have:
The AbstractEntityCollectionAdapter maps individual entries via a "resource name." You must provide a way to create a resource name for your entry and also provide a way to look up an entry from your resource name. In this case, our entry is an Employee.
When we do this we must ensure that we won't have conflicts. Which means we don't want to use the employee name as the unique resource name as there may be conflicts. However we don't necessarily want to use just the employee ID either as the URL isn't very friendly. So we'll create a hybrid of the form: "EMPLOYEE_ID-EMPLOYEE_NAME".
Note the use of the sanitizer. This will take any invalid characters for a URL and either strip or replace them from the string.
We must also provide a way to turn a resource name into an employee:
The last step is to implement the POST, DELETE, and PUT operations.
The POST method corresponds to creating an Employee in the database. Here we're:
The putEntry method is similar. In this case we're just updating the employee name.
Finally, we have the deleteEntry method which gives us the resource name and allows us to remove it from the Map.
Because we've already supplied Abdera with lots of metadata about our entry, you get the HEAD operation for free!
You've now written an Abdera CollectionAdapter to expose your employee database to the world via an Atom collection. You must still expose it via a servlet though. Below shows how to extend the AbderaServlet to create your provider.
In this code we're setting up a Provider which contains an Atom workspace which contains our Atom collection.
When we initialize our CollectionAdapter we call setHref. Abdera uses this to determine the URL space. This leaves us with the following URL structure:
URL |
Description |
---|---|
/ |
The services document |
/employee |
The Atom feed which maps to the employee collection. |
/employee/XXX |
An individual atom entry from our collection. |
You could just as well use the Spring Integration or the web.xml configuration capabilities of Abdera to expose your Provider/CollectionAdapter as well.
Finally, you can deploy your Atom service inside your favorite servlet container witht he following XML.