/*- * Copyright © 2009 Diamond Light Source Ltd., Science and Technology * Facilities Council Daresbury Laboratory * * This file is part of GDA. * * GDA is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License version 3 as published by the Free * Software Foundation. * * GDA 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 GDA. If not, see <http://www.gnu.org/licenses/>. */ package gda.observable; import java.util.HashMap; import java.util.Map; import java.util.Vector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A Component that may be used by Observable objects to maintain its list of Observers * DO NOT synchronize the methods of this class as doing so in the past led to deadlocks when used with DOFS and AbosulteMove objects */ public class ObservableUtil<E> implements Observable<E>, IIsBeingObserved { private Vector<Observer<E>> myObservers = new Vector<Observer<E>>(); private Map<Observer<E>, Predicate<E>> observersPredicates = new HashMap<Observer<E>, Predicate<E>>(); private static final Logger logger = LoggerFactory.getLogger(ObservableUtil.class); /** * Add an observer to the list of observers providing that the list does not already contain an instance of the * observer on it. If a predicate was associated with this observer then remove it. {@inheritDoc} * * @param observer * the observer * @see gda.observable.Observable#addObserver(gda.observable.Observer) */ @Override public void addObserver(Observer<E> observer) { if (observer == null) return; synchronized(myObservers){ if (!myObservers.contains(observer)){ myObservers.addElement(observer); } observersPredicates.remove(observer); } } /** * Add an observer to the list of observers providing that the list does not already contain an instance of the * observer on it. Either way, associate the specified predicate with the observer. {@inheritDoc} * * @param observer * the observer * @see gda.observable.Observable#addObserver(gda.observable.Observer) */ @Override public void addObserver(Observer<E> observer, Predicate<E> predicate) { if (observer == null) return; synchronized(myObservers){ if (!myObservers.contains(observer)){ myObservers.addElement(observer); } observersPredicates.put(observer, predicate); } } /** * Delete the instance of this observer from the list observers. {@inheritDoc} * * @param observer * the observer * @see gda.observable.Observable#removeObserver(gda.observable.Observer) */ @Override public void removeObserver(Observer<E> observer) { if (observer == null) return; synchronized(myObservers){ myObservers.removeElement(observer); observersPredicates.remove(observer); } } /** * Delete all observers from the list of observers. */ public void deleteIObservers() { synchronized(myObservers){ myObservers.removeAllElements(); observersPredicates.clear(); } } /** * Notify all observers on the list of the requested change. * * @param theObserved * the observed component * @param changeCode * the data to be sent to the observer. */ @SuppressWarnings("unchecked") public void notifyIObservers(Observable<E> theObserved, E changeCode) { Observer<E>[] observers; synchronized(myObservers){ observers = (Observer<E>[]) myObservers.toArray(new Observer<?>[0]); } for (Observer<E> observer : observers) { try { Predicate<E> predicate = observersPredicates.get(observer); if (predicate != null) { // if predicate is configured and it is *not* true then don't send the update. if (!predicate.apply(changeCode)) { return; } } observer.update(theObserved, changeCode); } catch (Exception ex) { logger.error("notifyIObservers of " + theObserved.toString(), ex); } } } @Override public boolean IsBeingObserved() { return !myObservers.isEmpty(); } }