Package com.salas.bb.core

Source Code of com.salas.bb.core.SearchFeedsManager$ProcessArticleAdded

// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software Foundation;
// either version 2 of the License, or (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: SearchFeedsManager.java,v 1.26 2008/02/28 09:58:33 spyromus Exp $
//

package com.salas.bb.core;

import EDU.oswego.cs.dl.util.concurrent.Executor;
import com.jgoodies.uif.application.Application;
import com.salas.bb.domain.*;
import com.salas.bb.domain.events.FeedRemovedEvent;
import com.salas.bb.domain.query.articles.Query;
import com.salas.bb.domain.utils.DomainAdapter;
import com.salas.bb.utils.concurrency.ExecutorFactory;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.prefs.Preferences;

/**
* Manager of all search feeds, which is doing scans for them.
*/
public class SearchFeedsManager extends DomainAdapter
{
    private static final int KEEP_ALIVE_TIME = 10000;

    private static Boolean dontUpdateAutomatically;

    private GuidesSet       guidesSet;
    private Set<SearchFeed> searchFeeds;

    private Executor executor;

    /**
     * Creates feeds manager of some guides set.
     *
     * @param aSet guides set to work with.
     */
    public SearchFeedsManager(GuidesSet aSet)
    {
        guidesSet = aSet;
        searchFeeds = new CopyOnWriteArraySet<SearchFeed>();

        executor = ExecutorFactory.createPooledExecutor("Search Feeds", 1, Thread.MIN_PRIORITY, KEEP_ALIVE_TIME);

        loadCurrentSearchFeedsInMap();
    }

    private void loadCurrentSearchFeedsInMap()
    {
        StandardGuide[] guides = guidesSet.getStandardGuides(null);
        for (StandardGuide guide : guides) collectSearchFeedsInGuide(guide);
    }

    private void collectSearchFeedsInGuide(StandardGuide aGuide)
    {
        IFeed[] feeds = aGuide.getFeeds();
        for (IFeed feed : feeds)
        {
            if (feed instanceof SearchFeed) searchFeeds.add((SearchFeed)feed);
        }
    }

    public void runAllQueries()
    {
//        List<Integer> sids = new ArrayList<Integer>();
//
//        StandardGuide[] guides = guidesSet.getStandardGuides(null);
//        for (StandardGuide guide : guides)
//        {
//            IFeed[] feeds = guide.getFeeds();
//            for (IFeed feed : feeds)
//            {
//                if (feed instanceof SearchFeed)
//                {
//                    Integer id = System.identityHashCode(feed);
//                    if (!sids.contains(id))
//                    {
//                        sids.add(id);
//                        runQuery((SearchFeed)feed);
//                    }
//                }
//            }
//        }
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

        SearchFeed[] sfeeds = searchFeeds.toArray(new SearchFeed[0]);
        processingStarted(sfeeds);
        try
        {
            List<IFeed> feeds = guidesSet.getFeedsList().getFeeds();
            for (IFeed feed : feeds)
            {
                if (feed instanceof DataFeed)
                {
                    for (SearchFeed sfeed : sfeeds) scanFeed(feed, sfeed);

                    try
                    {
                        Thread.sleep(100);
                    } catch (InterruptedException e)
                    {
                        // Ignore
                    }
                }
            }
        } finally
        {
            processingFinished(sfeeds);
        }
    }

    private void processingStarted(SearchFeed[] sfeeds)
    {
        for (SearchFeed sfeed : sfeeds) sfeed.processingStarted();
    }

    private void processingFinished(SearchFeed[] sfeeds)
    {
        for (SearchFeed sfeed : sfeeds) sfeed.processingFinished();
    }

    /**
     * Returns all search feeds that have sentiments clause in them.
     *
     * @return feeds.
     */
    public static List<SearchFeed> findFeedsWithSentimentsClause()
    {
        return GlobalController.getSearchFeedsManager().findFeedsWithSentimentsClause0();
    }

    /**
     * Returns all search feeds that have sentiments clause in them.
     *
     * @return feeds.
     */
    private List<SearchFeed> findFeedsWithSentimentsClause0()
    {
        List<SearchFeed> feeds = new LinkedList<SearchFeed>();

        for (SearchFeed feed : searchFeeds)
        {
            Query query = feed.getQuery();
            if (query.hasSentimentsClause()) feeds.add(feed);
        }

        return feeds;
    }

    /**
     * Runs query for a given search feed. Updates the list of articles.
     *
     * @param aSearchFeed search feed.
     */
    public void runQuery(SearchFeed aSearchFeed)
    {
        aSearchFeed.processingStarted();
        try
        {
            aSearchFeed.reviewArticlesTakenFrom(null);
            StandardGuide[] guides = guidesSet.getStandardGuides(null);
            for (StandardGuide guide : guides) scanGuide(guide, aSearchFeed);
        } finally
        {
            aSearchFeed.processingFinished();
        }
    }

    private void scanGuide(StandardGuide aGuide, SearchFeed aSearchFeed)
    {
        IFeed[] feeds = aGuide.getFeeds();
        for (IFeed feed : feeds) if (feed instanceof DataFeed) scanFeed(feed, aSearchFeed);
    }

    private void scanFeed(IFeed aFeed, SearchFeed aSearchFeed)
    {
        IArticle[] articles = aFeed.getArticles();
        for (IArticle article : articles) aSearchFeed.addArticleIfMatching(article);
    }
   
    // ---------------------------------------------------------------------------------------------
    // Listening to domain events
    // ---------------------------------------------------------------------------------------------

    /**
     * Invoked when new article has been added to the feed.
     *
     * @param feed    feed.
     * @param article article.
     */
    public void articleAdded(IFeed feed, IArticle article)
    {
        if (feed instanceof SearchFeed || isNotUpdatingAutomatically()) return;

        scheduleOrRun(new ProcessArticleAdded(article));
    }

    /**
     * Returns <code>TRUE</code> only if there's a property set that
     * doesn't allow search feeds to be updated dynamically.
     *
     * @return <code>TRUE</code> to not update search feeds.
     */
    private static synchronized boolean isNotUpdatingAutomatically()
    {
        if (dontUpdateAutomatically == null)
        {
            Preferences prefs = Application.getUserPreferences();
            dontUpdateAutomatically = prefs.getBoolean("searchfeeds.dontUpdateAutomatically", false);
        }

        return dontUpdateAutomatically;
    }

    /**
     * Invoked when the article has been removed from the feed.
     *
     * @param feed    feed.
     * @param article article.
     */
    public void articleRemoved(IFeed feed, IArticle article)
    {
        scheduleOrRun(new ProcessArticleRemoved(article));
    }

    /**
     * Schedule the task for execution or run if unable to schedule.
     *
     * @param task task.
     */
    private void scheduleOrRun(Runnable task)
    {
        try
        {
            executor.execute(task);
        } catch (InterruptedException e)
        {
            task.run();
        }
    }

    /**
     * Invoked when new guide has been added to the set.
     *
     * @param set           guides set.
     * @param guide         added guide.
     * @param lastInBatch   <code>TRUE</code> when this is the last even in batch.
     */
    public void guideAdded(GuidesSet set, IGuide guide, boolean lastInBatch)
    {
        if (guide instanceof StandardGuide)
        {
            collectSearchFeedsInGuide((StandardGuide)guide);
        }
    }

    /**
     * Invoked when new feed has been added to the guide.
     *
     * @param guide parent guide.
     * @param feed  added feed.
     */
    public void feedAdded(IGuide guide, IFeed feed)
    {
        if (feed instanceof SearchFeed) searchFeeds.add((SearchFeed)feed);
    }

    /**
     * Invoked when the feed has been removed from the guide.
     *
     * @param event feed removal event.
     */
    public void feedRemoved(FeedRemovedEvent event)
    {
        IFeed feed = event.getFeed();

        if (feed.getParentGuides().length == 0)
        {
            if (feed instanceof SearchFeed)
            {
                SearchFeed sfeed = (SearchFeed)feed;

                sfeed.unregisterListeners();
                searchFeeds.remove(sfeed);
            } else if (feed instanceof DataFeed)
            {
                IArticle[] articles = feed.getArticles();
                for (IArticle article : articles) articleRemoved(feed, article);
            }
        }
    }

    /**
     * Invoked when the property of the feed has been changed.
     *
     * @param feed     feed.
     * @param property property of the feed.
     * @param oldValue old property value.
     * @param newValue new property value.
     */
    public void propertyChanged(IFeed feed, String property, Object oldValue, Object newValue)
    {
        if (feed instanceof SearchFeed)
        {
            SearchFeed sfeed = (SearchFeed)feed;
            if (SearchFeed.PROP_QUERY.equals(property) ||
                SearchFeed.PROP_DEDUP_UPDATED.equals(property))
            {
                runQuery(sfeed);
            }
        } else if (isInterestingFeedProperty(property))
        {
            for (SearchFeed searchFeed : searchFeeds)
            {
                searchFeed.reviewArticlesTakenFrom(feed);
                scanFeed(feed, searchFeed);
            }
        }
    }

    /**
     * Invoked when the property of the article has been changed.
     *
     * @param article  article.
     * @param property property of the article.
     * @param oldValue old property value.
     * @param newValue new property value.
     */
// This one creates a deadlock on startup see (BT #248)
//    public void propertyChanged(IArticle article, String property, Object oldValue, Object newValue)
//    {
//        Iterator iterator = searchFeeds.iterator();
//        while (iterator.hasNext())
//        {
//            SearchFeed searchFeed = (SearchFeed)iterator.next();
//            searchFeed.addArticleIfMatching(article);
//        }
//    }

    /**
     * Far not all properties should induce review of results of a query. In this
     * method we check if a property of the feed is interesting to us.
     *
     * @param aProperty name of feed property.
     *
     * @return <code>TRUE</code> if the change of this property is interesting to search feeds.
     */
    private boolean isInterestingFeedProperty(String aProperty)
    {
        return aProperty.equals(IFeed.PROP_TITLE) ||
            aProperty.equals(IFeed.PROP_RATING) ||
            aProperty.equals(DirectFeed.PROP_USER_TAGS);
    }

    /**
     * Reviews whole search feed.
     *
     * @param aSearchFeed search feed with changed query criteria.
     */
    public void queryUpdated(SearchFeed aSearchFeed)
    {
        aSearchFeed.reviewArticlesTakenFrom(null);
    }

    /**
     * Updates a search feed.
     *
     * @param feed feed.
     */
    public static void update(SearchFeed feed)
    {
        GlobalController.getSearchFeedsManager().runQuery(feed);
    }

    /**
     * Processes article removed event. Walks through the list of search feeds and
     * notifies them one by one.
     */
    private class ProcessArticleAdded implements Runnable
    {
        private final IArticle article;

        /**
         * Creates the task with an article.
         *
         * @param article article.
         */
        public ProcessArticleAdded(IArticle article)
        {
            this.article = article;
        }

        /**
         * Executed when processing should start.
         */
        public void run()
        {
            for (SearchFeed searchFeed : searchFeeds) searchFeed.addArticleIfMatching(article);
        }
    }

    /**
     * Processes article removed event. Walks through the list of search feeds and
     * notifies them one by one.
     */
    private class ProcessArticleRemoved implements Runnable
    {
        private final IArticle article;

        /**
         * Creates the task with an article.
         *
         * @param article article.
         */
        public ProcessArticleRemoved(IArticle article)
        {
            this.article = article;
        }

        /**
         * Executed when processing should start.
         */
        public void run()
        {
            for (SearchFeed searchFeed : searchFeeds) searchFeed.removeArticle(article);
        }
    }
}
TOP

Related Classes of com.salas.bb.core.SearchFeedsManager$ProcessArticleAdded

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.