/*******************************************************************************
* Copyright (c) 2012 - 2014 Pivotal Software, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.springsource.ide.eclipse.dashboard.internal.ui.feeds;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.springsource.ide.eclipse.commons.core.ResourceProvider;
import org.springsource.ide.eclipse.dashboard.internal.ui.IIdeUiConstants;
import org.springsource.ide.eclipse.dashboard.internal.ui.IdeUiPlugin;
import org.springsource.ide.eclipse.dashboard.internal.ui.editors.AggregateFeedJob;
import org.springsource.ide.eclipse.dashboard.internal.ui.editors.UpdateNotification;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
public class FeedMonitor {
public static final String RESOURCE_DASHBOARD_FEEDS_BLOGS = "dashboard.feeds.blogs";
public static final String RESOURCE_DASHBOARD_FEEDS_UPDATE = "dashboard.feeds.update";
private final static int FEED_POLLING_RATE = 60 * 60 * 1000; // 60 Minutes
private static final long FEED_STARTUP_DELAY = 15 * 1000; // Allow STS to startup before pulling feeds from the internet
private Date lastUpdated;
private static FeedMonitor instance;
private boolean newFeedItems;
private Set<SyndEntry> feedEntries;
private List<UpdateNotification> updates;
private List<IFeedListener> listeners = new ArrayList<IFeedListener>();
private AggregateFeedJob blogFeedJob = null;
private AggregateFeedJob newsFeedJob = null;
private FeedMonitor() {
IPreferenceStore prefStore = IdeUiPlugin.getDefault().getPreferenceStore();
long lastUpdateLong = prefStore.getLong(IIdeUiConstants.PREF_FEED_ENTRY_LAST_UPDATE_DISPLAYED);
lastUpdated = new Date(lastUpdateLong);
prefStore.addPropertyChangeListener(new IPropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
if (IIdeUiConstants.PREF_UPDATE_DASHBOARD_NEWS_FEED.equals(event.getProperty())) {
initNewsFeedUpdates();
}
}
});
ResourceProvider.getInstance().addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(java.beans.PropertyChangeEvent evt) {
if (RESOURCE_DASHBOARD_FEEDS_BLOGS.equals(evt.getPropertyName())) {
initBlogFeedUpdates();
}
}
});
addListener(new IFeedListener() {
@Override
public void updated(String id) {
updateDashboardButtons();
}
});
initBlogFeedUpdates();
initNewsFeedUpdates();
}
private void initBlogFeedUpdates() {
final Map<String, String> springMap = new HashMap<String, String>();
String[] urls = ResourceProvider.getUrls(RESOURCE_DASHBOARD_FEEDS_BLOGS);
for (String url : urls) {
springMap.put(url, null);
}
if (blogFeedJob != null) {
blogFeedJob.cancel();
}
if (!springMap.isEmpty()) {
blogFeedJob = new AggregateFeedJob(springMap, RESOURCE_DASHBOARD_FEEDS_BLOGS);
blogFeedJob.setSystem(true);
blogFeedJob.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
Map<SyndEntry, SyndFeed> entryToFeed = blogFeedJob.getFeedReader().getFeedsWithEntries();
Set<SyndEntry> retrieveFeedEntries = entryToFeed.keySet();
newFeedItems = false;
feedEntries = new HashSet<SyndEntry>(retrieveFeedEntries);
checkFeedsUpToDate();
update(blogFeedJob.getFeedName());
if (event.getResult().getSeverity() != IStatus.CANCEL) {
blogFeedJob.schedule(FEED_POLLING_RATE);
}
}
});
//Add a delay for the initial feed fetch. The job, when run early during startup causes trouble:
// See https://issuetracker.springsource.com/browse/STS-4188
blogFeedJob.schedule(FEED_STARTUP_DELAY);
}
}
private void initNewsFeedUpdates() {
if (newsFeedJob != null) {
newsFeedJob.cancel();
}
if (IdeUiPlugin.getDefault().getPreferenceStore().getBoolean(IIdeUiConstants.PREF_UPDATE_DASHBOARD_NEWS_FEED)) {
Map<String, String> updateMap = new HashMap<String, String>();
updateMap.put(ResourceProvider.getUrl(RESOURCE_DASHBOARD_FEEDS_UPDATE), null);
newsFeedJob = new AggregateFeedJob(updateMap, RESOURCE_DASHBOARD_FEEDS_UPDATE);
newsFeedJob.setSystem(true);
newsFeedJob.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
updates = new ArrayList<UpdateNotification>(newsFeedJob
.getNotifications());
update(newsFeedJob.getFeedName());
if (event.getResult().getSeverity() != IStatus.CANCEL) {
newsFeedJob.schedule(FEED_POLLING_RATE);
}
}
});
newsFeedJob.schedule(FEED_STARTUP_DELAY);
}
}
public static synchronized FeedMonitor getInstance() {
if (instance==null) {
instance = new FeedMonitor();
}
return instance;
}
public boolean isNewFeedItems() {
return newFeedItems;
}
public Set<SyndEntry> getFeedEntries() {
return feedEntries;
}
public List<UpdateNotification> getUpdates() {
return updates;
}
private void update(String id) {
if (PlatformUI.isWorkbenchRunning()) {
for (IFeedListener listener : listeners) {
listener.updated(id);
}
}
}
public void updateDashboardButtons() {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (activeWorkbenchWindow != null) {
ICommandService commandService = (ICommandService) activeWorkbenchWindow
.getService(ICommandService.class);
if (commandService != null) {
commandService.refreshElements("org.springsource.ide.eclipse.dashboard.ui.showDashboard", null);
}
}
}
});
}
private void checkFeedsUpToDate() {
newFeedItems = false;
for (SyndEntry entry : feedEntries) {
if ((entry.getUpdatedDate() != null && entry.getUpdatedDate().after(lastUpdated))
|| (entry.getPublishedDate() != null && entry.getPublishedDate().after(lastUpdated))) {
newFeedItems = true;
break;
}
}
}
public void markRead() {
lastUpdated = new Date();
IPreferenceStore prefStore = IdeUiPlugin.getDefault().getPreferenceStore();
prefStore.setValue(IIdeUiConstants.PREF_FEED_ENTRY_LAST_UPDATE_DISPLAYED, lastUpdated.getTime());
if (PlatformUI.isWorkbenchRunning()) {
checkFeedsUpToDate();
updateDashboardButtons();
}
}
public void addListener(IFeedListener listener) {
listeners.add(listener);
}
public void removeListener(IFeedListener listener) {
listeners.remove(listener);
}
public void refresh() {
initBlogFeedUpdates();
initNewsFeedUpdates();
}
}