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 }