// 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: ChangesMonitor.java,v 1.34 2008/02/27 15:45:40 spyromus Exp $
//
package com.salas.bb.persistence;
import com.salas.bb.domain.*;
import com.salas.bb.domain.utils.DomainAdapter;
import com.salas.bb.utils.i18n.Strings;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Monitor of changes in model. It looks for changes in model and calls correspondent
* methods of a given persistence manager to make persistent changes.
*/
public final class ChangesMonitor extends DomainAdapter
{
/** Default logger. */
private static final Logger LOG = Logger.getLogger(ChangesMonitor.class.getName());
/** Persistence operation has failed. */
private static final String MSG_PERS_OP_FAILED = Strings.error("db.persistent.operation.has.failed");
/** Persistence manager used to perform persistent changes. */
private final IPersistenceManager manager;
/** The set being monitored. */
private final GuidesSet set;
/** List of properties to skip updating in database. */
private final List<String> articlePropertiesToSkip;
/** List of properties to skip updating in database. */
private final List<String> feedPropertiesToSkip;
/**
* Creates the monitor for a given set.
*
* @param aSet set to monitor.
* @param aManager manager to call for persistent changes.
*/
public ChangesMonitor(GuidesSet aSet, IPersistenceManager aManager)
{
manager = aManager;
set = aSet;
articlePropertiesToSkip = new ArrayList<String>();
articlePropertiesToSkip.add(ITaggable.PROP_SHARED_TAGS);
articlePropertiesToSkip.add(ITaggable.PROP_TAGS_DESCRIPTION);
articlePropertiesToSkip.add(ITaggable.PROP_UNSAVED_USER_TAGS);
articlePropertiesToSkip.add(ITaggable.PROP_USER_TAGS);
articlePropertiesToSkip.add(AbstractArticle.PROP_ID);
articlePropertiesToSkip.add(IArticle.PROP_POSITIVE);
articlePropertiesToSkip.add(IArticle.PROP_NEGATIVE);
feedPropertiesToSkip = new ArrayList<String>();
feedPropertiesToSkip.add(IFeed.PROP_PROCESSING);
feedPropertiesToSkip.add(IFeed.PROP_UNREAD_ARTICLES_COUNT);
}
/**
* 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 aSet, IGuide guide, boolean lastInBatch)
{
try
{
manager.insertGuide(guide, set.indexOf(guide));
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked when the guide has been removed from the set.
*
* @param set guides set.
* @param guide removed guide.
* @param index old guide index.
*/
public void guideRemoved(GuidesSet set, IGuide guide, int index)
{
try
{
manager.removeGuide(guide);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked when the guide has been moved to a new location in list.
*
* @param set guides set.
* @param guide guide which has been removed.
* @param oldIndex old guide index.
* @param newIndex new guide index.
*/
public void guideMoved(GuidesSet set, IGuide guide, int oldIndex, int newIndex)
{
try
{
manager.updateGuidePositions(set);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* 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 is still transient, it will be added later with the link-creation
// even and the position will be updated there too
if (feed == null || feed.getID() == -1) return;
// Update feed or feeds position
try
{
boolean last = guide.indexOf(feed) == guide.getFeedsCount() - 1;
if (last)
{
manager.updateFeedPosition(guide, feed);
} else
{
manager.updateFeedsPositions(guide);
}
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked when a feed is moved from one position to another.
*
* @param guide source guide.
* @param feed feed moved.
* @param oldPosition old position.
* @param newPosition new position.
*/
public void feedRepositioned(IGuide guide, IFeed feed, int oldPosition, int newPosition)
{
try
{
if (oldPosition != newPosition) manager.updateFeedsPositions(guide);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked when new feed has been added directly to this guide (not through the Reading List).
* In fact, it doesn't mean that the feed should appear in the guide if it's already there. This
* event will be followed by <code>feedAdded</code> event if this is the first addition of this
* feed (not visible yet) and will not, if the feed is already in the list.
*
* @param guide parent guide.
* @param feed added feed.
*/
public void feedLinkAdded(IGuide guide, IFeed feed)
{
try
{
manager.addFeedToGuide(guide, feed);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked when the feed has been removed directly from the feed. It has nothing to do with the
* visual representation of the guide because this feed can still be visible in the guide
* because of its presence in one or more associated reading lists. This even simply means that
* there's no direct connection between the guide and the feed.
*
* @param guide source guide.
* @param feed removed feed.
*/
public void feedLinkRemoved(IGuide guide, IFeed feed)
{
try
{
manager.removeFeedFromGuide(guide, feed);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked when feed link property changes its value.
*
* @param guide source guide.
* @param feed feed, who's link property has changed.
* @param property property name.
* @param oldValue old value.
* @param newValue new value.
*/
public void feedLinkPropertyChanged(StandardGuide guide, IFeed feed, String property,
long oldValue, long newValue)
{
try
{
manager.updateFeedLink(guide, feed);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked after new reading list is added to the guide.
*
* @param guide source guide.
* @param list reading list added.
*/
public void readingListAdded(IGuide guide, ReadingList list)
{
try
{
manager.insertReadingList(list);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked after reading list is removed from the guide.
*
* @param guide source guide.
* @param list reading list removed.
*/
public void readingListRemoved(IGuide guide, ReadingList list)
{
try
{
manager.removeReadingList(list);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked when new feed has been added to the reading list.
*
* @param list reading list the feed was added to.
* @param feed added feed.
*/
public void feedAdded(ReadingList list, IFeed feed)
{
try
{
manager.addFeedToReadingList(list, feed);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked when the feed has been removed from the reading list.
*
* @param list reading list the feed was removed from.
* @param feed removed feed.
*/
public void feedRemoved(ReadingList list, IFeed feed)
{
try
{
manager.removeFeedFromReadingList(list, feed);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked when the property of the list has been changed.
*
* @param list list owning the property.
* @param property property name.
* @param oldValue old property value.
* @param newValue new property value.
*/
public void propertyChanged(ReadingList list, String property, Object oldValue, Object newValue)
{
try
{
manager.updateReadingList(list);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Invoked when the property of the guide has been changed.
*
* @param guide guide owning the property.
* @param property property name.
* @param oldValue old property value.
* @param newValue new property value.
*/
public void propertyChanged(IGuide guide, String property, Object oldValue, Object newValue)
{
try
{
manager.updateGuide(guide, set.indexOf(guide));
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Called when some article is added to the feed.
*
* @param feed feed.
* @param article article.
*/
public void articleAdded(IFeed feed, IArticle article)
{
if (feed instanceof SearchFeed) return;
try
{
manager.insertArticle(article);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Called when some article is removed from the feed.
*
* @param feed feed.
* @param article article.
*/
public void articleRemoved(IFeed feed, IArticle article)
{
if (feed instanceof SearchFeed) return;
try
{
manager.removeArticle(article);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
/**
* Called when information in feed 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)
{
boolean persistent = (feed instanceof DataFeed || feed instanceof SearchFeed) &&
!feedPropertiesToSkip.contains(property);
if (persistent)
{
try
{
manager.updateFeed(feed, property);
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
// STATS: Report that a feed being visited
if (IFeed.PROP_VIEWS.equals(property)) manager.getStatisticsManager().feedVisited(feed);
}
/**
* 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.
*/
public void propertyChanged(IArticle article, String property, Object oldValue,
Object newValue)
{
if (article.getID() == -1 || articlePropertiesToSkip.contains(property)) return;
try
{
if (property.equals(IArticle.PROP_SENTIMENT_COUNTS))
{
manager.updateArticleProperties(article);
} else
{
manager.updateArticle(article);
}
} catch (PersistenceException e)
{
LOG.log(Level.SEVERE, MSG_PERS_OP_FAILED, e);
}
}
}