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