/*
* DirClassLoader.java
*
* Created on 21 August 2004, 21:02
*/
package org.reldb.rel.v0.external;
import java.io.*;
import java.util.*;
import org.reldb.rel.exceptions.*;
/**
* A class loader to load named classes from a specified directory. With
* class unload and class caching.
*
* @author dave
*/
public class DirClassLoader extends ClassLoader {
private static HashMap<String, Class<?>> loaded = new HashMap<String, Class<?>>();
private String dir;
public DirClassLoader(String dir) {
this.dir = dir;
}
/** Unload a given Class. */
public void unload(String name) {
loaded.remove(name);
}
public Class<?> findClass(String name) {
try {
return Class.forName(name);
} catch (ClassNotFoundException cnfe) {
Class<?> c = (Class<?>) loaded.get(name);
if (c == null) {
byte[] b = loadClassData(name);
c = defineClass(name, b, 0, b.length);
loaded.put(name, c);
}
return c;
}
}
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
Class<?> c = findClass(name);
if (resolve)
resolveClass(c);
return c;
}
private File getClassFileName(String name) {
name = name.replace('.', File.separatorChar);
if (dir.endsWith(File.separator))
return new File(dir + name + ".class");
else
return new File(dir + File.separator + name + ".class");
}
private byte[] loadClassData(String name) {
File f = getClassFileName(name);
BytestreamOutputArray bytes = new BytestreamOutputArray();
try {
FileInputStream reader = new FileInputStream(f);
byte[] b = new byte[65535];
while (true) {
int read = reader.read(b);
if (read < 0)
break;
bytes.put(b, 0, read);
}
reader.close();
} catch (FileNotFoundException fnfe) {
throw new ExceptionFatal("RS0290: File " + f + " not found for " + name);
} catch (IOException ioe) {
throw new ExceptionFatal("RS0291: Error reading " + f + ": " + ioe.toString());
}
return bytes.getBytes();
}
/** Get Class for given name. Will check the system loader first, then the specified directory. */
public Class<?> forName(final String name) throws ClassNotFoundException {
// Creation of new ClassLoader allows same class name to be reloaded, as when user
// drops and then re-creates a given user-defined Java-based type.
return new DirClassLoader(dir).loadClass(name);
}
}