/* ********************************************************************** ** ** Copyright notice ** ** ** ** (c) 2005-2009 RSSOwl Development Team ** ** http://www.rssowl.org/ ** ** ** ** 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.rssowl.org/legal/epl-v10.html ** ** ** ** A copy is found in the file epl-v10.html and important notices to the ** ** license from the team is found in the textfile LICENSE.txt distributed ** ** in this package. ** ** ** ** This copyright notice MUST APPEAR in all copies of the file! ** ** ** ** Contributors: ** ** RSSOwl Development Team - initial API and implementation ** ** ** ** ********************************************************************** */ package org.rssowl.core.internal.persist.service; import org.eclipse.core.runtime.Assert; import org.rssowl.core.persist.IFeed; import org.rssowl.core.persist.INews; import org.rssowl.core.persist.NewsCounter; import org.rssowl.core.persist.NewsCounterItem; import org.rssowl.core.persist.dao.INewsCounterDAO; import org.rssowl.core.persist.event.FeedEvent; import org.rssowl.core.persist.event.NewsEvent; import com.db4o.ObjectContainer; import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; /** * Service to update the news counter that is used for quick access of counts * per news state. */ public final class NewsCounterService { private final ObjectContainer fDb; private final NewsCounter fNewsCounter; public NewsCounterService(INewsCounterDAO newsCounterDAO, ObjectContainer db) { this.fDb = db; fNewsCounter = newsCounterDAO.load(); } /** * Update the news counter from the list of added news. * * @param newsEvents the added news */ public void onNewsAdded(Collection<NewsEvent> newsEvents) { if (newsEvents.isEmpty()) return; boolean newsCounterUpdated = false; Map<String, NewsCounterItem> updatedCounterItems = new HashMap<String, NewsCounterItem>(); synchronized (fNewsCounter) { for (NewsEvent newsEvent : newsEvents) { INews news = newsEvent.getEntity(); if (news.getParentId() != 0) //News is stored inside a Bin continue; if (news.getState() == INews.State.DELETED) //Could be DELETED from filters continue; NewsCounterItem newsCounterItem = fNewsCounter.get(news.getFeedLinkAsText()); /* Create Counter if not yet done */ if (newsCounterItem == null) { newsCounterItem = new NewsCounterItem(); fNewsCounter.put(news.getFeedLinkAsText(), newsCounterItem); newsCounterUpdated = true; } /* Update Counter */ if (news.getState() == INews.State.NEW) newsCounterItem.incrementNewCounter(); if (isUnread(news.getState())) newsCounterItem.incrementUnreadCounter(); if (news.isFlagged()) newsCounterItem.incrementStickyCounter(); if (!newsCounterUpdated) updatedCounterItems.put(news.getFeedLinkAsText(), newsCounterItem); } if (newsCounterUpdated) fDb.ext().set(fNewsCounter, Integer.MAX_VALUE); else { for (NewsCounterItem item : updatedCounterItems.values()) fDb.set(item); } } } /** * Update the news counter from the list of updated news. * * @param newsEvents the updated news */ public void onNewsUpdated(Collection<NewsEvent> newsEvents) { Map<String, NewsCounterItem> updatedCounterItems = new HashMap<String, NewsCounterItem>(); synchronized (fNewsCounter) { for (NewsEvent event : newsEvents) { INews currentNews = event.getEntity(); if (currentNews.getParentId() != 0) //News is stored inside a Bin continue; INews oldNews = event.getOldNews(); Assert.isNotNull(oldNews, "oldNews cannot be null on newsUpdated"); //$NON-NLS-1$ boolean oldStateUnread = isUnread(oldNews.getState()); boolean currentStateUnread = isUnread(currentNews.getState()); boolean oldStateNew = INews.State.NEW.equals(oldNews.getState()); boolean currentStateNew = INews.State.NEW.equals(currentNews.getState()); boolean oldStateSticky = oldNews.isFlagged() && oldNews.isVisible(); boolean newStateSticky = currentNews.isFlagged() && currentNews.isVisible(); /* No Change - continue */ if (oldStateUnread == currentStateUnread && oldStateNew == currentStateNew && oldStateSticky == newStateSticky) continue; NewsCounterItem counterItem = fNewsCounter.get(currentNews.getFeedLinkAsText()); /* News became read */ if (oldStateUnread && !currentStateUnread) counterItem.decrementUnreadCounter(); /* News became unread */ else if (!oldStateUnread && currentStateUnread) counterItem.incrementUnreadCounter(); /* News no longer New */ if (oldStateNew && !currentStateNew) counterItem.decrementNewCounter(); /* News became New */ else if (!oldStateNew && currentStateNew) counterItem.incrementNewCounter(); /* News became unsticky */ if (oldStateSticky && !newStateSticky) counterItem.decrementStickyCounter(); /* News became sticky */ else if (!oldStateSticky && newStateSticky) counterItem.incrementStickyCounter(); updatedCounterItems.put(currentNews.getFeedLinkAsText(), counterItem); } for (NewsCounterItem counterItem : updatedCounterItems.values()) fDb.set(counterItem); } } /** * Update the news counter from the list of deleted news. * * @param newsEvents the deleted news */ public void onNewsRemoved(Collection<NewsEvent> newsEvents) { Map<String, NewsCounterItem> updatedCounterItems = new HashMap<String, NewsCounterItem>(); synchronized (fNewsCounter) { for (NewsEvent newsEvent : newsEvents) { INews news = newsEvent.getEntity(); if (news.getParentId() != 0) //News is stored inside a Bin continue; NewsCounterItem counterItem = fNewsCounter.get(news.getFeedLinkAsText()); /* Update Counter */ if (news.getState() == INews.State.NEW) counterItem.decrementNewCounter(); if (isUnread(news.getState())) counterItem.decrementUnreadCounter(); if (news.isFlagged() && (!EnumSet.of(INews.State.DELETED, INews.State.HIDDEN).contains(news.getState()))) counterItem.decrementStickyCounter(); updatedCounterItems.put(news.getFeedLinkAsText(), counterItem); } for (NewsCounterItem counterItem : updatedCounterItems.values()) fDb.set(counterItem); } } /** * Update the news counter from the list of deleted feeds. * * @param feedEvents the deleted feeds */ public void onFeedRemoved(Collection<FeedEvent> feedEvents) { if (feedEvents.isEmpty()) return; synchronized (fNewsCounter) { for (FeedEvent feedEvent : feedEvents) { IFeed feed = feedEvent.getEntity(); fNewsCounter.remove(feed.getLink().toString()); } fDb.ext().set(fNewsCounter, Integer.MAX_VALUE); } } private static boolean isUnread(INews.State state) { return state == INews.State.NEW || state == INews.State.UPDATED || state == INews.State.UNREAD; } }