Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/eireneh/util/EventListenerList.java


1   
2   package com.eireneh.util;
3   
4   import java.io.*;
5   import java.util.*;
6   
7   /**
8    * A class which holds a list of EventListeners.
9    * This code is lifted from javax.sw*ng.event.EventListnerList. It is
10   * very useful in non GUI code which does not need the rest of sw*ng.
11   * So I copied it here to save the need for sw*ngall.jar
12   * 
13   * <p>A single instance
14   * can be used to hold all listeners (of all types) for the instance
15   * using the lsit.  It is the responsiblity of the class using the
16   * EventListenerList to provide type-safe API (preferably conforming
17   * to the JavaBeans spec) and methods which dispatch event notification
18   * methods to appropriate Event Listeners on the list.
19   * 
20   * The main benefits which this class provides are that it is relatively
21   * cheap in the case of no listeners, and provides serialization for 
22   * eventlistener lists in a single place, as well as a degree of MT safety
23   * (when used correctly).
24   *
25   * Usage example:
26   *    Say one is defining a class which sends out FooEvents, and wantds
27   * to allow users of the class to register FooListeners and receive 
28   * notification when FooEvents occur.  The following should be added
29   * to the class definition:
30     <pre>
31     EventListenerList listenrList = new EventListnerList();
32     FooEvent fooEvent = null;
33  
34     public void addFooListener(FooListener l) {
35         listenerList.add(FooListener.class, l);
36     }
37  
38     public void removeFooListener(FooListener l) {
39         listenerList.remove(FooListener.class, l);
40     }
41  
42   
43      // Notify all listeners that have registered interest for
44      // notification on this event type.  The event instance 
45      // is lazily created using the parameters passed into 
46      // the fire method.
47  
48      protected void firefooXXX() {
49    // Guaranteed to return a non-null array
50    Object[] listeners = listenerList.getListenerList();
51    // Process the listeners last to first, notifying
52    // those that are interested in this event
53    for (int i = listeners.length-2; i>=0; i-=2) {
54        if (listeners[i]==FooListener.class) {
55      // Lazily create the event:
56      if (fooEvent == null)
57          fooEvent = new FooEvent(this);
58      ((FooListener)listeners[i+1]).fooXXX(fooEvent);
59        }         
60    }
61      }  
62     </pre>
63   * foo should be changed to the appropriate name, and Method to the
64   * appropriate method name (one fire method should exist for each
65   * notification method in the FooListener interface).
66   * <p>
67   * <strong>Warning:</strong>
68   * Serialized objects of this class will not be compatible with 
69   * future Sw*ng releases.  The current serialization support is appropriate
70   * for short term storage or RMI between applications running the same
71   * version of Sw*ng.  A future release of Sw*ng will provide support for
72   * long term persistence.
73   *
74   * @version 1.23 10/01/98
75   * @author Georges Saab
76   * @author Hans Muller
77   * @author James Gosling
78   */
79  public class EventListenerList implements Serializable {
80      /* A null array to be shared by all empty listener lists*/
81      private final static Object[] NULL_ARRAY = new Object[0];
82      /* The list of ListenerType - Listener pairs */
83      protected transient Object[] listenerList = NULL_ARRAY;
84  
85      /**
86       * This passes back the event listener list as an array
87       * of ListenerType - listener pairs.  Note that for 
88       * performance reasons, this implementation passes back 
89       * the actual data structure in which the listner data
90       * is stored internally!  
91       * This method is guaranteed to pass back a non-null
92       * array, so that no null-checking is required in 
93       * fire methods.  A zero-length array of Object should
94       * be returned if there are currently no listeners.
95       * 
96       * WARNING!!! Absolutely NO modification of
97       * the data contained in this array should be made -- if
98       * any such manipulation is necessary, it should be done
99       * on a copy of the array returned rather than the array 
100      * itself.
101      */
102     public Object[] getListenerList() {
103   return listenerList;
104     }
105 
106     /**
107      * Return the total number of listeners for this listenerlist
108      */
109     public int getListenerCount() {
110   return listenerList.length/2;
111     }
112 
113     /**
114      * Return the total number of listeners of the supplied type 
115      * for this listenerlist.
116      */
117     public int getListenerCount(Class t) {
118   int count = 0;
119   Object[] lList = listenerList;
120   for (int i = 0; i < lList.length; i+=2) {
121       if (t == (Class)lList[i])
122     count++;
123   }
124   return count;
125     }
126     /**
127      * Add the listener as a listener of the specified type.
128      * @param t the type of the listener to be added
129      * @param l the listener to be added
130      */
131     public synchronized void add(Class t, EventListener l) {
132   if (l==null) {
133       // In an ideal world, we would do an assertion here
134       // to help developers know they are probably doing
135       // something wrong
136       return;
137   }
138   if (!t.isInstance(l)) {
139       throw new IllegalArgumentException("Listener " + l +
140            " is not of type " + t);
141   }
142   if (listenerList == NULL_ARRAY) {
143       // if this is the first listener added, 
144       // initialize the lists
145       listenerList = new Object[] { t, l };
146   } else {
147       // Otherwise copy the array and add the new listener
148       int i = listenerList.length;
149       Object[] tmp = new Object[i+2];
150       System.arraycopy(listenerList, 0, tmp, 0, i);
151 
152       tmp[i] = t;
153       tmp[i+1] = l;
154 
155       listenerList = tmp;
156   }
157     }
158 
159     /**
160      * Remove the listener as a listener of the specified type.
161      * @param t the type of the listener to be removed
162      * @param l the listener to be removed
163      */
164     public synchronized void remove(Class t, EventListener l) {
165   if (l ==null) {
166       // In an ideal world, we would do an assertion here
167       // to help developers know they are probably doing
168       // something wrong
169       return;
170   }
171   if (!t.isInstance(l)) {
172       throw new IllegalArgumentException("Listener " + l +
173            " is not of type " + t);
174   }
175   // Is l on the list?
176   int index = -1;
177   for (int i = listenerList.length-2; i>=0; i-=2) {
178       if ((listenerList[i]==t) && (listenerList[i+1].equals(l) == true)) {
179     index = i;
180     break;
181       }
182   }
183   
184   // If so,  remove it
185   if (index != -1) {
186       Object[] tmp = new Object[listenerList.length-2];
187       // Copy the list up to index
188       System.arraycopy(listenerList, 0, tmp, 0, index);
189       // Copy from two past the index, up to
190       // the end of tmp (which is two elements
191       // shorter than the old list)
192       if (index < tmp.length)
193     System.arraycopy(listenerList, index+2, tmp, index, 
194          tmp.length - index);
195       // set the listener array to the new array or null
196       listenerList = (tmp.length == 0) ? NULL_ARRAY : tmp;
197       }
198     }
199 
200     // Serialization support.  
201     private void writeObject(ObjectOutputStream s) throws IOException {
202   Object[] lList = listenerList;
203   s.defaultWriteObject();
204   
205   // Save the non-null event listeners:
206   for (int i = 0; i < lList.length; i+=2) {
207       Class t = (Class)lList[i];
208       EventListener l = (EventListener)lList[i+1];
209       if ((l!=null) && (l instanceof Serializable)) {
210     s.writeObject(t.getName());
211     s.writeObject(l);
212       }
213   }
214   
215   s.writeObject(null);
216     }
217 
218     private void readObject(ObjectInputStream s) 
219   throws IOException, ClassNotFoundException {
220         listenerList = NULL_ARRAY;
221   s.defaultReadObject();
222   Object listenerTypeOrNull;
223   
224   while (null != (listenerTypeOrNull = s.readObject())) {
225       EventListener l = (EventListener)s.readObject();
226       add(Class.forName((String)listenerTypeOrNull), l);
227   }      
228     }
229 
230     /**
231      * Return a string representation of the EventListenerList.
232      */
233     public String toString() {
234   Object[] lList = listenerList;
235   String s = "EventListenerList: ";
236   s += lList.length/2 + " listeners: ";
237   for (int i = 0 ; i <= lList.length-2 ; i+=2) {
238       s += " type " + ((Class)lList[i]).getName();
239       s += " listener " + lList[i+1];
240   }
241   return s;
242     }
243 }