Overview | Package | Class | Tree | Serialized | Deprecated | Index | Help
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES

## Package com.ibm.portal.resolver.atom

See:
Description

Interface Summary
AtomContentHandler | http://tools.ietf.org/html/rfc4287 RFC 4287
AtomThreadingContentHandler | http://www.ietf.org/rfc/rfc4685.txt ATOM threading extension (RFC 4685)
AtomXMLReader | Data source for an XML stream in ATOM format (http://tools.ietf.org/html/rfc4287).
DefaultAtomContentHandler | Extension of the `AtomContentHandler` interface that provides convenience methods to more easily generate ATOM events.
DefaultAtomThreadingContentHandler | Extension of the `AtomThreadingContentHandler` interface that provides convenience methods to more easily generate ATOM threading events.
ResettableAtomContentHandler | Extension of `AtomContentHandler` that allows to builds processing chains of these handlers.
ResettableAtomThreadingContentHandler | Extension of `AtomThreadingContentHandler` that allows to builds processing chains of these handlers.

## Package com.ibm.portal.resolver.atom Description

# ATOM API

### From Portalpedia

This article describes an API to facilitate the generation and parsing of ATOM feeds in JAVA. The goal of the API is to be easy to use, efficient and to cooperate well with existing XML generation and parsing mechanisms on the JAVA platform.

Table of contents
1 Design Principles 1.1 AtomXMLReader 1.2 AtomContentHandler 1.3 DefaultAtomContentHandler 1.4 AtomXMLReaderFactory 2 Access to the service 2.1 Example how to access an implementation 2.2 Example how to access the registry 3 Examples 3.1 Producers 3.1.1 Simple Feed Producer 3.1.2 Sophisticated Feed Producer 3.2 Consumers 3.3 Glueing it together 3.3.1 Serialization of a feed into XML markup 3.3.2 Interpretation of an XML markup stream as ATOM feed

# Design Principles

The ATOM API fully integrates with the JAXP API and is based on the SAX interfaces that are part of this API. The advantages of this design decision are

- the SAX API is very performant, because it avoids the generation of intermediary object both at feed generation and feed consumption time. Even large feeds can therefore handled in a scalable way
- by reusing the JAXP mechanism ATOM feeds can be serialized, deserialized, transformed (via XSLT) using existing and efficient mechanisms. The ATOM API only adds semantic on top of existing interfaces without breaking interoperability. This extra semantic makes it simple for clients to generate or parse ATOM feeds but at the same time maintain full flexibility.

## AtomXMLReader

The `AtomXMLReader` interface represents the source of SAX events and extends the defaultl `XMLReader` interface. Generators of feeds need to implement this interface, see the example section how this can be easily done. The actual events can be delivered in two ways

- directly as SAX events on the `ContentHandler` that is attached to the reader. This is the default case if interoparability with JAXP is required (e.g. if the feed needs to be serialized into XML markup).
- as callbacks to the `AtomContentHandler` interfaces. This is useful if there exists code that needs to further interpret the ATOM feeds.

## AtomContentHandler

As an extension of `ContentHandler` the `AtomContentHandler` interface adds method calls for each XML element that is defined in the ATOM RFC. So instead of constructing low level SAX events client can call these human readable methods to generate ATOM events.

The same interface is also used during ATOM parsing. The ATOM parser will make callbacks to the methods on the `AtomContentHandler` interface for all elements of the parsed feed that are in the ATOM namespace. All other events are transmitted as SAX events.

The methods on the `AtomContentHandler` are meant to be complete in the sense that they cover all elements that are declared in the ATOM namespace by RFC 4287. All methods define the attributes that the RFC mentions explicitly as possible attributes as top level parameters. All common or custom extensions are transported via the `Attributes` interface. The top level parameters carry a prefix that indicates if they are optional (`o`) or (`r`) required attributes. Optional attributes may be set to `null`, required attributes must not be `null`.

## DefaultAtomContentHandler

This is an extension of the `AtomContentHandler` interface that adds another layer of convenience for generators of ATOM feeds. In contrast to the `AtomContentHandler` interface however it is not used for parsing. This makes life easier for the consumer of the feed, because only the methods on `AtomContentHandler` need to be implemented.

The use of the methods on `DefaultAtomContentHandler` is optional, the complete functionality can be achieved by calling methods on `AtomContentHandler` directly. The purpose of the convenience layer is to simplify the common use cases. In particular all convenience methods assume that no custom attributes to the ATOM format are required, so they leave of the `Attributes` parameter. There exist the following categories of convenience methods

atomXXX
  these methods write the start and the end tag in one single call, without an enclosed `text()` element
startXXX
  these methods simplify the generation of start tags by omitting the `Attributes` parameter
misc
  there exist convenience methods to write `text()` elements in different formats.

## AtomXMLReaderFactory

The `com.ibm.portal.resolver.atom.AtomXMLReaderFactory` is the main entry point for the API. It allows for the construction of implementations of the ATOM API interfaces that can be used by feed producers and feed consumers to build their environment.

# Access to the service

The ATOM XML factory defines the Eclipse extension point `AtomXMLReaderFactory.EXTENSION_POINT_ID`. Clients can either look for any available extension of this extension point or directly look for the extension `AtomXMLReaderFactory.DEFAULT_EXTENSION_ID`.

## Example how to access an implementation

    final IExtensionPoint extPoint = extReg
            .getExtensionPoint(AtomXMLReaderFactory.EXTENSION_POINT_ID);
    final IExtension ext = extPoint
            .getExtension(AtomXMLReaderFactory.DEFAULT_EXTENSION_ID);
    final IConfigurationElement[] cfgElems = ext.getConfigurationElements();
    final AtomXMLReaderFactory atomFct = (AtomXMLReaderFactory) cfgElems[0]
            .createExecutableExtension(AtomXMLReaderFactory.ATTR_CLASS);

## Example how to access the registry

    InitialContext initialcontext = new InitialContext();
    IExtensionRegistry extReg = (IExtensionRegistry) initialcontext
                    .lookup("services/extensionregistry/global");

# Examples

These examples demonstrate how feeds can be produced, consumed and how both sides can be plugged together, e.g. to serialize or transform a feed.

## Producers

In order to generate an ATOM feed we need to create a stream of SAX events that corresponds to the ATOM specification. In the JAXP API the generator of SAX events is abstracted by the `XMLReader` interface. Our feed producer therefore needs to implement this interface and can do so conveniently by extending the `XMLFilterImpl` class that is part of the JAXP framework. As a minimum the implementor needs to override the parse method and needs to generate SAX events on the attached content handler. `XMLFilterImpl` implements the `ContentHandler` interface and dispatches automatically to the attached content handler, so we can use `this` as the content handler.

### Simple Feed Producer

Instead of directly generating SAX events we use the `DefaultAtomContentHandler` that allows to make human readable method calls to produce the events instead of generating the events directly. The implementation of `DefaultAtomContentHandler` translates these method calls into SAX events on a content handler that is attached to the `DefaultAtomContentHandler`. As discussed before, the target content handler is the `this` object, so as a first parsing step we attach this content handler to the `DefaultAtomContentHandler`. All subsequent calls on `DefaultAtomContentHandler` will then finally be translated into SAX events on the content handler that is attached to the `XMLReader`.

    package com.ibm.wps.resolver.test;

    import java.io.IOException;

    import org.xml.sax.InputSource;
    import org.xml.sax.SAXException;
    import org.xml.sax.helpers.XMLFilterImpl;

    import com.ibm.portal.resolver.atom.AtomXMLReaderFactory;
    import com.ibm.portal.resolver.atom.DefaultAtomContentHandler;

    /**
     * This example demonstrates how to produce a simple ATOM feed.
     *
     * @author cleue
     *
     */
    public class SimpleAtomFeed extends XMLFilterImpl {

            /**
             * handler that converts convenient method calls into ATOM events
             */
            protected final DefaultAtomContentHandler handler;

            public SimpleAtomFeed(final AtomXMLReaderFactory aFct) throws SAXException {
                    handler = aFct.createAtomContentHandler();
            }

            /* (non-Javadoc)
             * @see org.xml.sax.XMLReader#parse(org.xml.sax.InputSource)
             */
            public void parse(final InputSource input) throws SAXException, IOException {
                    // reroute the events via our own content handler
                    handler.setContentHandler(this);

                    // produce the events
                    handler.startDocument();
                    handler.startFeed();
                    handler.atomTitle("Mein erster Feed");
                    handler.atomAuthor("Carsten Leue");
                    handler.atomUpdated(System.currentTimeMillis());
                    handler.atomId("urn:test");

                    handler.startEntry();
                    handler.atomTitle("yet another title");
                    handler.atomLink("http://www.ibm.com", null, null, null, null, null);
                    handler.atomId("urn:test:entry");
                    handler.atomUpdated(System.currentTimeMillis());
                    handler.atomSummary("some text");
                    handler.endEntry();

                    handler.endFeed();
                    handler.endDocument();
            }

    }

### Sophisticated Feed Producer

In a more sophisticated example we show how standard JAXP mechanisms can be reused to merge existing XML documents into the ATOM feed. This can be very useful if such documents (or more generally any JAXP Source object) become the content of an `atom:content` element. The example shows this for the special case of a `javax.xml.transform.sax.SAXSource` object. For a generic source object, an identity transform needs to be applied to transform the generic source onto a `javax.xml.transform.sax.SAXResult` attached to the inner handler in the example.

For our example we reuse the system parser object in form of an `XMLReader` to parse an XML document. The parsing result is a series of SAX events that the parser throws onto a `ContentHandler`. The `DefaultAtomContentHandler` provides access to a special `ContentHandler` implementation that merges all events thrown onto it into the target XML stream. This merging process is very efficient, because it basically only consists of routing all events except the `start/endDocument` events to the target stream.

Note that the same parser object can be reused to embed an arbitrary number of inner content elements.

    package com.ibm.wps.resolver.test;

    import java.io.IOException;

    import org.xml.sax.InputSource;
    import org.xml.sax.SAXException;
    import org.xml.sax.XMLReader;
    import org.xml.sax.helpers.AttributesImpl;
    import org.xml.sax.helpers.XMLFilterImpl;
    import org.xml.sax.helpers.XMLReaderFactory;

    import com.ibm.portal.resolver.atom.AtomContentHandler;
    import com.ibm.portal.resolver.atom.AtomXMLReader;
    import com.ibm.portal.resolver.atom.AtomXMLReaderFactory;
    import com.ibm.portal.resolver.atom.DefaultAtomContentHandler;

    /**
     * <p>
     * Somewhat more spohisticated feed that demonstrates how custom attributes are
     * serialized and how content from an external source can be embedded into the stream.
     * </p>
     *
     * <p>
     * Notice that the feed implements the AtomXMLReader interface, implementing the #setAtomContentHandler(AtomContentHandler)
     * method. This allows the feed to be caugth on the AtomContentHandler interface
     * instead of the ContentHandler interface.
     * </p>

     *
     * @author cleue
     *
     */
    public class ExtensiveAtomFeed extends XMLFilterImpl implements AtomXMLReader {

            /**
             * handler that converts convenient method calls into ATOM events
             */
            protected final DefaultAtomContentHandler handler;

            /**
             * holder for custom attributes on the ATOM entries
             */
            protected final AttributesImpl attrs = new AttributesImpl();

            /**
             * parser used to embed XHTML content from an external source in the feed
             */
            protected final XMLReader parser;

            public ExtensiveAtomFeed(final AtomXMLReaderFactory aFct) throws SAXException {
                    parser = XMLReaderFactory.createXMLReader();
                    handler = aFct.createAtomContentHandler();
            }

            /* (non-Javadoc)
             * @see org.xml.sax.XMLReader#parse(org.xml.sax.InputSource)
             */
            public void parse(final InputSource input) throws SAXException, IOException {
                    // reroute the event
                    handler.setContentHandler(this);

                    handler.startDocument();
                    handler.startFeed();
                    handler.atomTitle("dive into mark");
                    handler.startSubtitle("html");
                    handler.text("A <em>lot</em> of effort went into making this effortless");
                    handler.endSubtitle();
                    handler.atomUpdated(System.currentTimeMillis());
                    handler.atomId("tag:example.org,2003:3");
                    handler.atomLink("http://example.org", "alternate", "text/html", "en",
                                    null, null);
                    handler.atomLink("http://example.org/feed.atom", "self",
                                    "application/atom+xml", null, null, null);
                    handler.atomRights("Rights");
                    handler.atomGenerator("http://www.example.com/", "1.0", "Example Toolkit");
                    handler.startEntry();
                    handler.atomTitle("Atom draft-07 snapshot");
                    handler.atomLink("http://example.org/2005/04/02/atom", "alternate",
                                    "text/html", null, null, null);
                    handler.atomLink("http://example.org/audio/ph34r_my_podcast.mp3",
                                    "enclosure", "audio/mpeg", null, null, "1337");
                    handler.atomId("tag:example.org,2003:3.2397");
                    handler.atomUpdated(System.currentTimeMillis());
                    handler.atomPublished(System.currentTimeMillis());
                    handler.startAuthor();
                    handler.atomName("Mark Pilgrim");
                    handler.atomURI("http://example.org/");
                    handler.atomEMail("f8dy@example.com");
                    handler.endAuthor();
                    handler.atomContributor("Sam Ruby");
                    handler.atomContributor("Joe Gregorio");

                    attrs.addAttribute("", "xml:lang", "xml:lang", "NMTOKEN", "en");
                    attrs.addAttribute("", "xml:base", "xml:base", "NMTOKEN",
                                    "http://diveintomark.org/");
                    handler.startContent("xhtml", null, attrs);
                    // now fetch this content from some external source
                    parser.setContentHandler(handler.getInnerHandler());
                    parser.parse(new InputSource(getClass().getResourceAsStream(
                            "content.xhtml")));
                    handler.endContent();
                    handler.endEntry();
                    handler.endFeed();
                    handler.endDocument();
            }

            /* (non-Javadoc)
             * @see com.ibm.portal.resolver.atom.AtomXMLReader#setAtomContentHandler(com.ibm.portal.resolver.atom.AtomContentHandler)
             */
            public void setAtomContentHandler(final AtomContentHandler aHandler) {
                    // replace the atom handler on the delegate
                    handler.setAtomContentHandler(aHandler);
            }

    }

## Consumers

ATOM parsing is done by the `AtomXMLReader` that is instantiated via the `com.ibm.portal.resolver.atom.AtomXMLReaderFactory`. This reader produced method callbacks on the `AtomContentHandler` interface for each XML element in the ATOM namespace. Clients of the parser that want to interpret the feed need to implement `AtomContentHandler` and further interpret the method calls.

In many cases clients will only be interested in a small subset of all ATOM events. For this purpose they can subclass `EmptyAtomContentHandler` and only override the methods they are interested in.

    public class TestAtomHandler extends EmptyAtomContentHandler {

            public void endEntry() throws SAXException {
                    System.out.println("endEntry"); }

            public void startEntry(Attributes attrs) throws SAXException {
                    System.out.println("startEntry");
            }

            public void startLink(String rHref, String oRel, String oType, String oHrefLang, String oTitle, String oLength, Attributes attrs) throws SAXException {
                    System.out.println("startLink href = " + rHref);
            }

            public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                    System.out.println("startElement uri = " + uri);
            }

    }

## Glueing it together

Feed producers and consumers can be glued together in many different ways, only restricted by the JAXP APIs. These possibilities include the serialization of feeds into XML markup, transformation into different formats or ATOM flavors using XSLT, merging or chaining feeds, etc. The following examples illustrate the main usecases.

### Serialization of a feed into XML markup

In JAXP the serialization of XML into markup is done by applying the identity transformation to a `Source` object, routing the events onto a `javax.xml.transform.stream.StreamResult` object. The same mechanism is used to serialize ATOM feeds.

Note that the `InputSource` that is passed as a parameter to `javax.xml.transform.sax.SAXSource` can be used to carry parametrization on to the parse method of the feed provider.

Ir the transformer used in the example was not the identity transform but a more sophisticated XSLT, then the same code could be used to transform the ATOM feed on-the-fly before serializing it.

    final Transformer trfrm = TransformerFactory.newInstance().newTransformer();

    Source src = new SAXSource(new SimpleAtomFeed(xmlFct), new InputSource());
    Result res = new StreamResult(System.out);

    trfrm.transform(src, res);

### Interpretation of an XML markup stream as ATOM feed

The interpretation of a feed is done by an implementation of `AtomContentHandler`. In this example this is the TestAtomHandler class. The ATOM API framework takes care of the production of method callbacks onto this handler that then can be interpreted easily.

    final AtomXMLReader rdr = xmlFct.createXMLReader();
    final AtomContentHandler handler = new TestAtomHandler();

    final InputSource in = new InputSource(getClass().getResourceAsStream("sampleFeed.xml"));
    rdr.setAtomContentHandler(handler);
    rdr.parse(in);

or

    final Transformer trfrm = TransformerFactory.newInstance().newTransformer();
    final AtomContentHandler handler = new TestAtomHandler();

    final Source src = new StreamSource(getClass().getResourceAsStream("sampleFeed.xml"));
    final Result res = new SAXResult(xmlFct.createContentHandler(handler));

    trfrm.transform(src, res);

Overview | Package | Class | Tree | Serialized | Deprecated | Index | Help
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES