/* * Copyright 2005 the original author or authors. * * 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.wamblee.observer; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * Implements subscription and notification logic for an observer pattern. This * class is thread safe. */ public class Observable { private static final Logger LOGGER = Logger.getLogger(Observable.class); /** * Observable. */ private ObservableType observable; /** * Used to notify observers. */ private ObserverNotifier notifier; /** * Map of subscription to observer. */ private Map> observers; /** * Counter for subscriptions. Holds the next subscription. */ private long counter; /** * Constructs the observable. * * @param aObservable * Observable this instance is used for. * @param aNotifier * Object used for implementing notification of listeners. */ public Observable(ObservableType aObservable, ObserverNotifier aNotifier) { observable = aObservable; notifier = aNotifier; observers = new TreeMap>(); counter = 0; } /** * Subscribe an obvers. * * @param aObserver * Observer to subscribe. * @return Event Event to send. */ public synchronized long subscribe( Observer aObserver) { long subscription = counter++; // integer rage is so large it will // never roll over. observers.put(subscription, aObserver); return subscription; } /** * Unsubscribe an observer. * * @param aSubscription * Subscription which is used * @throws IllegalArgumentException * In case the subscription is not known. */ public synchronized void unsubscribe(long aSubscription) { Object obj = observers.remove(aSubscription); if (obj == null) { throw new IllegalArgumentException("Subscription '" + aSubscription + "'"); } } /** * Gets the number of subscribed observers. * * @return Number of subscribed observers. */ public int getObserverCount() { return observers.size(); } /** * Notifies all subscribed observers. * * @param aEvent * Event to send. */ public void send(Event aEvent) { // Make sure we do the notification while not holding the lock to avoid // potential deadlock // situations. List> myObservers = new ArrayList>(); synchronized (this) { myObservers.addAll(observers.values()); } for (Observer observer : myObservers) { notifier.update(observer, observable, aEvent); } } /* * (non-Javadoc) * * @see java.lang.Object#finalize() */ @Override protected void finalize() throws Throwable { if (observers.size() > 0) { LOGGER.error( "Still observers registered at finalization of observer!"); for (Observer observer : observers.values()) { LOGGER.error(" observer: " + observer); } } super.finalize(); } }