Clover Coverage Report - Pebble 2.5-SNAPSHOT
Coverage timestamp: Sat Jun 12 2010 09:39:29 EST
../../../../img/srcFileCovDistChart0.png 48% of files have more coverage
73   235   28   8,11
26   150   0,38   9
9     3,11  
1    
This report was generated with an evaluation server license. Purchase Clover or configure your license.
 
  NewsFeedCache       Line # 56 73 0% 28 108 0% 0.0
 
No Tests
 
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   
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  0 toggle private NewsFeedCache() {
68    }
69   
 
70  0 toggle public static NewsFeedCache getInstance() {
71  0 return instance;
72    }
73   
 
74  0 toggle public void addSubscription(Blog blog, String url) {
75  0 synchronized (feeds) {
76  0 Set<String> urls = getUrls(blog.getId());
77  0 urls.add(url);
78   
79  0 NewsFeed feed = feeds.get(url);
80  0 if (feed == null) {
81  0 feed = updateFeed(url);
82  0 feeds.put(url, feed);
83    }
84    }
85    }
86   
 
87  0 toggle public void removeAllSubscriptions(Blog blog) {
88  0 synchronized (feeds) {
89  0 Set<String> urls = getUrls(blog.getId());
90  0 urls.clear();
91    }
92    }
93   
 
94  0 toggle public void refreshFeeds() {
95  0 for (String url : feeds.keySet()) {
96  0 try {
97  0 NewsFeed updatedFeed = updateFeed(url);
98  0 synchronized (feeds) {
99  0 feeds.put(url, updatedFeed);
100    }
101    } catch (Exception e) {
102  0 log.warn("Couldn't update feed from " + url, e);
103    }
104    }
105   
106  0 for (String blogId : subscriptions.keySet()) {
107  0 List<NewsFeedEntry> entriesForBlog = new LinkedList<NewsFeedEntry>();
108  0 for (String url : getUrls(blogId)) {
109  0 entriesForBlog.addAll(feeds.get(url).getEntries());
110    }
111   
112  0 Collections.sort(entriesForBlog, new NewsFeedEntryComparator());
113   
114  0 if (entriesForBlog.size() > FEED_ENTRY_LIMIT) {
115  0 entriesForBlog = entriesForBlog.subList(0, FEED_ENTRY_LIMIT);
116    }
117   
118  0 entries.put(blogId, entriesForBlog);
119    }
120    }
121   
 
122  0 toggle private NewsFeed updateFeed(String url) {
123  0 NewsFeed feed = new NewsFeed(url);
124   
125  0 try {
126  0 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   
147  0 WireFeedInput input = new WireFeedInput(true);
148  0 WireFeed wf = input.build(new XmlReader(new URL(url)));
149   
150  0 if (wf.getFeedType() != null && wf.getFeedType().startsWith("rss")) {
151  0 Channel rssFeed = (Channel)wf;
152  0 feed.setTitle(rssFeed.getTitle());
153  0 feed.setLink(rssFeed.getLink());
154   
155  0 for (Item item : (List<Item>)rssFeed.getItems()) {
156  0 NewsFeedEntry fe = new NewsFeedEntry(
157    item.getLink(),
158    item.getTitle(),
159  0 item.getDescription() != null ? item.getDescription().getValue() : "",
160    item.getAuthor(),
161    item.getPubDate()
162    );
163  0 feed.add(fe);
164    }
165  0 } else if (wf.getFeedType() != null && wf.getFeedType().startsWith("atom")) {
166  0 com.sun.syndication.feed.atom.Feed atomFeed = (com.sun.syndication.feed.atom.Feed)wf;
167  0 feed.setTitle(atomFeed.getTitle());
168  0 for (Link link : (List<Link>)atomFeed.getAlternateLinks()) {
169  0 if ("text/html".equals(link.getType()))
170  0 feed.setLink(link.getHref());
171    }
172   
173  0 for (Entry entry : (List<Entry>)atomFeed.getEntries()) {
174  0 String href = "";
175  0 for (Link link : (List<Link>)entry.getAlternateLinks()) {
176  0 if ("text/html".equals(link.getType()))
177  0 href = link.getHref();
178    }
179  0 String body = null;
180  0 for (Content content : (List<Content>)entry.getContents()) {
181  0 if ("html".equals(content.getType()))
182  0 body = content.getValue();
183    }
184  0 if (body == null) {
185  0 for (Content content : (List<Content>)entry.getSummary()) {
186  0 if ("html".equals(content.getType()))
187  0 body = content.getValue();
188    }
189    }
190  0 String author = entry.getAuthors() != null && entry.getAuthors().size() > 0 ? entry.getAuthors().get(0).toString() : "";
191  0 NewsFeedEntry fe = new NewsFeedEntry(
192    href,
193    entry.getTitle(),
194    body,
195    author,
196    entry.getPublished()
197    );
198  0 feed.add(fe);
199    }
200    }
201   
202  0 log.debug("Refreshed feed from " + url);
203    } catch (FeedException e) {
204  0 log.warn("Error while updating feed from " + url, e);
205    } catch (IOException e) {
206  0 log.warn("Error while updating feed from " + url, e);
207    }
208   
209  0 return feed;
210    }
211   
 
212  0 toggle public NewsFeed getFeed(String url) {
213  0 return feeds.get(url);
214    }
215   
 
216  0 toggle public List<NewsFeedEntry> getNewsFeedEntries(Blog blog) {
217  0 List<NewsFeedEntry> list = entries.get(blog.getId());
218  0 if (list == null) {
219  0 list = new LinkedList<NewsFeedEntry>();
220    }
221   
222  0 return list;
223    }
224   
 
225  0 toggle private Set<String> getUrls(String blogId) {
226  0 Set<String> urls = subscriptions.get(blogId);
227  0 if (urls == null) {
228  0 urls = new HashSet<String>();
229  0 subscriptions.put(blogId, urls);
230    }
231   
232  0 return urls;
233    }
234   
235    }