// (c) MIT 2003.  All rights reserved.

// Copyright (C) 1998 Graham Kirby
// 
// This library is free software; you can redistribute it and/or modify it under the
// terms of the GNU Library General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
// 
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE. See the GNU Library General Public License for more details.
// 
// To receive a copy of the GNU Library General Public License, write to the Free
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.

package rec.util;

import java.io.*;
import java.util.*;

/**
 * Loads classes from <I>.class</I> files in a directory specified at construction time.
 *
 * @author	Graham Kirby (<A HREF="mailto:graham@dcs.st-and.ac.uk">graham@dcs.st-and.ac.uk</A>)
 * @version 1.1 17-Jul-98
 *
 */
public class DirSpecificClassLoader extends ClassLoader {

	/**
	 * The directory from which classes are loaded.
	 */
	private File rootDir;

	/**
	 * Hash table memorising loaded classes.
	 */
	private Hashtable hashtable;

	/**
	 * Dynamic compiler object used to find byte codes in the file system.
	 */
	private DynamicCompiler dynamicCompiler;

	/**
	 * @param rootDir	the directory from which classes are loaded
	 */
	DirSpecificClassLoader (File rootDir, DynamicCompiler dynamicCompiler) {

		this.rootDir = rootDir;
		this.dynamicCompiler = dynamicCompiler;
		hashtable = new Hashtable ();
	}

	/**
	 * Returns the named class, first by checking for an already loaded version, and
	 * then if that fails, attempts to load a <I>.class</I> file from the appropriate directory.
	 * 
	 * @param name		the name of the class to be loaded
	 * @param resolve	flag specifying whether referenced classes should be resolved
	 * @return			the loaded class
	 * @exception		ClassNotFoundException	if the class can not be loaded
	 */
	protected Class loadClass (String name, boolean resolve) throws ClassNotFoundException {

		Class resultClass;

		try {

			// Attempt to access an already loaded version of the class.
			resultClass = findSystemClass (name);
		}
		catch (Exception e1) {

			// Check whether the class has been loaded previously by this class loader.
			Object lookup = hashtable.get (name);

			// If so, return the class from the hash table.
			if (lookup != null) resultClass = (Class) lookup;
			else {
				try {

					// Read the bytes from the appropriate .class file.
					byte[] classBytes = dynamicCompiler.findClassBytes (name, rootDir);

					// Convert the array to a class.
					resultClass = defineClass (name, classBytes, 0, classBytes.length);
				}

				catch (ClassFormatError e2) { throw new ClassNotFoundException( "format of class file incorrect: " + e2.getMessage() ); }
			}
		}

		// Resolve the class if necessary.
		if ( resolve ) resolveClass (resultClass);

		// Memorise the class for any further loading attempts.
		hashtable.put (name, resultClass);

		return resultClass;
	}
}
