Coverage details for org.chwf.filter.GenericPropertyFilter

LineHitsSource
1 /*
2 Chrysalis Web Framework [http://chrysalis.sourceforge.net]
3 Copyright (c) 2002, 2003, 2004, Paul Strack
4  
5 All rights reserved.
6  
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9  
10 1. Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
12  
13 2. Redistributions in binary form must reproduce the above copyright notice,
14 this list of conditions and the following disclaimer in the documentation
15 and/or other materials provided with the distribution.
16  
17 3. Neither the name of the copyright holder nor the names of its contributors
18 may be used to endorse or promote products derived from this software without
19 specific prior written permission.
20  
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
25 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32  
33 package org.chwf.filter;
34  
35 import java.beans.PropertyDescriptor;
36 import java.lang.reflect.InvocationTargetException;
37 import java.lang.reflect.Method;
38 import java.util.HashMap;
39 import java.util.Iterator;
40 import java.util.Locale;
41 import java.util.Map;
42  
43 import org.chwf.config.Config;
44 import org.chwf.config.ConfigFactory;
45 import org.chwf.config.PolymorphicConfig;
46 import org.chwf.converter.ConversionException;
47 import org.chwf.converter.Converter;
48  
49 /**
50  * An abstract superclass of property filters.
51  *
52  * @author <a href="mailto:pfstrack@users.sourceforge.net">Paul Strack</a>
53  */
54 public abstract class PropertyFilter {
55  
56   /** The property name. */
57   private final String name;
58  
59   /** The property type. */
60   private final Class type;
61  
62   /** The bean class. */
63   private final Class beanClass;
64  
65   /** Property attributes. */
66   private final Map attributes = new HashMap();
67  
68   /**
69    * The validator that should be used; if <code>null</code>, no validation
70    * should be performed.
71    */
72   private final Validator validator;
73  
74   /**
75    * Constructor.<p>
76    *
77    * @param beanClass The bean class.
78    * @param name The property name.
79    * @param type The property type.
80    * @throws InitializationException If filter initialization fails.
81    */
82   public PropertyFilter(Class beanClass, String name, Class type)
83     throws InitializationException {
84     this.name = name;
85     this.beanClass = beanClass;
86     this.type = type;
87     Config config = ConfigFactory.getConfig(beanClass);
88     if (config.getBoolean("external-validation", false)) {
89       this.validator = Validator.findValidator(beanClass);
90     } else {
91       this.validator = null;
92     }
93   }
94  
95   /**
96    * The bean class for the filter.<p>
97    *
98    * @return The bean class for the filter.
99    */
100   public Class getBeanClass() {
101     return beanClass;
102   }
103  
104   /**
105    * Get the specified property of the target object, as a string.<p>
106    *
107    * @param object The object whose property is being retrieved.
108    * @return The property value.
109    * @throws FilterException For read failure.
110    */
111   public abstract String get(Object object) throws FilterException;
112  
113   /**
114    * Get the specified property of the target object, as an object.<p>
115    *
116    * @param object The object whose property is being retrieved.
117    * @return The property value.
118    * @throws FilterException For read failure.
119    */
120   public abstract Object getPropertyAsObject(Object object)
121     throws FilterException;
122  
123   /**
124    * Set the specified property of the target object, using a string.<p>
125    *
126    * @param object The object whose property is being updated.
127    * @param value The new property value.
128    * @throws ConversionException If the value cannot be converted to
129    * the correct type.
130    * @throws FilterException For write failure.
131    */
132   public abstract void set(Object object, String value)
133     throws ConversionException, FilterException;
134  
135   /**
136    * Get the property name.<p>
137    *
138    * @return The property name.
139    */
140   public String getName() {
141     return this.name;
142   }
143  
144   /**
145    * Get the property's Java type.<p>
146    *
147    * @return The property's Java type.
148    */
149   public Class getType() {
150     return this.type;
151   }
152  
153   /**
154    * Get the named attribute value.<p>
155    *
156    * @param name The attribute name.
157    * @return The attribute value.
158    */
159   public Object getAttribute(String name) {
160     return this.attributes.get(name);
161   }
162  
163   /**
164    * Get the localized value of the named attribute.<p>
165    *
166    * @param name The attribute name.
167    * @param locale The locale.
168    * @return The attribute value.
169    */
170   public String getLocalizedAttribute(String name, Locale locale) {
171     String defaultValue = Converter.convert(this.attributes.get(name));
172     String key = this.name + "." + name;
173     Config config = PolymorphicConfig.getConfig(beanClass, locale);
174     return config.get(key, defaultValue);
175   }
176  
177   /**
178    * Get all attribute names.<p>
179    *
180    * @return An iterator for all the attribute names.
181    */
182   public Iterator attributeNames() {
183     return this.attributes.keySet().iterator();
184   }
185  
186   /**
187    * Whether the property is readable. For dynamically generated property
188    * filters, this value is determined by whether the property has a getter
189    * method. For custom filters that extend this class, this value defaults
190    * to <code>true</code>. Custom filters must override this method if they
191    * are not readable<p>
192    *
193    * @return true if readable.
194    */
195   public boolean isReadable() {
196     return true;
197   }
198  
199   /**
200    * Whether the property is writeable. For dynamically generated property
201    * filters, this value is determined by whether the property has a setter
202    * method and a converter from the <code>org.chwf.converter</code> package.
203    * For custom filters that extend this class, this value defaults to
204    * <code>true</code>. Custom filters must override this method if they
205    * are not writeable.<p>
206    *
207    * @return true if writeable.
208    */
209   public boolean isWriteable() {
210     return true;
211   }
212  
213   /**
214    * Set the named attribute.<p>
215    *
216    * @param name The attribute name.
217    * @param value The attribute value.
218    */
219   protected void setAttribute(String name, Object value) {
220     this.attributes.put(name, value);
221   }
222  
223   /**
224    * Return the validator for this class, or <code>null</code> if the filter
225    * should not perform external validation.<p>
226    *
227    * @return The validator or <code>null</code>
228    */
229   protected Validator getValidator() {
230     return this.validator;
231   }
232 }
233  
234 /**
235  * Generic default filter created through introspection.
236  *
237  * @author Paul Strack
238  */
239 class GenericPropertyFilter extends PropertyFilter {
240  
241   /** Suffix for datatype properties. */
242   private static final String DATATYPE_PROPERTY_SUFFIX = ".datatype";
243  
244   /** An array for method invocations with no parameters. */
2451  private static final Object[] NO_PARAMETER = new Object[0];
246  
247   /** The property's getter. */
248   private final Method getter;
249  
250   /** The property's setter. */
251   private final Method setter;
252  
253   /** The property's converter. */
254   private final Converter converter;
255  
256   /**
257    * Constructor.
258    *
259    * @param beanClass The bean class.
260    * @param descriptor The BeanInfo property descriptor.
261    */
262   public GenericPropertyFilter(
263     Class beanClass,
264     PropertyDescriptor descriptor) {
265103    super(beanClass, descriptor.getName(), descriptor.getPropertyType());
266103    this.getter = descriptor.getReadMethod();
267103    this.converter = Converter.getConverter(this.deriveDatatype());
268103    if (this.converter.isSimpleType()) {
26974      this.setter = descriptor.getWriteMethod();
270     } else {
27129      this.setter = null;
272     }
273103  }
274  
275   /**
276    * Get the specified property of the target object, as a string.
277    *
278    * @param object The object whose property is being retrieved.
279    * @return The property value.
280    * @throws FilterException For read failure.
281    */
282   public String get(Object object) throws FilterException {
28336    return getConverter().format(getPropertyAsObject(object));
284   }
285  
286   /**
287    * Get the specified property of the target object, as an object.
288    *
289    * @param object The object whose property is being retrieved.
290    * @return The property value.
291    * @throws FilterException For read failure.
292    */
293   public Object getPropertyAsObject(Object object) throws FilterException {
29458    checkBeanClass(object);
295     try {
29658      return getGetter().invoke(object, NO_PARAMETER);
297     } catch (PropertyNotReadableException ex) {
2982      throw ex;
299     } catch (Exception ex) {
3000      throw new OperationException(ex);
301     }
302   }
303  
304   /**
305    * Set the specified property of the target object, using a string.
306    *
307    * @param object The object whose property is being updated.
308    * @param value The new property value.
309    * @throws FilterException For write failure.
310    * @throws ConversionException For string conversion failure.
311    */
312   public void set(Object object, String value)
313     throws FilterException, ConversionException {
314  
31531    checkBeanClass(object);
316     try {
31729      Object valueAsObject = getConverter().parse(value);
31828      if (getValidator() != null) {
3192        getValidator().validate(object, getName(), valueAsObject);
320       }
32126      Object[] arguments = { valueAsObject};
32226      getSetter().invoke(object, arguments);
32322    } catch (ConversionException ex) {
3241      throw ex;
325     } catch (PropertyNotWriteableException ex) {
3262      throw ex;
327     } catch (InvocationTargetException ex) {
3282      throw new OperationException(ex.getTargetException());
329     } catch (IllegalAccessException ex) {
3300      throw new PropertyNotWriteableException(getName());
331     }
33222  }
333  
334   /**
335    * Overrides its superclass method to return <code>true</code> if the
336    * property has a getter method.
337    *
338    * @return true if readable.
339    */
340   public boolean isReadable() {
34118    return (this.getter != null);
342   }
343  
344   /**
345    * Overrides its superclass method to return <code>true</code> if the
346    * property has a setter method.
347    *
348    * @return true if writeable.
349    */
350   public boolean isWriteable() {
351143    return (this.setter != null);
352   }
353  
354   /**
355    * Get the property's converter.
356    *
357    * @return The property's converter.
358    */
359   private Converter getConverter() {
36065    return this.converter;
361   }
362  
363   /**
364    * Get the property's getter.
365    *
366    * @return The property's getter.
367    * @throws PropertyNotReadableException If not readable.
368    */
369   private Method getGetter() throws PropertyNotReadableException {
37058    if (getter == null) {
3712      throw new PropertyNotReadableException(getName());
372     }
37356    return getter;
374   }
375  
376   /**
377    * Get the property's setter.
378    *
379    * @return The property's setter.
380    * @throws PropertyNotWriteableException If not writeable.
381    */
382   private Method getSetter() throws PropertyNotWriteableException {
38326    if (setter == null) {
3842      throw new PropertyNotWriteableException(getName());
385     }
38624    return setter;
387   }
388  
389   /**
390    * Check the bean's type.
391    *
392    * @param object The target object.
393    * @throws FilterException If not the correct type.
394    */
395   private void checkBeanClass(Object object) throws FilterException {
39689    if (!getBeanClass().isInstance(object)) {
3972      throw new FilterException(
398         FilterException.MESSAGE_INCORRECT_OBJECT_TYPE,
399         new Object[] { getBeanClass().getName()});
400     }
40187  }
402  
403   /**
404    * Derive the datatype.
405    *
406    * @return Derive the datatype.
407    */
408   private String deriveDatatype() {
409103    String typeKey = getName() + DATATYPE_PROPERTY_SUFFIX;
410103    String defaultType = getType().getName();
411103    Config config = PolymorphicConfig.getConfig(getBeanClass());
412103    return config.get(typeKey, defaultType);
413   }
414 }

this report was generated by version 1.0.5 of jcoverage.
visit www.jcoverage.com for updates.

copyright © 2003, jcoverage ltd. all rights reserved.
Java is a trademark of Sun Microsystems, Inc. in the United States and other countries.