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