311 lines
10 KiB
Java
311 lines
10 KiB
Java
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
// Contributors: Georg Lundesgaard
|
|
|
|
package org.apache.log4j.config;
|
|
|
|
import org.apache.log4j.Appender;
|
|
import org.apache.log4j.Level;
|
|
import org.apache.log4j.Priority;
|
|
import org.apache.log4j.helpers.LogLog;
|
|
import org.apache.log4j.helpers.OptionConverter;
|
|
import org.apache.log4j.spi.OptionHandler;
|
|
import org.apache.log4j.spi.ErrorHandler;
|
|
|
|
import java.beans.BeanInfo;
|
|
import java.beans.IntrospectionException;
|
|
import java.beans.Introspector;
|
|
import java.beans.PropertyDescriptor;
|
|
import java.io.InterruptedIOException;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.util.Enumeration;
|
|
import java.util.Properties;
|
|
|
|
/**
|
|
General purpose Object property setter. Clients repeatedly invokes
|
|
{@link #setProperty setProperty(name,value)} in order to invoke setters
|
|
on the Object specified in the constructor. This class relies on the
|
|
JavaBeans {@link Introspector} to analyze the given Object Class using
|
|
reflection.
|
|
|
|
<p>Usage:
|
|
<pre>
|
|
PropertySetter ps = new PropertySetter(anObject);
|
|
ps.set("name", "Joe");
|
|
ps.set("age", "32");
|
|
ps.set("isMale", "true");
|
|
</pre>
|
|
will cause the invocations anObject.setName("Joe"), anObject.setAge(32),
|
|
and setMale(true) if such methods exist with those signatures.
|
|
Otherwise an {@link IntrospectionException} are thrown.
|
|
|
|
@author Anders Kristensen
|
|
@since 1.1
|
|
*/
|
|
public class PropertySetter {
|
|
protected Object obj;
|
|
protected PropertyDescriptor[] props;
|
|
|
|
/**
|
|
Create a new PropertySetter for the specified Object. This is done
|
|
in prepartion for invoking {@link #setProperty} one or more times.
|
|
|
|
@param obj the object for which to set properties
|
|
*/
|
|
public
|
|
PropertySetter(Object obj) {
|
|
this.obj = obj;
|
|
}
|
|
|
|
/**
|
|
Uses JavaBeans {@link Introspector} to computer setters of object to be
|
|
configured.
|
|
*/
|
|
protected
|
|
void introspect() {
|
|
try {
|
|
BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
|
|
props = bi.getPropertyDescriptors();
|
|
} catch (IntrospectionException ex) {
|
|
LogLog.error("Failed to introspect "+obj+": " + ex.getMessage());
|
|
props = new PropertyDescriptor[0];
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Set the properties of an object passed as a parameter in one
|
|
go. The <code>properties</code> are parsed relative to a
|
|
<code>prefix</code>.
|
|
|
|
@param obj The object to configure.
|
|
@param properties A java.util.Properties containing keys and values.
|
|
@param prefix Only keys having the specified prefix will be set.
|
|
*/
|
|
public
|
|
static
|
|
void setProperties(Object obj, Properties properties, String prefix) {
|
|
new PropertySetter(obj).setProperties(properties, prefix);
|
|
}
|
|
|
|
|
|
/**
|
|
Set the properites for the object that match the
|
|
<code>prefix</code> passed as parameter.
|
|
|
|
|
|
*/
|
|
public
|
|
void setProperties(Properties properties, String prefix) {
|
|
int len = prefix.length();
|
|
|
|
for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) {
|
|
String key = (String) e.nextElement();
|
|
|
|
// handle only properties that start with the desired frefix.
|
|
if (key.startsWith(prefix)) {
|
|
|
|
|
|
// ignore key if it contains dots after the prefix
|
|
if (key.indexOf('.', len + 1) > 0) {
|
|
//System.err.println("----------Ignoring---["+key
|
|
// +"], prefix=["+prefix+"].");
|
|
continue;
|
|
}
|
|
|
|
String value = OptionConverter.findAndSubst(key, properties);
|
|
key = key.substring(len);
|
|
if (("layout".equals(key) || "errorhandler".equals(key)) && obj instanceof Appender) {
|
|
continue;
|
|
}
|
|
//
|
|
// if the property type is an OptionHandler
|
|
// (for example, triggeringPolicy of org.apache.log4j.rolling.RollingFileAppender)
|
|
PropertyDescriptor prop = getPropertyDescriptor(Introspector.decapitalize(key));
|
|
if (prop != null
|
|
&& OptionHandler.class.isAssignableFrom(prop.getPropertyType())
|
|
&& prop.getWriteMethod() != null) {
|
|
OptionHandler opt = (OptionHandler)
|
|
OptionConverter.instantiateByKey(properties, prefix + key,
|
|
prop.getPropertyType(),
|
|
null);
|
|
PropertySetter setter = new PropertySetter(opt);
|
|
setter.setProperties(properties, prefix + key + ".");
|
|
try {
|
|
prop.getWriteMethod().invoke(this.obj, new Object[] { opt });
|
|
} catch(IllegalAccessException ex) {
|
|
LogLog.warn("Failed to set property [" + key +
|
|
"] to value \"" + value + "\". ", ex);
|
|
} catch(InvocationTargetException ex) {
|
|
if (ex.getTargetException() instanceof InterruptedException
|
|
|| ex.getTargetException() instanceof InterruptedIOException) {
|
|
Thread.currentThread().interrupt();
|
|
}
|
|
LogLog.warn("Failed to set property [" + key +
|
|
"] to value \"" + value + "\". ", ex);
|
|
} catch(RuntimeException ex) {
|
|
LogLog.warn("Failed to set property [" + key +
|
|
"] to value \"" + value + "\". ", ex);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
setProperty(key, value);
|
|
}
|
|
}
|
|
activate();
|
|
}
|
|
|
|
/**
|
|
Set a property on this PropertySetter's Object. If successful, this
|
|
method will invoke a setter method on the underlying Object. The
|
|
setter is the one for the specified property name and the value is
|
|
determined partly from the setter argument type and partly from the
|
|
value specified in the call to this method.
|
|
|
|
<p>If the setter expects a String no conversion is necessary.
|
|
If it expects an int, then an attempt is made to convert 'value'
|
|
to an int using new Integer(value). If the setter expects a boolean,
|
|
the conversion is by new Boolean(value).
|
|
|
|
@param name name of the property
|
|
@param value String value of the property
|
|
*/
|
|
public
|
|
void setProperty(String name, String value) {
|
|
if (value == null) return;
|
|
|
|
name = Introspector.decapitalize(name);
|
|
PropertyDescriptor prop = getPropertyDescriptor(name);
|
|
|
|
//LogLog.debug("---------Key: "+name+", type="+prop.getPropertyType());
|
|
|
|
if (prop == null) {
|
|
LogLog.warn("No such property [" + name + "] in "+
|
|
obj.getClass().getName()+"." );
|
|
} else {
|
|
try {
|
|
setProperty(prop, name, value);
|
|
} catch (PropertySetterException ex) {
|
|
LogLog.warn("Failed to set property [" + name +
|
|
"] to value \"" + value + "\". ", ex.rootCause);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Set the named property given a {@link PropertyDescriptor}.
|
|
|
|
@param prop A PropertyDescriptor describing the characteristics
|
|
of the property to set.
|
|
@param name The named of the property to set.
|
|
@param value The value of the property.
|
|
*/
|
|
public
|
|
void setProperty(PropertyDescriptor prop, String name, String value)
|
|
throws PropertySetterException {
|
|
Method setter = prop.getWriteMethod();
|
|
if (setter == null) {
|
|
throw new PropertySetterException("No setter for property ["+name+"].");
|
|
}
|
|
Class[] paramTypes = setter.getParameterTypes();
|
|
if (paramTypes.length != 1) {
|
|
throw new PropertySetterException("#params for setter != 1");
|
|
}
|
|
|
|
Object arg;
|
|
try {
|
|
arg = convertArg(value, paramTypes[0]);
|
|
} catch (Throwable t) {
|
|
throw new PropertySetterException("Conversion to type ["+paramTypes[0]+
|
|
"] failed. Reason: "+t);
|
|
}
|
|
if (arg == null) {
|
|
throw new PropertySetterException(
|
|
"Conversion to type ["+paramTypes[0]+"] failed.");
|
|
}
|
|
LogLog.debug("Setting property [" + name + "] to [" +arg+"].");
|
|
try {
|
|
setter.invoke(obj, new Object[] { arg });
|
|
} catch (IllegalAccessException ex) {
|
|
throw new PropertySetterException(ex);
|
|
} catch (InvocationTargetException ex) {
|
|
if (ex.getTargetException() instanceof InterruptedException
|
|
|| ex.getTargetException() instanceof InterruptedIOException) {
|
|
Thread.currentThread().interrupt();
|
|
}
|
|
throw new PropertySetterException(ex);
|
|
} catch (RuntimeException ex) {
|
|
throw new PropertySetterException(ex);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Convert <code>val</code> a String parameter to an object of a
|
|
given type.
|
|
*/
|
|
protected
|
|
Object convertArg(String val, Class type) {
|
|
if(val == null)
|
|
return null;
|
|
|
|
String v = val.trim();
|
|
if (String.class.isAssignableFrom(type)) {
|
|
return val;
|
|
} else if (Integer.TYPE.isAssignableFrom(type)) {
|
|
return new Integer(v);
|
|
} else if (Long.TYPE.isAssignableFrom(type)) {
|
|
return new Long(v);
|
|
} else if (Boolean.TYPE.isAssignableFrom(type)) {
|
|
if ("true".equalsIgnoreCase(v)) {
|
|
return Boolean.TRUE;
|
|
} else if ("false".equalsIgnoreCase(v)) {
|
|
return Boolean.FALSE;
|
|
}
|
|
} else if (Priority.class.isAssignableFrom(type)) {
|
|
return OptionConverter.toLevel(v, (Level) Level.DEBUG);
|
|
} else if (ErrorHandler.class.isAssignableFrom(type)) {
|
|
return OptionConverter.instantiateByClassName(v,
|
|
ErrorHandler.class, null);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
protected
|
|
PropertyDescriptor getPropertyDescriptor(String name) {
|
|
if (props == null) introspect();
|
|
|
|
for (int i = 0; i < props.length; i++) {
|
|
if (name.equals(props[i].getName())) {
|
|
return props[i];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public
|
|
void activate() {
|
|
if (obj instanceof OptionHandler) {
|
|
((OptionHandler) obj).activateOptions();
|
|
}
|
|
}
|
|
}
|