From f911ba985aa7fe0096c386c5be385ac5825ea527 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Sat, 16 Jul 2005 00:30:23 +0000 Subject: Initial revision From-SVN: r102074 --- .../classpath/java/beans/EventSetDescriptor.java | 442 +++++++++++++++++++++ 1 file changed, 442 insertions(+) create mode 100644 libjava/classpath/java/beans/EventSetDescriptor.java (limited to 'libjava/classpath/java/beans/EventSetDescriptor.java') diff --git a/libjava/classpath/java/beans/EventSetDescriptor.java b/libjava/classpath/java/beans/EventSetDescriptor.java new file mode 100644 index 00000000000..8624e643476 --- /dev/null +++ b/libjava/classpath/java/beans/EventSetDescriptor.java @@ -0,0 +1,442 @@ +/* java.beans.EventSetDescriptor + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.beans; + +import gnu.java.lang.ClassHelper; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Vector; + +/** + ** EventSetDescriptor describes the hookup between an event source + ** class and an event listener class. + ** + ** EventSets have several attributes: the listener class, the events + ** that can be fired to the listener (methods in the listener class), and + ** an add and remove listener method from the event firer's class.

+ ** + ** The methods have these constraints on them:

+ **

+ ** + ** A final constraint is that event listener classes must extend from EventListener.

+ ** + ** There are also various design patterns associated with some of the methods + ** of construction. Those are explained in more detail in the appropriate + ** constructors.

+ ** + ** Documentation Convention: for proper + ** Internalization of Beans inside an RAD tool, sometimes there + ** are two names for a property or method: a programmatic, or + ** locale-independent name, which can be used anywhere, and a + ** localized, display name, for ease of use. In the + ** documentation I will specify different String values as + ** either programmatic or localized to + ** make this distinction clear. + ** + ** @author John Keiser + ** @since JDK1.1 + ** @version 1.1.0, 31 May 1998 + **/ + +public class EventSetDescriptor extends FeatureDescriptor { + private Method addListenerMethod; + private Method removeListenerMethod; + private Class listenerType; + private MethodDescriptor[] listenerMethodDescriptors; + private Method[] listenerMethods; + + private boolean unicast; + private boolean inDefaultEventSet = true; + + /** Create a new EventSetDescriptor. + ** This version of the constructor enforces the rules imposed on the methods + ** described at the top of this class, as well as searching for:

+ **

    + **
  1. The event-firing method must be non-private with signature + ** void <listenerMethodName>(<eventSetName>Event) + ** (where <eventSetName> has its first character capitalized + ** by the constructor and the Event is a descendant of + ** java.util.EventObject) in class listenerType + ** (any exceptions may be thrown). + ** Implementation note: Note that there could conceivably be multiple + ** methods with this type of signature (example: java.util.MouseEvent vs. + ** my.very.own.MouseEvent). In this implementation, all methods fitting the + ** description will be put into the EventSetDescriptor, even + ** though the spec says only one should be chosen (they probably weren't thinking as + ** pathologically as I was). I don't like arbitrarily choosing things. + ** If your class has only one such signature, as most do, you'll have no problems.
  2. + **
  3. The add and remove methods must be public and named + ** void add<eventSetName>Listener(<listenerType>) and + ** void remove<eventSetName>Listener(<listenerType>) in + ** in class eventSourceClass, where + ** <eventSetName> will have its first letter capitalized. + ** Standard exception rules (see class description) apply.
  4. + **
+ ** @param eventSourceClass the class containing the add/remove listener methods. + ** @param eventSetName the programmatic name of the event set, generally starting + ** with a lowercase letter (i.e. fooManChu instead of FooManChu). This will be used + ** to generate the name of the event object as well as the names of the add and + ** remove methods. + ** @param listenerType the class containing the event firing method. + ** @param listenerMethodName the name of the event firing method. + ** @exception IntrospectionException if listenerType is not an EventListener, + ** or if methods are not found or are invalid. + **/ + public EventSetDescriptor(Class eventSourceClass, + String eventSetName, + Class listenerType, + String listenerMethodName) throws IntrospectionException { + setName(eventSetName); + if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { + throw new IntrospectionException("Listener type is not an EventListener."); + } + + String[] names = new String[1]; + names[0] = listenerMethodName; + + try { + eventSetName = Character.toUpperCase(eventSetName.charAt(0)) + eventSetName.substring(1); + } catch(StringIndexOutOfBoundsException e) { + eventSetName = ""; + } + + findMethods(eventSourceClass,listenerType,names,"add"+eventSetName+"Listener","remove"+eventSetName+"Listener",eventSetName+"Event"); + this.listenerType = listenerType; + checkAddListenerUnicast(); + if(this.removeListenerMethod.getExceptionTypes().length > 0) { + throw new IntrospectionException("Listener remove method throws exceptions."); + } + } + + /** Create a new EventSetDescriptor. + ** This form of the constructor allows you to specify the names of the methods and adds + ** no new constraints on top of the rules already described at the top of the class.

+ ** + ** @param eventSourceClass the class containing the add and remove listener methods. + ** @param eventSetName the programmatic name of the event set, generally starting + ** with a lowercase letter (i.e. fooManChu instead of FooManChu). + ** @param listenerType the class containing the event firing methods. + ** @param listenerMethodNames the names of the even firing methods. + ** @param addListenerMethodName the name of the add listener method. + ** @param removeListenerMethodName the name of the remove listener method. + ** @exception IntrospectionException if listenerType is not an EventListener + ** or if methods are not found or are invalid. + **/ + public EventSetDescriptor(Class eventSourceClass, + String eventSetName, + Class listenerType, + String[] listenerMethodNames, + String addListenerMethodName, + String removeListenerMethodName) throws IntrospectionException { + setName(eventSetName); + if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { + throw new IntrospectionException("Listener type is not an EventListener."); + } + + findMethods(eventSourceClass,listenerType,listenerMethodNames,addListenerMethodName,removeListenerMethodName,null); + this.listenerType = listenerType; + checkAddListenerUnicast(); + if(this.removeListenerMethod.getExceptionTypes().length > 0) { + throw new IntrospectionException("Listener remove method throws exceptions."); + } + } + + /** Create a new EventSetDescriptor. + ** This form of constructor allows you to explicitly say which methods do what, and + ** no reflection is done by the EventSetDescriptor. The methods are, however, + ** checked to ensure that they follow the rules set forth at the top of the class. + ** @param eventSetName the programmatic name of the event set, generally starting + ** with a lowercase letter (i.e. fooManChu instead of FooManChu). + ** @param listenerType the class containing the listenerMethods. + ** @param listenerMethods the event firing methods. + ** @param addListenerMethod the add listener method. + ** @param removeListenerMethod the remove listener method. + ** @exception IntrospectionException if the listenerType is not an EventListener, + ** or any of the methods are invalid. + **/ + public EventSetDescriptor(String eventSetName, + Class listenerType, + Method[] listenerMethods, + Method addListenerMethod, + Method removeListenerMethod) throws IntrospectionException { + setName(eventSetName); + if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { + throw new IntrospectionException("Listener type is not an EventListener."); + } + + this.listenerMethods = listenerMethods; + this.addListenerMethod = addListenerMethod; + this.removeListenerMethod = removeListenerMethod; + this.listenerType = listenerType; + checkMethods(); + checkAddListenerUnicast(); + if(this.removeListenerMethod.getExceptionTypes().length > 0) { + throw new IntrospectionException("Listener remove method throws exceptions."); + } + } + + /** Create a new EventSetDescriptor. + ** This form of constructor allows you to explicitly say which methods do what, and + ** no reflection is done by the EventSetDescriptor. The methods are, however, + ** checked to ensure that they follow the rules set forth at the top of the class. + ** @param eventSetName the programmatic name of the event set, generally starting + ** with a lowercase letter (i.e. fooManChu instead of FooManChu). + ** @param listenerType the class containing the listenerMethods. + ** @param listenerMethodDescriptors the event firing methods. + ** @param addListenerMethod the add listener method. + ** @param removeListenerMethod the remove listener method. + ** @exception IntrospectionException if the listenerType is not an EventListener, + ** or any of the methods are invalid. + **/ + public EventSetDescriptor(String eventSetName, + Class listenerType, + MethodDescriptor[] listenerMethodDescriptors, + Method addListenerMethod, + Method removeListenerMethod) throws IntrospectionException { + setName(eventSetName); + if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { + throw new IntrospectionException("Listener type is not an EventListener."); + } + + this.listenerMethodDescriptors = listenerMethodDescriptors; + this.listenerMethods = new Method[listenerMethodDescriptors.length]; + for(int i=0;i 0) { + throw new IntrospectionException("Listener remove method throws exceptions."); + } + } + + /** Get the class that contains the event firing methods. **/ + public Class getListenerType() { + return listenerType; + } + + /** Get the event firing methods. **/ + public Method[] getListenerMethods() { + return listenerMethods; + } + + /** Get the event firing methods as MethodDescriptors. **/ + public MethodDescriptor[] getListenerMethodDescriptors() { + if(listenerMethodDescriptors == null) { + listenerMethodDescriptors = new MethodDescriptor[listenerMethods.length]; + for(int i=0;i 1) { + throw new IntrospectionException("Listener add method throws too many exceptions."); + } else if(addListenerExceptions.length == 1 + && !java.util.TooManyListenersException.class.isAssignableFrom(addListenerExceptions[0])) { + throw new IntrospectionException("Listener add method throws too many exceptions."); + } + } + + private void checkMethods() throws IntrospectionException { + if(!addListenerMethod.getDeclaringClass().isAssignableFrom(removeListenerMethod.getDeclaringClass()) + && !removeListenerMethod.getDeclaringClass().isAssignableFrom(addListenerMethod.getDeclaringClass())) { + throw new IntrospectionException("add and remove listener methods do not come from the same class. This is bad."); + } + if(!addListenerMethod.getReturnType().equals(java.lang.Void.TYPE) + || addListenerMethod.getParameterTypes().length != 1 + || !listenerType.equals(addListenerMethod.getParameterTypes()[0]) + || !Modifier.isPublic(addListenerMethod.getModifiers())) { + throw new IntrospectionException("Add Listener Method invalid."); + } + if(!removeListenerMethod.getReturnType().equals(java.lang.Void.TYPE) + || removeListenerMethod.getParameterTypes().length != 1 + || !listenerType.equals(removeListenerMethod.getParameterTypes()[0]) + || removeListenerMethod.getExceptionTypes().length > 0 + || !Modifier.isPublic(removeListenerMethod.getModifiers())) { + throw new IntrospectionException("Remove Listener Method invalid."); + } + + for(int i=0;i