FeedTool is built on the Rome API and provides the ability to retrieve and manipulate RSS and Atom feeds from within Velocity templates.

The tool works by retrieving a feed from a specified URI and returning it in a ContextFeedWrapper class. The idea wth the wrapper class is to have a convenient location for the provision of convenience methods for feed and feed entry manipulation ... although it could easily be incorporated into a single class.

The tool consists of:

package org.apache.velocity.tools.view.tools;

import java.net.URL;
import java.net.HttpURLConnection;
import java.io.IOException;
import java.net.MalformedURLException;

import sun.misc.BASE64Encoder;

import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.XmlReader;
import com.sun.syndication.fetcher.FeedFetcher;
import com.sun.syndication.fetcher.FetcherException;
import com.sun.syndication.fetcher.impl.FeedFetcherCache;
import com.sun.syndication.fetcher.impl.HashMapFeedInfoCache;
import com.sun.syndication.fetcher.impl.HttpURLFeedFetcher;

/**
 * FeedTool
 * <p>
 * A Velocity View Tool for working with RSS and Atom APIs using Rome
 * </p>
 * @author C.Townson
 */
public class ViewFeedTool {
        /**
         * The URL of the feed to be fetched by RomeFetcher
         */
        private URL feedURL;
        
        /**
         * The FeedObject returned from fetch by RomeFetcher
         */
        private ContextFeedWrapper feed;

        /**
         * Default view tool no-arg constructor
         */
        public ViewFeedTool() {
                // do nothing - View Tools must have public no-arg constructor
        }
        
        /**
         * Returns the feed located at the specified URL
         * <p>
         * This is the core method provided with this tool - use this
         * from template, rather than any of the other public methods
         * </p>
         * TODO overloaded method with authenication parameterss
         * @param feedURL the url of the feed to retrieve
         * @return feed The feed object inside a utility wrapper class
         */
        public ContextFeedWrapper get(String feedURL) {
                // cast String to URL
                this.setFeedURL(feedURL);
                
                // rev up RomeFetcher
                FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance();
            FeedFetcher feedFetcher = new HttpURLFeedFetcher(feedInfoCache);
            
            // retrieve feed or freak out (silently!)
            try {
                // grab feed
                this.setFeed(feedFetcher.retrieveFeed(this.getFeedURL()));
            } catch (FetcherException fetchx) {
                // do something here?
            } catch (FeedException feedx) {
                // do something here?
            } catch (IOException iox) {
                // do something here?
            } catch (Exception x) {
                // do something here?
            }
            
            // return wrapped feed
                return this.getFeed();
        }
        
        /**
         * Returns the feed located at the specified (password protected) URL
         * @param feedURL the URL of the feed to retrieve
         * @param userName the userName to access the protected URL with
         * @param password the password to access the protected URL with
         * @return feed the feed object inside a utility wrapper class
         */
        public ContextFeedWrapper get(String feedURL, String userName, String password) {
                // set feed url
                this.setFeedURL(feedURL);
                
                // construct auth string
                String auth = userName + ":" + password;
                
                // initialize httpcon variable
                HttpURLConnection httpcon = null;
                
                try {
                        // create connection
                        httpcon = (HttpURLConnection) this.getFeedURL().openConnection();
                        
                        // encode username:password
                        String encoding = new BASE64Encoder().encode(auth.getBytes());
                        
                        // set request property
                        httpcon.setRequestProperty("Authorization","Basic " + encoding);
                        
                        // connect
                        httpcon.connect();
                } catch(IOException iox) {
                        // do something here?
                }
                
                // rev up Rome (not using fetcher this time)
                SyndFeedInput input = new SyndFeedInput();
                
                // grab and wrap feed
                try {
                        this.setFeed(input.build(new XmlReader(httpcon)));
                } catch(FeedException fx) {
                        // do something here?
                } catch(IOException iox) {
                        // do something here?
                }
                
                // if we have a connection, disconnect now
                if(httpcon != null) {
                        httpcon.disconnect();
                }
                
                // return wrapped feed
                return this.getFeed();
        }

        /**
         * @return Returns the feed.
         */
        public ContextFeedWrapper getFeed() {
                return this.feed;
        }

        /**
         * @param feed The feed to set.
         */
        public void setFeed(ContextFeedWrapper feed) {
                this.feed = feed;
        }
        
        /**
         * @param feed The feed to set
         */
        public void setFeed(SyndFeed feed) {
                this.setFeed(new ContextFeedWrapper(feed));
        }

        /**
         * @return Returns the feedURL.
         */
        public URL getFeedURL() {
                return feedURL;
        }

        /**
         * @param feedURL The feedURL to set.
         */
        public void setFeedURL(URL feedURL) {
                this.feedURL = feedURL;
        }
        
        /**
         * Private helper method to covert String to URL
         * @param url
         */
        public void setFeedURL(String url) {
                // try to cast URL string to URL
                try {
                        this.setFeedURL(new URL(url));
                } catch(MalformedURLException mfux) {
                        // do something here?
                } catch (Exception x) {
                        // do something here?
                }
        }
}

package org.apache.velocity.tools.view.tools;

import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndEntry;

/**
 * Feed wrapper for Velocity context providing
 * utility methods for accessing feed object properties
 * 
 * @author Christopher Townson
 *
 */
public class ContextFeedWrapper {
        
        /**
         * The feed
         */
        private SyndFeed feed;
        
        /**
         * An interger containing the total number of items in the retrieved feed
         */
        private int numberOfEntries;
        
        /**
         * A SyndEntry object for holding the most recent feed entry
         */
        private SyndEntry latest;
        
        /**
         * 
         * @param feed
         */
        public ContextFeedWrapper(SyndFeed feed) {
                // assign feed object
                this.setFeed(feed);
                
                // grab number of entries
                this.numberOfEntries = this.getFeed().getEntries().size();
                
                // grab most recent entry (presently: just first entry)
                // TODO make this loop through entries and compare dates
                this.latest = (SyndEntry) this.getFeed().getEntries().get(0);
        }
        
        /**
         * @return Returns the feed.
         */
        public SyndFeed getFeed() {
                return this.feed;
        }

        /**
         * @param feed The feed to set.
         */
        public void setFeed(SyndFeed feed) {
                this.feed = feed;
        }

        /**
         * @return Returns the numberOfEntries.
         */
        public int getNumberOfEntries() {
                return numberOfEntries;
        }

        /**
         * @param numberOfEntries The numberOfEntries to set.
         */
        public void setNumberOfEntries(int numberOfEntries) {
                this.numberOfEntries = numberOfEntries;
        }

        /**
         * @return Returns the latest feed entry.
         */
        public SyndEntry getLatest() {
                return latest;
        }

        /**
         * @param latest The entry to set as the latest
         */
        public void setLatest(SyndEntry latest) {
                this.latest = latest;
        }

}

<!-- FeedTool: for fetching, parsing, and otherwise handling syndicated feeds of any type -->
<tool>
    <key>FeedTool</key>
    <scope>request</scope>
    <class>com.nature.velocity.tools.view.tools.ViewFeedTool</class>
</tool>