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