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