newsfeedcache.java

### 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