Create a sidebar using an Atom service document

Atom service documents provide more than just where to find the feeds for a site

An Atom service document is for more than just telling readers where to find a site's feeds. This article shows you how to use this introspection document to create a sidebar that provides a window into everything your server has to offer. This article uses the Blogapps server, which supports draft 10 of the Atom Publishing Protocol 1.0 specification, but will be applicable to any APP 1.0 compliant server. To use the actual code, you should also be familiar with Java programming but you can apply the Atom concepts to any programming language.

Share:

Nicholas Chase (ibmquestions@nicholaschase.com), Writer, Freelance

Nicholas Chase has been involved in Web site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. Nick has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, an Oracle instructor, and the Chief Technology Officer of an interactive communications company. He is the author of several books, including XML Primer Plus (Sams).



10 July 2007

The service document

The Atom service document is how a service tells you know what is available. Each service represents one or more workspaces, which represent one or more collections. The collections contain the individual resources. For example, you can retrieve the Blogapps service document at http://local hosts:8080/roller/app (see Listing 1).

Listing 1. The service document
<?xml version="1.0" encoding="UTF-8"?>
<app:service xmlns:app="http://purl.org/atom/app#" 
              xmlns:atom="http://www.w3.org/2005/atom">
  <app:workspace>
    <atom:title>AdminBlog</atom:title>
    <app:collection 
          href="http://localhost:8080/roller/app/adminblog/entries">
      <atom:title>Weblog Entries</atom:title>
      <app:categories app:fixed="yes" 
            app:scheme="http://localhost:8080/roller/adminblog/">
        <atom:category atom:term="/General" atom:label="General" />
        <atom:category atom:term="/Status" atom:label="Status" />
      </app:categories>
      <app:accept>entry</app:accept>
    </app:collection>
    <app:collection 
         href="http://localhost:8080/roller/app/adminblog/resources">
      <atom:title>Media Files</atom:title>
      <app:accept>image/*</app:accept>
    </app:collection>
  </app:workspace>
  <app:workspace>
...
  </app:workspace>
</app:service>

From this document, you can create a servlet that includes a sidebar that shows all of the services and feeds available, along with links to their HTML versions.


The basic servlet

The first step is to create the basic servlet, including space for the sidebar (see Listing 2).

Listing 2. The basic servlet
package com.backstop.atom;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;

public class SideBarServlet extends javax.servlet.http.HttpServlet 
                                   implements javax.servlet.Servlet {

   String APPNS = "http://purl.org/atom/app#"; 
   String AtomNS = "http://www.w3.org/2005/atom";
   String AtomNS2 = "http://www.w3.org/2005/Atom";

   protected void doGet(HttpServletRequest request, 
                        HttpServletResponse response) 
                             throws ServletException, IOException {

      response.getWriter().print(
                         "<div style='width:25%; float: right;'>");   
      Document doc = URLContents.getContentsAsXMLDoc(
                                "http://localhost:8080/roller/app" );
      Element root = (Element)doc.getDocumentElement();
            
      NodeList workspaces = root.getElementsByTagNameNS(APPNS, 
                                                        "workspace");

      for (int i = 0; i < workspaces.getLength(); i++){

         Element thisWorkspace = (Element)workspaces.item(i);
         response.getWriter().print(
             "<div style='border: 1px solid green; padding: 5px;'>");

         String wsTitle = 
                    thisWorkspace.getElementsByTagNameNS(AtomNS, 
                                   "title").item(0).getTextContent();
         response.getWriter().print(
                             "<h3 class='wstitle'>"+wsTitle+"</h3>");

         response.getWriter().print("</div>");
      }
      response.getWriter().print("</div>");         

   }     
}

The class includes all of the import statements you'll need, as well as variables representing the needed namespaces. (Blogapps has a slight bug in that the service document has a slightly incorrect namespace; until that is fixed, you'll need to declare both versions: http://www.w3.org/2005/atom and http://www.w3.org/2005/Atom.)

The next step is to add the actual workspaces to the sidebar. To do that, loop through the workspace elements in the document. All of these documents are password-protected in the Blogapps server, so to keep things simple, I moved their actual retrieval to a separate utility class, URLContents. You can find it in the source code for this article. (If you wind up doing this retrieval on your own, make sure that you set your DocumentBuilderFactory to be namespace-aware.)

Once you have the XML Document object, you can loop through each of the workspace elements, and create a div on the page for each of them. For each one, extract the text of the title element and place it on the page, as you can see in Figure 1.

Figure 1. The workspaces
the workspaces

Now look at adding the collections.


Add the collections

Adding the collections to the page involves much the same process. Once you have the individual workspace, you can retrieve each of its collections (see Listing 3).

Listing 3. Looping through the collections
...
         response.getWriter().print(
                  "<h3 class='wstitle'>"+wsTitle+"</h3>");

         NodeList collections = 
            thisWorkspace.getElementsByTagNameNS(APPNS, "collection");

         for (int j = 0; j < collections.getLength(); j++){

            Element thisCollection = (Element)collections.item(j);

            String colTitle = 
                    thisCollection.getElementsByTagNameNS(AtomNS, 
                                    "title").item(0).getTextContent();
            String feedURL = thisCollection.getAttribute("href");

            response.getWriter().print(
                                 "<h4 class='collection'>"+colTitle);
            response.getWriter().print(" -- <a href='"+feedURL+
               "'><img border='0' src='images/feed-icon.gif' /></a>");
            response.getWriter().print("</h4>");
         }
         response.getWriter().print("</div>");
      }
      response.getWriter().print("</div>");         

   }
}

For each collection, you do a little bit more than just display the title, though. Each collection element also includes an href attribute, representing the location of the Atom feed for the collection. To take advantage of this, extract this information and add a feed icon, linking it to the feed's URL. The result should look something like Figure 2.

Figure 2. Adding the feeds
adding the feeds

Add categories

You can also add an indication of the categories of content covered by each collection (see Listing 4).

Listing 4. Adding categories
...
            response.getWriter().print(" -- <a href='"+feedURL+
               "'><img border='0' src='images/feed-icon.gif' /></a>");
            response.getWriter().print("</h4>");

            NodeList categories = 
                        thisCollection.getElementsByTagNameNS(AtomNS, 
                                                          "category");
            if (categories.getLength() > 0){
               response.getWriter().print(
                                   "Categories in this collection: ");
            }
            for (int k = 0; k < categories.getLength(); k++){
               Element thisCategory = (Element)categories.item(k);
               String catName = thisCategory.getAttributeNS(AtomNS, 
                                                             "label");
               if (k > 0){
                  response.getWriter().print(", ");
               }
               response.getWriter().print(catName);
            }

         }
         response.getWriter().print("</div>");
      }
      response.getWriter().print("</div>");
        
   }     
}

The result looks like Figure 3.

Figure 3. Adding categories
adding categories

Link to the HTML version

The final step is to include a link to the HTML representation of the information. Unfortunately, that information does not actually exist in the service document. To retrieve it, you will have to look at the feed itself (see Listing 5).

Listing 5. Retrieving the feed information
...
         for (int j = 0; j < collections.getLength(); j++){
            Element thisCollection = (Element)collections.item(j);
            String colTitle = 
                    thisCollection.getElementsByTagNameNS(AtomNS, 
                                    "title").item(0).getTextContent();
            String feedURL = thisCollection.getAttribute("href");
            String webURL = getWebURL(feedURL);

            response.getWriter().print(
               "<h4 class='collection'><a href='"+webURL+"'>"+>
                                                     colTitle+"</a>");
  ... 
         }
         response.getWriter().print("</div>");
      }
      response.getWriter().print("</div>");         

   }

   private String getWebURL(String feedURL){

      String webURL = "";

      Document doc = URLContents.getContentsAsXMLDoc(feedURL);
      Element root = (Element)doc.getDocumentElement();

      NodeList links = root.getElementsByTagNameNS(AtomNS2, "link");
      for (int i = 0; i < links.getLength(); i++){
         Element thisLink = (Element)links.item(i);
         if (thisLink.getAttribute("rel").equals("alternate") && 
                             thisLink.getParentNode().equals(root)){
             webURL = thisLink.getAttribute("href");
         }
      }
      return webURL;
   }
}

In this case, you retrieve the feed URL from the service document, and then retrieve that actual document, which includes a link element, such as <link rel="alternate" href="http://localhost:8080/roller/adminBlog" /> representing the HTML version of data represented by the feed. You can then add that information to the sidebar. The final result looks like Figure 4.

Figure 4. Adding categories
adding categories

Summary

The service document is more than just an opportunity for introspection; with careful planning, you can use it to provide actual content and links to content.


Download

DescriptionNameSize
Atom sidebar samplesx-atomsidebar-source.zip3KB

Resources

Learn

Get products and technologies

  • The Blogapps server: Download the server in this collection of useful RSS and Atom utilities and examples.
  • IBM trial software: Build your next development project with trial software available for download directly from developerWorks.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=229310
ArticleTitle=Create a sidebar using an Atom service document
publish-date=07102007