core/com.nokia.carbide.cpp.news.reader/src/com/nokia/carbide/cpp/internal/news/reader/feed/FeedManager.java
Changes to remote connections
add javadoc to IConnectionsManager + IConnectionTypeProvider
deprecate internal methods and don't use them internally from interface
add new interfaces and methods to support host PnP
/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.carbide.cpp.internal.news.reader.feed;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.osgi.service.datalocation.Location;
import com.nokia.carbide.cpp.internal.news.reader.CarbideNewsReaderPlugin;
import com.nokia.carbide.cpp.internal.news.reader.gen.FeedCache.FeedCacheManager;
import com.nokia.carbide.cpp.internal.news.reader.gen.FeedInfo.FeedInfoConstants;
import com.nokia.carbide.cpp.internal.news.reader.gen.FeedInfo.FeedInfoManager;
import com.nokia.carbide.cpp.internal.news.reader.gen.FeedInfo.FeedType;
import com.nokia.carbide.cpp.internal.news.reader.ui.NewsPreferenceConstants;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.fetcher.FeedFetcher;
import com.sun.syndication.fetcher.impl.FeedFetcherCache;
import com.sun.syndication.fetcher.impl.HashMapFeedInfoCache;
/**
* A class to manage feeds for the Carbide.c++ news reader.
*
*/
public class FeedManager {
// public data
public static final String FEED_CACHE_FILE_NAME = "carbide.c++.news.xml";
public static final String PROPERTIES_FILE_LOCATION = "configuration/server.properties";
// private data
private FeedCacheManager feedCacheManager;
private FeedInfoManager feedListingManager;
private List<CarbideSyndFeed> newsFeeds;
private CarbideSyndFeed resourceFeed;
private Timer updateTimer;
/**
* Private class to handle scheduled feeds updates.
*
*/
private class UpdateTimerTask extends TimerTask {
/*
* (non-Javadoc)
* @see java.util.TimerTask#run()
*/
public void run(){
CarbideNewsReaderPlugin.updateFeeds();
}
}
/**
* The constructor.
*/
public FeedManager() {
feedCacheManager = new FeedCacheManager();
feedListingManager = new FeedInfoManager();
newsFeeds = new ArrayList<CarbideSyndFeed>();
}
public boolean isCacheEmpty() {
return feedCacheManager.isCacheEmpty();
}
/**
* Load feeds listed in the news feeds listing file.
*/
@SuppressWarnings("static-access")
public void loadFeeds() {
try {
if (!loadFeedListing(false)) {
return;
}
if (feedCacheManager.isCacheEmpty()) {
loadFeedCache();
}
clearFeeds();
updateCache();
feedCacheManager.fireFeedCacheChanged(feedCacheManager.isCacheUpdated());
feedCacheManager.setCacheUpdated(false);
} catch (Exception e) {
CarbideNewsReaderPlugin.log(e);
}
}
/**
* Retrieve all the currently available news feeds.
* @return list of feed objects
*/
public List<CarbideSyndFeed> getNewsFeeds() {
validateFeeds();
return newsFeeds;
}
/**
* Retrieve a property string from the news reader properties file.
* @param key - key used to identify the property string
* @return property string if found; null otherwise
*/
public String getProperty(String key) {
try {
Location installLocation = Platform.getInstallLocation();
if (installLocation == null) {
return null;
}
URL url = installLocation.getURL();
if (url == null) {
return null;
}
IPath path = new Path(url.getPath());
path = path.append(PROPERTIES_FILE_LOCATION);
File file = path.toFile();
InputStream is = new FileInputStream(file);
Properties properties = new Properties();
properties.load(is);
is.close();
String result = (String)properties.get(key);
return result;
} catch (Exception e) {
CarbideNewsReaderPlugin.log(e);
}
return null;
}
/**
* Retrieve the resource feed.
* @return resource feed object
*/
public CarbideSyndFeed getResourceFeed() {
validateFeeds();
return resourceFeed;
}
public List<CarbideSyndFeed> getSubscribedNewsFeeds() {
validateFeeds();
List<CarbideSyndFeed> subscribedFeeds = new ArrayList<CarbideSyndFeed>();
for (Iterator<CarbideSyndFeed> iterator = newsFeeds.iterator(); iterator.hasNext();) {
CarbideSyndFeed feed = iterator.next();
if (feed.isSubscribed()) {
subscribedFeeds.add(feed);
}
}
return subscribedFeeds;
}
/**
* Return the total number of unread entries from subscribed news feeds.
* @return total number of unread entries from subscribed news feeds
*/
public int getUnreadEntriesCount() {
int count = 0;
for (Iterator<CarbideSyndFeed> iterator = newsFeeds.iterator(); iterator.hasNext();) {
CarbideSyndFeed feed = iterator.next();
if (feed.isSubscribed()) {
count += feed.getUnreadEntries().size();
}
}
return count;
}
/**
* Search for a feed entry by name and then mark it as read.
* @param entries - feed entries to be checked
* @param entryTitle - title of the entry to be marked as read
*/
public void markEntryAsRead(List<CarbideSyndEntry> entries, String entryTitle) {
if (entries == null || entryTitle == null) {
return;
}
for (Iterator<CarbideSyndEntry> iterator = entries.iterator(); iterator.hasNext();) {
CarbideSyndEntry entry = iterator.next();
String title = entry.getTitle();
title = title.replaceAll("\n", "");
if (title.equals(entryTitle) && !entry.isRead()) {
entry.setRead(true);
break;
}
}
}
/**
* Reset the update timer.
*/
public void resetUpdateTimer() {
if (updateTimer == null) {
updateTimer = new Timer();
}
long updateInterval = getUpdateInterval();
UpdateTimerTask updateTask = new UpdateTimerTask();
updateTimer.schedule(updateTask, updateInterval);
}
/**
* Save relevant feed information to local cache.
*/
public void saveFeeds() {
feedCacheManager.clearFeedCache();
for (Iterator<CarbideSyndFeed> iterator = newsFeeds.iterator(); iterator.hasNext();) {
CarbideSyndFeed feed = iterator.next();
feedCacheManager.saveFeedToCache(feed);
}
feedCacheManager.saveFeedToCache(resourceFeed);
saveFeedCache();
}
/**
* Perform any necessary actions when the total number of unread entries from
* subscribed news feeds has changed.
*/
@SuppressWarnings("static-access")
public void unreadEntriesCountChanged() {
feedCacheManager.fireFeedCacheChanged(false);
}
/**
* Update all news and resource feeds.
*/
@SuppressWarnings("static-access")
public void updateFeeds() {
try {
if (!loadFeedListing(false)) {
return;
}
clearFeeds();
updateCache();
feedCacheManager.fireFeedCacheChanged(feedCacheManager.isCacheUpdated());
feedCacheManager.setCacheUpdated(false);
} catch (Exception e) {
CarbideNewsReaderPlugin.log(e);
}
}
/**
* Add a news feed. The news reader can have multiple news feeds.
* @param feed - incoming news feed
* @return true on success
*/
private boolean addNewsFeed(CarbideSyndFeed feed) {
if (feed == null) {
return false;
}
if (feed != null ) {
boolean feedExist = false;
for (Iterator<CarbideSyndFeed> iterator = newsFeeds.iterator(); iterator.hasNext();) {
CarbideSyndFeed aFeed = iterator.next();
if (aFeed.getTitle().equals(feed.getTitle()) &&
aFeed.getLink().equals(feed.getLink())) {
int index = newsFeeds.indexOf(aFeed);
newsFeeds.set(index, feed);
feedExist = true;
}
}
if (!feedExist) {
feed.setType(FeedInfoConstants.FEED_TYPE_NEWS);
newsFeeds.add(feed);
}
return true;
}
return false;
}
/**
* Add a resource feed. The news reader can only have one resource feed.
* @param feed - incoming resource feed
* @return true on success
*/
private boolean addResourceFeed(CarbideSyndFeed feed) {
if (feed == null) {
return false;
}
resourceFeed = feed;
if (resourceFeed != null) {
resourceFeed.setType(FeedInfoConstants.FEED_TYPE_RESOURCE);
return true;
}
return false;
}
/**
* Clear all news and resource feeds.
*/
private void clearFeeds() {
newsFeeds.clear();
resourceFeed = null;
}
/**
* Feed feed content from its server.
* @param feedUrl - URL of the feed
* @return feed object on success; null otherwise
*/
private CarbideSyndFeed fetchFeed(URL feedUrl) throws Exception {
if (feedUrl == null) {
return null;
}
FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance();
FeedFetcher fetcher = new CarbideFeedFetcher(feedInfoCache);
SyndFeed sFeed = fetcher.retrieveFeed(feedUrl);
CarbideSyndFeed feed = new CarbideSyndFeed(sFeed);
if (feed != null) {
feed.setSubscribed(true);
feed.setLink(feedUrl.toString());
return feed;
}
return null;
}
/**
* Get the default local feeds cache file.
* @return default local feeds cache
*/
private File getDefaultFeedCacheFile() {
String location = System.getProperty("user.home") + File.separator +
FEED_CACHE_FILE_NAME;
File file = new File(location);
return file;
}
/**
* Get the update interval from news reader preferences.
* @return update interval
*/
private long getUpdateInterval() {
IPreferenceStore store = CarbideNewsReaderPlugin.getPrefsStore();
long interval = store.getLong(NewsPreferenceConstants.UPDATE_INTERVAL) * 1000 * 60 * 60;
return interval;
}
/**
* Load feed information from local cache.
*/
private void loadFeedCache() throws Exception {
File file = getDefaultFeedCacheFile();
URL url = file.toURL();
if (file.exists()) {
if (url != null) {
feedCacheManager.loadCacheFromFile(url);
}
}
else {
file.createNewFile();
feedCacheManager.createDefaultFeedCache();
feedCacheManager.saveCacheToFile(url);
}
}
/**
* Load feed information from feed listing file.
* @param useLocal - use local copy of feed listing file?
* @return true on success; false otherwise
*/
private boolean loadFeedListing(boolean useLocalCopy) throws Exception {
URL url = feedListingManager.getFeedInfoFileURL(useLocalCopy);
if (url != null) {
return feedListingManager.loadFeedInfo(url);
}
return false;
}
/**
* Save feed information to local cache.
*/
private void saveFeedCache() {
try {
File file = getDefaultFeedCacheFile();
URL url = file.toURL();
if (file.exists()) {
if (url != null) {
feedCacheManager.saveCacheToFile(url);
}
}
else {
file.createNewFile();
feedCacheManager.saveCacheToFile(url);
}
} catch (Exception e) {
CarbideNewsReaderPlugin.log(e);
}
}
/**
* Update local cache of feeds.
*/
private void updateCache() throws Exception {
List<FeedType> feedInfoList = feedListingManager.getFeedInfo().getFeeds().getFeed();
for (Iterator<FeedType> iterator = feedInfoList.iterator(); iterator.hasNext();) {
FeedType feedInfo = iterator.next();
URL feedUrl = new URL(feedInfo.getUrl());
if (feedUrl != null) {
CarbideSyndFeed feed = fetchFeed(feedUrl);
if (feed != null) {
if (feedCacheManager.isFeedInCache(feed)) {
feedCacheManager.syncFeedWithCache(feed);
}
else {
feed.setIsNew(true);
}
feedCacheManager.saveFeedToCache(feed);
if (FeedInfoManager.isNewsFeed(feedInfo)) {
if (!addNewsFeed(feed)) {
break;
}
}
else
if (FeedInfoManager.isResourceFeed(feedInfo)) {
if (!addResourceFeed(feed)) {
break;
}
}
}
}
}
// reset the update timer after each cache update
resetUpdateTimer();
}
/**
* Check news and resource feeds to make sure they are valid.
* Reload feeds from cache if necessary.
*/
private void validateFeeds() {
if ((newsFeeds == null || newsFeeds.size() == 0) && resourceFeed == null) {
try {
if (!loadFeedListing(true)) {
return;
}
loadFeedCache();
List<FeedType> feedInfoList = feedListingManager.getFeedInfo().getFeeds().getFeed();
for (Iterator<FeedType> iterator = feedInfoList.iterator(); iterator.hasNext();) {
FeedType feedInfo = iterator.next();
URL feedUrl = new URL(feedInfo.getUrl());
CarbideSyndFeed feed = feedCacheManager.loadFeedFromCache(feedUrl);
if (feed != null) {
if (FeedInfoManager.isNewsFeed(feedInfo)) {
if (!addNewsFeed(feed)) {
break;
}
}
else
if (FeedInfoManager.isResourceFeed(feedInfo)) {
if (!addResourceFeed(feed)) {
break;
}
}
}
}
} catch (Exception e) {
CarbideNewsReaderPlugin.log(e);
}
}
}
}