/** * Copyright (C) 2010 EdgyTech LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.edgytech.umongo; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.zip.ZipEntry; /** * * @author antoine */ public class PluginClassLoader extends ClassLoader { /** * This is the directory from which the classes will be loaded */ File directory; /** * The constructor. Just initialize the directory */ public PluginClassLoader(File dir) { directory = dir; } /** * A convenience method that calls the 2-argument form of this method */ public Class loadClass(String name) throws ClassNotFoundException { return loadClass(name, true); } /** * This is one abstract method of ClassLoader that all subclasses must * define. Its job is to load an array of bytes from somewhere and to pass * them to defineClass(). If the resolve argument is true, it must also call * resolveClass(), which will do things like verify the presence of the * superclass. Because of this second step, this method may be called to * load superclasses that are system classes, and it must take this into * account. */ public Class loadClass(String classname, boolean resolve) throws ClassNotFoundException { try { // Our ClassLoader superclass has a built-in cache of classes it has // already loaded. So, first check the cache. Class c = findLoadedClass(classname); // After this method loads a class, it will be called again to // load the superclasses. Since these may be system classes, we've // got to be able to load those too. So try to load the class as // a system class (i.e. from the CLASSPATH) and ignore any errors if (c == null) { try { c = findSystemClass(classname); } catch (Exception ex) { } } // If the class wasn't found by either of the above attempts, then // try to load it from a file in (or beneath) the directory // specified when this ClassLoader object was created. Form the // filename by replacing all dots in the class name with // (platform-independent) file separators and by adding the ".class" extension. if (c == null) { // Figure out the filename String filename = classname.replace('.', File.separatorChar) + ".class"; // Create a File object. Interpret the filename relative to the // directory specified for this ClassLoader. File f = new File(directory, filename); // Get the length of the class file, allocate an array of bytes for // it, and read it in all at once. int length = (int) f.length(); byte[] classbytes = new byte[length]; DataInputStream in = new DataInputStream(new FileInputStream(f)); in.readFully(classbytes); in.close(); // Now call an inherited method to convert those bytes into a Class c = defineClass(classname, classbytes, 0, length); } // If the resolve argument is true, call the inherited resolveClass method. if (resolve) { resolveClass(c); } // And we're done. Return the Class object we've loaded. return c; } // If anything goes wrong, throw a ClassNotFoundException error catch (Exception ex) { throw new ClassNotFoundException(ex.toString()); } } public List<Class> loadClasses(JarFile jar) throws ClassNotFoundException, IOException { List<Class> classes = new ArrayList<Class>(); for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements();) { JarEntry entry = e.nextElement(); // System.out.println(entry.getName()); String name = entry.getName(); if (name.endsWith(".class")) { ZipEntry zip = jar.getEntry(entry.getName()); int len = (int) zip.getSize(); byte[] bytes = new byte[len]; DataInputStream is = new DataInputStream(jar.getInputStream(zip)); is.readFully(bytes); Class c = defineClass(name.substring(0, name.indexOf(".")), bytes, 0, len); boolean resolve = true; if (resolve) { resolveClass(c); } classes.add(c); } } return classes; } }