File Source: newsfeedcache.java
/*
P/P * Method: net.sourceforge.pebble.aggregator.NewsFeedCache__static_init
*
* Postconditions:
* instance == &new NewsFeedCache(NewsFeedCache__static_init#1)
* init'ed(log)
* new HashMap(NewsFeedCache#1) num objects == 1
* new HashMap(NewsFeedCache#2) num objects == 1
* new HashMap(NewsFeedCache#3) num objects == 1
* new NewsFeedCache(NewsFeedCache__static_init#1) num objects == 1
* instance.entries == &new HashMap(NewsFeedCache#3)
* instance.feeds == &new HashMap(NewsFeedCache#2)
* instance.subscriptions == &new HashMap(NewsFeedCache#1)
*/
1 /*
2 * Copyright (c) 2003-2006, Simon Brown
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * - Neither the name of Pebble nor the names of its contributors may
17 * be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32 package net.sourceforge.pebble.aggregator;
33
/*
P/P * Method: void net.sourceforge.pebble.aggregator.NewsFeedCache()
*
* Postconditions:
* this.entries == &new HashMap(NewsFeedCache#3)
* this.feeds == &new HashMap(NewsFeedCache#2)
* this.subscriptions == &new HashMap(NewsFeedCache#1)
* new HashMap(NewsFeedCache#1) num objects == 1
* new HashMap(NewsFeedCache#2) num objects == 1
* new HashMap(NewsFeedCache#3) num objects == 1
*/
34 import com.sun.syndication.feed.WireFeed;
35 import com.sun.syndication.feed.atom.Content;
36 import com.sun.syndication.feed.atom.Entry;
37 import com.sun.syndication.feed.atom.Link;
38 import com.sun.syndication.feed.rss.Channel;
39 import com.sun.syndication.feed.rss.Item;
40 import com.sun.syndication.io.FeedException;
41 import com.sun.syndication.io.WireFeedInput;
42 import com.sun.syndication.io.XmlReader;
43 import net.sourceforge.pebble.domain.Blog;
44 import org.apache.commons.logging.Log;
45 import org.apache.commons.logging.LogFactory;
46
47 import java.io.IOException;
48 import java.net.URL;
49 import java.util.*;
50
51 /**
52 * A cache of newsfeed subscriptions and their entries.
53 *
54 * @author Simon Brown
55 */
56 public class NewsFeedCache {
57
58 private static final int FEED_ENTRY_LIMIT = 20;
59
60 private static final Log log = LogFactory.getLog(NewsFeedCache.class);
61 private static final NewsFeedCache instance = new NewsFeedCache();
62
63 private final Map<String,Set<String>> subscriptions = new HashMap<String,Set<String>>();
64 private final Map<String, NewsFeed> feeds = new HashMap<String, NewsFeed>();
65 private final Map<String,List<NewsFeedEntry>> entries = new HashMap<String,List<NewsFeedEntry>>();
66
67 private NewsFeedCache() {
68 }
69
/*
P/P * Method: NewsFeedCache getInstance()
*
* Postconditions:
* return_value == &new NewsFeedCache(NewsFeedCache__static_init#1)
*/
70 public static NewsFeedCache getInstance() {
71 return instance;
72 }
73
/*
P/P * Method: void addSubscription(Blog, String)
*
* Preconditions:
* blog != null
* init'ed(blog.id)
* this.feeds != null
* this.subscriptions != null
*/
74 public void addSubscription(Blog blog, String url) {
75 synchronized (feeds) {
76 Set<String> urls = getUrls(blog.getId());
77 urls.add(url);
78
79 NewsFeed feed = feeds.get(url);
80 if (feed == null) {
81 feed = updateFeed(url);
82 feeds.put(url, feed);
83 }
84 }
85 }
86
/*
P/P * Method: void removeAllSubscriptions(Blog)
*
* Preconditions:
* blog != null
* init'ed(blog.id)
* this.subscriptions != null
*/
87 public void removeAllSubscriptions(Blog blog) {
88 synchronized (feeds) {
89 Set<String> urls = getUrls(blog.getId());
90 urls.clear();
91 }
92 }
93
/*
P/P * Method: void refreshFeeds()
*
* Preconditions:
* this.feeds != null
* this.subscriptions != null
* (soft) this.entries != null
*
* Presumptions:
* java.util.Map:get(...)@109 != null
* java.util.Map:keySet(...)@106 != null
* java.util.Map:keySet(...)@95 != null
* org.apache.commons.logging.LogFactory:getLog(...)@60 != null
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@106: {1}, {0}
* java.util.Iterator:hasNext(...)@108: {1}, {0}
* java.util.Iterator:hasNext(...)@95: {1}, {0}
* java.util.List:size(...)@114: {-231..20}, {21..232-1}
*/
94 public void refreshFeeds() {
95 for (String url : feeds.keySet()) {
96 try {
97 NewsFeed updatedFeed = updateFeed(url);
98 synchronized (feeds) {
99 feeds.put(url, updatedFeed);
100 }
101 } catch (Exception e) {
102 log.warn("Couldn't update feed from " + url, e);
103 }
104 }
105
106 for (String blogId : subscriptions.keySet()) {
107 List<NewsFeedEntry> entriesForBlog = new LinkedList<NewsFeedEntry>();
108 for (String url : getUrls(blogId)) {
109 entriesForBlog.addAll(feeds.get(url).getEntries());
110 }
111
112 Collections.sort(entriesForBlog, new NewsFeedEntryComparator());
113
114 if (entriesForBlog.size() > FEED_ENTRY_LIMIT) {
115 entriesForBlog = entriesForBlog.subList(0, FEED_ENTRY_LIMIT);
116 }
117
118 entries.put(blogId, entriesForBlog);
119 }
120 }
121
122 private NewsFeed updateFeed(String url) {
123 NewsFeed feed = new NewsFeed(url);
124
125 try {
126 log.debug("Refreshing feed from " + url);
127
128 // SyndFeedInput input = new SyndFeedInput(true);
129 // SyndFeed sf = input.build(new XmlReader(new URL(url)));
130 //
131 // feed.setTitle(sf.getTitle());
132 // feed.setLink(sf.getLink());
133 //
134 // for (SyndEntry se : (List<SyndEntry>)sf.getEntries()) {
135 // log.info(se);
136 // NewsFeedEntry fe = new NewsFeedEntry(
137 // se.getLink(),
138 // se.getTitle(),
139 // se.getDescription() != null ? se.getDescription().getValue() : "",
140 // se.getAuthor(),
141 // se.getPublishedDate()
142 // );
143 // feed.add(fe);
144 // log.info(fe);
145 // }
146
/*
P/P * Method: NewsFeed updateFeed(String)
*
* Presumptions:
* com.sun.syndication.feed.WireFeed:getFeedType(...)@150 != null
* com.sun.syndication.feed.WireFeed:getFeedType(...)@165 != null
* com.sun.syndication.feed.atom.Entry:getAlternateLinks(...)@175 != null
* com.sun.syndication.feed.atom.Entry:getAuthors(...)@190 != null
* com.sun.syndication.feed.atom.Entry:getContents(...)@180 != null
* ...
*
* Postconditions:
* return_value == &new NewsFeed(updateFeed#1)
* new LinkedList(NewsFeed#1) num objects == 1
* new NewsFeed(updateFeed#1) num objects == 1
* return_value.entries == &new LinkedList(NewsFeed#1)
* init'ed(return_value.link)
* init'ed(return_value.timestamp)
* init'ed(return_value.title)
* return_value.url == url
* init'ed(return_value.url)
*
* Test Vectors:
* com.sun.syndication.feed.WireFeed:getFeedType(...)@150: Addr_Set{null}, Inverse{null}
* com.sun.syndication.feed.WireFeed:getFeedType(...)@165: Addr_Set{null}, Inverse{null}
* java.lang.String:equals(...)@169: {0}, {1}
* java.lang.String:equals(...)@176: {0}, {1}
* java.lang.String:equals(...)@181: {0}, {1}
* java.lang.String:equals(...)@186: {0}, {1}
* java.lang.String:startsWith(...)@150: {0}, {1}
* java.lang.String:startsWith(...)@165: {0}, {1}
* java.util.Iterator:hasNext(...)@168: {1}, {0}
* java.util.Iterator:hasNext(...)@173: {1}, {0}
* ...
*/
147 WireFeedInput input = new WireFeedInput(true);
148 WireFeed wf = input.build(new XmlReader(new URL(url)));
149
150 if (wf.getFeedType() != null && wf.getFeedType().startsWith("rss")) {
151 Channel rssFeed = (Channel)wf;
152 feed.setTitle(rssFeed.getTitle());
153 feed.setLink(rssFeed.getLink());
154
155 for (Item item : (List<Item>)rssFeed.getItems()) {
156 NewsFeedEntry fe = new NewsFeedEntry(
157 item.getLink(),
158 item.getTitle(),
159 item.getDescription() != null ? item.getDescription().getValue() : "",
160 item.getAuthor(),
161 item.getPubDate()
162 );
163 feed.add(fe);
164 }
165 } else if (wf.getFeedType() != null && wf.getFeedType().startsWith("atom")) {
166 com.sun.syndication.feed.atom.Feed atomFeed = (com.sun.syndication.feed.atom.Feed)wf;
167 feed.setTitle(atomFeed.getTitle());
168 for (Link link : (List<Link>)atomFeed.getAlternateLinks()) {
169 if ("text/html".equals(link.getType()))
170 feed.setLink(link.getHref());
171 }
172
173 for (Entry entry : (List<Entry>)atomFeed.getEntries()) {
174 String href = "";
175 for (Link link : (List<Link>)entry.getAlternateLinks()) {
176 if ("text/html".equals(link.getType()))
177 href = link.getHref();
178 }
179 String body = null;
180 for (Content content : (List<Content>)entry.getContents()) {
181 if ("html".equals(content.getType()))
182 body = content.getValue();
183 }
184 if (body == null) {
185 for (Content content : (List<Content>)entry.getSummary()) {
186 if ("html".equals(content.getType()))
187 body = content.getValue();
188 }
189 }
190 String author = entry.getAuthors() != null && entry.getAuthors().size() > 0 ? entry.getAuthors().get(0).toString() : "";
191 NewsFeedEntry fe = new NewsFeedEntry(
192 href,
193 entry.getTitle(),
194 body,
195 author,
196 entry.getPublished()
197 );
198 feed.add(fe);
199 }
200 }
201
202 log.debug("Refreshed feed from " + url);
203 } catch (FeedException e) {
204 log.warn("Error while updating feed from " + url, e);
205 } catch (IOException e) {
206 log.warn("Error while updating feed from " + url, e);
207 }
208
209 return feed;
210 }
211
/*
P/P * Method: NewsFeed getFeed(String)
*
* Preconditions:
* this.feeds != null
*
* Postconditions:
* init'ed(return_value)
*/
212 public NewsFeed getFeed(String url) {
213 return feeds.get(url);
214 }
215
/*
P/P * Method: List getNewsFeedEntries(Blog)
*
* Preconditions:
* blog != null
* init'ed(blog.id)
* this.entries != null
*
* Postconditions:
* return_value != null
* new LinkedList(getNewsFeedEntries#1) num objects <= 1
*
* Test Vectors:
* java.util.Map:get(...)@217: Inverse{null}, Addr_Set{null}
*/
216 public List<NewsFeedEntry> getNewsFeedEntries(Blog blog) {
217 List<NewsFeedEntry> list = entries.get(blog.getId());
218 if (list == null) {
219 list = new LinkedList<NewsFeedEntry>();
220 }
221
222 return list;
223 }
224
/*
P/P * Method: Set getUrls(String)
*
* Preconditions:
* this.subscriptions != null
*
* Postconditions:
* return_value != null
* new HashSet(getUrls#1) num objects <= 1
*
* Test Vectors:
* java.util.Map:get(...)@226: Inverse{null}, Addr_Set{null}
*/
225 private Set<String> getUrls(String blogId) {
226 Set<String> urls = subscriptions.get(blogId);
227 if (urls == null) {
228 urls = new HashSet<String>();
229 subscriptions.put(blogId, urls);
230 }
231
232 return urls;
233 }
234
235 }
SofCheck Inspector Build Version : 2.22510
| newsfeedcache.java |
2010-Jun-25 19:40:32 |
| newsfeedcache.class |
2010-Jul-19 20:23:40 |