Save This Page
Home » openjdk-7 » java » beans » [javadoc | source]
    1   /*
    2    * Copyright 1996-2008 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   
   26   package java.beans;
   27   
   28   import java.lang.ref.Reference;
   29   
   30   import java.lang.reflect.Method;
   31   
   32   /**
   33    * An EventSetDescriptor describes a group of events that a given Java
   34    * bean fires.
   35    * <P>
   36    * The given group of events are all delivered as method calls on a single
   37    * event listener interface, and an event listener object can be registered
   38    * via a call on a registration method supplied by the event source.
   39    */
   40   public class EventSetDescriptor extends FeatureDescriptor {
   41   
   42       private MethodDescriptor[] listenerMethodDescriptors;
   43       private MethodDescriptor addMethodDescriptor;
   44       private MethodDescriptor removeMethodDescriptor;
   45       private MethodDescriptor getMethodDescriptor;
   46   
   47       private Reference<Method[]> listenerMethodsRef;
   48       private Reference<Class> listenerTypeRef;
   49   
   50       private boolean unicast;
   51       private boolean inDefaultEventSet = true;
   52   
   53       /**
   54        * Creates an <TT>EventSetDescriptor</TT> assuming that you are
   55        * following the most simple standard design pattern where a named
   56        * event &quot;fred&quot; is (1) delivered as a call on the single method of
   57        * interface FredListener, (2) has a single argument of type FredEvent,
   58        * and (3) where the FredListener may be registered with a call on an
   59        * addFredListener method of the source component and removed with a
   60        * call on a removeFredListener method.
   61        *
   62        * @param sourceClass  The class firing the event.
   63        * @param eventSetName  The programmatic name of the event.  E.g. &quot;fred&quot;.
   64        *          Note that this should normally start with a lower-case character.
   65        * @param listenerType  The target interface that events
   66        *          will get delivered to.
   67        * @param listenerMethodName  The method that will get called when the event gets
   68        *          delivered to its target listener interface.
   69        * @exception IntrospectionException if an exception occurs during
   70        *              introspection.
   71        */
   72       public EventSetDescriptor(Class<?> sourceClass, String eventSetName,
   73                   Class<?> listenerType, String listenerMethodName)
   74                   throws IntrospectionException {
   75           this(sourceClass, eventSetName, listenerType,
   76                new String[] { listenerMethodName },
   77                Introspector.ADD_PREFIX + getListenerClassName(listenerType),
   78                Introspector.REMOVE_PREFIX + getListenerClassName(listenerType),
   79                Introspector.GET_PREFIX + getListenerClassName(listenerType) + "s");
   80   
   81           String eventName = NameGenerator.capitalize(eventSetName) + "Event";
   82           Method[] listenerMethods = getListenerMethods();
   83           if (listenerMethods.length > 0) {
   84               Class[] args = getParameterTypes(getClass0(), listenerMethods[0]);
   85               // Check for EventSet compliance. Special case for vetoableChange. See 4529996
   86               if (!"vetoableChange".equals(eventSetName) && !args[0].getName().endsWith(eventName)) {
   87                   throw new IntrospectionException("Method \"" + listenerMethodName +
   88                                                    "\" should have argument \"" +
   89                                                    eventName + "\"");
   90               }
   91           }
   92       }
   93   
   94       private static String getListenerClassName(Class cls) {
   95           String className = cls.getName();
   96           return className.substring(className.lastIndexOf('.') + 1);
   97       }
   98   
   99       /**
  100        * Creates an <TT>EventSetDescriptor</TT> from scratch using
  101        * string names.
  102        *
  103        * @param sourceClass  The class firing the event.
  104        * @param eventSetName The programmatic name of the event set.
  105        *          Note that this should normally start with a lower-case character.
  106        * @param listenerType  The Class of the target interface that events
  107        *          will get delivered to.
  108        * @param listenerMethodNames The names of the methods that will get called
  109        *          when the event gets delivered to its target listener interface.
  110        * @param addListenerMethodName  The name of the method on the event source
  111        *          that can be used to register an event listener object.
  112        * @param removeListenerMethodName  The name of the method on the event source
  113        *          that can be used to de-register an event listener object.
  114        * @exception IntrospectionException if an exception occurs during
  115        *              introspection.
  116        */
  117       public EventSetDescriptor(Class<?> sourceClass,
  118                   String eventSetName,
  119                   Class<?> listenerType,
  120                   String listenerMethodNames[],
  121                   String addListenerMethodName,
  122                   String removeListenerMethodName)
  123                   throws IntrospectionException {
  124           this(sourceClass, eventSetName, listenerType,
  125                listenerMethodNames, addListenerMethodName,
  126                removeListenerMethodName, null);
  127       }
  128   
  129       /**
  130        * This constructor creates an EventSetDescriptor from scratch using
  131        * string names.
  132        *
  133        * @param sourceClass  The class firing the event.
  134        * @param eventSetName The programmatic name of the event set.
  135        *          Note that this should normally start with a lower-case character.
  136        * @param listenerType  The Class of the target interface that events
  137        *          will get delivered to.
  138        * @param listenerMethodNames The names of the methods that will get called
  139        *          when the event gets delivered to its target listener interface.
  140        * @param addListenerMethodName  The name of the method on the event source
  141        *          that can be used to register an event listener object.
  142        * @param removeListenerMethodName  The name of the method on the event source
  143        *          that can be used to de-register an event listener object.
  144        * @param getListenerMethodName The method on the event source that
  145        *          can be used to access the array of event listener objects.
  146        * @exception IntrospectionException if an exception occurs during
  147        *              introspection.
  148        * @since 1.4
  149        */
  150       public EventSetDescriptor(Class<?> sourceClass,
  151                   String eventSetName,
  152                   Class<?> listenerType,
  153                   String listenerMethodNames[],
  154                   String addListenerMethodName,
  155                   String removeListenerMethodName,
  156                   String getListenerMethodName)
  157                   throws IntrospectionException {
  158           if (sourceClass == null || eventSetName == null || listenerType == null) {
  159               throw new NullPointerException();
  160           }
  161           setName(eventSetName);
  162           setClass0(sourceClass);
  163           setListenerType(listenerType);
  164   
  165           Method[] listenerMethods = new Method[listenerMethodNames.length];
  166           for (int i = 0; i < listenerMethodNames.length; i++) {
  167               // Check for null names
  168               if (listenerMethodNames[i] == null) {
  169                   throw new NullPointerException();
  170               }
  171               listenerMethods[i] = getMethod(listenerType, listenerMethodNames[i], 1);
  172           }
  173           setListenerMethods(listenerMethods);
  174   
  175           setAddListenerMethod(getMethod(sourceClass, addListenerMethodName, 1));
  176           setRemoveListenerMethod(getMethod(sourceClass, removeListenerMethodName, 1));
  177   
  178           // Be more forgiving of not finding the getListener method.
  179           Method method = Introspector.findMethod(sourceClass,
  180                                                   getListenerMethodName, 0);
  181           if (method != null) {
  182               setGetListenerMethod(method);
  183           }
  184       }
  185   
  186       private static Method getMethod(Class cls, String name, int args)
  187           throws IntrospectionException {
  188           if (name == null) {
  189               return null;
  190           }
  191           Method method = Introspector.findMethod(cls, name, args);
  192           if (method == null) {
  193               throw new IntrospectionException("Method not found: " + name +
  194                                                " on class " + cls.getName());
  195           }
  196           return method;
  197       }
  198   
  199       /**
  200        * Creates an <TT>EventSetDescriptor</TT> from scratch using
  201        * <TT>java.lang.reflect.Method</TT> and <TT>java.lang.Class</TT> objects.
  202        *
  203        * @param eventSetName The programmatic name of the event set.
  204        * @param listenerType The Class for the listener interface.
  205        * @param listenerMethods  An array of Method objects describing each
  206        *          of the event handling methods in the target listener.
  207        * @param addListenerMethod  The method on the event source
  208        *          that can be used to register an event listener object.
  209        * @param removeListenerMethod  The method on the event source
  210        *          that can be used to de-register an event listener object.
  211        * @exception IntrospectionException if an exception occurs during
  212        *              introspection.
  213        */
  214       public EventSetDescriptor(String eventSetName,
  215                   Class<?> listenerType,
  216                   Method listenerMethods[],
  217                   Method addListenerMethod,
  218                   Method removeListenerMethod)
  219                   throws IntrospectionException {
  220           this(eventSetName, listenerType, listenerMethods,
  221                addListenerMethod, removeListenerMethod, null);
  222       }
  223   
  224       /**
  225        * This constructor creates an EventSetDescriptor from scratch using
  226        * java.lang.reflect.Method and java.lang.Class objects.
  227        *
  228        * @param eventSetName The programmatic name of the event set.
  229        * @param listenerType The Class for the listener interface.
  230        * @param listenerMethods  An array of Method objects describing each
  231        *          of the event handling methods in the target listener.
  232        * @param addListenerMethod  The method on the event source
  233        *          that can be used to register an event listener object.
  234        * @param removeListenerMethod  The method on the event source
  235        *          that can be used to de-register an event listener object.
  236        * @param getListenerMethod The method on the event source
  237        *          that can be used to access the array of event listener objects.
  238        * @exception IntrospectionException if an exception occurs during
  239        *              introspection.
  240        * @since 1.4
  241        */
  242       public EventSetDescriptor(String eventSetName,
  243                   Class<?> listenerType,
  244                   Method listenerMethods[],
  245                   Method addListenerMethod,
  246                   Method removeListenerMethod,
  247                   Method getListenerMethod)
  248                   throws IntrospectionException {
  249           setName(eventSetName);
  250           setListenerMethods(listenerMethods);
  251           setAddListenerMethod(addListenerMethod);
  252           setRemoveListenerMethod( removeListenerMethod);
  253           setGetListenerMethod(getListenerMethod);
  254           setListenerType(listenerType);
  255       }
  256   
  257       /**
  258        * Creates an <TT>EventSetDescriptor</TT> from scratch using
  259        * <TT>java.lang.reflect.MethodDescriptor</TT> and <TT>java.lang.Class</TT>
  260        *  objects.
  261        *
  262        * @param eventSetName The programmatic name of the event set.
  263        * @param listenerType The Class for the listener interface.
  264        * @param listenerMethodDescriptors  An array of MethodDescriptor objects
  265        *           describing each of the event handling methods in the
  266        *           target listener.
  267        * @param addListenerMethod  The method on the event source
  268        *          that can be used to register an event listener object.
  269        * @param removeListenerMethod  The method on the event source
  270        *          that can be used to de-register an event listener object.
  271        * @exception IntrospectionException if an exception occurs during
  272        *              introspection.
  273        */
  274       public EventSetDescriptor(String eventSetName,
  275                   Class<?> listenerType,
  276                   MethodDescriptor listenerMethodDescriptors[],
  277                   Method addListenerMethod,
  278                   Method removeListenerMethod)
  279                   throws IntrospectionException {
  280           setName(eventSetName);
  281           this.listenerMethodDescriptors = listenerMethodDescriptors;
  282           setAddListenerMethod(addListenerMethod);
  283           setRemoveListenerMethod(removeListenerMethod);
  284           setListenerType(listenerType);
  285       }
  286   
  287       /**
  288        * Gets the <TT>Class</TT> object for the target interface.
  289        *
  290        * @return The Class object for the target interface that will
  291        * get invoked when the event is fired.
  292        */
  293       public Class<?> getListenerType() {
  294           return (this.listenerTypeRef != null)
  295                   ? this.listenerTypeRef.get()
  296                   : null;
  297       }
  298   
  299       private void setListenerType(Class cls) {
  300           this.listenerTypeRef = getWeakReference(cls);
  301       }
  302   
  303       /**
  304        * Gets the methods of the target listener interface.
  305        *
  306        * @return An array of <TT>Method</TT> objects for the target methods
  307        * within the target listener interface that will get called when
  308        * events are fired.
  309        */
  310       public synchronized Method[] getListenerMethods() {
  311           Method[] methods = getListenerMethods0();
  312           if (methods == null) {
  313               if (listenerMethodDescriptors != null) {
  314                   methods = new Method[listenerMethodDescriptors.length];
  315                   for (int i = 0; i < methods.length; i++) {
  316                       methods[i] = listenerMethodDescriptors[i].getMethod();
  317                   }
  318               }
  319               setListenerMethods(methods);
  320           }
  321           return methods;
  322       }
  323   
  324       private void setListenerMethods(Method[] methods) {
  325           if (methods == null) {
  326               return;
  327           }
  328           if (listenerMethodDescriptors == null) {
  329               listenerMethodDescriptors = new MethodDescriptor[methods.length];
  330               for (int i = 0; i < methods.length; i++) {
  331                   listenerMethodDescriptors[i] = new MethodDescriptor(methods[i]);
  332               }
  333           }
  334           this.listenerMethodsRef = getSoftReference(methods);
  335       }
  336   
  337       private Method[] getListenerMethods0() {
  338           return (this.listenerMethodsRef != null)
  339                   ? this.listenerMethodsRef.get()
  340                   : null;
  341       }
  342   
  343       /**
  344        * Gets the <code>MethodDescriptor</code>s of the target listener interface.
  345        *
  346        * @return An array of <code>MethodDescriptor</code> objects for the target methods
  347        * within the target listener interface that will get called when
  348        * events are fired.
  349        */
  350       public synchronized MethodDescriptor[] getListenerMethodDescriptors() {
  351           return listenerMethodDescriptors;
  352       }
  353   
  354       /**
  355        * Gets the method used to add event listeners.
  356        *
  357        * @return The method used to register a listener at the event source.
  358        */
  359       public synchronized Method getAddListenerMethod() {
  360           return (addMethodDescriptor != null ?
  361                       addMethodDescriptor.getMethod() : null);
  362       }
  363   
  364       private synchronized void setAddListenerMethod(Method method) {
  365           if (method == null) {
  366               return;
  367           }
  368           if (getClass0() == null) {
  369               setClass0(method.getDeclaringClass());
  370           }
  371           addMethodDescriptor = new MethodDescriptor(method);
  372           setTransient(method.getAnnotation(Transient.class));
  373       }
  374   
  375       /**
  376        * Gets the method used to remove event listeners.
  377        *
  378        * @return The method used to remove a listener at the event source.
  379        */
  380       public synchronized Method getRemoveListenerMethod() {
  381           return (removeMethodDescriptor != null ?
  382                       removeMethodDescriptor.getMethod() : null);
  383       }
  384   
  385       private synchronized void setRemoveListenerMethod(Method method) {
  386           if (method == null) {
  387               return;
  388           }
  389           if (getClass0() == null) {
  390               setClass0(method.getDeclaringClass());
  391           }
  392           removeMethodDescriptor = new MethodDescriptor(method);
  393           setTransient(method.getAnnotation(Transient.class));
  394       }
  395   
  396       /**
  397        * Gets the method used to access the registered event listeners.
  398        *
  399        * @return The method used to access the array of listeners at the event
  400        *         source or null if it doesn't exist.
  401        * @since 1.4
  402        */
  403       public synchronized Method getGetListenerMethod() {
  404           return (getMethodDescriptor != null ?
  405                       getMethodDescriptor.getMethod() : null);
  406       }
  407   
  408       private synchronized void setGetListenerMethod(Method method) {
  409           if (method == null) {
  410               return;
  411           }
  412           if (getClass0() == null) {
  413               setClass0(method.getDeclaringClass());
  414           }
  415           getMethodDescriptor = new MethodDescriptor(method);
  416           setTransient(method.getAnnotation(Transient.class));
  417       }
  418   
  419       /**
  420        * Mark an event set as unicast (or not).
  421        *
  422        * @param unicast  True if the event set is unicast.
  423        */
  424       public void setUnicast(boolean unicast) {
  425           this.unicast = unicast;
  426       }
  427   
  428       /**
  429        * Normally event sources are multicast.  However there are some
  430        * exceptions that are strictly unicast.
  431        *
  432        * @return  <TT>true</TT> if the event set is unicast.
  433        *          Defaults to <TT>false</TT>.
  434        */
  435       public boolean isUnicast() {
  436           return unicast;
  437       }
  438   
  439       /**
  440        * Marks an event set as being in the &quot;default&quot; set (or not).
  441        * By default this is <TT>true</TT>.
  442        *
  443        * @param inDefaultEventSet <code>true</code> if the event set is in
  444        *                          the &quot;default&quot; set,
  445        *                          <code>false</code> if not
  446        */
  447       public void setInDefaultEventSet(boolean inDefaultEventSet) {
  448           this.inDefaultEventSet = inDefaultEventSet;
  449       }
  450   
  451       /**
  452        * Reports if an event set is in the &quot;default&quot; set.
  453        *
  454        * @return  <TT>true</TT> if the event set is in
  455        *          the &quot;default&quot; set.  Defaults to <TT>true</TT>.
  456        */
  457       public boolean isInDefaultEventSet() {
  458           return inDefaultEventSet;
  459       }
  460   
  461       /*
  462        * Package-private constructor
  463        * Merge two event set descriptors.  Where they conflict, give the
  464        * second argument (y) priority over the first argument (x).
  465        *
  466        * @param x  The first (lower priority) EventSetDescriptor
  467        * @param y  The second (higher priority) EventSetDescriptor
  468        */
  469       EventSetDescriptor(EventSetDescriptor x, EventSetDescriptor y) {
  470           super(x,y);
  471           listenerMethodDescriptors = x.listenerMethodDescriptors;
  472           if (y.listenerMethodDescriptors != null) {
  473               listenerMethodDescriptors = y.listenerMethodDescriptors;
  474           }
  475   
  476           listenerTypeRef = x.listenerTypeRef;
  477           if (y.listenerTypeRef != null) {
  478               listenerTypeRef = y.listenerTypeRef;
  479           }
  480   
  481           addMethodDescriptor = x.addMethodDescriptor;
  482           if (y.addMethodDescriptor != null) {
  483               addMethodDescriptor = y.addMethodDescriptor;
  484           }
  485   
  486           removeMethodDescriptor = x.removeMethodDescriptor;
  487           if (y.removeMethodDescriptor != null) {
  488               removeMethodDescriptor = y.removeMethodDescriptor;
  489           }
  490   
  491           getMethodDescriptor = x.getMethodDescriptor;
  492           if (y.getMethodDescriptor != null) {
  493               getMethodDescriptor = y.getMethodDescriptor;
  494           }
  495   
  496           unicast = y.unicast;
  497           if (!x.inDefaultEventSet || !y.inDefaultEventSet) {
  498               inDefaultEventSet = false;
  499           }
  500       }
  501   
  502       /*
  503        * Package-private dup constructor
  504        * This must isolate the new object from any changes to the old object.
  505        */
  506       EventSetDescriptor(EventSetDescriptor old) {
  507           super(old);
  508           if (old.listenerMethodDescriptors != null) {
  509               int len = old.listenerMethodDescriptors.length;
  510               listenerMethodDescriptors = new MethodDescriptor[len];
  511               for (int i = 0; i < len; i++) {
  512                   listenerMethodDescriptors[i] = new MethodDescriptor(
  513                                           old.listenerMethodDescriptors[i]);
  514               }
  515           }
  516           listenerTypeRef = old.listenerTypeRef;
  517   
  518           addMethodDescriptor = old.addMethodDescriptor;
  519           removeMethodDescriptor = old.removeMethodDescriptor;
  520           getMethodDescriptor = old.getMethodDescriptor;
  521   
  522           unicast = old.unicast;
  523           inDefaultEventSet = old.inDefaultEventSet;
  524       }
  525   }

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