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}