1 /*
   2  * Copyright (c) 1996, 2014, 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  */
  25 package java.awt;
  26 
  27 import java.awt.event.*;
  28 import java.lang.reflect.Array;
  29 import java.util.EventListener;
  30 import java.io.Serializable;
  31 import java.io.ObjectOutputStream;
  32 import java.io.IOException;
  33 import 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 
 106 public 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     protected final EventListener a, b;
 114 
 115     /**
 116      * Creates an event multicaster instance which chains listener-a
 117      * with listener-b. Input parameters <code>a</code> and <code>b</code>
 118      * should not be <code>null</code>, though implementations may vary in
 119      * choosing whether or not to throw <code>NullPointerException</code>
 120      * in that case.
 121      * @param a listener-a
 122      * @param b listener-b
 123      */
 124     protected AWTEventMulticaster(EventListener a, EventListener b) {
 125         this.a = a; this.b = b;
 126     }
 127 
 128     /**
 129      * Removes a listener from this multicaster.
 130      * <p>
 131      * The returned multicaster contains all the listeners in this
 132      * multicaster with the exception of all occurrences of {@code oldl}.
 133      * If the resulting multicaster contains only one regular listener
 134      * the regular listener may be returned.  If the resulting multicaster
 135      * is empty, then {@code null} may be returned instead.
 136      * <p>
 137      * No exception is thrown if {@code oldl} is {@code null}.
 138      *
 139      * @param oldl the listener to be removed
 140      * @return resulting listener
 141      */
 142     protected EventListener remove(EventListener oldl) {
 143         if (oldl == a)  return b;
 144         if (oldl == b)  return a;
 145         EventListener a2 = removeInternal(a, oldl);
 146         EventListener b2 = removeInternal(b, oldl);
 147         if (a2 == a && b2 == b) {
 148             return this;        // it's not here
 149         }
 150         return addInternal(a2, b2);
 151     }
 152 
 153     /**
 154      * Handles the componentResized event by invoking the
 155      * componentResized methods on listener-a and listener-b.
 156      * @param e the component event
 157      */
 158     public void componentResized(ComponentEvent e) {
 159         ((ComponentListener)a).componentResized(e);
 160         ((ComponentListener)b).componentResized(e);
 161     }
 162 
 163     /**
 164      * Handles the componentMoved event by invoking the
 165      * componentMoved methods on listener-a and listener-b.
 166      * @param e the component event
 167      */
 168     public void componentMoved(ComponentEvent e) {
 169         ((ComponentListener)a).componentMoved(e);
 170         ((ComponentListener)b).componentMoved(e);
 171     }
 172 
 173     /**
 174      * Handles the componentShown event by invoking the
 175      * componentShown methods on listener-a and listener-b.
 176      * @param e the component event
 177      */
 178     public void componentShown(ComponentEvent e) {
 179         ((ComponentListener)a).componentShown(e);
 180         ((ComponentListener)b).componentShown(e);
 181     }
 182 
 183     /**
 184      * Handles the componentHidden event by invoking the
 185      * componentHidden methods on listener-a and listener-b.
 186      * @param e the component event
 187      */
 188     public void componentHidden(ComponentEvent e) {
 189         ((ComponentListener)a).componentHidden(e);
 190         ((ComponentListener)b).componentHidden(e);
 191     }
 192 
 193     /**
 194      * Handles the componentAdded container event by invoking the
 195      * componentAdded methods on listener-a and listener-b.
 196      * @param e the component event
 197      */
 198     public void componentAdded(ContainerEvent e) {
 199         ((ContainerListener)a).componentAdded(e);
 200         ((ContainerListener)b).componentAdded(e);
 201     }
 202 
 203     /**
 204      * Handles the componentRemoved container event by invoking the
 205      * componentRemoved methods on listener-a and listener-b.
 206      * @param e the component event
 207      */
 208     public void componentRemoved(ContainerEvent e) {
 209         ((ContainerListener)a).componentRemoved(e);
 210         ((ContainerListener)b).componentRemoved(e);
 211     }
 212 
 213     /**
 214      * Handles the focusGained event by invoking the
 215      * focusGained methods on listener-a and listener-b.
 216      * @param e the focus event
 217      */
 218     public void focusGained(FocusEvent e) {
 219         ((FocusListener)a).focusGained(e);
 220         ((FocusListener)b).focusGained(e);
 221     }
 222 
 223     /**
 224      * Handles the focusLost event by invoking the
 225      * focusLost methods on listener-a and listener-b.
 226      * @param e the focus event
 227      */
 228     public void focusLost(FocusEvent e) {
 229         ((FocusListener)a).focusLost(e);
 230         ((FocusListener)b).focusLost(e);
 231     }
 232 
 233     /**
 234      * Handles the keyTyped event by invoking the
 235      * keyTyped methods on listener-a and listener-b.
 236      * @param e the key event
 237      */
 238     public void keyTyped(KeyEvent e) {
 239         ((KeyListener)a).keyTyped(e);
 240         ((KeyListener)b).keyTyped(e);
 241     }
 242 
 243     /**
 244      * Handles the keyPressed event by invoking the
 245      * keyPressed methods on listener-a and listener-b.
 246      * @param e the key event
 247      */
 248     public void keyPressed(KeyEvent e) {
 249         ((KeyListener)a).keyPressed(e);
 250         ((KeyListener)b).keyPressed(e);
 251     }
 252 
 253     /**
 254      * Handles the keyReleased event by invoking the
 255      * keyReleased methods on listener-a and listener-b.
 256      * @param e the key event
 257      */
 258     public void keyReleased(KeyEvent e) {
 259         ((KeyListener)a).keyReleased(e);
 260         ((KeyListener)b).keyReleased(e);
 261     }
 262 
 263     /**
 264      * Handles the mouseClicked event by invoking the
 265      * mouseClicked methods on listener-a and listener-b.
 266      * @param e the mouse event
 267      */
 268     public void mouseClicked(MouseEvent e) {
 269         ((MouseListener)a).mouseClicked(e);
 270         ((MouseListener)b).mouseClicked(e);
 271     }
 272 
 273     /**
 274      * Handles the mousePressed event by invoking the
 275      * mousePressed methods on listener-a and listener-b.
 276      * @param e the mouse event
 277      */
 278     public void mousePressed(MouseEvent e) {
 279         ((MouseListener)a).mousePressed(e);
 280         ((MouseListener)b).mousePressed(e);
 281     }
 282 
 283     /**
 284      * Handles the mouseReleased event by invoking the
 285      * mouseReleased methods on listener-a and listener-b.
 286      * @param e the mouse event
 287      */
 288     public void mouseReleased(MouseEvent e) {
 289         ((MouseListener)a).mouseReleased(e);
 290         ((MouseListener)b).mouseReleased(e);
 291     }
 292 
 293     /**
 294      * Handles the mouseEntered event by invoking the
 295      * mouseEntered methods on listener-a and listener-b.
 296      * @param e the mouse event
 297      */
 298     public void mouseEntered(MouseEvent e) {
 299         ((MouseListener)a).mouseEntered(e);
 300         ((MouseListener)b).mouseEntered(e);
 301     }
 302 
 303     /**
 304      * Handles the mouseExited event by invoking the
 305      * mouseExited methods on listener-a and listener-b.
 306      * @param e the mouse event
 307      */
 308     public void mouseExited(MouseEvent e) {
 309         ((MouseListener)a).mouseExited(e);
 310         ((MouseListener)b).mouseExited(e);
 311     }
 312 
 313     /**
 314      * Handles the mouseDragged event by invoking the
 315      * mouseDragged methods on listener-a and listener-b.
 316      * @param e the mouse event
 317      */
 318     public void mouseDragged(MouseEvent e) {
 319         ((MouseMotionListener)a).mouseDragged(e);
 320         ((MouseMotionListener)b).mouseDragged(e);
 321     }
 322 
 323     /**
 324      * Handles the mouseMoved event by invoking the
 325      * mouseMoved methods on listener-a and listener-b.
 326      * @param e the mouse event
 327      */
 328     public void mouseMoved(MouseEvent e) {
 329         ((MouseMotionListener)a).mouseMoved(e);
 330         ((MouseMotionListener)b).mouseMoved(e);
 331     }
 332 
 333     /**
 334      * Handles the windowOpened event by invoking the
 335      * windowOpened methods on listener-a and listener-b.
 336      * @param e the window event
 337      */
 338     public void windowOpened(WindowEvent e) {
 339         ((WindowListener)a).windowOpened(e);
 340         ((WindowListener)b).windowOpened(e);
 341     }
 342 
 343     /**
 344      * Handles the windowClosing event by invoking the
 345      * windowClosing methods on listener-a and listener-b.
 346      * @param e the window event
 347      */
 348     public void windowClosing(WindowEvent e) {
 349         ((WindowListener)a).windowClosing(e);
 350         ((WindowListener)b).windowClosing(e);
 351     }
 352 
 353     /**
 354      * Handles the windowClosed event by invoking the
 355      * windowClosed methods on listener-a and listener-b.
 356      * @param e the window event
 357      */
 358     public void windowClosed(WindowEvent e) {
 359         ((WindowListener)a).windowClosed(e);
 360         ((WindowListener)b).windowClosed(e);
 361     }
 362 
 363     /**
 364      * Handles the windowIconified event by invoking the
 365      * windowIconified methods on listener-a and listener-b.
 366      * @param e the window event
 367      */
 368     public void windowIconified(WindowEvent e) {
 369         ((WindowListener)a).windowIconified(e);
 370         ((WindowListener)b).windowIconified(e);
 371     }
 372 
 373     /**
 374      * Handles the windowDeiconfied event by invoking the
 375      * windowDeiconified methods on listener-a and listener-b.
 376      * @param e the window event
 377      */
 378     public void windowDeiconified(WindowEvent e) {
 379         ((WindowListener)a).windowDeiconified(e);
 380         ((WindowListener)b).windowDeiconified(e);
 381     }
 382 
 383     /**
 384      * Handles the windowActivated event by invoking the
 385      * windowActivated methods on listener-a and listener-b.
 386      * @param e the window event
 387      */
 388     public void windowActivated(WindowEvent e) {
 389         ((WindowListener)a).windowActivated(e);
 390         ((WindowListener)b).windowActivated(e);
 391     }
 392 
 393     /**
 394      * Handles the windowDeactivated event by invoking the
 395      * windowDeactivated methods on listener-a and listener-b.
 396      * @param e the window event
 397      */
 398     public void windowDeactivated(WindowEvent e) {
 399         ((WindowListener)a).windowDeactivated(e);
 400         ((WindowListener)b).windowDeactivated(e);
 401     }
 402 
 403     /**
 404      * Handles the windowStateChanged event by invoking the
 405      * windowStateChanged methods on listener-a and listener-b.
 406      * @param e the window event
 407      * @since 1.4
 408      */
 409     public void windowStateChanged(WindowEvent e) {
 410         ((WindowStateListener)a).windowStateChanged(e);
 411         ((WindowStateListener)b).windowStateChanged(e);
 412     }
 413 
 414 
 415     /**
 416      * Handles the windowGainedFocus event by invoking the windowGainedFocus
 417      * methods on listener-a and listener-b.
 418      * @param e the window event
 419      * @since 1.4
 420      */
 421     public void windowGainedFocus(WindowEvent e) {
 422         ((WindowFocusListener)a).windowGainedFocus(e);
 423         ((WindowFocusListener)b).windowGainedFocus(e);
 424     }
 425 
 426     /**
 427      * Handles the windowLostFocus event by invoking the windowLostFocus
 428      * methods on listener-a and listener-b.
 429      * @param e the window event
 430      * @since 1.4
 431      */
 432     public void windowLostFocus(WindowEvent e) {
 433         ((WindowFocusListener)a).windowLostFocus(e);
 434         ((WindowFocusListener)b).windowLostFocus(e);
 435     }
 436 
 437     /**
 438      * Handles the actionPerformed event by invoking the
 439      * actionPerformed methods on listener-a and listener-b.
 440      * @param e the action event
 441      */
 442     public void actionPerformed(ActionEvent e) {
 443         ((ActionListener)a).actionPerformed(e);
 444         ((ActionListener)b).actionPerformed(e);
 445     }
 446 
 447     /**
 448      * Handles the itemStateChanged event by invoking the
 449      * itemStateChanged methods on listener-a and listener-b.
 450      * @param e the item event
 451      */
 452     public void itemStateChanged(ItemEvent e) {
 453         ((ItemListener)a).itemStateChanged(e);
 454         ((ItemListener)b).itemStateChanged(e);
 455     }
 456 
 457     /**
 458      * Handles the adjustmentValueChanged event by invoking the
 459      * adjustmentValueChanged methods on listener-a and listener-b.
 460      * @param e the adjustment event
 461      */
 462     public void adjustmentValueChanged(AdjustmentEvent e) {
 463         ((AdjustmentListener)a).adjustmentValueChanged(e);
 464         ((AdjustmentListener)b).adjustmentValueChanged(e);
 465     }
 466     public void textValueChanged(TextEvent e) {
 467         ((TextListener)a).textValueChanged(e);
 468         ((TextListener)b).textValueChanged(e);
 469     }
 470 
 471     /**
 472      * Handles the inputMethodTextChanged event by invoking the
 473      * inputMethodTextChanged methods on listener-a and listener-b.
 474      * @param e the item event
 475      */
 476     public void inputMethodTextChanged(InputMethodEvent e) {
 477        ((InputMethodListener)a).inputMethodTextChanged(e);
 478        ((InputMethodListener)b).inputMethodTextChanged(e);
 479     }
 480 
 481     /**
 482      * Handles the caretPositionChanged event by invoking the
 483      * caretPositionChanged methods on listener-a and listener-b.
 484      * @param e the item event
 485      */
 486     public void caretPositionChanged(InputMethodEvent e) {
 487        ((InputMethodListener)a).caretPositionChanged(e);
 488        ((InputMethodListener)b).caretPositionChanged(e);
 489     }
 490 
 491     /**
 492      * Handles the hierarchyChanged event by invoking the
 493      * hierarchyChanged methods on listener-a and listener-b.
 494      * @param e the item event
 495      * @since 1.3
 496      */
 497     public void hierarchyChanged(HierarchyEvent e) {
 498         ((HierarchyListener)a).hierarchyChanged(e);
 499         ((HierarchyListener)b).hierarchyChanged(e);
 500     }
 501 
 502     /**
 503      * Handles the ancestorMoved event by invoking the
 504      * ancestorMoved methods on listener-a and listener-b.
 505      * @param e the item event
 506      * @since 1.3
 507      */
 508     public void ancestorMoved(HierarchyEvent e) {
 509         ((HierarchyBoundsListener)a).ancestorMoved(e);
 510         ((HierarchyBoundsListener)b).ancestorMoved(e);
 511     }
 512 
 513     /**
 514      * Handles the ancestorResized event by invoking the
 515      * ancestorResized methods on listener-a and listener-b.
 516      * @param e the item event
 517      * @since 1.3
 518      */
 519     public void ancestorResized(HierarchyEvent e) {
 520         ((HierarchyBoundsListener)a).ancestorResized(e);
 521         ((HierarchyBoundsListener)b).ancestorResized(e);
 522     }
 523 
 524     /**
 525      * Handles the mouseWheelMoved event by invoking the
 526      * mouseWheelMoved methods on listener-a and listener-b.
 527      * @param e the mouse event
 528      * @since 1.4
 529      */
 530     public void mouseWheelMoved(MouseWheelEvent e) {
 531         ((MouseWheelListener)a).mouseWheelMoved(e);
 532         ((MouseWheelListener)b).mouseWheelMoved(e);
 533     }
 534 
 535     /**
 536      * Adds component-listener-a with component-listener-b and
 537      * returns the resulting multicast listener.
 538      * @param a component-listener-a
 539      * @param b component-listener-b
 540      */
 541     public static ComponentListener add(ComponentListener a, ComponentListener b) {
 542         return (ComponentListener)addInternal(a, b);
 543     }
 544 
 545     /**
 546      * Adds container-listener-a with container-listener-b and
 547      * returns the resulting multicast listener.
 548      * @param a container-listener-a
 549      * @param b container-listener-b
 550      */
 551     public static ContainerListener add(ContainerListener a, ContainerListener b) {
 552         return (ContainerListener)addInternal(a, b);
 553     }
 554 
 555     /**
 556      * Adds focus-listener-a with focus-listener-b and
 557      * returns the resulting multicast listener.
 558      * @param a focus-listener-a
 559      * @param b focus-listener-b
 560      */
 561     public static FocusListener add(FocusListener a, FocusListener b) {
 562         return (FocusListener)addInternal(a, b);
 563     }
 564 
 565     /**
 566      * Adds key-listener-a with key-listener-b and
 567      * returns the resulting multicast listener.
 568      * @param a key-listener-a
 569      * @param b key-listener-b
 570      */
 571     public static KeyListener add(KeyListener a, KeyListener b) {
 572         return (KeyListener)addInternal(a, b);
 573     }
 574 
 575     /**
 576      * Adds mouse-listener-a with mouse-listener-b and
 577      * returns the resulting multicast listener.
 578      * @param a mouse-listener-a
 579      * @param b mouse-listener-b
 580      */
 581     public static MouseListener add(MouseListener a, MouseListener b) {
 582         return (MouseListener)addInternal(a, b);
 583     }
 584 
 585     /**
 586      * Adds mouse-motion-listener-a with mouse-motion-listener-b and
 587      * returns the resulting multicast listener.
 588      * @param a mouse-motion-listener-a
 589      * @param b mouse-motion-listener-b
 590      */
 591     public static MouseMotionListener add(MouseMotionListener a, MouseMotionListener b) {
 592         return (MouseMotionListener)addInternal(a, b);
 593     }
 594 
 595     /**
 596      * Adds window-listener-a with window-listener-b and
 597      * returns the resulting multicast listener.
 598      * @param a window-listener-a
 599      * @param b window-listener-b
 600      */
 601     public static WindowListener add(WindowListener a, WindowListener b) {
 602         return (WindowListener)addInternal(a, b);
 603     }
 604 
 605     /**
 606      * Adds window-state-listener-a with window-state-listener-b
 607      * and returns the resulting multicast listener.
 608      * @param a window-state-listener-a
 609      * @param b window-state-listener-b
 610      * @since 1.4
 611      */
 612     @SuppressWarnings("overloads")
 613     public static WindowStateListener add(WindowStateListener a,
 614                                           WindowStateListener b) {
 615         return (WindowStateListener)addInternal(a, b);
 616     }
 617 
 618     /**
 619      * Adds window-focus-listener-a with window-focus-listener-b
 620      * and returns the resulting multicast listener.
 621      * @param a window-focus-listener-a
 622      * @param b window-focus-listener-b
 623      * @since 1.4
 624      */
 625     public static WindowFocusListener add(WindowFocusListener a,
 626                                           WindowFocusListener b) {
 627         return (WindowFocusListener)addInternal(a, b);
 628     }
 629 
 630     /**
 631      * Adds action-listener-a with action-listener-b and
 632      * returns the resulting multicast listener.
 633      * @param a action-listener-a
 634      * @param b action-listener-b
 635      */
 636     @SuppressWarnings("overloads")
 637     public static ActionListener add(ActionListener a, ActionListener b) {
 638         return (ActionListener)addInternal(a, b);
 639     }
 640 
 641     /**
 642      * Adds item-listener-a with item-listener-b and
 643      * returns the resulting multicast listener.
 644      * @param a item-listener-a
 645      * @param b item-listener-b
 646      */
 647     @SuppressWarnings("overloads")
 648     public static ItemListener add(ItemListener a, ItemListener b) {
 649         return (ItemListener)addInternal(a, b);
 650     }
 651 
 652     /**
 653      * Adds adjustment-listener-a with adjustment-listener-b and
 654      * returns the resulting multicast listener.
 655      * @param a adjustment-listener-a
 656      * @param b adjustment-listener-b
 657      */
 658     @SuppressWarnings("overloads")
 659     public static AdjustmentListener add(AdjustmentListener a, AdjustmentListener b) {
 660         return (AdjustmentListener)addInternal(a, b);
 661     }
 662     @SuppressWarnings("overloads")
 663     public static TextListener add(TextListener a, TextListener b) {
 664         return (TextListener)addInternal(a, b);
 665     }
 666 
 667     /**
 668      * Adds input-method-listener-a with input-method-listener-b and
 669      * returns the resulting multicast listener.
 670      * @param a input-method-listener-a
 671      * @param b input-method-listener-b
 672      */
 673      public static InputMethodListener add(InputMethodListener a, InputMethodListener b) {
 674         return (InputMethodListener)addInternal(a, b);
 675      }
 676 
 677     /**
 678      * Adds hierarchy-listener-a with hierarchy-listener-b and
 679      * returns the resulting multicast listener.
 680      * @param a hierarchy-listener-a
 681      * @param b hierarchy-listener-b
 682      * @since 1.3
 683      */
 684     @SuppressWarnings("overloads")
 685      public static HierarchyListener add(HierarchyListener a, HierarchyListener b) {
 686         return (HierarchyListener)addInternal(a, b);
 687      }
 688 
 689     /**
 690      * Adds hierarchy-bounds-listener-a with hierarchy-bounds-listener-b and
 691      * returns the resulting multicast listener.
 692      * @param a hierarchy-bounds-listener-a
 693      * @param b hierarchy-bounds-listener-b
 694      * @since 1.3
 695      */
 696      public static HierarchyBoundsListener add(HierarchyBoundsListener a, HierarchyBoundsListener b) {
 697         return (HierarchyBoundsListener)addInternal(a, b);
 698      }
 699 
 700     /**
 701      * Adds mouse-wheel-listener-a with mouse-wheel-listener-b and
 702      * returns the resulting multicast listener.
 703      * @param a mouse-wheel-listener-a
 704      * @param b mouse-wheel-listener-b
 705      * @since 1.4
 706      */
 707     @SuppressWarnings("overloads")
 708     public static MouseWheelListener add(MouseWheelListener a,
 709                                          MouseWheelListener b) {
 710         return (MouseWheelListener)addInternal(a, b);
 711     }
 712 
 713     /**
 714      * Removes the old component-listener from component-listener-l and
 715      * returns the resulting multicast listener.
 716      * @param l component-listener-l
 717      * @param oldl the component-listener being removed
 718      */
 719     public static ComponentListener remove(ComponentListener l, ComponentListener oldl) {
 720         return (ComponentListener) removeInternal(l, oldl);
 721     }
 722 
 723     /**
 724      * Removes the old container-listener from container-listener-l and
 725      * returns the resulting multicast listener.
 726      * @param l container-listener-l
 727      * @param oldl the container-listener being removed
 728      */
 729     public static ContainerListener remove(ContainerListener l, ContainerListener oldl) {
 730         return (ContainerListener) removeInternal(l, oldl);
 731     }
 732 
 733     /**
 734      * Removes the old focus-listener from focus-listener-l and
 735      * returns the resulting multicast listener.
 736      * @param l focus-listener-l
 737      * @param oldl the focus-listener being removed
 738      */
 739     public static FocusListener remove(FocusListener l, FocusListener oldl) {
 740         return (FocusListener) removeInternal(l, oldl);
 741     }
 742 
 743     /**
 744      * Removes the old key-listener from key-listener-l and
 745      * returns the resulting multicast listener.
 746      * @param l key-listener-l
 747      * @param oldl the key-listener being removed
 748      */
 749     public static KeyListener remove(KeyListener l, KeyListener oldl) {
 750         return (KeyListener) removeInternal(l, oldl);
 751     }
 752 
 753     /**
 754      * Removes the old mouse-listener from mouse-listener-l and
 755      * returns the resulting multicast listener.
 756      * @param l mouse-listener-l
 757      * @param oldl the mouse-listener being removed
 758      */
 759     public static MouseListener remove(MouseListener l, MouseListener oldl) {
 760         return (MouseListener) removeInternal(l, oldl);
 761     }
 762 
 763     /**
 764      * Removes the old mouse-motion-listener from mouse-motion-listener-l
 765      * and returns the resulting multicast listener.
 766      * @param l mouse-motion-listener-l
 767      * @param oldl the mouse-motion-listener being removed
 768      */
 769     public static MouseMotionListener remove(MouseMotionListener l, MouseMotionListener oldl) {
 770         return (MouseMotionListener) removeInternal(l, oldl);
 771     }
 772 
 773     /**
 774      * Removes the old window-listener from window-listener-l and
 775      * returns the resulting multicast listener.
 776      * @param l window-listener-l
 777      * @param oldl the window-listener being removed
 778      */
 779     public static WindowListener remove(WindowListener l, WindowListener oldl) {
 780         return (WindowListener) removeInternal(l, oldl);
 781     }
 782 
 783     /**
 784      * Removes the old window-state-listener from window-state-listener-l
 785      * and returns the resulting multicast listener.
 786      * @param l window-state-listener-l
 787      * @param oldl the window-state-listener being removed
 788      * @since 1.4
 789      */
 790     @SuppressWarnings("overloads")
 791     public static WindowStateListener remove(WindowStateListener l,
 792                                              WindowStateListener oldl) {
 793         return (WindowStateListener) removeInternal(l, oldl);
 794     }
 795 
 796     /**
 797      * Removes the old window-focus-listener from window-focus-listener-l
 798      * and returns the resulting multicast listener.
 799      * @param l window-focus-listener-l
 800      * @param oldl the window-focus-listener being removed
 801      * @since 1.4
 802      */
 803     public static WindowFocusListener remove(WindowFocusListener l,
 804                                              WindowFocusListener oldl) {
 805         return (WindowFocusListener) removeInternal(l, oldl);
 806     }
 807 
 808     /**
 809      * Removes the old action-listener from action-listener-l and
 810      * returns the resulting multicast listener.
 811      * @param l action-listener-l
 812      * @param oldl the action-listener being removed
 813      */
 814     @SuppressWarnings("overloads")
 815     public static ActionListener remove(ActionListener l, ActionListener oldl) {
 816         return (ActionListener) removeInternal(l, oldl);
 817     }
 818 
 819     /**
 820      * Removes the old item-listener from item-listener-l and
 821      * returns the resulting multicast listener.
 822      * @param l item-listener-l
 823      * @param oldl the item-listener being removed
 824      */
 825     @SuppressWarnings("overloads")
 826     public static ItemListener remove(ItemListener l, ItemListener oldl) {
 827         return (ItemListener) removeInternal(l, oldl);
 828     }
 829 
 830     /**
 831      * Removes the old adjustment-listener from adjustment-listener-l and
 832      * returns the resulting multicast listener.
 833      * @param l adjustment-listener-l
 834      * @param oldl the adjustment-listener being removed
 835      */
 836     @SuppressWarnings("overloads")
 837     public static AdjustmentListener remove(AdjustmentListener l, AdjustmentListener oldl) {
 838         return (AdjustmentListener) removeInternal(l, oldl);
 839     }
 840     @SuppressWarnings("overloads")
 841     public static TextListener remove(TextListener l, TextListener oldl) {
 842         return (TextListener) removeInternal(l, oldl);
 843     }
 844 
 845     /**
 846      * Removes the old input-method-listener from input-method-listener-l and
 847      * returns the resulting multicast listener.
 848      * @param l input-method-listener-l
 849      * @param oldl the input-method-listener being removed
 850      */
 851     public static InputMethodListener remove(InputMethodListener l, InputMethodListener oldl) {
 852         return (InputMethodListener) removeInternal(l, oldl);
 853     }
 854 
 855     /**
 856      * Removes the old hierarchy-listener from hierarchy-listener-l and
 857      * returns the resulting multicast listener.
 858      * @param l hierarchy-listener-l
 859      * @param oldl the hierarchy-listener being removed
 860      * @since 1.3
 861      */
 862     @SuppressWarnings("overloads")
 863     public static HierarchyListener remove(HierarchyListener l, HierarchyListener oldl) {
 864         return (HierarchyListener) removeInternal(l, oldl);
 865     }
 866 
 867     /**
 868      * Removes the old hierarchy-bounds-listener from
 869      * hierarchy-bounds-listener-l and returns the resulting multicast
 870      * listener.
 871      * @param l hierarchy-bounds-listener-l
 872      * @param oldl the hierarchy-bounds-listener being removed
 873      * @since 1.3
 874      */
 875     public static HierarchyBoundsListener remove(HierarchyBoundsListener l, HierarchyBoundsListener oldl) {
 876         return (HierarchyBoundsListener) removeInternal(l, oldl);
 877     }
 878 
 879     /**
 880      * Removes the old mouse-wheel-listener from mouse-wheel-listener-l
 881      * and returns the resulting multicast listener.
 882      * @param l mouse-wheel-listener-l
 883      * @param oldl the mouse-wheel-listener being removed
 884      * @since 1.4
 885      */
 886     @SuppressWarnings("overloads")
 887     public static MouseWheelListener remove(MouseWheelListener l,
 888                                             MouseWheelListener oldl) {
 889       return (MouseWheelListener) removeInternal(l, oldl);
 890     }
 891 
 892     /**
 893      * Returns the resulting multicast listener from adding listener-a
 894      * and listener-b together.
 895      * If listener-a is null, it returns listener-b;
 896      * If listener-b is null, it returns listener-a
 897      * If neither are null, then it creates and returns
 898      * a new AWTEventMulticaster instance which chains a with b.
 899      * @param a event listener-a
 900      * @param b event listener-b
 901      */
 902     protected static EventListener addInternal(EventListener a, EventListener b) {
 903         if (a == null)  return b;
 904         if (b == null)  return a;
 905         return new AWTEventMulticaster(a, b);
 906     }
 907 
 908     /**
 909      * Returns the resulting multicast listener after removing the
 910      * old listener from listener-l.
 911      * If listener-l equals the old listener OR listener-l is null,
 912      * returns null.
 913      * Else if listener-l is an instance of AWTEventMulticaster,
 914      * then it removes the old listener from it.
 915      * Else, returns listener l.
 916      * @param l the listener being removed from
 917      * @param oldl the listener being removed
 918      */
 919     protected static EventListener removeInternal(EventListener l, EventListener oldl) {
 920         if (l == oldl || l == null) {
 921             return null;
 922         } else if (l instanceof AWTEventMulticaster) {
 923             return ((AWTEventMulticaster)l).remove(oldl);
 924         } else {
 925             return l;           // it's not here
 926         }
 927     }
 928 
 929 
 930     /* Serialization support.
 931      */
 932 
 933     protected void saveInternal(ObjectOutputStream s, String k) throws IOException {
 934         if (a instanceof AWTEventMulticaster) {
 935             ((AWTEventMulticaster)a).saveInternal(s, k);
 936         }
 937         else if (a instanceof Serializable) {
 938             s.writeObject(k);
 939             s.writeObject(a);
 940         }
 941 
 942         if (b instanceof AWTEventMulticaster) {
 943             ((AWTEventMulticaster)b).saveInternal(s, k);
 944         }
 945         else if (b instanceof Serializable) {
 946             s.writeObject(k);
 947             s.writeObject(b);
 948         }
 949     }
 950 
 951     protected static void save(ObjectOutputStream s, String k, EventListener l) throws IOException {
 952       if (l == null) {
 953           return;
 954       }
 955       else if (l instanceof AWTEventMulticaster) {
 956           ((AWTEventMulticaster)l).saveInternal(s, k);
 957       }
 958       else if (l instanceof Serializable) {
 959            s.writeObject(k);
 960            s.writeObject(l);
 961       }
 962     }
 963 
 964     /*
 965      * Recursive method which returns a count of the number of listeners in
 966      * EventListener, handling the (common) case of l actually being an
 967      * AWTEventMulticaster.  Additionally, only listeners of type listenerType
 968      * are counted.  Method modified to fix bug 4513402.  -bchristi
 969      */
 970     private static int getListenerCount(EventListener l, Class<?> listenerType) {
 971         if (l instanceof AWTEventMulticaster) {
 972             AWTEventMulticaster mc = (AWTEventMulticaster)l;
 973             return getListenerCount(mc.a, listenerType) +
 974              getListenerCount(mc.b, listenerType);
 975         }
 976         else {
 977             // Only count listeners of correct type
 978             return listenerType.isInstance(l) ? 1 : 0;
 979         }
 980     }
 981 
 982     /*
 983      * Recusive method which populates EventListener array a with EventListeners
 984      * from l.  l is usually an AWTEventMulticaster.  Bug 4513402 revealed that
 985      * if l differed in type from the element type of a, an ArrayStoreException
 986      * would occur.  Now l is only inserted into a if it's of the appropriate
 987      * type.  -bchristi
 988      */
 989     private static int populateListenerArray(EventListener[] a, EventListener l, int index) {
 990         if (l instanceof AWTEventMulticaster) {
 991             AWTEventMulticaster mc = (AWTEventMulticaster)l;
 992             int lhs = populateListenerArray(a, mc.a, index);
 993             return populateListenerArray(a, mc.b, lhs);
 994         }
 995         else if (a.getClass().getComponentType().isInstance(l)) {
 996             a[index] = l;
 997             return index + 1;
 998         }
 999         // Skip nulls, instances of wrong class
1000         else {
1001             return index;
1002         }
1003     }
1004 
1005     /**
1006      * Returns an array of all the objects chained as
1007      * <code><em>Foo</em>Listener</code>s by the specified
1008      * <code>java.util.EventListener</code>.
1009      * <code><em>Foo</em>Listener</code>s are chained by the
1010      * <code>AWTEventMulticaster</code> using the
1011      * <code>add<em>Foo</em>Listener</code> method.
1012      * If a <code>null</code> listener is specified, this method returns an
1013      * empty array. If the specified listener is not an instance of
1014      * <code>AWTEventMulticaster</code>, this method returns an array which
1015      * contains only the specified listener. If no such listeners are chained,
1016      * this method returns an empty array.
1017      *
1018      * @param l the specified <code>java.util.EventListener</code>
1019      * @param listenerType the type of listeners requested; this parameter
1020      *          should specify an interface that descends from
1021      *          <code>java.util.EventListener</code>
1022      * @return an array of all objects chained as
1023      *          <code><em>Foo</em>Listener</code>s by the specified multicast
1024      *          listener, or an empty array if no such listeners have been
1025      *          chained by the specified multicast listener
1026      * @exception NullPointerException if the specified
1027      *             {@code listenertype} parameter is {@code null}
1028      * @exception ClassCastException if <code>listenerType</code>
1029      *          doesn't specify a class or interface that implements
1030      *          <code>java.util.EventListener</code>
1031      *
1032      * @since 1.4
1033      */
1034     @SuppressWarnings("unchecked")
1035     public static <T extends EventListener> T[]
1036         getListeners(EventListener l, Class<T> listenerType)
1037     {
1038         if (listenerType == null) {
1039             throw new NullPointerException ("Listener type should not be null");
1040         }
1041 
1042         int n = getListenerCount(l, listenerType);
1043         T[] result = (T[])Array.newInstance(listenerType, n);
1044         populateListenerArray(result, l, 0);
1045         return result;
1046     }
1047 }