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