package org.safehaus.penrose.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.safehaus.penrose.Penrose; import java.io.File; import java.io.BufferedInputStream; import java.io.IOException; import java.io.FileInputStream; import java.util.*; import java.util.jar.JarFile; import java.util.jar.JarEntry; import java.net.URL; import java.net.MalformedURLException; /** * Based on example at http://forums.sun.com/thread.jspa?threadID=360060&forumID=31. */ public class PenroseClassLoader extends ClassLoader { protected Logger log = LoggerFactory.getLogger(getClass()); protected Collection<File> classPaths = new ArrayList<File>(); protected Map<String,Class> classes = new LinkedHashMap<String,Class>(); public PenroseClassLoader(ClassLoader parent) { super(parent); } public void setClassPaths(Collection<File> classPaths) { if (this.classPaths == classPaths) return; this.classPaths.clear(); if (classPaths == null) return; this.classPaths.addAll(classPaths); } public Collection<File> getClassPaths() { return classPaths; } public byte[] getClassData(File classPath, String classFileName) throws Exception { if (classPath.isDirectory()) { return getClassDataFromDirectory(classPath, classFileName); } else { return getClassDataFromFile(classPath, classFileName); } } public byte[] getClassDataFromDirectory(File dir, String classFileName) throws Exception { BufferedInputStream is = null; try { File file = new File(dir, classFileName); if (!file.exists()) return null; is = new BufferedInputStream(new FileInputStream(file)); byte[] buffer = new byte[(int)file.length()]; int c = is.read(buffer, 0, buffer.length); if (c < 0) throw new Exception("Error reading "+file.getName()+"."); return buffer; } finally { if (is != null) try { is.close(); } catch (IOException e) { Penrose.errorLog.error(e.getMessage(), e); } } } public byte[] getClassDataFromFile(File file, String classFileName) throws Exception { JarFile jarFile = null; BufferedInputStream is = null; try { jarFile = new JarFile(file); JarEntry jarEntry = (JarEntry)jarFile.getEntry(classFileName); if (jarEntry == null) return null; is = new BufferedInputStream(jarFile.getInputStream(jarEntry)); byte[] buffer = new byte[(int)jarEntry.getSize()]; int c = is.read(buffer, 0, buffer.length); if (c < 0) throw new Exception("Error reading "+ file.getName()+"."); return buffer; } finally { if (is != null) try { is.close(); } catch (IOException e) { Penrose.errorLog.error(e.getMessage(), e); } if (jarFile != null) try { jarFile.close(); } catch (IOException e) { Penrose.errorLog.error(e.getMessage(), e); } } } public byte[] getClassData(String className) { //if (debug) log.debug("Searching for "+className+":"); String classFileName = className.replace('.', '/')+".class"; for (File classPath : classPaths) { try { byte[] buffer = getClassData(classPath, classFileName); if (buffer == null) continue; //if (debug) log.debug("Class "+className+" found in "+classPath+"."); return buffer; } catch (Exception e) { Penrose.errorLog.error(e.getMessage(), e); } } //if (debug) log.debug("Class "+className+" not found."); return null; } public synchronized Class loadClass(String className, boolean resolve) throws ClassNotFoundException { if (classes.containsKey(className)) return classes.get(className); byte[] buffer = getClassData(className); if (buffer == null) return super.loadClass(className, resolve); Class clazz = defineClass(className, buffer, 0, buffer.length); if (clazz == null) throw new ClassFormatError(); if (resolve) resolveClass(clazz); classes.put(className, clazz); return(clazz); } public URL getResourceURL(File classPath, String name) throws Exception { if (classPath.isDirectory()) { return getResourceURLFromDirectory(classPath, name); } else { return getResourceURLFromFile(classPath, name); } } public URL getResourceURLFromDirectory(File dir, String name) throws MalformedURLException { File file = new File(dir, name); if (!file.exists()) return null; return file.toURL(); } public URL getResourceURLFromFile(File file, String name) throws IOException { JarFile jarFile = null; try { jarFile = new JarFile(file); JarEntry jarEntry = (JarEntry)jarFile.getEntry(name); if (jarEntry == null) return null; return new URL("jar:file:"+file+"!/"+name); } finally { if (jarFile != null) try { jarFile.close(); } catch (IOException e) { Penrose.errorLog.error(e.getMessage(), e); } } } public URL findResource(String name) { //boolean debug = log.isDebugEnabled(); //if (debug) log.debug("Searching resource "+name+":"); for (File classPath : classPaths) { try { URL url = getResourceURL(classPath, name); if (url == null) continue; //if (debug) log.debug("URL: "+url); return url; } catch (Exception e) { Penrose.errorLog.error(e.getMessage(), e); } } //if (debug) log.debug("Resource "+name+" not found."); return null; } public Enumeration<URL> findResources(String name) throws IOException { //boolean debug = log.isDebugEnabled(); //if (debug) log.debug("Searching resources "+name+":"); final Collection<URL> urls = new ArrayList<URL>(); for (File classPath : classPaths) { try { URL url = getResourceURL(classPath, name); if (url == null) continue; //if (debug) log.debug("URL: "+url); urls.add(url); } catch (Exception e) { Penrose.errorLog.error(e.getMessage(), e); } } return new Enumeration<URL>() { Iterator<URL> iterator = urls.iterator(); public boolean hasMoreElements() { return iterator.hasNext(); } public URL nextElement() { return iterator.next(); } }; } }