All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cristalise.kernel.process.Bootstrap Maven / Gradle / Ivy

/**
 * This file is part of the CRISTAL-iSE kernel.
 * Copyright (c) 2001-2015 The CRISTAL Consortium. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * http://www.fsf.org/licensing/licenses/lgpl.html
 */
package org.cristalise.kernel.process;

import static org.cristalise.kernel.property.BuiltInItemProperties.KERNEL_VERSION;
import static org.cristalise.kernel.property.BuiltInItemProperties.MODULE;
import static org.cristalise.kernel.property.BuiltInItemProperties.NAME;
import static org.cristalise.kernel.property.BuiltInItemProperties.TYPE;
import static org.cristalise.kernel.security.BuiltInAuthc.ADMIN_ROLE;
import static org.cristalise.kernel.security.BuiltInAuthc.SYSTEM_AGENT;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.cristalise.kernel.collection.Collection;
import org.cristalise.kernel.collection.CollectionArrayList;
import org.cristalise.kernel.common.InvalidDataException;
import org.cristalise.kernel.common.ObjectNotFoundException;
import org.cristalise.kernel.common.PersistencyException;
import org.cristalise.kernel.entity.proxy.AgentProxy;
import org.cristalise.kernel.entity.proxy.ItemProxy;
import org.cristalise.kernel.events.History;
import org.cristalise.kernel.lifecycle.CompositeActivityDef;
import org.cristalise.kernel.lifecycle.instance.CompositeActivity;
import org.cristalise.kernel.lifecycle.instance.Workflow;
import org.cristalise.kernel.lifecycle.instance.predefined.PredefinedStep;
import org.cristalise.kernel.lifecycle.instance.predefined.server.ServerPredefinedStepContainer;
import org.cristalise.kernel.lifecycle.instance.stateMachine.StateMachine;
import org.cristalise.kernel.lookup.AgentPath;
import org.cristalise.kernel.lookup.DomainPath;
import org.cristalise.kernel.lookup.InvalidItemPathException;
import org.cristalise.kernel.lookup.ItemPath;
import org.cristalise.kernel.lookup.LookupManager;
import org.cristalise.kernel.lookup.RolePath;
import org.cristalise.kernel.persistency.ClusterType;
import org.cristalise.kernel.persistency.outcome.Outcome;
import org.cristalise.kernel.persistency.outcome.Schema;
import org.cristalise.kernel.persistency.outcome.Viewpoint;
import org.cristalise.kernel.process.resource.BuiltInResources;
import org.cristalise.kernel.process.resource.ResourceImportHandler;
import org.cristalise.kernel.property.Property;
import org.cristalise.kernel.property.PropertyArrayList;
import org.cristalise.kernel.property.PropertyDescription;
import org.cristalise.kernel.property.PropertyDescriptionList;
import org.cristalise.kernel.scripting.ScriptConsole;
import org.cristalise.kernel.utils.FileStringUtility;
import org.cristalise.kernel.utils.LocalObjectLoader;
import org.cristalise.kernel.utils.Logger;


/**
 * Bootstrap loads all Items defined in the kernel resource XMLs and the module XML
 */
public class Bootstrap
{
    static DomainPath thisServerPath;
    static HashMap systemAgents = new HashMap();
    public static boolean shutdown = false;
    static StateMachine predefSM;

    /**
     * Get the StateMachine of a Predefined Step
     * 
     * @return the fully initialised StateMachine DescriptionObject
     * @throws ObjectNotFoundException StateMachine called 'PredefinedStep' version '0' does not exists
     * @throws InvalidDataException the stored state machine data was invalid
     */
    public static StateMachine getPredefSM() throws ObjectNotFoundException, InvalidDataException {
        if (predefSM == null) predefSM = LocalObjectLoader.getStateMachine("PredefinedStep", 0);

        return predefSM;
    }
    
    /**
     * Initialise Bootstrap
     * 
     * @throws Exception in case of any error
     */
    static void init() throws Exception {
        getPredefSM();

        // check for system agents
        checkAdminAgents();

        // create the server's mother item
        createServerItem();
    }

    /**
     * Run everything without timing-out the service wrapper
     */
    static void run() throws Exception {
        init();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.currentThread().setName("Bootstrapper");

                    Logger.msg("Bootstrap.run() - Bootstrapper started");

                    ClassLoader wClassLoader = Bootstrap.class.getClassLoader();
                    Logger.msg("Bootstrap.run() setContextClassLoader=[%s]", wClassLoader);
                    Thread.currentThread().setContextClassLoader(wClassLoader);

                    // make sure all of the boot items are up-to-date
                    if (!shutdown) {
                        Logger.msg("Bootstrap.run() - Verifying kernel boot data items");
                        verifyBootDataItems();
                    }

                    // verify the server item's wf
                    if (!shutdown) {
                        Logger.msg("Bootstrap.run() - Initialising Server Item Workflow");
                        initServerItemWf();
                    }

                    if (!shutdown) {
                        Gateway.getModuleManager().setUser(systemAgents.get(SYSTEM_AGENT.getName()));
                        Gateway.getModuleManager().registerModules();
                    }

                    if (!shutdown) {
                        Logger.msg("Bootstrap.run() - Bootstrapper complete");
                        Gateway.getModuleManager().runScripts("initialized");

                        if (Gateway.getLookupManager() != null) Gateway.getLookupManager().postBoostrap();
                        Gateway.getStorage().postBoostrap();
                    }
                }
                catch (Throwable e) {
                    Logger.error(e);
                    Logger.die("Exception performing bootstrap. Check that everything is OK.");
                }
            }
        }).start();
    }

    /**
     * Set flag for the thread to abort gracefully
     */
    public static void abort() {
        shutdown = true;
    }

    /**
     * Checks all kernel descriptions stored in resources and create or update them if they were changed
     */
    public static void verifyBootDataItems() throws Exception {
        String bootItems;
        Logger.msg(1, "Bootstrap.verifyBootDataItems() - Start checking kernel descriptions ...");

        bootItems = FileStringUtility.url2String(Gateway.getResource().getKernelResourceURL("boot/allbootitems.txt"));

        verifyBootDataItems(bootItems, null, true);

        Logger.msg(1, "Bootstrap.verifyBootDataItems() - DONE.");
    }

    /**
     *
     * @param bootList
     * @param ns
     * @param reset
     * @throws InvalidItemPathException
     */
    private static void verifyBootDataItems(String bootList, String ns, boolean reset) throws InvalidItemPathException {
        StringTokenizer str = new StringTokenizer(bootList, "\n\r");

        while (str.hasMoreTokens() && !shutdown) {
            String thisItem = str.nextToken();
            String[] idFilename = thisItem.split(",");
            String id = idFilename[0], filename = idFilename[1];
            ItemPath itemPath = new ItemPath(id);
            String[] fileParts = filename.split("/");
            String itemType = fileParts[0], itemName = fileParts[1];

            try {
                String location = "boot/"+filename+(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.");
            }
        }
    }


    /**
     * Create a resource item from its module definition. The item should not exist.
     */
    public static DomainPath createResource(String ns, String itemName, int version, String itemType, Set outcomes, boolean reset)
            throws Exception
    {
        return verifyResource(ns, itemName, version, itemType, null, outcomes, null, reset);
    }

    /**
     * Verify a resource item against a module version, using a ResourceImportHandler configured
     * to find outcomes at the given dataLocation
     */
    public static DomainPath verifyResource(String ns, String itemName, int version, String itemType, ItemPath itemPath, String dataLocation, boolean reset)
            throws Exception
    {
        return verifyResource(ns, itemName, version, itemType, itemPath, null, dataLocation, reset);
    }

    /**
     * Verify a resource item against a module version, but supplies the resource outcomes directly
     * instead of through a location lookup
     */
    public static DomainPath verifyResource(String ns, String itemName, int version, String itemType, ItemPath itemPath, Set outcomes, boolean reset)
            throws Exception
    {
        return verifyResource(ns, itemName, version, itemType, itemPath, outcomes, null, reset);
    }

    /**
     *
     * @param ns
     * @param itemName
     * @param version
     * @param itemType
     * @param itemPath
     * @param outcomes
     * @param dataLocation
     * @param reset
     * @return the Path of the resource either created or initialised from existing data
     * @throws Exception
     */
    private static DomainPath verifyResource(String ns, String itemName, int version, String itemType, ItemPath itemPath, Set outcomes, String dataLocation, boolean reset)
            throws Exception
    {
        ResourceImportHandler typeImpHandler = Gateway.getResourceImportHandler(BuiltInResources.getValue(itemType));

        Logger.msg(1, "Bootstrap.verifyResource() - Verifying "+typeImpHandler.getName()+" "+ itemName+" v"+version);

        // Find or create Item for Resource
        ItemProxy thisProxy;
        DomainPath modDomPath = typeImpHandler.getPath(itemName, ns);

        if (modDomPath.exists()) {
            Logger.msg(3, "Bootstrap.verifyResource() - Found "+typeImpHandler.getName()+" "+itemName + ".");

            thisProxy = verifyPathAndModuleProperty(ns, itemType, itemName, itemPath, modDomPath, modDomPath);
        }
        else {
            if (itemPath == null) itemPath = new ItemPath();

            Logger.msg("Bootstrap.verifyResource() - "+typeImpHandler.getName()+" "+itemName+" not found. Creating new.");

            thisProxy = createResourceItem(typeImpHandler, itemName, ns, itemPath);
        }

        // Verify/Import Outcomes, creating events and views as necessary
        if (outcomes == null || outcomes.size() == 0) {
            outcomes = typeImpHandler.getResourceOutcomes(itemName, ns, dataLocation, version);
        }

        if (outcomes.size() == 0) Logger.warning("Bootstrap.verifyResource() - no Outcome found therefore nothing stored!");

        for (Outcome newOutcome : outcomes) {
            if (checkToStoreOutcomeVersion(thisProxy, newOutcome, version, reset)) {
                // validate it, but not for kernel objects (ns == null) because those are to validate the rest
                if (ns != null) newOutcome.validateAndCheck();

                storeOutcomeEventAndViews(thisProxy, newOutcome, version);

                CollectionArrayList cols = typeImpHandler.getCollections(itemName, version, newOutcome);

                for (Collection col : cols.list) {
                    Gateway.getStorage().put(thisProxy.getPath(), col, thisProxy);
                    Gateway.getStorage().clearCache(thisProxy.getPath(), ClusterType.COLLECTION+"/"+col.getName());
                    col.setVersion(null);
                    Gateway.getStorage().put(thisProxy.getPath(), col, thisProxy);
                }
            }
        }
        Gateway.getStorage().commit(thisProxy);
        return modDomPath;
    }

    /**
     * Verify module property and location
     *
     * @param ns
     * @param itemType
     * @param itemName
     * @param itemPath
     * @param modDomPath
     * @param path
     * @return the ItemProxy either create or initialised for existing
     * @throws Exception
     */
    private static ItemProxy verifyPathAndModuleProperty(String ns, String itemType, String itemName, ItemPath itemPath, DomainPath modDomPath, DomainPath path)
            throws Exception
    {
        LookupManager lookupManager = Gateway.getLookupManager();
        ItemProxy 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();

        String moduleName = (ns==null?"kernel":ns);
        String itemModule;
        try {
            itemModule = thisProxy.getProperty("Module");
            if (itemModule != null && !itemModule.equals("") && !itemModule.equals("null") && !moduleName.equals(itemModule)) {
                String error = "Module clash! Resource '"+itemName+"' included in module "+moduleName+" but is assigned to '"+itemModule + "'.";
                Logger.error(error);
                throw new InvalidDataException(error);
            }
        }
        catch (ObjectNotFoundException ex) {
            itemModule = "";
        }

        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);
        }
        return thisProxy;
    }

    /**
     *
     * @param item
     * @param newOutcome
     * @param version
     * @throws PersistencyException
     * @throws ObjectNotFoundException
     * @throws InvalidDataException
     */
    private static void storeOutcomeEventAndViews(ItemProxy item, Outcome newOutcome, int version)
            throws PersistencyException, ObjectNotFoundException, InvalidDataException
    {
        Logger.msg("Bootstrap.storeOutcomeEventAndViews() - Writing new " + newOutcome.getSchema().getName() + " v" + version + " to "+item.getName());

        History hist = new History( item.getPath(), item);
        String viewName = String.valueOf(version);

        int eventID = hist.addEvent( systemAgents.get(SYSTEM_AGENT.getName()).getPath(), null,
                ADMIN_ROLE.getName(), "Bootstrap", "Bootstrap", "Bootstrap",
                newOutcome.getSchema(), getPredefSM(), PredefinedStep.DONE, viewName
                ).getID();

        newOutcome.setID(eventID);

        Viewpoint newLastView   = new Viewpoint(item.getPath(), newOutcome.getSchema(), "last",   eventID);
        Viewpoint newNumberView = new Viewpoint(item.getPath(), newOutcome.getSchema(), viewName, eventID);

        Gateway.getStorage().put(item.getPath(), newOutcome,    item);
        Gateway.getStorage().put(item.getPath(), newLastView,   item);
        Gateway.getStorage().put(item.getPath(), newNumberView, item);
    }

    /**
     *
     * @param item
     * @param newOutcome
     * @param version
     * @param reset
     * @return true i the data was changed, since the last Bootstrap run
     * @throws PersistencyException
     * @throws InvalidDataException
     * @throws ObjectNotFoundException
     */
    private static boolean checkToStoreOutcomeVersion(ItemProxy item, Outcome newOutcome, int version, boolean reset)
            throws PersistencyException, InvalidDataException, ObjectNotFoundException
    {
        Schema schema = newOutcome.getSchema();
        try {
            Viewpoint currentData = (Viewpoint) item.getObject(ClusterType.VIEWPOINT+"/"+newOutcome.getSchema().getName()+"/"+version);

            if (newOutcome.isIdentical(currentData.getOutcome())) {
                Logger.msg(5, "Bootstrap.checkToStoreOutcomeVersion() - Data identical, no update required");
                return false;
            }
            else {
                if (!reset  && !currentData.getEvent().getStepPath().equals("Bootstrap")) {
                    Logger.msg("Bootstrap.checkToStoreOutcomeVersion() - Version " + version + " was not set by Bootstrap, and reset not requested. Not overwriting.");
                    return false;
                }
            }
        }
        catch (ObjectNotFoundException ex) {
            Logger.msg("Bootstrap.checkToStoreOutcomeVersion() - "+schema.getName()+" "+item.getName()+" v"+version+" not found! Attempting to insert new.");
        }
        return true;
    }

    /**
     *
     * @param impHandler
     * @param itemName
     * @param ns
     * @param itemPath
     * @return the ItemProxy representing the newly create Item
     * @throws Exception
     */
    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  = pd.getDefaultValue();

            if (propName.equals(NAME.toString()))        propVal = itemName;
            else if (propName.equals(MODULE.toString())) propVal = (ns == null) ? "kernel" : ns;

            props.list.add(new Property(propName, propVal, pd.getIsMutable()));
        }

        CompositeActivity ca = new CompositeActivity();
        try {
            ca = (CompositeActivity) ((CompositeActivityDef)LocalObjectLoader.getActDef(impHandler.getWorkflowName(), 0)).instantiate();
        }
        catch (ObjectNotFoundException ex) {
            Logger.error(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_AGENT.getName()).getPath(), props, ca, null);
        return newItemProxy;
    }

    /**
     * Checks for the existence of a agents and creates it if needed so it can be used
     *
     * @param name the name of the agent
     * @param pass the password of the agent
     * @param rolePath the role of the agent
     * @param uuid the UUID os the agent
     * @return the Proxy representing the Agent
     * @throws Exception any exception found
     */
    private static AgentProxy checkAgent(String name, String pass, RolePath rolePath, String uuid) throws Exception {
        Logger.msg(1, "Bootstrap.checkAgent() - Checking for existence of '"+name+"' agent.");
        LookupManager lookup = Gateway.getLookupManager();

        try {
            AgentProxy agentProxy = Gateway.getProxyManager().getAgentProxy(lookup.getAgentPath(name));
            systemAgents.put(name, agentProxy);
            Logger.msg(3, "Bootstrap.checkAgent() - Agent '"+name+"' found.");
            return agentProxy;
        }
        catch (ObjectNotFoundException ex) { }

        Logger.msg("Bootstrap.checkAgent() - Agent '"+name+"' not found. Creating.");

        try {
            AgentPath agentPath = new AgentPath(new ItemPath(uuid), name);

            Gateway.getCorbaServer().createAgent(agentPath);
            lookup.add(agentPath);

            if (StringUtils.isNotBlank(pass)) lookup.setAgentPassword(agentPath, pass);

            // assign 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);
            AgentProxy agentProxy = Gateway.getProxyManager().getAgentProxy(agentPath);
            //TODO: properly init agent here with wf, props and colls -> use CreatItemFromDescription
            systemAgents.put(name, agentProxy);
            return agentProxy;
        }
        catch (Exception ex) {
            Logger.error("Unable to create '"+name+"' Agent.");
            throw ex;
        }
    }

    /**
     * 
     * @throws Exception
     */
    public static void checkAdminAgents() throws Exception {
        RolePath rootRole = new RolePath();
        if (!rootRole.exists()) Gateway.getLookupManager().createRole(rootRole);

        // check for admin role
        RolePath adminRole = new RolePath(rootRole, ADMIN_ROLE.getName(), false);
        if (!adminRole.exists()) Gateway.getLookupManager().createRole(adminRole);
        Gateway.getLookupManager().setPermission(adminRole, "*");

        // check for import Agent
        AgentProxy system = checkAgent(SYSTEM_AGENT.getName(), null, adminRole, new UUID(0, 1).toString());
        ScriptConsole.setUser(system);

        String ucRole = Gateway.getProperties().getString("UserCode.roleOverride", UserCodeProcess.DEFAULT_ROLE);

        // check for local usercode user & role
        RolePath usercodeRole = new RolePath(rootRole, ucRole, true);
        if (!usercodeRole.exists()) Gateway.getLookupManager().createRole(usercodeRole);
        checkAgent(
                Gateway.getProperties().getString(ucRole + ".agent",     InetAddress.getLocalHost().getHostName()),
                Gateway.getProperties().getString(ucRole + ".password", "uc"),
                usercodeRole,
                UUID.randomUUID().toString());
    }

    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 serverItem;
        try {
            serverItem = thisServerPath.getItemPath();
        }
        catch (ObjectNotFoundException ex) {
            Logger.msg("Creating server item "+thisServerPath);
            serverItem = new ItemPath();
            Gateway.getCorbaServer().createItem(serverItem);
            lookupManager.add(serverItem);
            thisServerPath.setItemPath(serverItem);
            lookupManager.add(thisServerPath);
        }

        int proxyPort = Gateway.getProperties().getInt("ItemServer.Proxy.port", 1553);

        Gateway.getStorage().put(serverItem, new Property(NAME,            serverName,                              false), null);
        Gateway.getStorage().put(serverItem, new Property(TYPE,            "Server",                                false), null);
        Gateway.getStorage().put(serverItem, new Property(KERNEL_VERSION,  Gateway.getKernelVersion(),              true),  null);
        Gateway.getStorage().put(serverItem, new Property("ProxyPort",     String.valueOf(proxyPort),               false), null);
        Gateway.getStorage().put(serverItem, 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_AGENT.getName()).getPath(), null);
        Gateway.getStorage().put(thisServerPath.getItemPath(), wf, null);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy