1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package ch.qos.logback.core.util;
19
20 import java.beans.BeanInfo;
21 import java.beans.IntrospectionException;
22 import java.beans.Introspector;
23 import java.beans.MethodDescriptor;
24 import java.beans.PropertyDescriptor;
25 import java.lang.reflect.Method;
26
27 import ch.qos.logback.core.spi.ContextAwareBase;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class PropertySetter extends ContextAwareBase {
54 private static final int X_NOT_FOUND = 0;
55 private static final int X_AS_COMPONENT = 1;
56 private static final int X_AS_PROPERTY = 2;
57
58 private static final Class[] STING_CLASS_PARAMETER = new Class[] {String.class};
59
60
61 protected Object obj;
62 protected Class objClass;
63 protected PropertyDescriptor[] propertyDescriptors;
64 protected MethodDescriptor[] methodDescriptors;
65
66
67
68
69
70
71
72
73 public PropertySetter(Object obj) {
74 this.obj = obj;
75 this.objClass = obj.getClass();
76 }
77
78
79
80
81
82 protected void introspect() {
83 try {
84 BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
85 propertyDescriptors = bi.getPropertyDescriptors();
86 methodDescriptors = bi.getMethodDescriptors();
87 } catch (IntrospectionException ex) {
88 addError("Failed to introspect " + obj + ": " + ex.getMessage());
89 propertyDescriptors = new PropertyDescriptor[0];
90 methodDescriptors = new MethodDescriptor[0];
91 }
92 }
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 public void setProperty(String name, String value) {
113 if (value == null) {
114 return;
115 }
116
117 name = Introspector.decapitalize(name);
118
119 PropertyDescriptor prop = getPropertyDescriptor(name);
120
121 if (prop == null) {
122 addWarn("No such property [" + name + "] in " + objClass.getName() + ".");
123 } else {
124 try {
125 setProperty(prop, name, value);
126 } catch (PropertySetterException ex) {
127 addWarn("Failed to set property [" + name + "] to value \"" + value
128 + "\". ", ex);
129 }
130 }
131 }
132
133
134
135
136
137
138
139
140
141
142
143
144 public void setProperty(PropertyDescriptor prop, String name, String value)
145 throws PropertySetterException {
146 Method setter = prop.getWriteMethod();
147
148 if (setter == null) {
149 throw new PropertySetterException("No setter for property [" + name
150 + "].");
151 }
152
153 Class[] paramTypes = setter.getParameterTypes();
154
155
156 if (paramTypes.length != 1) {
157 throw new PropertySetterException("#params for setter != 1");
158 }
159
160 Object arg;
161
162 try {
163 arg = convertArg(value, paramTypes[0]);
164 } catch (Throwable t) {
165 throw new PropertySetterException("Conversion to type [" + paramTypes[0]
166 + "] failed. ", t);
167 }
168
169 if (arg == null) {
170 throw new PropertySetterException("Conversion to type [" + paramTypes[0]
171 + "] failed.");
172 }
173
174
175
176 try {
177 setter.invoke(obj, new Object[] { arg });
178 } catch (Exception ex) {
179 throw new PropertySetterException(ex);
180 }
181 }
182
183 public ContainmentType canContainComponent(String name) {
184 String cName = capitalizeFirstLetter(name);
185
186 Method addMethod = getMethod("add" + cName);
187
188 if (addMethod != null) {
189 int type = computeContainmentTpye(addMethod);
190 switch (type) {
191 case X_NOT_FOUND:
192 return ContainmentType.NOT_FOUND;
193 case X_AS_PROPERTY:
194 return ContainmentType.AS_PROPERTY_COLLECTION;
195 case X_AS_COMPONENT:
196 return ContainmentType.AS_COMPONENT_COLLECTION;
197 }
198 }
199
200 String dName = Introspector.decapitalize(name);
201
202 PropertyDescriptor propertyDescriptor = getPropertyDescriptor(dName);
203
204 if (propertyDescriptor != null) {
205 Method setterMethod = propertyDescriptor.getWriteMethod();
206 if (setterMethod != null) {
207
208
209
210 int type = computeContainmentTpye(setterMethod);
211
212
213 switch (type) {
214 case X_NOT_FOUND:
215 return ContainmentType.NOT_FOUND;
216 case X_AS_PROPERTY:
217 return ContainmentType.AS_SINGLE_PROPERTY;
218 case X_AS_COMPONENT:
219 return ContainmentType.AS_SINGLE_COMPONENT;
220 }
221 }
222 }
223
224
225 return ContainmentType.NOT_FOUND;
226 }
227
228 int computeContainmentTpye(Method setterMethod) {
229 Class[] classArray = setterMethod.getParameterTypes();
230 if (classArray.length != 1) {
231 return X_NOT_FOUND;
232 } else {
233 Class clazz = classArray[0];
234 Package p = clazz.getPackage();
235 if (clazz.isPrimitive()) {
236 return X_AS_PROPERTY;
237 } else if (p != null && "java.lang".equals(p.getName())) {
238 return X_AS_PROPERTY;
239 } else if (Duration.class.isAssignableFrom(clazz)) {
240 return X_AS_PROPERTY;
241 } else if (FileSize.class.isAssignableFrom(clazz)) {
242 return X_AS_PROPERTY;
243 } else if (clazz.isEnum()){
244 return X_AS_PROPERTY;
245 } else {
246 return X_AS_COMPONENT;
247 }
248 }
249 }
250
251 public Class getObjClass() {
252 return objClass;
253 }
254
255 @SuppressWarnings("unchecked")
256 public void addComponent(String name, Object childComponent) {
257 Class ccc = childComponent.getClass();
258 name = capitalizeFirstLetter(name);
259
260 Method method = getMethod("add" + name);
261
262
263 if (method != null) {
264 Class[] params = method.getParameterTypes();
265
266 if (params.length == 1) {
267 if (params[0].isAssignableFrom(childComponent.getClass())) {
268 try {
269 method.invoke(this.obj, new Object[] { childComponent });
270 } catch (Exception e) {
271 addError("Could not invoke method " + method.getName()
272 + " in class " + obj.getClass().getName()
273 + " with parameter of type " + ccc.getName(), e);
274 }
275 } else {
276 addError("A \"" + ccc.getName()
277 + "\" object is not assignable to a \"" + params[0].getName()
278 + "\" variable.");
279 addError("The class \"" + params[0].getName() + "\" was loaded by ");
280 addError("[" + params[0].getClassLoader()
281 + "] whereas object of type ");
282 addError("\"" + ccc.getName() + "\" was loaded by ["
283 + ccc.getClassLoader() + "].");
284 }
285 }
286 } else {
287 addError("Could not find method [" + "add" + name + "] in class ["
288 + objClass.getName() + "].");
289 }
290 }
291
292 @SuppressWarnings("unchecked")
293 public void addProperty(String name, String strValue) {
294
295 if (strValue == null) {
296 return;
297 }
298
299 name = capitalizeFirstLetter(name);
300 Method adderMethod = getMethod("add" + name);
301
302 if (adderMethod == null) {
303 addError("No adder for property [" + name + "].");
304 return;
305 }
306
307 Class[] paramTypes = adderMethod.getParameterTypes();
308 if (paramTypes.length != 1) {
309 addError("#params for setter != 1");
310 return;
311
312 }
313 Object arg;
314 try {
315 arg = convertArg(strValue, paramTypes[0]);
316 } catch (Throwable t) {
317 addError("Conversion to type [" + paramTypes[0] + "] failed. ", t);
318 return;
319 }
320
321 if (arg == null) {
322 addError("Conversion to type [" + paramTypes[0] + "] failed.");
323 } else {
324 try {
325 adderMethod.invoke(obj, arg);
326 } catch (Exception ex) {
327 addError("Failed to invoke adder for " + name, ex);
328 }
329 }
330
331 }
332
333 public void setComponent(String name, Object childComponent) {
334 String dName = Introspector.decapitalize(name);
335 PropertyDescriptor propertyDescriptor = getPropertyDescriptor(dName);
336
337 if (propertyDescriptor == null) {
338 addWarn("Could not find PropertyDescriptor for [" + name + "] in "
339 + objClass.getName());
340
341 return;
342 }
343
344 Method setter = propertyDescriptor.getWriteMethod();
345
346 if (setter == null) {
347 addWarn("Not setter method for property [" + name + "] in "
348 + obj.getClass().getName());
349
350 return;
351 }
352
353 Class[] paramTypes = setter.getParameterTypes();
354
355 if (paramTypes.length != 1) {
356 addError("Wrong number of parameters in setter method for property ["
357 + name + "] in " + obj.getClass().getName());
358
359 return;
360 }
361
362 try {
363 setter.invoke(obj, new Object[] { childComponent });
364
365
366
367 } catch (Exception e) {
368 addError("Could not set component " + obj + " for parent component "
369 + obj, e);
370 }
371 }
372
373 private String capitalizeFirstLetter(String name) {
374 return name.substring(0, 1).toUpperCase() + name.substring(1);
375 }
376
377
378
379
380 protected Object convertArg(String val, Class type) {
381 if (val == null) {
382 return null;
383 }
384
385 String v = val.trim();
386
387 if (String.class.isAssignableFrom(type)) {
388 return val;
389 } else if (Integer.TYPE.isAssignableFrom(type)) {
390 return new Integer(v);
391 } else if (Long.TYPE.isAssignableFrom(type)) {
392 return new Long(v);
393 } else if (Float.TYPE.isAssignableFrom(type)) {
394 return new Float(v);
395 } else if (Double.TYPE.isAssignableFrom(type)) {
396 return new Double(v);
397 } else if (Boolean.TYPE.isAssignableFrom(type)) {
398 if ("true".equalsIgnoreCase(v)) {
399 return Boolean.TRUE;
400 } else if ("false".equalsIgnoreCase(v)) {
401 return Boolean.FALSE;
402 }
403 } else if (Duration.class.isAssignableFrom(type)) {
404 return Duration.valueOf(val);
405 } else if (FileSize.class.isAssignableFrom(type)) {
406 return FileSize.valueOf(val);
407 } else if(type.isEnum()) {
408 return convertEnum(val, type);
409 }
410
411 return null;
412 }
413
414 protected Object convertEnum(String val, Class type) {
415 try {
416 Method m = type.getMethod("valueOf", STING_CLASS_PARAMETER);
417 return m.invoke(null, val);
418 } catch (Exception e) {
419 addError("Failed to convert value ["+val+"] to enum ["+type.getName()+"]", e);
420 }
421 return null;
422 }
423
424 protected Method getMethod(String methodName) {
425 if (methodDescriptors == null) {
426 introspect();
427 }
428
429 for (int i = 0; i < methodDescriptors.length; i++) {
430 if (methodName.equals(methodDescriptors[i].getName())) {
431 return methodDescriptors[i].getMethod();
432 }
433 }
434
435 return null;
436 }
437
438 protected PropertyDescriptor getPropertyDescriptor(String name) {
439 if (propertyDescriptors == null) {
440 introspect();
441 }
442
443 for (int i = 0; i < propertyDescriptors.length; i++) {
444
445
446 if (name.equals(propertyDescriptors[i].getName())) {
447
448 return propertyDescriptors[i];
449 }
450 }
451
452 return null;
453 }
454
455 public Object getObj() {
456 return obj;
457 }
458 }