/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
*
* Sun Microsystems, Inc. has intellectual property rights relating to
* technology embodied in the product that is described in this document.
* In particular, and without limitation, these intellectual property
* rights may include one or more of the U.S. patents listed at
* http://www.sun.com/patents and one or more additional patents or
* pending patent applications in the U.S. and in other countries.
*
* U.S. Government Rights - Commercial software. Government users are subject
* to the Sun Microsystems, Inc. standard license agreement and applicable
* provisions of the FAR and its supplements. Use is subject to license terms.
* This distribution may include materials developed by third parties.
* Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered
* trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
*/
package com.sun.portal.rssportlet;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.xml.sax.InputSource;
/**
* This class manages a cache of ROME feeds.
*/
public class FeedHelper {
// singleton instance
private static FeedHelper feedHelper = new FeedHelper();
//
// sync the map, not the method.
// if the method is sync'd, we end up spinning whenever a feed host
// fails to respond. with the map sync'd, we still may fetch
// feeds twice under some extreme race condition, but that is
// very unlikely and will not cause data corruption.
//
private Map feeds = Collections.synchronizedMap(new HashMap());
/**
* This class is the cached representation of a ROME feed.
*/
private static final class FeedElement {
private SyndFeed feed = null;
private long cacheTime;
private long timeout;
public FeedElement(SyndFeed feed, int timeout) {
this.feed = feed;
this.cacheTime = System.currentTimeMillis();
this.timeout = timeout * 1000;
}
public SyndFeed getFeed() {
return feed;
}
public boolean isExpired() {
// negative timeout means that the cached element never expires
if (timeout < 0) {
return false;
}
// otherwise, is the time cached plus the timeout still
// less than the current time? if so, then the cache
// has not expired
if ((cacheTime + timeout) < System.currentTimeMillis()) {
return true;
}
return false;
}
}
private FeedHelper() {
// nothing, cannot be called
}
/**
* Get the feed handler singleton instance.
*/
public static FeedHelper getInstance() {
return feedHelper;
}
/**
* Get the ROME SyndFeed object for the specified feed. The object may come
* from a cache; the data in the feed may not be read at the time
* this method is called.
*
* The <code>RssPortletBean</code> object is used to identify the feed
* of interest, and the timeout value to be used when managing this
* feed's cached value.
*
* @param bean an <code>RssPortletBean</code> object that describes
* the feed of interest, and the cache timeout value for the feed.
* @return a ROME <code>SyndFeed</code> object encapsulating the
* feed specified by the URL.
*/
public SyndFeed getFeed(SettingsBean bean, String selectedFeed) throws IOException, FeedException {
SyndFeed feed = null;
FeedElement feedElement = (FeedElement)feeds.get(selectedFeed);
if (feedElement != null && !feedElement.isExpired()) {
feed = feedElement.getFeed();
} else {
URL feedUrl = new URL(selectedFeed);
URLConnection urlc = feedUrl.openConnection();
urlc.connect();
SyndFeedInput input = new SyndFeedInput();
InputSource src = new InputSource(urlc.getInputStream());
feed = input.build(src);
//
// only cache the feed if the cache timeout is not equal to 0
// a cache timeout of 0 means "don't cache"
//
int timeout = bean.getCacheTimeout();
if (timeout != 0) {
putFeed(selectedFeed, feed, timeout);
}
}
return feed;
}
/**
* Get the ROME SyndFeed object for the feed specified by the
* SettingsBean's selectedFeed field.
*/
public SyndFeed getFeed(SettingsBean bean) throws IOException, FeedException {
return getFeed(bean, bean.getSelectedFeed());
}
/**
* Put a ROME feed into the cache.
* This method must be called from within a synchronzied block.
*/
private void putFeed(String url, SyndFeed feed, int timeout) {
FeedElement feedElement = new FeedElement(feed, timeout);
feeds.put(url, feedElement);
}
}
|