001: /**
002: * Redistribution and use of this software and associated documentation
003: * ("Software"), with or without modification, are permitted provided
004: * that the following conditions are met:
005: *
006: * 1. Redistributions of source code must retain copyright
007: * statements and notices. Redistributions must also contain a
008: * copy of this document.
009: *
010: * 2. Redistributions in binary form must reproduce the
011: * above copyright notice, this list of conditions and the
012: * following disclaimer in the documentation and/or other
013: * materials provided with the distribution.
014: *
015: * 3. The name "Exolab" must not be used to endorse or promote
016: * products derived from this Software without prior written
017: * permission of Intalio, Inc. For written permission,
018: * please contact info@exolab.org.
019: *
020: * 4. Products derived from this Software may not be called "Exolab"
021: * nor may "Exolab" appear in their names without prior written
022: * permission of Intalio, Inc. Exolab is a registered
023: * trademark of Intalio, Inc.
024: *
025: * 5. Due credit should be given to the Exolab Project
026: * (http://www.exolab.org/).
027: *
028: * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
029: * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
030: * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
031: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
032: * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
033: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
034: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
035: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
036: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
037: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
038: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
039: * OF THE POSSIBILITY OF SUCH DAMAGE.
040: *
041: * Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved.
042: *
043: * $Id: CollectionHandlers.java 6230 2006-09-19 07:56:07Z wguttmn $
044: */package org.exolab.castor.mapping.loader;
045:
046: import java.util.Vector;
047: import java.util.Enumeration;
048: import java.util.NoSuchElementException;
049: import java.util.StringTokenizer;
050: import java.io.Serializable;
051: import java.lang.reflect.Method;
052: import org.exolab.castor.mapping.MappingException;
053: import org.exolab.castor.mapping.CollectionHandler;
054: import org.exolab.castor.util.LocalConfiguration;
055:
056: /**
057: * Utility class for obtaining collection handlers. Based on the
058: * configuration and supported classes it will return collections
059: * suitable for Java 1.1 and Java 1.2 run times.
060: *
061: * @author <a href="arkin@intalio.com">Assaf Arkin</a>
062: * @version $Revision: 6230 $ $Date: 2005-05-02 14:58:59 -0600 (Mon, 02 May 2005) $
063: * @see CollectionHandler
064: */
065: public final class CollectionHandlers {
066:
067: // For JDK 1.1 compatilibity
068: private static Class _collectionClass = null;
069: private static boolean _loadedCollectionClass = false;
070:
071: /**
072: * Returns the collection's Java class from the collection name.
073: * The collection name may be a short name (e.g. <tt>vector</tt>)
074: * or the collection Java class name (e.g. <tt>java.util.Vector</tt>).
075: * If the collection is not supported, an exception is thrown.
076: *
077: * @param name The collection name
078: * @return The collection Java class
079: * @throws MappingException The named collection is not supported
080: */
081: public static Class getCollectionType(String name)
082: throws MappingException {
083: if (_info == null)
084: loadInfo();
085: for (int i = 0; i < _info.length; ++i)
086: if (_info[i].shortName.equalsIgnoreCase(name)
087: || _info[i].javaClass.getName().equals(name))
088: return _info[i].javaClass;
089: //throw new MappingException( "mapping.noCollectionHandler", name );
090:
091: //-- Fix for JDK 1.1 compatibility
092: // old code: return Collection.class;
093: if (!_loadedCollectionClass) {
094: _loadedCollectionClass = true;
095: try {
096: _collectionClass = Class
097: .forName("java.util.Collection");
098: } catch (ClassNotFoundException cnfe) {
099: // Do nothing we are just here for JDK 1.1
100: // compatibility
101: }
102: }
103: return _collectionClass;
104: }
105:
106: /**
107: * Returns true if the given class has an associated CollectionHandler.
108: *
109: * @param javaClass the class to search collection handlers for
110: * @return true if the given class has an associated CollectionHandler,
111: * otherwise false.
112: */
113: public static boolean hasHandler(Class javaClass) {
114:
115: if (_info == null)
116: loadInfo();
117:
118: //-- Adjust javaClass for arrays, needed for arrays of
119: //-- primitives, except for byte[] which shouldn't
120: //-- use a collection handler
121: if (javaClass.isArray()) {
122: if (javaClass.getComponentType() != Byte.TYPE)
123: javaClass = Object[].class;
124: }
125:
126: for (int i = 0; i < _info.length; ++i)
127: if (_info[i].javaClass.isAssignableFrom(javaClass))
128: return true;
129:
130: return false;
131:
132: } //-- hasHandler
133:
134: /**
135: * Returns the associated string name for a given collection.
136: *
137: * @param javaClass the class to search collection handlers for
138: * @return the string name for the given collection type or null
139: * if no association has been defined.
140: */
141: public static String getCollectionName(Class javaClass) {
142:
143: if (_info == null)
144: loadInfo();
145:
146: //-- Adjust javaClass for arrays, needed for arrays of
147: //-- primitives, except for byte[] which shouldn't
148: //-- use a collection handler
149: if (javaClass.isArray()) {
150: if (javaClass.getComponentType() != Byte.TYPE)
151: javaClass = Object[].class;
152: }
153:
154: //-- First check direct class equality, to provide a better match
155: //-- (for example in JDK 1.2 a Vector is also a Collection)
156: for (int i = 0; i < _info.length; ++i)
157: if (_info[i].javaClass.equals(javaClass))
158: return _info[i].shortName;
159:
160: //-- handle Possible inheritence
161: for (int i = 0; i < _info.length; ++i)
162: if (_info[i].javaClass.isAssignableFrom(javaClass))
163: return _info[i].shortName;
164:
165: return null;
166:
167: } //-- hasHandler
168:
169: /**
170: * Returns the collection's handler based on the Java class.
171: *
172: * @param javaClass The collection's Java class
173: * @return The collection handler
174: * @throws MappingException The collection class is not supported
175: */
176: public static CollectionHandler getHandler(Class javaClass)
177: throws MappingException {
178: if (_info == null)
179: loadInfo();
180:
181: //-- Adjust javaClass for arrays, needed for arrays of
182: //-- primitives, except for byte[] which shouldn't
183: //-- use a collection handler
184: if (javaClass.isArray()) {
185: if (javaClass.getComponentType() != Byte.TYPE)
186: javaClass = Object[].class;
187: }
188:
189: //-- First check direct class equality, to provide a better match
190: //-- (for example in JDK 1.2 a Vector is also a Collection)
191: for (int i = 0; i < _info.length; ++i)
192: if (_info[i].javaClass.equals(javaClass))
193: return _info[i].handler;
194:
195: //-- handle Possible inheritence
196: for (int i = 0; i < _info.length; ++i)
197: if (_info[i].javaClass.isAssignableFrom(javaClass))
198: return _info[i].handler;
199:
200: throw new MappingException("mapping.noCollectionHandler",
201: javaClass.getName());
202: }
203:
204: /**
205: * Returns true if the collection requires get/set methods.
206: * <tt>java.util</tt> collections only require a get method,
207: * but an array collection required both get and set methods.
208: *
209: * @param javaClass The collection's java class
210: * @return True if collection requires get/set methods, false
211: * if collection requires only get method
212: * @throws MappingException The collection class is not supported
213: */
214: public static boolean isGetSetCollection(Class javaClass)
215: throws MappingException {
216: if (_info == null)
217: loadInfo();
218: for (int i = 0; i < _info.length; ++i)
219: if (_info[i].javaClass.equals(javaClass))
220: return _info[i].getSetCollection;
221: throw new MappingException("mapping.noCollectionHandler",
222: javaClass.getName());
223: }
224:
225: /**
226: * Called once to load collection handler information for the various
227: * collection handlers (Java 1.1, Java 1.2) based on the configuration
228: * file.
229: */
230: private static synchronized void loadInfo() {
231: if (_info == null) {
232: Vector allInfo;
233: Info[] info;
234: StringTokenizer tokenizer;
235: Class infoClass;
236: Method method;
237:
238: allInfo = new Vector();
239: LocalConfiguration config = LocalConfiguration
240: .getInstance();
241: tokenizer = new StringTokenizer(config.getProperty(
242: "org.exolab.castor.mapping.collections", ""), ", ");
243: while (tokenizer.hasMoreTokens()) {
244: try {
245: if (CollectionHandlers.class.getClassLoader() != null)
246: infoClass = CollectionHandlers.class
247: .getClassLoader().loadClass(
248: tokenizer.nextToken());
249: else
250: infoClass = Class
251: .forName(tokenizer.nextToken());
252: method = infoClass
253: .getMethod("getCollectionHandlersInfo",
254: (Class[]) null);
255: info = (Info[]) method
256: .invoke(null, (Object[]) null);
257: for (int i = 0; i < info.length; ++i)
258: allInfo.addElement(info[i]);
259: } catch (Exception except) {
260: // System.err.println( "CollectionHandlers: " + except.toString() );
261: }
262: }
263: _info = new Info[allInfo.size()];
264: allInfo.copyInto(_info);
265: }
266: }
267:
268: private static Info[] _info;
269:
270: static class Info {
271:
272: /**
273: * The short name of the collection (e.g. <tt>vector</tt>).
274: */
275: final String shortName;
276:
277: /**
278: * The Java class of the collection (e.g. <tt>java.util.Vector</tt>).
279: */
280: final Class javaClass;
281:
282: /**
283: * The collection handler instance.
284: */
285: final CollectionHandler handler;
286:
287: /**
288: * True for collections that require both get and set methods.
289: */
290: final boolean getSetCollection;
291:
292: Info(String shortName, Class javaClass,
293: boolean getSetCollection, CollectionHandler handler) {
294: this .shortName = shortName;
295: this .javaClass = javaClass;
296: this .handler = handler;
297: this .getSetCollection = getSetCollection;
298: }
299:
300: }
301:
302: /**
303: * Enumerator for a null collection.
304: */
305: static final class EmptyEnumerator implements Enumeration,
306: Serializable {
307:
308: public boolean hasMoreElements() {
309: return false;
310: }
311:
312: public Object nextElement() {
313: throw new NoSuchElementException();
314: }
315:
316: }
317:
318: }
|