001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    
019    package org.apache.commons.beanutils;
020    
021    import java.io.Serializable;
022    import java.lang.reflect.InvocationTargetException;
023    
024    
025    /**
026     * <p>Implementation of <code>DynaBean</code> that wraps a standard JavaBean
027     * instance, so that DynaBean APIs can be used to access its properties.</p>
028     *
029     * <p>
030     * The most common use cases for this class involve wrapping an existing java bean.
031     * (This makes it different from the typical use cases for other <code>DynaBean</code>'s.) 
032     * For example:
033     * </p>
034     * <code><pre>
035     *  Object aJavaBean = ...;
036     *  ...
037     *  DynaBean db = new WrapDynaBean(aJavaBean);
038     *  ...
039     * </pre></code>
040     *
041     * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does not
042     * support the <code>contains()</code> and <code>remove()</code> methods.</p>
043     *
044     * @author Craig McClanahan
045     * @version $Revision: 926529 $ $Date: 2010-03-23 11:44:24 +0000 (Tue, 23 Mar 2010) $
046     */
047    
048    public class WrapDynaBean implements DynaBean, Serializable {
049    
050    
051        // ---------------------------------------------------------- Constructors
052    
053    
054        /**
055         * Construct a new <code>DynaBean</code> associated with the specified
056         * JavaBean instance.
057         *
058         * @param instance JavaBean instance to be wrapped
059         */
060        public WrapDynaBean(Object instance) {
061    
062            super();
063            this.instance = instance;
064            this.dynaClass = (WrapDynaClass)getDynaClass();
065    
066        }
067    
068    
069        // ---------------------------------------------------- Instance Variables
070    
071    
072        /**
073         * The <code>DynaClass</code> "base class" that this DynaBean
074         * is associated with.
075         */
076        protected transient WrapDynaClass dynaClass = null;
077    
078    
079        /**
080         * The JavaBean instance wrapped by this WrapDynaBean.
081         */
082        protected Object instance = null;
083    
084    
085        // ------------------------------------------------------ DynaBean Methods
086    
087    
088        /**
089         * Does the specified mapped property contain a value for the specified
090         * key value?
091         *
092         * @param name Name of the property to check
093         * @param key Name of the key to check
094         * @return <code>true<code> if the mapped property contains a value for
095         * the specified key, otherwise <code>false</code>
096         *
097         * @exception IllegalArgumentException if there is no property
098         *  of the specified name
099         */
100        public boolean contains(String name, String key) {
101    
102            throw new UnsupportedOperationException
103                    ("WrapDynaBean does not support contains()");
104    
105        }
106    
107    
108        /**
109         * Return the value of a simple property with the specified name.
110         *
111         * @param name Name of the property whose value is to be retrieved
112         * @return The property's value
113         *
114         * @exception IllegalArgumentException if there is no property
115         *  of the specified name
116         */
117        public Object get(String name) {
118    
119            Object value = null;
120            try {
121                value = PropertyUtils.getSimpleProperty(instance, name);
122            } catch (InvocationTargetException ite) {
123                Throwable cause = ite.getTargetException();
124                throw new IllegalArgumentException
125                        ("Error reading property '" + name +
126                                  "' nested exception - " + cause);
127            } catch (Throwable t) {
128                throw new IllegalArgumentException
129                        ("Error reading property '" + name +
130                                  "', exception - " + t);
131            }
132            return (value);
133    
134        }
135    
136    
137        /**
138         * Return the value of an indexed property with the specified name.
139         *
140         * @param name Name of the property whose value is to be retrieved
141         * @param index Index of the value to be retrieved
142         * @return The indexed property's value
143         *
144         * @exception IllegalArgumentException if there is no property
145         *  of the specified name
146         * @exception IllegalArgumentException if the specified property
147         *  exists, but is not indexed
148         * @exception IndexOutOfBoundsException if the specified index
149         *  is outside the range of the underlying property
150         * @exception NullPointerException if no array or List has been
151         *  initialized for this property
152         */
153        public Object get(String name, int index) {
154    
155            Object value = null;
156            try {
157                value = PropertyUtils.getIndexedProperty(instance, name, index);
158            } catch (IndexOutOfBoundsException e) {
159                throw e;
160            } catch (InvocationTargetException ite) {
161                Throwable cause = ite.getTargetException();
162                throw new IllegalArgumentException
163                        ("Error reading indexed property '" + name +
164                                  "' nested exception - " + cause);
165            } catch (Throwable t) {
166                throw new IllegalArgumentException
167                        ("Error reading indexed property '" + name +
168                                  "', exception - " + t);
169            }
170            return (value);
171    
172        }
173    
174    
175        /**
176         * Return the value of a mapped property with the specified name,
177         * or <code>null</code> if there is no value for the specified key.
178         *
179         * @param name Name of the property whose value is to be retrieved
180         * @param key Key of the value to be retrieved
181         * @return The mapped property's value
182         *
183         * @exception IllegalArgumentException if there is no property
184         *  of the specified name
185         * @exception IllegalArgumentException if the specified property
186         *  exists, but is not mapped
187         */
188        public Object get(String name, String key) {
189    
190            Object value = null;
191            try {
192                value = PropertyUtils.getMappedProperty(instance, name, key);
193            } catch (InvocationTargetException ite) {
194                Throwable cause = ite.getTargetException();
195                throw new IllegalArgumentException
196                        ("Error reading mapped property '" + name +
197                                  "' nested exception - " + cause);
198            } catch (Throwable t) {
199                throw new IllegalArgumentException
200                        ("Error reading mapped property '" + name +
201                                  "', exception - " + t);
202            }
203            return (value);
204    
205        }
206    
207    
208        /**
209         * Return the <code>DynaClass</code> instance that describes the set of
210         * properties available for this DynaBean.
211         * @return The associated DynaClass
212         */
213        public DynaClass getDynaClass() {
214    
215            if (dynaClass == null) {
216                dynaClass = WrapDynaClass.createDynaClass(instance.getClass());
217            }
218    
219            return (this.dynaClass);
220    
221        }
222    
223    
224        /**
225         * Remove any existing value for the specified key on the
226         * specified mapped property.
227         *
228         * @param name Name of the property for which a value is to
229         *  be removed
230         * @param key Key of the value to be removed
231         *
232         * @exception IllegalArgumentException if there is no property
233         *  of the specified name
234         */
235        public void remove(String name, String key) {
236    
237    
238            throw new UnsupportedOperationException
239                    ("WrapDynaBean does not support remove()");
240    
241        }
242    
243    
244        /**
245         * Set the value of a simple property with the specified name.
246         *
247         * @param name Name of the property whose value is to be set
248         * @param value Value to which this property is to be set
249         *
250         * @exception ConversionException if the specified value cannot be
251         *  converted to the type required for this property
252         * @exception IllegalArgumentException if there is no property
253         *  of the specified name
254         * @exception NullPointerException if an attempt is made to set a
255         *  primitive property to null
256         */
257        public void set(String name, Object value) {
258    
259            try {
260                PropertyUtils.setSimpleProperty(instance, name, value);
261            } catch (InvocationTargetException ite) {
262                Throwable cause = ite.getTargetException();
263                throw new IllegalArgumentException
264                        ("Error setting property '" + name +
265                                  "' nested exception -" + cause);
266            } catch (Throwable t) {
267                throw new IllegalArgumentException
268                        ("Error setting property '" + name +
269                                  "', exception - " + t);
270            }
271    
272        }
273    
274    
275        /**
276         * Set the value of an indexed property with the specified name.
277         *
278         * @param name Name of the property whose value is to be set
279         * @param index Index of the property to be set
280         * @param value Value to which this property is to be set
281         *
282         * @exception ConversionException if the specified value cannot be
283         *  converted to the type required for this property
284         * @exception IllegalArgumentException if there is no property
285         *  of the specified name
286         * @exception IllegalArgumentException if the specified property
287         *  exists, but is not indexed
288         * @exception IndexOutOfBoundsException if the specified index
289         *  is outside the range of the underlying property
290         */
291        public void set(String name, int index, Object value) {
292    
293            try {
294                PropertyUtils.setIndexedProperty(instance, name, index, value);
295            } catch (IndexOutOfBoundsException e) {
296                throw e;
297            } catch (InvocationTargetException ite) {
298                Throwable cause = ite.getTargetException();
299                throw new IllegalArgumentException
300                        ("Error setting indexed property '" + name +
301                                  "' nested exception - " + cause);
302            } catch (Throwable t) {
303                throw new IllegalArgumentException
304                        ("Error setting indexed property '" + name +
305                                  "', exception - " + t);
306            }
307    
308        }
309    
310    
311        /**
312         * Set the value of a mapped property with the specified name.
313         *
314         * @param name Name of the property whose value is to be set
315         * @param key Key of the property to be set
316         * @param value Value to which this property is to be set
317         *
318         * @exception ConversionException if the specified value cannot be
319         *  converted to the type required for this property
320         * @exception IllegalArgumentException if there is no property
321         *  of the specified name
322         * @exception IllegalArgumentException if the specified property
323         *  exists, but is not mapped
324         */
325        public void set(String name, String key, Object value) {
326    
327            try {
328                PropertyUtils.setMappedProperty(instance, name, key, value);
329            } catch (InvocationTargetException ite) {
330                Throwable cause = ite.getTargetException();
331                throw new IllegalArgumentException
332                        ("Error setting mapped property '" + name +
333                                  "' nested exception - " + cause);
334            } catch (Throwable t) {
335                throw new IllegalArgumentException
336                        ("Error setting mapped property '" + name +
337                                  "', exception - " + t);
338            }
339    
340        }
341    
342        /** 
343         * Gets the bean instance wrapped by this DynaBean.
344         * For most common use cases, 
345         * this object should already be known 
346         * and this method safely be ignored.
347         * But some creators of frameworks using <code>DynaBean</code>'s may 
348         * find this useful.
349         *
350         * @return the java bean Object wrapped by this <code>DynaBean</code>
351         */
352        public Object getInstance() {
353            return instance;
354        }
355    
356    
357        // ------------------------------------------------------ Protected Methods
358    
359    
360        /**
361         * Return the property descriptor for the specified property name.
362         *
363         * @param name Name of the property for which to retrieve the descriptor
364         * @return The descriptor for the specified property
365         *
366         * @exception IllegalArgumentException if this is not a valid property
367         *  name for our DynaClass
368         */
369        protected DynaProperty getDynaProperty(String name) {
370    
371            DynaProperty descriptor = getDynaClass().getDynaProperty(name);
372            if (descriptor == null) {
373                throw new IllegalArgumentException
374                        ("Invalid property name '" + name + "'");
375            }
376            return (descriptor);
377    
378        }
379    
380    
381    }