/* ********************************************************************** ** ** 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.persist.event.runnable; import org.eclipse.core.runtime.Assert; import org.rssowl.core.Owl; import org.rssowl.core.persist.dao.DAOService; import org.rssowl.core.persist.dao.IEntityDAO; import org.rssowl.core.persist.event.ModelEvent; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Base class for runnables that fire events. These runnables are useful when * one wants to specify a Set of events to be fired in the future. Another * possible use is to fire the events in an event loop. * * @param <T> A subclass of ModelEvent that establishes the event type that this * class represents. * @author Ismael Juma (ismael@juma.me.uk) */ public abstract class EventRunnable<T extends ModelEvent> implements Runnable { private Set<T> fPersistEvents; private Set<T> fRemoveEvents; private Set<T> fUpdateEvents; private final Class<T> fEventClass; private final IEntityDAO<?, ?, T> fEntityDAO; /** * Creates an instance of this class. * * @param eventClass The subclass of ModelEvent represented by this runnable. * @param entityDAO The entityDAO to be used for firing the events in this * runnable. */ protected EventRunnable(Class<T> eventClass, IEntityDAO<?, ?, T> entityDAO) { Assert.isNotNull(eventClass, "eventClass"); //$NON-NLS-1$ Assert.isNotNull(entityDAO, "entityDAO"); //$NON-NLS-1$ fEventClass = eventClass; fEntityDAO = entityDAO; } /** * @return the current {@link DAOService} instance. */ protected static final DAOService getDAOService() { return Owl.getPersistenceService().getDAOService(); } /** * @return {@code true} is there are any events stored in this runnable. */ public boolean isEmpty() { return isEmpty(fPersistEvents) && isEmpty(fRemoveEvents) && isEmpty(fUpdateEvents); } private boolean isEmpty(Set<?> set) { return set == null || set.isEmpty(); } /** * Fires the event type defined by the eventType property appropriate to T. */ public final void run() { if (shouldFirePersistEvents()) fireEvents(fPersistEvents, EventType.PERSIST); if (shouldFireRemoveEvents()) fireEvents(fRemoveEvents, EventType.REMOVE); if (shouldFireUpdateEvents()) fireEvents(fUpdateEvents, EventType.UPDATE); } private void fireEvents(Set<T> persistEvents, EventType eventType) { fEntityDAO.fireEvents(Collections.unmodifiableSet(persistEvents), eventType); } /** * Checks if {@code event} is an instance of {@code T} and if so calls * {@code addPersistEvent}. * * @param event Persist event to be added. * @throws IllegalArgumentException if {@code event} is not an instance of * {@code T}. */ @SuppressWarnings("unchecked") public final void addCheckedPersistEvent(ModelEvent event) { checkEventType(getEventClass(), event); addPersistEvent((T) event); } private Class<? extends ModelEvent> getEventClass() { return fEventClass; } private void checkEventType(Class<?> expectedClass, ModelEvent eventReceived) { if (!expectedClass.isInstance(eventReceived)) throw new IllegalArgumentException("event must be of type: " + //$NON-NLS-1$ expectedClass + ", but it is of type: " + eventReceived.getClass()); //$NON-NLS-1$ } /** * Checks if {@code event} is an instance of {@code T} and if so calls * {@code addRemoveEvent}. * * @param event Remove event to be added. * @throws IllegalArgumentException if {@code event} is not an instance of * {@code T}. */ @SuppressWarnings("unchecked") public final void addCheckedRemoveEvent(ModelEvent event) { checkEventType(getEventClass(), event); addRemoveEvent((T) event); } /** * Checks if {@code event} is an instance of {@code T} and if so calls * {@code addUpdateEvent}. * * @param event Update event to be added. * @throws IllegalArgumentException if {@code event} is not an instance of * {@code T}. */ @SuppressWarnings("unchecked") public final void addCheckedUpdateEvent(ModelEvent event) { checkEventType(getEventClass(), event); addUpdateEvent((T) event); } /** * Adds {@code event} to the list of persist events. * * @param event Persist event to be added. */ public final void addPersistEvent(T event) { if (fPersistEvents == null) fPersistEvents = new HashSet<T>(3); if (removeEventsContains(event)) return; fPersistEvents.add(event); } private boolean removeEventsContains(ModelEvent event) { return fRemoveEvents != null && fRemoveEvents.contains(event); } private boolean persistEventsContains(ModelEvent event) { return fPersistEvents != null && fPersistEvents.contains(event); } /** * Adds {@code event} to the list of remove events. * * @param event Remove event to be added. */ public final void addRemoveEvent(T event) { if (fRemoveEvents == null) fRemoveEvents = new HashSet<T>(3); if (fUpdateEvents != null) fUpdateEvents.remove(event); if (fPersistEvents != null) fPersistEvents.remove(event); fRemoveEvents.add(event); } /** * Adds {@code event} to the list of update events. * * @param event Update event to be added. */ public final void addUpdateEvent(T event) { if (fUpdateEvents == null) fUpdateEvents = new HashSet<T>(3); if (removeEventsContains(event) || persistEventsContains(event)) return; fUpdateEvents.add(event); } /** * Returns a list of all events stored in this runnable. * * @return a list of all events stored in this runnable. */ public final List<T> getAllEvents() { List<T> allEvents = new ArrayList<T>(getPersistEvents().size() + getRemoveEvents().size() + getUpdateEvents().size()); allEvents.addAll(getPersistEvents()); allEvents.addAll(getRemoveEvents()); allEvents.addAll(getUpdateEvents()); return allEvents; } private boolean shouldFirePersistEvents() { return (fPersistEvents != null) && (fPersistEvents.size() > 0); } private boolean shouldFireUpdateEvents() { return (fUpdateEvents != null) && (fUpdateEvents.size() > 0); } private boolean shouldFireRemoveEvents() { return (fRemoveEvents != null) && (fRemoveEvents.size() > 0); } /** * Returns an unmodifiable list containing the persist events stored in this * runnable. * * @return an unmodifiable list of persist events. */ public final Set<T> getPersistEvents() { if (fPersistEvents == null) return Collections.emptySet(); return Collections.unmodifiableSet(fPersistEvents); } /** * Returns an unmodifiable list containing the remove events stored in this * runnable. * * @return an unmodifiable list of remove events. */ public final Set<T> getRemoveEvents() { if (fRemoveEvents == null) return Collections.emptySet(); return Collections.unmodifiableSet(fRemoveEvents); } /** * Returns an unmodifiable list containing the update events stored in this * runnable. * * @return an unmodifiable list of update events. */ public final Set<T> getUpdateEvents() { if (fUpdateEvents == null) return Collections.emptySet(); return Collections.unmodifiableSet(fUpdateEvents); } }