| /* gnu.java.beans.IntrospectionIncubator |
| 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., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307 USA. |
| |
| As a special exception, if you link this library with other files to |
| produce an executable, this library does not by itself cause the |
| resulting executable to be covered by the GNU General Public License. |
| This exception does not however invalidate any other reasons why the |
| executable file might be covered by the GNU General Public License. */ |
| |
| |
| package gnu.java.beans; |
| |
| import java.beans.*; |
| import java.util.*; |
| import java.lang.reflect.*; |
| import gnu.java.lang.*; |
| |
| /** |
| ** IntrospectionIncubator takes in a bunch of Methods, and |
| ** Introspects only those Methods you give it. |
| ** |
| ** @author John Keiser |
| ** @version 1.1.0, 30 Jul 1998 |
| ** @see gnu.java.beans.ExplicitBeanInfo |
| ** @see java.beans.BeanInfo |
| **/ |
| |
| public class IntrospectionIncubator { |
| Hashtable propertyMethods = new Hashtable(); |
| Hashtable listenerMethods = new Hashtable(); |
| Vector otherMethods = new Vector(); |
| |
| Class propertyStopClass; |
| Class eventStopClass; |
| Class methodStopClass; |
| |
| public IntrospectionIncubator() { |
| } |
| |
| /* Paving the way for automatic Introspection */ |
| public void addMethod(Method method) { |
| if(Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) { |
| String name = ClassHelper.getTruncatedName(method.getName()); |
| Class retType = method.getReturnType(); |
| Class[] params = method.getParameterTypes(); |
| boolean isVoid = retType.equals(java.lang.Void.TYPE); |
| Class methodClass = method.getDeclaringClass(); |
| if(propertyStopClass == null || (propertyStopClass.isAssignableFrom(methodClass) && !propertyStopClass.equals(methodClass))) { |
| if(name.startsWith("is") |
| && retType.equals(java.lang.Boolean.TYPE) |
| && params.length == 0) { |
| addToPropertyHash(name,method,IS); |
| } else if(name.startsWith("get") && !isVoid) { |
| if(params.length == 0) { |
| addToPropertyHash(name,method,GET); |
| } else if(params.length == 1 && params[0].equals(java.lang.Integer.TYPE)) { |
| addToPropertyHash(name,method,GET_I); |
| } else { |
| otherMethods.addElement(method); |
| } |
| } else if(name.startsWith("set") && isVoid) { |
| if(params.length == 1) { |
| addToPropertyHash(name,method,SET); |
| } else if(params.length == 2 && params[0].equals(java.lang.Integer.TYPE)) { |
| addToPropertyHash(name,method,SET_I); |
| } else { |
| otherMethods.addElement(method); |
| } |
| } |
| } |
| if(eventStopClass == null || (eventStopClass.isAssignableFrom(methodClass) && !eventStopClass.equals(methodClass))) { |
| if(name.startsWith("add") |
| && isVoid |
| && params.length == 1 |
| && java.util.EventListener.class.isAssignableFrom(params[0])) { |
| addToListenerHash(name,method,ADD); |
| } else if(name.startsWith("remove") |
| && isVoid |
| && params.length == 1 |
| && java.util.EventListener.class.isAssignableFrom(params[0])) { |
| addToListenerHash(name,method,REMOVE); |
| } |
| } |
| if(methodStopClass == null || (methodStopClass.isAssignableFrom(methodClass) && !methodStopClass.equals(methodClass))) { |
| otherMethods.addElement(method); |
| } |
| } |
| } |
| |
| public void addMethods(Method[] m) { |
| for(int i=0;i<m.length;i++) { |
| addMethod(m[i]); |
| } |
| } |
| |
| public void setPropertyStopClass(Class c) { |
| propertyStopClass = c; |
| } |
| |
| public void setEventStopClass(Class c) { |
| eventStopClass = c; |
| } |
| |
| public void setMethodStopClass(Class c) { |
| methodStopClass = c; |
| } |
| |
| |
| public BeanInfoEmbryo getBeanInfoEmbryo() throws IntrospectionException { |
| BeanInfoEmbryo b = new BeanInfoEmbryo(); |
| findXXX(b,IS); |
| findXXXInt(b,GET_I); |
| findXXXInt(b,SET_I); |
| findXXX(b,GET); |
| findXXX(b,SET); |
| findAddRemovePairs(b); |
| for(int i=0;i<otherMethods.size();i++) { |
| MethodDescriptor newMethod = new MethodDescriptor((Method)otherMethods.elementAt(i)); |
| if(!b.hasMethod(newMethod)) { |
| b.addMethod(new MethodDescriptor((Method)otherMethods.elementAt(i))); |
| } |
| } |
| return b; |
| } |
| |
| public BeanInfo getBeanInfo() throws IntrospectionException { |
| return getBeanInfoEmbryo().getBeanInfo(); |
| } |
| |
| |
| void findAddRemovePairs(BeanInfoEmbryo b) throws IntrospectionException { |
| Enumeration listenerEnum = listenerMethods.keys(); |
| while(listenerEnum.hasMoreElements()) { |
| DoubleKey k = (DoubleKey)listenerEnum.nextElement(); |
| Method[] m = (Method[])listenerMethods.get(k); |
| if(m[ADD] != null && m[REMOVE] != null) { |
| EventSetDescriptor e = new EventSetDescriptor(Introspector.decapitalize(k.getName()), |
| k.getType(), k.getType().getMethods(), |
| m[ADD],m[REMOVE]); |
| e.setUnicast(ArrayHelper.contains(m[ADD].getExceptionTypes(),java.util.TooManyListenersException.class)); |
| if(!b.hasEvent(e)) { |
| b.addEvent(e); |
| } |
| } |
| } |
| } |
| |
| void findXXX(BeanInfoEmbryo b, int funcType) throws IntrospectionException { |
| Enumeration keys = propertyMethods.keys(); |
| while(keys.hasMoreElements()) { |
| DoubleKey k = (DoubleKey)keys.nextElement(); |
| Method[] m = (Method[])propertyMethods.get(k); |
| if(m[funcType] != null) { |
| PropertyDescriptor p = new PropertyDescriptor(Introspector.decapitalize(k.getName()), |
| m[IS] != null ? m[IS] : m[GET], |
| m[SET]); |
| if(m[SET] != null) { |
| p.setConstrained(ArrayHelper.contains(m[SET].getExceptionTypes(),java.beans.PropertyVetoException.class)); |
| } |
| if(!b.hasProperty(p)) { |
| b.addProperty(p); |
| } |
| } |
| } |
| } |
| |
| void findXXXInt(BeanInfoEmbryo b, int funcType) throws IntrospectionException { |
| Enumeration keys = propertyMethods.keys(); |
| while(keys.hasMoreElements()) { |
| DoubleKey k = (DoubleKey)keys.nextElement(); |
| Method[] m = (Method[])propertyMethods.get(k); |
| if(m[funcType] != null) { |
| boolean constrained; |
| if(m[SET_I] != null) { |
| constrained = ArrayHelper.contains(m[SET_I].getExceptionTypes(),java.beans.PropertyVetoException.class); |
| } else { |
| constrained = false; |
| } |
| |
| /** Find out if there is an array type get or set **/ |
| Class arrayType = Array.newInstance(k.getType(),0).getClass(); |
| DoubleKey findSetArray = new DoubleKey(arrayType,k.getName()); |
| Method[] m2 = (Method[])propertyMethods.get(findSetArray); |
| IndexedPropertyDescriptor p; |
| if(m2 == null) { |
| p = new IndexedPropertyDescriptor(Introspector.decapitalize(k.getName()), |
| null,null, |
| m[GET_I],m[SET_I]); |
| } else { |
| if(constrained && m2[SET] != null) { |
| constrained = ArrayHelper.contains(m2[SET].getExceptionTypes(),java.beans.PropertyVetoException.class); |
| } |
| p = new IndexedPropertyDescriptor(Introspector.decapitalize(k.getName()), |
| m2[GET],m2[SET], |
| m[GET_I],m[SET_I]); |
| } |
| p.setConstrained(constrained); |
| if(!b.hasProperty(p)) { |
| b.addProperty(p); |
| } |
| } |
| } |
| } |
| |
| static final int IS=0; |
| static final int GET_I=1; |
| static final int SET_I=2; |
| static final int GET=3; |
| static final int SET=4; |
| |
| static final int ADD=0; |
| static final int REMOVE=1; |
| |
| void addToPropertyHash(String name, Method method, int funcType) { |
| String newName; |
| Class type; |
| |
| switch(funcType) { |
| case IS: |
| type = java.lang.Boolean.TYPE; |
| newName = name.substring(2); |
| break; |
| case GET_I: |
| type = method.getReturnType(); |
| newName = name.substring(3); |
| break; |
| case SET_I: |
| type = method.getParameterTypes()[1]; |
| newName = name.substring(3); |
| break; |
| case GET: |
| type = method.getReturnType(); |
| newName = name.substring(3); |
| break; |
| case SET: |
| type = method.getParameterTypes()[0]; |
| newName = name.substring(3); |
| break; |
| default: |
| return; |
| } |
| newName = capitalize(newName); |
| |
| DoubleKey k = new DoubleKey(type,newName); |
| Method[] methods = (Method[])propertyMethods.get(k); |
| if(methods == null) { |
| methods = new Method[5]; |
| propertyMethods.put(k,methods); |
| } |
| methods[funcType] = method; |
| } |
| |
| |
| void addToListenerHash(String name, Method method, int funcType) { |
| String newName; |
| Class type; |
| |
| switch(funcType) { |
| case ADD: |
| type = method.getParameterTypes()[0]; |
| newName = name.substring(3,name.length()-8); |
| break; |
| case REMOVE: |
| type = method.getParameterTypes()[0]; |
| newName = name.substring(6,name.length()-8); |
| break; |
| default: |
| return; |
| } |
| newName = capitalize(newName); |
| |
| DoubleKey k = new DoubleKey(type,newName); |
| Method[] methods = (Method[])listenerMethods.get(k); |
| if(methods == null) { |
| methods = new Method[2]; |
| listenerMethods.put(k,methods); |
| } |
| methods[funcType] = method; |
| } |
| |
| static String capitalize(String name) { |
| try { |
| if(Character.isUpperCase(name.charAt(0))) { |
| return name; |
| } else { |
| char[] c = name.toCharArray(); |
| c[0] = Character.toLowerCase(c[0]); |
| return new String(c); |
| } |
| } catch(StringIndexOutOfBoundsException E) { |
| return name; |
| } catch(NullPointerException E) { |
| return null; |
| } |
| } |
| } |
| |
| class DoubleKey { |
| Class type; |
| String name; |
| |
| DoubleKey(Class type, String name) { |
| this.type = type; |
| this.name = name; |
| } |
| |
| Class getType() { |
| return type; |
| } |
| |
| String getName() { |
| return name; |
| } |
| |
| public boolean equals(Object o) { |
| if(o instanceof DoubleKey) { |
| DoubleKey d = (DoubleKey)o; |
| return d.type.equals(type) && d.name.equals(name); |
| } else { |
| return false; |
| } |
| } |
| |
| public int hashCode() { |
| return type.hashCode() ^ name.hashCode(); |
| } |
| } |