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 (C) Intalio, Inc. All Rights Reserved.
42 *
43 * Portions of this file developed by Keith Visco after Jan 19 2005 are
44 * Copyright (C) 2005 Keith Visco. All Rights Reserverd.
45 *
46 * $Id$
47 */
48 package org.exolab.castor.xml.handlers;
49
50 import java.lang.reflect.Array;
51 import java.lang.reflect.InvocationTargetException;
52 import java.lang.reflect.Method;
53 import java.lang.reflect.Modifier;
54
55 import org.exolab.castor.mapping.FieldHandler;
56 import org.exolab.castor.mapping.ValidityException;
57
58 /**
59 * A specialized FieldHandler for the XML Schema enumeration types.
60 *
61 * @author <a href="keith AT kvisco DOT com">Keith Visco</a>
62 * @version $Revision$ $Date: 2006-04-13 06:47:36 -0600 (Thu, 13 Apr 2006) $
63 */
64 public class EnumFieldHandler implements FieldHandler {
65
66 /** Used to find the method "valueOf" taking an argument of type String. */
67 private static final Class[] STRING_ARGS = new Class[] {String.class};
68 /** The Factory Method name. */
69 private static final String METHOD_VALUEOF = "valueOf";
70 private static final String METHOD_FROMVALUE = "fromValue";
71 private static final String METHOD_VALUE = "value";
72 private static final String METHOD_TOSTRING = "toString";
73
74 /** The <code>valueOf(String)</code> method for the provided enumtype. */
75 private final Method _valueOf;
76 /** The field handler to which we delegate. */
77 private final FieldHandler _handler;
78
79 //----------------/
80 //- Constructors -/
81 //----------------/
82
83 /**
84 * Creates a new EnumFieldHandler with the given type and FieldHandler.
85 *
86 * @param enumType the Class type of the described field
87 * @param handler the FieldHandler to delegate to
88 */
89 public EnumFieldHandler(final Class enumType, final FieldHandler handler) {
90 this._handler = handler;
91 this._valueOf = getUnmarshallMethod(enumType);
92 } //-- EnumFieldHandler
93
94 /**
95 * Reflectively finds the <code>valueOf(String)</code> method for the
96 * provided class type.
97 *
98 * @param type the Class for which to locate the valueOf method.
99 * @return the Method <code>valueOf(String)</code>
100 */
101 private Method getUnmarshallMethod(final Class type) {
102 if (type == null) {
103 String err = "The Class argument passed to the "
104 + "constructor of EnumMarshalDescriptor cannot be null.";
105 throw new IllegalArgumentException(err);
106 }
107
108 Method method = null;
109
110 // try the fromValue method to support enums with value object
111 try {
112 method = type.getMethod(METHOD_FROMVALUE, STRING_ARGS);
113 return method;
114 } catch(NoSuchMethodException exception) {
115 // do nothing, check valueOf
116 }
117
118 //
119 try {
120 method = type.getMethod(METHOD_VALUEOF, STRING_ARGS);
121 } catch (NoSuchMethodException nsme) {
122 String err = type.getName()
123 + " does not contain one of the required methods public static "
124 + type.getName() + " valueOf(String); " +
125 "or public static " + type.getName() + ".fromvalue(String value)";
126 throw new IllegalArgumentException(err);
127 }
128
129 if (!Modifier.isStatic(method.getModifiers())) {
130 String err = type.getName() + " public " + type.getName()
131 + " valueOf(String); exists but is not static";
132 throw new IllegalArgumentException(err);
133 }
134 return method;
135 }
136
137 private Method getMarshallMethod(final Class type) {
138 if (type == null) {
139 String err = "The Class argument passed to the "
140 + "constructor of EnumMarshalDescriptor cannot be null.";
141 throw new IllegalArgumentException(err);
142 }
143
144 Method method = null;
145
146 // try the value() method to support enums with value object
147 try {
148 method = type.getMethod(METHOD_VALUE, null);
149 return method;
150 } catch(NoSuchMethodException exception) {
151 // do nothing, use toString
152 }
153
154 //
155 try {
156 method = type.getMethod(METHOD_TOSTRING, null);
157 } catch (NoSuchMethodException nsme) {
158 String err = type.getName()
159 + " does not contain one of the required methods value() or toString() ";
160 throw new IllegalArgumentException(err);
161 }
162
163 return method;
164 }
165
166 //------------------/
167 //- Public Methods -/
168 //------------------/
169
170 /**
171 * Returns the value of the field associated with this descriptor from the
172 * given target object.
173 *
174 * @param target the object to get the value from
175 * @return the value of the field associated with this descriptor from the
176 * given target object.
177 * @throws IllegalStateException The Java object has changed and is no
178 * longer supported by this handler, or the handler is not
179 * compatible with the Java object
180 */
181 public Object getValue(final Object target) throws java.lang.IllegalStateException {
182 Object val = _handler.getValue(target);
183 if (val == null) {
184 return val;
185 }
186
187 Object result = null;
188 if (val.getClass().isArray()) {
189 int size = Array.getLength(val);
190 String[] values = new String[size];
191
192 for (int i = 0; i < size; i++) {
193 Object obj = Array.get(val, i);
194 try {
195 values[i] = (String) getMarshallMethod(obj.getClass()).invoke(obj, null);
196 } catch (Exception e) {
197 throw new IllegalStateException(e.toString());
198 }
199 }
200 result = values;
201 } else {
202 try {
203 result = getMarshallMethod(val.getClass()).invoke(val, null);
204 } catch (Exception e) {
205 throw new IllegalStateException(e.toString());
206 }
207 }
208 return result;
209 } //-- getValue
210
211 /**
212 * Sets the value of the field associated with this descriptor.
213 *
214 * @param target the object in which to set the value
215 * @param value the value of the field
216 * @throws IllegalStateException The Java object has changed and is no
217 * longer supported by this handler, or the handler is not
218 * compatible with the Java object.
219 */
220 public void setValue(final Object target, final Object value)
221 throws java.lang.IllegalStateException {
222 Object obj = null;
223 if (value != null) {
224 Object[] args = new String[1];
225 args[0] = value.toString();
226 try {
227 obj = _valueOf.invoke(null, args);
228 } catch (java.lang.reflect.InvocationTargetException ite) {
229 Throwable toss = ite.getTargetException();
230 throw new IllegalStateException(toss.toString());
231 } catch (java.lang.IllegalAccessException iae) {
232 throw new IllegalStateException(iae.toString());
233 }
234 }
235 _handler.setValue(target, obj);
236 } //-- setValue
237
238 /**
239 * Sets the value of the field to a default value -- for enum, no action
240 * needed.
241 *
242 * @param target The object.
243 */
244 public void resetValue(final Object target) {
245 // No action needed
246 }
247
248 /**
249 * Checks the field validity. Returns successfully if the field can be
250 * stored, is valid, etc, throws an exception otherwise.
251 *
252 * @param object The object
253 * @throws ValidityException The field is invalid, is required and null, or
254 * any other validity violation
255 * @throws IllegalStateException The Java object has changed and is no
256 * longer supported by this handler, or the handler is not
257 * compatiable with the Java object
258 */
259 public void checkValidity(final Object object) throws ValidityException, IllegalStateException {
260 //-- do nothing for now
261 } //-- checkValidity
262
263 /**
264 * Creates a new instance of the object described by this field.
265 *
266 * @param parent The object for which the field is created
267 * @return A new instance of the field's value
268 * @throws IllegalStateException This field is a simple type and cannot be
269 * instantiated
270 */
271 public Object newInstance(final Object parent) throws IllegalStateException {
272 return "";
273 } //-- newInstance
274
275 /**
276 * Returns true if the given object is an XMLFieldHandler that is equivalent
277 * to the delegated handler. An equivalent XMLFieldHandler is an
278 * XMLFieldHandler that is an instances of the same class.
279 *
280 * @return true if the given object is an XMLFieldHandler that is equivalent
281 * to this one.
282 */
283 public boolean equals(final Object obj) {
284 if (obj == null) {
285 return false;
286 }
287 if (obj == this) {
288 return true;
289 }
290 if (!(obj instanceof FieldHandler)) {
291 return false;
292 }
293 return (_handler.getClass().isInstance(obj) || getClass().isInstance(obj));
294 } //-- equals
295
296 } //-- EnumFieldHandler