You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by to...@apache.org on 2007/07/18 06:06:28 UTC

svn commit: r557142 - /harmony/enhanced/classlib/trunk/modules/beans/src/main/java/java/beans/StandardBeanInfo.java

Author: tonywu
Date: Tue Jul 17 21:06:27 2007
New Revision: 557142

URL: http://svn.apache.org/viewvc?view=rev&rev=557142
Log:
add the BeanInfo wrapper class

Added:
    harmony/enhanced/classlib/trunk/modules/beans/src/main/java/java/beans/StandardBeanInfo.java   (with props)

Added: harmony/enhanced/classlib/trunk/modules/beans/src/main/java/java/beans/StandardBeanInfo.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/beans/src/main/java/java/beans/StandardBeanInfo.java?view=auto&rev=557142
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/beans/src/main/java/java/beans/StandardBeanInfo.java (added)
+++ harmony/enhanced/classlib/trunk/modules/beans/src/main/java/java/beans/StandardBeanInfo.java Tue Jul 17 21:06:27 2007
@@ -0,0 +1,944 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.beans;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.EventListener;
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.TooManyListenersException;
+
+import static java.beans.Introspector.decapitalize;
+
+class StandardBeanInfo extends SimpleBeanInfo {
+    
+
+    // Prefixes for methods that set or get a Property
+    private static final String PREFIX_IS = "is"; //$NON-NLS-1$
+
+    private static final String PREFIX_GET = "get"; //$NON-NLS-1$
+
+    private static final String PREFIX_SET = "set"; //$NON-NLS-1$
+
+    // Prefix and suffix for Event related methods
+    private static final String PREFIX_ADD = "add"; //$NON-NLS-1$
+
+    private static final String PREFIX_REMOVE = "remove"; //$NON-NLS-1$
+
+    private static final String SUFFIX_LISTEN = "Listener"; //$NON-NLS-1$
+
+    private boolean explicitMethods = false;
+
+    private boolean explicitProperties = false;
+
+    private boolean explicitEvents = false;
+
+    private BeanInfo explicitBeanInfo = null;
+
+    private EventSetDescriptor[] events = new EventSetDescriptor[0];
+
+    private MethodDescriptor[] methods = new MethodDescriptor[0];
+
+    private PropertyDescriptor[] properties = new PropertyDescriptor[0];
+    
+    BeanInfo[] additionalBeanInfo = null;
+
+    private Class beanClass;
+
+    private int defaultEventIndex = -1;
+
+    private int defaultPropertyIndex = -1;
+
+    private static PropertyComparator comparator = new PropertyComparator();
+
+    StandardBeanInfo(Class beanClass) {
+        super();
+        this.beanClass = beanClass;
+
+    }
+    
+    StandardBeanInfo(Class beanClass,
+            BeanInfo explicitBeanInfo) throws IntrospectionException {
+        this(beanClass);
+        /*--------------------------------------------------------------------------------------
+         * There are 3 aspects of BeanInfo that must be supplied:
+         * a) PropertyDescriptors
+         * b) MethodDescriptors
+         * c) EventSetDescriptors
+         * Each of these may be optionally provided in the explicitBeanInfo object relating to
+         * this bean.  Where the explicitBeanInfo provides one of these aspects, it is used
+         * without question and no introspection of the beanClass is performed for that aspect.
+         * There are also 3 optional items of BeanInfo that may be provided by the 
+         * explicitBeanInfo object:
+         * 1) BeanDescriptor
+         * 2) DefaultEventIndex
+         * 3) DefaultPropertyIndex
+         * These aspects of the beanClass cannot be derived through introspection of the class.
+         * If they are not provided by the explicitBeanInfo, then they must be left null in the 
+         * returned BeanInfo, otherwise they will be copied from the explicitBeanInfo 
+         --------------------------------------------------------------------------------------*/
+        if (explicitBeanInfo != null){
+            this.explicitBeanInfo = explicitBeanInfo;
+            events = explicitBeanInfo.getEventSetDescriptors();
+            methods = explicitBeanInfo.getMethodDescriptors();
+            properties = explicitBeanInfo.getPropertyDescriptors();
+            this.defaultEventIndex = explicitBeanInfo.getDefaultEventIndex();
+            this.defaultPropertyIndex = explicitBeanInfo.getDefaultPropertyIndex();
+            additionalBeanInfo = explicitBeanInfo.getAdditionalBeanInfo();
+            
+            if (events != null)
+                explicitEvents = true;
+            if (methods != null)
+                explicitMethods = true;
+            if (properties != null)
+                explicitProperties = true;
+        }
+
+        if (!explicitMethods) {
+            methods = introspectMethods(beanClass);
+        }
+
+        if (!explicitProperties) {
+            properties = introspectProperties(beanClass);
+        }
+
+        if (!explicitEvents) {
+            events = introspectEvents(beanClass);
+        }
+    }
+
+    public BeanInfo[] getAdditionalBeanInfo() {
+        return null;
+    }
+
+    public EventSetDescriptor[] getEventSetDescriptors() {
+        return events;
+    }
+
+    public MethodDescriptor[] getMethodDescriptors() {
+        return methods;
+    }
+
+    public PropertyDescriptor[] getPropertyDescriptors() {
+        PropertyDescriptor[] sortedProperties = properties;
+
+        if (sortedProperties != null) {
+            Arrays.sort(sortedProperties, comparator);
+        }
+        return sortedProperties;
+    }
+
+    public BeanDescriptor getBeanDescriptor() {
+        if (explicitBeanInfo != null) {
+            BeanDescriptor beanDesc = explicitBeanInfo.getBeanDescriptor();
+            if (beanDesc != null) {
+                return beanDesc;
+            }
+        }
+        return new BeanDescriptor(beanClass);
+    }
+
+    public int getDefaultEventIndex() {
+        return this.defaultEventIndex;
+    }
+
+    public int getDefaultPropertyIndex() {
+        return this.defaultPropertyIndex;
+    }
+    
+    
+    void mergeBeanInfo(BeanInfo superBeanInfo, boolean force) throws IntrospectionException{
+        if(force){
+            if (superBeanInfo.getPropertyDescriptors() != null) {
+                PropertyDescriptor[] superDescs = superBeanInfo
+                        .getPropertyDescriptors();
+                if (getPropertyDescriptors() != null) {
+                    if (explicitProperties == false)
+                        properties = mergeProps(superDescs);
+                } else {
+                    if (explicitProperties == false)
+                        properties = superDescs;
+                }
+            }
+
+            //merge MethodDescriptors
+            if (superBeanInfo.getMethodDescriptors() != null) {
+                if (getMethodDescriptors() != null) {
+                    if (explicitMethods == false)
+                    methods = mergeMethods(superBeanInfo
+                                                .getMethodDescriptors(), getMethodDescriptors());
+                } else {
+                    if (explicitMethods == false)
+                        methods = superBeanInfo.getMethodDescriptors();
+                }
+            }
+
+            //merge EventSetDescriptors
+            if (superBeanInfo.getEventSetDescriptors() != null) {
+                if (getEventSetDescriptors() != null) {
+                    if (explicitEvents == false)
+                    events = mergeEvents(superBeanInfo
+                                                .getEventSetDescriptors());
+                } else {
+                    if (explicitEvents == false)
+                        events = superBeanInfo.getEventSetDescriptors();
+                }
+            }           
+        }
+        mergeBeanInfo(superBeanInfo);
+    }
+
+    void mergeBeanInfo(BeanInfo superBeanInfo) throws IntrospectionException{
+        //FIXME: the merge principle seems very different with RI's behavior
+            //merge PropertyDescriptors
+            if ((!explicitProperties)
+                    && (superBeanInfo.getPropertyDescriptors() != null)) {
+                PropertyDescriptor[] superDescs = superBeanInfo
+                        .getPropertyDescriptors();
+                if (getPropertyDescriptors() != null) {
+                    properties = mergeProps(superDescs);
+                } else {
+                    properties = superDescs;
+                }
+            }
+
+            //merge MethodDescriptors
+            if ((!explicitMethods)
+                    && (superBeanInfo.getMethodDescriptors() != null)) {
+                if (getMethodDescriptors() != null) {
+                    methods = mergeMethods(superBeanInfo
+                                                .getMethodDescriptors(), getMethodDescriptors());
+                } else {
+                        methods = superBeanInfo.getMethodDescriptors();
+                }
+            }
+
+            //merge EventSetDescriptors
+            if ((!explicitEvents)
+                    && (superBeanInfo.getEventSetDescriptors() != null)) {
+                if (getEventSetDescriptors() != null) {
+                    events = mergeEvents(superBeanInfo
+                                                .getEventSetDescriptors());
+                } else {
+                    events = superBeanInfo.getEventSetDescriptors();
+                }
+            }
+
+            //merge defaultPropertyIndex, and defaultEventIndex
+            if ((getDefaultEventIndex() == -1)
+                    && (superBeanInfo.getDefaultEventIndex() != -1)) {
+                defaultEventIndex = superBeanInfo.getDefaultEventIndex();
+            }
+
+            if ((getDefaultPropertyIndex() == -1)
+                    && (superBeanInfo.getDefaultPropertyIndex() != -1)) {
+                defaultPropertyIndex = superBeanInfo.getDefaultPropertyIndex();
+            }
+
+    }        
+
+    /*
+     * merge the PropertyDescriptor with superclass
+     */
+    private PropertyDescriptor[] mergeProps(
+            PropertyDescriptor[] superDescs)
+            throws IntrospectionException {
+        HashMap<String, PropertyDescriptor> subMap = internalAsMap(getPropertyDescriptors());
+
+        for (int i = 0; i < superDescs.length; i++) {
+            PropertyDescriptor superDesc = superDescs[i];
+            String propertyName = superDesc.getName();
+            if (!subMap.containsKey(propertyName)) {
+                subMap.put(propertyName, superDesc);
+                continue;
+            }
+
+            Object value = subMap.get(propertyName);
+            //if sub and super are both PropertyDescriptor
+            Method subGet = ((PropertyDescriptor) value).getReadMethod();
+            Method subSet = ((PropertyDescriptor) value).getWriteMethod();
+            Method superGet = superDesc.getReadMethod();
+            Method superSet = superDesc.getWriteMethod();
+
+            Class superType = superDesc.getPropertyType();
+            Class superIndexedType = null;
+            Class subType = ((PropertyDescriptor) value).getPropertyType();
+            Class subIndexedType = null;
+
+            if (value instanceof IndexedPropertyDescriptor) {
+                subIndexedType = ((IndexedPropertyDescriptor) value)
+                        .getIndexedPropertyType();
+            }
+            if (superDesc instanceof IndexedPropertyDescriptor) {
+                superIndexedType = ((IndexedPropertyDescriptor) superDesc)
+                        .getIndexedPropertyType();
+            }
+
+            //if superDesc is PropertyDescriptor
+            if (superIndexedType == null) {
+                PropertyDescriptor subDesc = (PropertyDescriptor) value;
+                //Sub is PropertyDescriptor
+                if (subIndexedType == null) {
+                    //Same property type
+                    if (subType.getName().equals(superType.getName())) {
+                        if ((subGet == null) && (superGet != null)) {
+                            subDesc.setReadMethod(superGet);
+                        }
+                        if ((subSet == null) && (superSet != null)) {
+                            subDesc.setWriteMethod(superSet);
+                        }
+                    } else { //Different type: type = getMethod
+                        if ((subGet == null) && (superGet != null)) {
+                            subDesc.setWriteMethod(null);
+                            subDesc.setReadMethod(superGet);
+                        }
+                    }
+                } else { //Sub is IndexedPropertyDescriptor
+                    if ((superType.isArray())
+                            && (superType.getComponentType().getName()
+                                    .equals(subIndexedType.getName()))) {
+                        //same type
+                        if ((subGet == null) && (superGet != null)) {
+                            subDesc.setReadMethod(superGet);
+                        }
+                        if ((subSet == null) && (superSet != null)) {
+                            subDesc.setWriteMethod(superSet);
+                        }
+                    } //different type do nothing
+                }
+                subMap.put(propertyName, subDesc);
+            } else { //Super is IndexedPropertyDescriptor
+                if (subIndexedType == null) { //Sub is PropertyDescriptor
+                    if (subType.isArray()
+                            && (subType.getComponentType().getName()
+                                    .equals(superIndexedType.getName()))) {
+                        // Same type
+                        if (subGet != null) {
+                            superDesc.setReadMethod(subGet);
+                        }
+                        if (subSet != null) {
+                            superDesc.setWriteMethod(subSet);
+                        }
+                        subMap.put(propertyName, superDesc);
+                    } else { //Different type do nothing
+                        subMap.put(propertyName, (PropertyDescriptor)value);
+                    }
+
+                } else if (subIndexedType.getName().equals(
+                        superIndexedType.getName())) {
+                    //Sub is IndexedPropertyDescriptor and Same type
+                    IndexedPropertyDescriptor subDesc = (IndexedPropertyDescriptor) value;
+                    if ((subGet == null) && (superGet != null)) {
+                        subDesc.setReadMethod(superGet);
+                    }
+                    if ((subSet == null) && (superSet != null)) {
+                        subDesc.setWriteMethod(superSet);
+                    }
+                    IndexedPropertyDescriptor superIndexedDesc = (IndexedPropertyDescriptor) superDesc;
+
+                    if ((subDesc.getIndexedReadMethod() == null)
+                            && (superIndexedDesc.getIndexedReadMethod() != null)) {
+                        subDesc.setIndexedReadMethod(superIndexedDesc
+                                .getIndexedReadMethod());
+                    }
+
+                    if ((subDesc.getIndexedWriteMethod() == null)
+                            && (superIndexedDesc.getIndexedWriteMethod() != null)) {
+                        subDesc.setIndexedWriteMethod(superIndexedDesc
+                                .getIndexedWriteMethod());
+                    }
+                    
+                    subMap.put(propertyName, subDesc);
+                } // Different indexed type, do nothing
+            }
+            mergeAttributes((PropertyDescriptor)value, superDesc);
+        }
+
+        PropertyDescriptor[] theDescs = new PropertyDescriptor[subMap.size()];
+        subMap.values().toArray(theDescs);
+
+        return theDescs;
+    }
+
+    private static void mergeAttributes(PropertyDescriptor subDesc, PropertyDescriptor superDesc) {
+        subDesc.hidden |= superDesc.hidden;
+        subDesc.expert |= superDesc.expert;
+        subDesc.preferred |= superDesc.preferred;
+        subDesc.name = superDesc.name;
+        if (superDesc.shortDescription != null) {
+            subDesc.shortDescription = superDesc.shortDescription;
+        }
+        if (superDesc.displayName != null) {
+            subDesc.displayName = superDesc.displayName;
+        }
+    }
+
+    /*
+     * merge the MethodDescriptor
+     */
+    private static MethodDescriptor[] mergeMethods(
+            MethodDescriptor[] superDescs, MethodDescriptor[] subDescs) {
+        HashMap<String, MethodDescriptor> subMap = internalAsMap(subDescs);
+
+        for (int i = 0; i < superDescs.length; i++) {
+            MethodDescriptor superDesc = superDescs[i];
+            String methodName = getQualifiedName(superDesc.getMethod());
+            if (subMap.containsKey(methodName)) {
+                continue;
+            }
+            subMap.put(methodName, superDesc);
+        }
+
+        MethodDescriptor[] theMethods = new MethodDescriptor[subMap.size()];
+        subMap.values().toArray(theMethods);
+        return theMethods;
+    }
+    
+    private EventSetDescriptor[] mergeEvents(
+            EventSetDescriptor[] otherEvents) {
+        HashMap<String, EventSetDescriptor> subMap = internalAsMap(this.getEventSetDescriptors());
+
+        for (int i = 0; i < otherEvents.length; i++) {
+            String eventName = otherEvents[i].getName();
+            if (subMap.containsKey(eventName)) {
+                continue;
+            }
+            subMap.put(eventName, otherEvents[i]);
+        }
+
+        EventSetDescriptor[] theMethods = new EventSetDescriptor[subMap.size()];
+        subMap.values().toArray(theMethods);
+        return theMethods;
+    }
+
+    private static HashMap<String, PropertyDescriptor> internalAsMap(PropertyDescriptor[] propertyDescs) {
+        HashMap<String, PropertyDescriptor> map = new HashMap<String, PropertyDescriptor>();
+        for (int i = 0; i < propertyDescs.length; i++) {
+            map.put(propertyDescs[i].getName(), propertyDescs[i]);
+        }
+        return map;
+    }
+
+    private static HashMap<String, MethodDescriptor> internalAsMap(MethodDescriptor[] theDescs) {
+        HashMap<String, MethodDescriptor> map = new HashMap<String, MethodDescriptor>();
+        for (int i = 0; i < theDescs.length; i++) {
+            String qualifiedName = getQualifiedName(theDescs[i].getMethod());
+            map.put(qualifiedName, theDescs[i]);
+        }
+        return map;
+    }
+
+    private static HashMap<String, EventSetDescriptor> internalAsMap(EventSetDescriptor[] theDescs) {
+        HashMap<String, EventSetDescriptor> map = new HashMap<String, EventSetDescriptor>();
+        for (int i = 0; i < theDescs.length; i++) {
+            map.put(theDescs[i].getName(), theDescs[i]);
+        }
+        return map;
+    }
+    
+    
+    private static String getQualifiedName(Method method) {
+        String qualifiedName = method.getName();
+        Class[] paramTypes = method.getParameterTypes();
+        if (paramTypes != null) {
+            for (int i = 0; i < paramTypes.length; i++) {
+                qualifiedName += "_" + paramTypes[i].getName(); //$NON-NLS-1$
+            }
+        }
+        return qualifiedName;
+    }
+    
+    /**
+     * Introspects the supplied class and returns a list of the public methods
+     * of the class
+     * 
+     * @param beanClass -
+     *            the class
+     * @return An array of MethodDescriptors with the public methods. null if
+     *         there are no public methods
+     */
+    private static MethodDescriptor[] introspectMethods(Class beanClass) {
+
+        MethodDescriptor[] theMethods = null;
+
+        if (beanClass == null)
+            return null;
+
+        // Get the list of methods belonging to this class
+        Method[] basicMethods = beanClass.getDeclaredMethods();
+
+        if (basicMethods == null || basicMethods.length == 0)
+            return null;
+
+        ArrayList<MethodDescriptor> methodList = new ArrayList<MethodDescriptor>(basicMethods.length);
+
+        // Loop over the methods found, looking for public methods
+        for (int i = 0; i < basicMethods.length; i++) {
+            int modifiers = basicMethods[i].getModifiers();
+            if (Modifier.isPublic(modifiers)) {
+                // Allocate a MethodDescriptor for this method
+                MethodDescriptor theDescriptor = new MethodDescriptor(
+                        basicMethods[i]);
+                methodList.add(theDescriptor);
+            }
+        }
+
+        // Get the list of public methods into the returned array
+        int methodCount = methodList.size();
+        if (methodCount > 0) {
+            theMethods = new MethodDescriptor[methodCount];
+            theMethods = (MethodDescriptor[]) methodList.toArray(theMethods);
+        }
+
+        return theMethods;
+    }
+
+    /**
+     * Introspects the supplied class and returns a list of the Properties of
+     * the class
+     * 
+     * @param beanClass -
+     *            the Class
+     * @return The list of Properties as an array of PropertyDescriptors
+     * @throws IntrospectionException
+     */
+    private static PropertyDescriptor[] introspectProperties(Class beanClass)
+            throws IntrospectionException {
+        if (beanClass == null)
+            return null;
+
+        // Get descriptors for the public methods
+        MethodDescriptor[] theMethods = introspectMethods(beanClass);
+
+        if (theMethods == null)
+            return null;
+
+        HashMap<String, HashMap> propertyTable = new HashMap<String, HashMap>(theMethods.length);
+
+        // Search for methods that either get or set a Property
+        for (int i = 0; i < theMethods.length; i++) {
+            introspectGet(theMethods[i].getMethod(), propertyTable);
+            introspectSet(theMethods[i].getMethod(), propertyTable);
+        }
+
+        // Put the properties found into the PropertyDescriptor array
+        ArrayList<PropertyDescriptor> propertyList = new ArrayList<PropertyDescriptor>();
+
+        Iterator keys = propertyTable.keySet().iterator();
+        while (keys.hasNext()) {
+            String propertyName = (String) keys.next();
+            HashMap table = propertyTable.get(propertyName);
+            if (table == null) {
+                continue;
+            }
+            String normalTag = (String) table.get("normal"); //$NON-NLS-1$
+            String indexedTag = (String) table.get("indexed"); //$NON-NLS-1$
+
+            if ((normalTag == null) && (indexedTag == null)) {
+                continue;
+            }
+
+            Method get = (Method) table.get("normalget"); //$NON-NLS-1$
+            Method set = (Method) table.get("normalset"); //$NON-NLS-1$
+            Method indexedGet = (Method) table.get("indexedget"); //$NON-NLS-1$
+            Method indexedSet = (Method) table.get("indexedset"); //$NON-NLS-1$
+            
+            PropertyDescriptor propertyDesc = null;
+            if (indexedTag == null) {
+                propertyDesc = new PropertyDescriptor(propertyName, get, set);
+            } else {
+                try {
+                    propertyDesc = new IndexedPropertyDescriptor(propertyName,
+                            get, set, indexedGet, indexedSet);
+                } catch (IntrospectionException e) {
+                    // If the getter and the indexGetter is not compatible, try
+                    // getter/setter is null;
+                    propertyDesc = new IndexedPropertyDescriptor(propertyName,
+                            null, null, indexedGet, indexedSet);
+                }
+            }
+            //RI set propretyDescriptor as bound.
+            propertyDesc.setBound(true);
+            propertyList.add(propertyDesc);
+        }
+
+        PropertyDescriptor[] theProperties = new PropertyDescriptor[propertyList
+                .size()];
+        propertyList.toArray(theProperties);
+        return theProperties;
+    }
+
+    private static void introspectGet(Method theMethod, HashMap<String, HashMap> propertyTable) {
+        String methodName = theMethod.getName();
+        if (methodName == null) {
+            return;
+        }
+
+        int prefixLength = 0;
+        if (methodName.startsWith(PREFIX_GET)) {
+            prefixLength = PREFIX_GET.length();
+        }
+
+        if (methodName.startsWith(PREFIX_IS)) {
+            prefixLength = PREFIX_IS.length();
+        }
+
+        if (prefixLength == 0) {
+            return;
+        }
+
+        String propertyName = decapitalize(methodName.substring(prefixLength));
+        //validate property name
+        if (!isValidProperty(propertyName)) {
+            return;
+        }
+
+        Class propertyType = theMethod.getReturnType();
+
+        //check return type getMethod
+        if (propertyType.getName().equals(Void.TYPE.getName())) {
+            return;
+        }
+
+        // isXXX return boolean
+        if (prefixLength == 2) {
+            if (!propertyType.getName().equals(Boolean.TYPE.getName())) {
+                return;
+            }
+        }
+
+        //indexed get method
+        Class[] paramTypes = theMethod.getParameterTypes();
+
+        if (paramTypes.length > 1) {
+            return;
+        }
+
+        String tag = "normal"; //$NON-NLS-1$
+
+        if (paramTypes.length == 1) {
+            if (paramTypes[0].getName().equals(Integer.TYPE.getName())) {
+                tag = "indexed"; //$NON-NLS-1$
+            } else {
+                return;
+            }
+
+        }
+
+        HashMap table = propertyTable.get(propertyName);
+        if (table == null) {
+            table = new HashMap();
+        }
+
+        //the "get" propertyType is conflict with "set" propertyType
+        Class oldPropertyType = (Class) table.get(tag + "PropertyType"); //$NON-NLS-1$
+        if ((oldPropertyType != null)
+                && (!oldPropertyType.getName().equals(propertyType.getName()))) {
+            table.put(tag, "invalid"); //$NON-NLS-1$
+            table.put(tag + "get", theMethod); //$NON-NLS-1$
+            table.put(tag + "PropertyType", propertyType); //$NON-NLS-1$
+            table.remove(tag + "set"); //$NON-NLS-1$
+            return;
+        }
+
+        table.put(tag, "valid"); //$NON-NLS-1$
+        table.put(tag + "get", theMethod); //$NON-NLS-1$
+        table.put(tag + "PropertyType", propertyType); //$NON-NLS-1$
+
+        propertyTable.put(propertyName, table);
+    }
+
+    private static void introspectSet(Method theMethod, HashMap<String, HashMap> propertyTable) {
+        String methodName = theMethod.getName();
+        if (methodName == null) {
+            return;
+        }
+
+        int prefixLength = 0;
+        if (methodName.startsWith(PREFIX_SET)) {
+            prefixLength = PREFIX_GET.length();
+        }
+
+        if (prefixLength == 0) {
+            return;
+        }
+
+        String propertyName = decapitalize(methodName.substring(prefixLength));
+
+        //validate property name
+        if (!isValidProperty(propertyName)) {
+            return;
+        }
+
+        Class returnType = theMethod.getReturnType();
+
+        if (!returnType.getName().equals(Void.TYPE.getName())) {
+            return;
+        }
+
+        //indexed get method
+        Class[] paramTypes = theMethod.getParameterTypes();
+
+        if ((paramTypes.length == 0) || (paramTypes.length > 2)) {
+            return;
+        }
+
+        String tag = "normal"; //$NON-NLS-1$
+
+        Class propertyType = paramTypes[0];
+
+        if (paramTypes.length == 2) {
+            if (paramTypes[0].getName().equals(Integer.TYPE.getName())) {
+                tag = "indexed"; //$NON-NLS-1$
+                propertyType = paramTypes[1];
+            } else {
+                return;
+            }
+        }
+
+        HashMap table = propertyTable.get(propertyName);
+        if (table == null) {
+            table = new HashMap();
+        }
+
+        Class oldPropertyType = (Class) table.get(tag + "PropertyType"); //$NON-NLS-1$
+        if ((oldPropertyType != null)
+                && (!oldPropertyType.getName().equals(propertyType.getName()))) {
+            table.put(tag, "invalid"); //$NON-NLS-1$
+            return;
+        }
+
+        table.put(tag, "valid"); //$NON-NLS-1$
+        table.put(tag + "set", theMethod); //$NON-NLS-1$
+        table.put(tag + "PropertyType", propertyType); //$NON-NLS-1$
+
+        propertyTable.put(propertyName, table);
+    }
+
+    /**
+     * Introspects the supplied Bean class and returns a list of the Events of
+     * the class
+     * 
+     * @param beanClass
+     * @return the events
+     * @throws IntrospectionException
+     */
+    private static EventSetDescriptor[] introspectEvents(Class beanClass)
+            throws IntrospectionException {
+        if (beanClass == null)
+            return null;
+
+        // Get descriptors for the public methods
+        MethodDescriptor[] theMethods = introspectMethods(beanClass);
+
+        if (theMethods == null)
+            return null;
+
+        HashMap<String, HashMap> eventTable = new HashMap<String, HashMap>(theMethods.length);
+
+        // Search for methods that add an Event Listener
+        for (int i = 0; i < theMethods.length; i++) {
+            introspectListenerMethods(PREFIX_ADD, theMethods[i].getMethod(),
+                    eventTable);
+            introspectListenerMethods(PREFIX_REMOVE, theMethods[i].getMethod(),
+                    eventTable);
+            introspectGetListenerMethods(theMethods[i].getMethod(), eventTable);
+
+        }
+
+        ArrayList<EventSetDescriptor> eventList = new ArrayList<EventSetDescriptor>();
+        Iterator keys = eventTable.keySet().iterator();
+        while (keys.hasNext()) {
+            String key = (String) keys.next();
+            HashMap table = eventTable.get(key);
+            Method add = (Method) table.get(PREFIX_ADD);
+            Method remove = (Method) table.get(PREFIX_REMOVE);
+
+            if ((add == null) || (remove == null)) {
+                continue;
+            }
+
+            Method get = (Method) table.get(PREFIX_GET);
+            Class listenerType = (Class) table.get("listenerType"); //$NON-NLS-1$
+            Method[] listenerMethods = (Method[]) table.get("listenerMethods"); //$NON-NLS-1$
+            EventSetDescriptor eventSetDescriptor = new EventSetDescriptor(
+                    decapitalize(key), listenerType, listenerMethods, add,
+                    remove, get);
+
+            eventSetDescriptor.setUnicast(table.get("isUnicast") != null); //$NON-NLS-1$
+            eventList.add(eventSetDescriptor);
+        }
+
+        EventSetDescriptor[] theEvents = new EventSetDescriptor[eventList
+                .size()];
+        eventList.toArray(theEvents);
+
+        return theEvents;
+    }
+
+    /*
+     * find the add, remove listener method
+     */
+    private static void introspectListenerMethods(String type,
+            Method theMethod, HashMap methodsTable) {
+        String methodName = theMethod.getName();
+        if (methodName == null) {
+            return;
+        }
+
+        if (!((methodName.startsWith(type)) && (methodName
+                .endsWith(SUFFIX_LISTEN)))) {
+            return;
+        }
+
+        String listenerName = methodName.substring(type.length());
+        String eventName = listenerName.substring(0, listenerName
+                .lastIndexOf(SUFFIX_LISTEN));
+        if ((eventName == null) || (eventName.length() == 0)) {
+            return;
+        }
+
+        Class[] paramTypes = theMethod.getParameterTypes();
+        if ((paramTypes == null) || (paramTypes.length != 1)) {
+            return;
+        }
+
+        Class listenerType = paramTypes[0];
+
+        if (!EventListener.class.isAssignableFrom(listenerType)) {
+            return;
+        }
+
+        if (!listenerType.getName().endsWith(listenerName)) {
+            return;
+        }
+
+        HashMap table = (HashMap) methodsTable.get(eventName);
+        if (table == null) {
+            table = new HashMap();
+        }
+        //put listener type
+        if (table.get("listenerType") == null) { //$NON-NLS-1$
+            table.put("listenerType", listenerType); //$NON-NLS-1$
+            table.put("listenerMethods", //$NON-NLS-1$
+                    introspectListenerMethods(listenerType));
+        }
+        //put add / remove
+        table.put(type, theMethod);
+
+        //determine isUnicast()
+        if (type.equals(PREFIX_ADD)) {
+            Class[] exceptionTypes = theMethod.getExceptionTypes();
+            if (exceptionTypes != null) {
+                for (int i = 0; i < exceptionTypes.length; i++) {
+                    if (exceptionTypes[i].getName().equals(
+                            TooManyListenersException.class.getName())) {
+                        table.put("isUnicast", "true"); //$NON-NLS-1$//$NON-NLS-2$
+                        break;
+                    }
+                }
+            }
+        }
+
+        methodsTable.put(eventName, table);
+    }
+
+    private static Method[] introspectListenerMethods(Class listenerType) {
+        Method[] methods = listenerType.getDeclaredMethods();
+        ArrayList<Method> list = new ArrayList<Method>();
+        for (int i = 0; i < methods.length; i++) {
+            Class[] paramTypes = methods[i].getParameterTypes();
+            if (paramTypes.length != 1) {
+                continue;
+            }
+
+            if (EventObject.class.isAssignableFrom(paramTypes[0])) {
+                list.add(methods[i]);
+            }
+        }
+        Method[] matchedMethods = new Method[list.size()];
+        list.toArray(matchedMethods);
+        return matchedMethods;
+    }
+
+    private static void introspectGetListenerMethods(Method theMethod,
+            HashMap methodsTable) {
+        String type = PREFIX_GET;
+
+        String methodName = theMethod.getName();
+        if (methodName == null) {
+            return;
+        }
+
+        if (!((methodName.startsWith(type)) && (methodName
+                .endsWith(SUFFIX_LISTEN + "s")))) { //$NON-NLS-1$
+            return;
+        }
+
+        String listenerName = methodName.substring(type.length(), methodName
+                .length() - 1);
+        String eventName = listenerName.substring(0, listenerName
+                .lastIndexOf(SUFFIX_LISTEN));
+        if ((eventName == null) || (eventName.length() == 0)) {
+            return;
+        }
+
+        Class[] paramTypes = theMethod.getParameterTypes();
+        if ((paramTypes == null) || (paramTypes.length != 0)) {
+            return;
+        }
+
+        Class returnType = theMethod.getReturnType();
+        if ((returnType.getComponentType() == null)
+                || (!returnType.getComponentType().getName().endsWith(
+                        listenerName))) {
+            return;
+        }
+
+        HashMap table = (HashMap) methodsTable.get(eventName);
+        if (table == null) {
+            table = new HashMap();
+        }
+        //put add / remove
+        table.put(type, theMethod);
+        methodsTable.put(eventName, table);
+    }
+    
+
+    private static boolean isValidProperty(String propertyName) {
+        return (propertyName != null) && (propertyName.length() != 0);
+    }
+    
+    private static class PropertyComparator implements Comparator {
+
+        public int compare(Object object1, Object object2) {
+            PropertyDescriptor theDesc = (PropertyDescriptor) object1;
+            PropertyDescriptor otherDesc = (PropertyDescriptor) object2;
+
+            return theDesc.getName().compareTo(otherDesc.getName());
+        }
+
+    }
+
+}
+

Propchange: harmony/enhanced/classlib/trunk/modules/beans/src/main/java/java/beans/StandardBeanInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native