View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 1999-2005 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id$
34   */
35  
36  package org.exolab.castor.mapping;
37  
38  import org.exolab.castor.mapping.loader.CollectionHandlers;
39  import java.util.Enumeration;
40  
41  /**
42   * An extended version of the FieldHandler interface which is used for making generic libraries of
43   * FieldHandlers which can be used for more than one field or class, but have similar conversion
44   * algorithms.
45   *
46   * @author <a href="kvisco-at-intalio.com">Keith Visco</a>
47   * @version $Revision$ $Date: 2005-01-18 17:29:45 -0700 (Tue, 18 Jan 2005) $
48   * @see FieldDescriptor
49   * @see FieldHandler
50   */
51  public abstract class GeneralizedFieldHandler extends AbstractFieldHandler {
52  
53    /**
54     * Error message when a null FieldHandler is encountered
55     */
56    private static final String NULL_HANDLER_ERR =
57        "A call to #setFieldHandler (with a non-null value) must be "
58            + "made before calling this method.";
59  
60    /**
61     * The actual FieldHandler to delegate to
62     */
63    private FieldHandler _handler = null;
64  
65    /**
66     * The flag controlling automatic collection iteration during convertUponGet
67     */
68    private boolean _autoCollectionIteration = true;
69  
70  
71    /**
72     * Creates a new default GeneralizedFieldHandler. This method should be called by all extending
73     * classes so that any important initialization code will be executed.
74     */
75    protected GeneralizedFieldHandler() {
76      super();
77      // -- currently nothing to do, but initialization
78      // -- code may be needed in the future
79    } // -- GeneralizedFieldHandler
80  
81  
82    /**
83     * This method is used to convert the value when the getValue method is called. The getValue
84     * method will obtain the actual field value from given 'parent' object. This convert method is
85     * then invoked with the field's value. The value returned from this method will be the actual
86     * value returned by getValue method.
87     *
88     * @param value the object value to convert after performing a get operation
89     * @return the converted value.
90     */
91    public abstract Object convertUponGet(Object value);
92  
93    /**
94     * This method is used to convert the value when the setValue method is called. The setValue
95     * method will call this method to obtain the converted value. The converted value will then be
96     * used as the value to set for the field.
97     *
98     * @param value the object value to convert before performing a set operation
99     * @return the converted value.
100    */
101   public abstract Object convertUponSet(Object value);
102 
103   /**
104    * Returns the class type for the field that this GeneralizedFieldHandler converts to and from.
105    * This should be the type that is used in the object model.
106    *
107    * @return the class type of of the field
108    */
109   public abstract Class getFieldType();
110 
111   /**
112    * Sets the FieldHandler that this FieldHander delegates to. A call to this method must be made
113    * with a non-null FieldHandler before this GeneralizedFieldHandler can be used.
114    *
115    * @param handler the FieldHandler to delegate to
116    */
117   public final void setFieldHandler(FieldHandler handler) {
118     _handler = handler;
119   } // -- setFieldHandler
120 
121   /**
122    * Sets whether or not this GeneralizedFieldHandler should automatically iterate over the
123    * collection returned by the target object and pass only the items (one by one) to the
124    * convertUponGet method.
125    * 
126    * As of Castor 0.9.6 this is true by default.
127    * 
128    * @param autoCollectionIteration a boolean that when true indicates that this
129    *        GeneralizedFieldHandler should automatically iterate over a collection and pass only
130    *        collection items to the convertUponGet method.
131    */
132   public void setCollectionIteration(boolean autoCollectionIteration) {
133     _autoCollectionIteration = autoCollectionIteration;
134   } // -- setCollectionIteration
135 
136   // -----------------------------------------------/
137   // - Methods inherited from AbstractFieldHandler -/
138   // -----------------------------------------------/
139 
140   /**
141    * Returns the value of the field from the object.
142    *
143    * @param object The object
144    * @return The value of the field
145    * @throws IllegalStateException The Java object has changed and is no longer supported by this
146    *         handler, or the handler is not compatiable with the Java object
147    */
148   public final Object getValue(Object object) throws IllegalStateException {
149     if (_handler == null) {
150       throw new IllegalStateException(NULL_HANDLER_ERR);
151     }
152 
153     Object value = _handler.getValue(object);
154     if ((_autoCollectionIteration) && (value != null)) {
155 
156       if (value instanceof java.util.Enumeration) {
157         return new GFHConverterEnumeration(this, (Enumeration) value);
158       }
159       // -- other collection type?
160       if (CollectionHandlers.hasHandler(value.getClass())) {
161         CollectionHandler colHandler = null;
162         try {
163           colHandler = CollectionHandlers.getHandler(value.getClass());
164         } catch (MappingException mx) {
165           throw new IllegalStateException(mx.getMessage());
166         }
167         return new GFHConverterEnumeration(this, colHandler.elements(value));
168       }
169     }
170 
171     return convertUponGet(value);
172   } // -- getValue
173 
174 
175   /**
176    * Creates a new instance of the object described by this field.
177    *
178    * @param parent The object for which the field is created
179    * @return A new instance of the field's value
180    * @throws IllegalStateException This field is a simple type and cannot be instantiated
181    */
182   public Object newInstance(Object parent) throws IllegalStateException {
183     if (_handler == null) {
184       throw new IllegalStateException(NULL_HANDLER_ERR);
185     }
186     return _handler.newInstance(parent);
187   }
188 
189   /**
190    * Creates a new instance of the object described by this field.
191    *
192    * @param parent The object for which the field is created
193    * @param args the set of constructor arguments
194    * @return A new instance of the field's value
195    * @throws IllegalStateException This field is a simple type and cannot be instantiated
196    */
197   public Object newInstance(Object parent, Object[] args) throws IllegalStateException {
198     if (_handler instanceof ExtendedFieldHandler) {
199       return ((ExtendedFieldHandler) _handler).newInstance(parent, args);
200     }
201 
202     // -- backward compatibility: ignore arguments
203     return newInstance(parent);
204   }
205 
206   /**
207    * Sets the value of the field to a default value.
208    * <p>
209    * Reference fields are set to null, primitive fields are set to their default value, collection
210    * fields are emptied of all elements.
211    *
212    * @param object The object
213    * @throws IllegalStateException The Java object has changed and is no longer supported by this
214    *         handler, or the handler is not compatiable with the Java object
215    */
216   public final void resetValue(Object object)
217       throws IllegalStateException, IllegalArgumentException {
218     if (_handler == null) {
219       throw new IllegalStateException(NULL_HANDLER_ERR);
220     }
221     _handler.resetValue(object);
222   }
223 
224   /**
225    * Sets the value of the field on the object.
226    *
227    * @param object The object.
228    * @param value The new value.
229    * @throws IllegalStateException The Java object has changed and is no longer supported by this
230    *         handler, or the handler is not compatiable with the Java object.
231    * @throws IllegalArgumentException The value passed is not of a supported type.
232    */
233   public final void setValue(Object object, Object value)
234       throws IllegalStateException, IllegalArgumentException {
235     if (_handler == null) {
236       throw new IllegalStateException(NULL_HANDLER_ERR);
237     }
238     _handler.setValue(object, convertUponSet(value));
239   }
240 
241   static class GFHConverterEnumeration implements Enumeration {
242 
243     Enumeration _enumeration = null;
244     GeneralizedFieldHandler _handler = null;
245 
246     GFHConverterEnumeration(GeneralizedFieldHandler handler, Enumeration enumeration) {
247       _enumeration = enumeration;
248       _handler = handler;
249     }
250 
251     public boolean hasMoreElements() {
252       return _enumeration.hasMoreElements();
253     }
254 
255     public Object nextElement() {
256       Object value = _enumeration.nextElement();
257       return _handler.convertUponGet(value);
258     }
259 
260 
261   }
262 
263 }
264