PluginLoader.java

Go to the documentation of this file.
00001 package theba.core;
00002 
00003 /***
00004 @author perchrh
00005 This class deals with loading plugins. 
00006 It will try to load them from certain directories (theba/{plugins,descriptors,trackers}, and if that fail, from 
00007 a certain jar file (theba.jar).
00008 ***/
00009 
00010 import java.io.BufferedInputStream;
00011 import java.io.File;
00012 import java.io.FileInputStream;
00013 import java.io.FilenameFilter;
00014 import java.io.IOException;
00015 import java.lang.reflect.Constructor;
00016 import java.util.ArrayList;
00017 import java.util.Enumeration;
00018 import java.util.Hashtable;
00019 import java.util.jar.JarEntry;
00020 import java.util.jar.JarFile;
00021 import java.util.jar.JarInputStream;
00022 
00023 import javax.swing.JFrame;
00024 import javax.swing.JOptionPane;
00025 
00026 import theba.core.gui.ThebaGUI;
00027 
00028 public class PluginLoader extends ClassLoader{
00029 
00030         private JFrame mainWindow;
00031         private ThebaGUI gui;
00032 
00033         private ArrayList<RegionDescriptor> descriptors;
00034         private ArrayList<Tracker> trackers;
00035         private ArrayList<Plugin> plugins;
00036 
00037         private Hashtable<String,Integer> jarEntrySizes = new Hashtable<String,Integer> ();
00038         private Hashtable<String,byte[]> jarEntryContents = new Hashtable<String,byte[]>();
00039 
00040         @SuppressWarnings("unchecked")
00041         private Hashtable<String,Class> classes = new Hashtable<String,Class>();
00042 
00043         private final boolean debug = false;
00044         private boolean jarFileIsAvailable;
00045 
00046         private boolean isPlugin(String name){
00047 
00048                 boolean retval = false;
00049 
00050                 if (name.startsWith("theba/descriptors/")) retval = true;
00051                 else if (name.startsWith("theba/plugins/")) retval = true;
00052                 else if (name.startsWith("theba/trackers/")) retval = true;
00053 
00054                 if (debug) System.out.println("Checking name " + name + " found " + retval);
00055 
00056                 return retval;
00057 
00058         }
00059 
00060         public PluginLoader(ThebaGUI gui, String jarFileName){
00061                 this.gui = gui;
00062                 mainWindow = gui.getWindow();
00063                 
00064                 jarFileIsAvailable = false;
00065                 try {
00066                         File test = new File(jarFileName);
00067                         jarFileIsAvailable = test.exists();
00068                 } catch (Exception why){
00069                         //ignore why
00070                 }
00071 
00072                 if ( jarFileIsAvailable ){
00073 
00074                         JarFile jarFile=null;
00075                         try {
00076                                 jarFile = new JarFile(jarFileName);
00077                                 Enumeration<JarEntry> e = jarFile.entries();
00078                                 while (e.hasMoreElements()) {
00079                                         JarEntry jarEntry = e.nextElement();
00080                                         if ( ! isPlugin(jarEntry.getName() )){
00081                                                 continue;
00082                                         }
00083                                         jarEntrySizes.put(jarEntry.getName(), new Integer( (int) jarEntry.getSize()));
00084 
00085                                 }
00086                                 jarFile.close();
00087 
00088                                 FileInputStream fis = new FileInputStream(jarFileName);
00089                                 BufferedInputStream bis = new BufferedInputStream(fis);
00090                                 JarInputStream jis = new JarInputStream(bis);
00091                                 JarEntry jarEntry = null;
00092                                 while ((jarEntry = jis.getNextJarEntry()) != null) {
00093                                         if (jarEntry.isDirectory()) {
00094                                                 continue;
00095                                         }
00096                                         if ( ! isPlugin(jarEntry.getName() )){
00097                                                 continue;
00098                                         }
00099 
00100                                         int size = (int) jarEntry.getSize();
00101                                         // -1 means unknown size.
00102                                         if (size == -1) {
00103                                                 size = jarEntrySizes.get(jarEntry.getName()).intValue();
00104                                         }
00105 
00106                                         byte[] b = new byte[size];
00107                                         int rb = 0;
00108                                         int chunk = 0;
00109                                         while ((size - rb) > 0) {
00110                                                 chunk = jis.read(b, rb, size - rb);
00111                                                 if (chunk == -1) {
00112                                                         break;
00113                                                 }
00114                                                 rb += chunk;
00115                                         }
00116                                         jarEntryContents.put(jarEntry.getName(), b);
00117                                 }
00118 
00119                         } catch (IOException why) {
00120                                 why.printStackTrace();
00121                         }
00122                         
00123                 }
00124                 else{
00125                         if (debug)
00126                                 System.out.println("Jar file not found, loading plugins from filesystem instead.");
00127                 }
00128                 
00129                 init(); //load plugins
00130         }
00131 
00132         private void init(){
00133                 //try to load classes, if they don't load show error message
00134 
00135                 descriptors = loadRegionDescriptors();
00136                 plugins = loadPlugins();
00137                 trackers = loadTrackers();
00138 
00139                 if (trackers.size() == 0 || descriptors.size() == 0 || plugins.size() == 0){
00140                         String errormesg = "Could not get all required plugins.\n" +
00141                         "Got " + trackers.size() + " tracker plugins.\n" +
00142                         "Got " + descriptors.size() + " region descriptor plugins.\n" +
00143                         "Got " + plugins.size() + " other descriptor plugins.\n";
00144 
00145                         JOptionPane.showMessageDialog(mainWindow,
00146                                         errormesg, "Loading problem",
00147                                         JOptionPane.ERROR_MESSAGE);
00148                 }
00149         }
00150 
00151 
00152         private byte[] getClassBytes(String name) {
00153                 return jarEntryContents.get(name);
00154         }
00155 
00156 
00157         private String classToFile(String name){
00158                 name = name+".class";
00159 
00160                 char[] clsName = name.toCharArray();
00161                 for (int i = 0; i < clsName.length-6; i++) {
00162                         if (clsName[i] == '.') {
00163                                 clsName[i] = '/';
00164                         }
00165                 }
00166 
00167                 return new String(clsName);
00168 
00169         }
00170 
00171         private String fileToClass(String name) {
00172                 char[] clsName = name.toCharArray();
00173 
00174                 for (int i = clsName.length - 6; i >= 0; i--) {
00175                         if (clsName[i] == '/') {
00176                                 clsName[i] = '.';
00177                         }
00178                 }
00179 
00180                 return new String(clsName, 0, clsName.length - 6);
00181         }
00182 
00183         @SuppressWarnings("unchecked")
00184         private ArrayList<RegionDescriptor> loadRegionDescriptors() {
00185                 ArrayList<RegionDescriptor> descriptors = new ArrayList<RegionDescriptor>();
00186                 ArrayList<String> classes = getPluginClassNames("descriptors");
00187 
00188                 for(int i = 0; i < classes.size();i++){
00189                         String classname = classes.get(i);
00190                         try {
00191                                 Class c = loadClass(classname);
00192                                 if (c.getInterfaces().length > 0 && c.getInterfaces()[0].getName().equals("theba.core.RegionDescriptor")) {
00193                                         Object o = c.newInstance();
00194                                         descriptors.add((RegionDescriptor) o);
00195                                 }
00196                         } catch (Exception e) {
00197                                 e.printStackTrace();
00198                         }
00199                 }
00200 
00201                 return descriptors;
00202         }
00203 
00204         @SuppressWarnings("unchecked")
00205         public ArrayList<Plugin> loadPlugins() {
00206                 ArrayList<Plugin> plugins = new ArrayList<Plugin>();
00207                 ArrayList<String> classes = getPluginClassNames("plugins");
00208 
00209                 for(int i = 0; i < classes.size();i++){
00210                         String classname = classes.get(i);
00211                         try {
00212                                 Class c = loadClass(classname);
00213                                 if (c.getInterfaces().length > 0 && c.getInterfaces()[0].getName().equals("theba.core.Plugin")) {
00214                                         Object o = c.newInstance();
00215                                         plugins.add((Plugin) o);
00216                                 }
00217                         } catch (Exception e) {
00218                                 e.printStackTrace();
00219                         }
00220                 }
00221 
00222                 return plugins;
00223         }
00224 
00225 
00226 
00227         @SuppressWarnings("unchecked")
00228         public ArrayList<Tracker> loadTrackers() {
00229                 ArrayList<Tracker> trackers = new ArrayList<Tracker>();
00230                 ArrayList<String> classes = getPluginClassNames("trackers");
00231 
00232                 for(int i = 0; i < classes.size();i++){
00233                         String classname = classes.get(i);
00234                         try {
00235                                 Class c = loadClass(classname);
00236                                 Constructor cs = c.getConstructors()[0];
00237                                 Object[] args = new Object[1];
00238                                 args[0] = gui; // needs ThebaGUI to construct
00239                                 Object o = cs.newInstance(args);
00240                                 trackers.add((Tracker) o);
00241                         } catch (Exception e) {
00242                                 e.printStackTrace();
00243                         }
00244                 }
00245 
00246                 return trackers;
00247         }
00248 
00249         private ArrayList<String> getPluginClassNames(final String dirName){
00250                 ArrayList<String> names = new ArrayList<String>();
00251 
00252                 //Find classes from search directories on disk:
00253                 File dir = new File("theba/"+dirName);
00254                 FilenameFilter filter = new FilenameFilter() {
00255                         public boolean accept(File dir, String name) {
00256                                 boolean retval = name.endsWith(".class");
00257                                 retval &= !name.contains("$");
00258                                 return retval;
00259                         }
00260                 };
00261 
00262                 String[] files = dir.list(filter);
00263                 if (files != null) {
00264                         for (int i=0; i < files.length; i++){
00265                                 names.add("theba."+dirName+"."+fileToClass(files[i]));
00266                         }
00267                 } 
00268 
00269                 if (debug) System.out.println("Found " + names.size() + " classes in " + dirName);
00270 
00271                 if (names.size() == 0 && jarFileIsAvailable ){ //We didn't find classes, so we try the jar file
00272 
00273                         Enumeration<String> keys = jarEntryContents.keys();
00274                         while(keys.hasMoreElements()){
00275                                 String name = keys.nextElement();
00276                                 if(name.startsWith("theba/"+dirName) && !name.contains("$") && name.endsWith(".class")){
00277                                         names.add(fileToClass(name));
00278                                         if (debug) System.out.println("Added class " + fileToClass(name));
00279                                 }
00280                         }
00281                 }
00282 
00283                 return names;
00284         }
00285 
00286 
00287         public ArrayList<RegionDescriptor> getRegionDescriptors() {
00288                 return descriptors;
00289         }
00290 
00291         public ArrayList<Plugin> getPlugins() {
00292                 return plugins;
00293         }
00294 
00295         public ArrayList<Tracker> getTrackers() {
00296                 return trackers;
00297         }
00298 
00299         @Override
00300         protected synchronized Class<?> loadClass(String name, boolean resolve)
00301         throws ClassNotFoundException
00302         {
00303 
00304                 if (debug) System.out.println("Call to loadClass " + name + "with resolve=" + resolve);
00305 
00306                 Class c = null; 
00307                 c = classes.get(name);
00308                 if (c != null) { 
00309                         if (debug) System.out.println("already loaded Class " + name );
00310                         return c; 
00311                 }
00312 
00313                 if (jarEntryContents.containsKey(classToFile(name))){
00314                         if (debug) System.out.println("Loading class " + name + " from jar file.");
00315                         byte[] classData = getClassBytes(classToFile(name));
00316                         c = defineClass(name, classData, 0, classData.length);
00317                         if (c == null) {
00318                                 throw new ClassFormatError();
00319                         }
00320                 }
00321 
00322                 if (c == null){
00323                         if (debug) System.out.println("Using parent class loader to load " + name);
00324                         return super.loadClass(name,resolve);
00325                 }
00326                 else{
00327                         if (resolve) {
00328                                 resolveClass(c);
00329                         }
00330                         classes.put(name,c);
00331 
00332                         return c;
00333                 }
00334         }
00335 }

Generated on Fri Nov 13 08:57:07 2009 for Theba by  doxygen 1.6.1