001/*
002 * Copyright (c) 2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-12-07 23:37:59 +0000 (Tue, 07 Dec 2010) $' 
007 * '$Revision: 26433 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.gui.state;
031
032import java.util.Hashtable;
033import java.util.Vector;
034
035import org.apache.commons.logging.Log;
036import org.apache.commons.logging.LogFactory;
037
038/**
039 * Maintain a registry of objects that are interested in changes in application
040 * state. When the application state changes (through posting a notification to
041 * this class), distribute the StateChangeEvent to all of the registered
042 * listeners. This class follows the singleton pattern because we never need or
043 * want more than a single instance to manage all of the change events.
044 * 
045 * @author Matt Jones
046 */
047public class StateChangeMonitor {
048        private static StateChangeMonitor monitor;
049        private static final Object classLock = StateChangeMonitor.class;
050        private Hashtable listeners = null;
051
052        private static Log log = LogFactory.getLog(StateChangeMonitor.class);
053
054        /**
055         * Creates a new instance of the StateChangeMonitor, and is private because
056         * this is a singleton.
057         */
058        private StateChangeMonitor() {
059                // Create the registry of StateChangeListeners
060                listeners = new Hashtable();
061        }
062
063        /**
064         * Get the single instance of the StateChangeMonitor, creating it if needed.
065         * 
066         * @return the single instance of the StateChangeMonitor
067         */
068        public static StateChangeMonitor getInstance() {
069                synchronized (classLock) {
070                        if (monitor == null) {
071                                monitor = new StateChangeMonitor();
072                        }
073                        return monitor;
074                }
075        }
076
077        /**
078         * This method is called by objects to register a listener for changes in
079         * the application state. Any change in the state will trigger notification.
080         * 
081         * @param stateChange
082         *            the name of the state change for which notifications should be
083         *            sent
084         * @param listener
085         *            a reference to the object to be notified of changes
086         */
087        public void addStateChangeListener(String stateChange,
088                        StateChangeListener listener) {
089                Vector currentStateListeners = null;
090                if (!listeners.containsKey(stateChange)) {
091                        log.debug("Adding state vector: " + stateChange);
092                        currentStateListeners = new Vector();
093                        listeners.put(stateChange, currentStateListeners);
094                } else {
095                        currentStateListeners = (Vector) listeners.get(stateChange);
096                }
097
098                if (!currentStateListeners.contains(listener)) {
099                        log.debug("Adding listener: " + listener.toString());
100                        currentStateListeners.addElement(listener);
101                }
102        }
103
104        /**
105         * This method is called by objects to remove a listener for changes in the
106         * application state. Any change in the state will trigger notification.
107         * 
108         * @param stateChange
109         *            the name of the state change for which the listener should be
110         *            removed
111         * @param listener
112         *            a reference to the object to be removed
113         */
114        public void removeStateChangeListener(String stateChange,
115                        StateChangeListener listener) {
116                Vector currentStateListeners = null;
117                if (listeners.containsKey(stateChange)) {
118                        currentStateListeners = (Vector) listeners.get(stateChange);
119                        log.debug("Removing listener: " + listener.toString());
120                        currentStateListeners.removeElement(listener);
121                        if (currentStateListeners.size() == 0) {
122                                listeners.remove(stateChange);
123                        }
124                }
125        }
126
127        /**
128         * Notify the monitor of an application state change so that it in turn can
129         * notify all of the registered listeners of that state change.
130         * 
131         * @param event
132         *            the StateChangeEvent that has occurred
133         */
134        public void notifyStateChange(StateChangeEvent event) {
135                String stateChange = event.getChangedState();
136                Vector currentStateListeners = null;
137                if (listeners.containsKey(stateChange)) {
138                        currentStateListeners = (Vector) listeners.get(stateChange);
139                        for (int i = 0; i < currentStateListeners.size(); i++) {
140                                StateChangeListener listener = (StateChangeListener) currentStateListeners
141                                                .elementAt(i);
142                                if (listener != null) {
143                                        listener.handleStateChange(event);
144                                }
145                        }
146                }
147        }
148}