content: /**
   * 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;
      }
  }
  