/* * 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.module; import hk.hku.cecid.piazza.commons.Sys; import hk.hku.cecid.piazza.commons.util.ConsoleLogger; import hk.hku.cecid.piazza.commons.util.Instance; import hk.hku.cecid.piazza.commons.util.Logger; import hk.hku.cecid.piazza.commons.util.PropertyTree; import java.io.File; import java.io.InputStream; import java.net.URL; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; /** * A Module is described by a module descriptor and contains zero to many * components. Each module has its own classloader for loading its components, * which are defined in the module descriptor, and its resources. * * @see Component * * @author Hugo Y. K. Lam * */ public class Module extends Component { private ModuleGroup group; private final PropertyTree descriptor; private final ClassLoader classLoader; private final Map components; /** * Creates and initializes a new instance of Module. * * @param descriptorLocation the module descriptor. * @throws ModuleException if errors encountered when loading the module * descriptor. */ public Module(String descriptorLocation) { this(descriptorLocation, true); } /** * Creates a new instance of Module. * * @param descriptorLocation the module descriptor. * @param shouldInitialize true if the module should be initialized. * @throws ModuleException if errors encountered when loading the module * descriptor. */ public Module(String descriptorLocation, boolean shouldInitialize) { this(descriptorLocation, null, shouldInitialize); } /** * Creates and initializes a new instance of Module. * * @param descriptorLocation the module descriptor. * @param loader the class loader for this module. * @throws ModuleException if errors encountered when loading the module * descriptor. */ public Module(String descriptorLocation, ClassLoader loader) { this(descriptorLocation, loader, true); } /** * Creates a new instance of Module. * * @param descriptorLocation the module descriptor. * @param loader the class loader for this module. * @param shouldInitialize true if the module should be initialized. * @throws ModuleException if errors encountered when loading the module * descriptor. */ public Module(String descriptorLocation, ClassLoader loader, boolean shouldInitialize) { if (descriptorLocation == null) { throw new ModuleException("No module descriptor specified"); } if (loader == null) { loader = getClass().getClassLoader(); } URL resrc = getResource(descriptorLocation, loader); if (resrc == null) { throw new ModuleException("Module descriptor not found: " + descriptorLocation); } try { this.classLoader = loader; this.components = Collections.synchronizedMap(new LinkedHashMap()); this.descriptor = new PropertyTree(resrc); super.setModule(this); super.setId(getString("/module/@id")); super.setName(getString("/module/@name")); super.setParameters(descriptor.createProperties("/module/parameters/parameter")); createComponents(); if (shouldInitialize) { init(); } } catch (Exception e) { throw new ModuleException("Unable to initialize module '"+getName()+"'", e); } } /** * Initializes the module and all its components. * * @throws ModuleException if unable to initialize the module. */ public void init() { initComponents(); getLogger().info("Module '" + getName() + "' initialized successfully."); } /** * Creates all the components defined in the module descriptor. * * @throws ModuleException if unable to create any component. */ protected void createComponents() { // get all defined components String[] componentIds = descriptor .getProperties("/module/component/@id"); for (int i = 0; i < componentIds.length; i++) { // retrieve the component information String id = componentIds[i]; String key = "/module/component[@id='" + id + "']"; String name = descriptor.getProperty(key + "/@name"); String className = descriptor.getProperty(key + "/class"); Properties parameters = descriptor.createProperties(key + "/parameter"); try { // create the component Instance instance = new Instance(className, classLoader); Component component = (Component) instance.getObject(); component.setId(id); component.setName(name); component.setParameters(parameters); setComponent(component); } catch (Exception e) { throw new ModuleException("Unable to create module component '" + name + "' of class " + className, e); } } } /** * Initializes all the created components. * * @throws ModuleException if unable to initialize any component. */ protected void initComponents() { Iterator orderedComponents = components.values().iterator(); while (orderedComponents.hasNext()) { Component component = (Component) orderedComponents.next(); try { component.init(); getLogger().debug( "Component '" + component.getName() + "' in module '" + getName() + "' initialized successfully."); } catch (Exception e) { throw new ModuleException("Unable to initialize component '" + component.getName() + "'", e); } } } /** * Gets the specified component in this module. * * @param id the ID of the module component. * @return the module component. */ public Component getComponent(String id) { if (id == null) { return null; } else { return (Component) components.get(id); } } /** * Gets all the components in this module. * * @return all module components */ public Collection getComponents() { return components.values(); } /** * Sets a component to this module. * * @param component the component to be set. */ public void setComponent(Component component) { String id = component.getId(); if (component != null && id!=null) { component.setModule(this); components.put(id, component); } } /** * Gets the number of components in this module. * * @return the number of components in this module. */ public int getComponentCount() { return components.size(); } /** * Gets the string value of the specified key from the module descriptor. * * @param key the key in the resource bundle. * @return the string value. */ protected String getString(String key) { try { return descriptor.getProperty(key).trim(); } catch (Exception e) { return ""; } } /** * Get the mandatory parameter from the current module, throw ModuleException if not found. * * @param key the key in the parameters list. * @return The value of the parameter if found. * @throws ModuleException if the parameter with <code>key</code> does not exist. */ protected String getRequiredParameter(String key) { if (key == null) { throw new NullPointerException("Missing 'key' in the arguments."); } String value = super.getParameters().getProperty(key); if (value == null) { throw new ModuleException("Missing required parameter '" + key + "' in module:" + super.getId()); } return value; } /** * Gets a resource as stream. * * @param name the name of the resource. * @return an input stream of the resource. * * @see #getResource(String) */ public InputStream getResourceAsStream(String name) { try { URL url = getResource(name); return url == null ? null : url.openStream(); } catch (Exception e) { return null; } } /** * Gets a resource as URL. * * @param name the name of the resource. * @return the URL of the resource. * * @see #getResource(String, ClassLoader) */ public URL getResource(String name) { return getResource(name, classLoader); } /** * Gets a resource as URL. * <p> * The specified name can be an absolute path or a relative path to the * current directory or classpaths. * <p> * If the specified name is a relative path, it will be searched through the * current directory and then the classpaths. * * @param name the name of the resource. * @param loader the class loader for finding the resource. * @return the URL of the resource. */ public static URL getResource(String name, ClassLoader loader) { if (name == null || "".equals((name = name.trim()))) { return null; } if (loader == null) { loader = Module.class.getClassLoader(); } try { File f = new File(name); return f.exists() ? f.toURI().toURL() : loader.getResource(name); } catch (Exception e) { return null; } } /** * Gets the class loader that this module uses to load classes. * * @return the class loader for this module. */ public ClassLoader getClassLoader() { return classLoader; } /** * Gets the module descriptor. * * @return the module descriptor. */ public URL getDescriptor() { return descriptor.getURL(); } /** * Gets the logger of this module. * * @return the logger of this module. */ public Logger getLogger() { ModuleGroup group = getGroup(); if (group != null) { SystemModule sysmod = group.getSystemModule(); if (sysmod != null) { Logger logger = sysmod.getLogger(); if (logger != null) { return logger; } } } if (Sys.main == null || Sys.main.log == null) { return ConsoleLogger.getInstance(); } else { return Sys.main.log; } } /** * Gets the version of this module. * * @return the version of this module. */ public String getVersion() { return getString("/module/@version"); } public String getBuildID() { return getString("/module/@buildID"); } /** * Gets the module group to which this module belongs. * * @return the module group. */ public ModuleGroup getGroup() { return group; } /** * Sets the module group to which this module belongs. * * @param group the module group. */ public void setGroup(ModuleGroup group) { this.group = group; } /** * Returns a string representation of this module. * * @return a string representation of this module. * @see java.lang.Object#toString() */ public String toString() { return "Module: " + getName(); } }