/*
 * @(#)UrlClassLoader.java
 *
 * Copyright (C) 2000,2002-2003 Matt Albrecht
 * groboclown@users.sourceforge.net
 * http://groboutils.sourceforge.net
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 */

package net.sourceforge.groboutils.util.classes.v1.jdk2;

import java.net.URL;
import java.net.URLClassLoader;

import java.io.File;
import java.io.IOException;

import java.util.Hashtable;

import net.sourceforge.groboutils.util.classes.v1.IUrlClassLoader;


/**
 * A JDK 1.2+ URL Class Loader implementation.
 * <P>
 * New in version 1.0.0: This will attempt to load from the thread's
 * context loader if the URL is bad.
 *
 * @author  Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
 * @version $Date: 2003/05/06 05:35:01 $
 * @since   November 17, 2000 (GroboUtils Alpha 0.9.0)
 */
public class UrlClassLoader implements IUrlClassLoader
{
    //----------------------------
    // Public data
    
    //----------------------------
    // Private data
    
    private Hashtable m_urlLoaders = new Hashtable();
    
    //----------------------------
    // constructors
    
    /**
    * Default constructor
    */
    public UrlClassLoader()
    {
        // do nothing
    }
    
    
    //----------------------------
    // Public methods
    
    
    /**
     * Load the given class from the given URL.  If the URL is <tt>null</tt>,
     * then it is up to the classloader to figure out where to load it from.
     * This should, in general, load the class from the default class loader.
     *
     * @param className the exact class name to load.
     * @param url the URL from which the class is loaded.  If this is
     *    <tt>null</tt>, then the returned class is implementation specific.
     * @return the loaded Class instance, or <tt>null</tt> if the class could
     *    not be found or if the given URL is not valid.
     */
    public Class loadClass( String className, String url )
    {
        URL murl = convertUrl( url );
        ClassLoader cl = getClassLoader( murl );
        Class c = null;
        
        // Try 5 times to get around time-out issues.
        for (int i = 0; i < 5 && c == null; ++i)
        {
            try
            {
                c = cl.loadClass( className );
            }
            catch (ClassNotFoundException cnfe)
            {
                // ignore
cnfe.printStackTrace();
            }
        }
        return c;
    }
    
    
    /**
     * Call to flush any cache stored in the interface.  This allows for
     * a class loader to cache results, and free up memory when it is
     * not needed.
     */
    public void flush()
    {
        this.m_urlLoaders = new Hashtable();
    }
    
    
    
    //----------------------------
    // Protected methods
    
    
    /**
     * Converts the given string to a fully qualified URL.  If no
     * scheme is given, then it is converted to a File scheme.
     */
    protected URL convertUrl( String url )
    {
        if (url == null)
        {
            return null;
        }
        
        try
        {
            return new URL( url );
        }
        catch (IOException ioe)
        {
            // assume that the string is intended to be a file name.
            try
            {
                return new URL( "file:" + url );
            }
            catch (IOException e)
            {
                return null;
            }
        }
    }
    
    
    /**
     * 
     */
    protected ClassLoader getClassLoader( URL url )
    {
        ClassLoader cl;
        if (url == null)
        {
            cl = Thread.currentThread().getContextClassLoader();
        }
        else
        {
            cl = (URLClassLoader)this.m_urlLoaders.get( url );
            if (cl == null)
            {
                cl = new URLClassLoader( new URL[] { url } );
                this.m_urlLoaders.put( url, cl );
            }
        }
        return cl;
    }
    
    
    //----------------------------
    // Private methods
}
 
