1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.onemind.commons.relabean;
22
23 import java.beans.*;
24 import java.beans.PropertyDescriptor;
25 import java.lang.reflect.Method;
26 import java.util.*;
27 import org.apache.log4j.Logger;
28 /***
29 * A Relational Bean introspector uses a relational bean model descriptor - introspect a root bean
30 * to generate a RelationalBeanModel - introspect a bean to generate a RelationalBeanInfo based
31 *
32 * @author TiongHiang Lee (thlee@onemindsoft.org)
33 * @version $Id: RelationalBeanIntrospector.java,v 1.2 2004/08/26 16:28:58 thlee Exp $ $Name: $
34 */
35 public final class RelationalBeanIntrospector
36 {
37
38 /*** the logger * */
39 private static final Logger _logger = Logger
40 .getLogger(RelationalBeanIntrospector.class);
41
42 /***
43 * {@inheritDoc}
44 */
45 private RelationalBeanIntrospector()
46 {
47 }
48
49 /***
50 * Get an instance of the introspector
51 *
52 * @return the instance
53 */
54 public static RelationalBeanIntrospector getInstance()
55 {
56 return new RelationalBeanIntrospector();
57 }
58
59 /***
60 * Introspect the RelationalBeanInfo based on the model descriptor
61 *
62 * @param desc the model descritpror
63 * @param beanClass the bean class
64 * @return the RelationalBeanInfo
65 * @throws IntrospectionException if there's problem introspect the bean properties
66 */
67 public RelationalBeanInfo introspectBeanInfo(
68 RelationalBeanModelDescriptor desc, Class beanClass)
69 throws IntrospectionException
70 {
71 RelationalBeanInfo relaInfo = new RelationalBeanInfo(beanClass);
72 BeanInfo info = null;
73 info = Introspector
74 .getBeanInfo(beanClass, desc.getStopClass(beanClass));
75 PropertyDescriptor[] propdesc = info.getPropertyDescriptors();
76 for (int i = 0; i < propdesc.length; i++)
77 {
78 Class propType = propdesc[i].getPropertyType();
79 if (propType != null)
80 {
81 if (propType.isPrimitive() || desc.isPrimitiveType(propType))
82 {
83 relaInfo
84 .addProperty(new org.onemind.commons.relabean.PropertyDescriptor(
85 propdesc[i].getName(), propdesc[i]
86 .getReadMethod(), propdesc[i]
87 .getWriteMethod()));
88 } else
89 {
90 relaInfo.addRelation(constructRelationDescriptor(beanClass,
91 propdesc[i]));
92 }
93 } else
94 {
95 _logger.warn("bypass field " + propdesc[i].getName() + " of "
96 + relaInfo.getBeanClass() + " because of null type");
97 }
98 }
99 return relaInfo;
100 }
101
102 /***
103 * Construct a relation descriptor for a property descriptor for the given bean class
104 *
105 * @param beanClass the bean class
106 * @param desc the descriptor
107 * @return the relation descriptor
108 * @todo improve the detection of the member type of the composite relation
109 */
110 private RelationDescriptor constructRelationDescriptor(Class beanClass,
111 PropertyDescriptor desc)
112 {
113 RelationDescriptor rdesc = new RelationDescriptor(desc.getName(), desc
114 .getPropertyType(), desc.getReadMethod(), desc.getWriteMethod());
115 if (Collection.class.isAssignableFrom(desc.getPropertyType()))
116 {
117 Method addMethod = guessAddMethod(beanClass, desc.getName());
118 rdesc.setAddMethod(addMethod);
119 rdesc.setRemoveMethod(guessRemoveMethod(beanClass, desc.getName()));
120 if ((addMethod != null)
121 && (addMethod.getParameterTypes().length > 0))
122 {
123
124 rdesc.setMemberType(addMethod.getParameterTypes()[0]);
125 }
126 }
127 return rdesc;
128 }
129
130 /***
131 * @param beanClass tje bean class
132 * @param relationName the relation
133 * @return the method, or null
134 * @todo optimize the guessing of remove method
135 */
136 private Method guessRemoveMethod(Class beanClass, String relationName)
137 {
138
139 Method[] methods = beanClass.getMethods();
140 for (int i = 0; i < methods.length; i++)
141 {
142 if (methods[i].getName().startsWith("remove"))
143 {
144 String suffix = methods[i].getName().substring(6);
145 if ((relationName.length() > suffix.length())
146 && relationName.substring(0, suffix.length())
147 .equalsIgnoreCase(suffix))
148 {
149 return methods[i];
150 }
151 }
152 }
153 return null;
154 }
155
156 /***
157 * Guess the add method of relation
158 *
159 * @param beanClass the bean class
160 * @param relationName the relation name
161 * @return the add method, or null
162 * @todo optimize the guessing of add method
163 */
164 private Method guessAddMethod(Class beanClass, String relationName)
165 {
166
167 Method[] methods = beanClass.getMethods();
168 for (int i = 0; i < methods.length; i++)
169 {
170 if (methods[i].getName().startsWith("add"))
171 {
172 String suffix = methods[i].getName().substring(3);
173 if ((relationName.length() > suffix.length())
174 && relationName.substring(0, suffix.length())
175 .equalsIgnoreCase(suffix))
176 {
177 return methods[i];
178 }
179 }
180 }
181 return null;
182 }
183
184 /***
185 * Construct the relational bean model from a set of bean classes using the relational bean model descriptor
186 *
187 * @param desc the descriptor
188 * @param beanClasses the bean classes
189 * @return the relation bean model
190 * @throws IntrospectionException if there's problem in instropecting the bean properties
191 */
192 public RelationalBeanModel introspectModel(
193 RelationalBeanModelDescriptor desc, Collection beanClasses)
194 throws IntrospectionException
195 {
196 RelationalBeanModel model = new RelationalBeanModel(desc);
197 Iterator it = beanClasses.iterator();
198 while (it.hasNext())
199 {
200 model.addBeanInfo(introspectBeanInfo(desc, (Class) it.next()));
201 }
202 return model;
203 }
204
205 /***
206 * Return a relational bean model from the given set of beans based on reflections
207 *
208 * @param list the list of beans
209 * @return the relational bean model
210 * @throws IntrospectionException if there's exception introspecting the model
211 */
212 public RelationalBeanModel introspectModel(List list)
213 throws IntrospectionException
214 {
215 return introspectModel(new RelationalBeanModelDescriptor("Unnamed"),
216 list);
217 }
218 }