Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/puppycrawl/tools/checkstyle/api/AutomaticBean.java


1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2003  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.BeanUtils;
22  import org.apache.commons.beanutils.ConversionException;
23  import org.apache.commons.beanutils.ConvertUtils;
24  import org.apache.commons.beanutils.PropertyUtils;
25  import org.apache.commons.beanutils.converters.AbstractArrayConverter;
26  import org.apache.commons.beanutils.converters.BooleanArrayConverter;
27  import org.apache.commons.beanutils.converters.BooleanConverter;
28  import org.apache.commons.beanutils.converters.ByteArrayConverter;
29  import org.apache.commons.beanutils.converters.ByteConverter;
30  import org.apache.commons.beanutils.converters.CharacterArrayConverter;
31  import org.apache.commons.beanutils.converters.CharacterConverter;
32  import org.apache.commons.beanutils.converters.DoubleArrayConverter;
33  import org.apache.commons.beanutils.converters.DoubleConverter;
34  import org.apache.commons.beanutils.converters.FloatArrayConverter;
35  import org.apache.commons.beanutils.converters.FloatConverter;
36  import org.apache.commons.beanutils.converters.IntegerArrayConverter;
37  import org.apache.commons.beanutils.converters.IntegerConverter;
38  import org.apache.commons.beanutils.converters.LongArrayConverter;
39  import org.apache.commons.beanutils.converters.LongConverter;
40  import org.apache.commons.beanutils.converters.ShortArrayConverter;
41  import org.apache.commons.beanutils.converters.ShortConverter;
42  
43  import java.lang.reflect.InvocationTargetException;
44  
45  import java.util.ArrayList;
46  import java.util.List;
47  import java.util.StringTokenizer;
48  import java.beans.PropertyDescriptor;
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      static {
60          initConverters();
61      }
62  
63      /**
64       * Setup the jakarta-commons-beanutils type converters so they throw
65       * a ConversionException instead of using the default value.
66       */
67      private static void initConverters()
68      {
69          // TODO: is there a smarter way to tell beanutils not to use defaults?
70  
71          // If any runtime environment like ANT or an IDE would use beanutils
72          // with different converters we would really be stuck here.
73          // Having to configure a static utility class in this way is really
74          // strange, it seems like a design problem in BeanUtils
75          final boolean[] booleanArray = new boolean[0];
76          final byte[] byteArray = new byte[0];
77          final char[] charArray = new char[0];
78          final double[] doubleArray = new double[0];
79          final float[] floatArray = new float[0];
80          final int[] intArray = new int[0];
81          final long[] longArray = new long[0];
82          final short[] shortArray = new short[0];
83  
84          ConvertUtils.register(new BooleanConverter(), Boolean.TYPE);
85          ConvertUtils.register(new BooleanConverter(), Boolean.class);
86          ConvertUtils.register(
87              new BooleanArrayConverter(), booleanArray.getClass());
88          ConvertUtils.register(new ByteConverter(), Byte.TYPE);
89          ConvertUtils.register(new ByteConverter(), Byte.class);
90          ConvertUtils.register(
91              new ByteArrayConverter(byteArray), byteArray.getClass());
92          ConvertUtils.register(new CharacterConverter(), Character.TYPE);
93          ConvertUtils.register(new CharacterConverter(), Character.class);
94          ConvertUtils.register(
95              new CharacterArrayConverter(), charArray.getClass());
96          ConvertUtils.register(new DoubleConverter(), Double.TYPE);
97          ConvertUtils.register(new DoubleConverter(), Double.class);
98          ConvertUtils.register(
99              new DoubleArrayConverter(doubleArray), doubleArray.getClass());
100         ConvertUtils.register(new FloatConverter(), Float.TYPE);
101         ConvertUtils.register(new FloatConverter(), Float.class);
102         ConvertUtils.register(new FloatArrayConverter(), floatArray.getClass());
103         ConvertUtils.register(new IntegerConverter(), Integer.TYPE);
104         ConvertUtils.register(new IntegerConverter(), Integer.class);
105         ConvertUtils.register(new IntegerArrayConverter(), intArray.getClass());
106         ConvertUtils.register(new LongConverter(), Long.TYPE);
107         ConvertUtils.register(new LongConverter(), Long.class);
108         ConvertUtils.register(new LongArrayConverter(), longArray.getClass());
109         ConvertUtils.register(new ShortConverter(), Short.TYPE);
110         ConvertUtils.register(new ShortConverter(), Short.class);
111         ConvertUtils.register(new ShortArrayConverter(), shortArray.getClass());
112         // TODO: investigate:
113         // StringArrayConverter doesn't properly convert an array of tokens with
114         // elements containing an underscore, "_".
115         // Hacked a replacement class :(
116         //        ConvertUtils.register(new StringArrayConverter(),
117         //                        String[].class);
118         ConvertUtils.register(new StrArrayConverter(), String[].class);
119         ConvertUtils.register(new IntegerArrayConverter(), Integer[].class);
120 
121         // BigDecimal, BigInteger, Class, Date, String, Time, TimeStamp
122         // do not use defaults in the default configuration of ConvertUtils
123     }
124 
125     /** the configuration of this bean */
126     private Configuration mConfiguration;
127 
128     /**
129      * Implements the Configurable interface using bean introspection.
130      *
131      * Subclasses are allowed to add behaviour. After the bean
132      * based setup has completed first the method
133      * {@link #finishLocalSetup finishLocalSetup}
134      * is called to allow completion of the bean's local setup,
135      * after that the method {@link #setupChild setupChild}
136      * is called for each {@link Configuration#getChildren child Configuration}
137      * of <code>aConfiguration</code>.
138      *
139      * @see Configurable
140      */
141     public final void configure(Configuration aConfiguration)
142         throws CheckstyleException
143     {
144         mConfiguration = aConfiguration;
145 
146         // TODO: debug log messages
147         final String[] attributes = aConfiguration.getAttributeNames();
148 
149         for (int i = 0; i < attributes.length; i++) {
150             final String key = attributes[i];
151             final String value = aConfiguration.getAttribute(key);
152 
153             try {
154                 // BeanUtils.copyProperties silently ignores missing setters
155                 // for key, so we have to go through great lengths here to
156                 // figure out if the bean property really exists.
157                 PropertyDescriptor pd =
158                         PropertyUtils.getPropertyDescriptor(this, key);
159                 if (pd == null || pd.getWriteMethod() == null) {
160                     throw new CheckstyleException(
161                         "Property '" + key + "' in module "
162                         + aConfiguration.getName()
163                         + " does not exist, please check the documentation");
164                 }
165 
166                 // finally we can set the bean property
167                 BeanUtils.copyProperty(this, key, value);
168             }
169             catch (InvocationTargetException e) {
170                 throw new CheckstyleException(
171                     "Cannot set property '" + key + "' in module "
172                     + aConfiguration.getName() + " to '" + value
173                     + "': " + e.getTargetException().getMessage(), e);
174             }
175             catch (IllegalAccessException e) {
176                 throw new CheckstyleException(
177                     "cannot access " + key + " in "
178                     + this.getClass().getName(), e);
179             }
180             catch (NoSuchMethodException e) {
181                 throw new CheckstyleException(
182                     "cannot access " + key + " in "
183                     + this.getClass().getName(), e);
184             }
185             catch (IllegalArgumentException e) {
186                 throw new CheckstyleException(
187                     "illegal value '" + value + "' for property '" + key
188                     + "' of module " + aConfiguration.getName(), e);
189             }
190             catch (ConversionException e) {
191                 throw new CheckstyleException(
192                     "illegal value '" + value + "' for property '" + key
193                     + "' of module " + aConfiguration.getName(), e);
194             }
195 
196         }
197 
198         finishLocalSetup();
199 
200         Configuration[] childConfigs = aConfiguration.getChildren();
201         for (int i = 0; i < childConfigs.length; i++) {
202             final Configuration childConfig = childConfigs[i];
203             setupChild(childConfig);
204         }
205     }
206 
207     /**
208      * Implements the Contextualizable interface using bean introspection.
209      * @see Contextualizable
210      */
211     public final void contextualize(Context aContext)
212         throws CheckstyleException
213     {
214         // TODO: debug log messages
215         final String[] attributes = aContext.getAttributeNames();
216 
217         for (int i = 0; i < attributes.length; i++) {
218             final String key = attributes[i];
219             final Object value = aContext.get(key);
220 
221             try {
222                 BeanUtils.copyProperty(this, key, value);
223             }
224             catch (InvocationTargetException e) {
225                 // TODO: log.debug("The bean " + this.getClass()
226                 // + " is not interested in " + value)
227                 throw new CheckstyleException("cannot set property "
228                     + key + " to value " + value + " in bean "
229                     + this.getClass().getName(), e);
230             }
231             catch (IllegalAccessException e) {
232                 throw new CheckstyleException(
233                     "cannot access " + key + " in "
234                     + this.getClass().getName(), e);
235             }
236             catch (IllegalArgumentException e) {
237                 throw new CheckstyleException(
238                     "illegal value '" + value + "' for property '" + key
239                     + "' of bean " + this.getClass().getName(), e);
240             }
241             catch (ConversionException e) {
242                 throw new CheckstyleException(
243                     "illegal value '" + value + "' for property '" + key
244                     + "' of bean " + this.getClass().getName(), e);
245             }
246         }
247     }
248 
249     /**
250      * Returns the configuration that was used to configure this component.
251      * @return the configuration that was used to configure this component.
252      */
253     protected final Configuration getConfiguration()
254     {
255         return mConfiguration;
256     }
257 
258     /**
259      * Provides a hook to finish the part of this compoent's setup that
260      * was not handled by the bean introspection.
261      * <p>
262      * The default implementation does nothing.
263      * </p>
264      * @throws CheckstyleException if there is a configuration error.
265      */
266     protected void finishLocalSetup() throws CheckstyleException
267     {
268     }
269 
270     /**
271      * Called by configure() for every child of this component's Configuration.
272      * <p>
273      * The default implementation does nothing.
274      * </p>
275      * @param aChildConf a child of this component's Configuration
276      * @throws CheckstyleException if there is a configuration error.
277      * @see Configuration#getChildren
278      */
279     protected void setupChild(Configuration aChildConf)
280         throws CheckstyleException
281     {
282     }
283 }
284 
285 /**
286  * <p>Standard Converter implementation that converts an incoming
287  * String into an array of String.  On a conversion failure, returns
288  * a specified default value or throws a ConversionException depending
289  * on how this instance is constructed.</p>
290  *
291  * Hacked from
292  * http://cvs.apache.org/viewcvs/jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/converters/StringArrayConverter.java
293  * because that implementation fails to convert array of tokens with elements
294  * containing an underscore, "_" :(
295  *
296  * @author Rick Giles
297  */
298 
299 
300 final class StrArrayConverter extends AbstractArrayConverter
301 {
302     /**
303      * <p>Model object for type comparisons.</p>
304      */
305     private static String[] sModel = new String[0];
306 
307     /**
308      * Creates a new StrArrayConverter object.
309      */
310     public StrArrayConverter()
311     {
312         this.defaultValue = null;
313         this.useDefault = false;
314     }
315 
316     /**
317      * Create a onverter that will return the specified default value
318      * if a conversion error occurs.
319      *
320      * @param aDefaultValue The default value to be returned
321      */
322     public StrArrayConverter(Object aDefaultValue)
323     {
324         this.defaultValue = aDefaultValue;
325         this.useDefault = true;
326     }
327 
328     /**
329      * Convert the specified input object into an output object of the
330      * specified type.
331      *
332      * @param aType Data type to which this value should be converted
333      * @param aValue The input value to be converted
334      *
335      * @return the converted object
336      *
337      * @throws ConversionException if conversion cannot be performed
338      *  successfully
339      */
340     public Object convert(Class aType, Object aValue)
341         throws ConversionException
342     {
343         // Deal with a null value
344         if (aValue == null) {
345             if (useDefault) {
346                 return (defaultValue);
347             }
348             else {
349                 throw new ConversionException("No value specified");
350             }
351         }
352 
353         // Deal with the no-conversion-needed case
354         if (sModel.getClass() == aValue.getClass()) {
355             return (aValue);
356         }
357 
358         // Parse the input value as a String into elements
359         // and convert to the appropriate type
360         try {
361             final List list = parseElements(aValue.toString());
362             final String[] results = new String[list.size()];
363 
364             for (int i = 0; i < results.length; i++) {
365                 results[i] = (String) list.get(i);
366             }
367             return (results);
368         }
369         catch (Exception e) {
370             if (useDefault) {
371                 return (defaultValue);
372             }
373             else {
374                 throw new ConversionException(aValue.toString(), e);
375             }
376         }
377     }
378 
379     /**
380     * <p>Parse an incoming String of the form similar to an array initializer
381     * in the Java language into a <code>List</code> individual Strings
382     * for each element, according to the following rules.</p>
383     * <ul>
384     * <li>The string must have matching '{' and '}' delimiters around
385     *     a comma-delimited list of values.</li>
386     * <li>Whitespace before and after each element is stripped.
387     * <li>If an element is itself delimited by matching single or double
388     *     quotes, the usual rules for interpreting a quoted String apply.</li>
389     * </ul>
390     *
391     * @param aValue String value to be parsed
392     * @return the list of Strings parsed from the array
393     * @throws NullPointerException if <code>svalue</code>
394     *  is <code>null</code>
395     */
396     protected List parseElements(String aValue)
397         throws NullPointerException
398     {
399         // Validate the passed argument
400         if (aValue == null) {
401             throw new NullPointerException();
402         }
403 
404         // Trim any matching '{' and '}' delimiters
405         aValue = aValue.trim();
406 
407         if (aValue.startsWith("{") && aValue.endsWith("}")) {
408             aValue = aValue.substring(1, aValue.length() - 1);
409         }
410 
411         final StringTokenizer st = new StringTokenizer(aValue, ",");
412         final List retVal = new ArrayList();
413 
414         while (st.hasMoreTokens()) {
415             final String token = st.nextToken();
416             retVal.add(token.trim());
417         }
418 
419         return retVal;
420     }
421 }