001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.geronimo.gbean;
018    
019    import java.beans.Introspector;
020    import java.lang.reflect.Constructor;
021    import java.lang.reflect.Method;
022    import java.util.Collection;
023    import java.util.HashMap;
024    import java.util.HashSet;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Map;
028    import java.util.Set;
029    import java.util.Arrays;
030    
031    import org.apache.geronimo.kernel.ClassLoading;
032    import org.apache.geronimo.kernel.Kernel;
033    
034    /**
035     * @version $Rev: 889880 $ $Date: 2009-12-12 10:45:24 +0800 (Sat, 12 Dec 2009) $
036     */
037    public class GBeanInfoBuilder {
038        public static GBeanInfoBuilder createStatic(Class gbeanType) {
039            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
040            return createStatic(gbeanType, gbeanType.getName(), gbeanType, null, null);
041        }
042    
043        public static GBeanInfoBuilder createStatic(Class gbeanType, String j2eeType) {
044            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
045            return createStatic(gbeanType, gbeanType.getName(), gbeanType, null, j2eeType);
046        }
047    
048        public static GBeanInfoBuilder createStatic(String name, Class gbeanType) {
049            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
050            return createStatic(gbeanType, name, gbeanType, null, null);
051        }
052    
053        public static GBeanInfoBuilder createStatic(String name, Class gbeanType, String j2eeType) {
054            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
055            return createStatic(gbeanType, name, gbeanType, null, j2eeType);
056        }
057    
058        public static GBeanInfoBuilder createStatic(Class gbeanType, GBeanInfo source) {
059            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
060            return createStatic(gbeanType, gbeanType.getName(), gbeanType, source, null);
061        }
062    
063        public static GBeanInfoBuilder createStatic(Class gbeanType, GBeanInfo source, String j2eeType) {
064            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
065            return createStatic(gbeanType, gbeanType.getName(), gbeanType, source, j2eeType);
066        }
067    
068        public static GBeanInfoBuilder createStatic(String name, Class gbeanType, GBeanInfo source) {
069            if (name == null) throw new NullPointerException("name is null");
070            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
071            return createStatic(gbeanType, name, gbeanType, source, null);
072        }
073    
074        //
075        // These methods are used by classes that declare a GBeanInfo for another class
076        //
077        public static GBeanInfoBuilder createStatic(Class sourceClass, Class gbeanType) {
078            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
079            return createStatic(sourceClass, gbeanType.getName(), gbeanType, null, null);
080        }
081    
082        public static GBeanInfoBuilder createStatic(Class sourceClass, Class gbeanType, String j2eeType) {
083            if (sourceClass == null) throw new NullPointerException("sourceClass is null");
084            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
085            return createStatic(sourceClass, gbeanType.getName(), gbeanType, null, j2eeType);
086        }
087    
088        public static GBeanInfoBuilder createStatic(Class sourceClass, Class gbeanType, GBeanInfo source, String j2eeType) {
089            if (sourceClass == null) throw new NullPointerException("sourceClass is null");
090            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
091            return createStatic(sourceClass, gbeanType.getName(), gbeanType, source, j2eeType);
092        }
093    
094        public static GBeanInfoBuilder createStatic(Class sourceClass, String name, Class gbeanType, String j2eeType) {
095            if (sourceClass == null) throw new NullPointerException("sourceClass is null");
096            if (name == null) throw new NullPointerException("name is null");
097            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
098            return createStatic(sourceClass, name, gbeanType, null, j2eeType);
099        }
100    
101        public static GBeanInfoBuilder createStatic(Class sourceClass, String name, Class gbeanType, GBeanInfo source, String j2eeType) {
102            if (sourceClass == null) throw new NullPointerException("sourceClass is null");
103            if (name == null) throw new NullPointerException("name is null");
104            if (gbeanType == null) throw new NullPointerException("gbeanType is null");
105            return new GBeanInfoBuilder(sourceClass.getName(), name, gbeanType, source, j2eeType);
106        }
107    
108        public static final String DEFAULT_J2EE_TYPE = "GBean"; //NameFactory.GERONIMO_SERVICE
109    
110        private static final Class[] NO_ARGS = {};
111    
112        /**
113         * The class from which the info can be retrieved using GBeanInfo.getGBeanInfo(className, classLoader)
114         */
115        private final String sourceClass;
116    
117        private final String name;
118    
119        private final String j2eeType;
120    
121        private final Class gbeanType;
122    
123        private final Map attributes = new HashMap();
124    
125        private GConstructorInfo constructor = new GConstructorInfo();
126    
127        private final Map operations = new HashMap();
128    
129        private final Map references = new HashMap();
130    
131        private final Set interfaces = new HashSet();
132    
133        private int priority = GBeanInfo.PRIORITY_NORMAL;
134    
135        public GBeanInfoBuilder(Class gbeanType) {
136            this(checkNotNull(gbeanType).getName(), gbeanType, null, null);
137        }
138    
139        public GBeanInfoBuilder(Class gbeanType, String j2eeType) {
140            this(checkNotNull(gbeanType).getName(), gbeanType, null, j2eeType);
141        }
142    
143        public GBeanInfoBuilder(String name, Class gbeanType) {
144            this(name, checkNotNull(gbeanType), null, null);
145        }
146    
147        public GBeanInfoBuilder(String name, Class gbeanType, String j2eeType) {
148            this(name, checkNotNull(gbeanType), null, j2eeType);
149        }
150    
151        public GBeanInfoBuilder(Class gbeanType, GBeanInfo source) {
152            this(checkNotNull(gbeanType).getName(), gbeanType, source);
153        }
154    
155        public GBeanInfoBuilder(Class gbeanType, GBeanInfo source, String j2eeType) {
156            this(checkNotNull(gbeanType).getName(), gbeanType, source, j2eeType);
157        }
158    
159        //TODO remove this
160        /**
161         * @deprecated This will be removed in a future release
162         */
163        public GBeanInfoBuilder(String name, ClassLoader classLoader) {
164            this(checkNotNull(name), loadClass(classLoader, name), GBeanInfo.getGBeanInfo(name, classLoader));
165        }
166    
167        public GBeanInfoBuilder(String name, Class gbeanType, GBeanInfo source) {
168            this(name, gbeanType, source, null);
169        }
170    
171        public GBeanInfoBuilder(String name, Class gbeanType, GBeanInfo source, String j2eeType) {
172            this(null, name, gbeanType, source, j2eeType);
173        }
174    
175        private GBeanInfoBuilder(String sourceClass, String name, Class gbeanType, GBeanInfo source, String j2eeType) {
176            checkNotNull(name);
177            checkNotNull(gbeanType);
178            this.name = name;
179            this.gbeanType = gbeanType;
180            this.sourceClass = sourceClass;
181    
182            if (source != null) {
183                for (Iterator i = source.getAttributes().iterator(); i.hasNext();) {
184                    GAttributeInfo attributeInfo = (GAttributeInfo) i.next();
185                    attributes.put(attributeInfo.getName(), attributeInfo);
186                }
187    
188                for (Iterator i = source.getOperations().iterator(); i.hasNext();) {
189                    GOperationInfo operationInfo = (GOperationInfo) i.next();
190                    operations.put(new GOperationSignature(operationInfo.getName(), operationInfo.getParameterList()), operationInfo);
191                }
192    
193                for (Iterator iterator = source.getReferences().iterator(); iterator.hasNext();) {
194                    GReferenceInfo referenceInfo = (GReferenceInfo) iterator.next();
195                    references.put(referenceInfo.getName(), new RefInfo(referenceInfo.getReferenceType(), referenceInfo.getNameTypeName()));
196                }
197    
198                for (Iterator iterator = source.getInterfaces().iterator(); iterator.hasNext();) {
199                    String intf = (String) iterator.next();
200                    interfaces.add(intf);
201                }
202    
203                //in case subclass constructor has same parameters as superclass.
204                constructor = source.getConstructor();
205    
206                priority = source.getPriority();
207            }
208            if (j2eeType != null) {
209                this.j2eeType = j2eeType;
210            } else if (source != null) {
211                this.j2eeType = source.getJ2eeType();
212            } else {
213                this.j2eeType = DEFAULT_J2EE_TYPE; //NameFactory.GERONIMO_SERVICE
214            }
215    
216            // add all interfaces based on GBean type
217            if (gbeanType.isArray()) {
218                throw new IllegalArgumentException("GBean is an array type: gbeanType=" + gbeanType.getName());
219            }
220            Set allTypes = ClassLoading.getAllTypes(gbeanType);
221            for (Iterator iterator = allTypes.iterator(); iterator.hasNext();) {
222                Class type = (Class) iterator.next();
223                addInterface(type);
224            }
225        }
226    
227        public void setPersistentAttributes(String[] persistentAttributes) {
228            for (int i = 0; i < persistentAttributes.length; i++) {
229                String attributeName = persistentAttributes[i];
230                GAttributeInfo attribute = (GAttributeInfo) attributes.get(attributeName);
231                if (attribute != null && !references.containsKey(attributeName)) {
232                    if (isMagicAttribute(attribute)) {
233                        // magic attributes can't be persistent
234                        continue;
235                    }
236                    attributes.put(attributeName,   
237                            new GAttributeInfo(attributeName,
238                                    attribute.getType(), 
239                                    true,
240                                    attribute.isManageable(),
241                                    attribute.isEncrypted(),
242                                    attribute.getGetterName(),
243                                    attribute.getSetterName()));
244                } else {
245                    if (attributeName.equals("kernel")) {
246                        addAttribute("kernel", Kernel.class, false);
247                    } else if (attributeName.equals("classLoader")) {
248                        addAttribute("classLoader", ClassLoader.class, false);
249                    } else if (attributeName.equals("abstractName")) {
250                        addAttribute("abstractName", AbstractName.class, false);
251                    } else if (attributeName.equals("objectName")) {
252                        addAttribute("objectName", String.class, false);
253                    }
254                }
255            }
256        }
257    
258        public void setManageableAttributes(String[] manageableAttributes) {
259            for (int i = 0; i < manageableAttributes.length; i++) {
260                String attributeName = manageableAttributes[i];
261                GAttributeInfo attribute = (GAttributeInfo) attributes.get(attributeName);
262                if (attribute != null) {
263                    attributes.put(attributeName,
264                            new GAttributeInfo(attributeName,
265                                    attribute.getType(),
266                                    attribute.isPersistent(),
267                                    true,
268                                    attribute.isEncrypted(),
269                                    attribute.getGetterName(),
270                                    attribute.getSetterName()));
271                }
272            }
273        }
274    
275        private boolean isMagicAttribute(GAttributeInfo attributeInfo) {
276            String name = attributeInfo.getName();
277            String type = attributeInfo.getType();
278            return ("kernel".equals(name) && Kernel.class.getName().equals(type)) ||
279                    ("classLoader".equals(name) && ClassLoader.class.getName().equals(type)) ||
280                    ("abstractName".equals(name) && AbstractName.class.getName().equals(type)) ||
281                    ("objectName".equals(name) && String.class.getName().equals(type));
282        }
283    
284        public void addInterface(Class intf) {
285            addInterface(intf, new String[0]);
286        }
287    
288        //do not use beaninfo Introspector to list the properties.  This method is primarily for interfaces,
289        //and it does not process superinterfaces.  It seems to really only work well for classes.
290        public void addInterface(Class intf, String[] persistentAttributes) {
291            addInterface(intf, persistentAttributes, new String[0]);
292        }
293    
294        public void addInterface(Class intf, String[] persistentAttributes, String[] manageableAttributes) {
295            Set persistentNames = new HashSet(Arrays.asList(persistentAttributes));
296            Set manageableNames = new HashSet(Arrays.asList(manageableAttributes));
297            Method[] methods = intf.getMethods();
298            for (int i = 0; i < methods.length; i++) {
299                Method method = methods[i];
300                if ("java.lang.Object".equals(method.getDeclaringClass().getName())) continue;
301                if (isGetter(method)) {
302                    String attributeName = getAttributeName(method);
303                    GAttributeInfo attribute = (GAttributeInfo) attributes.get(attributeName);
304                    String attributeType = method.getReturnType().getName();
305                    if (attribute == null) {
306                        attributes.put(attributeName,
307                                new GAttributeInfo(attributeName,
308                                        attributeType,
309                                        persistentNames.contains(attributeName),
310                                        manageableNames.contains(attributeName),
311                                        method.getName(),
312                                        null));
313                    } else {
314                        if (!attributeType.equals(attribute.getType())) {
315                            throw new IllegalArgumentException("Getter and setter type do not match: " + attributeName + " for gbeanType: " + gbeanType.getName());
316                        }
317                        attributes.put(attributeName,
318                                new GAttributeInfo(attributeName,
319                                        attributeType,
320                                        attribute.isPersistent() || persistentNames.contains(attributeName),
321                                        attribute.isManageable() || manageableNames.contains(attributeName),
322                                        attribute.isEncrypted(),
323                                        method.getName(),
324                                        attribute.getSetterName()));
325                    }
326                } else if (isSetter(method)) {
327                    String attributeName = getAttributeName(method);
328                    String attributeType = method.getParameterTypes()[0].getName();
329                    GAttributeInfo attribute = (GAttributeInfo) attributes.get(attributeName);
330                    if (attribute == null) {
331                        attributes.put(attributeName,
332                                new GAttributeInfo(attributeName,
333                                        attributeType,
334                                        persistentNames.contains(attributeName),
335                                        manageableNames.contains(attributeName),
336                                        null,
337                                        method.getName()));
338                    } else {
339                        if (!attributeType.equals(attribute.getType())) {
340                            throw new IllegalArgumentException("Getter and setter type do not match: " + attributeName + " for gbeanType: " + gbeanType.getName());
341                        }
342                        attributes.put(attributeName,
343                                new GAttributeInfo(attributeName,
344                                        attributeType,
345                                        attribute.isPersistent() || persistentNames.contains(attributeName),
346                                        attribute.isManageable() || manageableNames.contains(attributeName),
347                                        attribute.isEncrypted(),
348                                        attribute.getGetterName(),
349                                        method.getName()));
350                    }
351                } else {
352                    addOperation(new GOperationInfo(method.getName(), method.getParameterTypes(), method.getReturnType().getName()));
353                }
354            }
355            addInterface(interfaces, intf);
356        }
357    
358        private static void addInterface(Set set, Class intf) {
359            String name = intf.getName();
360            if(set.contains(name)) {
361                return;
362            }
363            set.add(name);
364            Class cls[] = intf.getInterfaces();
365            for (int i = 0; i < cls.length; i++) {
366                addInterface(set, cls[i]);
367            }
368        }
369        public void addAttribute(String name, Class type, boolean persistent) {
370            addAttribute(name, type.getName(), persistent, true);
371        }
372    
373        public void addAttribute(String name, String type, boolean persistent) {
374            addAttribute(name, type, persistent, true);
375        }
376    
377        public void addAttribute(String name, Class type, boolean persistent, boolean manageable) {
378            addAttribute(name, type.getName(), persistent, manageable);
379        }
380    
381        public void addAttribute(String name, String type, boolean persistent, boolean manageable) {
382            String getter = searchForGetter(name, type, gbeanType);
383            String setter = searchForSetter(name, type, gbeanType);
384            addAttribute(new GAttributeInfo(name, type, persistent, manageable, getter, setter));
385        }
386    
387        public void addAttribute(String name, Class type, boolean persistent, boolean manageable, boolean encrypted) {
388            addAttribute(name, type.getName(), persistent, manageable, encrypted);
389        }
390    
391        public void addAttribute(String name, String type, boolean persistent, boolean manageable, boolean encrypted) {
392            String getter = searchForGetter(name, type, gbeanType);
393            String setter = searchForSetter(name, type, gbeanType);
394            addAttribute(new GAttributeInfo(name, type, persistent, manageable, encrypted, getter, setter));
395        }
396    
397        public void addAttribute(GAttributeInfo info) {
398            attributes.put(info.getName(), info);
399        }
400    
401        public void setConstructor(GConstructorInfo constructor) {
402            assert constructor != null;
403            this.constructor = constructor;
404            List names = constructor.getAttributeNames();
405            setPersistentAttributes((String[]) names.toArray(new String[names.size()]));
406        }
407    
408        public void setConstructor(String[] names) {
409            constructor = new GConstructorInfo(names);
410            setPersistentAttributes(names);
411        }
412    
413        public void addOperation(GOperationInfo operationInfo) {
414            operations.put(new GOperationSignature(operationInfo.getName(), operationInfo.getParameterList()), operationInfo);
415        }
416        
417        /**
418         * @deprecated
419         */
420        public void addOperation(String name) {
421            // FIXME : This is needed because the getters/setters are not being added as operation
422            // i.e. kerenl.invoke("getX") fails.
423            addOperation(new GOperationInfo(name, NO_ARGS, ""));
424        }
425    
426        /**
427         * @deprecated
428         */
429        public void addOperation(String name, Class[] paramTypes) {
430            //addOperation(new GOperationInfo(name, paramTypes, ""));
431        }
432       
433        public void addOperation(String name, String returnType) {
434            addOperation(new GOperationInfo(name, NO_ARGS, returnType));
435        }
436    
437        // This is redundant because these operations are added automatically; it can be made private
438        public void addOperation(String name, Class[] paramTypes, String returnType) {
439            addOperation(new GOperationInfo(name, paramTypes, returnType));
440        }
441    
442        public void addReference(GReferenceInfo info) {
443            references.put(info.getName(), new RefInfo(info.getReferenceType(), info.getNameTypeName()));
444        }
445    
446        /**
447         * Add a reference to another GBean or collection of GBeans
448         * @param name the name of the reference
449         * @param type The proxy type of the GBean or objects in a ReferenceCollection
450         * @param namingType the string expected as the type component of the name.  For jsr-77 names this is the j2eeType value
451         */
452        public void addReference(String name, Class type, String namingType) {
453            references.put(name, new RefInfo(type.getName(), namingType));
454        }
455    
456        public void addReference(String name, Class type) {
457            references.put(name, new RefInfo(type.getName(), null));
458        }
459    
460        public void setPriority(int priority) {
461            this.priority = priority;
462        }
463    
464        public GBeanInfo getBeanInfo() {
465            // get the types of the constructor args
466            // this also verifies that we have a valid constructor
467            Map constructorTypes = getConstructorTypes();
468    
469            // build the reference infos now that we know the constructor types
470            Set referenceInfos = new HashSet();
471            for (Iterator iterator = references.entrySet().iterator(); iterator.hasNext();) {
472                Map.Entry entry = (Map.Entry) iterator.next();
473                String referenceName = (String) entry.getKey();
474                RefInfo refInfo = (RefInfo) entry.getValue();
475                String referenceType = refInfo.getJavaType();
476                String namingType = refInfo.getNamingType();
477    
478                String proxyType = (String) constructorTypes.get(referenceName);
479                String setterName = null;
480                if (proxyType == null) {
481                    Method setter = searchForSetterMethod(referenceName, referenceType, gbeanType);
482                    if (setter == null) {
483                        setter = searchForSetterMethod(referenceName, Collection.class.getName(), gbeanType);
484                        if (setter == null) {
485                            throw new InvalidConfigurationException("Reference must be a constructor argument or have a setter: name=" + referenceName + " for gbeanType: " + gbeanType);
486                        }
487                    }
488                    proxyType = setter.getParameterTypes()[0].getName();
489    
490                    setterName = setter.getName();
491                }
492    
493                if (!proxyType.equals(Collection.class.getName()) && !proxyType.equals(referenceType)) {
494                    throw new InvalidConfigurationException("Reference proxy type must be Collection or " + referenceType + ": name=" + referenceName + " for gbeanType: " + gbeanType.getName());
495                }
496    
497                referenceInfos.add(new GReferenceInfo(referenceName, referenceType, proxyType, setterName, namingType));
498            }
499    
500            return new GBeanInfo(sourceClass, name, gbeanType.getName(), j2eeType, attributes.values(), constructor, operations.values(), referenceInfos, interfaces, priority);
501        }
502    
503        private Map getConstructorTypes() throws InvalidConfigurationException {
504            List arguments = constructor.getAttributeNames();
505            String[] argumentTypes = new String[arguments.size()];
506            boolean[] isReference = new boolean[arguments.size()];
507            for (int i = 0; i < argumentTypes.length; i++) {
508                String argumentName = (String) arguments.get(i);
509                if (references.containsKey(argumentName)) {
510                    argumentTypes[i] = ((RefInfo) references.get(argumentName)).getJavaType();
511                    isReference[i] = true;
512                } else if (attributes.containsKey(argumentName)) {
513                    GAttributeInfo attribute = (GAttributeInfo) attributes.get(argumentName);
514                    argumentTypes[i] = attribute.getType();
515                    isReference[i] = false;
516                }  
517            }
518    
519            Constructor[] constructors = gbeanType.getConstructors();
520            Set validConstructors = new HashSet();
521            for (int i = 0; i < constructors.length; i++) {
522                Constructor constructor = constructors[i];
523                if (isValidConstructor(constructor, argumentTypes, isReference)) {
524                    validConstructors.add(constructor);
525                }
526            }
527    
528            if (validConstructors.isEmpty()) {
529                throw new InvalidConfigurationException("Could not find a valid constructor for GBean: " + gbeanType.getName());
530            }
531            if (validConstructors.size() > 1) {
532                throw new InvalidConfigurationException("More then one valid constructors found for GBean: " + gbeanType.getName());
533            }
534    
535            Map constructorTypes = new HashMap();
536            Constructor constructor = (Constructor) validConstructors.iterator().next();
537            Class[] parameterTypes = constructor.getParameterTypes();
538            Iterator argumentIterator = arguments.iterator();
539            for (int i = 0; i < parameterTypes.length; i++) {
540                String parameterType = parameterTypes[i].getName();
541                String argumentName = (String) argumentIterator.next();
542                constructorTypes.put(argumentName, parameterType);
543            }
544            return constructorTypes;
545        }
546    
547        private static String searchForGetter(String name, String type, Class gbeanType) throws InvalidConfigurationException {
548            Method getterMethod = null;
549    
550            // no explicit name give so we must search for a name
551            String getterName = "get" + name;
552            String isName = "is" + name;
553            Method[] methods = gbeanType.getMethods();
554            for (int i = 0; i < methods.length; i++) {
555                if (methods[i].getParameterTypes().length == 0 && methods[i].getReturnType() != Void.TYPE
556                        && (getterName.equalsIgnoreCase(methods[i].getName()) || isName.equalsIgnoreCase(methods[i].getName()))) {
557    
558                    // found it
559                    getterMethod = methods[i];
560                    break;
561                }
562            }
563    
564            // if the return type of the getter doesn't match, throw an exception
565            if (getterMethod != null && !type.equals(getterMethod.getReturnType().getName())) {
566                throw new InvalidConfigurationException("Incorrect return type for getter method:" +
567                        " name=" + name +
568                        ", targetClass=" + gbeanType.getName() +
569                        ", getter type=" + getterMethod.getReturnType() +
570                        ", expected type=" + type);
571            }
572    
573            if (getterMethod == null) {
574                return null;
575            }
576            return getterMethod.getName();
577        }
578    
579        private static String searchForSetter(String name, String type, Class gbeanType) throws InvalidConfigurationException {
580            Method method = searchForSetterMethod(name, type, gbeanType);
581            if (method == null) {
582                return null;
583            }
584            return method.getName();
585        }
586    
587        private static Method searchForSetterMethod(String name, String type, Class gbeanType) throws InvalidConfigurationException {
588            // no explicit name give so we must search for a name
589            String setterName = "set" + name;
590            Method[] methods = gbeanType.getMethods();
591            for (int i = 0; i < methods.length; i++) {
592                Method method = methods[i];
593                if (method.getParameterTypes().length == 1 &&
594                        method.getParameterTypes()[0].getName().equals(type) &&
595                        method.getReturnType() == Void.TYPE &&
596                        setterName.equalsIgnoreCase(method.getName())) {
597    
598                    return method;
599                }
600            }
601    
602            // a setter is not necessary for this attribute
603            return null;
604        }
605    
606        private static boolean isValidConstructor(Constructor constructor, String[] argumentTypes, boolean[] isReference) {
607            Class[] parameterTypes = constructor.getParameterTypes();
608    
609            // same number of parameters?
610            if (parameterTypes.length != argumentTypes.length) {
611                return false;
612            }
613    
614            // is each parameter the correct type?
615            for (int i = 0; i < parameterTypes.length; i++) {
616                String parameterType = parameterTypes[i].getName();
617                if (isReference[i]) {
618                    // reference: does type match
619                    // OR is it a java.util.Collection
620                    // OR is it a java.util.Set?
621                    if (!parameterType.equals(argumentTypes[i]) &&
622                            !parameterType.equals(Collection.class.getName()) &&
623                            !parameterType.equals(Set.class.getName())) {
624                        return false;
625                    }
626                } else {
627                    // attribute: does type match?
628                    if (!parameterType.equals(argumentTypes[i])) {
629                        return false;
630                    }
631                }
632            }
633            return true;
634        }
635    
636        private String getAttributeName(Method method) {
637            String name = method.getName();
638            String attributeName = (name.startsWith("get") || name.startsWith("set")) ? name.substring(3) : name.substring(2);
639            attributeName = Introspector.decapitalize(attributeName);
640            return attributeName;
641        }
642    
643        private boolean isSetter(Method method) {
644            return method.getName().startsWith("set") && method.getParameterTypes().length == 1;
645        }
646    
647        private static boolean isGetter(Method method) {
648            String name = method.getName();
649            return (name.startsWith("get") || name.startsWith("is")) && method.getParameterTypes().length == 0;
650        }
651    
652        /**
653         * Checks whether or not the input argument is null; otherwise it throws
654         * {@link IllegalArgumentException}.
655         *
656         * @param clazz the input argument to validate
657         * @throws IllegalArgumentException if input is null
658         */
659        private static Class checkNotNull(final Class clazz) {
660            if (clazz == null) {
661                throw new IllegalArgumentException("null argument supplied");
662            }
663            return clazz;
664        }
665    
666        /**
667         * Checks whether or not the input argument is null; otherwise it throws
668         * {@link IllegalArgumentException}.
669         *
670         * @param string the input argument to validate
671         * @throws IllegalArgumentException if input is null
672         */
673        private static String checkNotNull(final String string) {
674            if (string == null) {
675                throw new IllegalArgumentException("null argument supplied");
676            }
677            return string;
678        }
679    
680        private static Class loadClass(ClassLoader classLoader, String name) {
681            try {
682                return classLoader.loadClass(name);
683            } catch (ClassNotFoundException e) {
684                throw new InvalidConfigurationException("Could not load class " + name, e);
685            }
686        }
687    
688        private static class RefInfo {
689            private final String javaType;
690            private final String namingType;
691    
692            public RefInfo(String javaType, String namingType) {
693                this.javaType = javaType;
694                this.namingType = namingType;
695            }
696    
697            public String getJavaType() {
698                return javaType;
699            }
700    
701            public String getNamingType() {
702                return namingType;
703            }
704        }
705    }