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-2003 (C) Intalio, Inc. All Rights Reserved.
42 *
43 * $Id$
44 */
45
46 package org.exolab.castor.mapping.loader;
47
48 import java.io.Serializable;
49 import java.lang.reflect.Method;
50 import java.util.Enumeration;
51 import java.util.NoSuchElementException;
52 import java.util.StringTokenizer;
53 import java.util.Vector;
54
55 import org.castor.core.util.AbstractProperties;
56 import org.castor.xml.XMLProperties;
57 import org.exolab.castor.mapping.CollectionHandler;
58 import org.exolab.castor.mapping.MappingException;
59
60 /**
61 * Utility class for obtaining collection handlers. Based on the configuration
62 * and supported classes it will return collections suitable for Java 1.1 and
63 * Java 1.2 run times.
64 *
65 * @author <a href="arkin@intalio.com">Assaf Arkin</a>
66 * @version $Revision$ $Date: 2005-05-02 14:58:59 -0600 (Mon, 02 May
67 * 2005) $
68 * @see CollectionHandler
69 */
70 public final class CollectionHandlers {
71
72 private static Info[] _info;
73
74 // For JDK 1.1 compatilibity
75 private static Class _collectionClass = null;
76 private static boolean _loadedCollectionClass = false;
77
78 static {
79 Vector<Info> allInfo = new Vector<Info>();
80 AbstractProperties properties = XMLProperties.newInstance();
81 StringTokenizer tokenizer = new StringTokenizer(properties.getString(
82 XMLProperties.COLLECTION_HANDLERS_FOR_JAVA_11_OR_12, ""), ", ");
83 while (tokenizer.hasMoreTokens()) {
84 try {
85 Class<?> infoClass;
86 if (CollectionHandlers.class.getClassLoader() != null)
87 infoClass = CollectionHandlers.class.getClassLoader().loadClass(tokenizer.nextToken());
88 else
89 infoClass = Class.forName(tokenizer.nextToken());
90 Method method = infoClass.getMethod("getCollectionHandlersInfo", (Class[]) null);
91 Info[] info = (Info[]) method.invoke(null, (Object[]) null);
92 for (int i = 0; i < info.length; ++i)
93 allInfo.addElement(info[i]);
94 } catch (Exception except) {
95 // System.err.println( "CollectionHandlers: " + except.toString()
96 // );
97 }
98 }
99 _info = new Info[allInfo.size()];
100 allInfo.copyInto(_info);
101 }
102
103 /**
104 * Returns the collection's Java class from the collection name. The
105 * collection name may be a short name (e.g. <tt>vector</tt>) or the
106 * collection Java class name (e.g. <tt>java.util.Vector</tt>). If the
107 * collection is not supported, an exception is thrown.
108 *
109 * @param name
110 * The collection name
111 * @return The collection Java class
112 * @throws MappingException
113 * The named collection is not supported
114 */
115 public static Class<?> getCollectionType(String name) throws MappingException {
116 for (Info info : _info) {
117 if (info.getShortName().equalsIgnoreCase(name) || info.getJavaClass().getName().equals(name)) {
118 return info.getJavaClass();
119 }
120 }
121
122 // for (int i = 0; i < _info.length; ++i) {
123 // if (_info[i].getShortName().equalsIgnoreCase(name) || _info[i].getJavaClass().getName().equals(name)) {
124 // return _info[i].getJavaClass();
125 // // throw new MappingException( "mapping.noCollectionHandler", name);
126 // }
127 // }
128
129 // -- Fix for JDK 1.1 compatibility
130 // old code: return Collection.class;
131 if (!_loadedCollectionClass) {
132 _loadedCollectionClass = true;
133 try {
134 _collectionClass = Class.forName("java.util.Collection");
135 } catch (ClassNotFoundException cnfe) {
136 // Do nothing we are just here for JDK 1.1
137 // compatibility
138 }
139 }
140 return _collectionClass;
141 }
142
143 /**
144 * Returns true if the given class has an associated CollectionHandler.
145 *
146 * @param javaClass
147 * the class to search collection handlers for
148 * @return true if the given class has an associated CollectionHandler,
149 * otherwise false.
150 */
151 public static boolean hasHandler(Class<?> javaClass) {
152 // -- Adjust javaClass for arrays, needed for arrays of
153 // -- primitives, except for byte[] which shouldn't
154 // -- use a collection handler
155 if (javaClass.isArray()) {
156 if (javaClass.getComponentType() != Byte.TYPE)
157 javaClass = Object[].class;
158 }
159
160 for (Info info : _info) {
161 if (info.getJavaClass().isAssignableFrom(javaClass)) {
162 return true;
163 }
164 }
165 // for (int i = 0; i < _info.length; ++i)
166 // if (_info[i].getJavaClass().isAssignableFrom(javaClass))
167 // return true;
168
169 return false;
170
171 }
172
173 /**
174 * Returns the associated string name for a given collection.
175 *
176 * @param javaClass
177 * the class to search collection handlers for
178 * @return the string name for the given collection type or null if no
179 * association has been defined.
180 */
181 public static String getCollectionName(Class<?> javaClass) {
182 // -- Adjust javaClass for arrays, needed for arrays of
183 // -- primitives, except for byte[] which shouldn't
184 // -- use a collection handler
185 if (javaClass.isArray()) {
186 if (javaClass.getComponentType() != Byte.TYPE)
187 javaClass = Object[].class;
188 }
189
190 // -- First check direct class equality, to provide a better match
191 // -- (for example in JDK 1.2 a Vector is also a Collection)
192 for (int i = 0; i < _info.length; ++i)
193 if (_info[i].getJavaClass().equals(javaClass))
194 return _info[i].getShortName();
195
196 // -- handle Possible inheritance
197 for (int i = 0; i < _info.length; ++i)
198 if (_info[i].getJavaClass().isAssignableFrom(javaClass))
199 return _info[i].getShortName();
200
201 return null;
202
203 } // -- hasHandler
204
205 /**
206 * Returns the collection's handler based on the Java class.
207 *
208 * @param javaClass
209 * The collection's Java class
210 * @return The collection handler
211 * @throws MappingException
212 * The collection class is not supported
213 */
214 public static CollectionHandler getHandler(Class<?> javaClass) throws MappingException {
215 // -- Adjust javaClass for arrays, needed for arrays of
216 // -- primitives, except for byte[] which shouldn't
217 // -- use a collection handler
218 if (javaClass.isArray()) {
219 if (javaClass.getComponentType() != Byte.TYPE)
220 javaClass = Object[].class;
221 }
222
223 // -- First check direct class equality, to provide a better match
224 // -- (for example in JDK 1.2 a Vector is also a Collection)
225 for (int i = 0; i < _info.length; ++i)
226 if (_info[i].getJavaClass().equals(javaClass))
227 return _info[i].handler;
228
229 // -- handle Possible inheritence
230 for (int i = 0; i < _info.length; ++i)
231 if (_info[i].getJavaClass().isAssignableFrom(javaClass))
232 return _info[i].handler;
233
234 throw new MappingException("mapping.noCollectionHandler", javaClass.getName());
235 }
236
237 /**
238 * Returns true if the collection requires get/set methods.
239 * <tt>java.util</tt> collections only require a get method, but an array
240 * collection required both get and set methods.
241 *
242 * @param javaClass
243 * The collection's java class
244 * @return True if collection requires get/set methods, false if collection
245 * requires only get method
246 * @throws MappingException
247 * The collection class is not supported
248 */
249 public static boolean isGetSetCollection(Class<?> javaClass) throws MappingException {
250 for (int i = 0; i < _info.length; ++i)
251 if (_info[i].getJavaClass().equals(javaClass))
252 return _info[i].getSetCollection;
253 throw new MappingException("mapping.noCollectionHandler", javaClass.getName());
254 }
255
256 static class Info {
257
258 /**
259 * The short name of the collection (e.g. <tt>vector</tt>).
260 */
261 private final String shortName;
262
263 /**
264 * The Java class of the collection (e.g. <tt>java.util.Vector</tt>).
265 */
266 private final Class<?> javaClass;
267
268 /**
269 * The collection handler instance.
270 */
271 private final CollectionHandler handler;
272
273 /**
274 * True for collections that require both get and set methods.
275 */
276 final boolean getSetCollection;
277
278 Info(String shortName, Class<?> javaClass, boolean getSetCollection, CollectionHandler handler) {
279 this.shortName = shortName;
280 this.javaClass = javaClass;
281 this.handler = handler;
282 this.getSetCollection = getSetCollection;
283 }
284
285 String getShortName() {
286 return shortName;
287 }
288
289 Class<?> getJavaClass() {
290 return javaClass;
291 }
292
293 CollectionHandler getHandler() {
294 return handler;
295 }
296
297 }
298
299 /**
300 * Enumerator for a null collection.
301 */
302 public static final class EmptyEnumerator<T> implements Enumeration<T>, Serializable {
303
304 public boolean hasMoreElements() {
305 return false;
306 }
307
308 public T nextElement() {
309 throw new NoSuchElementException();
310 }
311 }
312
313 }