001: /*
002: * Copyright © 2006 Sun Microsystems, Inc. All rights reserved.
003: *
004: * Sun Microsystems, Inc. has intellectual property rights relating to
005: * technology embodied in the product that is described in this document.
006: * In particular, and without limitation, these intellectual property
007: * rights may include one or more of the U.S. patents listed at
008: * http://www.sun.com/patents and one or more additional patents or
009: * pending patent applications in the U.S. and in other countries.
010: *
011: * U.S. Government Rights - Commercial software. Government users are subject
012: * to the Sun Microsystems, Inc. standard license agreement and applicable
013: * provisions of the FAR and its supplements. Use is subject to license terms.
014: * This distribution may include materials developed by third parties.
015: * Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered
016: * trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
017: */
018: package com.sun.portal.rssportlet;
019:
020: import com.sun.syndication.feed.synd.SyndFeed;
021: import com.sun.syndication.io.FeedException;
022: import com.sun.syndication.io.SyndFeedInput;
023: import java.io.IOException;
024: import java.net.URL;
025: import java.net.URLConnection;
026: import java.util.Collections;
027: import java.util.HashMap;
028: import java.util.Map;
029: import org.xml.sax.InputSource;
030:
031: /**
032: * This class manages a cache of ROME feeds.
033: */
034: public class FeedHelper {
035: // singleton instance
036: private static FeedHelper feedHelper = new FeedHelper();
037:
038: //
039: // sync the map, not the method.
040: // if the method is sync'd, we end up spinning whenever a feed host
041: // fails to respond. with the map sync'd, we still may fetch
042: // feeds twice under some extreme race condition, but that is
043: // very unlikely and will not cause data corruption.
044: //
045: private Map feeds = Collections.synchronizedMap(new HashMap());
046:
047: /**
048: * This class is the cached representation of a ROME feed.
049: */
050: private static final class FeedElement {
051: private SyndFeed feed = null;
052: private long cacheTime;
053: private long timeout;
054:
055: public FeedElement(SyndFeed feed, int timeout) {
056: this .feed = feed;
057: this .cacheTime = System.currentTimeMillis();
058: this .timeout = timeout * 1000;
059: }
060:
061: public SyndFeed getFeed() {
062: return feed;
063: }
064:
065: public boolean isExpired() {
066: // negative timeout means that the cached element never expires
067: if (timeout < 0) {
068: return false;
069: }
070:
071: // otherwise, is the time cached plus the timeout still
072: // less than the current time? if so, then the cache
073: // has not expired
074: if ((cacheTime + timeout) < System.currentTimeMillis()) {
075: return true;
076: }
077:
078: return false;
079: }
080: }
081:
082: private FeedHelper() {
083: // nothing, cannot be called
084: }
085:
086: /**
087: * Get the feed handler singleton instance.
088: */
089: public static FeedHelper getInstance() {
090: return feedHelper;
091: }
092:
093: /**
094: * Get the ROME SyndFeed object for the specified feed. The object may come
095: * from a cache; the data in the feed may not be read at the time
096: * this method is called.
097: *
098: * The <code>RssPortletBean</code> object is used to identify the feed
099: * of interest, and the timeout value to be used when managing this
100: * feed's cached value.
101: *
102: * @param bean an <code>RssPortletBean</code> object that describes
103: * the feed of interest, and the cache timeout value for the feed.
104: * @return a ROME <code>SyndFeed</code> object encapsulating the
105: * feed specified by the URL.
106: */
107: public SyndFeed getFeed(SettingsBean bean, String selectedFeed)
108: throws IOException, FeedException {
109: SyndFeed feed = null;
110: FeedElement feedElement = (FeedElement) feeds.get(selectedFeed);
111:
112: if (feedElement != null && !feedElement.isExpired()) {
113: feed = feedElement.getFeed();
114: } else {
115: URL feedUrl = new URL(selectedFeed);
116: URLConnection urlc = feedUrl.openConnection();
117: urlc.connect();
118: SyndFeedInput input = new SyndFeedInput();
119: InputSource src = new InputSource(urlc.getInputStream());
120: feed = input.build(src);
121:
122: //
123: // only cache the feed if the cache timeout is not equal to 0
124: // a cache timeout of 0 means "don't cache"
125: //
126: int timeout = bean.getCacheTimeout();
127: if (timeout != 0) {
128: putFeed(selectedFeed, feed, timeout);
129: }
130: }
131:
132: return feed;
133: }
134:
135: /**
136: * Get the ROME SyndFeed object for the feed specified by the
137: * SettingsBean's selectedFeed field.
138: */
139: public SyndFeed getFeed(SettingsBean bean) throws IOException,
140: FeedException {
141: return getFeed(bean, bean.getSelectedFeed());
142: }
143:
144: /**
145: * Put a ROME feed into the cache.
146: * This method must be called from within a synchronzied block.
147: */
148: private void putFeed(String url, SyndFeed feed, int timeout) {
149: FeedElement feedElement = new FeedElement(feed, timeout);
150: feeds.put(url, feedElement);
151: }
152: }
|