| package org.apache.commons.jcs3.utils.config; |
| |
| /* |
| * 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. |
| */ |
| |
| import java.beans.BeanInfo; |
| import java.beans.IntrospectionException; |
| import java.beans.Introspector; |
| import java.beans.PropertyDescriptor; |
| import java.io.File; |
| import java.lang.reflect.Method; |
| import java.util.Enumeration; |
| import java.util.Properties; |
| |
| import org.apache.commons.jcs3.log.Log; |
| import org.apache.commons.jcs3.log.LogManager; |
| |
| /** |
| * This class is based on the log4j class org.apache.log4j.config.PropertySetter that was made by |
| * Anders Kristensen |
| * <p> |
| * 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. |
| */ |
| public class PropertySetter |
| { |
| /** Logger */ |
| private static final Log log = LogManager.getLog( PropertySetter.class ); |
| |
| /** Description of the Field */ |
| private final Object obj; |
| |
| /** Description of the Field */ |
| private PropertyDescriptor[] props; |
| |
| /** |
| * Create a new PropertySetter for the specified Object. This is done in preparation 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 compute setters of object to be configured. |
| */ |
| protected void introspect() |
| { |
| try |
| { |
| BeanInfo bi = Introspector.getBeanInfo( obj.getClass() ); |
| props = bi.getPropertyDescriptors(); |
| } |
| catch ( IntrospectionException ex ) |
| { |
| log.error( "Failed to introspect {0}", obj, ex ); |
| 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>. |
| * <p> |
| * @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 properties for the object that match the <code>prefix</code> passed as parameter. |
| * <p> |
| * @param properties The new properties value |
| * @param prefix The new properties value |
| */ |
| 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 prefix. |
| 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 ); |
| |
| setProperty( key, value ); |
| } |
| } |
| |
| } |
| |
| /** |
| * 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 Integer.valueOf(value). If the setter expects |
| * a boolean, the conversion is by Boolean.valueOf(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 ); |
| |
| //log.debug("---------Key: "+name+", type="+prop.getPropertyType()); |
| |
| if ( prop == null ) |
| { |
| log.warn( "No such property [{0}] in {1}.", name, obj.getClass().getName() ); |
| } |
| else |
| { |
| try |
| { |
| setProperty( prop, name, value ); |
| } |
| catch ( PropertySetterException ex ) |
| { |
| log.warn( "Failed to set property {0} to value \"{1}\".", name, value, ex ); |
| } |
| } |
| } |
| |
| /** |
| * 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. |
| * @throws PropertySetterException |
| */ |
| |
| 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" ); |
| } |
| 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." ); |
| } |
| log.debug( "Setting property [{0}] to [{1}].", name, arg ); |
| try |
| { |
| setter.invoke( obj, new Object[] { arg } ); |
| } |
| catch ( Exception ex ) |
| { |
| throw new PropertySetterException( ex ); |
| } |
| } |
| |
| /** |
| * Convert <code>val</code> a String parameter to an object of a given type. |
| * @param val |
| * @param type |
| * @return Object |
| */ |
| 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 Integer.valueOf( v ); |
| } |
| else if ( Long.TYPE.isAssignableFrom( type ) ) |
| { |
| return Long.valueOf( v ); |
| } |
| else if ( Boolean.TYPE.isAssignableFrom( type ) ) |
| { |
| if ( "true".equalsIgnoreCase( v ) ) |
| { |
| return Boolean.TRUE; |
| } |
| else if ( "false".equalsIgnoreCase( v ) ) |
| { |
| return Boolean.FALSE; |
| } |
| } |
| else if( type.isEnum() ) |
| { |
| Enum<?> en = Enum.valueOf(type.asSubclass(Enum.class), v ); |
| return en; |
| } |
| else if ( File.class.isAssignableFrom( type ) ) |
| { |
| return new File( v ); |
| } |
| return null; |
| } |
| |
| /** |
| * Gets the propertyDescriptor attribute of the PropertySetter object |
| * @param name |
| * @return The propertyDescriptor value |
| */ |
| 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; |
| } |
| } |