001    /* java.beans.Introspector
002       Copyright (C) 1998, 2002, 2003 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010     
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.beans;
040    
041    import gnu.java.beans.BeanInfoEmbryo;
042    import gnu.java.beans.ExplicitBeanInfo;
043    import gnu.java.beans.IntrospectionIncubator;
044    import gnu.java.lang.ClassHelper;
045    
046    import java.util.Hashtable;
047    import java.util.Vector;
048    
049    /**
050     * Introspector is the class that does the bulk of the
051     * design-time work in Java Beans.  Every class must have
052     * a BeanInfo in order for an RAD tool to use it; but, as
053     * promised, you don't have to write the BeanInfo class
054     * yourself if you don't want to.  All you have to do is
055     * call getBeanInfo() in the Introspector and it will use
056     * standard JavaBeans-defined method signatures to
057     * determine the information about your class.<P>
058     *
059     * Don't worry about it too much, though: you can provide
060     * JavaBeans with as much customized information as you
061     * want, or as little as you want, using the BeanInfo
062     * interface (see BeanInfo for details).<P>
063     *
064     * <STRONG>Order of Operations</STRONG><P>
065     *
066     * When you call getBeanInfo(class c), the Introspector
067     * first searches for BeanInfo class to see if you
068     * provided any explicit information.  It searches for a
069     * class named &lt;bean class name&gt;BeanInfo in different
070     * packages, first searching the bean class's package
071     * and then moving on to search the beanInfoSearchPath.<P>
072     *
073     * If it does not find a BeanInfo class, it acts as though
074     * it had found a BeanInfo class returning null from all
075     * methods (meaning it should discover everything through
076     * Introspection).  If it does, then it takes the
077     * information it finds in the BeanInfo class to be
078     * canonical (that is, the information speaks for its
079     * class as well as all superclasses).<P>
080     *
081     * When it has introspected the class, calls
082     * getBeanInfo(c.getSuperclass) and adds that information
083     * to the information it has, not adding to any information
084     * it already has that is canonical.<P>
085     *
086     * <STRONG>Introspection Design Patterns</STRONG><P>
087     *
088     * When the Introspector goes in to read the class, it
089     * follows a well-defined order in order to not leave any
090     * methods unaccounted for.  Its job is to step over all
091     * of the public methods in a class and determine whether
092     * they are part of a property, an event, or a method (in
093     * that order).
094     *
095     *
096     * <STRONG>Properties:</STRONG><P>
097     * 
098     * <OL>
099     * <LI>If there is a <CODE>public boolean isXXX()</CODE>
100     *     method, then XXX is a read-only boolean property.
101     *     <CODE>boolean getXXX()</CODE> may be supplied in
102     *     addition to this method, although isXXX() is the
103     *     one that will be used in this case and getXXX()
104     *     will be ignored.  If there is a
105     *     <CODE>public void setXXX(boolean)</CODE> method,
106     *     it is part of this group and makes it a read-write
107     *     property.</LI>
108     * <LI>If there is a
109     *     <CODE>public &lt;type&gt; getXXX(int)</CODE>
110     *     method, then XXX is a read-only indexed property of
111     *     type &lt;type&gt;.  If there is a
112     *     <CODE>public void setXXX(int,&lt;type&gt;)</CODE>
113     *     method, then it is a read-write indexed property of
114     *     type &lt;type&gt;.  There may also be a
115     *     <CODE>public &lt;type&gt;[] getXXX()</CODE> and a
116     *     <CODE>public void setXXX(&lt;type&gt;)</CODE>
117     *     method as well.</LI>
118     * <LI>If there is a
119     *     <CODE>public void setXXX(int,&lt;type&gt;)</CODE>
120     *     method, then it is a write-only indexed property of
121     *     type &lt;type&gt;.  There may also be a
122     *     <CODE>public &lt;type&gt;[] getXXX()</CODE> and a
123     *     <CODE>public void setXXX(&lt;type&gt;)</CODE>
124     *     method as well.</LI>
125     * <LI>If there is a
126     *     <CODE>public &lt;type&gt; getXXX()</CODE> method,
127     *     then XXX is a read-only property of type
128     *     &lt;type&gt;.  If there is a
129     *     <CODE>public void setXXX(&lt;type&gt;)</CODE>
130     *     method, then it will be used for the property and
131     *     the property will be considered read-write.</LI>
132     * <LI>If there is a
133     *     <CODE>public void setXXX(&lt;type&gt;)</CODE>
134     *     method, then as long as XXX is not already used as
135     *     the name of a property, XXX is assumed to be a
136     *     write-only property of type &lt;type&gt;.</LI>
137     * <LI>In all of the above cases, if the setXXX() method
138     *     throws <CODE>PropertyVetoException</CODE>, then the
139     *     property in question is assumed to be constrained.
140     *     No properties are ever assumed to be bound
141     *     (<STRONG>Spec Note:</STRONG> this is not in the
142     *     spec, it just makes sense).  See PropertyDescriptor
143     *     for a description of bound and constrained
144     *     properties.</LI>
145     * </OL>
146     *
147     * <STRONG>Events:</STRONG><P>
148     *
149     * If there is a pair of methods,
150     * <CODE>public void addXXX(&lt;type&gt;)</CODE> and
151     * <CODE>public void removeXXX(&lt;type&gt;)</CODE>, where
152     * &lt;type&gt; is a descendant of
153     * <CODE>java.util.EventListener</CODE>, then the pair of
154     * methods imply that this Bean will fire events to
155     * listeners of type &lt;type&gt;.<P>
156     *
157     * If the addXXX() method throws
158     * <CODE>java.util.TooManyListenersException</CODE>, then
159     * the event set is assumed to be <EM>unicast</EM>.  See
160     * EventSetDescriptor for a discussion of unicast event
161     * sets.<P>
162     *
163     * <STRONG>Spec Note:</STRONG> the spec seems to say that
164     * the listener type's classname must be equal to the XXX
165     * part of addXXX() and removeXXX(), but that is not the
166     * case in Sun's implementation, so I am assuming it is
167     * not the case in general.<P>
168     *
169     * <STRONG>Methods:</STRONG><P>
170     * 
171     * Any public methods (including those which were used
172     * for Properties or Events) are used as Methods.
173     *
174     * @author John Keiser
175     * @since JDK1.1
176     * @see java.beans.BeanInfo
177     */
178    public class Introspector {
179      
180      public static final int USE_ALL_BEANINFO = 1;
181      public static final int IGNORE_IMMEDIATE_BEANINFO = 2;
182      public static final int IGNORE_ALL_BEANINFO = 3;
183    
184      static String[] beanInfoSearchPath = {"gnu.java.beans.info"};
185      static Hashtable<Class<?>,BeanInfo> beanInfoCache = 
186        new Hashtable<Class<?>,BeanInfo>();
187      
188      private Introspector() {}
189      
190      /** 
191       * Get the BeanInfo for class <CODE>beanClass</CODE>,
192       * first by looking for explicit information, next by
193       * using standard design patterns to determine
194       * information about the class.
195       *
196       * @param beanClass the class to get BeanInfo about.
197       * @return the BeanInfo object representing the class.
198       */
199      public static BeanInfo getBeanInfo(Class<?> beanClass) 
200        throws IntrospectionException 
201      {
202        BeanInfo cachedInfo;
203        synchronized(beanClass) 
204          {
205            cachedInfo = beanInfoCache.get(beanClass);
206            if(cachedInfo != null) 
207              {
208                return cachedInfo;
209              }
210            cachedInfo = getBeanInfo(beanClass,null);
211            beanInfoCache.put(beanClass,cachedInfo);
212            return cachedInfo;
213          }
214      }
215      
216      /**
217       * Returns a {@BeanInfo} instance for the given Bean class where a flag
218       * controls the usage of explicit BeanInfo class to retrieve that
219       * information.
220       * 
221       * <p>You have three options:</p>
222       * <p>With {@link #USE_ALL_BEANINFO} the result is the same as
223       * {@link #getBeanInfo(Class)}.</p>
224       * 
225       * <p>Calling the method with <code>flag</code> set to
226       * {@link #IGNORE_IMMEDIATE_BEANINFO} will let it use all
227       * explicit BeanInfo classes for the beans superclasses
228       * but not for the bean class itself. Furthermore eventset,
229       * property and method information is retrieved by introspection
230       * if the explicit <code>BeanInfos</code> did not provide such data
231       * (ie. return <code>null</code> on {@link BeanInfo.getMethodDescriptors},
232       * {@link BeanInfo.getEventSetDescriptors} and
233       * {@link BeanInfo.getPropertyDescriptors}.)
234       * </p>
235       * 
236       * <p>When the method is called with <code>flag</code< set to
237       * {@link #IGNORE_ALL_BEANINFO} all the bean data is retrieved
238       * by inspecting the class.</p>
239       * 
240       * <p>Note: Any unknown value for <code>flag</code> is interpreted
241       * as {@link #IGNORE_ALL_BEANINFO}</p>.
242       * 
243       * @param beanClass The class whose BeanInfo should be returned.
244       * @param flag Controls the usage of explicit <code>BeanInfo</code> classes.
245       * @return A BeanInfo object describing the class. 
246       * @throws IntrospectionException If something goes wrong while retrieving
247       *    the bean data.
248       */
249      public static BeanInfo getBeanInfo(Class<?> beanClass, int flag)
250        throws IntrospectionException
251      {
252        IntrospectionIncubator ii;
253        BeanInfoEmbryo infoEmbryo;
254        
255        switch(flag)
256        {
257          case USE_ALL_BEANINFO:
258            return getBeanInfo(beanClass);
259          case IGNORE_IMMEDIATE_BEANINFO:
260            Class superclass = beanClass.getSuperclass();
261            ExplicitInfo explicit = new ExplicitInfo(superclass, null);
262            
263            ii = new IntrospectionIncubator();
264            if (explicit.explicitEventSetDescriptors != null)
265              ii.setEventStopClass(superclass);
266            
267            if (explicit.explicitMethodDescriptors != null)
268              ii.setMethodStopClass(superclass);
269            
270            if (explicit.explicitPropertyDescriptors != null)
271              ii.setPropertyStopClass(superclass);
272            
273            ii.addMethods(beanClass.getMethods());
274    
275            infoEmbryo = ii.getBeanInfoEmbryo();
276            merge(infoEmbryo, explicit);
277    
278            infoEmbryo.setBeanDescriptor(new BeanDescriptor(beanClass, null));
279            
280            return infoEmbryo.getBeanInfo();
281          case IGNORE_ALL_BEANINFO:
282          default:
283            ii = new IntrospectionIncubator();
284            ii.addMethods(beanClass.getMethods());
285            infoEmbryo = ii.getBeanInfoEmbryo();
286            infoEmbryo.setBeanDescriptor(new BeanDescriptor(beanClass, null));
287            
288            return infoEmbryo.getBeanInfo();
289        }
290      }
291    
292      /**
293       * Flush all of the Introspector's internal caches.
294       *
295       * @since 1.2
296       */
297      public static void flushCaches()
298      {
299        beanInfoCache.clear();
300    
301            // Clears all the intermediate ExplicitInfo instances which
302            // have been created.
303            // This makes sure we have to retrieve stuff like BeanDescriptors
304            // again. (Remember that FeatureDescriptor can be modified by the user.)
305            ExplicitInfo.flushCaches();
306      }
307    
308      /**
309       * Flush the Introspector's internal cached information for a given
310       * class.
311       *
312       * @param clz the class to be flushed.
313       * @throws NullPointerException if clz is null.
314       * @since 1.2
315       */
316      public static void flushFromCaches(Class<?> clz)
317      {
318        synchronized (clz)
319          {
320            beanInfoCache.remove(clz);
321          }
322      }
323    
324      /** Adds all explicity given bean info data to the introspected
325       * data.
326       * 
327       * @param infoEmbryo Bean info data retrieved by introspection.
328       * @param explicit Bean info data retrieved by BeanInfo classes.
329       */
330      private static void merge(BeanInfoEmbryo infoEmbryo, ExplicitInfo explicit)
331      {
332        PropertyDescriptor[] p = explicit.explicitPropertyDescriptors;
333        if(p!=null) 
334          {
335        for(int i=0;i<p.length;i++) 
336          {
337            if(!infoEmbryo.hasProperty(p[i])) 
338              {
339            infoEmbryo.addProperty(p[i]);
340              }
341          }
342        
343        // -1 should be used to denote a missing default property but
344        // for robustness reasons any value below zero is discarded.
345        // Not doing so would let Classpath fail where the JDK succeeds.
346        if(explicit.defaultProperty > -1) 
347          {
348            infoEmbryo.setDefaultPropertyName(p[explicit.defaultProperty].getName());
349          }
350          }
351        EventSetDescriptor[] e = explicit.explicitEventSetDescriptors;
352        if(e!=null) 
353          {
354        for(int i=0;i<e.length;i++) 
355          {
356            if(!infoEmbryo.hasEvent(e[i])) 
357              {
358            infoEmbryo.addEvent(e[i]);
359              }
360          }
361        
362        // -1 should be used to denote a missing default event but
363        // for robustness reasons any value below zero is discarded.
364        // Not doing so would let Classpath fail where the JDK succeeds.
365        if(explicit.defaultEvent > -1) 
366          {
367            infoEmbryo.setDefaultEventName(e[explicit.defaultEvent].getName());
368          }
369          }
370        MethodDescriptor[] m = explicit.explicitMethodDescriptors;
371        if(m!=null) 
372          {
373        for(int i=0;i<m.length;i++) 
374          {
375            if(!infoEmbryo.hasMethod(m[i])) 
376              {
377            infoEmbryo.addMethod(m[i]);
378              }
379          }
380          }
381    
382        infoEmbryo.setAdditionalBeanInfo(explicit.explicitBeanInfo);
383        infoEmbryo.setIcons(explicit.im);
384        
385      }
386      
387      /** 
388       * Get the BeanInfo for class <CODE>beanClass</CODE>,
389       * first by looking for explicit information, next by
390       * using standard design patterns to determine
391       * information about the class.  It crawls up the
392       * inheritance tree until it hits <CODE>topClass</CODE>.
393       *
394       * @param beanClass the Bean class.
395       * @param stopClass the class to stop at.
396       * @return the BeanInfo object representing the class.
397       */
398      public static BeanInfo getBeanInfo(Class<?> beanClass, Class<?> stopClass) 
399        throws IntrospectionException 
400      {
401        ExplicitInfo explicit = new ExplicitInfo(beanClass, stopClass);
402    
403        IntrospectionIncubator ii = new IntrospectionIncubator();
404        ii.setPropertyStopClass(explicit.propertyStopClass);
405        ii.setEventStopClass(explicit.eventStopClass);
406        ii.setMethodStopClass(explicit.methodStopClass);
407        ii.addMethods(beanClass.getMethods());
408        
409        BeanInfoEmbryo currentInfo = ii.getBeanInfoEmbryo();
410        
411        merge(currentInfo, explicit);
412        
413        //  Sets the info's BeanDescriptor to the one we extracted from the
414        // explicit BeanInfo instance(s) if they contained one. Otherwise we
415        // create the BeanDescriptor from scratch.
416        // Note: We do not create a copy the retrieved BeanDescriptor which will allow
417        // the user to modify the instance while it is cached. However this is how
418        // the RI does it.
419        currentInfo.setBeanDescriptor(
420            (explicit.explicitBeanDescriptor == null ? 
421                new BeanDescriptor(beanClass, null) :
422                explicit.explicitBeanDescriptor));    
423        return currentInfo.getBeanInfo();
424      }
425      
426      /** 
427       * Get the search path for BeanInfo classes.
428       *
429       * @return the BeanInfo search path.
430       */
431      public static String[] getBeanInfoSearchPath() 
432      {
433        return beanInfoSearchPath;
434      }
435      
436      /** 
437       * Set the search path for BeanInfo classes.
438       * @param beanInfoSearchPath the new BeanInfo search
439       *        path.
440       */
441      public static void setBeanInfoSearchPath(String[] beanInfoSearchPath) 
442      {
443        Introspector.beanInfoSearchPath = beanInfoSearchPath;
444      }
445      
446      /** 
447       * A helper method to convert a name to standard Java
448       * naming conventions: anything with two capitals as the
449       * first two letters remains the same, otherwise the
450       * first letter is decapitalized.  URL = URL, I = i,
451       * MyMethod = myMethod.
452       *
453       * @param name the name to decapitalize.
454       * @return the decapitalized name.
455       */
456      public static String decapitalize(String name) 
457      {
458        try 
459          {
460          if(!Character.isUpperCase(name.charAt(0))) 
461            {
462              return name;
463            } 
464          else 
465            {
466            try 
467              {
468              if(Character.isUpperCase(name.charAt(1))) 
469                {
470                  return name;
471                } 
472              else 
473                {
474                  char[] c = name.toCharArray();
475                  c[0] = Character.toLowerCase(c[0]);
476                  return new String(c);
477                }
478              } 
479            catch(StringIndexOutOfBoundsException E) 
480              {
481                char[] c = new char[1];
482                c[0] = Character.toLowerCase(name.charAt(0));
483                return new String(c);
484              }
485            }
486          } 
487        catch(StringIndexOutOfBoundsException E) 
488          {
489            return name;
490          } 
491        catch(NullPointerException E) 
492          {
493            return null;
494          }
495      }
496    
497      static BeanInfo copyBeanInfo(BeanInfo b) 
498      {
499        java.awt.Image[] icons = new java.awt.Image[4];
500        for(int i=1;i<=4;i++) 
501          {
502            icons[i-1] = b.getIcon(i);
503          }
504    
505        return new ExplicitBeanInfo(b.getBeanDescriptor(),
506                                    b.getAdditionalBeanInfo(),
507                                    b.getPropertyDescriptors(),
508                                    b.getDefaultPropertyIndex(),
509                                    b.getEventSetDescriptors(),
510                                    b.getDefaultEventIndex(),
511                                    b.getMethodDescriptors(),
512                                    icons);
513      }
514    }
515    
516    class ExplicitInfo 
517    {
518      BeanDescriptor explicitBeanDescriptor;
519      BeanInfo[] explicitBeanInfo;
520      
521      PropertyDescriptor[] explicitPropertyDescriptors;
522      EventSetDescriptor[] explicitEventSetDescriptors;
523      MethodDescriptor[] explicitMethodDescriptors;
524      
525      int defaultProperty;
526      int defaultEvent;
527      
528      java.awt.Image[] im = new java.awt.Image[4];
529      
530      Class propertyStopClass;
531      Class eventStopClass;
532      Class methodStopClass;
533    
534      static Hashtable explicitBeanInfos = new Hashtable();
535      static Vector emptyBeanInfos = new Vector();
536    
537      ExplicitInfo(Class beanClass, Class stopClass) 
538      {
539        while(beanClass != null && !beanClass.equals(stopClass)) 
540          {
541    
542            BeanInfo explicit = findExplicitBeanInfo(beanClass);
543            
544    
545            if(explicit != null) 
546              {
547    
548                if(explicitBeanDescriptor == null) 
549                  {
550                    explicitBeanDescriptor = explicit.getBeanDescriptor();
551                  }
552    
553                if(explicitBeanInfo == null) 
554                  {
555                    explicitBeanInfo = explicit.getAdditionalBeanInfo();
556                  }
557    
558                if(explicitPropertyDescriptors == null) 
559                  {
560                    if(explicit.getPropertyDescriptors() != null) 
561                      {
562                        explicitPropertyDescriptors = explicit.getPropertyDescriptors();
563                        defaultProperty = explicit.getDefaultPropertyIndex();
564                        propertyStopClass = beanClass;
565                      }
566                  }
567    
568                if(explicitEventSetDescriptors == null) 
569                  {
570                    if(explicit.getEventSetDescriptors() != null) 
571                      {
572                        explicitEventSetDescriptors = explicit.getEventSetDescriptors();
573                        defaultEvent = explicit.getDefaultEventIndex();
574                        eventStopClass = beanClass;
575                      }
576                  }
577    
578                if(explicitMethodDescriptors == null) 
579                  {
580                    if(explicit.getMethodDescriptors() != null) 
581                      {
582                        explicitMethodDescriptors = explicit.getMethodDescriptors();
583                        methodStopClass = beanClass;
584                      }
585                  }
586    
587                if(im[0] == null && im[1] == null 
588                   && im[2] == null && im[3] == null) 
589                  {
590                    im[0] = explicit.getIcon(0);
591                    im[1] = explicit.getIcon(1);
592                    im[2] = explicit.getIcon(2);
593                    im[3] = explicit.getIcon(3);
594                  }
595              }
596            beanClass = beanClass.getSuperclass();
597          }
598    
599        if(propertyStopClass == null) 
600          {
601            propertyStopClass = stopClass;
602          }
603    
604        if(eventStopClass == null) 
605          {
606            eventStopClass = stopClass;
607          }
608    
609        if(methodStopClass == null) 
610          {
611            methodStopClass = stopClass;
612          }
613      }
614      
615      /** Throws away all cached data and makes sure we re-instantiate things
616        * like BeanDescriptors again.
617        */
618      static void flushCaches() {
619            explicitBeanInfos.clear();
620            emptyBeanInfos.clear();
621      }
622      
623      static BeanInfo findExplicitBeanInfo(Class beanClass) 
624      {
625        BeanInfo retval = (BeanInfo)explicitBeanInfos.get(beanClass);
626        if(retval != null) 
627          {
628            return retval;
629          } 
630        else if(emptyBeanInfos.indexOf(beanClass) != -1) 
631          {
632            return null;
633          } 
634        else 
635          {
636            retval = reallyFindExplicitBeanInfo(beanClass);
637            if(retval != null) 
638              {
639                explicitBeanInfos.put(beanClass,retval);
640              } 
641            else 
642              {
643                emptyBeanInfos.addElement(beanClass);
644              }
645            return retval;
646          }
647      }
648      
649      static BeanInfo reallyFindExplicitBeanInfo(Class beanClass) 
650      {
651        ClassLoader beanClassLoader = beanClass.getClassLoader();
652        BeanInfo beanInfo;
653    
654        beanInfo = getBeanInfo(beanClassLoader, beanClass.getName() + "BeanInfo");
655        if (beanInfo == null)
656          {
657            String newName;
658            newName = ClassHelper.getTruncatedClassName(beanClass) + "BeanInfo";
659    
660            for(int i = 0; i < Introspector.beanInfoSearchPath.length; i++) 
661              {
662                if (Introspector.beanInfoSearchPath[i].equals("")) 
663                  beanInfo = getBeanInfo(beanClassLoader, newName);
664                else 
665                  beanInfo = getBeanInfo(beanClassLoader,
666                                         Introspector.beanInfoSearchPath[i] + "."
667                                         + newName);
668    
669                    // Returns the beanInfo if it exists and the described class matches
670                    // the one we searched.
671                if (beanInfo != null && beanInfo.getBeanDescriptor() != null &&
672                            beanInfo.getBeanDescriptor().getBeanClass() == beanClass)
673    
674                  return beanInfo;
675              }
676          }
677    
678        return beanInfo;
679      }
680    
681      /**
682       * Returns an instance of the given class name when it can be loaded
683       * through the given class loader, or null otherwise.
684       */
685      private static BeanInfo getBeanInfo(ClassLoader cl, String infoName)
686      {
687        try
688          {
689            return (BeanInfo) Class.forName(infoName, true, cl).newInstance();
690          }
691        catch (ClassNotFoundException cnfe)
692          {
693            return null;
694          }
695        catch (IllegalAccessException iae)
696          {
697            return null;
698          }
699        catch (InstantiationException ie)
700          {
701            return null;
702          }
703      }
704      
705    }