Source for java.beans.EventSetDescriptor

   1: /* java.beans.EventSetDescriptor
   2:  Copyright (C) 1998, 2006 Free Software Foundation, Inc.
   3: 
   4:  This file is part of GNU Classpath.
   5: 
   6:  GNU Classpath is free software; you can redistribute it and/or modify
   7:  it under the terms of the GNU General Public License as published by
   8:  the Free Software Foundation; either version 2, or (at your option)
   9:  any later version.
  10:  
  11:  GNU Classpath is distributed in the hope that it will be useful, but
  12:  WITHOUT ANY WARRANTY; without even the implied warranty of
  13:  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14:  General Public License for more details.
  15: 
  16:  You should have received a copy of the GNU General Public License
  17:  along with GNU Classpath; see the file COPYING.  If not, write to the
  18:  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19:  02110-1301 USA.
  20: 
  21:  Linking this library statically or dynamically with other modules is
  22:  making a combined work based on this library.  Thus, the terms and
  23:  conditions of the GNU General Public License cover the whole
  24:  combination.
  25: 
  26:  As a special exception, the copyright holders of this library give you
  27:  permission to link this library with independent modules to produce an
  28:  executable, regardless of the license terms of these independent
  29:  modules, and to copy and distribute the resulting executable under
  30:  terms of your choice, provided that you also meet, for each linked
  31:  independent module, the terms and conditions of the license of that
  32:  module.  An independent module is a module which is not derived from
  33:  or based on this library.  If you modify this library, you may extend
  34:  this exception to your version of the library, but you are not
  35:  obligated to do so.  If you do not wish to do so, delete this
  36:  exception statement from your version. */
  37: 
  38: 
  39: package java.beans;
  40: 
  41: import gnu.java.lang.ClassHelper;
  42: 
  43: import java.lang.reflect.Method;
  44: import java.lang.reflect.Modifier;
  45: import java.util.Vector;
  46: 
  47: /**
  48:  * EventSetDescriptor describes the hookup between an event source class and
  49:  * an event listener class.
  50:  * 
  51:  * <p>EventSets have several attributes: the listener class,
  52:  * the events that can be fired to the listener (methods in the listener
  53:  * class), and an add and remove listener method from the event firer's
  54:  * class.
  55:  * </p>
  56:  * 
  57:  * <p>
  58:  * The methods have these constraints on them:
  59:  * <ul>
  60:  * <li>event firing methods: must have <code>void</code> return value. Any
  61:  * parameters and exceptions are allowed. May be public, protected or
  62:  * package-protected. (Don't ask me why that is, I'm just following the spec.
  63:  * The only place it is even mentioned is in the Java Beans white paper, and
  64:  * there it is only implied.)</li>
  65:  * 
  66:  * <li>add listener method: must have <code>void</code> return value. Must
  67:  * take exactly one argument, of the listener class's type. May fire either
  68:  * zero exceptions, or one exception of type
  69:  * <code>java.util.TooManyListenersException</code>.
  70:  * Must be public.</li>
  71:  * 
  72:  * <li>remove listener method: must have <code>void</code> return value. Must
  73:  * take exactly one argument, of the listener class's type. May not fire any
  74:  * exceptions. Must be public.</li>
  75:  * </ul>
  76:  * 
  77:  * <p>
  78:  * A final constraint is that event listener classes must extend from
  79:  * EventListener.
  80:  * </p>
  81:  * 
  82:  * <p>
  83:  * There are also various design patterns associated with some of the methods
  84:  * of construction. Those are explained in more detail in the appropriate
  85:  * constructors.
  86:  * </p>
  87:  * 
  88:  * <p>
  89:  * <strong>Documentation Convention:</strong> for proper Internalization of
  90:  * Beans inside an RAD tool, sometimes there are two names for a property or
  91:  * method: a programmatic, or locale-independent name, which can be used
  92:  * anywhere, and a localized, display name, for ease of use. In the
  93:  * documentation I will specify different String values as either
  94:  * <em>programmatic</em> or <em>localized</em> to make this distinction clear.
  95:  * 
  96:  * @author John Keiser
  97:  * @author Robert Schuster (robertschuster@fsfe.org)
  98:  * @since 1.1
  99:  */
 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: }