org.eclipsetrader.news.internal.connectors.RSSNewsProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipsetrader.news.internal.connectors.RSSNewsProvider.java

Source

/*
 * Copyright (c) 2004-2006 Marco Maccaferri and others.
 * 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:
 *     Marco Maccaferri - initial API and implementation
 */

package org.eclipsetrader.news.internal.connectors;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.eclipse.core.net.proxy.IProxyData;
import org.eclipse.core.net.proxy.IProxyService;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipsetrader.core.instruments.ISecurity;
import org.eclipsetrader.news.core.IHeadLine;
import org.eclipsetrader.news.core.INewsProvider;
import org.eclipsetrader.news.core.INewsService;
import org.eclipsetrader.news.core.INewsServiceRunnable;
import org.eclipsetrader.news.internal.Activator;
import org.eclipsetrader.news.internal.repository.HeadLine;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.fetcher.impl.FeedFetcherCache;
import com.sun.syndication.fetcher.impl.HashMapFeedInfoCache;
import com.sun.syndication.fetcher.impl.HttpClientFeedFetcher;

public class RSSNewsProvider implements INewsProvider, IExecutableExtension {

    public static final String HEADLINES_FILE = "rss.xml"; //$NON-NLS-1$

    private String id;
    private String name;

    private FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance();
    private HttpClientFeedFetcher fetcher = new HttpClientFeedFetcher(feedInfoCache);

    private INewsService newsService;
    private boolean started;

    static private List<HeadLine> oldItems = new ArrayList<HeadLine>();

    private JobChangeAdapter jobChangeListener = new JobChangeAdapter() {

        @Override
        public void done(IJobChangeEvent event) {
            IPreferenceStore store = Activator.getDefault().getPreferenceStore();
            int interval = store.getInt(Activator.PREFS_UPDATE_INTERVAL);
            job.schedule(interval * 60 * 1000);
        }
    };

    private Job job = new Job("RSS Subscriptions") {

        @Override
        protected IStatus run(IProgressMonitor monitor) {
            return jobRunner(monitor);
        }
    };

    public RSSNewsProvider() {
    }

    /* (non-Javadoc)
     * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object)
     */
    @Override
    public void setInitializationData(IConfigurationElement config, String propertyName, Object data)
            throws CoreException {
        id = config.getAttribute("id");
        name = config.getAttribute("name");
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.news.core.INewsProvider#getId()
     */
    @Override
    public String getId() {
        return id;
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.news.core.INewsProvider#getName()
     */
    @Override
    public String getName() {
        return name;
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.news.core.INewsProvider#getHeadLines()
     */
    @Override
    public IHeadLine[] getHeadLines() {
        return new IHeadLine[0];
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.news.core.INewsProvider#start()
     */
    @Override
    public void start() {
        if (!started) {
            job.schedule(5 * 1000);
            job.addJobChangeListener(jobChangeListener);
            started = true;
        }
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.news.core.INewsProvider#stop()
     */
    @Override
    public void stop() {
        if (started) {
            job.removeJobChangeListener(jobChangeListener);
            job.cancel();
            started = false;
        }
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.news.core.INewsProvider#refresh()
     */
    @Override
    public void refresh() {
        job.removeJobChangeListener(jobChangeListener);
        job.cancel();

        if (started) {
            job.addJobChangeListener(jobChangeListener);
        }

        job.schedule(0);
    }

    protected IStatus jobRunner(IProgressMonitor monitor) {
        final List<IHeadLine> list = new ArrayList<IHeadLine>();

        FeedSource[] sources = getActiveSubscriptions();
        monitor.beginTask("Updating RSS Subscriptions", sources.length);

        try {
            for (int i = 0; i < sources.length; i++) {
                try {
                    HeadLine[] headLines = update(new URL(sources[i].getUrl()), sources[i].getName());
                    for (HeadLine headLine : headLines) {
                        if (!oldItems.contains(headLine)) {
                            headLine.setRecent(true);
                            oldItems.add(headLine);
                            list.add(headLine);
                        }
                    }
                } catch (Exception e) {
                    Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, 0,
                            "Error updating headlines from " + sources[i].getUrl(), null); //$NON-NLS-1$
                    Activator.getDefault().getLog().log(status);
                } finally {
                    monitor.worked(1);
                }
            }

            final INewsService service = getNewsService();
            service.runInService(new INewsServiceRunnable() {

                @Override
                public IStatus run(IProgressMonitor monitor) throws Exception {
                    service.addHeadLines(list.toArray(new IHeadLine[list.size()]));
                    return Status.OK_STATUS;
                }
            }, null);
        } finally {
            monitor.done();
        }

        return Status.OK_STATUS;
    }

    protected void resetRecentFlag() {
        final List<HeadLine> updated = new ArrayList<HeadLine>();
        for (HeadLine headLine : oldItems) {
            if (headLine.isRecent()) {
                headLine.setRecent(false);
                updated.add(headLine);
            }
        }

        final INewsService service = getNewsService();
        service.runInService(new INewsServiceRunnable() {

            @Override
            public IStatus run(IProgressMonitor monitor) throws Exception {
                service.updateHeadLines(updated.toArray(new IHeadLine[updated.size()]));
                return Status.OK_STATUS;
            }
        }, null);
    }

    protected FeedSource[] getActiveSubscriptions() {
        List<FeedSource> list = new ArrayList<FeedSource>();

        try {
            File file = Activator.getDefault().getStateLocation().append(HEADLINES_FILE).toFile();
            if (file.exists()) {
                JAXBContext jaxbContext = JAXBContext.newInstance(FeedSource[].class);
                Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
                unmarshaller.setEventHandler(new ValidationEventHandler() {

                    @Override
                    public boolean handleEvent(ValidationEvent event) {
                        Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, 0,
                                "Error validating XML: " + event.getMessage(), null); //$NON-NLS-1$
                        Activator.getDefault().getLog().log(status);
                        return true;
                    }
                });
                JAXBElement<FeedSource[]> element = unmarshaller.unmarshal(new StreamSource(file),
                        FeedSource[].class);
                for (FeedSource source : element.getValue()) {
                    if (source.isEnabled()) {
                        list.add(source);
                    }
                }
            }
        } catch (Exception e) {
            Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, 0, "Error reading RSS subscriptions", //$NON-NLS-1$
                    null);
            Activator.getDefault().getLog().log(status);
        }

        return list.toArray(new FeedSource[list.size()]);
    }

    private HeadLine[] update(URL feedUrl, String source) {
        Map<String, SyndEntry> titles = new HashMap<String, SyndEntry>();
        Map<SyndEntry, Set<ISecurity>> entries = new HashMap<SyndEntry, Set<ISecurity>>();
        Set<HeadLine> headLines = new HashSet<HeadLine>();

        try {
            HttpClient client = new HttpClient();
            client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);

            if (Activator.getDefault() != null) {
                BundleContext context = Activator.getDefault().getBundle().getBundleContext();
                ServiceReference reference = context.getServiceReference(IProxyService.class.getName());
                if (reference != null) {
                    IProxyService proxy = (IProxyService) context.getService(reference);
                    IProxyData data = proxy.getProxyDataForHost(feedUrl.getHost(), IProxyData.HTTP_PROXY_TYPE);
                    if (data != null) {
                        if (data.getHost() != null) {
                            client.getHostConfiguration().setProxy(data.getHost(), data.getPort());
                        }
                        if (data.isRequiresAuthentication()) {
                            client.getState().setProxyCredentials(AuthScope.ANY,
                                    new UsernamePasswordCredentials(data.getUserId(), data.getPassword()));
                        }
                    }
                    context.ungetService(reference);
                }
            }

            SyndFeed feed = fetcher.retrieveFeed(feedUrl, client);
            for (Iterator<?> iter = feed.getEntries().iterator(); iter.hasNext();) {
                SyndEntry entry = (SyndEntry) iter.next();

                if (titles.containsKey(entry.getTitle())) {
                    entry = titles.get(entry.getTitle());
                } else {
                    titles.put(entry.getTitle(), entry);
                }

                Set<ISecurity> set = entries.get(entry);
                if (set == null) {
                    set = new HashSet<ISecurity>();
                    entries.put(entry, set);
                }
            }

            for (SyndEntry entry : entries.keySet()) {
                Set<ISecurity> set = entries.get(entry);

                String url = entry.getLink();
                if (url.indexOf('*') != -1) {
                    url = url.substring(url.indexOf('*') + 1);
                }

                String title = entry.getTitle();
                if (title.endsWith(")")) {
                    int s = title.lastIndexOf('(');
                    if (s != -1) {
                        source = title.substring(s + 1, title.length() - 1);
                        if (source.startsWith("at ")) {
                            source = source.substring(3);
                        }
                        title = title.substring(0, s - 1).trim();
                    }
                }

                HeadLine headLine = new HeadLine(entry.getPublishedDate(), source, title,
                        set.toArray(new ISecurity[set.size()]), url);
                headLines.add(headLine);
            }
        } catch (Exception e) {
            Status status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, 0,
                    "Error reading RSS subscription " + feedUrl.toString(), e); //$NON-NLS-1$
            Activator.getDefault().getLog().log(status);
        }
        return headLines.toArray(new HeadLine[headLines.size()]);
    }

    protected INewsService getNewsService() {
        if (newsService == null) {
            BundleContext context = Activator.getDefault().getBundle().getBundleContext();
            ServiceReference serviceReference = context.getServiceReference(INewsService.class.getName());
            if (serviceReference != null) {
                newsService = (INewsService) context.getService(serviceReference);
                context.ungetService(serviceReference);
            }
        }
        return newsService;
    }
}