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
039package java.beans;
040
041import gnu.java.lang.ClassHelper;
042
043import java.lang.reflect.Method;
044import java.lang.reflect.Modifier;
045import 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
101public 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}