001    /* java.beans.EventSetDescriptor
002     Copyright (C) 1998, 2006 Free Software Foundation, Inc.
003    
004     This file is part of GNU Classpath.
005    
006     GNU Classpath is free software; you can redistribute it and/or modify
007     it under the terms of the GNU General Public License as published by
008     the Free Software Foundation; either version 2, or (at your option)
009     any later version.
010     
011     GNU Classpath is distributed in the hope that it will be useful, but
012     WITHOUT ANY WARRANTY; without even the implied warranty of
013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     General Public License for more details.
015    
016     You should have received a copy of the GNU General Public License
017     along with GNU Classpath; see the file COPYING.  If not, write to the
018     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019     02110-1301 USA.
020    
021     Linking this library statically or dynamically with other modules is
022     making a combined work based on this library.  Thus, the terms and
023     conditions of the GNU General Public License cover the whole
024     combination.
025    
026     As a special exception, the copyright holders of this library give you
027     permission to link this library with independent modules to produce an
028     executable, regardless of the license terms of these independent
029     modules, and to copy and distribute the resulting executable under
030     terms of your choice, provided that you also meet, for each linked
031     independent module, the terms and conditions of the license of that
032     module.  An independent module is a module which is not derived from
033     or based on this library.  If you modify this library, you may extend
034     this exception to your version of the library, but you are not
035     obligated to do so.  If you do not wish to do so, delete this
036     exception statement from your version. */
037    
038    
039    package java.beans;
040    
041    import gnu.java.lang.ClassHelper;
042    
043    import java.lang.reflect.Method;
044    import java.lang.reflect.Modifier;
045    import java.util.Vector;
046    
047    /**
048     * EventSetDescriptor describes the hookup between an event source class and
049     * an event listener class.
050     * 
051     * <p>EventSets have several attributes: the listener class,
052     * the events that can be fired to the listener (methods in the listener
053     * class), and an add and remove listener method from the event firer's
054     * class.
055     * </p>
056     * 
057     * <p>
058     * The methods have these constraints on them:
059     * <ul>
060     * <li>event firing methods: must have <code>void</code> return value. Any
061     * parameters and exceptions are allowed. May be public, protected or
062     * package-protected. (Don't ask me why that is, I'm just following the spec.
063     * The only place it is even mentioned is in the Java Beans white paper, and
064     * there it is only implied.)</li>
065     * 
066     * <li>add listener method: must have <code>void</code> return value. Must
067     * take exactly one argument, of the listener class's type. May fire either
068     * zero exceptions, or one exception of type
069     * <code>java.util.TooManyListenersException</code>.
070     * Must be public.</li>
071     * 
072     * <li>remove listener method: must have <code>void</code> return value. Must
073     * take exactly one argument, of the listener class's type. May not fire any
074     * exceptions. Must be public.</li>
075     * </ul>
076     * 
077     * <p>
078     * A final constraint is that event listener classes must extend from
079     * EventListener.
080     * </p>
081     * 
082     * <p>
083     * There are also various design patterns associated with some of the methods
084     * of construction. Those are explained in more detail in the appropriate
085     * constructors.
086     * </p>
087     * 
088     * <p>
089     * <strong>Documentation Convention:</strong> for proper Internalization of
090     * Beans inside an RAD tool, sometimes there are two names for a property or
091     * method: a programmatic, or locale-independent name, which can be used
092     * anywhere, and a localized, display name, for ease of use. In the
093     * documentation I will specify different String values as either
094     * <em>programmatic</em> or <em>localized</em> to make this distinction clear.
095     * 
096     * @author John Keiser
097     * @author Robert Schuster (robertschuster@fsfe.org)
098     * @since 1.1
099     */
100    
101    public class EventSetDescriptor extends FeatureDescriptor
102    {
103      private Method addListenerMethod;
104    
105      private Method removeListenerMethod;
106    
107      private Class listenerType;
108    
109      private MethodDescriptor[] listenerMethodDescriptors;
110    
111      private Method[] listenerMethods;
112    
113      private Method getListenerMethod;
114    
115      private boolean unicast;
116    
117      private boolean inDefaultEventSet = true;
118    
119      /**
120       * Creates a new <code>EventSetDescriptor</code<.
121       * 
122       * <p>
123       * This version of the constructor enforces the rules imposed on the methods
124       * described at the top of this class, as well as searching for:
125       * </p>
126       * 
127       * <ol>
128       * <li>
129       * The event-firing method must be non-private with signature <code>void
130       * &lt;listenerMethodName&gt;(&lt;eventSetName&gt;Event)</code> (where
131       * <code>&lt;eventSetName&gt;</code> has its first character capitalized
132       * by the constructor and the Event is a descendant of
133       * {@link java.util.EventObject}) in class <code>listenerType</code>
134       * (any exceptions may be thrown). <b>Implementation note:</b> Note that
135       * there could conceivably be multiple methods with this type of signature
136       * (example: <code>java.util.MouseEvent</code> vs.
137       * <code>my.very.own.MouseEvent</code>). In this implementation, all
138       * methods fitting the description will be put into the
139       * <code>EventSetDescriptor</code>, even though the spec says only one
140       * should be chosen (they probably weren't thinking as pathologically as I
141       * was). I don't like arbitrarily choosing things. If your class has only one
142       * such signature, as most do, you'll have no problems.</li>
143       * 
144       * <li>The add and remove methods must be public and named <code>void
145       * add&lt;eventSetName&gt;Listener(&lt;listenerType&gt;)</code> and
146       * <code>void remove&lt;eventSetName&gt;Listener(&lt;listenerType&gt;)</code>
147       * in in class <code>eventSourceClass</code>, where
148       * <code>&lt;eventSetName&gt;</code> will have its first letter capitalized.
149       * Standard exception rules (see class description) apply.</li>
150       * </ol>
151       * 
152       * @param eventSourceClass
153       *          the class containing the add/remove listener methods.
154       * @param eventSetName
155       *          the programmatic name of the event set, generally starting with a
156       *          lowercase letter (i.e. fooManChu instead of FooManChu). This will
157       *          be used to generate the name of the event object as well as the
158       *          names of the add and remove methods.
159       * @param listenerType
160       *          the class containing the event firing method.
161       * @param listenerMethodName
162       *          the name of the event firing method.
163       * @exception IntrospectionException
164       *              if listenerType is not an EventListener, or if methods are not
165       *              found or are invalid.
166       */
167      public EventSetDescriptor(Class<?> eventSourceClass, String eventSetName,
168                                Class<?> listenerType, String listenerMethodName)
169          throws IntrospectionException
170      {
171        setName(eventSetName);
172        if (!java.util.EventListener.class.isAssignableFrom(listenerType))
173          {
174            throw new IntrospectionException(
175                      "Listener type is not an EventListener.");
176          }
177    
178        String[] names = new String[1];
179        names[0] = listenerMethodName;
180    
181        try
182          {
183            eventSetName = Character.toUpperCase(eventSetName.charAt(0))
184                           + eventSetName.substring(1);
185          }
186        catch (StringIndexOutOfBoundsException e)
187          {
188            eventSetName = "";
189          }
190    
191        findMethods(eventSourceClass, listenerType, names,
192                    "add" + eventSetName + "Listener",
193                    "remove" + eventSetName + "Listener", eventSetName + "Event");
194        this.listenerType = listenerType;
195        checkAddListenerUnicast();
196        if (this.removeListenerMethod.getExceptionTypes().length > 0)
197          {
198            throw new IntrospectionException(
199                      "Listener remove method throws exceptions.");
200          }
201      }
202    
203      /**
204       * Creates a new <code>EventSetDescriptor</code>.
205       * 
206       * <p>This form of the constructor allows you to specify the names of the
207       * methods and adds no new constraints on top of the rules already described
208       * at the top of the class.
209       * </p>
210       * 
211       * @param eventSourceClass
212       *          the class containing the add and remove listener methods.
213       * @param eventSetName
214       *          the programmatic name of the event set, generally starting with a
215       *          lowercase letter (i.e. fooManChu instead of FooManChu).
216       * @param listenerType
217       *          the class containing the event firing methods.
218       * @param listenerMethodNames
219       *          the names of the even firing methods.
220       * @param addListenerMethodName
221       *          the name of the add listener method.
222       * @param removeListenerMethodName
223       *          the name of the remove listener method.
224       * @exception IntrospectionException
225       *              if listenerType is not an EventListener or if methods are not
226       *              found or are invalid.
227       */
228      public EventSetDescriptor(Class<?> eventSourceClass, String eventSetName,
229                                Class<?> listenerType, String[] listenerMethodNames,
230                                String addListenerMethodName,
231                                String removeListenerMethodName)
232          throws IntrospectionException
233      {
234        setName(eventSetName);
235        if (!java.util.EventListener.class.isAssignableFrom(listenerType))
236          {
237            throw new IntrospectionException(
238                      "Listener type is not an EventListener.");
239          }
240    
241        findMethods(eventSourceClass, listenerType, listenerMethodNames,
242                    addListenerMethodName, removeListenerMethodName, null);
243        this.listenerType = listenerType;
244        checkAddListenerUnicast();
245        if (this.removeListenerMethod.getExceptionTypes().length > 0)
246          {
247            throw new IntrospectionException(
248                      "Listener remove method throws exceptions.");
249          }
250      }
251    
252      /**
253       * Creates a new <code>EventSetDescriptor</code>.
254       * 
255       * <p>
256       * This variant of the constructor allows you to specify the names of the
257       * methods and adds no new constraints on top of the rules already described
258       * at the top of the class.
259       * </p>
260       * <p>
261       * A valid GetListener method is public, flags no exceptions and has one
262       * argument which is of type <code>Class</code>
263       * {@link java.awt.Component#getListeners(Class)} is such a method.
264       * </p>
265       * <p>
266       * Note: The validity of the return value of the GetListener method is not
267       * checked.
268       * </p>
269       * 
270       * @param eventSourceClass
271       *          the class containing the add and remove listener methods.
272       * @param eventSetName
273       *          the programmatic name of the event set, generally starting with a
274       *          lowercase letter (i.e. fooManChu instead of FooManChu).
275       * @param listenerType
276       *          the class containing the event firing methods.
277       * @param listenerMethodNames
278       *          the names of the even firing methods.
279       * @param addListenerMethodName
280       *          the name of the add listener method.
281       * @param removeListenerMethodName
282       *          the name of the remove listener method.
283       * @param getListenerMethodName
284       *          Name of a method which returns the array of listeners.
285       * @exception IntrospectionException
286       *              if listenerType is not an EventListener or if methods are not
287       *              found or are invalid.
288       * @since 1.4
289       */
290      public EventSetDescriptor(Class<?> eventSourceClass, String eventSetName,
291                                Class<?> listenerType, String[] listenerMethodNames,
292                                String addListenerMethodName,
293                                String removeListenerMethodName,
294                                String getListenerMethodName)
295          throws IntrospectionException
296      {
297        this(eventSourceClass, eventSetName, listenerType, listenerMethodNames,
298             addListenerMethodName, removeListenerMethodName);
299    
300        Method newGetListenerMethod = null;
301    
302        try
303          {
304            newGetListenerMethod 
305              = eventSourceClass.getMethod(getListenerMethodName,
306                                           new Class[] { Class.class });
307          }
308        catch (NoSuchMethodException nsme)
309          {
310            throw (IntrospectionException) 
311              new IntrospectionException("No method named " + getListenerMethodName
312                                          + " in class " + listenerType
313                                          + " which can be used as"
314                                          + " getListenerMethod.").initCause(nsme);
315          }
316    
317        // Note: This does not check the return value (which
318        // should be EventListener[]) but the JDK does not either.
319    
320        getListenerMethod = newGetListenerMethod;
321    
322      }
323    
324      /**
325       * Creates a new <code>EventSetDescriptor.</code>
326       * 
327       * <p>
328       * This variant of the constructor allows you to specify the names of the
329       * methods and adds no new constraints on top of the rules already described
330       * at the top of the class.
331       * </p>
332       * <p>
333       * A valid GetListener method is public, flags no exceptions and has one
334       * argument which is of type <code>Class</code>
335       * {@link java.awt.Component#getListeners(Class)} is such a method.
336       * </p>
337       * <p>
338       * Note: The validity of the return value of the GetListener method is not
339       * checked.
340       * </p>
341       * 
342       * @param eventSetName
343       *          the programmatic name of the event set, generally starting with a
344       *          lowercase letter (i.e. fooManChu instead of FooManChu).
345       * @param listenerType
346       *          the class containing the listenerMethods.
347       * @param listenerMethods
348       *          the event firing methods.
349       * @param addListenerMethod
350       *          the add listener method.
351       * @param removeListenerMethod
352       *          the remove listener method.
353       * @param getListenerMethod
354       *          The method which returns an array of the listeners.
355       * @exception IntrospectionException
356       *              if the listenerType is not an EventListener, or any of the
357       *              methods are invalid.
358       * @since 1.4
359       */
360      public EventSetDescriptor(String eventSetName, Class<?> listenerType,
361                                Method[] listenerMethods, Method addListenerMethod,
362                                Method removeListenerMethod,
363                                Method getListenerMethod)
364          throws IntrospectionException
365      {
366        this(eventSetName, listenerType, listenerMethods, addListenerMethod,
367             removeListenerMethod);
368    
369        // Do no checks if the getListenerMethod is null.
370        if (getListenerMethod.getParameterTypes().length != 1
371            || getListenerMethod.getParameterTypes()[0] != Class.class
372            || getListenerMethod.getExceptionTypes().length > 0
373            || !Modifier.isPublic(getListenerMethod.getModifiers()))
374          throw new IntrospectionException("GetListener method is invalid.");
375    
376        // Note: This does not check the return value (which
377        // should be EventListener[]) but the JDK does not either.
378    
379        this.getListenerMethod = getListenerMethod;
380      }
381    
382      /**
383       * Creates a new <code>EventSetDescriptor</code>.
384       * 
385       * <p>This form of constructor allows you to explicitly say which methods
386       * do what, and no reflection is done by the <code>EventSetDescriptor</code>.
387       * The methods are, however, checked to ensure that they follow the rules
388       * set forth at the top of the class.
389       * 
390       * @param eventSetName
391       *          the programmatic name of the event set, generally starting with a
392       *          lowercase letter (i.e. fooManChu instead of FooManChu).
393       * @param listenerType
394       *          the class containing the listenerMethods.
395       * @param listenerMethods
396       *          the event firing methods.
397       * @param addListenerMethod
398       *          the add listener method.
399       * @param removeListenerMethod
400       *          the remove listener method.
401       * @exception IntrospectionException
402       *              if the listenerType is not an EventListener, or any of the
403       *              methods are invalid.
404       */
405      public EventSetDescriptor(String eventSetName, Class<?> listenerType,
406                                Method[] listenerMethods, Method addListenerMethod,
407                                Method removeListenerMethod)
408          throws IntrospectionException
409      {
410        setName(eventSetName);
411        if (!java.util.EventListener.class.isAssignableFrom(listenerType))
412          {
413            throw new IntrospectionException(
414                      "Listener type is not an EventListener.");
415          }
416    
417        this.listenerMethods = listenerMethods;
418        this.addListenerMethod = addListenerMethod;
419        this.removeListenerMethod = removeListenerMethod;
420        this.listenerType = listenerType;
421        checkMethods();
422        checkAddListenerUnicast();
423        if (this.removeListenerMethod.getExceptionTypes().length > 0)
424          {
425            throw new IntrospectionException(
426                      "Listener remove method throws exceptions.");
427          }
428      }
429    
430      /** Creates a new <code>EventSetDescriptor</code>.
431       * 
432       * <p>This form of constructor allows you to explicitly say which methods do
433       * what, and no reflection is done by the <code>EventSetDescriptor</code>.
434       * The methods are, however, checked to ensure that they follow the rules
435       * set forth at the top of the class.
436       * 
437       * @param eventSetName
438       *          the programmatic name of the event set, generally starting with a
439       *          lowercase letter (i.e. fooManChu instead of FooManChu).
440       * @param listenerType
441       *          the class containing the listenerMethods.
442       * @param listenerMethodDescriptors
443       *          the event firing methods.
444       * @param addListenerMethod
445       *          the add listener method.
446       * @param removeListenerMethod
447       *          the remove listener method.
448       * @exception IntrospectionException
449       *              if the listenerType is not an EventListener, or any of the
450       *              methods are invalid.
451       */
452      public EventSetDescriptor(String eventSetName, Class<?> listenerType,
453                                MethodDescriptor[] listenerMethodDescriptors,
454                                Method addListenerMethod,
455                                Method removeListenerMethod)
456          throws IntrospectionException
457      {
458        setName(eventSetName);
459        if (!java.util.EventListener.class.isAssignableFrom(listenerType))
460          {
461            throw new IntrospectionException(
462                      "Listener type is not an EventListener.");
463          }
464    
465        this.listenerMethodDescriptors = listenerMethodDescriptors;
466        this.listenerMethods = new Method[listenerMethodDescriptors.length];
467        for (int i = 0; i < this.listenerMethodDescriptors.length; i++)
468          {
469            this.listenerMethods[i]
470               = this.listenerMethodDescriptors[i].getMethod();
471          }
472    
473        this.addListenerMethod = addListenerMethod;
474        this.removeListenerMethod = removeListenerMethod;
475        this.listenerType = listenerType;
476        checkMethods();
477        checkAddListenerUnicast();
478        if (this.removeListenerMethod.getExceptionTypes().length > 0)
479          {
480            throw new IntrospectionException(
481                      "Listener remove method throws exceptions.");
482          }
483      }
484    
485      /** Returns the class that contains the event firing methods.
486       */
487      public Class<?> getListenerType()
488      {
489        return listenerType;
490      }
491    
492      /** Returns the event firing methods.
493       */
494      public Method[] getListenerMethods()
495      {
496        return listenerMethods;
497      }
498    
499      /** Returns the event firing methods as {@link MethodDescriptor}.
500       */
501      public MethodDescriptor[] getListenerMethodDescriptors()
502      {
503        if (listenerMethodDescriptors == null)
504          {
505            listenerMethodDescriptors
506              = new MethodDescriptor[listenerMethods.length];
507            
508            for (int i = 0; i < listenerMethods.length; i++)
509              {
510                listenerMethodDescriptors[i]
511                  = new MethodDescriptor(listenerMethods[i]);
512              }
513          }
514        
515        return listenerMethodDescriptors;
516      }
517    
518      /** Returns the add listener method.
519       */
520      public Method getAddListenerMethod()
521      {
522        return addListenerMethod;
523      }
524    
525      /* Returns the remove listener method.
526       */
527      public Method getRemoveListenerMethod()
528      {
529        return removeListenerMethod;
530      }
531    
532      /**
533       * Returns the method that retrieves the listeners or <code>null</code> if
534       * it does not exist.
535       */
536      public Method getGetListenerMethod()
537      {
538        return getListenerMethod;
539      }
540    
541      /** Sets whether or not multiple listeners may be added.
542       * 
543       * @param unicast
544       *          whether or not multiple listeners may be added.
545       */
546      public void setUnicast(boolean unicast)
547      {
548        this.unicast = unicast;
549      }
550    
551      /** Returns whether or not multiple listeners may be added.
552       * (Defaults to false.)
553       */
554      public boolean isUnicast()
555      {
556        return unicast;
557      }
558    
559      /** Sets whether or not this is in the default event set.
560       * 
561       * @param inDefaultEventSet
562       *          whether this is in the default event set.
563       */
564      public void setInDefaultEventSet(boolean inDefaultEventSet)
565      {
566        this.inDefaultEventSet = inDefaultEventSet;
567      }
568    
569      /** Returns whether or not this is in the default event set.
570       * (Defaults to true.)
571       */
572      public boolean isInDefaultEventSet()
573      {
574        return inDefaultEventSet;
575      }
576    
577      private void checkAddListenerUnicast() throws IntrospectionException
578      {
579        Class[] addListenerExceptions = this.addListenerMethod.getExceptionTypes();
580        if (addListenerExceptions.length > 1)
581          {
582            throw new IntrospectionException(
583                      "Listener add method throws too many exceptions.");
584          }
585        else if (addListenerExceptions.length == 1
586                 && !java.util.TooManyListenersException.class
587                    .isAssignableFrom(addListenerExceptions[0]))
588          {
589            throw new IntrospectionException(
590                      "Listener add method throws too many exceptions.");
591          }
592      }
593    
594      private void checkMethods() throws IntrospectionException
595      {
596        if (!addListenerMethod.getDeclaringClass()
597            .isAssignableFrom(removeListenerMethod.getDeclaringClass())
598            && !removeListenerMethod.getDeclaringClass()
599            .isAssignableFrom(addListenerMethod.getDeclaringClass()))
600          {
601            throw new IntrospectionException(
602                      "add and remove listener methods do not come from the"
603                      + " same class.  This is bad.");
604          }
605        if (!addListenerMethod.getReturnType().equals(java.lang.Void.TYPE)
606            || addListenerMethod.getParameterTypes().length != 1
607            || !listenerType.equals(addListenerMethod.getParameterTypes()[0])
608            || !Modifier.isPublic(addListenerMethod.getModifiers()))
609          {
610            throw new IntrospectionException("Add Listener Method invalid.");
611          }
612        if (!removeListenerMethod.getReturnType().equals(java.lang.Void.TYPE)
613            || removeListenerMethod.getParameterTypes().length != 1
614            || !listenerType.equals(removeListenerMethod.getParameterTypes()[0])
615            || removeListenerMethod.getExceptionTypes().length > 0
616            || !Modifier.isPublic(removeListenerMethod.getModifiers()))
617          {
618            throw new IntrospectionException("Remove Listener Method invalid.");
619          }
620    
621        for (int i = 0; i < listenerMethods.length; i++)
622          {
623            if (!listenerMethods[i].getReturnType().equals(java.lang.Void.TYPE)
624                || Modifier.isPrivate(listenerMethods[i].getModifiers()))
625              {
626                throw new IntrospectionException("Event Method "
627                                                 + listenerMethods[i].getName()
628                                                 + " non-void or private.");
629              }
630            if (!listenerMethods[i].getDeclaringClass()
631                .isAssignableFrom(listenerType))
632              {
633                throw new IntrospectionException("Event Method "
634                                                 + listenerMethods[i].getName()
635                                                 + " not from class "
636                                                 + listenerType.getName());
637              }
638          }
639      }
640    
641      private void findMethods(Class eventSourceClass, Class listenerType,
642                               String listenerMethodNames[],
643                               String addListenerMethodName,
644                               String removeListenerMethodName,
645                               String absurdEventClassCheckName)
646          throws IntrospectionException
647      {
648    
649        /* Find add listener method and remove listener method. */
650        Class[] listenerArgList = new Class[1];
651        listenerArgList[0] = listenerType;
652        try
653          {
654            this.addListenerMethod
655              = eventSourceClass.getMethod(addListenerMethodName,
656                                           listenerArgList);
657          }
658        catch (SecurityException E)
659          {
660            throw new IntrospectionException(
661                      "SecurityException trying to access method "
662                      + addListenerMethodName + ".");
663          }
664        catch (NoSuchMethodException E)
665          {
666            throw new IntrospectionException("Could not find method "
667                                             + addListenerMethodName + ".");
668          }
669    
670        if (this.addListenerMethod == null
671            || !this.addListenerMethod.getReturnType().equals(java.lang.Void.TYPE))
672          {
673            throw new IntrospectionException(
674                      "Add listener method does not exist, is not public,"
675                      + " or is not void.");
676          }
677    
678        try
679          {
680            this.removeListenerMethod
681              = eventSourceClass.getMethod(removeListenerMethodName,
682                                           listenerArgList);
683          }
684        catch (SecurityException E)
685          {
686            throw new IntrospectionException(
687                      "SecurityException trying to access method "
688                      + removeListenerMethodName + ".");
689          }
690        catch (NoSuchMethodException E)
691          {
692            throw new IntrospectionException("Could not find method "
693                                             + removeListenerMethodName + ".");
694          }
695        if (this.removeListenerMethod == null
696            || !this.removeListenerMethod.getReturnType()
697               .equals(java.lang.Void.TYPE))
698          {
699            throw new IntrospectionException(
700                      "Remove listener method does not exist, is not public,"
701                      + " or is not void.");
702          }
703    
704        /* Find the listener methods. */
705        Method[] methods;
706        try
707          {
708            methods = ClassHelper.getAllMethods(listenerType);
709          }
710        catch (SecurityException E)
711          {
712            throw new IntrospectionException(
713                      "Security: You cannot access fields in this class.");
714          }
715    
716        Vector chosenMethods = new Vector();
717        boolean[] listenerMethodFound = new boolean[listenerMethodNames.length];
718        for (int i = 0; i < methods.length; i++)
719          {
720            if (Modifier.isPrivate(methods[i].getModifiers()))
721              {
722                continue;
723              }
724            Method currentMethod = methods[i];
725            Class retval = currentMethod.getReturnType();
726            if (retval.equals(java.lang.Void.TYPE))
727              {
728                for (int j = 0; j < listenerMethodNames.length; j++)
729                  {
730                    if (currentMethod.getName().equals(listenerMethodNames[j])
731                        && (absurdEventClassCheckName == null
732                        || (currentMethod.getParameterTypes().length == 1
733                        && ((currentMethod.getParameterTypes()[0])
734                            .getName().equals(absurdEventClassCheckName)
735                        || (currentMethod.getParameterTypes()[0])
736                           .getName().endsWith("." + absurdEventClassCheckName)))))
737                      {
738                        chosenMethods.addElement(currentMethod);
739                        listenerMethodFound[j] = true;
740                      }
741                  }
742              }
743          }
744    
745        /* Make sure we found all the methods we were looking for. */
746        for (int i = 0; i < listenerMethodFound.length; i++)
747          {
748            if (!listenerMethodFound[i])
749              {
750                throw new IntrospectionException("Could not find event method "
751                                                 + listenerMethodNames[i]);
752              }
753          }
754    
755        /* Now that we've chosen the listener methods we want, store them. */
756        this.listenerMethods = new Method[chosenMethods.size()];
757        for (int i = 0; i < chosenMethods.size(); i++)
758          {
759            this.listenerMethods[i] = (Method) chosenMethods.elementAt(i);
760          }
761      }
762      
763    }