package com.c2kernel.process; import java.net.InetAddress; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import java.util.StringTokenizer; import java.util.UUID; import org.custommonkey.xmlunit.Diff; import org.custommonkey.xmlunit.XMLUnit; import com.c2kernel.common.InvalidDataException; import com.c2kernel.common.ObjectNotFoundException; import com.c2kernel.entity.proxy.AgentProxy; import com.c2kernel.entity.proxy.ItemProxy; import com.c2kernel.events.Event; import com.c2kernel.events.History; import com.c2kernel.lifecycle.CompositeActivityDef; import com.c2kernel.lifecycle.instance.CompositeActivity; import com.c2kernel.lifecycle.instance.Workflow; import com.c2kernel.lifecycle.instance.predefined.server.ServerPredefinedStepContainer; import com.c2kernel.lifecycle.instance.stateMachine.Transition; import com.c2kernel.lookup.AgentPath; import com.c2kernel.lookup.DomainPath; import com.c2kernel.lookup.ItemPath; import com.c2kernel.lookup.LookupManager; import com.c2kernel.lookup.Path; import com.c2kernel.lookup.RolePath; import com.c2kernel.persistency.ClusterStorage; import com.c2kernel.persistency.outcome.Outcome; import com.c2kernel.persistency.outcome.OutcomeValidator; import com.c2kernel.persistency.outcome.Viewpoint; import com.c2kernel.process.resource.DefaultResourceImportHandler; import com.c2kernel.process.resource.ResourceImportHandler; import com.c2kernel.property.Property; import com.c2kernel.property.PropertyArrayList; import com.c2kernel.property.PropertyDescription; import com.c2kernel.property.PropertyDescriptionList; import com.c2kernel.utils.FileStringUtility; import com.c2kernel.utils.LocalObjectLoader; import com.c2kernel.utils.Logger; /** * @version $Revision: 1.25 $ $Date: 2006/01/10 09:48:32 $ * @author $Author: abranson $ */ public class Bootstrap { static DomainPath thisServerPath; static HashMap resHandlerCache = new HashMap(); static HashMap systemAgents = new HashMap(); /** * Run everything without timing-out the service wrapper */ public static void run() throws Exception { // check for system agents checkAdminAgents(); // create the server's mother item createServerItem(); new Thread(new Runnable() { @Override public void run() { try { Thread.currentThread().setName("Bootstrapper"); // make sure all of the boot items are up-to-date Logger.msg("Bootstrap.run() - Verifying kernel boot data items"); verifyBootDataItems(); // verify the server item's wf Logger.msg("Bootstrap.run() - Initialising Server Item Workflow"); initServerItemWf(); Gateway.getModuleManager().setUser(systemAgents.get("system")); Gateway.getModuleManager().registerModules(); Logger.msg("Bootstrap.run() - Bootstrapping complete"); } catch (Throwable e) { Logger.error(e); Logger.die("Exception performing bootstrap. Check that everything is OK."); } } }).start(); } /************************************************************************** * Checks all kernel descriptions, stored in resources **************************************************************************/ public static void verifyBootDataItems() throws Exception { String bootItems; Logger.msg(1, "Verifying kernel boot items"); bootItems = FileStringUtility.url2String(Gateway.getResource().getKernelResourceURL("boot/allbootitems.txt")); verifyBootDataItems(bootItems, null, true); Logger.msg(1, "Boot data items complete"); } private static void verifyBootDataItems(String bootList, String ns, boolean reset) { StringTokenizer str = new StringTokenizer(bootList, "\n\r"); while (str.hasMoreTokens()) { String thisItem = str.nextToken(); ItemPath itemPath = null; String[] itemParts = thisItem.split("/"); if (itemParts.length == 3) { // includes UUID itemPath = new ItemPath(UUID.fromString(itemParts[2])); } String itemType = itemParts[0]; String itemName = itemParts[1]; try { String location = "boot/"+thisItem+(itemType.equals("OD")?".xsd":".xml"); verifyResource(ns, itemName, 0, itemType, itemPath, location, reset); } catch (Exception e) { Logger.error(e); Logger.die("Error importing bootstrap items. Unsafe to continue."); } } } public static DomainPath verifyResource(String ns, String itemName, Integer version, String itemType, ItemPath itemPath, String dataLocation, boolean reset) throws Exception { if (version == null) version = 0; LookupManager lookupManager = Gateway.getLookupManager(); ResourceImportHandler typeImpHandler = getHandler(itemType); Logger.msg(1, "Bootstrap.verifyResource() - Verifying version "+version+" of "+typeImpHandler.getName()+" "+itemName); // Find or create Item for Resource DomainPath modDomPath = typeImpHandler.getPath(itemName, ns); ItemProxy thisProxy; Iterator en = Gateway.getLookup().search(typeImpHandler.getTypeRoot(), itemName); if (!en.hasNext()) { if (itemPath == null) itemPath = new ItemPath(); Logger.msg("Bootstrap.verifyResource() - "+typeImpHandler.getName()+" "+itemName+" not found. Creating new."); thisProxy = createResourceItem(typeImpHandler, itemName, ns, itemPath); } else { DomainPath path = (DomainPath)en.next(); thisProxy = Gateway.getProxyManager().getProxy(path); if (itemPath != null && !path.getItemPath().equals(itemPath)) { Logger.warning("Resource "+itemType+"/"+itemName+" should have path "+itemPath+" but was found with path "+path.getItemPath()); itemPath = path.getItemPath(); } if (itemPath == null) itemPath = path.getItemPath(); // Verify module property and location String moduleName = (ns==null?"kernel":ns); String itemModule; try{ itemModule = thisProxy.getProperty("Module"); if (!itemModule.equals("") && !itemModule.equals("null") && !moduleName.equals(itemModule)) { Logger.error("Bootstrap.verifyResource() - Module clash! Resource '"+itemName+"' included in module "+moduleName+" but is assigned to '"+itemModule+"'. Not overwriting."); return path; } } catch (ObjectNotFoundException ex) { itemModule = ""; } if (!moduleName.equals(itemModule)) { // write module property Gateway.getStorage().put(itemPath, new Property("Module", moduleName, false), thisProxy); } if (!modDomPath.equals(path)) { // move item to module subtree Logger.msg("Module item "+itemName+" found with path "+path.toString()+". Moving to "+modDomPath.toString()); modDomPath.setItemPath(itemPath); if (!modDomPath.exists()) lookupManager.add(modDomPath); lookupManager.delete(path); } } // Verify/Import Outcomes, creating events and views as necessary Set impList = typeImpHandler.getResourceOutcomes(itemName, ns, dataLocation, version); for (Outcome newOutcome : impList) { try { Viewpoint currentData = (Viewpoint)thisProxy.getObject(ClusterStorage.VIEWPOINT+"/"+newOutcome.getSchemaType()+"/"+version); Outcome oldData = currentData.getOutcome(); XMLUnit.setIgnoreWhitespace(true); XMLUnit.setIgnoreComments(true); Diff xmlDiff = new Diff(newOutcome.getDOM(), oldData.getDOM()); if (xmlDiff.identical()) { Logger.msg(5, "Bootstrap.verifyResource() - Data identical, no update required"); continue; } else { Logger.msg("Difference found in "+itemName+": "+xmlDiff.toString()); if (!reset && !currentData.getEvent().getStepPath().equals("Bootstrap")) { Logger.msg("Version "+version+" was not set by Bootstrap, and reset not requested. Not overwriting."); continue; } } } catch (ObjectNotFoundException ex) { Logger.msg("Bootstrap.verifyResource() - Item "+itemName+" exists but version "+version+" not found! Attempting to insert new."); } // data was missing or doesn't match // validate it (but not for kernel objects because we need those to validate the rest) if (ns!= null) { OutcomeValidator validator = OutcomeValidator.getValidator(LocalObjectLoader.getSchema(newOutcome.getSchemaType(), newOutcome.getSchemaVersion())); String error = validator.validate(newOutcome.getData()); if (error.length() > 0) { Logger.error("Outcome not valid: \n " + error); throw new InvalidDataException(error, ""); } } // store Logger.msg("Bootstrap.verifyResource() - Writing new "+newOutcome.getSchemaType()+" v"+version+" to "+typeImpHandler.getName()+" "+itemName); History hist = new History(itemPath, thisProxy); Transition predefDone = new Transition(0, "Done", 0, 0); Event newEvent = hist.addEvent(systemAgents.get("system").getPath(), "Admin", "Bootstrap", "Bootstrap", "Bootstrap", newOutcome.getSchemaType(), 0, "PredefinedStep", 0, predefDone, String.valueOf(version)); newOutcome.setID(newEvent.getID()); Viewpoint newLastView = new Viewpoint(itemPath, newOutcome.getSchemaType(), "last", 0, newEvent.getID()); Viewpoint newNumberView = new Viewpoint(itemPath, newOutcome.getSchemaType(), String.valueOf(version), 0, newEvent.getID()); Gateway.getStorage().put(itemPath, newOutcome, thisProxy); Gateway.getStorage().put(itemPath, newLastView, thisProxy); Gateway.getStorage().put(itemPath, newNumberView, thisProxy); } Gateway.getStorage().commit(thisProxy); return modDomPath; } private static ResourceImportHandler getHandler(String resType) throws Exception { if (resHandlerCache.containsKey(resType)) return resHandlerCache.get(resType); ResourceImportHandler handler = null; if (Gateway.getProperties().containsKey("ResourceImportHandler."+resType)) { try { handler = (ResourceImportHandler) Gateway.getProperties().getInstance("ResourceImportHandler."+resType); } catch (Exception ex) { Logger.error(ex); Logger.error("Exception loading ResourceHandler for "+resType+". Using default."); } } if (handler == null) handler = new DefaultResourceImportHandler(resType); resHandlerCache.put(resType, handler); return handler; } /** * @param itemType * @param itemName * @param data */ private static ItemProxy createResourceItem(ResourceImportHandler impHandler, String itemName, String ns, ItemPath itemPath) throws Exception { // create props PropertyDescriptionList pdList = impHandler.getPropDesc(); PropertyArrayList props = new PropertyArrayList(); LookupManager lookupManager = Gateway.getLookupManager(); for (int i = 0; i < pdList.list.size(); i++) { PropertyDescription pd = pdList.list.get(i); String propName = pd.getName(); String propVal = propName.equals("Name")?itemName:pd.getDefaultValue(); props.list.add(new Property(propName, propVal, pd.getIsMutable())); } CompositeActivity ca = new CompositeActivity(); if (ns!=null && Gateway.getProperties().getBoolean("Module.debug", false)) try { ca = (CompositeActivity) ((CompositeActivityDef)LocalObjectLoader.getActDef(impHandler.getWorkflowName(), 0)).instantiate(); } catch (ObjectNotFoundException ex) { Logger.error("Module resource workflow "+impHandler.getWorkflowName()+" not found. Using empty."); } Gateway.getCorbaServer().createItem(itemPath); lookupManager.add(itemPath); DomainPath newDomPath = impHandler.getPath(itemName, ns); newDomPath.setItemPath(itemPath); lookupManager.add(newDomPath); ItemProxy newItemProxy = Gateway.getProxyManager().getProxy(itemPath); newItemProxy.initialise( systemAgents.get("system").getPath(), props, ca, null); return newItemProxy; } /************************************************************************** * Checks for the existence of the admin users so you can use Cristal **************************************************************************/ private static void checkAgent(String name, String pass, RolePath rolePath, UUID uuid) throws Exception { Logger.msg(1, "Bootstrap.checkAgent() - Checking for existence of '"+name+"' user."); LookupManager lookup = Gateway.getLookupManager(); try { systemAgents.put(name, Gateway.getProxyManager().getAgentProxy(lookup.getAgentPath(name))); Logger.msg(3, "Bootstrap.checkAgent() - User '"+name+"' found."); return; } catch (ObjectNotFoundException ex) { } Logger.msg("Bootstrap.checkAgent() - User '"+name+"' not found. Creating."); try { AgentPath agentPath = new AgentPath(new ItemPath(uuid), name); agentPath.setPassword(pass); Gateway.getCorbaServer().createAgent(agentPath); lookup.add(agentPath); // assign admin role Logger.msg("Bootstrap.checkAgent() - Assigning role '"+rolePath.getName()+"'"); Gateway.getLookupManager().addRole(agentPath, rolePath); Gateway.getStorage().put(agentPath, new Property("Name", name, true), null); Gateway.getStorage().put(agentPath, new Property("Type", "Agent", false), null); systemAgents.put(name, Gateway.getProxyManager().getAgentProxy(agentPath)); } catch (Exception ex) { Logger.error("Unable to create "+name+" user."); throw ex; } } /** * */ public static void checkAdminAgents() throws Exception { // check for administrative user & admin role String adminPassword = Gateway.getProperties().getString("AdminPassword", "admin12345"); RolePath rootRole = new RolePath(); if (!rootRole.exists()) Gateway.getLookupManager().createRole(rootRole); RolePath adminRole = new RolePath(rootRole, "Admin", false); if (!adminRole.exists()) Gateway.getLookupManager().createRole(adminRole); // check for import user checkAgent("system", adminPassword, adminRole, new UUID(0, 0)); checkAgent("admin", adminPassword, adminRole, new UUID(0, 1)); // check for local usercode user & role RolePath usercodeRole = new RolePath(rootRole, "UserCode", true); if (!usercodeRole.exists()) Gateway.getLookupManager().createRole(usercodeRole); checkAgent(InetAddress.getLocalHost().getHostName(), "uc", usercodeRole, UUID.randomUUID()); } public static void createServerItem() throws Exception { LookupManager lookupManager = Gateway.getLookupManager(); String serverName = Gateway.getProperties().getString("ItemServer.name", InetAddress.getLocalHost().getHostName()); thisServerPath = new DomainPath("/servers/"+serverName); ItemPath serverEntity; try { serverEntity = thisServerPath.getItemPath(); } catch (ObjectNotFoundException ex) { Logger.msg("Creating server item "+thisServerPath); serverEntity = new ItemPath(); Gateway.getCorbaServer().createItem(serverEntity); lookupManager.add(serverEntity); thisServerPath.setItemPath(serverEntity); lookupManager.add(thisServerPath); } Gateway.getStorage().put(serverEntity, new Property("Name", serverName, false), null); Gateway.getStorage().put(serverEntity, new Property("Type", "Server", false), null); Gateway.getStorage().put(serverEntity, new Property("KernelVersion", Gateway.getKernelVersion(), true), null); int proxyPort = Gateway.getProperties().getInt("ItemServer.Proxy.port", 1553); Gateway.getStorage().put(serverEntity, new Property("ProxyPort", String.valueOf(proxyPort), false), null); Gateway.getStorage().put(serverEntity, new Property("ConsolePort", String.valueOf(Logger.getConsolePort()), true), null); Gateway.getProxyManager().connectToProxyServer(serverName, proxyPort); } public static void initServerItemWf() throws Exception { CompositeActivityDef serverWfCa = (CompositeActivityDef)LocalObjectLoader.getActDef("ServerItemWorkflow", 0); Workflow wf = new Workflow((CompositeActivity)serverWfCa.instantiate(), new ServerPredefinedStepContainer()); wf.initialise(thisServerPath.getItemPath(), systemAgents.get("system").getPath()); Gateway.getStorage().put(thisServerPath.getItemPath(), wf, null); } }