Package org.exolab.castor.util

Source Code of org.exolab.castor.util.EventListenerList

/**
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
*    statements and notices.  Redistributions must also contain a
*    copy of this document.
*
* 2. Redistributions in binary form must reproduce the
*    above copyright notice, this list of conditions and the
*    following disclaimer in the documentation and/or other
*    materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
*    products derived from this Software without prior written
*    permission of Intalio, Inc.  For written permission,
*    please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
*    nor may "Exolab" appear in their names without prior written
*    permission of Intalio, Inc. Exolab is a registered
*    trademark of Intalio, Inc.
*
* 5. Due credit should be given to the Exolab Project
*    (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
* INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Contribution(s):
*
* - Jeff Norris, Jeff.Norris@jpl.nasa.gov
*     - Original Author
*
* $Id: EventListenerList.java 5951 2006-05-30 22:18:48Z bsnyder $
*/

package org.exolab.castor.util;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.EventListener;

/**
* <p>This class is an efficient repository for EventListeners based
* on javax.swing.EventListenerList.</p>
*
* <p>This modification of javax.swing.EventListenerList retains the
* core functionality of that class but changes the basic API and adds
* a few more features, as summarized below:<p>
*
* <ol>
* <li>javax.swing.EventListenerList requires all listeners to be
* added in conjunction with a class object that identified the type
* of the listener.  This implementation's add methods simply take the
* listener object.
*
* <li>The listener list returned from javax.swing.EventListenerList
* had to be iterated over in a cumbersome manner because the
* listeners were stored along with their Class objects in the array.
* Since listener classes are not stored in this listener list, the
* returned listener array can be iterated over normally (1 element at
* a time).
*
* <li>The remove method in javax.swing.EventListenerList had return
* type "void".  This implementation's remove method returns true if
* the specified listener was found in the listener array and false
* otherwise.
*
* <li>This implementation adds {@link #add(EventListener, int)},
* which allows the addition of a listener at a specific position in
* the array. 
*
* <li>The add and remove methods in this implementation throw
* IllegalArgumentExceptions when their arguments are null.
* </ol>
*
* <p>As is the case with javax.swing.EventListenerList, this class
* provides multi-threaded safety through a copy-on-modify strategy.
* It is optimized to provide high performance when events are being
* fired, with slightly slower performance than the Collection API
* when listeners are being added and removed.  Like its predecessor,
* this class will never return a null array from getListenerList.</p>
*
* <p>The most important thing to keep in mind when using this class
* is that the array returned by getListenerList is the actual
* internal array of this class and MUST NOT BE MODIFIED UNDER ANY
* CIRCUMSTANCES.  Below is an example of how to use this class,
* borrowed (and slightly modified) from the
* javax.swing.EventListenerList documentation:</p>
*
* <p>Usage example:
*    Say one is defining a class that sends out FooEvents, and one wants
* to allow users of the class to register FooListeners and receive
* notification when FooEvents occur.  The following should be added
* to the class definition:</p>
* <pre>
* EventListenerList listenerList = new EventListenerList();
* FooEvent fooEvent = null;
*
* public void addFooListener(FooListener l) {
*     listenerList.add(l);
* }
*
* public void removeFooListener(FooListener l) {
*     listenerList.remove(l);
* }
*
* // Notify all listeners that have registered interest for
* // notification on this event type.  The event instance
* // is lazily created using the parameters passed into
* // the fire method.
*
* protected void fireFooXXX() {
*     // Guaranteed to return a non-null array
*     EventListener[] listeners = listenerList.getListenerList();
*     // Process the listeners last to first, notifying
*     // those that are interested in this event
*     for (int i = 0 ; i &lt; listeners.length ; i++) {
*         // Lazily create the event:
*         if (fooEvent == null)
*             fooEvent = new FooEvent(this);
*         ((FooListener)listeners[i]).fooXXX(fooEvent);
*     }
* }
* </pre>
*
* <p>foo should be changed to the appropriate name, and fireFooXxx to the
* appropriate method name.  One fire method should exist for each
* notification method in the FooListener interface.</p>
*
* <p>The authors of javax.swing.EventListenerList are Georges Saab,
* Hans Muller, and James Gosling.</p>
*
* @author <a href="mailto:Jeff.Norris@jpl.nasa.gov">Jeff Norris</a>
* @version $Revision: 5951 $ $Date: 2005-12-13 14:58:48 -0700 (Tue, 13 Dec 2005) $
*/
public class EventListenerList implements Serializable {
    /** SerialVersionUID */
    private static final long serialVersionUID = 4472874989562384564L;

  /**
   * A null array to be shared by all empty listener lists
   */
  private final static EventListener[] NULL_ARRAY = new EventListener[0];
 
  /**
   * The internal list of listeners that is returned from
   * getListenerList
   */
  protected transient EventListener[] listenerList = NULL_ARRAY;

  /**
   * <p>Passes back the event listener list as an array of
   * EventListeners.</p>
   *
   * <p>Note that for performance reasons, this implementation passes
   * back the actual data structure in which the listener data is
   * stored internally!  This method is guaranteed to pass back a
   * non-null array, so that no null-checking is required in fire
   * methods.  A zero-length array of Object will be returned if
   * there are currently no listeners.</p>
   *
   * WARNING!!! Absolutely NO modification of
   * the data contained in this array should be made -- if
   * any such manipulation is necessary, it should be done
   * on a copy of the array returned rather than the array
   * itself.
   */
  public EventListener[] getListenerList() {
    return listenerList;
  }

  /**
   * <p>Returns the total number of listeners in this listener
   * list.</p>
   *
   */
  public int getListenerCount() {
    return listenerList.length;
  }

  /**
   * <p>Adds the listener to the end of the listener list.</p>
   *
   * @param newListener the listener to be added
   * @exception IllegalArgumentException if the specified newListener
   * is null
   */
  public synchronized void add(EventListener newListener)
  {
   
    if (newListener==null)
      throw new IllegalArgumentException("Listener to add must not be null.");
   
    if (listenerList == NULL_ARRAY) {
      // if this is the first listener added,
      // initialize the lists
      listenerList = new EventListener[] { newListener };
    } else {
      // Otherwise copy the array and add the new listener
      int oldLength = listenerList.length;
      EventListener[] tmp = new EventListener[oldLength+1];
      System.arraycopy(listenerList, 0, tmp, 0, oldLength);

      tmp[oldLength] = newListener;

      listenerList = tmp;
    }
  }

  /**
   * <p>Adds the listener at the specified index in the listener
   * list.</p>
   *
   * @param newListener the listener to be added
   * @exception IllegalArgumentException if the specified newListener
   * is null, or the specified index is less than zero or greater than
   * the length of the listener list array.
   */
  public synchronized void add(EventListener newListener, int index)
  {
    if (newListener==null)
      throw new IllegalArgumentException("Listener to add must not be null.");
   
    if ((index < 0) || (index > listenerList.length))
      throw new IllegalArgumentException("Index to add listener (" + index +
                                         ") is out of bounds. List length is " +
                                         listenerList.length);
   
    if (listenerList == NULL_ARRAY) {
      // if this is the first listener added, initialize the lists
      listenerList = new EventListener[] { newListener };
    } else {
      // Otherwise copy the array and add the new listener
      int oldLength = listenerList.length;
      EventListener[] tmp = new EventListener[oldLength+1];
      // Copy up to the index where the new listener should go
      System.arraycopy(listenerList, 0, tmp, 0, index);
      // Skip a cell and copy the rest of the list
      System.arraycopy(listenerList, index, tmp, index+1, oldLength-index);
      // Insert the new listener
      tmp[index] = newListener;

      listenerList = tmp;
    }
  }

  /**
   * Removes the listener as a listener of the specified type.
   *
   * @param listenerToRemove the listener to be removed
   * @exception IllegalArgumentException if the specified listener is
   * null
   */
  public synchronized boolean remove(EventListener listenerToRemove) {
    if (listenerToRemove ==null)
      throw new IllegalArgumentException("Listener to remove must " +
                                         "not be null.");
    // Is listenerToRemove on the list?
    int index = -1;
    for (int i = listenerList.length-1; i>=0; i--) {
      if (listenerList[i].equals(listenerToRemove) == true) {
        index = i;
        break;
      }
    }

    // If so,  remove it
    if (index != -1) {
      EventListener[] tmp = new EventListener[listenerList.length-1];
      // Copy the list up to index
      System.arraycopy(listenerList, 0, tmp, 0, index);
      // Copy from one past the index, up to the end of tmp (which is
      // one element shorter than the old list)
      if (index < tmp.length)
        System.arraycopy(listenerList, index+1, tmp, index,
                         tmp.length - index);
      // set the listener array to the new array or null
      listenerList = (tmp.length == 0) ? NULL_ARRAY : tmp;
      return true;
    }
    return false;
  }

  // Serialization support. 
  private void writeObject(ObjectOutputStream s) throws IOException {
    Object[] lList = listenerList;
    s.defaultWriteObject();
 
    // Save the non-null event listeners:
    for (int i = 0; i < lList.length; i+=1) {
      EventListener l = (EventListener)lList[i];
      if ((l!=null) && (l instanceof Serializable)) {
        s.writeObject(l);
      }
    }
 
    s.writeObject(null);
  }

  private void readObject(ObjectInputStream s)
    throws IOException, ClassNotFoundException {
    listenerList = NULL_ARRAY;
    s.defaultReadObject();
    EventListener listenerOrNull;
   
    while (null != (listenerOrNull = (EventListener)s.readObject())) {
      add(listenerOrNull);
    }     
  }
 
  /**
   * Returns a string representation of the EventListenerList.
   */
  public String toString() {
    Object[] lList = listenerList;
    String s = "EventListenerList: ";
    s += lList.length + " listeners: ";
    for (int i = 0 ; i < lList.length ; i++) {
      s += " listener " + lList[i+1];
    }
    return s;
  }

} //-- class: EventListenerList
TOP

Related Classes of org.exolab.castor.util.EventListenerList

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.