Package org.jdesktop.wonderland.modules.service

Source Code of org.jdesktop.wonderland.modules.service.ModuleManager

/**
* Open Wonderland
*
* Copyright (c) 2010, Open Wonderland Foundation, All Rights Reserved
*
* Redistributions in source code form must reproduce the above
* copyright and this condition.
*
* The contents of this file are subject to the GNU General Public
* License, Version 2 (the "License"); you may not use this file
* except in compliance with the License. A copy of the License is
* available at http://www.opensource.org/licenses/gpl-license.php.
*
* The Open Wonderland Foundation designates this particular file as
* subject to the "Classpath" exception as provided by the Open Wonderland
* Foundation in the License file that accompanied this code.
*/

/**
* Project Wonderland
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc., All Rights Reserved
*
* Redistributions in source code form must reproduce the above
* copyright and this condition.
*
* The contents of this file are subject to the GNU General Public
* License, Version 2 (the "License"); you may not use this file
* except in compliance with the License. A copy of the License is
* available at http://www.opensource.org/licenses/gpl-license.php.
*
* Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the License file that accompanied
* this code.
*/
package org.jdesktop.wonderland.modules.service;

import java.io.File;
import java.io.FileWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jdesktop.wonderland.modules.Module;
import org.jdesktop.wonderland.common.modules.ModuleInfo;
import org.jdesktop.wonderland.common.modules.ModuleRequires;
import org.jdesktop.wonderland.modules.service.DeployManager.DeploymentQueryResult;
import org.jdesktop.wonderland.modules.service.ModuleOverwriteUtils.OverwriteQueryResult;
import org.jdesktop.wonderland.utils.RunUtil;


/**
* The ModuleManager class manages the modules on the Wonderland server. It
* enumerates the collection of installed modules on the system. During each
* restart (or when a management 'reload' message is received), it scans the
* module installation directory for modules to be installed or removed and
* updates the system.
* <p>
* TBD - Description of module state in order here
*
* @author Jordan Slott <jslott@dev.java.net>
*/
public class ModuleManager {

    /* The base module directory, and for the add/, pending/, and installed/ */
    private File root = null;
   
    /* Manages all of the deployers in the system */
    private DeployManager deployManager = null;
   
    /* Manages all of the modules that are pending for installation */
    private PendingManager pendingMananger = null;

    /* Manages all of the modules that are installed */
    private InstallManager installedMananger = null;
   
    /* Manages all of the modules to be uninstalled */
    private UninstallManager uninstallManager = null;
   
    /* The logger for the module manager */
    private static final Logger logger = Logger.getLogger(ModuleManager.class.getName());
   
    /**
     * The TaggedModule is an immutable class that represents a module to be
     * installed that is 'tagged' with a certain set of key-value pairs.
     */
    public static class TaggedModule {
        private File file;
        private Map<String, String> attributes;
       
        public TaggedModule(File file, Map<String, String> attributes) {
            this.file = file;
            this.attributes = attributes;
        }
       
        public File getFile() { return this.file; }
        public Map<String, String> getAttributes() { return this.attributes; }
    }
   
    /** Constructor */
    private ModuleManager() {
        // Put the "modules/" directory underneath the content directory
        File contentDir = RunUtil.getContentDir();
        root = new File(contentDir, "modules");
        logger.info("Wonderland modules base directory: " + root.getAbsolutePath());
       
        /* Set the base directory for the module system, create it if necessary */
        try {
            if (this.root.exists() == false) {
                ModuleManagerUtils.makeDirectory(this.root);
            }
        } catch (java.io.IOException excp) {
            logger.severe("[MODULES] Failed to create root " + this.root.getAbsolutePath());
            logger.severe("[MODULES] " + excp.toString());
            System.exit(1);
        }
       
        /* Create the managers to handle the whole module lifecycle */
        this.deployManager = new DeployManager();
        this.pendingMananger = new PendingManager(root);
        this.installedMananger = new InstallManager(root);
        this.uninstallManager = new UninstallManager(root);
    }
   
    /**
     * Singleton to hold instance of ModuleManager. This holder class is loaded
     * on the first execution of ModuleManager.getModuleManager().
     */
    private static class ModuleManagerHolder {
        private final static ModuleManager moduleManager = new ModuleManager();
    }
   
    /**
     * Returns a single instance of this class
     * <p>
     * @return Single instance of this class.
     */
    public static final ModuleManager getModuleManager() {
        return ModuleManagerHolder.moduleManager;
    }
   
    /**
     * Returns the error logger associated with this class.
     *
     * @return The error logger
     */
    public static Logger getLogger() {
        return ModuleManager.logger;
    }
   
    /**
     * Redeploys all installed modules. This method does not check whether
     * modules can or cannot be deployed, it assumes this method is called when
     * the system is in an appropriate state for deployment
     * <p>
     * Before redeploying, this method installs all pending modules. No modules
     * are deployed until all the pending modules are installed.
     */
    public void redeployAll() {
        // remove all modules pending for removal
        uninstallAll();

        // install all modules pending for install
        installAll(false);

        // deploy all modules
        Map<String, Module> modules = this.installedMananger.getModules();

        // calculate a valid deployment order
        List<String> order = DeployManager.getDeploymentOrder(modules);
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("[MODULES] Calculated deployment order: " + order.toString());
        }

        logger.warning("[MODULES] deploying " + order.size() + " modules.");

        for (String name : order) {
            Module module = modules.get(name);

            try {
                this.deployManager.deploy(module);
            } catch (DeployerException excp) {
                /* Log a warning message and continue */
                logger.log(Level.WARNING, "[MODULE] REDEPLOY FAILED FOR " +
                        excp.getModule().getName() + " BY " +
                        excp.getDeployerName(), excp);
            }
        }
    }

    /**
     * Attempts to add a collection of modules to install. Takes the Files of
     * Jar files containing the modules.
     */
    public Collection<Module> addToInstall(Collection<File> moduleFiles) {
        /* Returns a collection of modules added */
        Collection<Module> added = new LinkedList<Module>();
       
        /* Iterate through each module URL and make it a pending module */
        Iterator<File> it = moduleFiles.iterator();
        while (it.hasNext() == true) {
            File file = it.next();
            Module module = this.pendingMananger.add(file);
            if (module == null) {
                logger.warning("[MODULES] INSTALL Failed to add " + file);
                continue;
            }
            added.add(module);
        }
        return added;
    }

    /**
     * Attempts to add a collection of modules to install. Takes a collection
     * of TaggedModules as an argument.
     *
     * @param taggedModules
     * @return
     */
    public Collection<Module> addTaggedToInstall(Collection<TaggedModule> taggedModules) {
        /* Returns a collection of modules added */
        Collection<Module> added = new LinkedList<Module>();
       
        /*
         * Iterate through each module URL and make it a pending module
         */
        Iterator<TaggedModule> it = taggedModules.iterator();
        while (it.hasNext() == true) {
            /* Fetch the next tagged module in the collection */
            TaggedModule tm = it.next();
            File file = tm.getFile();
            Map<String, String> attributes = tm.getAttributes();
           
            /* Give the File to the manager of pending modules to add */
            Module module = this.pendingMananger.add(file);
            if (module == null) {
                logger.warning("[MODULES] INSTALL Failed to add " + file);
                continue;
            }
           
            /* See if we want to set attributes on the module and add if so */
            if (attributes != null) {
                ModuleInfo info = module.getInfo();
                info.putAttibutes(attributes);
                File infoFile = module.getFile(Module.MODULE_INFO);
                try {
                    FileWriter writer = new FileWriter(infoFile);
                    info.encode(writer);
                    writer.close();
                } catch (Exception ex) {
                    logger.log(Level.WARNING, "[MODULES] INSTALL Failed to update module.xml", ex);
                }
            }
           
            /* Add to the list of modules waiting to be installed */
            added.add(module);
        }
        return added;
    }
   
    /**
     * Attempts to remove a collection of modules. Returns a new collection of
     * all of the module names that were successfully removed and now pending
     * for un installation (during the next commit()). Note that a "removed"
     * module is still present in the system until the next commit(), during
     * which it is "uninstalled".
     *
     * @param removedModules A collection of modules to remove
     * @return The names of the successfully removed modules
     */
    public Collection<String> addToUninstall(Collection<String> moduleNames) {
        /* Returns a collection of module names removed */
        Collection<String> removed = new LinkedList<String>();
       
        /*
         * Make a copy of the map of removed modules so that we do not modify
         * the argument. We first need to make sure that these modules are
         * actually installed. If not, log a message and remove it from the
         * map.
         */
        Iterator<String> it = moduleNames.iterator();
        Map<String, Module> installed = this.getInstalledModules();
        while (it.hasNext() == true) {
            String moduleName = it.next();
            Module module = installed.get(moduleName);
            logger.warning("ADD TO UNINSTALL " + moduleName + " " + module);
            if (module != null) {
                this.uninstallManager.add(moduleName, module.getInfo());
                removed.add(moduleName);
            }
        }
        return removed;
    }

    /**
     * Installs all of the pending modules. This checks for all of the modules
     * that can be installed given dependency checks and whether the server
     * is started and stopped.
     */
    public void installAll() {
        installAll(true);
    }

    /**
     * Installs all pending modules.  The value of the deploy boolean tells
     * whether or not to deploy modules after they are installed.  This is
     * used at startup so that all modules are deployed at the same time,
     * after they are installed.
     * @param deploy true to deploy modules, or false not to
     */
    protected void installAll(boolean deploy) {
        Map<String, Module> installed = new HashMap(this.installedMananger.getModules());
      
        /*
         * Make a copy of the list of modules to be installed. Check whether
         * they can be deployed and remove from the list if not.
         */
        Map<String, Module> pending = new HashMap(this.pendingMananger.getModules());
        Iterator<Map.Entry<String, Module>> it = pending.entrySet().iterator();
        while (it.hasNext() == true) {
            Map.Entry<String, Module> entry = it.next();
            Module module = entry.getValue();
            DeploymentQueryResult res = this.deployManager.canDeploy(module);
            if (res.getResult() == false) {
                StringBuffer message = new StringBuffer("[MODULES] Unable to install " +
                                                        module.getName() + ":\n");
                for (String reason : res.getReasons()) {
                    message.append(reason + "\n");
                }
                logger.warning(message.toString());
                it.remove();
            }
        }
       
        /*
         * Check to see that the module can be safely installed by making sure
         * that first its dependencies are met.
         */
        Map<Module, List<ModuleInfo>> failures =
                new LinkedHashMap<Module, List<ModuleInfo>>();
        Map<String, Module> passed = this.checkDependencies(pending, failures);

        /* Format a message to describe any failures */
        if (failures.isEmpty() == false) {
            StringBuffer failureMessage = new StringBuffer("[MODULES] Module dependency failures: \n");
            for (Map.Entry<Module, List<ModuleInfo>> e : failures.entrySet()) {
                failureMessage.append("Module " + e.getKey().getName() +
                                      " depends on ");
                for (ModuleInfo depend : e.getValue()) {
                    failureMessage.append(depend.getName() + " ");
                    failureMessage.append(" v. " + depend.getMajor() + ".");
                    failureMessage.append(depend.getMinor() + ".");
                    failureMessage.append(depend.getMini() + " ");
                }
                failureMessage.append("\n");
            }
            logger.warning(failureMessage.toString());
        }


        /*
         * Next check whether the module is overwriting an existing installed
         * module. Make sure that the new version of the module does not
         * violate the dependencies of other modules.
         */
        Iterator<Map.Entry<String, Module>> it1 = passed.entrySet().iterator();
        while (it1.hasNext() == true) {
            Map.Entry<String, Module> entry = it1.next();
            ModuleInfo info = entry.getValue().getInfo();
           
            OverwriteQueryResult res = ModuleOverwriteUtils.canOverwrite(info);
            if (res.getResult() == false) {
                StringBuffer message = new StringBuffer("[MODULES] Unable to replace module " +
                                                        info.getName() + ":\n");
                for (String reason : res.getReasons()) {
                    message.append(reason + "\n");
                }
                logger.warning(message.toString());

                it1.remove();
            }
        }
       
        /*
         * Go ahead and install the module and deploy.  Make sure to do
         * this in a valid deploy order
         */
        List<String> ordered = DeployManager.getDeploymentOrder(passed);
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("[MODULES] Calculated deployment order: " + ordered.toString());
        }
       
        for (String moduleName : ordered) {
            Module module = passed.get(moduleName);
           
            /*
             * Check to see if the module is already installed. If we have
             * reached here it means that we can safely uninstall the module.
             * But we first have to undeploy it.
             */
            if (installed.containsKey(moduleName) == true) {
                try {
                    this.deployManager.undeploy(module);
                } catch (DeployerException excp) {
                    logger.log(Level.WARNING, "[MODULES] INSTALL ALL Unable to undeploy " + moduleName, excp);
                }
            }
           
            /*
             * Install the module into the installed/ directory. Fetch the
             * newly installed module (which differs from the pending Module)
             */
            File file = module.getFile();
            module = this.installedMananger.add(moduleName,file);
            if (module == null) {
                logger.warning("[MODULES] INSTALL ALL Failed on " + moduleName);
                continue;
            }
           
            /* Remove from the pending/ directory */
            this.pendingMananger.remove(moduleName);
           
            /* Deploy the module */
            if (deploy) {
                try {
                    this.deployManager.deploy(module);
                } catch (DeployerException excp) {
                    logger.log(Level.WARNING, "[MODULES] INSTALL ALL Unable to deploy " + moduleName, excp);
                }
            }
        }
    }
    /**
     * Uninstalls all of the modules waiting to be uninstalled if possible.
     * Checks for the modules that can be uninstalled and removes them.
     */
    public void uninstallAll() {
        /*
         * Make a copy of the list of modules to be uninstalled. Check whether
         * they require the server to be stopped.
         */
        Map<String, ModuleInfo> uninstall = new HashMap(this.uninstallManager.getModules());
        Iterator<Map.Entry<String, ModuleInfo>> it = uninstall.entrySet().iterator();
        Map<String, Module> installed = this.installedMananger.getModules();
        while (it.hasNext() == true) {
            Map.Entry<String, ModuleInfo> entry = it.next();
            String moduleName = entry.getKey();
            Module module = installed.get(moduleName);

            // OWL issue #165: if the module doesn't exist, remove it from
            // the uninstall list and move on. The reference to the file
            // should be removed the next time the uninstall list is
            // written
            if (module == null) {
                logger.warning("Module " + moduleName + " no longer installed. "
                        + "Skipping.");
               
                it.remove();
                continue;
            }

            DeploymentQueryResult res = this.deployManager.canUndeploy(module);
            if (res.getResult() == false) {
                StringBuffer message = new StringBuffer("[MODULES] Unable to uninstall " +
                                                        module.getName() + ":\n");
                for (String reason : res.getReasons()) {
                    message.append(reason + "\n");
                }
                logger.warning(message.toString());
                it.remove();
            }
        }
       
        /*
         * Check to see that the module can be safely removed by making sure that
         * first it is no longer required
         */
        Map<String, Set<ModuleInfo>> failures = new LinkedHashMap<String, Set<ModuleInfo>>();
        Map<String, ModuleInfo> checked = this.checkRequired(uninstall, failures);

        /* Format a message to describe any failures */
        if (failures.isEmpty() == false) {
            StringBuffer failureMessage = new StringBuffer("[MODULES] Module dependency failures: \n");
            for (Map.Entry<String, Set<ModuleInfo>> e : failures.entrySet()) {
                failureMessage.append("Modules that depend on " + e.getKey() + " ");
                for (ModuleInfo depend : e.getValue()) {
                    failureMessage.append(depend.getName() + " ");
                }
                failureMessage.append("\n");
            }
            logger.warning(failureMessage.toString());
        }

        /*
         * For all of the modules that can be uninstalled, undeploy them and
         * uninstall them
         */
        Iterator<Map.Entry<String, ModuleInfo>> it2 = checked.entrySet().iterator();
        while (it2.hasNext() == true) {
            Map.Entry<String, ModuleInfo> entry = it2.next();
            String moduleName = entry.getKey();
           
            /* Undeploy the module, log the error if it happens (should be rare) */
            Module module = installed.get(moduleName);
            try {
                this.deployManager.undeploy(module);
            } catch (DeployerException excp) {
                logger.log(Level.WARNING, "[MODULES] UNINSTALL Failed to Undeploy", excp);
            }
            this.installedMananger.remove(moduleName);
            this.uninstallManager.remove(moduleName);
        }

        // OWL issue #165: make sure the uninstall list gets written here,
        // to guarantee that any failed uninstalls will be cleaned up
        this.uninstallManager.write();
    }
   
    /**
     * Returns a map of module names and objects currently installed in the
     * system. If no modules are installed, this method returns an empty map.
     *
     * @return A map of unique installed module names and their Module objects
     */
    public Map<String, Module> getInstalledModules() {
        return new HashMap(this.installedMananger.getModules());
    }

    /**
     * Returns a map of module names and objects currently pending installation
     * in the system. If no modules are pending installation, this method
     * returns an empty map.
     *
     * @return A map of unique pending module names and their Module objects
     */
    public Map<String, Module> getPendingModules() {
        return new HashMap(this.pendingMananger.getModules());
    }
   
    /**
     * Returns a map of moduel names and info objects currently waiting for
     * uninstall in the system. If no modules are pending uninstall, this
     * method returns an empty map.
     *
     * @return A map of unique uninstall module names and their info objects
     */
    public Map<String, ModuleInfo> getUninstallModuleInfos() {
        return new HashMap(this.uninstallManager.getModules());
    }
   
    /**
     * Returns a map of installed modules that posses a property with a certain
     * key
     */
    public Map<String, Module> getInstalledModulesByKey(String key) {
        Map<String, Module> keyed = new HashMap();
        Map<String, Module> installed = this.installedMananger.getModules();
        Iterator<Map.Entry<String, Module>> it = installed.entrySet().iterator();
        while (it.hasNext() == true) {
            Map.Entry<String, Module> entry = it.next();
            String moduleName = entry.getKey();
            Module module = entry.getValue();
            if (module.getInfo().getAttribute(key) != null) {
                keyed.put(moduleName, module);
            }
        }
        return keyed;
    }
   
    /**
     * Checks whether a collection of modules asked to be removed are still
     * required and returns a collection of modules that are no longer required.
     * This method iteratres until it can find no more modules that are no
     * longer required.
     *
     * @param removedModules A collection of module infos to check
     * @param failures if non-null, this list will be filled in with
     * a list of modules for which the dependency check fails and the
     * unsatisfied dependencies
     * @return A collection of modules that are no longer required
     */
    private Map<String, ModuleInfo> checkRequired(Map<String, ModuleInfo> removedModules,
                                                  Map<String, Set<ModuleInfo>> failures)
    {
        Map<String, ModuleInfo> satisfied = new HashMap<String, ModuleInfo>();
       
        /*
         * Create a map of ModuleRequireCheck classes for each of the modules
         * we wish to check for removal
         */
        HashMap<String, ModuleRequiredCheck> required = new HashMap();
        Iterator<Map.Entry<String, ModuleInfo>> it = removedModules.entrySet().iterator();
        while (it.hasNext() == true) {
            Map.Entry<String, ModuleInfo> entry = it.next();
            ModuleInfo info = entry.getValue();
            required.put(info.getName(), new ModuleRequiredCheck(info));
        }
       
        /*
         * Fetch a map of installed modules. Loop through each and add as
         * requirements to the modules if they are being asked to be removed.
         */
        Map<String, Module> present = this.getInstalledModules();
        Iterator<Map.Entry<String, Module>> it2 = present.entrySet().iterator();
        while (it2.hasNext() == true) {
            /*
             * Fetch the map of modules that this module requires
             */
            Map.Entry<String, Module> entry = it2.next();
            String moduleName = entry.getKey();
            Module module = entry.getValue();
            ModuleInfo info = module.getInfo();
            ModuleRequires requirements = module.getRequires();
           
            /*
             * Loop through each of the requirements of the module and add it
             * to the ModuleRequiredCheck, if it exists. (If it does exist, it
             * means we are checking to see if the module is still required and
             * we want to flag it with this module).
             */
            for (ModuleInfo infoRequires : requirements.getRequires()) {
                ModuleRequiredCheck check = required.get(infoRequires.getName());
                if (check != null) {
                    check.addRequiresModuleInfo(info);
                }
            }
        }
       
        /*
         * Next we need to loop through and see which modules are no longer
         * required. When a module is no longer required, we should add it to
         * the map of satisfied modules and also remove it from all of the
         * other module requirement checks. We continue checking until we can
         * find no more additional modules that are no longer requires.
         */
        boolean found = true;
        while (found == true) {
            found = false;
            Iterator<Map.Entry<String, ModuleRequiredCheck>> it4 = required.entrySet().iterator();
            while (it4.hasNext() == true) {
                Map.Entry<String, ModuleRequiredCheck> entry = it4.next();
               
                /*
                 * If the module is no longer required, then...
                 */
                if (entry.getValue().isRequired() == false) {
                    /* Add it to the 'satified map' */
                    ModuleInfo moduleInfo = entry.getValue().getCheckedModuleInfo();
                    satisfied.put(moduleInfo.getName(), moduleInfo);
                   
                    /* Remove it from the dependency map using the iterator */
                    it4.remove();
                   
                    /*
                     * Iterator over the remaining required check objects. This
                     * part assumes the following works properly in Java: nested
                     * iterations where we just removed an entry from the original
                     * map using the Iterator.remove() method
                     */
                    Iterator<Map.Entry<String, ModuleRequiredCheck>> it5 = required.entrySet().iterator();
                    while (it5.hasNext() == true) {
                        Map.Entry<String, ModuleRequiredCheck> check = it5.next();
                        check.getValue().checkRequired(moduleInfo);
                    }
                   
                    /* Indicate we have found more satified modules */
                    found = true;
                }
            }
           
            /* If there are no more modules left, then we are done */
            if (required.isEmpty() == true) {
                break;
            }
        }

        if (failures != null) {
            for (Map.Entry<String, ModuleRequiredCheck> e : required.entrySet()) {
                failures.put(e.getKey(), e.getValue().getRequires());
            }
        }

        return satisfied;
    }
   
    /**
     * Checks the dependencies for a collection of modules and returns a
     * collection of modules whose requirements have been met. This method
     * iterates until it can satify the requirements of added modules no longer.
     *
     * @param modules A collection of modules to check dependencies
     * @param failures if non-null, this map will be filled in with
     * a list of modules for which the dependency check fails and the
     * unsatisfied dependencies
     * @return A collection of moduels with satified dependencies
     */
    private Map<String, Module> checkDependencies(Map<String, Module> modules,
                                        Map<Module, List<ModuleInfo>> failures)
    {
        Map<String, Module> satisfied = new HashMap<String, Module>();
       
        /*
         * Create a map of ModuleDependencyCheck classes for each of the
         * modules we wish to add.
         */
        HashMap<Module, ModuleDependencyCheck> dependencies = new HashMap();
        Iterator<Map.Entry<String, Module>> it = modules.entrySet().iterator();
        while (it.hasNext() == true) {
            Map.Entry<String, Module> entry = it.next();
            Module module = entry.getValue();
            dependencies.put(module, new ModuleDependencyCheck(module));
        }
       
        /*
         * Fetch a map of installed. Loop through each and see if any of the
         * added modules depends upon the installed module. If so, mark the
         * dependency as met.
         */
        Map<String, Module> present = this.getInstalledModules();
        Iterator<Map.Entry<String, Module>> it2 = present.entrySet().iterator();
        while (it2.hasNext() == true) {
            ModuleInfo potentialDependency = it2.next().getValue().getInfo();
            Iterator<Map.Entry<Module, ModuleDependencyCheck>> it3 = dependencies.entrySet().iterator();
            while (it3.hasNext() == true) {
                ModuleDependencyCheck check = it3.next().getValue();
                check.checkDependency(potentialDependency);
            }
        }
       
        /*
         * Next we need to loop through and see which modules have had their
         * requirements met. When a module has all of its requirements met, then
         * we should add it to the map of satified modules and also remove it
         * from all of the other module dependency checks. We continue checking
         * until we can find no more additional modules requirements met.
         */
        boolean found = true;
        while (found == true) {
            found = false;
            Iterator<Map.Entry<Module, ModuleDependencyCheck>> it4 = dependencies.entrySet().iterator();
            while (it4.hasNext() == true) {
                Map.Entry<Module, ModuleDependencyCheck> entry = it4.next();
                Module module = entry.getKey();
                String moduleName = module.getName();
                ModuleDependencyCheck mdc = entry.getValue();
               
                /*
                 * If the module has all of its requirements met and it is not
                 * already in the map of modules who have had their requirements
                 * met (meaning, this is the first time we see it has had its
                 * requirements met), then...
                 */
                if (mdc.isDependenciesMet() == true && satisfied.containsKey(moduleName) == false) {
                    /* Add it to the 'satified map' */
                    satisfied.put(moduleName, module);
                   
                    /* Remove it from the dependency map using the iterator */
                    it4.remove();
                   
                    /*
                     * Iterator over the remaining dependency check objects. This
                     * part assumes the following works properly in Java: nested
                     * iterations where we just removed an entry from the original
                     * map using the Iterator.remove() method
                     */
                    ModuleInfo moduleInfo = module.getInfo();
                    Iterator<Map.Entry<Module, ModuleDependencyCheck>> it5 = dependencies.entrySet().iterator();
                    while (it5.hasNext() == true) {
                        Map.Entry<Module, ModuleDependencyCheck> check = it5.next();
                        check.getValue().checkDependency(moduleInfo);
                    }
                   
                    /* Indicate we have found more satified modules */
                    found = true;
                }
            }
           
            /* If there are no more modules left, then we are done */
            if (dependencies.isEmpty() == true) {
                break;
            }
        }

        /* Populate the list of failed modules */
        if (failures != null) {
            for (Map.Entry<Module, ModuleDependencyCheck> e : dependencies.entrySet()) {
                failures.put(e.getKey(), e.getValue().getUnmetDependencies());
            }
        }
       
        return satisfied;
    }
}
TOP

Related Classes of org.jdesktop.wonderland.modules.service.ModuleManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.