001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.beans;
019:
020: import java.io.IOException;
021: import java.io.ObjectInputStream;
022: import java.io.ObjectOutputStream;
023: import java.io.Serializable;
024: import java.util.ArrayList;
025: import java.util.Hashtable;
026: import java.util.LinkedList;
027: import java.util.List;
028:
029: public class PropertyChangeSupport implements Serializable {
030:
031: private static final long serialVersionUID = 6401253773779951803l;
032:
033: private transient List<PropertyChangeListener> globalListeners = new ArrayList<PropertyChangeListener>();
034:
035: private Hashtable<String, PropertyChangeSupport> children = new Hashtable<String, PropertyChangeSupport>();
036:
037: private Object source;
038:
039: @SuppressWarnings("unused")
040: // for serialization compatibility
041: private int propertyChangeSupportSerializedDataVersion = 1;
042:
043: public PropertyChangeSupport(Object sourceBean) {
044: if (sourceBean == null) {
045: throw new NullPointerException();
046: }
047: this .source = sourceBean;
048: }
049:
050: public void firePropertyChange(String propertyName,
051: Object oldValue, Object newValue) {
052: PropertyChangeEvent event = createPropertyChangeEvent(
053: propertyName, oldValue, newValue);
054: doFirePropertyChange(event);
055: }
056:
057: public void fireIndexedPropertyChange(String propertyName,
058: int index, Object oldValue, Object newValue) {
059:
060: // nulls and equals check done in doFire...
061: doFirePropertyChange(new IndexedPropertyChangeEvent(source,
062: propertyName, oldValue, newValue, index));
063: }
064:
065: public synchronized void removePropertyChangeListener(
066: String propertyName, PropertyChangeListener listener) {
067: if ((propertyName != null) && (listener != null)) {
068: PropertyChangeSupport listeners = children
069: .get(propertyName);
070:
071: if (listeners != null) {
072: listeners.removePropertyChangeListener(listener);
073: }
074: }
075: }
076:
077: public synchronized void addPropertyChangeListener(
078: String propertyName, PropertyChangeListener listener) {
079: if ((listener != null) && (propertyName != null)) {
080: PropertyChangeSupport listeners = children
081: .get(propertyName);
082:
083: if (listeners == null) {
084: listeners = new PropertyChangeSupport(source);
085: children.put(propertyName, listeners);
086: }
087:
088: // RI compatibility
089: if (listener instanceof PropertyChangeListenerProxy) {
090: PropertyChangeListenerProxy proxy = (PropertyChangeListenerProxy) listener;
091:
092: listeners
093: .addPropertyChangeListener(new PropertyChangeListenerProxy(
094: proxy.getPropertyName(),
095: (PropertyChangeListener) proxy
096: .getListener()));
097: } else {
098: listeners.addPropertyChangeListener(listener);
099: }
100: }
101: }
102:
103: public synchronized PropertyChangeListener[] getPropertyChangeListeners(
104: String propertyName) {
105: PropertyChangeSupport listeners = null;
106:
107: if (propertyName != null) {
108: listeners = children.get(propertyName);
109: }
110:
111: return (listeners == null) ? new PropertyChangeListener[0]
112: : listeners.getPropertyChangeListeners();
113: }
114:
115: public void firePropertyChange(String propertyName,
116: boolean oldValue, boolean newValue) {
117: PropertyChangeEvent event = createPropertyChangeEvent(
118: propertyName, oldValue, newValue);
119: doFirePropertyChange(event);
120: }
121:
122: public void fireIndexedPropertyChange(String propertyName,
123: int index, boolean oldValue, boolean newValue) {
124:
125: if (oldValue != newValue) {
126: fireIndexedPropertyChange(propertyName, index, Boolean
127: .valueOf(oldValue), Boolean.valueOf(newValue));
128: }
129: }
130:
131: public void firePropertyChange(String propertyName, int oldValue,
132: int newValue) {
133: PropertyChangeEvent event = createPropertyChangeEvent(
134: propertyName, oldValue, newValue);
135: doFirePropertyChange(event);
136: }
137:
138: public void fireIndexedPropertyChange(String propertyName,
139: int index, int oldValue, int newValue) {
140:
141: if (oldValue != newValue) {
142: fireIndexedPropertyChange(propertyName, index, new Integer(
143: oldValue), new Integer(newValue));
144: }
145: }
146:
147: public synchronized boolean hasListeners(String propertyName) {
148: if (globalListeners.size() > 0) {
149: return true;
150: }
151: boolean result = false;
152: if (propertyName != null) {
153: PropertyChangeSupport listeners = children
154: .get(propertyName);
155: result = (listeners != null && listeners
156: .hasListeners(propertyName));
157: }
158: return result;
159: }
160:
161: public synchronized void removePropertyChangeListener(
162: PropertyChangeListener listener) {
163: if (listener instanceof PropertyChangeListenerProxy) {
164: String name = ((PropertyChangeListenerProxy) listener)
165: .getPropertyName();
166: PropertyChangeListener lst = (PropertyChangeListener) ((PropertyChangeListenerProxy) listener)
167: .getListener();
168:
169: removePropertyChangeListener(name, lst);
170: } else {
171: globalListeners.remove(listener);
172: }
173: }
174:
175: public synchronized void addPropertyChangeListener(
176: PropertyChangeListener listener) {
177: if (listener instanceof PropertyChangeListenerProxy) {
178: String name = ((PropertyChangeListenerProxy) listener)
179: .getPropertyName();
180: PropertyChangeListener lst = (PropertyChangeListener) ((PropertyChangeListenerProxy) listener)
181: .getListener();
182: addPropertyChangeListener(name, lst);
183: } else if (listener != null) {
184: globalListeners.add(listener);
185: }
186: }
187:
188: public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
189: ArrayList<PropertyChangeListener> result = new ArrayList<PropertyChangeListener>(
190: globalListeners);
191: for (String propertyName : children.keySet()) {
192: PropertyChangeSupport namedListener = children
193: .get(propertyName);
194: PropertyChangeListener[] listeners = namedListener
195: .getPropertyChangeListeners();
196: for (int i = 0; i < listeners.length; i++) {
197: result.add(new PropertyChangeListenerProxy(
198: propertyName, listeners[i]));
199: }
200: }
201: return result.toArray(new PropertyChangeListener[0]);
202: }
203:
204: private void writeObject(ObjectOutputStream oos) throws IOException {
205: oos.defaultWriteObject();
206: PropertyChangeListener[] gListeners = globalListeners
207: .toArray(new PropertyChangeListener[0]);
208: for (int i = 0; i < gListeners.length; i++) {
209: if (gListeners[i] instanceof Serializable) {
210: oos.writeObject(gListeners[i]);
211: }
212: }
213: // Denotes end of list
214: oos.writeObject(null);
215:
216: }
217:
218: private void readObject(ObjectInputStream ois) throws IOException,
219: ClassNotFoundException {
220: ois.defaultReadObject();
221: this .globalListeners = new LinkedList<PropertyChangeListener>();
222: if (null == this .children) {
223: this .children = new Hashtable<String, PropertyChangeSupport>();
224: }
225: Object listener = null;
226: do {
227: // Reads a listener _or_ proxy
228: listener = ois.readObject();
229: if (listener != null) {
230: addPropertyChangeListener((PropertyChangeListener) listener);
231: }
232: } while (listener != null);
233: }
234:
235: public void firePropertyChange(PropertyChangeEvent event) {
236: doFirePropertyChange(event);
237: }
238:
239: private PropertyChangeEvent createPropertyChangeEvent(
240: String propertyName, Object oldValue, Object newValue) {
241: return new PropertyChangeEvent(source, propertyName, oldValue,
242: newValue);
243: }
244:
245: @SuppressWarnings("boxing")
246: private PropertyChangeEvent createPropertyChangeEvent(
247: String propertyName, boolean oldValue, boolean newValue) {
248: return new PropertyChangeEvent(source, propertyName, oldValue,
249: newValue);
250: }
251:
252: @SuppressWarnings("boxing")
253: private PropertyChangeEvent createPropertyChangeEvent(
254: String propertyName, int oldValue, int newValue) {
255: return new PropertyChangeEvent(source, propertyName, oldValue,
256: newValue);
257: }
258:
259: private void doFirePropertyChange(PropertyChangeEvent event) {
260: Object oldValue = event.getOldValue();
261: Object newValue = event.getNewValue();
262: if (oldValue != null && newValue != null
263: && oldValue.equals(newValue)) {
264: return;
265: }
266:
267: // Collect up the global listeners
268: PropertyChangeListener[] gListeners = globalListeners
269: .toArray(new PropertyChangeListener[0]);
270: // Fire the events for global listeners
271: for (int i = 0; i < gListeners.length; i++) {
272: gListeners[i].propertyChange(event);
273: }
274:
275: // Fire the events for the property specific listeners if any
276: if (event.getPropertyName() != null) {
277: PropertyChangeSupport namedListener = children.get(event
278: .getPropertyName());
279: if (namedListener != null) {
280: namedListener.firePropertyChange(event);
281: }
282: }
283:
284: }
285:
286: }
|