package com.c2kernel.process.module; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Properties; import com.c2kernel.common.InvalidDataException; import com.c2kernel.common.ObjectNotFoundException; import com.c2kernel.entity.proxy.ItemProxy; import com.c2kernel.lookup.DomainPath; import com.c2kernel.persistency.outcome.OutcomeValidator; import com.c2kernel.persistency.outcome.Schema; import com.c2kernel.process.Gateway; import com.c2kernel.scripting.ScriptingEngineException; import com.c2kernel.utils.FileStringUtility; import com.c2kernel.utils.Logger; import com.c2kernel.utils.Resource; public class ModuleManager { ArrayList modules = new ArrayList(); HashMap modulesXML = new HashMap(); Properties props = new Properties(); boolean isServer; OutcomeValidator moduleValidator; public ModuleManager(Enumeration moduleEnum, boolean isServer) throws ModuleException { this.isServer = isServer; try { Schema moduleSchema = new Schema("Module", 0, FileStringUtility.url2String(Resource.getKernelResourceURL("boot/OD/Module.xsd"))); moduleValidator = new OutcomeValidator(moduleSchema); } catch (InvalidDataException ex) { Logger.error(ex); throw new ModuleException("Module Schema is not valid"); } catch (IOException ex) { throw new ModuleException("Could not load Module Schema from kernel resources"); } ArrayList loadedModules = new ArrayList(); ArrayList moduleNs = new ArrayList(); while(moduleEnum.hasMoreElements()) { URL newModuleURL = moduleEnum.nextElement(); try { String moduleXML = FileStringUtility.url2String(newModuleURL); String errors = moduleValidator.validate(moduleXML); if (errors.length() > 0) throw new ModuleException("Module XML found at "+newModuleURL+" was not valid: "+errors); Module newModule = (Module)Gateway.getMarshaller().unmarshall(moduleXML); if (newModule.resURL != null && newModule.resURL.length()>0) Resource.addModuleBaseURL(newModule.ns, newModule.resURL); modules.add(newModule); modulesXML.put(newModule.ns, moduleXML); if (loadedModules.contains(newModule.getName())) throw new ModuleException("Module name clash: "+newModule.getName()); if (moduleNs.contains(newModule.getNs())) throw new ModuleException("Module namespace clash: "+newModule.getNs()); Logger.debug(4, "Module found: "+newModule.getNs()+" - "+newModule.getName()); loadedModules.add(newModule.getName()); moduleNs.add(newModule.getNs()); Properties modProp = newModule.getProperties(isServer); for (Enumeration e = modProp.propertyNames(); e.hasMoreElements();) { String propName = (String)e.nextElement(); props.put(propName, modProp.get(propName)); } } catch (ModuleException e) { Logger.error("Could not load module description from "+newModuleURL); throw e; } catch (Exception e) { Logger.error(e); throw new ModuleException("Could not load module.xml from "+newModuleURL); } } Logger.debug(5, "Checking dependencies"); boolean allDepsPresent = false; ArrayList prevModules = new ArrayList(); for (int i=0; i deps = thisMod.getDependencies(); depClean = true; for (String dep : deps) { Logger.msg(6, thisMod.getName()+" depends on "+dep); if (!loadedModules.contains(dep)) { Logger.error("UNMET MODULE DEPENDENCY: "+thisMod.getName()+" requires "+dep); allDepsPresent = true; } else if (!prevModules.contains(dep)) { Logger.msg(1, "ModuleManager: Shuffling "+thisMod.getName()+" to the end to fulfil dependency on "+dep); modules.remove(i); modules.add(thisMod); thisMod = modules.get(i); skipped++; depClean = false; break; } } if (skipped > modules.size()-i) { StringBuffer badMod = new StringBuffer(); for (Module mod : modules.subList(i, modules.size())) { badMod.append(mod.getName()).append(" "); } Logger.die("Circular module dependencies involving: "+badMod); } } prevModules.add(thisMod.getName()); } if (allDepsPresent) Logger.die("Unmet module dependencies. Cannot continue"); } public String getModuleVersions() { StringBuffer ver = new StringBuffer(); for (Module thisMod : modules) { if (ver.length()>0) ver.append("; "); ver.append(thisMod.getName()+" ("+thisMod.getVersion()+")"); } return ver.toString(); } public Properties getAllModuleProperties() { return props; } public void runScripts(String event) { for (Module thisMod : modules) { try { thisMod.runScript(event, isServer); } catch (ScriptingEngineException e) { Logger.error(e); Logger.die(e.getMessage()); } } } public void registerModules() throws ModuleException { ItemProxy serverEntity; try { serverEntity = (ItemProxy)Gateway.getProxyManager().getProxy(new DomainPath("/servers/"+Gateway.getProperty("ItemServer.name"))); } catch (ObjectNotFoundException e) { throw new ModuleException("Cannot find local server name."); } Logger.debug(3, "Registering modules"); boolean reset = Gateway.getProperty("Module.reset", "false").equals("true"); for (Module thisMod : modules) { Logger.msg("Registering module "+thisMod.getName()); try { String nsReset = Gateway.getProperty("Module."+thisMod.ns+".reset"); boolean thisReset = nsReset == null?reset:nsReset.equals("true"); thisMod.importAll(serverEntity, modulesXML.get(thisMod.ns), thisReset); } catch (Exception e) { Logger.error(e); throw new ModuleException("Error importing items for module "+thisMod.getName()); } Logger.msg("Module "+thisMod.getName()+" registered"); try { thisMod.runScript("startup", true); } catch (ScriptingEngineException e) { Logger.error(e); throw new ModuleException("Error in startup script for module "+thisMod.getName()); } } } public void dumpModules() { for (Module thisMod : modules) { try { FileStringUtility.string2File(thisMod.getName()+".xml", Gateway.getMarshaller().marshall(thisMod)); } catch (Exception e) { Logger.error(e); } } } }