OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [java/] [beans/] [Introspector.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* java.beans.Introspector
2
   Copyright (C) 1998, 2002, 2003 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package java.beans;
40
 
41
import gnu.java.beans.BeanInfoEmbryo;
42
import gnu.java.beans.ExplicitBeanInfo;
43
import gnu.java.beans.IntrospectionIncubator;
44
import gnu.java.lang.ClassHelper;
45
 
46
import java.util.Hashtable;
47
import java.util.Vector;
48
 
49
/**
50
 * Introspector is the class that does the bulk of the
51
 * design-time work in Java Beans.  Every class must have
52
 * a BeanInfo in order for an RAD tool to use it; but, as
53
 * promised, you don't have to write the BeanInfo class
54
 * yourself if you don't want to.  All you have to do is
55
 * call getBeanInfo() in the Introspector and it will use
56
 * standard JavaBeans-defined method signatures to
57
 * determine the information about your class.<P>
58
 *
59
 * Don't worry about it too much, though: you can provide
60
 * JavaBeans with as much customized information as you
61
 * want, or as little as you want, using the BeanInfo
62
 * interface (see BeanInfo for details).<P>
63
 *
64
 * <STRONG>Order of Operations</STRONG><P>
65
 *
66
 * When you call getBeanInfo(class c), the Introspector
67
 * first searches for BeanInfo class to see if you
68
 * provided any explicit information.  It searches for a
69
 * class named &lt;bean class name&gt;BeanInfo in different
70
 * packages, first searching the bean class's package
71
 * and then moving on to search the beanInfoSearchPath.<P>
72
 *
73
 * If it does not find a BeanInfo class, it acts as though
74
 * it had found a BeanInfo class returning null from all
75
 * methods (meaning it should discover everything through
76
 * Introspection).  If it does, then it takes the
77
 * information it finds in the BeanInfo class to be
78
 * canonical (that is, the information speaks for its
79
 * class as well as all superclasses).<P>
80
 *
81
 * When it has introspected the class, calls
82
 * getBeanInfo(c.getSuperclass) and adds that information
83
 * to the information it has, not adding to any information
84
 * it already has that is canonical.<P>
85
 *
86
 * <STRONG>Introspection Design Patterns</STRONG><P>
87
 *
88
 * When the Introspector goes in to read the class, it
89
 * follows a well-defined order in order to not leave any
90
 * methods unaccounted for.  Its job is to step over all
91
 * of the public methods in a class and determine whether
92
 * they are part of a property, an event, or a method (in
93
 * that order).
94
 *
95
 *
96
 * <STRONG>Properties:</STRONG><P>
97
 *
98
 * <OL>
99
 * <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 beanInfoCache = new Hashtable();
186
 
187
  private Introspector() {}
188
 
189
  /**
190
   * Get the BeanInfo for class <CODE>beanClass</CODE>,
191
   * first by looking for explicit information, next by
192
   * using standard design patterns to determine
193
   * information about the class.
194
   *
195
   * @param beanClass the class to get BeanInfo about.
196
   * @return the BeanInfo object representing the class.
197
   */
198
  public static BeanInfo getBeanInfo(Class beanClass)
199
    throws IntrospectionException
200
  {
201
    BeanInfo cachedInfo;
202
    synchronized(beanClass)
203
      {
204
        cachedInfo = (BeanInfo)beanInfoCache.get(beanClass);
205
        if(cachedInfo != null)
206
          {
207
            return cachedInfo;
208
          }
209
        cachedInfo = getBeanInfo(beanClass,null);
210
        beanInfoCache.put(beanClass,cachedInfo);
211
        return cachedInfo;
212
      }
213
  }
214
 
215
  /**
216
   * Flush all of the Introspector's internal caches.
217
   *
218
   * @since 1.2
219
   */
220
  public static void flushCaches()
221
  {
222
    beanInfoCache.clear();
223
 
224
        // Clears all the intermediate ExplicitInfo instances which
225
        // have been created.
226
        // This makes sure we have to retrieve stuff like BeanDescriptors
227
        // again. (Remember that FeatureDescriptor can be modified by the user.)
228
        ExplicitInfo.flushCaches();
229
  }
230
 
231
  /**
232
   * Flush the Introspector's internal cached information for a given
233
   * class.
234
   *
235
   * @param clz the class to be flushed.
236
   * @throws NullPointerException if clz is null.
237
   * @since 1.2
238
   */
239
  public static void flushFromCaches(Class clz)
240
  {
241
    synchronized (clz)
242
      {
243
        beanInfoCache.remove(clz);
244
      }
245
  }
246
 
247
  /**
248
   * Get the BeanInfo for class <CODE>beanClass</CODE>,
249
   * first by looking for explicit information, next by
250
   * using standard design patterns to determine
251
   * information about the class.  It crawls up the
252
   * inheritance tree until it hits <CODE>topClass</CODE>.
253
   *
254
   * @param beanClass the Bean class.
255
   * @param stopClass the class to stop at.
256
   * @return the BeanInfo object representing the class.
257
   */
258
  public static BeanInfo getBeanInfo(Class beanClass, Class stopClass)
259
    throws IntrospectionException
260
  {
261
    ExplicitInfo explicit = new ExplicitInfo(beanClass, stopClass);
262
 
263
    IntrospectionIncubator ii = new IntrospectionIncubator();
264
    ii.setPropertyStopClass(explicit.propertyStopClass);
265
    ii.setEventStopClass(explicit.eventStopClass);
266
    ii.setMethodStopClass(explicit.methodStopClass);
267
    ii.addMethods(beanClass.getMethods());
268
 
269
    BeanInfoEmbryo currentInfo = ii.getBeanInfoEmbryo();
270
    PropertyDescriptor[] p = explicit.explicitPropertyDescriptors;
271
    if(p!=null)
272
      {
273
        for(int i=0;i<p.length;i++)
274
          {
275
            if(!currentInfo.hasProperty(p[i]))
276
              {
277
                currentInfo.addProperty(p[i]);
278
              }
279
          }
280
        if(explicit.defaultProperty != -1)
281
          {
282
            currentInfo.setDefaultPropertyName(p[explicit.defaultProperty].getName());
283
          }
284
      }
285
    EventSetDescriptor[] e = explicit.explicitEventSetDescriptors;
286
    if(e!=null)
287
      {
288
        for(int i=0;i<e.length;i++)
289
          {
290
            if(!currentInfo.hasEvent(e[i]))
291
              {
292
                currentInfo.addEvent(e[i]);
293
              }
294
          }
295
        if(explicit.defaultEvent != -1)
296
          {
297
            currentInfo.setDefaultEventName(e[explicit.defaultEvent].getName());
298
          }
299
      }
300
    MethodDescriptor[] m = explicit.explicitMethodDescriptors;
301
    if(m!=null)
302
      {
303
        for(int i=0;i<m.length;i++)
304
          {
305
            if(!currentInfo.hasMethod(m[i]))
306
              {
307
                currentInfo.addMethod(m[i]);
308
              }
309
          }
310
      }
311
 
312
        // Sets the info's BeanDescriptor to the one we extracted from the
313
        // explicit BeanInfo instance(s) if they contained one. Otherwise we
314
        // create the BeanDescriptor from scratch.
315
        // Note: We do not create a copy the retrieved BeanDescriptor which will allow
316
        // the user to modify the instance while it is cached. However this is how
317
        // the RI does it.
318
        currentInfo.setBeanDescriptor(
319
                (explicit.explicitBeanDescriptor == null ?
320
                        new BeanDescriptor(beanClass, null) :
321
                        explicit.explicitBeanDescriptor));
322
 
323
    currentInfo.setAdditionalBeanInfo(explicit.explicitBeanInfo);
324
    currentInfo.setIcons(explicit.im);
325
 
326
    return currentInfo.getBeanInfo();
327
  }
328
 
329
  /**
330
   * Get the search path for BeanInfo classes.
331
   *
332
   * @return the BeanInfo search path.
333
   */
334
  public static String[] getBeanInfoSearchPath()
335
  {
336
    return beanInfoSearchPath;
337
  }
338
 
339
  /**
340
   * Set the search path for BeanInfo classes.
341
   * @param beanInfoSearchPath the new BeanInfo search
342
   *        path.
343
   */
344
  public static void setBeanInfoSearchPath(String[] beanInfoSearchPath)
345
  {
346
    Introspector.beanInfoSearchPath = beanInfoSearchPath;
347
  }
348
 
349
  /**
350
   * A helper method to convert a name to standard Java
351
   * naming conventions: anything with two capitals as the
352
   * first two letters remains the same, otherwise the
353
   * first letter is decapitalized.  URL = URL, I = i,
354
   * MyMethod = myMethod.
355
   *
356
   * @param name the name to decapitalize.
357
   * @return the decapitalized name.
358
   */
359
  public static String decapitalize(String name)
360
  {
361
    try
362
      {
363
      if(!Character.isUpperCase(name.charAt(0)))
364
        {
365
          return name;
366
        }
367
      else
368
        {
369
        try
370
          {
371
          if(Character.isUpperCase(name.charAt(1)))
372
            {
373
              return name;
374
            }
375
          else
376
            {
377
              char[] c = name.toCharArray();
378
              c[0] = Character.toLowerCase(c[0]);
379
              return new String(c);
380
            }
381
          }
382
        catch(StringIndexOutOfBoundsException E)
383
          {
384
            char[] c = new char[1];
385
            c[0] = Character.toLowerCase(name.charAt(0));
386
            return new String(c);
387
          }
388
        }
389
      }
390
    catch(StringIndexOutOfBoundsException E)
391
      {
392
        return name;
393
      }
394
    catch(NullPointerException E)
395
      {
396
        return null;
397
      }
398
  }
399
 
400
  static BeanInfo copyBeanInfo(BeanInfo b)
401
  {
402
    java.awt.Image[] icons = new java.awt.Image[4];
403
    for(int i=1;i<=4;i++)
404
      {
405
        icons[i-1] = b.getIcon(i);
406
      }
407
 
408
    return new ExplicitBeanInfo(b.getBeanDescriptor(),
409
                                b.getAdditionalBeanInfo(),
410
                                b.getPropertyDescriptors(),
411
                                b.getDefaultPropertyIndex(),
412
                                b.getEventSetDescriptors(),
413
                                b.getDefaultEventIndex(),
414
                                b.getMethodDescriptors(),
415
                                icons);
416
  }
417
}
418
 
419
class ExplicitInfo
420
{
421
  BeanDescriptor explicitBeanDescriptor;
422
  BeanInfo[] explicitBeanInfo;
423
 
424
  PropertyDescriptor[] explicitPropertyDescriptors;
425
  EventSetDescriptor[] explicitEventSetDescriptors;
426
  MethodDescriptor[] explicitMethodDescriptors;
427
 
428
  int defaultProperty;
429
  int defaultEvent;
430
 
431
  java.awt.Image[] im = new java.awt.Image[4];
432
 
433
  Class propertyStopClass;
434
  Class eventStopClass;
435
  Class methodStopClass;
436
 
437
  static Hashtable explicitBeanInfos = new Hashtable();
438
  static Vector emptyBeanInfos = new Vector();
439
 
440
  ExplicitInfo(Class beanClass, Class stopClass)
441
  {
442
    while(beanClass != null && !beanClass.equals(stopClass))
443
      {
444
 
445
        BeanInfo explicit = findExplicitBeanInfo(beanClass);
446
 
447
 
448
        if(explicit != null)
449
          {
450
 
451
            if(explicitBeanDescriptor == null)
452
              {
453
                explicitBeanDescriptor = explicit.getBeanDescriptor();
454
              }
455
 
456
            if(explicitBeanInfo == null)
457
              {
458
                explicitBeanInfo = explicit.getAdditionalBeanInfo();
459
              }
460
 
461
            if(explicitPropertyDescriptors == null)
462
              {
463
                if(explicit.getPropertyDescriptors() != null)
464
                  {
465
                    explicitPropertyDescriptors = explicit.getPropertyDescriptors();
466
                    defaultProperty = explicit.getDefaultPropertyIndex();
467
                    propertyStopClass = beanClass;
468
                  }
469
              }
470
 
471
            if(explicitEventSetDescriptors == null)
472
              {
473
                if(explicit.getEventSetDescriptors() != null)
474
                  {
475
                    explicitEventSetDescriptors = explicit.getEventSetDescriptors();
476
                    defaultEvent = explicit.getDefaultEventIndex();
477
                    eventStopClass = beanClass;
478
                  }
479
              }
480
 
481
            if(explicitMethodDescriptors == null)
482
              {
483
                if(explicit.getMethodDescriptors() != null)
484
                  {
485
                    explicitMethodDescriptors = explicit.getMethodDescriptors();
486
                    methodStopClass = beanClass;
487
                  }
488
              }
489
 
490
            if(im[0] == null && im[1] == null
491
               && im[2] == null && im[3] == null)
492
              {
493
                im[0] = explicit.getIcon(0);
494
                im[1] = explicit.getIcon(1);
495
                im[2] = explicit.getIcon(2);
496
                im[3] = explicit.getIcon(3);
497
              }
498
          }
499
        beanClass = beanClass.getSuperclass();
500
      }
501
 
502
    if(propertyStopClass == null)
503
      {
504
        propertyStopClass = stopClass;
505
      }
506
 
507
    if(eventStopClass == null)
508
      {
509
        eventStopClass = stopClass;
510
      }
511
 
512
    if(methodStopClass == null)
513
      {
514
        methodStopClass = stopClass;
515
      }
516
  }
517
 
518
  /** Throws away all cached data and makes sure we re-instantiate things
519
    * like BeanDescriptors again.
520
    */
521
  static void flushCaches() {
522
        explicitBeanInfos.clear();
523
        emptyBeanInfos.clear();
524
  }
525
 
526
  static BeanInfo findExplicitBeanInfo(Class beanClass)
527
  {
528
    BeanInfo retval = (BeanInfo)explicitBeanInfos.get(beanClass);
529
    if(retval != null)
530
      {
531
        return retval;
532
      }
533
    else if(emptyBeanInfos.indexOf(beanClass) != -1)
534
      {
535
        return null;
536
      }
537
    else
538
      {
539
        retval = reallyFindExplicitBeanInfo(beanClass);
540
        if(retval != null)
541
          {
542
            explicitBeanInfos.put(beanClass,retval);
543
          }
544
        else
545
          {
546
            emptyBeanInfos.addElement(beanClass);
547
          }
548
        return retval;
549
      }
550
  }
551
 
552
  static BeanInfo reallyFindExplicitBeanInfo(Class beanClass)
553
  {
554
    ClassLoader beanClassLoader = beanClass.getClassLoader();
555
    BeanInfo beanInfo;
556
 
557
    beanInfo = getBeanInfo(beanClassLoader, beanClass.getName() + "BeanInfo");
558
    if (beanInfo == null)
559
      {
560
        String newName;
561
        newName = ClassHelper.getTruncatedClassName(beanClass) + "BeanInfo";
562
 
563
        for(int i = 0; i < Introspector.beanInfoSearchPath.length; i++)
564
          {
565
            if (Introspector.beanInfoSearchPath[i].equals(""))
566
              beanInfo = getBeanInfo(beanClassLoader, newName);
567
            else
568
              beanInfo = getBeanInfo(beanClassLoader,
569
                                     Introspector.beanInfoSearchPath[i] + "."
570
                                     + newName);
571
 
572
                // Returns the beanInfo if it exists and the described class matches
573
                // the one we searched.
574
            if (beanInfo != null && beanInfo.getBeanDescriptor() != null &&
575
                        beanInfo.getBeanDescriptor().getBeanClass() == beanClass)
576
 
577
              return beanInfo;
578
          }
579
      }
580
 
581
    return beanInfo;
582
  }
583
 
584
  /**
585
   * Returns an instance of the given class name when it can be loaded
586
   * through the given class loader, or null otherwise.
587
   */
588
  private static BeanInfo getBeanInfo(ClassLoader cl, String infoName)
589
  {
590
    try
591
      {
592
        return (BeanInfo) Class.forName(infoName, true, cl).newInstance();
593
      }
594
    catch (ClassNotFoundException cnfe)
595
      {
596
        return null;
597
      }
598
    catch (IllegalAccessException iae)
599
      {
600
        return null;
601
      }
602
    catch (InstantiationException ie)
603
      {
604
        return null;
605
      }
606
  }
607
 
608
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.