KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > api > AutomaticBean


1 ////////////////////////////////////////////////////////////////////////////////
2
// checkstyle: Checks Java source code for adherence to a set of rules.
3
// Copyright (C) 2001-2005 Oliver Burn
4
//
5
// This library is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation; either
8
// version 2.1 of the License, or (at your option) any later version.
9
//
10
// This library is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
// Lesser General Public License for more details.
14
//
15
// You should have received a copy of the GNU Lesser General Public
16
// License along with this library; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
////////////////////////////////////////////////////////////////////////////////
19
package com.puppycrawl.tools.checkstyle.api;
20
21 import org.apache.commons.beanutils.BeanUtilsBean;
22 import org.apache.commons.beanutils.ConversionException;
23 import org.apache.commons.beanutils.ConvertUtilsBean;
24 import org.apache.commons.beanutils.PropertyUtils;
25 import org.apache.commons.beanutils.PropertyUtilsBean;
26 import org.apache.commons.beanutils.converters.AbstractArrayConverter;
27 import org.apache.commons.beanutils.converters.BooleanArrayConverter;
28 import org.apache.commons.beanutils.converters.BooleanConverter;
29 import org.apache.commons.beanutils.converters.ByteArrayConverter;
30 import org.apache.commons.beanutils.converters.ByteConverter;
31 import org.apache.commons.beanutils.converters.CharacterArrayConverter;
32 import org.apache.commons.beanutils.converters.CharacterConverter;
33 import org.apache.commons.beanutils.converters.DoubleArrayConverter;
34 import org.apache.commons.beanutils.converters.DoubleConverter;
35 import org.apache.commons.beanutils.converters.FloatArrayConverter;
36 import org.apache.commons.beanutils.converters.FloatConverter;
37 import org.apache.commons.beanutils.converters.IntegerArrayConverter;
38 import org.apache.commons.beanutils.converters.IntegerConverter;
39 import org.apache.commons.beanutils.converters.LongArrayConverter;
40 import org.apache.commons.beanutils.converters.LongConverter;
41 import org.apache.commons.beanutils.converters.ShortArrayConverter;
42 import org.apache.commons.beanutils.converters.ShortConverter;
43
44 import java.beans.PropertyDescriptor JavaDoc;
45 import java.lang.reflect.InvocationTargetException JavaDoc;
46 import java.util.ArrayList JavaDoc;
47 import java.util.List JavaDoc;
48 import java.util.StringTokenizer JavaDoc;
49
50
51 /**
52  * A Java Bean that implements the component lifecycle interfaces by
53  * calling the bean's setters for all configration attributes.
54  * @author lkuehne
55  */

56 public class AutomaticBean
57     implements Configurable, Contextualizable
58 {
59     /** the configuration of this bean */
60     private Configuration mConfiguration;
61
62
63     /**
64      * Creates a BeanUtilsBean that is configured to use
65      * type converters that throw a ConversionException
66      * instead of using the default value when something
67      * goes wrong.
68      *
69      * @return a configured BeanUtilsBean
70      */

71     private static BeanUtilsBean createBeanUtilsBean()
72     {
73         final ConvertUtilsBean cub = new ConvertUtilsBean();
74
75         // TODO: is there a smarter way to tell beanutils not to use defaults?
76

77         final boolean[] booleanArray = new boolean[0];
78         final byte[] byteArray = new byte[0];
79         final char[] charArray = new char[0];
80         final double[] doubleArray = new double[0];
81         final float[] floatArray = new float[0];
82         final int[] intArray = new int[0];
83         final long[] longArray = new long[0];
84         final short[] shortArray = new short[0];
85
86
87         cub.register(new BooleanConverter(), Boolean.TYPE);
88         cub.register(new BooleanConverter(), Boolean JavaDoc.class);
89         cub.register(
90             new BooleanArrayConverter(), booleanArray.getClass());
91         cub.register(new ByteConverter(), Byte.TYPE);
92         cub.register(new ByteConverter(), Byte JavaDoc.class);
93         cub.register(
94             new ByteArrayConverter(byteArray), byteArray.getClass());
95         cub.register(new CharacterConverter(), Character.TYPE);
96         cub.register(new CharacterConverter(), Character JavaDoc.class);
97         cub.register(
98             new CharacterArrayConverter(), charArray.getClass());
99         cub.register(new DoubleConverter(), Double.TYPE);
100         cub.register(new DoubleConverter(), Double JavaDoc.class);
101         cub.register(
102             new DoubleArrayConverter(doubleArray), doubleArray.getClass());
103         cub.register(new FloatConverter(), Float.TYPE);
104         cub.register(new FloatConverter(), Float JavaDoc.class);
105         cub.register(new FloatArrayConverter(), floatArray.getClass());
106         cub.register(new IntegerConverter(), Integer.TYPE);
107         cub.register(new IntegerConverter(), Integer JavaDoc.class);
108         cub.register(new IntegerArrayConverter(), intArray.getClass());
109         cub.register(new LongConverter(), Long.TYPE);
110         cub.register(new LongConverter(), Long JavaDoc.class);
111         cub.register(new LongArrayConverter(), longArray.getClass());
112         cub.register(new ShortConverter(), Short.TYPE);
113         cub.register(new ShortConverter(), Short JavaDoc.class);
114         cub.register(new ShortArrayConverter(), shortArray.getClass());
115         // TODO: investigate:
116
// StringArrayConverter doesn't properly convert an array of tokens with
117
// elements containing an underscore, "_".
118
// Hacked a replacement class :(
119
// cub.register(new StringArrayConverter(),
120
// String[].class);
121
cub.register(new StrArrayConverter(), String JavaDoc[].class);
122         cub.register(new IntegerArrayConverter(), Integer JavaDoc[].class);
123
124         // BigDecimal, BigInteger, Class, Date, String, Time, TimeStamp
125
// do not use defaults in the default configuration of ConvertUtilsBean
126

127         return new BeanUtilsBean(cub, new PropertyUtilsBean());
128     }
129
130     /**
131      * Implements the Configurable interface using bean introspection.
132      *
133      * Subclasses are allowed to add behaviour. After the bean
134      * based setup has completed first the method
135      * {@link #finishLocalSetup finishLocalSetup}
136      * is called to allow completion of the bean's local setup,
137      * after that the method {@link #setupChild setupChild}
138      * is called for each {@link Configuration#getChildren child Configuration}
139      * of <code>aConfiguration</code>.
140      *
141      * @param aConfiguration {@inheritDoc}
142      * @throws CheckstyleException {@inheritDoc}
143      * @see Configurable
144      */

145     public final void configure(Configuration aConfiguration)
146         throws CheckstyleException
147     {
148         mConfiguration = aConfiguration;
149
150         final BeanUtilsBean beanUtils = createBeanUtilsBean();
151
152         // TODO: debug log messages
153
final String JavaDoc[] attributes = aConfiguration.getAttributeNames();
154
155         for (int i = 0; i < attributes.length; i++) {
156             final String JavaDoc key = attributes[i];
157             final String JavaDoc value = aConfiguration.getAttribute(key);
158
159             try {
160                 // BeanUtilsBean.copyProperties silently ignores missing setters
161
// for key, so we have to go through great lengths here to
162
// figure out if the bean property really exists.
163
final PropertyDescriptor JavaDoc pd =
164                     PropertyUtils.getPropertyDescriptor(this, key);
165                 if ((pd == null) || (pd.getWriteMethod() == null)) {
166                     throw new CheckstyleException(
167                         "Property '" + key + "' in module "
168                         + aConfiguration.getName()
169                         + " does not exist, please check the documentation");
170                 }
171
172                 // finally we can set the bean property
173
beanUtils.copyProperty(this, key, value);
174             }
175             catch (final InvocationTargetException JavaDoc e) {
176                 throw new CheckstyleException(
177                     "Cannot set property '" + key + "' in module "
178                     + aConfiguration.getName() + " to '" + value
179                     + "': " + e.getTargetException().getMessage(), e);
180             }
181             catch (final IllegalAccessException JavaDoc e) {
182                 throw new CheckstyleException(
183                     "cannot access " + key + " in "
184                     + this.getClass().getName(), e);
185             }
186             catch (final NoSuchMethodException JavaDoc e) {
187                 throw new CheckstyleException(
188                     "cannot access " + key + " in "
189                     + this.getClass().getName(), e);
190             }
191             catch (final IllegalArgumentException JavaDoc e) {
192                 throw new CheckstyleException(
193                     "illegal value '" + value + "' for property '" + key
194                     + "' of module " + aConfiguration.getName(), e);
195             }
196             catch (final ConversionException e) {
197                 throw new CheckstyleException(
198                     "illegal value '" + value + "' for property '" + key
199                     + "' of module " + aConfiguration.getName(), e);
200             }
201
202         }
203
204         finishLocalSetup();
205
206         final Configuration[] childConfigs = aConfiguration.getChildren();
207         for (int i = 0; i < childConfigs.length; i++) {
208             final Configuration childConfig = childConfigs[i];
209             setupChild(childConfig);
210         }
211     }
212
213     /**
214      * Implements the Contextualizable interface using bean introspection.
215      * @param aContext {@inheritDoc}
216      * @throws CheckstyleException {@inheritDoc}
217      * @see Contextualizable
218      */

219     public final void contextualize(Context aContext)
220         throws CheckstyleException
221     {
222         final BeanUtilsBean beanUtils = createBeanUtilsBean();
223
224         // TODO: debug log messages
225
final String JavaDoc[] attributes = aContext.getAttributeNames();
226
227         for (int i = 0; i < attributes.length; i++) {
228             final String JavaDoc key = attributes[i];
229             final Object JavaDoc value = aContext.get(key);
230
231             try {
232                 beanUtils.copyProperty(this, key, value);
233             }
234             catch (final InvocationTargetException JavaDoc e) {
235                 // TODO: log.debug("The bean " + this.getClass()
236
// + " is not interested in " + value)
237
throw new CheckstyleException("cannot set property "
238                     + key + " to value " + value + " in bean "
239                     + this.getClass().getName(), e);
240             }
241             catch (final IllegalAccessException JavaDoc e) {
242                 throw new CheckstyleException(
243                     "cannot access " + key + " in "
244                     + this.getClass().getName(), e);
245             }
246             catch (final IllegalArgumentException JavaDoc e) {
247                 throw new CheckstyleException(
248                     "illegal value '" + value + "' for property '" + key
249                     + "' of bean " + this.getClass().getName(), e);
250             }
251             catch (final ConversionException e) {
252                 throw new CheckstyleException(
253                     "illegal value '" + value + "' for property '" + key
254                     + "' of bean " + this.getClass().getName(), e);
255             }
256         }
257     }
258
259     /**
260      * Returns the configuration that was used to configure this component.
261      * @return the configuration that was used to configure this component.
262      */

263     protected final Configuration getConfiguration()
264     {
265         return mConfiguration;
266     }
267
268     /**
269      * Provides a hook to finish the part of this compoent's setup that
270      * was not handled by the bean introspection.
271      * <p>
272      * The default implementation does nothing.
273      * </p>
274      * @throws CheckstyleException if there is a configuration error.
275      */

276     protected void finishLocalSetup() throws CheckstyleException
277     {
278     }
279
280     /**
281      * Called by configure() for every child of this component's Configuration.
282      * <p>
283      * The default implementation does nothing.
284      * </p>
285      * @param aChildConf a child of this component's Configuration
286      * @throws CheckstyleException if there is a configuration error.
287      * @see Configuration#getChildren
288      */

289     protected void setupChild(Configuration aChildConf)
290         throws CheckstyleException
291     {
292     }
293 }
294
295 /**
296  * <p>Standard Converter implementation that converts an incoming
297  * String into an array of String. On a conversion failure, returns
298  * a specified default value or throws a ConversionException depending
299  * on how this instance is constructed.</p>
300  *
301  * Hacked from
302  * http://cvs.apache.org/viewcvs/jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/converters/StringArrayConverter.java
303  * because that implementation fails to convert array of tokens with elements
304  * containing an underscore, "_" :(
305  *
306  * @author Rick Giles
307  */

308
309
310 final class StrArrayConverter extends AbstractArrayConverter
311 {
312     /**
313      * <p>Model object for type comparisons.</p>
314      */

315     private static final String JavaDoc[] MODEL = new String JavaDoc[0];
316
317     /**
318      * Creates a new StrArrayConverter object.
319      */

320     public StrArrayConverter()
321     {
322         this.defaultValue = null;
323         this.useDefault = false;
324     }
325
326     /**
327      * Create a onverter that will return the specified default value
328      * if a conversion error occurs.
329      *
330      * @param aDefaultValue The default value to be returned
331      */

332     public StrArrayConverter(Object JavaDoc aDefaultValue)
333     {
334         this.defaultValue = aDefaultValue;
335         this.useDefault = true;
336     }
337
338     /**
339      * Convert the specified input object into an output object of the
340      * specified type.
341      *
342      * @param aType Data type to which this value should be converted
343      * @param aValue The input value to be converted
344      *
345      * @return the converted object
346      *
347      * @throws ConversionException if conversion cannot be performed
348      * successfully
349      */

350     public Object JavaDoc convert(Class JavaDoc aType, Object JavaDoc aValue)
351         throws ConversionException
352     {
353         // Deal with a null value
354
if (aValue == null) {
355             if (useDefault) {
356                 return (defaultValue);
357             }
358             throw new ConversionException("No value specified");
359         }
360
361         // Deal with the no-conversion-needed case
362
if (MODEL.getClass() == aValue.getClass()) {
363             return (aValue);
364         }
365
366         // Parse the input value as a String into elements
367
// and convert to the appropriate type
368
try {
369             final List JavaDoc list = parseElements(aValue.toString());
370             final String JavaDoc[] results = new String JavaDoc[list.size()];
371
372             for (int i = 0; i < results.length; i++) {
373                 results[i] = (String JavaDoc) list.get(i);
374             }
375             return (results);
376         }
377         catch (final Exception JavaDoc e) {
378             if (useDefault) {
379                 return (defaultValue);
380             }
381             throw new ConversionException(aValue.toString(), e);
382         }
383     }
384
385     /**
386      * <p>
387      * Parse an incoming String of the form similar to an array initializer in
388      * the Java language into a <code>List</code> individual Strings for each
389      * element, according to the following rules.
390      * </p>
391      * <ul>
392      * <li>The string must have matching '{' and '}' delimiters around a
393      * comma-delimited list of values.</li>
394      * <li>Whitespace before and after each element is stripped.
395      * <li>If an element is itself delimited by matching single or double
396      * quotes, the usual rules for interpreting a quoted String apply.</li>
397      * </ul>
398      *
399      * @param aValue
400      * String value to be parsed
401      * @return the list of Strings parsed from the array
402      * @throws NullPointerException
403      * if <code>svalue</code> is <code>null</code>
404      */

405     protected List JavaDoc parseElements(final String JavaDoc aValue)
406         throws NullPointerException JavaDoc
407     {
408         // Validate the passed argument
409
if (aValue == null) {
410             throw new NullPointerException JavaDoc();
411         }
412
413         // Trim any matching '{' and '}' delimiters
414
String JavaDoc str = aValue.trim();
415         if (str.startsWith("{") && str.endsWith("}")) {
416             str = str.substring(1, str.length() - 1);
417         }
418
419         final StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(str, ",");
420         final List JavaDoc retVal = new ArrayList JavaDoc();
421
422         while (st.hasMoreTokens()) {
423             final String JavaDoc token = st.nextToken();
424             retVal.add(token.trim());
425         }
426
427         return retVal;
428     }
429 }
430
Popular Tags