1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.clazz.bean;
17
18 import java.lang.reflect.Constructor;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27
28 import org.apache.commons.clazz.Clazz;
29 import org.apache.commons.clazz.ClazzChangeListener;
30 import org.apache.commons.clazz.ClazzInstanceFactory;
31 import org.apache.commons.clazz.ClazzLoader;
32 import org.apache.commons.clazz.ClazzOperation;
33 import org.apache.commons.clazz.ClazzProperty;
34
35
36
37
38
39
40
41
42
43
44 public class BeanClazz extends Clazz {
45 private Clazz superClazz;
46 private List declaredProperties = new ArrayList();
47 private List properties = new ArrayList();
48 private Map propertyMap = new HashMap();
49 private List declaredOperations = new ArrayList();
50 private List operations = new ArrayList();
51 private Map operationMap = new HashMap();
52 private List instanceFactories;
53 private Map instanceFactoryMap = new HashMap();
54 private Class instanceClass;
55 private List subclasses = new ArrayList();
56
57
58
59
60
61
62
63 public BeanClazz(ClazzLoader loader, String name, Class instanceClass) {
64 super(loader, name);
65 this.instanceClass = instanceClass;
66 }
67
68 public Class getInstanceClass() {
69 if (instanceClass != null) {
70 return instanceClass;
71 }
72
73 if (superClazz instanceof BeanClazz) {
74 return ((BeanClazz) superClazz).getInstanceClass();
75 }
76
77 return BasicBean.class;
78 }
79
80
81
82
83 public Clazz getSuperclazz() {
84 return superClazz;
85 }
86
87 public void setSuperclazz(Clazz clazz) {
88 if (superClazz != null) {
89 superClazz.removeClazzChangeListener(listener);
90 }
91 superClazz = clazz;
92 if (clazz != null) {
93 superClazz.addClazzChangeListener(listener);
94 }
95 refreshAllCaches();
96 }
97
98 protected void refreshAllCaches() {
99 refreshPropertyCache();
100 refreshOperationCache();
101 }
102
103 protected void refreshPropertyCache() {
104 properties = new ArrayList();
105 propertyMap = new HashMap();
106
107 Set propertyNames = new HashSet();
108 if (superClazz != null) {
109 List superProperties = superClazz.getProperties();
110 properties.addAll(superProperties);
111 for (int i = 0; i < superProperties.size(); i++) {
112 ClazzProperty superProperty =
113 (ClazzProperty) superProperties.get(i);
114 propertyNames.add(superProperty.getName());
115 }
116 }
117 for (int i = 0; i < declaredProperties.size(); i++) {
118 ClazzProperty property = (ClazzProperty) declaredProperties.get(i);
119 String name = property.getName();
120 if (!propertyNames.contains(name)) {
121 properties.add(property);
122 }
123 }
124
125 for (Iterator iter = properties.iterator(); iter.hasNext();) {
126 ClazzProperty property = (ClazzProperty) iter.next();
127 propertyMap.put(property.getName(), property);
128 }
129 }
130
131 protected void refreshOperationCache() {
132 List operations = new ArrayList();
133 Set signatures = new HashSet();
134 if (superClazz != null) {
135 List superOperations = superClazz.getOperations();
136 operations.addAll(superOperations);
137 for (int i = 0; i < superOperations.size(); i++) {
138 ClazzOperation superOperation =
139 (ClazzOperation) superOperations.get(i);
140 signatures.add(superOperation.getSignature());
141 }
142 }
143 for (int i = 0; i < declaredOperations.size(); i++) {
144 ClazzOperation operation =
145 (ClazzOperation) declaredOperations.get(i);
146 String signature = operation.getSignature();
147 if (!signatures.contains(signature)) {
148 operations.add(operation);
149 }
150 }
151 }
152
153
154
155
156 public List getDeclaredProperties() {
157 return Collections.unmodifiableList(declaredProperties);
158 }
159
160 public void addDeclaredProperty(ClazzProperty property) {
161 if (property.getDeclaringClazz() != this) {
162 throw new BeanClazzConfigurationException(
163 "Property belongs to a different clazz: "
164 + property.getDeclaringClazz().getName());
165 }
166
167 ClazzProperty oldProperty =
168 (ClazzProperty) propertyMap.get(property.getName());
169 if (oldProperty != null) {
170 removeDeclaredProperty(oldProperty);
171 }
172
173 declaredProperties.add(property);
174
175 addProperty(property);
176 }
177
178
179
180
181 protected void addProperty(ClazzProperty property) {
182 properties.add(property);
183 propertyMap.put(property.getName(), property);
184 firePropertyAdded(property);
185 }
186
187 public void removeDeclaredProperty(ClazzProperty property) {
188 String name = property.getName();
189 property = (ClazzProperty) propertyMap.get(name);
190 if (property != null) {
191 declaredProperties.remove(property);
192 removeProperty(property);
193 }
194 }
195
196
197
198
199 protected void removeProperty(ClazzProperty property) {
200 String name = property.getName();
201 properties.remove(property);
202 propertyMap.remove(name);
203 firePropertyRemoved(property);
204
205
206
207 if (superClazz != null) {
208 property = superClazz.getProperty(name);
209 if (property != null) {
210 addProperty(property);
211 }
212 }
213 }
214
215
216
217
218 public List getProperties() {
219 return properties;
220 }
221
222
223
224
225 public ClazzProperty getProperty(String name) {
226 return (ClazzProperty) propertyMap.get(name);
227 }
228
229
230
231
232 public List getDeclaredOperations() {
233 return Collections.unmodifiableList(declaredOperations);
234 }
235
236 public void addDeclaredOperation(ClazzOperation operation) {
237 if (operation.getDeclaringClazz() != this) {
238 throw new BeanClazzConfigurationException(
239 "Operation belongs to a different clazz: "
240 + operation.getDeclaringClazz().getName());
241 }
242
243 ClazzOperation oldOperation =
244 (ClazzOperation) operationMap.get(operation.getSignature());
245 if (oldOperation != null) {
246 removeDeclaredOperation(oldOperation);
247 }
248
249 declaredOperations.add(operation);
250
251 addOperation(operation);
252 }
253
254
255
256
257 protected void addOperation(ClazzOperation operation) {
258 operations.add(operation);
259 operationMap.put(operation.getSignature(), operation);
260 fireOperationAdded(operation);
261 }
262
263 public void removeDeclaredOperation(ClazzOperation operation) {
264 String signature = operation.getSignature();
265 operation = (ClazzOperation) operationMap.get(signature);
266 if (operation != null) {
267 declaredOperations.remove(operation);
268 removeOperation(operation);
269 }
270 }
271
272
273
274
275 protected void removeOperation(ClazzOperation operation) {
276 String signature = operation.getSignature();
277 operations.remove(operation);
278 operationMap.remove(signature);
279 fireOperationRemoved(operation);
280
281
282
283 if (superClazz != null) {
284 operation = superClazz.getOperation(signature);
285 if (operation != null) {
286 addOperation(operation);
287 }
288 }
289 }
290
291
292
293
294 public List getOperations() {
295 return operations;
296 }
297
298
299
300
301 public ClazzOperation getOperation(String signature) {
302 return (ClazzOperation) operationMap.get(signature);
303 }
304
305
306
307
308 public List getInstanceFactories() {
309 if (instanceFactories == null) {
310 introspectInstanceFactories();
311 }
312 return Collections.unmodifiableList(instanceFactories);
313 }
314
315
316
317
318 public ClazzInstanceFactory getInstanceFactory(String signature) {
319 if (instanceFactories == null) {
320 introspectInstanceFactories();
321 }
322
323 return (ClazzInstanceFactory) instanceFactoryMap.get(signature);
324 }
325
326 public void addInstanceFactory(ClazzInstanceFactory factory) {
327 if (factory.getDeclaringClazz() != this) {
328 throw new BeanClazzConfigurationException(
329 "Instance factory belongs to a different clazz: "
330 + factory.getDeclaringClazz().getName());
331 }
332
333 if (instanceFactories == null) {
334 introspectInstanceFactories();
335 }
336 ClazzInstanceFactory oldFactory =
337 (ClazzInstanceFactory) instanceFactoryMap.get(
338 factory.getSignature());
339 if (oldFactory != null) {
340 removeInstanceFactory(oldFactory);
341 }
342 instanceFactories.add(factory);
343 instanceFactoryMap.put(factory.getSignature(), factory);
344 fireInstanceFactoryAdded(factory);
345 }
346
347 public void removeInstanceFactory(ClazzInstanceFactory factory) {
348 if (instanceFactories.remove(factory)) {
349 instanceFactoryMap.remove(factory.getSignature());
350 fireInstanceFactoryRemoved(factory);
351 }
352 }
353
354
355
356
357
358
359
360
361
362 private void introspectInstanceFactories() {
363 instanceFactories = new ArrayList();
364 Class instanceClass = getInstanceClass();
365 Constructor constructors[] = instanceClass.getConstructors();
366 for (int i = 0; i < constructors.length; i++) {
367 Class[] parameterTypes = constructors[i].getParameterTypes();
368 if (parameterTypes != null
369 && parameterTypes.length >= 1
370 && Clazz.class.isAssignableFrom(parameterTypes[0])) {
371 addInstanceFactory(
372 new BeanClazzConstructorInstanceFactory(
373 this,
374 constructors[i]));
375 }
376 }
377 }
378
379 private ClazzChangeListener listener = new ClazzChangeListener() {
380 public void propertyAdded(Clazz clazz, ClazzProperty property) {
381 if (propertyMap.get(property.getName()) == null) {
382 addProperty(property);
383 }
384 }
385
386 public void propertyRemoved(Clazz clazz, ClazzProperty property) {
387 ClazzProperty declared =
388 (ClazzProperty) propertyMap.get(property.getName());
389 if (declared != null && declared.equals(property)) {
390 removeProperty(property);
391 }
392 }
393
394 public void operationAdded(Clazz clazz, ClazzOperation operation) {
395 if (operationMap.get(operation.getSignature()) == null) {
396 addOperation(operation);
397 }
398 }
399
400 public void operationRemoved(Clazz clazz, ClazzOperation operation) {
401 ClazzOperation declared =
402 (ClazzOperation) operationMap.get(operation.getSignature());
403 if (declared != null && declared.equals(operation)) {
404 removeOperation(operation);
405 }
406 }
407
408 public void instanceFactoryAdded(
409 Clazz clazz,
410 ClazzInstanceFactory property)
411 {
412
413 }
414
415 public void instanceFactoryRemoved(
416 Clazz clazz,
417 ClazzInstanceFactory property)
418 {
419
420 }
421 };
422 }