1/*
2 * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package java.awt;
26
27import java.awt.event.*;
28import java.lang.reflect.Array;
29import java.util.EventListener;
30import java.io.Serializable;
31import java.io.ObjectOutputStream;
32import java.io.IOException;
33import java.util.EventListener;
34
35
36/**
37 * {@code AWTEventMulticaster} implements efficient and thread-safe multi-cast
38 * event dispatching for the AWT events defined in the {@code java.awt.event}
39 * package.
40 * <p>
41 * The following example illustrates how to use this class:
42 *
43 * <pre><code>
44 * public myComponent extends Component {
45 *     ActionListener actionListener = null;
46 *
47 *     public synchronized void addActionListener(ActionListener l) {
48 *         actionListener = AWTEventMulticaster.add(actionListener, l);
49 *     }
50 *     public synchronized void removeActionListener(ActionListener l) {
51 *         actionListener = AWTEventMulticaster.remove(actionListener, l);
52 *     }
53 *     public void processEvent(AWTEvent e) {
54 *         // when event occurs which causes "action" semantic
55 *         ActionListener listener = actionListener;
56 *         if (listener != null) {
57 *             listener.actionPerformed(new ActionEvent());
58 *         }
59 *     }
60 * }
61 * </code></pre>
62 * The important point to note is the first argument to the {@code
63 * add} and {@code remove} methods is the field maintaining the
64 * listeners. In addition you must assign the result of the {@code add}
65 * and {@code remove} methods to the field maintaining the listeners.
66 * <p>
67 * {@code AWTEventMulticaster} is implemented as a pair of {@code
68 * EventListeners} that are set at construction time. {@code
69 * AWTEventMulticaster} is immutable. The {@code add} and {@code
70 * remove} methods do not alter {@code AWTEventMulticaster} in
71 * anyway. If necessary, a new {@code AWTEventMulticaster} is
72 * created. In this way it is safe to add and remove listeners during
73 * the process of an event dispatching.  However, event listeners
74 * added during the process of an event dispatch operation are not
75 * notified of the event currently being dispatched.
76 * <p>
77 * All of the {@code add} methods allow {@code null} arguments. If the
78 * first argument is {@code null}, the second argument is returned. If
79 * the first argument is not {@code null} and the second argument is
80 * {@code null}, the first argument is returned. If both arguments are
81 * {@code non-null}, a new {@code AWTEventMulticaster} is created using
82 * the two arguments and returned.
83 * <p>
84 * For the {@code remove} methods that take two arguments, the following is
85 * returned:
86 * <ul>
87 *   <li>{@code null}, if the first argument is {@code null}, or
88 *       the arguments are equal, by way of {@code ==}.
89 *   <li>the first argument, if the first argument is not an instance of
90 *       {@code AWTEventMulticaster}.
91 *   <li>result of invoking {@code remove(EventListener)} on the
92 *       first argument, supplying the second argument to the
93 *       {@code remove(EventListener)} method.
94 * </ul>
95 * <p>Swing makes use of
96 * {@link javax.swing.event.EventListenerList EventListenerList} for
97 * similar logic. Refer to it for details.
98 *
99 * @see javax.swing.event.EventListenerList
100 *
101 * @author      John Rose
102 * @author      Amy Fowler
103 * @since       1.1
104 */
105
106public class AWTEventMulticaster implements
107    ComponentListener, ContainerListener, FocusListener, KeyListener,
108    MouseListener, MouseMotionListener, WindowListener, WindowFocusListener,
109    WindowStateListener, ActionListener, ItemListener, AdjustmentListener,
110    TextListener, InputMethodListener, HierarchyListener,
111    HierarchyBoundsListener, MouseWheelListener {
112
113    /**
114     * A variable in the event chain (listener-a)
115     */
116    protected final EventListener a;
117
118    /**
119     * A variable in the event chain (listener-b)
120     */
121    protected final EventListener b;
122
123    /**
124     * Creates an event multicaster instance which chains listener-a
125     * with listener-b. Input parameters {@code a} and {@code b}
126     * should not be {@code null}, though implementations may vary in
127     * choosing whether or not to throw {@code NullPointerException}
128     * in that case.
129     * @param a listener-a
130     * @param b listener-b
131     */
132    protected AWTEventMulticaster(EventListener a, EventListener b) {
133        this.a = a; this.b = b;
134    }
135
136    /**
137     * Removes a listener from this multicaster.
138     * <p>
139     * The returned multicaster contains all the listeners in this
140     * multicaster with the exception of all occurrences of {@code oldl}.
141     * If the resulting multicaster contains only one regular listener
142     * the regular listener may be returned.  If the resulting multicaster
143     * is empty, then {@code null} may be returned instead.
144     * <p>
145     * No exception is thrown if {@code oldl} is {@code null}.
146     *
147     * @param oldl the listener to be removed
148     * @return resulting listener
149     */
150    protected EventListener remove(EventListener oldl) {
151        if (oldl == a)  return b;
152        if (oldl == b)  return a;
153        EventListener a2 = removeInternal(a, oldl);
154        EventListener b2 = removeInternal(b, oldl);
155        if (a2 == a && b2 == b) {
156            return this;        // it's not here
157        }
158        return addInternal(a2, b2);
159    }
160
161    /**
162     * Handles the componentResized event by invoking the
163     * componentResized methods on listener-a and listener-b.
164     * @param e the component event
165     */
166    public void componentResized(ComponentEvent e) {
167        ((ComponentListener)a).componentResized(e);
168        ((ComponentListener)b).componentResized(e);
169    }
170
171    /**
172     * Handles the componentMoved event by invoking the
173     * componentMoved methods on listener-a and listener-b.
174     * @param e the component event
175     */
176    public void componentMoved(ComponentEvent e) {
177        ((ComponentListener)a).componentMoved(e);
178        ((ComponentListener)b).componentMoved(e);
179    }
180
181    /**
182     * Handles the componentShown event by invoking the
183     * componentShown methods on listener-a and listener-b.
184     * @param e the component event
185     */
186    public void componentShown(ComponentEvent e) {
187        ((ComponentListener)a).componentShown(e);
188        ((ComponentListener)b).componentShown(e);
189    }
190
191    /**
192     * Handles the componentHidden event by invoking the
193     * componentHidden methods on listener-a and listener-b.
194     * @param e the component event
195     */
196    public void componentHidden(ComponentEvent e) {
197        ((ComponentListener)a).componentHidden(e);
198        ((ComponentListener)b).componentHidden(e);
199    }
200
201    /**
202     * Handles the componentAdded container event by invoking the
203     * componentAdded methods on listener-a and listener-b.
204     * @param e the component event
205     */
206    public void componentAdded(ContainerEvent e) {
207        ((ContainerListener)a).componentAdded(e);
208        ((ContainerListener)b).componentAdded(e);
209    }
210
211    /**
212     * Handles the componentRemoved container event by invoking the
213     * componentRemoved methods on listener-a and listener-b.
214     * @param e the component event
215     */
216    public void componentRemoved(ContainerEvent e) {
217        ((ContainerListener)a).componentRemoved(e);
218        ((ContainerListener)b).componentRemoved(e);
219    }
220
221    /**
222     * Handles the focusGained event by invoking the
223     * focusGained methods on listener-a and listener-b.
224     * @param e the focus event
225     */
226    public void focusGained(FocusEvent e) {
227        ((FocusListener)a).focusGained(e);
228        ((FocusListener)b).focusGained(e);
229    }
230
231    /**
232     * Handles the focusLost event by invoking the
233     * focusLost methods on listener-a and listener-b.
234     * @param e the focus event
235     */
236    public void focusLost(FocusEvent e) {
237        ((FocusListener)a).focusLost(e);
238        ((FocusListener)b).focusLost(e);
239    }
240
241    /**
242     * Handles the keyTyped event by invoking the
243     * keyTyped methods on listener-a and listener-b.
244     * @param e the key event
245     */
246    public void keyTyped(KeyEvent e) {
247        ((KeyListener)a).keyTyped(e);
248        ((KeyListener)b).keyTyped(e);
249    }
250
251    /**
252     * Handles the keyPressed event by invoking the
253     * keyPressed methods on listener-a and listener-b.
254     * @param e the key event
255     */
256    public void keyPressed(KeyEvent e) {
257        ((KeyListener)a).keyPressed(e);
258        ((KeyListener)b).keyPressed(e);
259    }
260
261    /**
262     * Handles the keyReleased event by invoking the
263     * keyReleased methods on listener-a and listener-b.
264     * @param e the key event
265     */
266    public void keyReleased(KeyEvent e) {
267        ((KeyListener)a).keyReleased(e);
268        ((KeyListener)b).keyReleased(e);
269    }
270
271    /**
272     * Handles the mouseClicked event by invoking the
273     * mouseClicked methods on listener-a and listener-b.
274     * @param e the mouse event
275     */
276    public void mouseClicked(MouseEvent e) {
277        ((MouseListener)a).mouseClicked(e);
278        ((MouseListener)b).mouseClicked(e);
279    }
280
281    /**
282     * Handles the mousePressed event by invoking the
283     * mousePressed methods on listener-a and listener-b.
284     * @param e the mouse event
285     */
286    public void mousePressed(MouseEvent e) {
287        ((MouseListener)a).mousePressed(e);
288        ((MouseListener)b).mousePressed(e);
289    }
290
291    /**
292     * Handles the mouseReleased event by invoking the
293     * mouseReleased methods on listener-a and listener-b.
294     * @param e the mouse event
295     */
296    public void mouseReleased(MouseEvent e) {
297        ((MouseListener)a).mouseReleased(e);
298        ((MouseListener)b).mouseReleased(e);
299    }
300
301    /**
302     * Handles the mouseEntered event by invoking the
303     * mouseEntered methods on listener-a and listener-b.
304     * @param e the mouse event
305     */
306    public void mouseEntered(MouseEvent e) {
307        ((MouseListener)a).mouseEntered(e);
308        ((MouseListener)b).mouseEntered(e);
309    }
310
311    /**
312     * Handles the mouseExited event by invoking the
313     * mouseExited methods on listener-a and listener-b.
314     * @param e the mouse event
315     */
316    public void mouseExited(MouseEvent e) {
317        ((MouseListener)a).mouseExited(e);
318        ((MouseListener)b).mouseExited(e);
319    }
320
321    /**
322     * Handles the mouseDragged event by invoking the
323     * mouseDragged methods on listener-a and listener-b.
324     * @param e the mouse event
325     */
326    public void mouseDragged(MouseEvent e) {
327        ((MouseMotionListener)a).mouseDragged(e);
328        ((MouseMotionListener)b).mouseDragged(e);
329    }
330
331    /**
332     * Handles the mouseMoved event by invoking the
333     * mouseMoved methods on listener-a and listener-b.
334     * @param e the mouse event
335     */
336    public void mouseMoved(MouseEvent e) {
337        ((MouseMotionListener)a).mouseMoved(e);
338        ((MouseMotionListener)b).mouseMoved(e);
339    }
340
341    /**
342     * Handles the windowOpened event by invoking the
343     * windowOpened methods on listener-a and listener-b.
344     * @param e the window event
345     */
346    public void windowOpened(WindowEvent e) {
347        ((WindowListener)a).windowOpened(e);
348        ((WindowListener)b).windowOpened(e);
349    }
350
351    /**
352     * Handles the windowClosing event by invoking the
353     * windowClosing methods on listener-a and listener-b.
354     * @param e the window event
355     */
356    public void windowClosing(WindowEvent e) {
357        ((WindowListener)a).windowClosing(e);
358        ((WindowListener)b).windowClosing(e);
359    }
360
361    /**
362     * Handles the windowClosed event by invoking the
363     * windowClosed methods on listener-a and listener-b.
364     * @param e the window event
365     */
366    public void windowClosed(WindowEvent e) {
367        ((WindowListener)a).windowClosed(e);
368        ((WindowListener)b).windowClosed(e);
369    }
370
371    /**
372     * Handles the windowIconified event by invoking the
373     * windowIconified methods on listener-a and listener-b.
374     * @param e the window event
375     */
376    public void windowIconified(WindowEvent e) {
377        ((WindowListener)a).windowIconified(e);
378        ((WindowListener)b).windowIconified(e);
379    }
380
381    /**
382     * Handles the windowDeiconified event by invoking the
383     * windowDeiconified methods on listener-a and listener-b.
384     * @param e the window event
385     */
386    public void windowDeiconified(WindowEvent e) {
387        ((WindowListener)a).windowDeiconified(e);
388        ((WindowListener)b).windowDeiconified(e);
389    }
390
391    /**
392     * Handles the windowActivated event by invoking the
393     * windowActivated methods on listener-a and listener-b.
394     * @param e the window event
395     */
396    public void windowActivated(WindowEvent e) {
397        ((WindowListener)a).windowActivated(e);
398        ((WindowListener)b).windowActivated(e);
399    }
400
401    /**
402     * Handles the windowDeactivated event by invoking the
403     * windowDeactivated methods on listener-a and listener-b.
404     * @param e the window event
405     */
406    public void windowDeactivated(WindowEvent e) {
407        ((WindowListener)a).windowDeactivated(e);
408        ((WindowListener)b).windowDeactivated(e);
409    }
410
411    /**
412     * Handles the windowStateChanged event by invoking the
413     * windowStateChanged methods on listener-a and listener-b.
414     * @param e the window event
415     * @since 1.4
416     */
417    public void windowStateChanged(WindowEvent e) {
418        ((WindowStateListener)a).windowStateChanged(e);
419        ((WindowStateListener)b).windowStateChanged(e);
420    }
421
422
423    /**
424     * Handles the windowGainedFocus event by invoking the windowGainedFocus
425     * methods on listener-a and listener-b.
426     * @param e the window event
427     * @since 1.4
428     */
429    public void windowGainedFocus(WindowEvent e) {
430        ((WindowFocusListener)a).windowGainedFocus(e);
431        ((WindowFocusListener)b).windowGainedFocus(e);
432    }
433
434    /**
435     * Handles the windowLostFocus event by invoking the windowLostFocus
436     * methods on listener-a and listener-b.
437     * @param e the window event
438     * @since 1.4
439     */
440    public void windowLostFocus(WindowEvent e) {
441        ((WindowFocusListener)a).windowLostFocus(e);
442        ((WindowFocusListener)b).windowLostFocus(e);
443    }
444
445    /**
446     * Handles the actionPerformed event by invoking the
447     * actionPerformed methods on listener-a and listener-b.
448     * @param e the action event
449     */
450    public void actionPerformed(ActionEvent e) {
451        ((ActionListener)a).actionPerformed(e);
452        ((ActionListener)b).actionPerformed(e);
453    }
454
455    /**
456     * Handles the itemStateChanged event by invoking the
457     * itemStateChanged methods on listener-a and listener-b.
458     * @param e the item event
459     */
460    public void itemStateChanged(ItemEvent e) {
461        ((ItemListener)a).itemStateChanged(e);
462        ((ItemListener)b).itemStateChanged(e);
463    }
464
465    /**
466     * Handles the adjustmentValueChanged event by invoking the
467     * adjustmentValueChanged methods on listener-a and listener-b.
468     * @param e the adjustment event
469     */
470    public void adjustmentValueChanged(AdjustmentEvent e) {
471        ((AdjustmentListener)a).adjustmentValueChanged(e);
472        ((AdjustmentListener)b).adjustmentValueChanged(e);
473    }
474    public void textValueChanged(TextEvent e) {
475        ((TextListener)a).textValueChanged(e);
476        ((TextListener)b).textValueChanged(e);
477    }
478
479    /**
480     * Handles the inputMethodTextChanged event by invoking the
481     * inputMethodTextChanged methods on listener-a and listener-b.
482     * @param e the item event
483     */
484    public void inputMethodTextChanged(InputMethodEvent e) {
485       ((InputMethodListener)a).inputMethodTextChanged(e);
486       ((InputMethodListener)b).inputMethodTextChanged(e);
487    }
488
489    /**
490     * Handles the caretPositionChanged event by invoking the
491     * caretPositionChanged methods on listener-a and listener-b.
492     * @param e the item event
493     */
494    public void caretPositionChanged(InputMethodEvent e) {
495       ((InputMethodListener)a).caretPositionChanged(e);
496       ((InputMethodListener)b).caretPositionChanged(e);
497    }
498
499    /**
500     * Handles the hierarchyChanged event by invoking the
501     * hierarchyChanged methods on listener-a and listener-b.
502     * @param e the item event
503     * @since 1.3
504     */
505    public void hierarchyChanged(HierarchyEvent e) {
506        ((HierarchyListener)a).hierarchyChanged(e);
507        ((HierarchyListener)b).hierarchyChanged(e);
508    }
509
510    /**
511     * Handles the ancestorMoved event by invoking the
512     * ancestorMoved methods on listener-a and listener-b.
513     * @param e the item event
514     * @since 1.3
515     */
516    public void ancestorMoved(HierarchyEvent e) {
517        ((HierarchyBoundsListener)a).ancestorMoved(e);
518        ((HierarchyBoundsListener)b).ancestorMoved(e);
519    }
520
521    /**
522     * Handles the ancestorResized event by invoking the
523     * ancestorResized methods on listener-a and listener-b.
524     * @param e the item event
525     * @since 1.3
526     */
527    public void ancestorResized(HierarchyEvent e) {
528        ((HierarchyBoundsListener)a).ancestorResized(e);
529        ((HierarchyBoundsListener)b).ancestorResized(e);
530    }
531
532    /**
533     * Handles the mouseWheelMoved event by invoking the
534     * mouseWheelMoved methods on listener-a and listener-b.
535     * @param e the mouse event
536     * @since 1.4
537     */
538    public void mouseWheelMoved(MouseWheelEvent e) {
539        ((MouseWheelListener)a).mouseWheelMoved(e);
540        ((MouseWheelListener)b).mouseWheelMoved(e);
541    }
542
543    /**
544     * Adds component-listener-a with component-listener-b and
545     * returns the resulting multicast listener.
546     * @param a component-listener-a
547     * @param b component-listener-b
548     * @return the resulting listener
549     */
550    public static ComponentListener add(ComponentListener a, ComponentListener b) {
551        return (ComponentListener)addInternal(a, b);
552    }
553
554    /**
555     * Adds container-listener-a with container-listener-b and
556     * returns the resulting multicast listener.
557     * @param a container-listener-a
558     * @param b container-listener-b
559     * @return the resulting listener
560     */
561    public static ContainerListener add(ContainerListener a, ContainerListener b) {
562        return (ContainerListener)addInternal(a, b);
563    }
564
565    /**
566     * Adds focus-listener-a with focus-listener-b and
567     * returns the resulting multicast listener.
568     * @param a focus-listener-a
569     * @param b focus-listener-b
570     * @return the resulting listener
571     */
572    public static FocusListener add(FocusListener a, FocusListener b) {
573        return (FocusListener)addInternal(a, b);
574    }
575
576    /**
577     * Adds key-listener-a with key-listener-b and
578     * returns the resulting multicast listener.
579     * @param a key-listener-a
580     * @param b key-listener-b
581     * @return the resulting listener
582     */
583    public static KeyListener add(KeyListener a, KeyListener b) {
584        return (KeyListener)addInternal(a, b);
585    }
586
587    /**
588     * Adds mouse-listener-a with mouse-listener-b and
589     * returns the resulting multicast listener.
590     * @param a mouse-listener-a
591     * @param b mouse-listener-b
592     * @return the resulting listener
593     */
594    public static MouseListener add(MouseListener a, MouseListener b) {
595        return (MouseListener)addInternal(a, b);
596    }
597
598    /**
599     * Adds mouse-motion-listener-a with mouse-motion-listener-b and
600     * returns the resulting multicast listener.
601     * @param a mouse-motion-listener-a
602     * @param b mouse-motion-listener-b
603     * @return the resulting listener
604     */
605    public static MouseMotionListener add(MouseMotionListener a, MouseMotionListener b) {
606        return (MouseMotionListener)addInternal(a, b);
607    }
608
609    /**
610     * Adds window-listener-a with window-listener-b and
611     * returns the resulting multicast listener.
612     * @param a window-listener-a
613     * @param b window-listener-b
614     * @return the resulting listener
615     */
616    public static WindowListener add(WindowListener a, WindowListener b) {
617        return (WindowListener)addInternal(a, b);
618    }
619
620    /**
621     * Adds window-state-listener-a with window-state-listener-b
622     * and returns the resulting multicast listener.
623     * @param a window-state-listener-a
624     * @param b window-state-listener-b
625     * @return the resulting listener
626     * @since 1.4
627     */
628    @SuppressWarnings("overloads")
629    public static WindowStateListener add(WindowStateListener a,
630                                          WindowStateListener b) {
631        return (WindowStateListener)addInternal(a, b);
632    }
633
634    /**
635     * Adds window-focus-listener-a with window-focus-listener-b
636     * and returns the resulting multicast listener.
637     * @param a window-focus-listener-a
638     * @param b window-focus-listener-b
639     * @return the resulting listener
640     * @since 1.4
641     */
642    public static WindowFocusListener add(WindowFocusListener a,
643                                          WindowFocusListener b) {
644        return (WindowFocusListener)addInternal(a, b);
645    }
646
647    /**
648     * Adds action-listener-a with action-listener-b and
649     * returns the resulting multicast listener.
650     * @param a action-listener-a
651     * @param b action-listener-b
652     * @return the resulting listener
653     */
654    @SuppressWarnings("overloads")
655    public static ActionListener add(ActionListener a, ActionListener b) {
656        return (ActionListener)addInternal(a, b);
657    }
658
659    /**
660     * Adds item-listener-a with item-listener-b and
661     * returns the resulting multicast listener.
662     * @param a item-listener-a
663     * @param b item-listener-b
664     * @return the resulting listener
665     */
666    @SuppressWarnings("overloads")
667    public static ItemListener add(ItemListener a, ItemListener b) {
668        return (ItemListener)addInternal(a, b);
669    }
670
671    /**
672     * Adds adjustment-listener-a with adjustment-listener-b and
673     * returns the resulting multicast listener.
674     * @param a adjustment-listener-a
675     * @param b adjustment-listener-b
676     * @return the resulting listener
677     */
678    @SuppressWarnings("overloads")
679    public static AdjustmentListener add(AdjustmentListener a, AdjustmentListener b) {
680        return (AdjustmentListener)addInternal(a, b);
681    }
682
683    /**
684     * Adds text-listener-a with text-listener-b and
685     * returns the resulting multicast listener.
686     *
687     * @param  a text-listener-a
688     * @param  b text-listener-b
689     * @return the resulting listener
690     */
691    @SuppressWarnings("overloads")
692    public static TextListener add(TextListener a, TextListener b) {
693        return (TextListener)addInternal(a, b);
694    }
695
696    /**
697     * Adds input-method-listener-a with input-method-listener-b and
698     * returns the resulting multicast listener.
699     * @param a input-method-listener-a
700     * @param b input-method-listener-b
701     * @return the resulting listener
702     */
703     public static InputMethodListener add(InputMethodListener a, InputMethodListener b) {
704        return (InputMethodListener)addInternal(a, b);
705     }
706
707    /**
708     * Adds hierarchy-listener-a with hierarchy-listener-b and
709     * returns the resulting multicast listener.
710     * @param a hierarchy-listener-a
711     * @param b hierarchy-listener-b
712     * @return the resulting listener
713     * @since 1.3
714     */
715    @SuppressWarnings("overloads")
716     public static HierarchyListener add(HierarchyListener a, HierarchyListener b) {
717        return (HierarchyListener)addInternal(a, b);
718     }
719
720    /**
721     * Adds hierarchy-bounds-listener-a with hierarchy-bounds-listener-b and
722     * returns the resulting multicast listener.
723     * @param a hierarchy-bounds-listener-a
724     * @param b hierarchy-bounds-listener-b
725     * @return the resulting listener
726     * @since 1.3
727     */
728     public static HierarchyBoundsListener add(HierarchyBoundsListener a, HierarchyBoundsListener b) {
729        return (HierarchyBoundsListener)addInternal(a, b);
730     }
731
732    /**
733     * Adds mouse-wheel-listener-a with mouse-wheel-listener-b and
734     * returns the resulting multicast listener.
735     * @param a mouse-wheel-listener-a
736     * @param b mouse-wheel-listener-b
737     * @return the resulting listener
738     * @since 1.4
739     */
740    @SuppressWarnings("overloads")
741    public static MouseWheelListener add(MouseWheelListener a,
742                                         MouseWheelListener b) {
743        return (MouseWheelListener)addInternal(a, b);
744    }
745
746    /**
747     * Removes the old component-listener from component-listener-l and
748     * returns the resulting multicast listener.
749     * @param l component-listener-l
750     * @param oldl the component-listener being removed
751     * @return the resulting listener
752     */
753    public static ComponentListener remove(ComponentListener l, ComponentListener oldl) {
754        return (ComponentListener) removeInternal(l, oldl);
755    }
756
757    /**
758     * Removes the old container-listener from container-listener-l and
759     * returns the resulting multicast listener.
760     * @param l container-listener-l
761     * @param oldl the container-listener being removed
762     * @return the resulting listener
763     */
764    public static ContainerListener remove(ContainerListener l, ContainerListener oldl) {
765        return (ContainerListener) removeInternal(l, oldl);
766    }
767
768    /**
769     * Removes the old focus-listener from focus-listener-l and
770     * returns the resulting multicast listener.
771     * @param l focus-listener-l
772     * @param oldl the focus-listener being removed
773     * @return the resulting listener
774     */
775    public static FocusListener remove(FocusListener l, FocusListener oldl) {
776        return (FocusListener) removeInternal(l, oldl);
777    }
778
779    /**
780     * Removes the old key-listener from key-listener-l and
781     * returns the resulting multicast listener.
782     * @param l key-listener-l
783     * @param oldl the key-listener being removed
784     * @return the resulting listener
785     */
786    public static KeyListener remove(KeyListener l, KeyListener oldl) {
787        return (KeyListener) removeInternal(l, oldl);
788    }
789
790    /**
791     * Removes the old mouse-listener from mouse-listener-l and
792     * returns the resulting multicast listener.
793     * @param l mouse-listener-l
794     * @param oldl the mouse-listener being removed
795     * @return the resulting listener
796     */
797    public static MouseListener remove(MouseListener l, MouseListener oldl) {
798        return (MouseListener) removeInternal(l, oldl);
799    }
800
801    /**
802     * Removes the old mouse-motion-listener from mouse-motion-listener-l
803     * and returns the resulting multicast listener.
804     * @param l mouse-motion-listener-l
805     * @param oldl the mouse-motion-listener being removed
806     * @return the resulting listener
807     */
808    public static MouseMotionListener remove(MouseMotionListener l, MouseMotionListener oldl) {
809        return (MouseMotionListener) removeInternal(l, oldl);
810    }
811
812    /**
813     * Removes the old window-listener from window-listener-l and
814     * returns the resulting multicast listener.
815     * @param l window-listener-l
816     * @param oldl the window-listener being removed
817     * @return the resulting listener
818     */
819    public static WindowListener remove(WindowListener l, WindowListener oldl) {
820        return (WindowListener) removeInternal(l, oldl);
821    }
822
823    /**
824     * Removes the old window-state-listener from window-state-listener-l
825     * and returns the resulting multicast listener.
826     * @param l window-state-listener-l
827     * @param oldl the window-state-listener being removed
828     * @return the resulting listener
829     * @since 1.4
830     */
831    @SuppressWarnings("overloads")
832    public static WindowStateListener remove(WindowStateListener l,
833                                             WindowStateListener oldl) {
834        return (WindowStateListener) removeInternal(l, oldl);
835    }
836
837    /**
838     * Removes the old window-focus-listener from window-focus-listener-l
839     * and returns the resulting multicast listener.
840     * @param l window-focus-listener-l
841     * @param oldl the window-focus-listener being removed
842     * @return the resulting listener
843     * @since 1.4
844     */
845    public static WindowFocusListener remove(WindowFocusListener l,
846                                             WindowFocusListener oldl) {
847        return (WindowFocusListener) removeInternal(l, oldl);
848    }
849
850    /**
851     * Removes the old action-listener from action-listener-l and
852     * returns the resulting multicast listener.
853     * @param l action-listener-l
854     * @param oldl the action-listener being removed
855     * @return the resulting listener
856     */
857    @SuppressWarnings("overloads")
858    public static ActionListener remove(ActionListener l, ActionListener oldl) {
859        return (ActionListener) removeInternal(l, oldl);
860    }
861
862    /**
863     * Removes the old item-listener from item-listener-l and
864     * returns the resulting multicast listener.
865     * @param l item-listener-l
866     * @param oldl the item-listener being removed
867     * @return the resulting listener
868     */
869    @SuppressWarnings("overloads")
870    public static ItemListener remove(ItemListener l, ItemListener oldl) {
871        return (ItemListener) removeInternal(l, oldl);
872    }
873
874    /**
875     * Removes the old adjustment-listener from adjustment-listener-l and
876     * returns the resulting multicast listener.
877     * @param l adjustment-listener-l
878     * @param oldl the adjustment-listener being removed
879     * @return the resulting listener
880     */
881    @SuppressWarnings("overloads")
882    public static AdjustmentListener remove(AdjustmentListener l, AdjustmentListener oldl) {
883        return (AdjustmentListener) removeInternal(l, oldl);
884    }
885
886    /**
887     * Removes the old text-listener from text-listener-l and
888     * returns the resulting multicast listener.
889     *
890     * @param  l text-listener-l
891     * @param  oldl the text-listener being removed
892     * @return the resulting listener
893     */
894    @SuppressWarnings("overloads")
895    public static TextListener remove(TextListener l, TextListener oldl) {
896        return (TextListener) removeInternal(l, oldl);
897    }
898
899    /**
900     * Removes the old input-method-listener from input-method-listener-l and
901     * returns the resulting multicast listener.
902     * @param l input-method-listener-l
903     * @param oldl the input-method-listener being removed
904     * @return the resulting listener
905     */
906    public static InputMethodListener remove(InputMethodListener l, InputMethodListener oldl) {
907        return (InputMethodListener) removeInternal(l, oldl);
908    }
909
910    /**
911     * Removes the old hierarchy-listener from hierarchy-listener-l and
912     * returns the resulting multicast listener.
913     * @param l hierarchy-listener-l
914     * @param oldl the hierarchy-listener being removed
915     * @return the resulting listener
916     * @since 1.3
917     */
918    @SuppressWarnings("overloads")
919    public static HierarchyListener remove(HierarchyListener l, HierarchyListener oldl) {
920        return (HierarchyListener) removeInternal(l, oldl);
921    }
922
923    /**
924     * Removes the old hierarchy-bounds-listener from
925     * hierarchy-bounds-listener-l and returns the resulting multicast
926     * listener.
927     * @param l hierarchy-bounds-listener-l
928     * @param oldl the hierarchy-bounds-listener being removed
929     * @return the resulting listener
930     * @since 1.3
931     */
932    public static HierarchyBoundsListener remove(HierarchyBoundsListener l, HierarchyBoundsListener oldl) {
933        return (HierarchyBoundsListener) removeInternal(l, oldl);
934    }
935
936    /**
937     * Removes the old mouse-wheel-listener from mouse-wheel-listener-l
938     * and returns the resulting multicast listener.
939     * @param l mouse-wheel-listener-l
940     * @param oldl the mouse-wheel-listener being removed
941     * @return the resulting listener
942     * @since 1.4
943     */
944    @SuppressWarnings("overloads")
945    public static MouseWheelListener remove(MouseWheelListener l,
946                                            MouseWheelListener oldl) {
947      return (MouseWheelListener) removeInternal(l, oldl);
948    }
949
950    /**
951     * Returns the resulting multicast listener from adding listener-a
952     * and listener-b together.
953     * If listener-a is null, it returns listener-b;
954     * If listener-b is null, it returns listener-a
955     * If neither are null, then it creates and returns
956     * a new AWTEventMulticaster instance which chains a with b.
957     * @param a event listener-a
958     * @param b event listener-b
959     * @return the resulting listener
960     */
961    protected static EventListener addInternal(EventListener a, EventListener b) {
962        if (a == null)  return b;
963        if (b == null)  return a;
964        return new AWTEventMulticaster(a, b);
965    }
966
967    /**
968     * Returns the resulting multicast listener after removing the
969     * old listener from listener-l.
970     * If listener-l equals the old listener OR listener-l is null,
971     * returns null.
972     * Else if listener-l is an instance of AWTEventMulticaster,
973     * then it removes the old listener from it.
974     * Else, returns listener l.
975     * @param l the listener being removed from
976     * @param oldl the listener being removed
977     * @return the resulting listener
978     */
979    protected static EventListener removeInternal(EventListener l, EventListener oldl) {
980        if (l == oldl || l == null) {
981            return null;
982        } else if (l instanceof AWTEventMulticaster) {
983            return ((AWTEventMulticaster)l).remove(oldl);
984        } else {
985            return l;           // it's not here
986        }
987    }
988
989
990   /**
991    * Serialization support. Saves all Serializable listeners
992    * to a serialization stream.
993    *
994    * @param  s the stream to save to
995    * @param  k a prefix stream to put before each serializable listener
996    * @throws IOException if serialization fails
997    */
998    protected void saveInternal(ObjectOutputStream s, String k) throws IOException {
999        if (a instanceof AWTEventMulticaster) {
1000            ((AWTEventMulticaster)a).saveInternal(s, k);
1001        }
1002        else if (a instanceof Serializable) {
1003            s.writeObject(k);
1004            s.writeObject(a);
1005        }
1006
1007        if (b instanceof AWTEventMulticaster) {
1008            ((AWTEventMulticaster)b).saveInternal(s, k);
1009        }
1010        else if (b instanceof Serializable) {
1011            s.writeObject(k);
1012            s.writeObject(b);
1013        }
1014    }
1015
1016   /**
1017    * Saves a Serializable listener chain to a serialization stream.
1018    *
1019    * @param  s the stream to save to
1020    * @param  k a prefix stream to put before each serializable listener
1021    * @param  l the listener chain to save
1022    * @throws IOException if serialization fails
1023    */
1024    protected static void save(ObjectOutputStream s, String k, EventListener l) throws IOException {
1025      if (l == null) {
1026          return;
1027      }
1028      else if (l instanceof AWTEventMulticaster) {
1029          ((AWTEventMulticaster)l).saveInternal(s, k);
1030      }
1031      else if (l instanceof Serializable) {
1032           s.writeObject(k);
1033           s.writeObject(l);
1034      }
1035    }
1036
1037    /*
1038     * Recursive method which returns a count of the number of listeners in
1039     * EventListener, handling the (common) case of l actually being an
1040     * AWTEventMulticaster.  Additionally, only listeners of type listenerType
1041     * are counted.  Method modified to fix bug 4513402.  -bchristi
1042     */
1043    private static int getListenerCount(EventListener l, Class<?> listenerType) {
1044        if (l instanceof AWTEventMulticaster) {
1045            AWTEventMulticaster mc = (AWTEventMulticaster)l;
1046            return getListenerCount(mc.a, listenerType) +
1047             getListenerCount(mc.b, listenerType);
1048        }
1049        else {
1050            // Only count listeners of correct type
1051            return listenerType.isInstance(l) ? 1 : 0;
1052        }
1053    }
1054
1055    /*
1056     * Recursive method which populates EventListener array a with EventListeners
1057     * from l.  l is usually an AWTEventMulticaster.  Bug 4513402 revealed that
1058     * if l differed in type from the element type of a, an ArrayStoreException
1059     * would occur.  Now l is only inserted into a if it's of the appropriate
1060     * type.  -bchristi
1061     */
1062    private static int populateListenerArray(EventListener[] a, EventListener l, int index) {
1063        if (l instanceof AWTEventMulticaster) {
1064            AWTEventMulticaster mc = (AWTEventMulticaster)l;
1065            int lhs = populateListenerArray(a, mc.a, index);
1066            return populateListenerArray(a, mc.b, lhs);
1067        }
1068        else if (a.getClass().getComponentType().isInstance(l)) {
1069            a[index] = l;
1070            return index + 1;
1071        }
1072        // Skip nulls, instances of wrong class
1073        else {
1074            return index;
1075        }
1076    }
1077
1078    /**
1079     * Returns an array of all the objects chained as
1080     * <code><em>Foo</em>Listener</code>s by the specified
1081     * {@code java.util.EventListener}.
1082     * <code><em>Foo</em>Listener</code>s are chained by the
1083     * {@code AWTEventMulticaster} using the
1084     * <code>add<em>Foo</em>Listener</code> method.
1085     * If a {@code null} listener is specified, this method returns an
1086     * empty array. If the specified listener is not an instance of
1087     * {@code AWTEventMulticaster}, this method returns an array which
1088     * contains only the specified listener. If no such listeners are chained,
1089     * this method returns an empty array.
1090     *
1091     * @param <T> the listener type
1092     * @param l the specified {@code java.util.EventListener}
1093     * @param listenerType the type of listeners requested; this parameter
1094     *          should specify an interface that descends from
1095     *          {@code java.util.EventListener}
1096     * @return an array of all objects chained as
1097     *          <code><em>Foo</em>Listener</code>s by the specified multicast
1098     *          listener, or an empty array if no such listeners have been
1099     *          chained by the specified multicast listener
1100     * @exception NullPointerException if the specified
1101     *             {@code listenertype} parameter is {@code null}
1102     * @exception ClassCastException if {@code listenerType}
1103     *          doesn't specify a class or interface that implements
1104     *          {@code java.util.EventListener}
1105     *
1106     * @since 1.4
1107     */
1108    @SuppressWarnings("unchecked")
1109    public static <T extends EventListener> T[]
1110        getListeners(EventListener l, Class<T> listenerType)
1111    {
1112        if (listenerType == null) {
1113            throw new NullPointerException ("Listener type should not be null");
1114        }
1115
1116        int n = getListenerCount(l, listenerType);
1117        T[] result = (T[])Array.newInstance(listenerType, n);
1118        populateListenerArray(result, l, 0);
1119        return result;
1120    }
1121}
1122