package de.ugoe.cs.quest.plugin; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.security.InvalidParameterException; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.jar.JarInputStream; import java.util.jar.Manifest; /** *
* This class provides the functionality to load QUEST plug-ins from a * pre-defined folder. *
* * @author Steffen Herbold * @version 1.0 */ public class PluginLoader { /** ** Handle of the plug-in directory. *
*/ private final File pluginDir; /** ** Collection of the loaded plug-ins. *
*/ private final Collection* Constructor. Creates a new PluginLoader that can load plug-ins the * defined directory. *
* * @param pluginDir * handle of the directory; in case the handle is *null
or does not describe a directory, an
* {@link InvalidParameterException} is thrown
*/
public PluginLoader(File pluginDir) {
if (pluginDir == null) {
throw new InvalidParameterException(
"Parameter pluginDir must not be null!");
}
if (!pluginDir.isDirectory()) {
throw new InvalidParameterException("File " + pluginDir.getPath()
+ " is not a directory");
}
this.pluginDir = pluginDir;
plugins = new LinkedList* Loads plug-ins from {@link #pluginDir}. *
* * @throws PluginLoaderException * thrown if there is a problem loading a plug-in or updating * the classpath */ public void load() throws PluginLoaderException { File[] jarFiles = pluginDir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return checkNameConformity(name); } }); for (File jarFile : jarFiles) { updateClassLoader(jarFile); String pluginName = jarFile.getName().split("-")[2]; String pluginClassName = "de.ugoe.cs.quest.plugin." + pluginName + "." + pluginName.toUpperCase() + "Plugin"; Class> pluginClass = null; try { pluginClass = Class.forName(pluginClassName); } catch (ClassNotFoundException e) { throw new PluginLoaderException("No class '" + pluginClassName + "' found in " + pluginDir + "/" + jarFile.getName()); } try { QuestPlugin pluginObject = (QuestPlugin) pluginClass .newInstance(); plugins.add(pluginObject); } catch (InstantiationException e) { throw new PluginLoaderException("Could not instantiate " + pluginClassName); } catch (IllegalAccessException e) { throw new PluginLoaderException("Could not access " + pluginClassName); } catch (ClassCastException e) { throw new PluginLoaderException("Class " + pluginClassName + " not instance of QuestPlugin"); } } } /** ** Retrieves the classpath from a Jar file's MANIFEST. *
* * @throws IOException * @throws FileNotFoundException */ protected String[] getClassPathFromJar(File jarFile) { String[] classPath; JarInputStream jarInputStream = null; try { jarInputStream = new JarInputStream(new FileInputStream(jarFile)); } catch (FileNotFoundException e) { throw new AssertionError( "FileNotFoundException should be impossible!"); } catch (IOException e) { throw new PluginLoaderException(e); } Manifest manifest = jarInputStream.getManifest(); String jarClassPath = manifest.getMainAttributes().getValue( "Class-Path"); if (jarClassPath != null) { String[] jarClassPathElements = jarClassPath.split(" "); classPath = new String[jarClassPathElements.length]; for (int i = 0; i < jarClassPathElements.length; i++) { classPath[i] = "file:" + jarFile.getParentFile().getAbsolutePath() + "/" + jarClassPathElements[i]; } try { jarInputStream.close(); } catch (IOException e) { throw new PluginLoaderException(e); } } else { classPath = new String[] {}; } return classPath; } /** *
* Updates the classpath of the {@link ClassLoader} to include the plug-in
* jar as well as further libraries required by the plug-in jar as defined
* in the Class-Path
section of its manifest.
*
* Checks if the name of a file indicates that it defines a QUEST plug-in.
* The structure of valid plug-in filenames is
* quest-plugin-%PLUGIN_NAME%-version.jar
, where
* %PLUGIN_NAME%
is replaced by the name of the plug-in. Note
* that plug-in names must not contain any dashes.
*