2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 // Contributors: Georg Lundesgaard
20 package org.apache.log4j.config;
22 import org.apache.log4j.Appender;
23 import org.apache.log4j.Level;
24 import org.apache.log4j.Priority;
25 import org.apache.log4j.helpers.LogLog;
26 import org.apache.log4j.helpers.OptionConverter;
27 import org.apache.log4j.spi.OptionHandler;
28 import org.apache.log4j.spi.ErrorHandler;
30 import java.beans.BeanInfo;
31 import java.beans.IntrospectionException;
32 import java.beans.Introspector;
33 import java.beans.PropertyDescriptor;
34 import java.io.InterruptedIOException;
35 import java.lang.reflect.InvocationTargetException;
36 import java.lang.reflect.Method;
37 import java.util.Enumeration;
38 import java.util.Properties;
41 General purpose Object property setter. Clients repeatedly invokes
42 {@link #setProperty setProperty(name,value)} in order to invoke setters
43 on the Object specified in the constructor. This class relies on the
44 JavaBeans {@link Introspector} to analyze the given Object Class using
49 PropertySetter ps = new PropertySetter(anObject);
50 ps.set("name", "Joe");
52 ps.set("isMale", "true");
54 will cause the invocations anObject.setName("Joe"), anObject.setAge(32),
55 and setMale(true) if such methods exist with those signatures.
56 Otherwise an {@link IntrospectionException} are thrown.
58 @author Anders Kristensen
61 public class PropertySetter {
63 protected PropertyDescriptor[] props;
66 Create a new PropertySetter for the specified Object. This is done
67 in prepartion for invoking {@link #setProperty} one or more times.
69 @param obj the object for which to set properties
72 PropertySetter(Object obj) {
77 Uses JavaBeans {@link Introspector} to computer setters of object to be
83 BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
84 props = bi.getPropertyDescriptors();
85 } catch (IntrospectionException ex) {
86 LogLog.error("Failed to introspect "+obj+": " + ex.getMessage());
87 props = new PropertyDescriptor[0];
93 Set the properties of an object passed as a parameter in one
94 go. The <code>properties</code> are parsed relative to a
97 @param obj The object to configure.
98 @param properties A java.util.Properties containing keys and values.
99 @param prefix Only keys having the specified prefix will be set.
103 void setProperties(Object obj, Properties properties, String prefix) {
104 new PropertySetter(obj).setProperties(properties, prefix);
109 Set the properites for the object that match the
110 <code>prefix</code> passed as parameter.
115 void setProperties(Properties properties, String prefix) {
116 int len = prefix.length();
118 for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) {
119 String key = (String) e.nextElement();
121 // handle only properties that start with the desired frefix.
122 if (key.startsWith(prefix)) {
125 // ignore key if it contains dots after the prefix
126 if (key.indexOf('.', len + 1) > 0) {
127 //System.err.println("----------Ignoring---["+key
128 // +"], prefix=["+prefix+"].");
132 String value = OptionConverter.findAndSubst(key, properties);
133 key = key.substring(len);
134 if (("layout".equals(key) || "errorhandler".equals(key)) && obj instanceof Appender) {
138 // if the property type is an OptionHandler
139 // (for example, triggeringPolicy of org.apache.log4j.rolling.RollingFileAppender)
140 PropertyDescriptor prop = getPropertyDescriptor(Introspector.decapitalize(key));
142 && OptionHandler.class.isAssignableFrom(prop.getPropertyType())
143 && prop.getWriteMethod() != null) {
144 OptionHandler opt = (OptionHandler)
145 OptionConverter.instantiateByKey(properties, prefix + key,
146 prop.getPropertyType(),
148 PropertySetter setter = new PropertySetter(opt);
149 setter.setProperties(properties, prefix + key + ".");
151 prop.getWriteMethod().invoke(this.obj, new Object[] { opt });
152 } catch(IllegalAccessException ex) {
153 LogLog.warn("Failed to set property [" + key +
154 "] to value \"" + value + "\". ", ex);
155 } catch(InvocationTargetException ex) {
156 if (ex.getTargetException() instanceof InterruptedException
157 || ex.getTargetException() instanceof InterruptedIOException) {
158 Thread.currentThread().interrupt();
160 LogLog.warn("Failed to set property [" + key +
161 "] to value \"" + value + "\". ", ex);
162 } catch(RuntimeException ex) {
163 LogLog.warn("Failed to set property [" + key +
164 "] to value \"" + value + "\". ", ex);
169 setProperty(key, value);
176 Set a property on this PropertySetter's Object. If successful, this
177 method will invoke a setter method on the underlying Object. The
178 setter is the one for the specified property name and the value is
179 determined partly from the setter argument type and partly from the
180 value specified in the call to this method.
182 <p>If the setter expects a String no conversion is necessary.
183 If it expects an int, then an attempt is made to convert 'value'
184 to an int using new Integer(value). If the setter expects a boolean,
185 the conversion is by new Boolean(value).
187 @param name name of the property
188 @param value String value of the property
191 void setProperty(String name, String value) {
196 name = Introspector.decapitalize(name);
197 PropertyDescriptor prop = getPropertyDescriptor(name);
199 //LogLog.debug("---------Key: "+name+", type="+prop.getPropertyType());
202 LogLog.warn("No such property [" + name + "] in "+
203 obj.getClass().getName()+"." );
206 setProperty(prop, name, value);
207 } catch (PropertySetterException ex) {
208 LogLog.warn("Failed to set property [" + name +
209 "] to value \"" + value + "\". ", ex.rootCause);
215 Set the named property given a {@link PropertyDescriptor}.
217 @param prop A PropertyDescriptor describing the characteristics
218 of the property to set.
219 @param name The named of the property to set.
220 @param value The value of the property.
223 void setProperty(PropertyDescriptor prop, String name, String value)
224 throws PropertySetterException {
225 Method setter = prop.getWriteMethod();
226 if (setter == null) {
227 throw new PropertySetterException("No setter for property ["+name+"].");
229 Class[] paramTypes = setter.getParameterTypes();
230 if (paramTypes.length != 1) {
231 throw new PropertySetterException("#params for setter != 1");
236 arg = convertArg(value, paramTypes[0]);
237 } catch (Throwable t) {
238 throw new PropertySetterException("Conversion to type ["+paramTypes[0]+
239 "] failed. Reason: "+t);
242 throw new PropertySetterException(
243 "Conversion to type ["+paramTypes[0]+"] failed.");
245 LogLog.debug("Setting property [" + name + "] to [" +arg+"].");
247 setter.invoke(obj, new Object[] { arg });
248 } catch (IllegalAccessException ex) {
249 throw new PropertySetterException(ex);
250 } catch (InvocationTargetException ex) {
251 if (ex.getTargetException() instanceof InterruptedException
252 || ex.getTargetException() instanceof InterruptedIOException) {
253 Thread.currentThread().interrupt();
255 throw new PropertySetterException(ex);
256 } catch (RuntimeException ex) {
257 throw new PropertySetterException(ex);
263 Convert <code>val</code> a String parameter to an object of a
267 Object convertArg(String val, Class type) {
272 String v = val.trim();
273 if (String.class.isAssignableFrom(type)) {
275 } else if (Integer.TYPE.isAssignableFrom(type)) {
276 return new Integer(v);
277 } else if (Long.TYPE.isAssignableFrom(type)) {
279 } else if (Boolean.TYPE.isAssignableFrom(type)) {
280 if ("true".equalsIgnoreCase(v)) {
282 } else if ("false".equalsIgnoreCase(v)) {
283 return Boolean.FALSE;
285 } else if (Priority.class.isAssignableFrom(type)) {
286 return OptionConverter.toLevel(v, Level.DEBUG);
287 } else if (ErrorHandler.class.isAssignableFrom(type)) {
288 return OptionConverter.instantiateByClassName(v,
289 ErrorHandler.class, null);
296 PropertyDescriptor getPropertyDescriptor(String name) {
301 for (int i = 0; i < props.length; i++) {
302 if (name.equals(props[i].getName())) {
311 if (obj instanceof OptionHandler) {
312 ((OptionHandler) obj).activateOptions();