KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > es > wrapper > ESBeanInfo


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.es.wrapper;
30
31 import java.beans.IntrospectionException JavaDoc;
32 import java.beans.MethodDescriptor JavaDoc;
33 import java.beans.PropertyDescriptor JavaDoc;
34 import java.lang.reflect.Constructor JavaDoc;
35 import java.lang.reflect.Field JavaDoc;
36 import java.lang.reflect.Method JavaDoc;
37 import java.lang.reflect.Modifier JavaDoc;
38 import java.util.ArrayList JavaDoc;
39 import java.util.HashMap JavaDoc;
40 import java.util.Iterator JavaDoc;
41 import java.util.Map JavaDoc;
42     
43 /**
44  * Full analyzed information on the class as a JavaScript object.
45  */

46 public class ESBeanInfo {
47   static String JavaDoc BAD = "bad";
48
49   Class JavaDoc cl;
50   HashMap JavaDoc<String JavaDoc,ArrayList JavaDoc<Method JavaDoc>> _methodMap;
51   HashMap JavaDoc<String JavaDoc,ArrayList JavaDoc<Method JavaDoc>> _staticMethodMap;
52   HashMap JavaDoc propMap;
53   ArrayList JavaDoc nonPkgClasses = new ArrayList JavaDoc();
54   PropertyDescriptor JavaDoc []propertyDescriptors;
55   ESMethodDescriptor iterator;
56
57   ESBeanInfo(Class JavaDoc cl)
58   {
59     this.cl = cl;
60     _methodMap = new HashMap JavaDoc<String JavaDoc,ArrayList JavaDoc<Method JavaDoc>>();
61     _staticMethodMap = new HashMap JavaDoc<String JavaDoc,ArrayList JavaDoc<Method JavaDoc>>();
62     propMap = new HashMap JavaDoc();
63   }
64   
65   void addNonPkgClass(String JavaDoc name)
66   {
67     if (name.indexOf('$') >= 0)
68       return;
69     
70     if (! nonPkgClasses.contains(name))
71       nonPkgClasses.add(name);
72   }
73
74   ArrayList JavaDoc getNonPkgClasses()
75   {
76     return nonPkgClasses;
77   }
78
79   /**
80    * Return the property descriptors for the bean.
81    */

82   public PropertyDescriptor JavaDoc []getPropertyDescriptors()
83   {
84     if (propertyDescriptors == null)
85       propertyDescriptors = propMapToArray(propMap);
86
87     return propertyDescriptors;
88   }
89   
90   private static PropertyDescriptor JavaDoc []propMapToArray(HashMap JavaDoc props)
91   {
92     int count = 0;
93     Iterator JavaDoc i = props.keySet().iterator();
94     while (i.hasNext()) {
95       String JavaDoc key = (String JavaDoc) i.next();
96       Object JavaDoc value = props.get(key);
97
98       if (value != BAD)
99     count++;
100     }
101
102     PropertyDescriptor JavaDoc []descriptors = new PropertyDescriptor JavaDoc[count];
103
104     count = 0;
105     i = props.keySet().iterator();
106     while (i.hasNext()) {
107       String JavaDoc key = (String JavaDoc) i.next();
108       Object JavaDoc value = props.get(key);
109
110       if (value != BAD) {
111     descriptors[count] = (PropertyDescriptor JavaDoc) value;
112     count++;
113       }
114     }
115
116     return descriptors;
117   }
118
119   void addProp(String JavaDoc name, Field JavaDoc field,
120            ESMethodDescriptor getter,
121            ESMethodDescriptor setter,
122            boolean overwrite)
123     throws IntrospectionException JavaDoc
124   {
125     Object JavaDoc value = propMap.get(name);
126
127     if (value instanceof ESPropertyDescriptor &&
128     ! (value instanceof ESIndexedPropertyDescriptor) &&
129     ! (value instanceof NamedPropertyDescriptor)) {
130       ESPropertyDescriptor prop = (ESPropertyDescriptor) value;
131       
132       
133       if (field != null)
134     prop.field = field;
135       if (getter != null)
136     prop.getter = getter;
137       if (setter != null)
138     prop.setter = setter;
139
140       propMap.put(name, prop);
141     } else if (value == null || overwrite) {
142       propMap.put(name, new ESPropertyDescriptor(name, field, getter, setter));
143     } else {
144       propMap.put(name, BAD);
145     }
146   }
147
148   void addProp(String JavaDoc name, Field JavaDoc field, ESMethodDescriptor getter, ESMethodDescriptor setter)
149     throws IntrospectionException JavaDoc
150   {
151     addProp(name, field, getter, setter, false);
152   }
153
154   void addIndexedProp(String JavaDoc name, ESMethodDescriptor getter, ESMethodDescriptor setter, ESMethodDescriptor size,
155               boolean overwrite)
156     throws IntrospectionException JavaDoc
157   {
158     Object JavaDoc value = propMap.get(name);
159
160     if (value instanceof ESIndexedPropertyDescriptor) {
161       ESIndexedPropertyDescriptor prop = (ESIndexedPropertyDescriptor) value;
162       
163       if (getter != null)
164     prop.getter = getter;
165       if (setter != null)
166     prop.setter = setter;
167       if (size != null)
168     prop.size = size;
169
170       propMap.put(name, prop);
171     } else if (value == null || overwrite) {
172       propMap.put(name, new ESIndexedPropertyDescriptor(name, getter, setter,
173                             size));
174     } else
175       propMap.put(name, BAD);
176   }
177
178   void addIndexedProp(String JavaDoc name, ESMethodDescriptor getter, ESMethodDescriptor setter, ESMethodDescriptor size)
179     throws IntrospectionException JavaDoc
180   {
181     addIndexedProp(name, getter, setter, size, false);
182   }
183
184   void addNamedProp(String JavaDoc name,
185             ESMethodDescriptor getter,
186             ESMethodDescriptor setter,
187             ESMethodDescriptor remover,
188             ESMethodDescriptor iterator,
189             boolean overwrite)
190     throws IntrospectionException JavaDoc
191   {
192     Object JavaDoc value = propMap.get(name);
193
194     if (value instanceof NamedPropertyDescriptor) {
195       NamedPropertyDescriptor prop = (NamedPropertyDescriptor) value;
196       
197       if (getter != null)
198     prop.namedGetter = getter;
199       if (setter != null)
200     prop.namedSetter = setter;
201       if (remover != null)
202     prop.namedRemover = remover;
203       if (iterator != null)
204     prop.namedIterator = iterator;
205     } else if (value == null || overwrite) {
206       propMap.put(name, new NamedPropertyDescriptor(name, null, null,
207                             getter, setter,
208                             remover, iterator));
209     } else
210       propMap.put(name, BAD);
211   }
212
213   void addNamedProp(String JavaDoc name, ESMethodDescriptor getter,
214             ESMethodDescriptor setter,
215             ESMethodDescriptor remover,
216             ESMethodDescriptor iterator)
217     throws IntrospectionException JavaDoc
218   {
219     addNamedProp(name, getter, setter, remover, iterator, false);
220   }
221
222   /**
223    * Returns the methods matching the given name.
224    */

225   public ArrayList JavaDoc<Method JavaDoc> getMethods(String JavaDoc name)
226   {
227     return _methodMap.get(name);
228   }
229
230   /**
231    * Returns the static methods matching the given name.
232    */

233   public ArrayList JavaDoc<Method JavaDoc> getStaticMethods(String JavaDoc name)
234   {
235     return _staticMethodMap.get(name);
236   }
237
238   public ArrayList JavaDoc getConstructors()
239   {
240     ArrayList JavaDoc overload = new ArrayList JavaDoc();
241     if (! Modifier.isPublic(cl.getModifiers()))
242       return overload;
243
244     // non-static inner classes have no constructor
245
if (cl.getDeclaringClass() != null &&
246         ! Modifier.isStatic(cl.getModifiers()))
247       return overload;
248     
249     Constructor JavaDoc []constructors = cl.getConstructors();
250     for (int i = 0; i < constructors.length; i++) {
251       if (! Modifier.isPublic(constructors[i].getModifiers()))
252         continue;
253
254       if (Modifier.isPublic(constructors[i].getModifiers()))
255         addConstructor(overload, constructors[i]);
256     }
257
258     return overload;
259   }
260
261   private void addConstructor(ArrayList JavaDoc overload,
262                               Constructor JavaDoc constructor)
263   {
264     int modifiers = constructor.getModifiers();
265
266     if (! Modifier.isPublic(modifiers))
267       return;
268
269     Class JavaDoc []params = constructor.getParameterTypes();
270     for (int i = 0; i < params.length; i++) {
271       if (! Modifier.isPublic(params[i].getModifiers()))
272         return;
273       if (! params[i].isPrimitive() && ! params[i].isArray() &&
274           params[i].getName().indexOf('.') < 0)
275         addNonPkgClass(params[i].getName());
276     }
277     int length = params.length;
278
279     Object JavaDoc oldConstructor;
280     if (length < overload.size() &&
281         (oldConstructor = overload.get(length)) != null) {
282       overload.set(length, BAD);
283     }
284     else {
285       while (overload.size() <= length)
286     overload.add(null);
287       overload.set(length, constructor);
288     }
289   }
290
291   /**
292    * Create a new method descriptor.
293    */

294   ESMethodDescriptor createMethodDescriptor(Method JavaDoc method, boolean overwrite)
295     throws IntrospectionException JavaDoc
296   {
297     boolean staticVirtual = isStaticVirtual(cl, method);
298     
299     return new ESMethodDescriptor(method, overwrite, staticVirtual);
300   }
301
302   /**
303    * Returns true if this is a static virtual method.
304    * Static virtual methods are used by FooEcmaWrap classes add new methods
305    * to a class.
306    *
307    * <p>The method is always static and the first argument has the class
308    * of the overwriting class.
309    */

310   private static boolean isStaticVirtual(Class JavaDoc cl, Method JavaDoc method)
311   {
312     int modifiers = method.getModifiers();
313
314     if (! Modifier.isStatic(modifiers))
315       return false;
316
317     if (method.getName().equals("<init>"))
318       return false;
319
320     if (! method.getDeclaringClass().getName().endsWith("EcmaWrap"))
321       return false;
322
323     Class JavaDoc []params = method.getParameterTypes();
324
325     boolean result = params.length > 0 && params[0].equals(cl);
326
327     return result;
328   }
329
330   /**
331    * Adds a new method to the bean info, changing the overwrite property.
332    *
333    * @param oldMd the old method descriptor.
334    * @param boolean true if overwritable.
335    */

336   void addMethod(MethodDescriptor JavaDoc oldMd, boolean overwrite)
337     throws IntrospectionException JavaDoc
338   {
339     ESMethodDescriptor md = createMethodDescriptor(oldMd.getMethod(),
340                            overwrite);
341     md.setName(oldMd.getName());
342     addMethod(_methodMap, md, false);
343     addMethod(_staticMethodMap, md, true);
344   }
345
346   /**
347    * Adds a new method to the bean info.
348    *
349    * @param me the method descriptor.
350    */

351   void addMethod(ESMethodDescriptor md)
352     throws IntrospectionException JavaDoc
353   {
354     addMethod(_methodMap, md, false);
355     addMethod(_staticMethodMap, md, true);
356   }
357
358   void addMethods(ESBeanInfo info)
359     throws IntrospectionException JavaDoc
360   {
361     if (info.iterator != null) {
362       iterator = info.iterator;
363     }
364     addMap(_methodMap, info._methodMap, false);
365     addMap(_staticMethodMap, info._staticMethodMap, true);
366   }
367
368   /**
369    * Merges two method maps together to produce a new map.
370    */

371   private void addMap(HashMap JavaDoc newMap, HashMap JavaDoc oldMap, boolean isStatic)
372   {
373     Iterator JavaDoc i = oldMap.entrySet().iterator();
374     
375     while (i.hasNext()) {
376       Map.Entry JavaDoc entry = (Map.Entry JavaDoc) i.next();
377       ArrayList JavaDoc overload = (ArrayList JavaDoc) entry.getValue();
378
379       for (int j = 0; j < overload.size(); j++) {
380         ESMethodDescriptor []mds = (ESMethodDescriptor []) overload.get(j);
381
382         if (mds != null) {
383           for (int k = 0; k < mds.length; k++)
384             addMethod(newMap, mds[k], isStatic);
385         }
386       }
387     }
388   }
389
390   /**
391    * Adds a method to the method map.
392    *
393    * @param map the method map to modify.
394    * @param md the method descriptor of the new method.
395    * @param isStatic true if this is a static method.
396    */

397   private void addMethod(HashMap JavaDoc map,
398                          ESMethodDescriptor md, boolean isStatic)
399   {
400     Method JavaDoc method = md.getMethod();
401     int modifiers = method.getModifiers();
402     boolean staticVirtual = md.isStaticVirtual();
403     boolean overwrite = md.isOverwrite();
404
405     if (! Modifier.isPublic(modifiers))
406       return;
407     if (isStatic && ! md.isStatic())
408       return;
409
410     Class JavaDoc []params = md.getParameterTypes();
411     for (int i = 0; i < params.length; i++) {
412       if (! Modifier.isPublic(params[i].getModifiers()))
413         return;
414       if (! params[i].isPrimitive() && ! params[i].isArray() &&
415           params[i].getName().indexOf('.') < 0)
416         addNonPkgClass(params[i].getName());
417     }
418           
419     ArrayList JavaDoc overload = (ArrayList JavaDoc) map.get(md.getName());
420     if (overload == null) {
421       overload = new ArrayList JavaDoc();
422       map.put(md.getName(), overload);
423     }
424
425     int length = params.length;
426
427     if (length >= overload.size()) {
428       while (overload.size() <= length)
429     overload.add(null);
430     }
431     
432     ESMethodDescriptor []oldMethods;
433     oldMethods = (ESMethodDescriptor []) overload.get(length);
434
435     if (oldMethods == null) {
436       overload.set(length, new ESMethodDescriptor[] { md });
437       return;
438     }
439
440     for (int i = 0; i < oldMethods.length; i++) {
441       ESMethodDescriptor testMd = oldMethods[i];
442                          
443       if (testMd.overwrites(md))
444         return;
445       else if (md.overwrites(testMd)) {
446         oldMethods[i] = md;
447         return;
448       }
449
450       Class JavaDoc []oldParams = testMd.getParameterTypes();
451
452       int j = 0;
453       for (; j < length; j++) {
454         if (! params[j].equals(oldParams[j]))
455           break;
456       }
457
458       // duplicates another method
459
if (j == length && md.isOverwrite()) {
460         oldMethods[i] = md;
461         return;
462       } else if (j == length) {
463         return;
464       }
465     }
466
467     ESMethodDescriptor []newMethods;
468     newMethods = new ESMethodDescriptor[oldMethods.length + 1];
469     System.arraycopy(oldMethods, 0, newMethods, 0, oldMethods.length);
470     newMethods[oldMethods.length] = md;
471     overload.set(length, newMethods);
472   }
473
474   private void addPropMap(HashMap JavaDoc oldMap)
475     throws IntrospectionException JavaDoc
476   {
477     Iterator JavaDoc i = oldMap.entrySet().iterator();
478     
479     while (i.hasNext()) {
480       Map.Entry JavaDoc entry = (Map.Entry JavaDoc) i.next();
481       Object JavaDoc value = entry.getValue();
482
483       if (value == BAD) {
484     // XXX: else add bad?
485
continue;
486       }
487
488       if (value instanceof NamedPropertyDescriptor) {
489     NamedPropertyDescriptor pd = (NamedPropertyDescriptor) value;
490
491     addNamedProp(pd.getName(), pd.namedGetter, pd.namedSetter,
492              pd.namedRemover, pd.namedIterator);
493       } else if (value instanceof ESIndexedPropertyDescriptor) {
494     ESIndexedPropertyDescriptor pd = (ESIndexedPropertyDescriptor) value;
495
496     addIndexedProp(pd.getName(), pd.getESReadMethod(),
497                pd.getESWriteMethod(), pd.getESSizeMethod());
498       } else if (value instanceof ESPropertyDescriptor) {
499     ESPropertyDescriptor pd = (ESPropertyDescriptor) value;
500
501     addProp(pd.getName(), pd.field, pd.getter, pd.setter);
502       }
503       // XXX: else add bad?
504
}
505   }
506
507   void addField(Field JavaDoc field)
508     throws IntrospectionException JavaDoc
509   {
510     int modifiers = field.getModifiers();
511     if (! Modifier.isPublic(modifiers))
512       return;
513
514     addProp(field.getName(), field, null, null);
515   }
516
517   void addProps(ESBeanInfo info)
518     throws IntrospectionException JavaDoc
519   {
520     addPropMap(info.propMap);
521   }
522 }
523
Popular Tags