/*==========================================================================*\
| $Id: RssFeed.java,v 1.4 2011/03/07 14:08:04 stedwar2 Exp $
|*-------------------------------------------------------------------------*|
| Copyright (C) 2007-2011 Virginia Tech
|
| This file is part of the Student-Library.
|
| The Student-Library is free software; you can redistribute it and/or
| modify it under the terms of the GNU Lesser General Public License as
| published by the Free Software Foundation; either version 3 of the
| License, or (at your option) any later version.
|
| The Student-Library is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU Lesser General Public License for more details.
|
| You should have received a copy of the GNU Lesser General Public License
| along with the Student-Library; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/
package student.web;
import static student.testingsupport.SystemIOUtilities.isOnServer;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.io.SyndFeedInput;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
//-------------------------------------------------------------------------
/**
* This class represents a syndication feed that contains a list of
* {@link RssEntry} objects.
*
* @author Stephen Edwards
* @author Last changed by $Author: stedwar2 $
* @version $Revision: 1.4 $, $Date: 2011/03/07 14:08:04 $
*/
public class RssFeed
implements RssEntity, Serializable, Cloneable
{
//~ Instance/static variables .............................................
private static final long serialVersionUID = -660537505655423375L;
private URL loadedFrom;
/** The raw ROME feed. */
protected SyndFeed nativeFeed;
/** The list of entries. */
protected List<RssEntry> entries;
/** The feed's link URL (set lazily in {@link #getLink()}. */
protected URL feedLink;
/** The feed's image URL (set lazily in {@link #getImageLink()}. */
protected URL imageLink;
/** The feed site's favicon URL (set lazily in {@link #getIconLink()}. */
protected URL iconLink;
//~ Constructor ...........................................................
// ----------------------------------------------------------
/**
* Creates a new RssFeed object that is completely empty.
*/
public RssFeed()
{
this(new SyndFeedImpl());
}
// ----------------------------------------------------------
/**
* Creates a new RssFeed object by reading from the given URL.
* @param url The URL to read from, as a string
*/
public RssFeed(String url)
{
this(readFeed(url));
try
{
loadedFrom = new URL(url);
}
catch (MalformedURLException e)
{
throw new RuntimeException(e);
}
}
// ----------------------------------------------------------
/**
* Creates a new RssFeed object by reading from the given URL.
* @param url The URL to read from, as a string
*/
public RssFeed(URL url)
{
this(readFeed(url));
loadedFrom = url;
}
// ----------------------------------------------------------
/**
* Creates a new RssFeed object by copying from an existing one.
* Subclasses should override this constructor if they add their
* own data, so that their internal subclass data gets initialized
* properly.
* @param existingFeed The feed to copy
*/
public RssFeed(RssFeed existingFeed)
{
this(existingFeed.nativeFeed);
}
// ----------------------------------------------------------
/**
* Creates a new RssFeed object from an existing ROME feed.
* @param feed The ROME feed to wrap
*/
RssFeed(SyndFeed feed)
{
nativeFeed = feed;
if (feed == null)
{
nativeFeed = new SyndFeedImpl();
}
}
//~ Public Methods ........................................................
// ----------------------------------------------------------
/**
* Get this feed's author. If there are multiple authors,
* this method returns the first one.
* @return This feed's author
*/
public String getAuthor()
{
return nativeFeed.getAuthor();
}
// ----------------------------------------------------------
/**
* Set this feed's author.
* @param author This feed's author
*/
public void setAuthor(String author)
{
nativeFeed.setAuthor(author);
}
// ----------------------------------------------------------
/**
* Get this feed's authors.
* @return This feed's authors
*/
@SuppressWarnings("unchecked")
public List<String> getAuthors()
{
return nativeFeed.getAuthors();
}
// ----------------------------------------------------------
/**
* Set this feed's authors.
* @param authors A list of this feed's authors
*/
public void setAuthors(List<String> authors)
{
nativeFeed.setAuthors(authors);
}
// ----------------------------------------------------------
/**
* Get this feed's publication date.
* @return This feed's date
*/
public Date getDate()
{
return nativeFeed.getPublishedDate();
}
// ----------------------------------------------------------
/**
* Set this feed's publication date.
* @param date This feed's date
*/
public void setDate(Date date)
{
nativeFeed.setPublishedDate(date);
}
// ----------------------------------------------------------
/**
* Get this feed's description.
* @return This feed's description
*/
public String getDescription()
{
return nativeFeed.getDescription();
}
// ----------------------------------------------------------
/**
* Set this feed's description.
* @param description The new description
*/
public void setDescription(String description)
{
nativeFeed.setDescription(description);
}
// ----------------------------------------------------------
/**
* Get this feed's entries.
* @return This feed's entries
*/
public List<RssEntry> getEntries()
{
if (entries == null)
{
convertEntryList();
}
return entries;
}
// ----------------------------------------------------------
/**
* Add a new entry to this feed.
* @param entry The new entry to add
*/
@SuppressWarnings("unchecked")
public void addEntry(RssEntry entry)
{
List<RssEntry> myEntries = getEntries();
if (myEntries == null)
{
myEntries = new ArrayList<RssEntry>();
myEntries.add(entry);
setEntries(myEntries);
}
else
{
myEntries.add(entry);
nativeFeed.getEntries().add(entry.nativeEntry);
}
}
// ----------------------------------------------------------
/**
* Set this feed's entries.
* @param entries This feed's entries
*/
@SuppressWarnings("unchecked")
public void setEntries(List<RssEntry> entries)
{
this.entries = entries;
if (nativeFeed.getEntries() == null)
{
nativeFeed.setEntries(new ArrayList<SyndEntry>(entries.size()));
}
List<SyndEntry> nativeEntries = nativeFeed.getEntries();
for (RssEntry entry : entries)
{
nativeEntries.add(entry.nativeEntry);
}
}
// ----------------------------------------------------------
/**
* Get the link for the site icon belonging to this feed's home site.
* This icon is often used in browsers and so on to identify the
* feed's site.
* @return The feed's icon URL, which points to the home site's
* "favicon.ico" icon (which may not even exist, of course)
*/
public URL getIconLink()
{
if (iconLink == null)
{
URL link = getLink();
if (link != null)
{
try
{
iconLink = new URL(link, "/favicon.ico");
}
catch (MalformedURLException e)
{
if (!isOnServer())
{
e.printStackTrace();
}
}
}
}
return iconLink;
}
// ----------------------------------------------------------
/**
* Set the link for the site icon belonging to this feed's home site.
* @param link The new URL to use
*/
public void setIconLink(URL link)
{
iconLink = link;
}
// ----------------------------------------------------------
/**
* Get the link for this feed's image as a URL.
* @return The feed's image URL, or null if there is none
*/
public URL getImageLink()
{
if (imageLink == null)
{
String link = nativeFeed.getImage().getUrl();
if (link != null)
{
try
{
imageLink = new URL(link);
}
catch (MalformedURLException e)
{
if (!isOnServer())
{
e.printStackTrace();
}
}
}
}
return imageLink;
}
// ----------------------------------------------------------
/**
* Set this link for this feed's image.
* @param link The new URL to use
*/
public void setImageLink(URL link)
{
imageLink = link;
nativeFeed.getImage().setUrl(link == null ? null : link.toString());
}
// ----------------------------------------------------------
/**
* Get the link as a URL where this feed was loaded from.
* @return The link's URL, or null if there is none
*/
public URL getLoadedFromLink()
{
return loadedFrom;
}
// ----------------------------------------------------------
/**
* Set the value this feed believes it was loaded from (normally
* set by the constructor).
* @param link The new URL to use
*/
public void setLoadedFromLink(URL link)
{
loadedFrom = link;
}
// ----------------------------------------------------------
/**
* Get the link (as a URL) where this feed is officially published.
* @return The link's URL, or null if there is none
*/
public URL getLink()
{
if (feedLink == null)
{
String link = nativeFeed.getLink();
if (link != null)
{
try
{
feedLink = new URL(link);
}
catch (MalformedURLException e)
{
if (!isOnServer())
{
e.printStackTrace();
}
}
}
}
return feedLink;
}
// ----------------------------------------------------------
/**
* Set this feed's publication link.
* @param link The new URL to use
*/
public void setLink(URL link)
{
feedLink = link;
nativeFeed.setLink(link == null ? null : link.toString());
}
// ----------------------------------------------------------
/**
* Get this feed's title.
* @return The feed's title
*/
public String getTitle()
{
return nativeFeed.getTitle();
}
// ----------------------------------------------------------
/**
* Set this feed's title.
* @param title The feed's title
*/
public void setTitle(String title)
{
nativeFeed.setTitle(title);
}
// ----------------------------------------------------------
/**
* Clone this object.
* @return a copy of this object
*/
public Object clone()
{
try
{
return new RssFeed((SyndFeed)nativeFeed.clone());
}
catch (CloneNotSupportedException e)
{
throw new RuntimeException(e);
}
}
// ----------------------------------------------------------
/**
* Generate a printable version of this feed.
* @return the string representation of this object
*/
public String toString()
{
return nativeFeed.toString();
}
//~ Protected Methods .....................................................
// ----------------------------------------------------------
/**
* Convert the native ROME feed's list of entities into a proper
* list of wrapped {@link RssEntry} objects, and store the result
* in the {@link #entries} field. If the native feed
* is null, this method leaves the entries field null as well.
*/
protected void convertEntryList()
{
List<RssEntry> result = null;
List<?> nativeEntries = nativeFeed.getEntries();
if (nativeEntries != null)
{
result = new ArrayList<RssEntry>(nativeEntries.size());
for (Object entry : nativeEntries)
{
result.add(new RssEntry((SyndEntry)entry));
}
}
entries = result;
}
// ----------------------------------------------------------
/**
* Create a ROME feed by reading from the given URL.
* @param url The feed URL to read from
* @return the corresponding ROME feed
*/
protected static SyndFeed readFeed(String url)
{
try
{
return readFeed(new URL(url));
}
catch (MalformedURLException e)
{
throw new RuntimeException(e);
}
}
// ----------------------------------------------------------
/**
* Create a ROME feed by reading from the given URL.
* @param url The feed URL to read from
* @return the corresponding ROME feed
*/
protected static SyndFeed readFeed(URL url)
{
SyndFeed feed = null;
try
{
SyndFeedInput input = new SyndFeedInput();
// URLConnection connection = url.openConnection();
// connection.setRequestProperty("User-Agent", USER_AGENT);
// feed = input.build(new XmlReader(connection));
feed = input.build(new java.io.StringReader(
student.web.internal.WebContent.get(url)));
}
catch (IllegalArgumentException e)
{
if (!student.testingsupport.SystemIOUtilities.isOnServer())
{
System.out.println("RSS feed type unrecognized: "
+ e.getMessage());
e.printStackTrace();
}
}
// catch (IOException e)
// {
// if (!net.sf.webcat.SystemIOUtilities.isOnServer())
// {
// System.out.println("Failed to connect to RSS site: "
// + e.getMessage());
// e.printStackTrace();
// }
// }
catch (Exception e)
{
if (!student.testingsupport.SystemIOUtilities.isOnServer())
{
System.out.println("Failed readding RSS: " + e.getMessage());
e.printStackTrace();
}
}
if (feed == null)
{
feed = new SyndFeedImpl();
}
return feed;
}
}