Save This Page
Home » openjdk-7 » java » beans » [javadoc | source]
    1   /*
    2    * Copyright 2007 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   package java.beans;
   26   
   27   import java.util.ArrayList;
   28   import java.util.Collections;
   29   import java.util.EventListener;
   30   import java.util.EventListenerProxy;
   31   import java.util.HashMap;
   32   import java.util.List;
   33   import java.util.Map;
   34   import java.util.Map.Entry;
   35   import java.util.Set;
   36   
   37   /**
   38    * This is an abstract class that provides base functionality
   39    * for the {@link PropertyChangeSupport PropertyChangeSupport} class
   40    * and the {@link VetoableChangeSupport VetoableChangeSupport} class.
   41    *
   42    * @see PropertyChangeListenerMap
   43    * @see VetoableChangeListenerMap
   44    *
   45    * @author Sergey A. Malenkov
   46    */
   47   abstract class ChangeListenerMap<L extends EventListener> {
   48       private Map<String, L[]> map;
   49   
   50       /**
   51        * Creates an array of listeners.
   52        * This method can be optimized by using
   53        * the same instance of the empty array
   54        * when {@code length} is equal to {@code 0}.
   55        *
   56        * @param length  the array length
   57        * @return        an array with specified length
   58        */
   59       protected abstract L[] newArray(int length);
   60   
   61       /**
   62        * Creates a proxy listener for the specified property.
   63        *
   64        * @param name      the name of the property to listen on
   65        * @param listener  the listener to process events
   66        * @return          a proxy listener
   67        */
   68       protected abstract L newProxy(String name, L listener);
   69   
   70       /**
   71        * Adds a listener to the list of listeners for the specified property.
   72        * This listener is called as many times as it was added.
   73        *
   74        * @param name      the name of the property to listen on
   75        * @param listener  the listener to process events
   76        */
   77       public final synchronized void add(String name, L listener) {
   78           if (this.map == null) {
   79               this.map = new HashMap<String, L[]>();
   80           }
   81           L[] array = this.map.get(name);
   82           int size = (array != null)
   83                   ? array.length
   84                   : 0;
   85   
   86           L[] clone = newArray(size + 1);
   87           clone[size] = listener;
   88           if (array != null) {
   89               System.arraycopy(array, 0, clone, 0, size);
   90           }
   91           this.map.put(name, clone);
   92       }
   93   
   94       /**
   95        * Removes a listener from the list of listeners for the specified property.
   96        * If the listener was added more than once to the same event source,
   97        * this listener will be notified one less time after being removed.
   98        *
   99        * @param name      the name of the property to listen on
  100        * @param listener  the listener to process events
  101        */
  102       public final synchronized void remove(String name, L listener) {
  103           if (this.map != null) {
  104               L[] array = this.map.get(name);
  105               if (array != null) {
  106                   for (int i = 0; i < array.length; i++) {
  107                       if (listener.equals(array[i])) {
  108                           int size = array.length - 1;
  109                           if (size > 0) {
  110                               L[] clone = newArray(size);
  111                               System.arraycopy(array, 0, clone, 0, i);
  112                               System.arraycopy(array, i + 1, clone, i, size - i);
  113                               this.map.put(name, clone);
  114                           }
  115                           else {
  116                               this.map.remove(name);
  117                               if (this.map.isEmpty()) {
  118                                   this.map = null;
  119                               }
  120                           }
  121                           break;
  122                       }
  123                   }
  124               }
  125           }
  126       }
  127   
  128       /**
  129        * Returns the list of listeners for the specified property.
  130        *
  131        * @param name  the name of the property
  132        * @return      the corresponding list of listeners
  133        */
  134       public final synchronized L[] get(String name) {
  135           return (this.map != null)
  136                   ? this.map.get(name)
  137                   : null;
  138       }
  139   
  140       /**
  141        * Sets new list of listeners for the specified property.
  142        *
  143        * @param name       the name of the property
  144        * @param listeners  new list of listeners
  145        */
  146       public final void set(String name, L[] listeners) {
  147           if (listeners != null) {
  148               if (this.map == null) {
  149                   this.map = new HashMap<String, L[]>();
  150               }
  151               this.map.put(name, listeners);
  152           }
  153           else if (this.map != null) {
  154               this.map.remove(name);
  155               if (this.map.isEmpty()) {
  156                   this.map = null;
  157               }
  158           }
  159       }
  160   
  161       /**
  162        * Returns all listeners in the map.
  163        *
  164        * @return an array of all listeners
  165        */
  166       public final synchronized L[] getListeners() {
  167           if (this.map == null) {
  168               return newArray(0);
  169           }
  170           List<L> list = new ArrayList<L>();
  171   
  172           L[] listeners = this.map.get(null);
  173           if (listeners != null) {
  174               for (L listener : listeners) {
  175                   list.add(listener);
  176               }
  177           }
  178           for (Entry<String, L[]> entry : this.map.entrySet()) {
  179               String name = entry.getKey();
  180               if (name != null) {
  181                   for (L listener : entry.getValue()) {
  182                       list.add(newProxy(name, listener));
  183                   }
  184               }
  185           }
  186           return list.toArray(newArray(list.size()));
  187       }
  188   
  189       /**
  190        * Returns listeners that have been associated with the named property.
  191        *
  192        * @param name  the name of the property
  193        * @return an array of listeners for the named property
  194        */
  195       public final L[] getListeners(String name) {
  196           if (name != null) {
  197               L[] listeners = get(name);
  198               if (listeners != null) {
  199                   return listeners.clone();
  200               }
  201           }
  202           return newArray(0);
  203       }
  204   
  205       /**
  206        * Indicates whether the map contains
  207        * at least one listener to be notified.
  208        *
  209        * @param name  the name of the property
  210        * @return      {@code true} if at least one listener exists or
  211        *              {@code false} otherwise
  212        */
  213       public final synchronized boolean hasListeners(String name) {
  214           if (this.map == null) {
  215               return false;
  216           }
  217           L[] array = this.map.get(null);
  218           return (array != null) || ((name != null) && (null != this.map.get(name)));
  219       }
  220   
  221       /**
  222        * Returns a set of entries from the map.
  223        * Each entry is a pair consisted of the property name
  224        * and the corresponding list of listeners.
  225        *
  226        * @return a set of entries from the map
  227        */
  228       public final Set<Entry<String, L[]>> getEntries() {
  229           return (this.map != null)
  230                   ? this.map.entrySet()
  231                   : Collections.<Entry<String, L[]>>emptySet();
  232       }
  233   
  234       /**
  235        * Extracts a real listener from the proxy listener.
  236        * It is necessary because default proxy class is not serializable.
  237        *
  238        * @return a real listener
  239        */
  240       public final L extract(L listener) {
  241           while (listener instanceof EventListenerProxy) {
  242               EventListenerProxy<L> proxy = (EventListenerProxy<L>) listener;
  243               listener = proxy.getListener();
  244           }
  245           return listener;
  246       }
  247   }

Save This Page
Home » openjdk-7 » java » beans » [javadoc | source]