
/**
 * InstruViewPluginLoader.java
 * Class for loading plugin classes package as jar files.
 * Created: July 3, 2005
 *
 * @author Nathan Stevens
 * @version 0.1 9/5/2006 
 */
import java.util.jar.*;
import java.util.*;
import java.io.*;

public class InstruViewPluginLoader extends ClassLoader {
  public static Hashtable pluginFactories = new Hashtable();
  public static String[] jarFileNames = null;
  private String pluginDirName = null;
  private JarFile jarFile = null;
  
  // the main constructor
  public InstruViewPluginLoader(String pluginDirName, ClassLoader parent) {
    super(parent);
    
    this.pluginDirName = pluginDirName;
    jarFileNames = getJarFileNames();
    
    if(jarFileNames != null && jarFileNames.length != 0) {
      loadPluginClasses(jarFileNames);
    }
    else {
      System.err.println("No plugins found in \"" + pluginDirName + "\"");
    }
  }
  
  // Method that is used to return the plugin jar file name
  public static String getJarFileName(String plugin) {
    String jarname = null;
    for(int i = 0; i < jarFileNames.length; i++) {
      String filename = new String(jarFileNames[i]);
      plugin.toLowerCase();
      filename.toLowerCase();
      
      if(filename.indexOf(plugin) != -1) {
        jarname = jarFileNames[i];
        break;
      }
    }
    
    return jarname;
  }
  
  // Method to get the jar file name
  private String[] getJarFileNames() {
    File pluginDir = new File(pluginDirName);
    String[] filenames = null;
    
    if(pluginDir.isDirectory()) {
      FilenameFilter filter = new FilenameFilter() {
        public boolean accept(File dir, String name) {
          return name.endsWith(".jar");
        }
      };
      filenames = pluginDir.list(filter);
    }
    
    // add the directory to the jar files
    for(int i = 0; i < filenames.length; i++) {
      filenames[i] = pluginDirName + filenames[i];
    }
    
    return filenames;
  }
  
  // Method to load the classes in the jar file
  public void loadPluginClasses(String[] jarFileNames) {
    for(int i = 0; i < jarFileNames.length; i++) {
      //debug code
      //System.out.println("Loading plugin " + (i+1)  + " : \""  + jarFileNames[i] + "\"");
      
      try {
        jarFile = new JarFile(jarFileNames[i]);
        
        // list all the files now and install the classes
        Enumeration entries = jarFile.entries();
        while(entries.hasMoreElements()) {
          String entryName = entries.nextElement().toString();
          
          if(entryName.endsWith(".class")) {
            int index = entryName.indexOf(".class");
            String className = entryName.substring(0, index);
            
            //System.out.println("Class Name is " + className);
            Class c = null;
            
            try { // first try to load the class, as it may already be loaded
              c = loadClass(className);
            }
            catch(ClassNotFoundException e) { // ok we got an exception which means it wasn't load
              c = findClass(className);
            }
            
            if(className.indexOf("$") == -1) {
              Object object = c.newInstance();
            }
          }
        }
      }
      catch(IOException ioe) {
        System.err.println("IO Exception while loading plugin \n" + jarFileNames[i]);
      }
      catch(InstantiationException e) {
        e.printStackTrace();
      }
      catch(IllegalAccessException e) {
        e.printStackTrace();
      }
    }
  }
  
  // Method to find a class
  public Class findClass(String name) {
    byte[] b = loadClassData(name);
    return defineClass(name, b, 0, b.length);
  }
  
  // Method to load a certain class 
  private byte[] loadClassData(String name) {
    byte[] buffer = null;
    String realName = name.replace('.', '/');
    realName += ".class";
    
    JarEntry entry = jarFile.getJarEntry(realName);
    if(entry != null) {
      try {
        buffer = new byte[(int)entry.getSize()];
        BufferedInputStream is = new BufferedInputStream(
        jarFile.getInputStream(entry));
        is.read(buffer);
      }
      catch(IOException ioe) {
        ioe.printStackTrace();
      }
    }
    
    return buffer;
  }
}// --end class InstruViewPluginLoader
