1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.log4j.config;
21
22 import java.beans.Introspector;
23 import java.beans.PropertyDescriptor;
24 import java.beans.BeanInfo;
25 import java.beans.IntrospectionException;
26 import java.lang.reflect.*;
27 import java.util.*;
28 import org.apache.log4j.*;
29 import org.apache.log4j.helpers.LogLog;
30 import org.apache.log4j.helpers.OptionConverter;
31 import org.apache.log4j.spi.OptionHandler;
32
33 /***
34 General purpose Object property setter. Clients repeatedly invokes
35 {@link #setProperty setProperty(name,value)} in order to invoke setters
36 on the Object specified in the constructor. This class relies on the
37 JavaBeans {@link Introspector} to analyze the given Object Class using
38 reflection.
39
40 <p>Usage:
41 <pre>
42 PropertySetter ps = new PropertySetter(anObject);
43 ps.set("name", "Joe");
44 ps.set("age", "32");
45 ps.set("isMale", "true");
46 </pre>
47 will cause the invocations anObject.setName("Joe"), anObject.setAge(32),
48 and setMale(true) if such methods exist with those signatures.
49 Otherwise an {@link IntrospectionException} are thrown.
50
51 @author Anders Kristensen
52 @since 1.1
53 */
54 public class PropertySetter {
55 protected Object obj;
56 protected PropertyDescriptor[] props;
57
58 /***
59 Create a new PropertySetter for the specified Object. This is done
60 in prepartion for invoking {@link #setProperty} one or more times.
61
62 @param obj the object for which to set properties
63 */
64 public
65 PropertySetter(Object obj) {
66 this.obj = obj;
67 }
68
69 /***
70 Uses JavaBeans {@link Introspector} to computer setters of object to be
71 configured.
72 */
73 protected
74 void introspect() {
75 try {
76 BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
77 props = bi.getPropertyDescriptors();
78 } catch (IntrospectionException ex) {
79 LogLog.error("Failed to introspect "+obj+": " + ex.getMessage());
80 props = new PropertyDescriptor[0];
81 }
82 }
83
84
85 /***
86 Set the properties of an object passed as a parameter in one
87 go. The <code>properties</code> are parsed relative to a
88 <code>prefix</code>.
89
90 @param obj The object to configure.
91 @param properties A java.util.Properties containing keys and values.
92 @param prefix Only keys having the specified prefix will be set.
93 */
94 public
95 static
96 void setProperties(Object obj, Properties properties, String prefix) {
97 new PropertySetter(obj).setProperties(properties, prefix);
98 }
99
100
101 /***
102 Set the properites for the object that match the
103 <code>prefix</code> passed as parameter.
104
105
106 */
107 public
108 void setProperties(Properties properties, String prefix) {
109 int len = prefix.length();
110
111 for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) {
112 String key = (String) e.nextElement();
113
114
115 if (key.startsWith(prefix)) {
116
117
118
119 if (key.indexOf('.', len + 1) > 0) {
120
121
122 continue;
123 }
124
125 String value = OptionConverter.findAndSubst(key, properties);
126 key = key.substring(len);
127 if ("layout".equals(key) && obj instanceof Appender) {
128 continue;
129 }
130 setProperty(key, value);
131 }
132 }
133 activate();
134 }
135
136 /***
137 Set a property on this PropertySetter's Object. If successful, this
138 method will invoke a setter method on the underlying Object. The
139 setter is the one for the specified property name and the value is
140 determined partly from the setter argument type and partly from the
141 value specified in the call to this method.
142
143 <p>If the setter expects a String no conversion is necessary.
144 If it expects an int, then an attempt is made to convert 'value'
145 to an int using new Integer(value). If the setter expects a boolean,
146 the conversion is by new Boolean(value).
147
148 @param name name of the property
149 @param value String value of the property
150 */
151 public
152 void setProperty(String name, String value) {
153 if (value == null) return;
154
155 name = Introspector.decapitalize(name);
156 PropertyDescriptor prop = getPropertyDescriptor(name);
157
158
159
160 if (prop == null) {
161 LogLog.warn("No such property [" + name + "] in "+
162 obj.getClass().getName()+"." );
163 } else {
164 try {
165 setProperty(prop, name, value);
166 } catch (PropertySetterException ex) {
167 LogLog.warn("Failed to set property [" + name +
168 "] to value \"" + value + "\". ", ex.rootCause);
169 }
170 }
171 }
172
173 /***
174 Set the named property given a {@link PropertyDescriptor}.
175
176 @param prop A PropertyDescriptor describing the characteristics
177 of the property to set.
178 @param name The named of the property to set.
179 @param value The value of the property.
180 */
181 public
182 void setProperty(PropertyDescriptor prop, String name, String value)
183 throws PropertySetterException {
184 Method setter = prop.getWriteMethod();
185 if (setter == null) {
186 throw new PropertySetterException("No setter for property ["+name+"].");
187 }
188 Class[] paramTypes = setter.getParameterTypes();
189 if (paramTypes.length != 1) {
190 throw new PropertySetterException("#params for setter != 1");
191 }
192
193 Object arg;
194 try {
195 arg = convertArg(value, paramTypes[0]);
196 } catch (Throwable t) {
197 throw new PropertySetterException("Conversion to type ["+paramTypes[0]+
198 "] failed. Reason: "+t);
199 }
200 if (arg == null) {
201 throw new PropertySetterException(
202 "Conversion to type ["+paramTypes[0]+"] failed.");
203 }
204 LogLog.debug("Setting property [" + name + "] to [" +arg+"].");
205 try {
206 setter.invoke(obj, new Object[] { arg });
207 } catch (Exception ex) {
208 throw new PropertySetterException(ex);
209 }
210 }
211
212
213 /***
214 Convert <code>val</code> a String parameter to an object of a
215 given type.
216 */
217 protected
218 Object convertArg(String val, Class type) {
219 if(val == null)
220 return null;
221
222 String v = val.trim();
223 if (String.class.isAssignableFrom(type)) {
224 return val;
225 } else if (Integer.TYPE.isAssignableFrom(type)) {
226 return new Integer(v);
227 } else if (Long.TYPE.isAssignableFrom(type)) {
228 return new Long(v);
229 } else if (Boolean.TYPE.isAssignableFrom(type)) {
230 if ("true".equalsIgnoreCase(v)) {
231 return Boolean.TRUE;
232 } else if ("false".equalsIgnoreCase(v)) {
233 return Boolean.FALSE;
234 }
235 } else if (Priority.class.isAssignableFrom(type)) {
236 return OptionConverter.toLevel(v, (Level) Level.DEBUG);
237 }
238 return null;
239 }
240
241
242 protected
243 PropertyDescriptor getPropertyDescriptor(String name) {
244 if (props == null) introspect();
245
246 for (int i = 0; i < props.length; i++) {
247 if (name.equals(props[i].getName())) {
248 return props[i];
249 }
250 }
251 return null;
252 }
253
254 public
255 void activate() {
256 if (obj instanceof OptionHandler) {
257 ((OptionHandler) obj).activateOptions();
258 }
259 }
260 }