KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > el > BeanInfoManager


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 1999 The Apache Software Foundation. All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in
16  * the documentation and/or other materials provided with the
17  * distribution.
18  *
19  * 3. The end-user documentation included with the redistribution, if
20  * any, must include the following acknowlegement:
21  * "This product includes software developed by the
22  * Apache Software Foundation (http://www.apache.org/)."
23  * Alternately, this acknowlegement may appear in the software itself,
24  * if and wherever such third-party acknowlegements normally appear.
25  *
26  * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
27  * Foundation" must not be used to endorse or promote products derived
28  * from this software without prior written permission. For written
29  * permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache"
32  * nor may "Apache" appear in their names without prior written
33  * permission of the Apache Group.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation. For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  */

55
56 package org.apache.commons.el;
57
58 import java.beans.BeanInfo JavaDoc;
59 import java.beans.EventSetDescriptor JavaDoc;
60 import java.beans.IndexedPropertyDescriptor JavaDoc;
61 import java.beans.IntrospectionException JavaDoc;
62 import java.beans.Introspector JavaDoc;
63 import java.beans.PropertyDescriptor JavaDoc;
64 import java.lang.reflect.Method JavaDoc;
65 import java.lang.reflect.Modifier JavaDoc;
66 import java.text.MessageFormat JavaDoc;
67 import java.util.HashMap JavaDoc;
68 import java.util.Map JavaDoc;
69 import javax.servlet.jsp.el.ELException JavaDoc;
70
71 /**
72  *
73  * <p>Manages the BeanInfo for one class - contains the BeanInfo, and
74  * also a mapping from property name to BeanInfoProperty. There are
75  * also static methods for accessing the BeanInfoManager for a class -
76  * those mappings are cached permanently so that once the
77  * BeanInfoManager is calculated, it doesn't have to be calculated
78  * again.
79  *
80  * @author Nathan Abramson - Art Technology Group
81  * @version $Change: 181181 $$DateTime: 2001/06/26 09:55:09 $$Author: luehe $
82  **/

83
84 public class BeanInfoManager
85 {
86   //-------------------------------------
87
// Properties
88
//-------------------------------------
89
// property beanClass
90

91   Class JavaDoc mBeanClass;
92   public Class JavaDoc getBeanClass ()
93   { return mBeanClass; }
94
95   //-------------------------------------
96
// Member variables
97
//-------------------------------------
98

99   // The BeanInfo
100
BeanInfo JavaDoc mBeanInfo;
101
102   // Mapping from property name to BeanInfoProperty
103
Map JavaDoc mPropertyByName;
104
105   // Mapping from property name to BeanInfoIndexedProperty
106
Map JavaDoc mIndexedPropertyByName;
107
108   // Mapping from event set name to event set descriptor
109
Map JavaDoc mEventSetByName;
110
111   // Flag if this is initialized
112
boolean mInitialized;
113
114   // The global mapping from class to BeanInfoManager
115
static Map JavaDoc mBeanInfoManagerByClass = new HashMap JavaDoc ();
116
117   //-------------------------------------
118
/**
119    *
120    * Constructor
121    **/

122   BeanInfoManager (Class JavaDoc pBeanClass)
123   {
124     mBeanClass = pBeanClass;
125   }
126
127   //-------------------------------------
128
/**
129    *
130    * Returns the BeanInfoManager for the specified class
131    **/

132   public static BeanInfoManager getBeanInfoManager (Class JavaDoc pClass)
133   {
134     BeanInfoManager ret = (BeanInfoManager)
135       mBeanInfoManagerByClass.get (pClass);
136     if (ret == null) {
137       ret = createBeanInfoManager (pClass);
138     }
139     return ret;
140   }
141
142   //-------------------------------------
143
/**
144    *
145    * Creates and registers the BeanInfoManager for the given class if
146    * it isn't already registered.
147    **/

148   static synchronized BeanInfoManager createBeanInfoManager (Class JavaDoc pClass)
149   {
150     // Because this method is synchronized statically, the
151
// BeanInfoManager is not initialized at this time (otherwise it
152
// could end up being a bottleneck for the entire system). It is
153
// put into the map in an uninitialized state. The first time
154
// someone tries to use it, it will be initialized (with proper
155
// synchronizations in place to make sure it is only initialized
156
// once).
157

158     BeanInfoManager ret = (BeanInfoManager)
159       mBeanInfoManagerByClass.get (pClass);
160     if (ret == null) {
161       ret = new BeanInfoManager (pClass);
162       mBeanInfoManagerByClass.put (pClass, ret);
163     }
164     return ret;
165   }
166
167   //-------------------------------------
168
/**
169    *
170    * Returns the BeanInfoProperty for the specified property in the
171    * given class, or null if not found.
172    **/

173   public static BeanInfoProperty getBeanInfoProperty
174     (Class JavaDoc pClass,
175      String JavaDoc pPropertyName,
176      Logger pLogger)
177     throws ELException JavaDoc
178   {
179     return getBeanInfoManager (pClass).getProperty (pPropertyName, pLogger);
180   }
181
182   //-------------------------------------
183
/**
184    *
185    * Returns the BeanInfoIndexedProperty for the specified property in
186    * the given class, or null if not found.
187    **/

188   public static BeanInfoIndexedProperty getBeanInfoIndexedProperty
189     (Class JavaDoc pClass,
190      String JavaDoc pIndexedPropertyName,
191      Logger pLogger)
192     throws ELException JavaDoc
193   {
194     return getBeanInfoManager
195       (pClass).getIndexedProperty (pIndexedPropertyName, pLogger);
196   }
197
198   //-------------------------------------
199
/**
200    *
201    * Makes sure that this class has been initialized, and synchronizes
202    * the initialization if it's required.
203    **/

204   void checkInitialized (Logger pLogger)
205     throws ELException JavaDoc
206   {
207     if (!mInitialized) {
208       synchronized (this) {
209     if (!mInitialized) {
210       initialize (pLogger);
211       mInitialized = true;
212     }
213       }
214     }
215   }
216
217   //-------------------------------------
218
/**
219    *
220    * Initializes by mapping property names to BeanInfoProperties
221    **/

222   void initialize (Logger pLogger)
223     throws ELException JavaDoc
224   {
225     try {
226       mBeanInfo = Introspector.getBeanInfo (mBeanClass);
227
228       mPropertyByName = new HashMap JavaDoc ();
229       mIndexedPropertyByName = new HashMap JavaDoc ();
230       PropertyDescriptor JavaDoc [] pds = mBeanInfo.getPropertyDescriptors ();
231       for (int i = 0; pds != null && i < pds.length; i++) {
232     // Treat as both an indexed property and a normal property
233
PropertyDescriptor JavaDoc pd = pds [i];
234     if (pd instanceof IndexedPropertyDescriptor JavaDoc) {
235       IndexedPropertyDescriptor JavaDoc ipd = (IndexedPropertyDescriptor JavaDoc) pd;
236       Method JavaDoc readMethod = getPublicMethod (ipd.getIndexedReadMethod ());
237       Method JavaDoc writeMethod = getPublicMethod (ipd.getIndexedWriteMethod ());
238       BeanInfoIndexedProperty property = new BeanInfoIndexedProperty
239         (readMethod,
240          writeMethod,
241          ipd);
242
243       mIndexedPropertyByName.put (ipd.getName (), property);
244     }
245
246     Method JavaDoc readMethod = getPublicMethod (pd.getReadMethod ());
247     Method JavaDoc writeMethod = getPublicMethod (pd.getWriteMethod ());
248     BeanInfoProperty property = new BeanInfoProperty
249       (readMethod,
250        writeMethod,
251        pd);
252
253     mPropertyByName.put (pd.getName (), property);
254       }
255
256       mEventSetByName = new HashMap JavaDoc ();
257       EventSetDescriptor JavaDoc [] esds = mBeanInfo.getEventSetDescriptors ();
258       for (int i = 0; esds != null && i < esds.length; i++) {
259     EventSetDescriptor JavaDoc esd = esds [i];
260     mEventSetByName.put (esd.getName (), esd);
261       }
262     }
263     catch (IntrospectionException JavaDoc exc) {
264       if (pLogger.isLoggingWarning ()) {
265     pLogger.logWarning
266       (Constants.EXCEPTION_GETTING_BEANINFO,
267        exc,
268        mBeanClass.getName ());
269       }
270     }
271   }
272
273   //-------------------------------------
274
/**
275    *
276    * Returns the BeanInfo for the class
277    **/

278   BeanInfo JavaDoc getBeanInfo (Logger pLogger)
279     throws ELException JavaDoc
280   {
281     checkInitialized (pLogger);
282     return mBeanInfo;
283   }
284
285   //-------------------------------------
286
/**
287    *
288    * Returns the BeanInfoProperty for the given property name, or null
289    * if not found.
290    **/

291   public BeanInfoProperty getProperty (String JavaDoc pPropertyName,
292                        Logger pLogger)
293     throws ELException JavaDoc
294   {
295     checkInitialized (pLogger);
296     return (BeanInfoProperty) mPropertyByName.get (pPropertyName);
297   }
298
299   //-------------------------------------
300
/**
301    *
302    * Returns the BeanInfoIndexedProperty for the given property name,
303    * or null if not found.
304    **/

305   public BeanInfoIndexedProperty getIndexedProperty
306     (String JavaDoc pIndexedPropertyName,
307      Logger pLogger)
308     throws ELException JavaDoc
309   {
310     checkInitialized (pLogger);
311     return (BeanInfoIndexedProperty)
312       mIndexedPropertyByName.get (pIndexedPropertyName);
313   }
314
315   //-------------------------------------
316
/**
317    *
318    * Returns the EventSetDescriptor for the given event set name, or
319    * null if not found.
320    **/

321   public EventSetDescriptor JavaDoc getEventSet (String JavaDoc pEventSetName,
322                      Logger pLogger)
323     throws ELException JavaDoc
324   {
325     checkInitialized (pLogger);
326     return (EventSetDescriptor JavaDoc) mEventSetByName.get (pEventSetName);
327   }
328
329   //-------------------------------------
330
// Finding the public version of a method - if a PropertyDescriptor
331
// is obtained for a non-public class that implements a public
332
// interface, the read/write methods will be for the class, and
333
// therefore inaccessible. To correct this, a version of the same
334
// method must be found in a superclass or interface.
335
//-------------------------------------
336
/**
337    *
338    * Returns a publicly-accessible version of the given method, by
339    * searching for a public declaring class.
340    **/

341   static Method JavaDoc getPublicMethod (Method JavaDoc pMethod)
342   {
343     if (pMethod == null) {
344       return null;
345     }
346
347     // See if the method is already available from a public class
348
Class JavaDoc cl = pMethod.getDeclaringClass ();
349     if (Modifier.isPublic (cl.getModifiers ())) {
350       return pMethod;
351     }
352
353     // Otherwise, try to find a public class that declares the method
354
Method JavaDoc ret = getPublicMethod (cl, pMethod);
355     if (ret != null) {
356       return ret;
357     }
358     else {
359       return pMethod;
360     }
361   }
362
363   //-------------------------------------
364
/**
365    *
366    * If the given class is public and has a Method that declares the
367    * same name and arguments as the given method, then that method is
368    * returned. Otherwise the superclass and interfaces are searched
369    * recursively.
370    **/

371   static Method JavaDoc getPublicMethod (Class JavaDoc pClass,
372                  Method JavaDoc pMethod)
373   {
374     // See if this is a public class declaring the method
375
if (Modifier.isPublic (pClass.getModifiers ())) {
376       try {
377         Method JavaDoc m;
378         try {
379       m = pClass.getDeclaredMethod (pMethod.getName (),
380                          pMethod.getParameterTypes ());
381         } catch (java.security.AccessControlException JavaDoc ex) {
382       // kludge to accommodate J2EE RI's default settings
383
// TODO: see if we can simply replace
384
// getDeclaredMethod() with getMethod() ...?
385
m = pClass.getMethod(pMethod.getName (),
386                                              pMethod.getParameterTypes ());
387         }
388     if (Modifier.isPublic (m.getModifiers ())) {
389       return m;
390     }
391       }
392       catch (NoSuchMethodException JavaDoc exc) {}
393     }
394
395     // Search the interfaces
396
{
397       Class JavaDoc [] interfaces = pClass.getInterfaces ();
398       if (interfaces != null) {
399     for (int i = 0; i < interfaces.length; i++) {
400       Method JavaDoc m = getPublicMethod (interfaces [i], pMethod);
401       if (m != null) {
402         return m;
403       }
404     }
405       }
406     }
407
408     // Search the superclass
409
{
410       Class JavaDoc superclass = pClass.getSuperclass ();
411       if (superclass != null) {
412     Method JavaDoc m = getPublicMethod (superclass, pMethod);
413     if (m != null) {
414       return m;
415     }
416       }
417     }
418
419     return null;
420   }
421
422   //-------------------------------------
423
}
424
Popular Tags