PluginLoader.java
Go to the documentation of this file.00001 package theba.core;
00002
00003
00004
00005
00006
00007
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
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
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();
00130 }
00131
00132 private void init(){
00133
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;
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
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 ){
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 }