Package org.exolab.castor.xml.util

Source Code of org.exolab.castor.xml.util.ClassDescriptorResolverImpl$XCDEnumerator$Entry

/**
* 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-2004 (C) Intalio, Inc. All Rights Reserved.
*
* $Id: ClassDescriptorResolverImpl.java,v 1.6 2004/10/26 02:08:17 kvisco Exp $
*/


package org.exolab.castor.xml.util;


import org.exolab.castor.xml.ClassDescriptorEnumeration;
import org.exolab.castor.xml.ClassDescriptorResolver;
import org.exolab.castor.xml.Introspector;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.XMLClassDescriptor;
import org.exolab.castor.xml.XMLMappingLoader;


import java.util.Hashtable;
import java.util.Enumeration;

/**
* The default implementation of the ClassDescriptorResolver interface
*
* @author <a href="mailto:kvisco-at-intalio.com">Keith Visco</a>
* @version $Revision: 1.6 $ $Date: 2004/10/26 02:08:17 $
*/
public class ClassDescriptorResolverImpl
    implements ClassDescriptorResolver
{
    private static final String DESCRIPTOR_PREFIX = "Descriptor";
    private static final String INTERNAL_CONTAINER_NAME = "-error-if-this-is-used-";

    /**
     * internal cache for class descriptors
     * with the class as the key
     */
    private Hashtable _cacheViaClass = null;
   
    /**
     * internal cache for class descriptors
     * with the xml-name as the key
     */
    private Hashtable _cacheViaName = null;
   
    /**
     * Keeps a list of ClassNotFoundExceptions
     * for faster lookups than using loadClass().
     * hopefully this won't eat up too much
     * memory.
     */
    private Hashtable _classNotFoundList = null;
   
    /**
     * A flag indicating an error has occured
    **/
    private boolean   _error      = false;
   
   
    /**
     * Error message
    **/
    private String    _errMessage = null;
   
    /**
     * The introspector to use, if necessary, to
     * create dynamic ClassDescriptors
     */
    private Introspector _introspector = null;
   
    /**
     * The classloader to use
     */
    private ClassLoader _loader  = null;
   
    /**
     * MappingLoader instance for finding user-defined
     * mappings from a mapping-file
     */
    private XMLMappingLoader _mappingLoader = null;
   
  
   
    /**
     * A flag to indicate the use of introspection
     */
    private boolean _useIntrospection = true;
   
   
    /**
     * Creates a new ClassDescriptorResolverImpl
     */
    public ClassDescriptorResolverImpl() {
        _cacheViaClass = new Hashtable();
        _cacheViaName  = new Hashtable();
    } //-- ClassDescriptorResolverImpl


    /**
     * Creates a new ClassDescriptorResolverImpl with the given ClassLoader
     *
     * @param loader the ClassLoader to use when loading ClassDescriptors
     */
    public ClassDescriptorResolverImpl(ClassLoader loader) {
        this();
        _loader = loader;
    } //-- ClassDescriptorResolverImpl

   
    /**
     * Associates (or binds) a class type with a given ClassDescriptor
     *
     * @param type the Class to associate with the given descriptor
     * @param classDesc the ClassDescriptor to associate the given
     * class with
     */
    public void associate(Class type, XMLClassDescriptor classDesc) {
       
        if (type == null) {
            throw new IllegalArgumentException("argument 'type' must not be null.");
        }
       
        //-- handle remove
        if (classDesc == null) {
            if (type != null) {
                _cacheViaClass.remove(type);
            }
        }
        else {
            _cacheViaClass.put(type, classDesc);
            String xmlName = classDesc.getXMLName();
            if ((xmlName != null) && (xmlName.length() > 0)) {
                if (!INTERNAL_CONTAINER_NAME.equals(xmlName)) {
                    String nameKey = xmlName;
                    String ns = classDesc.getNameSpaceURI();            
                    if ((ns != null) && (ns.length() > 0)) {
                        nameKey = ns + ':' + xmlName;
                    }
                    _cacheViaName.put(nameKey, classDesc);
                }
            }
        }
    } //-- associate
   
    /**
     * Returns the last error message generated
     * If no error String exists, null will be returned
     * @return the last error message generated.
     * If no error String exists, null will be returned
    **/
    public String getErrorMessage() {
        return _errMessage;
    } //-- getErrorMessage
   
    /**
     * Returns the Introspector being used by this ClassDescriptorResolver.
     * This allows for configuration of the Introspector.
     *
     * @return the Introspector being used by this ClassDescriptorResolver
    **/
    public Introspector getIntrospector() {
        if (_introspector == null)
            _introspector = new Introspector();
        return _introspector;
    } //-- getIntrospector
   
    public XMLMappingLoader getMappingLoader() {
        return _mappingLoader;
    } //-- getXMLMappingLoader
   
    /**
     * Returns true if an error was generated on the last call
     * to one of the resolve methods
     * @return true if an error was generated on the last call
     * to one of the resolve methods
    **/
    public boolean error() {
        return _error;
    } //-- error
   
    /**
     * Returns the XMLClassDescriptor for the given class
     * @param type the Class to find the XMLClassDescriptor for
     * @return the XMLClassDescriptor for the given class
    **/
    public XMLClassDescriptor resolve(Class type) {
       
        clearError();

        if (type == null) return null;
       
        XMLClassDescriptor classDesc = (XMLClassDescriptor) _cacheViaClass.get(type);
       
        if (classDesc != null) return classDesc;

        //-- check mapping loader first
        //-- [proposed by George Stewart]
        if (_mappingLoader != null) {           
            classDesc = (XMLClassDescriptor)_mappingLoader.getDescriptor(type);
            if (classDesc != null) {
               _cacheViaClass.put(type, classDesc);
               return classDesc;
            }
        }
      
        
        String className = type.getName() + DESCRIPTOR_PREFIX;
        try {
            ClassLoader loader = type.getClassLoader();
            Class dClass = loadClass(className, loader);           
            classDesc = (XMLClassDescriptor) dClass.newInstance();
            _cacheViaClass.put(type, classDesc);
        }
        catch(ClassNotFoundException cnfe) {
            /*
             This is ok, since we are just checking if the
             Class exists...if not we create one.
            */
        }
        catch(Exception ex) {
            String err = "instantiation error for class: " + className;
            err += "; " + ex.toString();
            setError(err);
            return null;
        }
       
        //-- create classDesc automatically if necessary
        if ((classDesc == null) && _useIntrospection) {
            try {
                classDesc = getIntrospector().generateClassDescriptor(type);
                if (classDesc != null) {
                    _cacheViaClass.put(type, classDesc);
                }
            }
            catch (MarshalException mx) {
                String err = mx.toString();
                setError(err);
                return null;
            }
        }
        return classDesc;
    } //-- resolve
   
    /**
     * Returns the XMLClassDescriptor for the given class name
     * @param className the class name to find the XMLClassDescriptor for
     * @return the XMLClassDescriptor for the given class name
    **/
    public XMLClassDescriptor resolve(String className) {
        return resolve(className, null);
    } //-- resolve(String)
   
    /**
     * Returns the XMLClassDescriptor for the given class name
     * @param className the class name to find the XMLClassDescriptor for
     * @param loader the ClassLoader to use
     * @return the XMLClassDescriptor for the given class name
    **/
    public XMLClassDescriptor resolve(String className, ClassLoader loader) {
       
        XMLClassDescriptor classDesc = null;
       
        if ((className == null) || (className.length() == 0)) {
            clearError(); //-- clear previous error flag
            setError("Cannot resolve a null or zero-length class name.");
            return null;
        }
           
        //-- first check mapping loader
        if (_mappingLoader != null) {
            classDesc = (XMLClassDescriptor)_mappingLoader.getDescriptor(className);
            if (classDesc != null)
                return classDesc;
        }
       
        //-- try and load class to check cache,
        Class _class = null;
        try {
            _class = loadClass(className, loader);
        }
        catch(ClassNotFoundException cnfe) {
            //-- save exception, for future calls with
            //-- the same classname
            if (_classNotFoundList == null)
                _classNotFoundList = new Hashtable();
            _classNotFoundList.put(className, cnfe);
        }
       
        if (_class != null) {
            classDesc = resolve(_class);
        }
        else clearError(); //-- clear error flag
       
        //-- try to load ClassDescriptor with no class being
        //-- present...does this make sense?
        if ((classDesc == null) && (_class == null)) {
            String dClassName = className+DESCRIPTOR_PREFIX;
            try {
              Class dClass = loadClass(dClassName, loader);
                classDesc = (XMLClassDescriptor) dClass.newInstance();
                if (classDesc.getJavaClass() != null) {
                    associate(classDesc.getJavaClass(), classDesc);
                }
            }
            catch(InstantiationException ie) { 
                //-- do nothing for now
            }
            catch(IllegalAccessException iae)  {
                //-- do nothing for now
            }
            catch(ClassNotFoundException cnfe) {
                //-- save exception, for future calls with
                //-- the same classname
                if (_classNotFoundList == null)
                    _classNotFoundList = new Hashtable();
                _classNotFoundList.put(className, cnfe);
            }
        }
        return classDesc;
    } //-- resolve(String, ClassLoader)
   
    /**
     * Returns the first XMLClassDescriptor that matches the given
     * XML name and namespaceURI. Null is returned if no descriptor
     * can be found.
     *
     * @param className the class name to find the XMLClassDescriptor for
     * @param loader the ClassLoader to use
     * @return the XMLClassDescriptor for the given XML name
    **/
    public XMLClassDescriptor resolveByXMLName
        (String xmlName, String namespaceURI, ClassLoader loader)
    {
        if ((xmlName == null) || (xmlName.length() == 0)) {
            clearError(); //-- clear previous error flag
            setError("Cannot resolve a null or zero-length xml name.");
            return null;
        }
       
       
        XMLClassDescriptor classDesc = null;
        Enumeration enumeration             = null;
       
        //-- check name cache first...
        String nameKey = xmlName;
        if ((namespaceURI != null) && (namespaceURI.length() > 0))
            nameKey = namespaceURI + ':' + xmlName;
           
        classDesc = (XMLClassDescriptor)_cacheViaName.get(nameKey);
        if(classDesc != null)
            return classDesc;

        //-- next check mapping loader...
        XMLClassDescriptor possibleMatch = null;
        if (_mappingLoader != null) {
            enumeration = _mappingLoader.listDescriptors();
            while (enumeration.hasMoreElements()) {
                classDesc = (XMLClassDescriptor)enumeration.nextElement();
                if (xmlName.equals(classDesc.getXMLName())) {
                    if (namespaceEquals(namespaceURI, classDesc.getNameSpaceURI())) {
                        _cacheViaName.put(nameKey, classDesc);
                        return classDesc;
                    }
                    possibleMatch = classDesc;
                }
                classDesc = null;
            }
        }
       
        //-- next look in local cache
        enumeration = _cacheViaClass.elements();
        while (enumeration.hasMoreElements()) {
            classDesc = (XMLClassDescriptor)enumeration.nextElement();
            if (xmlName.equals(classDesc.getXMLName())) {
                if (namespaceEquals(namespaceURI, classDesc.getNameSpaceURI())) {
                    _cacheViaName.put(nameKey, classDesc);
                    return classDesc;
                }
                if (possibleMatch == null)
                    possibleMatch = classDesc;
                else if (possibleMatch != classDesc) {
                    //-- too many possible matches, return null.
                    possibleMatch = null;
                }
            }
            classDesc = null;
        }
       
        if (classDesc == null)
            classDesc = possibleMatch;
           
        return classDesc;
  
    } //-- resolveByXMLName

    /**
     * Returns an enumeration of XMLClassDescriptor objects that
     * match the given xml name
     *
     * @param className the class name to find the XMLClassDescriptor for
     * @param loader the ClassLoader to use
     * @return an enumeration of XMLClassDescriptor objects.
    **/
    public ClassDescriptorEnumeration resolveAllByXMLName
        (String xmlName, String namespaceURI, ClassLoader loader)
    {
        if ((xmlName == null) || (xmlName.length() == 0)) {
            clearError(); //-- clear previous error flag
            setError("Cannot resolve a null or zero-length xml name.");
            return null;
        }
       
        XCDEnumerator xcdEnumerator  = new XCDEnumerator();
        XMLClassDescriptor classDesc = null;
        Enumeration enumeration             = null;
       
        //-- check mapping loader first
        if (_mappingLoader != null) {
            enumeration = _mappingLoader.listDescriptors();
            while (enumeration.hasMoreElements()) {
                classDesc = (XMLClassDescriptor)enumeration.nextElement();
                if (xmlName.equals(classDesc.getXMLName())) {
                    xcdEnumerator.add(classDesc);
                }
            }
        }
       
        //-- next look in local cache
        enumeration = _cacheViaClass.elements();
        while (enumeration.hasMoreElements()) {
            classDesc = (XMLClassDescriptor)enumeration.nextElement();
            if (xmlName.equals(classDesc.getXMLName())) {
                xcdEnumerator.add(classDesc);
            }
        }
       
        return xcdEnumerator;
       
    } //-- resolveByXMLName
   
   
    /**
     * Sets the ClassLoader to use when loading class descriptors
     * @param loader the ClassLoader to use
    **/
    public void setClassLoader(ClassLoader loader) {
        this._loader = loader;
    } //-- setClassLoader
   
    /**
     * Enables or disables introspection. Introspection is
     * enabled by default.
     *
     * @param enable a flag to indicate whether or not introspection
     * is allowed.
    **/
    public void setIntrospection(boolean enable) {
        _useIntrospection = enable;
    } //-- setIntrospection
   
    public void setMappingLoader(XMLMappingLoader mappingLoader) {
        _mappingLoader = mappingLoader;
    } //-- setMappingLoader
   
    //-------------------/
    //- Private Methods -/
    //-------------------/
   
    /**
     * Loads and returns the class with the given class name using the
     * given loader.
     * @param className the name of the class to load
     * @param loader the ClassLoader to use, this may be null.
    **/
    private Class loadClass(String className, ClassLoader loader)
        throws ClassNotFoundException
    {
        //-- for performance, check the classNotFound list
        //-- first to prevent searching through all the
        //-- possible classpaths etc for something we
        //-- already know doesn't exist.
        //-- check classNotFoundList
        if (_classNotFoundList != null) {
            Object exception = _classNotFoundList.get(className);
            if (exception != null)
                throw (ClassNotFoundException)exception;
        }
       
        try {
            //-- use passed in loader
          if ( loader != null )
            return loader.loadClass(className);
        //-- use internal loader
        else if (_loader != null)
            return _loader.loadClass(className);
        //-- no loader available use Class.forName
        return Class.forName(className);
        }
        catch(NoClassDefFoundError ncdfe) {
            //-- This can happen if we try to load a class with invalid case,
            //-- for example foo instead Foo.
            throw new ClassNotFoundException(ncdfe.getMessage());
        }
    } //-- loadClass
   
    /**
     * Clears the error flag
    **/
    private void clearError() {
        _error = false;
    } //-- clearError
   
    /**
     * Sets the current error message to the given String
     * @param message the error message
    **/
    private void setError(String message) {
        _error = true;
        _errMessage = message;
    } //-- setError
   
   
    /**
     * Compares the two strings for equality. A Null and empty
     * strings are considered equal.
     *
     * @return true if the two strings are considered equal.
     */
    private boolean namespaceEquals(String ns1, String ns2) {
        if (ns1 == null) {
            return ((ns2 == null) || (ns2.length() == 0));
        }
       
        if (ns2 == null) {
            return (ns1.length() == 0);
        }
       
        return ns1.equals(ns2);
    } //-- namespaceEquals

    /**
     * A locally used implementation of ClassDescriptorEnumeration
     */
    class XCDEnumerator implements ClassDescriptorEnumeration {
       
        private Entry _current = null;
       
        private Entry _last = null;
       
        /**
        * Creates an XCDEnumerator
        **/
        XCDEnumerator() {
            super();
        } //-- XCDEnumerator
       
        /**
        * Adds the given XMLClassDescriptor to this XCDEnumerator
        **/
        protected void add(XMLClassDescriptor classDesc) {
            Entry entry = new Entry();
            entry.classDesc = classDesc;
            if (_current == null) {
                _current = entry;
                _last    = entry;
            }
            else {
                _last.next = entry;
                _last = entry;
            }
        } //-- add
       
        /**
        * Returns true if there are more XMLClassDescriptors
        * available.
        *
        * @return true if more XMLClassDescriptors exist within this
        * enumeration.
        **/
        public boolean hasNext() {
            return (_current != null);
        } //-- hasNext
       
        /**
        * Returns the next XMLClassDescriptor in this enumeration.
        *
        * @return the next XMLClassDescriptor in this enumeration.
        **/
        public XMLClassDescriptor getNext() {
            if (_current == null) return null;
            Entry entry = _current;
            _current = _current.next;
            return entry.classDesc;
        } //-- getNext
           
        class Entry {
            XMLClassDescriptor classDesc = null;
            Entry next = null;
        }
       
    } //-- ClassDescriptorEnumeration
   
} //-- ClassDescriptorResolverImpl




TOP

Related Classes of org.exolab.castor.xml.util.ClassDescriptorResolverImpl$XCDEnumerator$Entry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.