package se.cth.hedgehogphoto.plugin; import java.io.File; import java.io.FilenameFilter; import java.net.MalformedURLException; import java.net.URL; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import se.cth.hedgehogphoto.log.Log; import se.cth.hedgehogphoto.view.MainView; /** * A class that handles the plugin-loading. * To see how to write plugins that will work with Headgehog Photo * please see the available annotations. * @author Barnabas Sapan */ public class PluginLoader implements Runnable{ private MainView view; private FileClassLoader classLoader; private String pluginRootDir; private boolean threaded = false; private List<Class<?>> loadedClasses = new LinkedList<Class<?>>(); @Override public void run(){ if(this.threaded){ this.threaded = true; this.loadAllPlugins(); this.parseClasses(); } else { throw new NotThreadedException(); } } public PluginLoader(MainView view, File pluginRootDir, boolean preLoad){ this(view, pluginRootDir.getAbsolutePath(), preLoad); } /** * The one and only constructor. The main entry point for this class. * @param view the view the plugins will get placed onto * @param pluginFolderName the plugin folder name, the folder will be * created in the users home folder. * @param preLoad true if this instance will be put in a separate thread * false if not. */ public PluginLoader(MainView view, String pluginRootDir, boolean preLoad) { this.view = view; this.pluginRootDir = pluginRootDir; this.threaded = preLoad; try { File file = new File(pluginRootDir); URL url = file.toURI().toURL(); URL[] urls = new URL[]{url}; Log.getLogger().log(Level.INFO, "Setting plugin directory: " + urls[0].getPath()); Helper.createPluginFolder(new File(urls[0].getPath())); Helper.copyPluginsToFolder(new File(urls[0].getPath())); this.classLoader = new FileClassLoader(urls); } catch (MalformedURLException e) { Log.getLogger().log(Level.SEVERE, "MalformedURLException", e); } } /** * Loads all the available plugins in the plugin root folder specified by the constructor */ public void loadAllPlugins(){ loadPluginFromDirectory(new File(this.pluginRootDir)); } /** * Loads a specific (or all if more plugins exist in same dir) plugin to the program * @param dir the absolute path of the directory to the plugin */ public void loadPluginFromDirectory(File dir){ List<File> files = Helper.getAllFilesInFolder(dir, new FilenameFilter() { @Override public boolean accept(File dir, String name) { return (name.toString().endsWith(".java"));// || name.toString().endsWith(".class")); } }); //Loop trough all files and load the classes. //Only add classes the the loadedClasses list if they were loaded (!=null) for(File file : files) { String className = Helper.stripDotAndSlashFromString(file.toString()); Log.getLogger().log(Level.INFO, "Loading class " + className + "..."); Class<?> c = this.classLoader.loadClass(className); if(c != null){ this.loadedClasses.add(c); } } Log.getLogger().log(Level.INFO, "Loaded classes: " + this.loadedClasses.toString()); /*Only parse classes right away if we do not thread the pluginLoader. *The run method will call parseClassed if we thread.*/ if(this.threaded == false){ parseClasses(this.loadedClasses, Helper.getDefaultPluginParsers()); } else { this.threaded = false; } } /** * Lazy method that just calls * parseClasses(List<Class<?>> list, List<Parsable> parsableAnnotations) * with the appropriate parameters */ private void parseClasses(){ parseClasses(this.loadedClasses, Helper.getDefaultPluginParsers()); } /** * This method parses all the classes in the list supplied to this method. * @param list the list of classes to parse * @param parsableAnnotations classes that implements Parsable to handle the parsing. * The classes get parsed according to the order of the list. */ private void parseClasses(List<Class<?>> list, List<Parsable> parsableAnnotations){ for(Class<?> c : list) { Object o = null; for(Parsable p : parsableAnnotations){ o = p.parseClass(c, o, this.view); } } } }