Fork me on GitHub

Rome v0.1 Tutorial, Using Rome to aggregate many syndication feeds into a single one

Software requirements: J2SE 1.4+, Xerces 2.4.0, JDOM B10, Commons Codec 1.2 and Rome 0.1.

Rome represents syndication feeds (RSS and Atom) as instances of the com.rometools.rome.synd.SyndFeedI interface. The SyndFeedI interfaces and its properties follow the Java Bean patterns. The default implementations provided with Rome are all lightweight classes.

Rome includes parsers to process syndication feeds into SyndFeedI instances. The SyndInput class handles the parsers using the correct one based on the syndication feed being processed. The developer does not need to worry about selecting the right parser for a syndication feed, the SyndInput will take care of it by peeking at the syndication feed structure. All it takes to read a syndication feed using Rome are the following 2 lines of code:

SyndInput input = new SyndInput();
SyndFeedI feed = input.build(feedUrl.openStream());

The first line creates a SyndInput instance that will work with any syndication feed type (RSS and Atom versions). The second line instructs the SyndInput to read the syndication feed from the InputStream of a URL pointing to the feed. The SyndInput.build() method returns a SyndFeedI instance that can be easily processed.

Rome also includes generators to create syndication feeds out of SyndFeedI instances. The SyndOutput class does this generation. When creating a syndication feed output, the developer has to indicate the syndication feed type for the ouput, and the SyndOutput will use the right generator for it. The following two lines of code show how to create a syndication feed output from a SyndFeedI instance:

SyndOutput output = new SyndOutput(outputType);
output.output(feed,System.out);

The first line creates a SyndOutput instance that will produce syndication feeds of the type indicated by the outputType parameter. The outputType parameter can be any of the following values: rss_0.9, rss_0.91, rss_0.92, rss_0.93, rss_0.94, rss_1.0, rss_2.0 & atom_0.3. The second line writes the SyndFeedI as a syndication feed into the application's output.

SyndFeedI can also be created and populated within the code. For example:

SyndFeedI aggrFeed = new SyndFeed();
aggrFeed.setTitle("Aggregated Feed");
aggrFeed.setDescription("Anonymous Aggregated Feed");
aggrFeed.setAuthor("anonymous");
aggrFeed.setLink("http://www.anonymous.com");

The snipped of code above creates a SyndFeedI instance using the default implementation provided by Rome and sets the title, description, author and link properties of the feed.

SyndFeedI properties can be modified, assigned to other SyndFeedI instances, removed, etc. It's important to remember that the getters/setters semantics defined for all SyndFeedI properties (and properties of its properties) is a copy by reference, not by value. In other words if you alter the property of a SyndFeedI property you are altering the SyndFeedI. Or, another example, if you assign the list of entries of one SyndFeedI instance to another SyndFeedI isntance and then you modify the list or any of the entries in the list, you are modifying the entries of both SyndFeedI instances.

The following lines of code show how to copy the entries of a SyndFeedI instance being read (inFeed) into a SyndFeedI instance being created within the application (feed):

SyndFeedI feed = new SyndFeed();
...
List entries = new ArrayList();
feed.setEntries(entries);
...
SyndInput input = new SyndInput(false);
SyndFeedI inFeed = input.build(inputUrl.openStream());

entries.addAll(inFeed.getEntries());

Note that it's OK to assign the entries list to the feed and later add entries to it as all SyndFeedI getters/setters do copy by reference.

Following is the full code for a Java application that reads a list of syndication feed, aggregates their items into a single feed, and writes the aggregated feed to the application's output.

package com.rometools.rome.samples;

import java.net.URL;
import java.util.List;
import java.util.ArrayList;

import com.rometools.rome.feed.synd.SyndFeedI;
import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.feed.synd.SyndEntryI;
import com.rometools.rome.io.SyndInput;
import com.rometools.rome.io.SyndOutput;

public class FeedAggregator {

    public static void main(String[] args) {
        boolean ok = false;
        if (args.length>=2) {
            try {
                String outputType = args[0];

                SyndFeedI feed = new SyndFeed();
                feed.setTitle("Aggregated Feed");
                feed.setDescription("Anonymous Aggregated Feed");
                feed.setAuthor("anonymous");
                feed.setLink("http://www.anonymous.com");

                List entries = new ArrayList();
                feed.setEntries(entries);

                for (int i=1;i<args.length;i++) {
                    URL inputUrl = new URL(args[i]);

                    SyndInput input = new SyndInput(false);
                    SyndFeedI inFeed = input.build(inputUrl.openStream());

                    entries.addAll(inFeed.getEntries());

                }

                SyndOutput output = new SyndOutput(outputType);
                output.output(feed,System.out);

                ok = true;
            }
            catch (Exception ex) {
                System.out.println("ERROR: "+ex.getMessage());
            }
        }

        if (!ok) {
            System.out.println();
            System.out.println("FeedAggregator aggregates different feeds into a single one.");
            System.out.println("The first parameter must be the feed type for the aggregated feed.");
            System.out.println(" [valid values are: rss_0.9, rss_0.91, rss_0.92, rss_0.93, ]");
            System.out.println(" [                  rss_0.94, rss_1.0, rss_2.0 & atom_0.3  ]");
            System.out.println("The second to last parameters are the URLs of feeds to aggregate.");
            System.out.println();
        }
    }

}