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 }