KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > inversoft > beans > IndexedBeanProperty


1 /*
2  * Copyright (c) 2003, Inversoft
3  *
4  * This software is distribuable under the GNU Lesser General Public License.
5  * For more information visit gnu.org.
6  */

7 package com.inversoft.beans;
8
9
10 import java.util.HashMap JavaDoc;
11 import java.util.Map JavaDoc;
12
13 import com.inversoft.util.typeconverter.TypeConversionException;
14
15
16 /**
17  * This class is used to access an indexed JavaBean property.
18  * Normal indexed JavaBean properties take a single int
19  * parameter, in addition to the value parameter for setters,
20  * that indicates the indices into an array or collection of
21  * values.
22  *
23  * @author Brian Pontarelli
24  */

25 public class IndexedBeanProperty extends BeanProperty {
26
27     //--------------------------------------------------------------------------
28
// Cache Methods
29
//--------------------------------------------------------------------------
30

31     /**
32      * Returns an instance of the IndexedBeanProperty for the given propertyName and
33      * bean Class. This object might be cached, depending on the implementation
34      * of this method. Therefore, you must take into account a cached or non-
35      * cached object.
36      *
37      * This returns a type of BeanProperty because of the getProperty method in
38      * the BeanProperty that this extends. So, it must be cast. However, you can
39      * use getIndexedInstance instead.
40      *
41      * @param propertyName The property name of the IndexedBeanProperty
42      * @param beanClass The bean Class
43      * @return The IndexedBeanProperty and never null
44      * @throws BeanException If the creation of the obejct fails
45      */

46     public static BeanProperty getInstance(String JavaDoc propertyName, Class JavaDoc beanClass)
47     throws BeanException {
48         return getIndexedInstance(propertyName, beanClass);
49     }
50
51     /**
52      * Returns an instance of the IndexedBeanProperty for the given propertyName and
53      * bean Class. This object might be cached, depending on the implementation
54      * of this method. Therefore, you must take into account a cached or non-
55      * cached object.
56      *
57      * @param propertyName The property name of the IndexedBeanProperty
58      * @param beanClass The bean Class
59      * @return The IndexedBeanProperty and never null
60      * @throws BeanException If the creation of the obejct fails
61      */

62     public static IndexedBeanProperty getIndexedInstance(String JavaDoc propertyName,
63             Class JavaDoc beanClass)
64     throws BeanException {
65
66         if (propertyName == null || propertyName.indexOf(".") != -1) {
67             throw new BeanException("Invalid propertyName: " + propertyName);
68         }
69
70         // If not caching, just create the objects
71
if (!CACHING) {
72             return new IndexedBeanProperty(propertyName, beanClass);
73         }
74
75         synchronized (cache) {
76             // Otherwise look for the property Map or create and store
77
Map JavaDoc propMap = (Map JavaDoc) cache.get(beanClass);
78             if (propMap == null) {
79                 propMap = new HashMap JavaDoc();
80                 cache.put(beanClass, propMap);
81             }
82
83             // Look for the property itself, or create and store
84
BeanProperty bp = (BeanProperty) propMap.get(propertyName);
85             if (bp == null) {
86                 bp = new SynchronizedIndexedBeanProperty(propertyName, beanClass);
87                 propMap.put(propertyName, bp);
88             } else {
89                 if (bp.getClass() != SynchronizedIndexedBeanProperty.class) {
90                     throw new BeanException("Looking for indexed property but " +
91                         "cached version is not indexed for property named: " +
92                         propertyName);
93                 }
94             }
95
96             return (IndexedBeanProperty) bp;
97         }
98     }
99
100
101     /**
102      * Default constructor that can be used by sub-classes that want to delay the
103      * initialization of the propertyName and beanClass or that do not use these
104      * members. This constructor also calls the default constructor from the
105      * BaseBeanProperty super-class. This means that using this constructor will
106      * not make a template method call to {@link #initialize() #initialize()}.
107      */

108     protected IndexedBeanProperty() {
109         // EMPTY
110
}
111
112     /**
113      * <p>
114      * Constructs a new indexed bean property using the property name and bean class
115      * given.
116      * </p>
117      *
118      * <p>
119      * If the bean class does not have a write method (set method) than the property
120      * is considered read-only. The bean class MUST have a read method (get method)
121      * or this method will throw and exception. This method calls the super-class
122      * constructor with the same signature.
123      * </p>
124      *
125      * @param propertyName The name of the indexed JavaBean property
126      * @param beanClass The Class object used to find the read and write methods
127      * for the indexed JavaBean property
128      * @throws BeanException If the property is invalid or does not exist in
129      * the bean class given
130      */

131     public IndexedBeanProperty(String JavaDoc propertyName, Class JavaDoc beanClass)
132     throws BeanException {
133         super(propertyName, beanClass); // The super constructor calls initialize
134
}
135
136     /**
137      * <p>
138      * Constructs a new indexed bean property using the property name and fully qualified
139      * name of the bean class given.
140      * </p>
141      *
142      * <p>
143      * If the bean class does not have a write method (set method) than the property
144      * is considered read-only. The bean class MUST have a read method (get method)
145      * or this method will throw and exception. This method calls the super-class
146      * constructor with the same signature.
147      * </p>
148      *
149      * @param propertyName The name of the indexed JavaBean property
150      * @param beanClass The fully qualified name of the bean Class object used to
151      * find the read and write methods for the indexed Java bean property
152      * @throws BeanException If the property is invalid or does not exist in
153      * the bean class given
154      */

155     public IndexedBeanProperty(String JavaDoc propertyName, String JavaDoc beanClass)
156     throws BeanException {
157         super(propertyName, beanClass); // The super constructor calls initialize
158
}
159
160     /**
161      * Initializes the bean property by finding the read and write methods and setting
162      * up the propertyType for this BeanProperty.
163      *
164      * @throws BeanException If the bean class does not contain the property
165      */

166     protected void initialize() throws BeanException {
167
168         read = JavaBeanTools.findIndexedReadMethod(propertyName, beanClass);
169         propertyType = read.getReturnType();
170
171         try {
172             write = JavaBeanTools.findIndexedWriteMethod(propertyName, beanClass,
173                 propertyType);
174         } catch (BeanException be) {
175             // smother the exception so that this property is read only
176
}
177     }
178
179     /**
180      * Always returns true
181      */

182     public boolean isIndexable(Object JavaDoc bean) {
183         return true;
184     }
185
186     /**
187      * Returns the value of the indexed JavaBean property at the given indices
188      *
189      * @param bean The instance of the JavaBean to retrieve the indexed property
190      * from.
191      * @param index The indices of the JavaBean property to retrieve, this is also the
192      * parameter to the getter
193      * @throws BeanException If there was an error getting the JavaBean property or
194      * the getter/is method threw a checked Exception
195      */

196     public Object JavaDoc getPropertyValue(final Object JavaDoc bean, final int index)
197     throws BeanException {
198         return getPropertyValue(bean, new Integer JavaDoc(index));
199     }
200
201     /**
202      * This method is not implemented and will throw an exception
203      */

204     public Object JavaDoc getPropertyValue(Object JavaDoc bean) throws BeanException {
205         throw new BeanException("This operation not supported, getPropertyValue " +
206             "must have an indices for property named: " + getPropertyName());
207     }
208
209     /**
210      * If the key given is an instance of Integer, this get the intValue from that
211      * object and calls {@link #getPropertyValue(Object, int)
212      * getPropertyValue(Object, int)}. If the key is null this calls
213      * {@link #getPropertyValue(Object) getPropertyValue(Object)}
214      */

215     public Object JavaDoc getPropertyValue(final Object JavaDoc bean, final Object JavaDoc key)
216     throws BeanException {
217         Integer JavaDoc index;
218         try {
219             index = (Integer JavaDoc) key;
220         } catch (ClassCastException JavaDoc cce) {
221             throw new BeanException("This operation not supported, getPropertyValue " +
222                 "must have an integer indices for property named: " + getPropertyName());
223         }
224
225         Object JavaDoc value = JavaBeanTools.callIndexedGetter(this, bean, index);
226         if (hasPropertyListeners()) {
227             firePropertyEvent(GET, value, value, bean, index);
228         }
229
230         return value;
231     }
232
233     /**
234      * Sets the value of the indexed JavaBean property at the given indices with
235      * the given value
236      *
237      * @param bean The instance of the JavaBean to set the indexed property on
238      * @param index The indices to set to value of
239      * @param value The value to set the indexed property to
240      * @param convert Determines whether or not value should be converted
241      * to the type that the setter requires or not
242      * @throws BeanException If there was an error setting the JavaBean property or
243      * the setter method threw a checked Exception
244      * @throws TypeConversionException If there was a problem auto-converting the
245      * property value
246      */

247     public void setPropertyValue(final Object JavaDoc bean, final int index, Object JavaDoc value,
248             final boolean convert) throws BeanException, TypeConversionException {
249         setPropertyValue(bean, new Integer JavaDoc(index), value, convert);
250     }
251
252     /**
253      * Sets the value of the indexed JavaBean property at the given indices with
254      * the given value. This value is set without doing any conversion. This
255      * method is the same as calling the other setPropertyValue method with the
256      * convert parameter set to false
257      *
258      * @param bean The instance of the JavaBean to set the indexed property on
259      * @param index The indices to set to value of
260      * @param value The value to set the indexed property to
261      * @throws BeanException If there was an error setting the JavaBean property or
262      * the setter method threw a checked Exception
263      */

264     public void setPropertyValue(final Object JavaDoc bean, final int index, Object JavaDoc value)
265     throws BeanException {
266         try {
267             setPropertyValue(bean, index, value, false);
268         } catch (TypeConversionException tce) {
269             assert false : "FATAL: should never throw TypeConversionException" +
270                 " because this method does no conversion";
271         }
272     }
273
274     /**
275      * This method is not implemented and will throw an exception
276      */

277     public void setPropertyValue(final Object JavaDoc bean, Object JavaDoc value,
278             final boolean convert)
279     throws BeanException {
280         throw new BeanException("This operation not supported, setPropertyValue " +
281             "must have an indices for property named: " + getPropertyName());
282     }
283
284     /**
285      * If the key given is an instance of Integer, this get the intValue from that
286      * object and calls {@link #setPropertyValue(Object, int, Object, boolean)
287      * setPropertyValue(Object, int, Object, boolean)}. If the key is null this calls
288      * {@link #setPropertyValue(Object, Object, boolean)
289      * getPropertyValue(Object, Object, boolean)}
290      */

291     public void setPropertyValue(final Object JavaDoc bean, final Object JavaDoc key, Object JavaDoc value,
292             final boolean convert)
293     throws BeanException, TypeConversionException {
294         Integer JavaDoc index;
295         try {
296             index = (Integer JavaDoc) key;
297         } catch (ClassCastException JavaDoc cce) {
298             throw new BeanException("This operation not supported, " +
299                 "setPropertyValue must have an indices for property named: " +
300                 getPropertyName());
301         }
302
303
304         // If we are autoConverting, convert the parameter
305
if (convert) {
306             value = convertParameter(value, bean, propertyType);
307         }
308
309         // Store the old value if there are property listeners
310
Object JavaDoc oldValue = null;
311
312         if (hasPropertyListeners()) {
313             oldValue = JavaBeanTools.callIndexedGetter(this, bean, index);
314         }
315
316         JavaBeanTools.callIndexedSetter(this, bean, index, value);
317
318         if (hasPropertyListeners()) {
319             firePropertyEvent(SET, oldValue, value, bean, index);
320         }
321     }
322 }
Popular Tags