/**
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Intalio, Inc. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Intalio, Inc. Exolab is a registered
* trademark of Intalio, Inc.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved.
*
* $Id$
*/
package org.exolab.castor.mapping.loader;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.Vector;
import org.castor.core.util.AbstractProperties;
import org.castor.xml.XMLProperties;
import org.exolab.castor.mapping.CollectionHandler;
import org.exolab.castor.mapping.MappingException;
/**
* Utility class for obtaining collection handlers. Based on the
* configuration and supported classes it will return collections
* suitable for Java 1.1 and Java 1.2 run times.
*
* @author <a href="arkin@intalio.com">Assaf Arkin</a>
* @version $Revision$ $Date: 2005-05-02 14:58:59 -0600 (Mon, 02 May 2005) $
* @see CollectionHandler
*/
public final class CollectionHandlers
{
// For JDK 1.1 compatilibity
private static Class _collectionClass = null;
private static boolean _loadedCollectionClass = false;
/**
* Returns the collection's Java class from the collection name.
* The collection name may be a short name (e.g. <tt>vector</tt>)
* or the collection Java class name (e.g. <tt>java.util.Vector</tt>).
* If the collection is not supported, an exception is thrown.
*
* @param name The collection name
* @return The collection Java class
* @throws MappingException The named collection is not supported
*/
public static Class getCollectionType( String name )
throws MappingException
{
if ( _info == null )
loadInfo();
for ( int i = 0 ; i < _info.length ; ++i )
if ( _info[ i ].shortName.equalsIgnoreCase( name ) ||
_info[ i ].javaClass.getName().equals( name ) )
return _info[ i ].javaClass;
//throw new MappingException( "mapping.noCollectionHandler", name );
//-- Fix for JDK 1.1 compatibility
// old code: return Collection.class;
if (!_loadedCollectionClass) {
_loadedCollectionClass = true;
try {
_collectionClass = Class.forName("java.util.Collection");
}
catch(ClassNotFoundException cnfe) {
// Do nothing we are just here for JDK 1.1
// compatibility
}
}
return _collectionClass;
}
/**
* Returns true if the given class has an associated CollectionHandler.
*
* @param javaClass the class to search collection handlers for
* @return true if the given class has an associated CollectionHandler,
* otherwise false.
*/
public static boolean hasHandler(Class javaClass) {
if ( _info == null )
loadInfo();
//-- Adjust javaClass for arrays, needed for arrays of
//-- primitives, except for byte[] which shouldn't
//-- use a collection handler
if (javaClass.isArray()) {
if (javaClass.getComponentType() != Byte.TYPE)
javaClass = Object[].class;
}
for ( int i = 0 ; i < _info.length ; ++i )
if ( _info[ i ].javaClass.isAssignableFrom( javaClass ) )
return true;
return false;
} //-- hasHandler
/**
* Returns the associated string name for a given collection.
*
* @param javaClass the class to search collection handlers for
* @return the string name for the given collection type or null
* if no association has been defined.
*/
public static String getCollectionName(Class javaClass) {
if ( _info == null )
loadInfo();
//-- Adjust javaClass for arrays, needed for arrays of
//-- primitives, except for byte[] which shouldn't
//-- use a collection handler
if (javaClass.isArray()) {
if (javaClass.getComponentType() != Byte.TYPE)
javaClass = Object[].class;
}
//-- First check direct class equality, to provide a better match
//-- (for example in JDK 1.2 a Vector is also a Collection)
for ( int i = 0 ; i < _info.length ; ++i )
if ( _info[ i ].javaClass.equals( javaClass ) )
return _info[ i ].shortName;
//-- handle Possible inheritence
for ( int i = 0 ; i < _info.length ; ++i )
if ( _info[ i ].javaClass.isAssignableFrom( javaClass ) )
return _info[ i ].shortName;
return null;
} //-- hasHandler
/**
* Returns the collection's handler based on the Java class.
*
* @param javaClass The collection's Java class
* @return The collection handler
* @throws MappingException The collection class is not supported
*/
public static CollectionHandler getHandler( Class javaClass )
throws MappingException
{
if ( _info == null )
loadInfo();
//-- Adjust javaClass for arrays, needed for arrays of
//-- primitives, except for byte[] which shouldn't
//-- use a collection handler
if (javaClass.isArray()) {
if (javaClass.getComponentType() != Byte.TYPE)
javaClass = Object[].class;
}
//-- First check direct class equality, to provide a better match
//-- (for example in JDK 1.2 a Vector is also a Collection)
for ( int i = 0 ; i < _info.length ; ++i )
if ( _info[ i ].javaClass.equals( javaClass ) )
return _info[ i ].handler;
//-- handle Possible inheritence
for ( int i = 0 ; i < _info.length ; ++i )
if ( _info[ i ].javaClass.isAssignableFrom( javaClass ) )
return _info[ i ].handler;
throw new MappingException( "mapping.noCollectionHandler", javaClass.getName() );
}
/**
* Returns true if the collection requires get/set methods.
* <tt>java.util</tt> collections only require a get method,
* but an array collection required both get and set methods.
*
* @param javaClass The collection's java class
* @return True if collection requires get/set methods, false
* if collection requires only get method
* @throws MappingException The collection class is not supported
*/
public static boolean isGetSetCollection( Class javaClass )
throws MappingException
{
if ( _info == null )
loadInfo();
for ( int i = 0 ; i < _info.length ; ++i )
if ( _info[ i ].javaClass.equals( javaClass ) )
return _info[ i ].getSetCollection;
throw new MappingException( "mapping.noCollectionHandler", javaClass.getName() );
}
/**
* Called once to load collection handler information for the various
* collection handlers (Java 1.1, Java 1.2) based on the configuration
* file.
*/
private static synchronized void loadInfo()
{
if ( _info == null ) {
Vector allInfo;
Info[] info;
StringTokenizer tokenizer;
Class infoClass;
Method method;
allInfo = new Vector();
AbstractProperties properties = XMLProperties.newInstance();
tokenizer = new StringTokenizer(properties.getString(XMLProperties.COLLECTION_HANDLERS_FOR_JAVA_11_OR_12, ""), ", ");
// Joachim 2007-09-01 old local configuration is dead!
// LocalConfiguration config = LocalConfiguration.getInstance();
// tokenizer = new StringTokenizer( config.getProperty( "org.exolab.castor.mapping.collections", "" ), ", " );
while ( tokenizer.hasMoreTokens() ) {
try {
if ( CollectionHandlers.class.getClassLoader() != null )
infoClass = CollectionHandlers.class.getClassLoader().loadClass( tokenizer.nextToken() );
else
infoClass = Class.forName( tokenizer.nextToken() );
method = infoClass.getMethod( "getCollectionHandlersInfo", (Class[]) null );
info = (Info[]) method.invoke( null, (Object[]) null );
for ( int i = 0 ; i < info.length ; ++i )
allInfo.addElement( info[ i ] );
} catch ( Exception except ) {
// System.err.println( "CollectionHandlers: " + except.toString() );
}
}
_info = new Info[ allInfo.size() ];
allInfo.copyInto( _info );
}
}
private static Info[] _info;
static class Info
{
/**
* The short name of the collection (e.g. <tt>vector</tt>).
*/
final String shortName;
/**
* The Java class of the collection (e.g. <tt>java.util.Vector</tt>).
*/
final Class javaClass;
/**
* The collection handler instance.
*/
final CollectionHandler handler;
/**
* True for collections that require both get and set methods.
*/
final boolean getSetCollection;
Info( String shortName, Class javaClass, boolean getSetCollection,
CollectionHandler handler )
{
this.shortName = shortName;
this.javaClass = javaClass;
this.handler = handler;
this.getSetCollection = getSetCollection;
}
}
/**
* Enumerator for a null collection.
*/
static final class EmptyEnumerator
implements Enumeration, Serializable
{
public boolean hasMoreElements()
{
return false;
}
public Object nextElement()
{
throw new NoSuchElementException();
}
}
}