/* * Copyright (c) 2009-2010 Lockheed Martin Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.eurekastreams.web.client.events; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; /** * The Event Bus. * */ public class EventBus { /** * The singleton. */ private static EventBus singleton = null; /** * Last fired events. */ @SuppressWarnings("unchecked") private HashMap<Class, Object> lastFiredEvent = new HashMap<Class, Object>(); /** * Stores the observers. */ @SuppressWarnings("unchecked") private HashMap<Class, List<Observer< ? >>> observerHandlers = new HashMap<Class, List<Observer< ? >>>(); /** * Buffered observers. */ @SuppressWarnings("unchecked") private HashMap<Class, List<Observer< ? >>> bufferedObserverHandlers = new HashMap<Class, List<Observer< ? >>>(); /** * Gets an instance of the event bus. * * @return the event bus. */ public static EventBus getInstance() { if (singleton == null) { singleton = new EventBus(); } return singleton; } /** * Adds an observer. * * @param event * the event. * @param observer * the observer. */ public void addObserver(final Object event, final Observer< ? > observer) { addObserver(event.getClass(), observer); } /** * Buffer off the current observers. */ public void bufferObservers() { bufferedObserverHandlers = cloneEventMap(observerHandlers); } /** * Restore the buffered observers. */ public void restoreBufferedObservers() { observerHandlers = cloneEventMap(bufferedObserverHandlers); } /** * Clones an event map. Cannot use Map.clone() since it is a shallow copy and does not clone the lists, thus using * the same list objects in the clone as in the original, resulting in observers added after the buffering to be * retained after the restore. * * @param map * Event map to clone. * @return Cloned map. */ @SuppressWarnings("unchecked") private HashMap<Class, List<Observer< ? >>> cloneEventMap(final HashMap<Class, List<Observer< ? >>> map) { HashMap<Class, List<Observer< ? >>> newMap = new HashMap<Class, List<Observer< ? >>>(map.size()); for (Entry<Class, List<Observer< ? >>> entry : map.entrySet()) { newMap.put(entry.getKey(), new LinkedList<Observer< ? >>(entry.getValue())); } return newMap; } /** * Adds an observer. * * @param event * the event class. * @param observer * the observer. * @param fireLastEvent * fire the last known event of that type. */ public void addObserver(final Class< ? extends Object> event, final Observer< ? > observer, final Boolean fireLastEvent) { addObserver(event, observer); if (fireLastEvent) { fireLastEvent(event, observer); } } /** * Fire the last event. * * @param event * the event type. * @param observer * the observer to fire. */ @SuppressWarnings("unchecked") private void fireLastEvent(final Class< ? extends Object> event, final Observer observer) { Object lastEvent = lastFiredEvent.get(event); if (lastEvent != null) { observer.update(lastEvent); } } /** * Adds an observer to many events. * * @param events * the event classes * @param observer * the observer. */ public void addObservers(final Observer observer, final Class... events) { for (Class event : events) { addObserver(event, observer); } } /** * Adds an observer. * * @param event * the event class. * @param observer * the observer. */ public void addObserver(final Class< ? extends Object> event, final Observer< ? > observer) { if (!observerHandlers.containsKey(event)) { List<Observer< ? >> observers = new LinkedList<Observer< ? >>(); observerHandlers.put(event, observers); } observerHandlers.get(event).add(observer); } /** * Removes an observer. * * @param event * the event for which to remove the observer. * @param observer * the observer. */ public void removeObserver(final Object event, final Observer< ? > observer) { removeObserver(event.getClass(), observer); } /** * Removes an observer. * * @param event * the event class. * @param observer * the observer. */ public void removeObserver(final Class< ? extends Object> event, final Observer< ? > observer) { final List<Observer< ? >> list = observerHandlers.get(event); if (list != null) { list.remove(observer); } } /** * Remove all observers. */ public void clear() { observerHandlers.clear(); } /** * Notifies the observers that subscribe to an event. * * @param event * the event. */ @SuppressWarnings("unchecked") public void notifyObservers(final Object event) { lastFiredEvent.put(event.getClass(), event); List<Observer< ? >> observers = observerHandlers.get(event.getClass()); if (observers != null) { for (Observer observer : observers) { // TODO: Should catch here and do something with it so that an exception in one observer doesn't cause // the others to not run observer.update(event); } } } }