/* * Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The * University of Hong Kong (HKU). All Rights Reserved. * * This software is licensed under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1] * * [1] http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt */ package hk.hku.cecid.piazza.commons.spa; import java.io.File; import java.io.FilenameFilter; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Properties; /** * A Plugin represents a plugin descriptor. * It contains the elements specified in the descriptor. * It also contains a class loader for loading classes which * stored in the libraries specified in the descriptor. * * If there is a plugin handler specified in the descriptor, * it will be invoked when the plugin is being activated. * * @see PluginRegistry * @see PluginClassLoader * @see PluginHandler * * @author Hugo Y. K. Lam * */ public class Plugin extends PluginComponent { private boolean activated; private Collection<Library> libraries; private Collection extensionPoints; private Collection extensions; private Collection imports; private File pluginFolder; private PluginDescriptor pluginDescriptor; private PluginClassLoader pluginClassLoader; private PluginRegistry pluginRegistry; /** * Creates a new instance of Plugin. * * @param registry the plugin registry which stores this plugin. * @param folder the folder which holds this plugin. * @param descriptor the descriptor of this plugin. * @throws PluginException if this plugin cannot be initialized according to its plugin descriptor. */ public Plugin(PluginRegistry registry, File folder, String descriptor) throws PluginException { super(null); try { pluginRegistry = registry; pluginFolder = folder; pluginDescriptor = new PluginDescriptor(new File(folder, descriptor)); pluginDescriptor.setParent(this); libraries = pluginDescriptor.getLibraries(); extensionPoints = pluginDescriptor.getExtensionPoints(); extensions = pluginDescriptor.getExtensions(); imports = pluginDescriptor.getImports(); pluginClassLoader = createClassLoader(); } catch (Exception e) { throw new PluginException("Unable to initialize plugin", e); } } /** * Creates a class loader for loading classes which * stored in the libraries specified in the plugin descriptor. * * @return a new class loader instance. * @throws PluginException if the libraries specified in the descriptor are invalid. */ private PluginClassLoader createClassLoader() throws PluginException { URL[] urls = getLibraryURLs(); return new PluginClassLoader(this, urls, this.getClass() .getClassLoader()); } /** * Gets the library URLs specified in the plugin descriptor. * * @return the library URLs specified in the plugin descriptor. * @throws PluginException if the libraries specified in the descriptor are invalid. */ private URL[] getLibraryURLs() throws PluginException { ArrayList<URL> urls = new ArrayList<URL>(); for(Library library: libraries) { File libFile = new File(pluginFolder, library.getName()); if (libFile.exists()) { try { if(libFile.isFile()) { urls.add(libFile.toURI().toURL()); } else if(libFile.isDirectory()) { urls.add(libFile.toURI().toURL()); addNestedJars(libFile, urls); } } catch (MalformedURLException e) { throw new PluginException("Invalid library URL", e); } } } return (URL[]) urls.toArray(new URL[]{}); } private void addNestedJars(File dir, ArrayList<URL> urls) throws MalformedURLException { File [] files = dir.listFiles(new FilenameFilter() { public boolean accept(File dir, String filename) { return filename.endsWith(".jar"); } }); for(File f: files) { urls.add(f.toURI().toURL()); } } /** * Activates this plugin by invoking the plugin handler specified in the plugin descriptor. * If the plugin has already been activated, nothing will be done. * * @throws PluginException if there is any error in processing activation by the handler. */ public synchronized void activate() throws PluginException { if (!activated) { if (getHandlerClass() != null && !"".equals(getHandlerClass())) { try { Class theClass = loadClass(getHandlerClass()); PluginHandler handler = (PluginHandler)theClass.newInstance(); handler.processActivation(this); } catch (Throwable e) { throw new PluginException("Error in processing activation by handler: "+getHandlerClass(), e); } } activated = true; } } /** * Deactivates this plugin by invoking the plugin handler specified in the plugin descriptor. * If the plugin has not yet been activated, nothing will be done. * * @throws PluginException if there is any error in processing deactivation by the handler. */ public synchronized void deactivate() throws PluginException { if (activated) { if (getHandlerClass() != null && !"".equals(getHandlerClass())) { try { Class theClass = loadClass(getHandlerClass()); PluginHandler handler = (PluginHandler)theClass.newInstance(); handler.processDeactivation(this); } catch (Throwable e) { throw new PluginException("Error in processing deactivation by handler: "+getHandlerClass(), e); } } activated = false; } } /** * Checks if this plugin has been activated. * * @return true if this plugin has been activated. */ public boolean isActivated() { return activated; } /** * Gets all the extension points declared in the plugin descriptor. * * @return all the extension points declared in the plugin descriptor. */ public Collection getExtensionPoints() { return extensionPoints; } /** * Gets all extensions declared in the plugin descriptor. * * @return all extensions declared in the plugin descriptor. */ public Collection getExtensions() { return extensions; } /** * Gets all extensions declared in the plugin descriptor which * extends the specified extension point. * * @param point the extension point. * @return all extensions declared in the plugin descriptor which * extends the specified extension point. */ public Collection getExtensions(String point) { ArrayList list = new ArrayList(); if (point != null) { Iterator exts = extensions.iterator(); while (exts.hasNext()) { Extension ext = (Extension) exts.next(); if (point.equals(ext.getPoint())) { list.add(ext); } } } return list; } /** * Gets all libraries declared in the plugin descriptor. * * @return all libraries declared in the plugin descriptor. */ public Collection getLibraries() { return libraries; } /** * Gets all plugin imports declared in the plugin descriptor. * * @return all plugin imports declared in the plugin descriptor. */ public Collection getImports() { return imports; } /** * Gets the plugin ID. * * @return the plugin ID. */ public String getId() { return pluginDescriptor.getId(); } /** * Gets the plugin name. * * @return the plugin name. */ public String getName() { return pluginDescriptor.getName(); } /** * Gets the handler class of this plugin. * * @return the handler class of this plugin. */ public String getHandlerClass() { return pluginDescriptor.getHandlerClass(); } /** * Gets the provider name of this plugin. * * @return the provider name of this plugin. */ public String getProviderName() { return pluginDescriptor.getProviderName(); } /** * Gets the version of this plugin. * * @return the version of this plugin. */ public String getVersion() { return pluginDescriptor.getVersion(); } /** * Gets the buildID of this plugin. * * @return the buildID of this plugin. */ public String getBuildID() { return pluginDescriptor.getBuildID(); } /** * Gets the parameters of this plugin. * * @return the parameters of this plugin. */ public Properties getParameters() { return pluginDescriptor.getParameters(); } /** * Returns a string representation of this plugin. * * @return a string representation of this plugin. * @see java.lang.Object#toString() */ public String toString() { return "Plugin ID: "+getId(); } /** * Loads a class from this plugin's class loader. * * @param name the class name. * @return the Class instance for the specified class name. * @throws PluginException if the class was not found. */ public Class loadClass(String name) throws PluginException { try { return Class.forName(name, true, pluginClassLoader); } catch (Throwable e) { throw new PluginException("Unable to load class '" + name + "' from plugin classloader :" + pluginClassLoader, e); } } /** * Gets the class loader for this plugin. * * @return the class loader for this plugin. */ public PluginClassLoader getClassLoader() { return pluginClassLoader; } /** * Gets the plugin registry of this plugin. * * @return the plugin registry of this plugin. */ public PluginRegistry getPluginRegistry() { return pluginRegistry; } }