info.magnolia.module.ModuleManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for info.magnolia.module.ModuleManagerImpl.java

Source

/**
 * This file Copyright (c) 2003-2012 Magnolia International
 * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
 *
 *
 * This file is dual-licensed under both the Magnolia
 * Network Agreement and the GNU General Public License.
 * You may elect to use one or the other of these licenses.
 *
 * This file is distributed in the hope that it will be
 * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
 * Redistribution, except as permitted by whichever of the GPL
 * or MNA you select, is prohibited.
 *
 * 1. For the GPL license (GPL), you can redistribute and/or
 * modify this file under the terms of the GNU General
 * Public License, Version 3, as published by the Free Software
 * Foundation.  You should have received a copy of the GNU
 * General Public License, Version 3 along with this program;
 * if not, write to the Free Software Foundation, Inc., 51
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * 2. For the Magnolia Network Agreement (MNA), this file
 * and the accompanying materials are made available under the
 * terms of the MNA which accompanies this distribution, and
 * is available at http://www.magnolia-cms.com/mna.html
 *
 * Any modifications to this file must keep this entire header
 * intact.
 *
 */
package info.magnolia.module;

import info.magnolia.cms.beans.config.ContentRepository;
import info.magnolia.cms.core.Content;
import info.magnolia.cms.core.HierarchyManager;
import info.magnolia.cms.core.SystemProperty;
import info.magnolia.cms.util.ObservationUtil;
import info.magnolia.cms.util.SystemContentWrapper;
import info.magnolia.context.MgnlContext;
import info.magnolia.jcr.node2bean.Node2BeanException;
import info.magnolia.jcr.node2bean.Node2BeanProcessor;
import info.magnolia.jcr.node2bean.impl.Node2BeanProcessorImpl;
import info.magnolia.jcr.node2bean.impl.Node2BeanTransformerImpl;
import info.magnolia.jcr.node2bean.impl.TypeMappingImpl;
import info.magnolia.module.delta.Condition;
import info.magnolia.module.delta.Delta;
import info.magnolia.module.delta.Task;
import info.magnolia.module.delta.TaskExecutionException;
import info.magnolia.module.model.ModuleDefinition;
import info.magnolia.module.model.RepositoryDefinition;
import info.magnolia.module.model.Version;
import info.magnolia.module.model.reader.BetwixtModuleDefinitionReader;
import info.magnolia.module.model.reader.DependencyChecker;
import info.magnolia.module.model.reader.DependencyCheckerImpl;
import info.magnolia.module.model.reader.ModuleDefinitionReader;
import info.magnolia.module.ui.ModuleManagerNullUI;
import info.magnolia.module.ui.ModuleManagerUI;
import info.magnolia.module.ui.ModuleManagerWebUI;
import info.magnolia.objectfactory.ClassFactory;
import info.magnolia.objectfactory.Classes;
import info.magnolia.objectfactory.Components;
import info.magnolia.objectfactory.MgnlInstantiationException;
import info.magnolia.repository.Provider;
import info.magnolia.repository.RepositoryConstants;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Singleton;
import javax.jcr.RepositoryException;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;

/**
 * TODO : factor out into simpler units.
 *
 * @author gjoseph
 * @version $Revision: $ ($Author: $)
 */
@Singleton
public class ModuleManagerImpl implements ModuleManager {

    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ModuleManagerImpl.class);

    private static final int DEFAULT_MODULE_OBSERVATION_DELAY = 5000;
    private static final int DEFAULT_MODULE_OBSERVATION_MAX_DELAY = 30000;

    // TODO : expose a method to retrieve a given module's node ?
    // TODO : see InstallContextImpl.getOrCreateCurrentModuleConfigNode()
    static final String MODULES_NODE = "modules";

    /**
     * List<ModuleDefinition> of modules found to be deployed.
     */
    private List<ModuleDefinition> orderedModuleDescriptors;

    private ModuleManagementState state;

    // here we use the implementation, since it has extra methods that should not be exposed to Task methods.
    private final InstallContextImpl installContext;

    private final ModuleRegistry registry;
    private final ModuleDefinitionReader moduleDefinitionReader;
    private final DependencyChecker dependencyChecker;
    private final Node2BeanProcessor nodeToBean;

    /**
     * @deprecated since 4.5 - use IoC - temporarily kept for tests ?
     */
    @Deprecated
    protected ModuleManagerImpl() {
        this(new InstallContextImpl(ModuleRegistry.Factory.getInstance()), new BetwixtModuleDefinitionReader());
    }

    /**
     * @deprecated since 4.5 - use IoC - temporarily kept for tests ?
     */
    @Deprecated
    protected ModuleManagerImpl(InstallContextImpl installContext, ModuleDefinitionReader moduleDefinitionReader) {
        this(installContext, moduleDefinitionReader, ModuleRegistry.Factory.getInstance(),
                new DependencyCheckerImpl(),
                new Node2BeanProcessorImpl(new TypeMappingImpl(), new Node2BeanTransformerImpl()));
    }

    @Inject
    public ModuleManagerImpl(InstallContextImpl installContext, ModuleDefinitionReader moduleDefinitionReader,
            ModuleRegistry moduleRegistry, DependencyChecker dependencyChecker, Node2BeanProcessor nodeToBean) {
        this.installContext = installContext;
        this.moduleDefinitionReader = moduleDefinitionReader;
        this.registry = moduleRegistry;
        this.dependencyChecker = dependencyChecker;
        this.nodeToBean = nodeToBean;
    }

    @Override
    public List<ModuleDefinition> loadDefinitions() throws ModuleManagementException {
        if (state != null) {
            throw new IllegalStateException("ModuleManager was already initialized !");
        }

        final Map<String, ModuleDefinition> moduleDefinitions = moduleDefinitionReader.readAll();
        if (moduleDefinitions.isEmpty()) {
            throw new ModuleManagementException("No module definition was found.");
        }
        log.debug("Loaded definitions: {}", moduleDefinitions);

        dependencyChecker.checkDependencies(moduleDefinitions);
        orderedModuleDescriptors = dependencyChecker.sortByDependencyLevel(moduleDefinitions);
        for (ModuleDefinition moduleDefinition : orderedModuleDescriptors) {
            registry.registerModuleDefinition(moduleDefinition.getName(), moduleDefinition);
        }
        return orderedModuleDescriptors;
    }

    /**
     * In addition to checking for install or updates, this method also loads
     * repositories when there are no pending install or update tasks.
     *
     * @see info.magnolia.module.ModuleManager#checkForInstallOrUpdates()
     */
    @Override
    public void checkForInstallOrUpdates() {
        // compare and determine if we need to do anything
        state = new ModuleManagementState();
        int taskCount = 0;
        for (ModuleDefinition module : orderedModuleDescriptors) {
            installContext.setCurrentModule(module);
            log.debug("Checking for installation or update [{}]", module);
            final ModuleVersionHandler versionHandler = newVersionHandler(module);
            registry.registerModuleVersionHandler(module.getName(), versionHandler);

            final Version currentVersion = versionHandler.getCurrentlyInstalled(installContext);
            final List<Delta> deltas = versionHandler.getDeltas(installContext, currentVersion);
            if (deltas.size() > 0) {
                state.addModule(module, currentVersion, deltas);
                for (Delta delta : deltas) {
                    taskCount += delta.getTasks().size();
                }
            }
        }
        // TODO handle modules found in repo but not found on classpath

        installContext.setCurrentModule(null);
        installContext.setTotalTaskCount(taskCount);

        // if we don't have to perform any update load repositories now
        if (!state.needsUpdateOrInstall()) {
            loadModulesRepositories();
        }

        // TODO : check the force bootstrap properties
    }

    @Override
    public ModuleManagementState getStatus() {
        if (state == null) {
            throw new IllegalStateException("ModuleManager was not initialized !");
        }

        return state;
    }

    @Override
    public ModuleManagerUI getUI() {
        if (SystemProperty.getBooleanProperty("magnolia.update.auto")) {
            return new ModuleManagerNullUI(this);
        }
        return new ModuleManagerWebUI(this);
    }

    protected ModuleVersionHandler newVersionHandler(ModuleDefinition module) {
        try {
            final Class<? extends ModuleVersionHandler> versionHandlerClass = module.getVersionHandler();
            if (versionHandlerClass != null) {
                return Classes.getClassFactory().newInstance(versionHandlerClass);
            }
            return new DefaultModuleVersionHandler();
        } catch (MgnlInstantiationException e) {
            throw e; // TODO
        }
    }

    @Override
    public void performInstallOrUpdate() {
        synchronized (installContext) {
            if (state == null) {
                throw new IllegalStateException("ModuleManager was not initialized !");
            }
            if (!state.needsUpdateOrInstall()) {
                throw new IllegalStateException("ModuleManager has nothing to do !");
            }
            if (installContext.getStatus() != null) {
                throw new IllegalStateException("ModuleManager.performInstallOrUpdate() was already started !");
            }
            installContext.setStatus(InstallStatus.inProgress);
        }

        // check all conditions
        boolean conditionsChecked = true;
        for (ModuleAndDeltas moduleAndDeltas : state.getList()) {
            // TODO extract "do for all deltas" logic ?
            installContext.setCurrentModule(moduleAndDeltas.getModule());
            for (Delta delta : moduleAndDeltas.getDeltas()) {
                final List<Condition> conditions = delta.getConditions();
                for (Condition cond : conditions) {
                    if (!cond.check(installContext)) {
                        conditionsChecked = false;
                        installContext.warn(cond.getDescription());
                    }
                }
            }
        }
        installContext.setCurrentModule(null);
        if (!conditionsChecked) {
            installContext.setStatus(InstallStatus.stoppedConditionsNotMet);
            return;
        }

        loadModulesRepositories();

        MgnlContext.doInSystemContext(new MgnlContext.VoidOp() {
            @Override
            public void doExec() {
                final Iterator<ModuleAndDeltas> it = state.getList().iterator();
                while (it.hasNext()) {
                    final ModuleAndDeltas moduleAndDeltas = it.next();
                    installOrUpdateModule(moduleAndDeltas, installContext);
                    it.remove();
                }
            }
        }, true);

        // TODO : this isn't super clean.
        final InstallStatus status = installContext.isRestartNeeded() ? InstallStatus.installDoneRestartNeeded
                : InstallStatus.installDone;
        installContext.setStatus(status);
    }

    @Override
    public InstallContext getInstallContext() {
        return installContext;
    }

    @Override
    public void startModules() {
        // process startup tasks before actually starting modules
        executeStartupTasks();

        // here we use the implementation, since it has extra methods that should not be exposed to ModuleLifecycle methods.
        // TODO we should keep only one instance of the lifecycle context
        final ModuleLifecycleContextImpl lifecycleContext = new ModuleLifecycleContextImpl();
        lifecycleContext.setPhase(ModuleLifecycleContext.PHASE_SYSTEM_STARTUP);
        final HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(RepositoryConstants.CONFIG);
        Content modulesParentNode;
        try {
            modulesParentNode = hm.getContent(MODULES_NODE);
        } catch (RepositoryException e) {
            throw new RuntimeException("Can't start module due to failing to load the /modules node.", e);
        }
        final Collection<Content> moduleNodes = new ArrayList<Content>();

        for (ModuleDefinition moduleDefinition : orderedModuleDescriptors) {
            final String moduleClassName = moduleDefinition.getClassName();
            final String moduleName = moduleDefinition.getName();
            log.info("Initializing module {}", moduleName);

            try {
                final Object moduleInstance;
                if (moduleClassName != null) {
                    try {
                        final ClassFactory classFactory = Classes.getClassFactory();
                        final Class<?> moduleClass = classFactory.forName(moduleClassName);
                        // We use the currently set ComponentProvider which is main
                        moduleInstance = Components.newInstance(moduleClass);
                    } catch (Throwable t) {
                        log.error("Can't instantiate " + moduleClassName + " for module " + moduleName + " : "
                                + t.getClass() + " : " + t.getMessage(), t);
                        continue;
                    }
                    // Still registering module instances with ModuleRegistry, although now one should use IoC and *depend* on such objects instead.
                    registry.registerModuleInstance(moduleName, moduleInstance);
                } else {
                    moduleInstance = null;
                }

                if (modulesParentNode.hasContent(moduleName)) {
                    moduleNodes.add(new SystemContentWrapper(modulesParentNode.getContent(moduleName)));
                }

                if (moduleInstance != null) {

                    populateModuleInstance(moduleInstance, getModuleInstanceProperties(moduleDefinition));

                    startModule(moduleInstance, moduleDefinition, lifecycleContext);

                    // start observation
                    ObservationUtil.registerDeferredChangeListener(RepositoryConstants.CONFIG,
                            "/modules/" + moduleName + "/config", new EventListener() {

                                @Override
                                public void onEvent(EventIterator events) {
                                    final Object moduleInstance = registry.getModuleInstance(moduleName);
                                    final ModuleDefinition moduleDefinition = registry.getDefinition(moduleName);

                                    // TODO we should keep only one instance of the lifecycle context
                                    final ModuleLifecycleContextImpl lifecycleContext = new ModuleLifecycleContextImpl();
                                    lifecycleContext.setPhase(ModuleLifecycleContext.PHASE_MODULE_RESTART);
                                    MgnlContext.doInSystemContext(new MgnlContext.VoidOp() {
                                        @Override
                                        public void doExec() {
                                            stopModule(moduleInstance, moduleDefinition, lifecycleContext);
                                            populateModuleInstance(moduleInstance,
                                                    getModuleInstanceProperties(moduleDefinition));
                                            startModule(moduleInstance, moduleDefinition, lifecycleContext);
                                        }
                                    }, true);
                                }
                            }, DEFAULT_MODULE_OBSERVATION_DELAY, DEFAULT_MODULE_OBSERVATION_MAX_DELAY);
                }
            } catch (Throwable th) {
                log.error("Can't start module " + moduleName, th);
            }
        }

        lifecycleContext.start(moduleNodes);
    }

    /**
     * Process startup tasks. Tasks retured by <code>ModuleDefinition.getStartupTasks()</code> are always executed and
     * do not require manual intervention.
     */
    protected void executeStartupTasks() {
        MgnlContext.doInSystemContext(new MgnlContext.VoidOp() {
            @Override
            public void doExec() {
                for (ModuleDefinition module : orderedModuleDescriptors) {
                    final ModuleVersionHandler versionHandler = registry.getVersionHandler(module.getName());
                    installContext.setCurrentModule(module);
                    final Delta startup = versionHandler.getStartupDelta(installContext);
                    applyDeltas(module, Collections.singletonList(startup), installContext);
                }
            }
        }, false);
    }

    protected void startModule(Object moduleInstance, final ModuleDefinition moduleDefinition,
            final ModuleLifecycleContextImpl lifecycleContext) {
        if (moduleInstance instanceof ModuleLifecycle) {
            lifecycleContext.setCurrentModuleDefinition(moduleDefinition);
            log.info("Starting module {}", moduleDefinition.getName());
            ((ModuleLifecycle) moduleInstance).start(lifecycleContext);
        }
    }

    protected void stopModule(Object moduleInstance, final ModuleDefinition moduleDefinition,
            final ModuleLifecycleContextImpl lifecycleContext) {
        if (moduleInstance instanceof ModuleLifecycle) {
            lifecycleContext.setCurrentModuleDefinition(moduleDefinition);
            log.info("Stopping module {}", moduleDefinition.getName());
            ((ModuleLifecycle) moduleInstance).stop(lifecycleContext);
        }
    }

    /**
     * Builds a map of properties to be set on the module instance, the properties are "moduleDefinition", "name",
     * "moduleNode" and "configNode". This map is rebuilt every-time reloading takes place just in case the nodes have
     * changed since startup. One situation where this is necessary is when a module does not have a config node at
     * startup but one is added later on, see MAGNOLIA-3457.
     */
    protected Map<String, Object> getModuleInstanceProperties(ModuleDefinition moduleDefinition) {

        final HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(RepositoryConstants.CONFIG);

        final String moduleNodePath = "/modules/" + moduleDefinition.getName();
        Content moduleNode = null;
        try {
            moduleNode = hm.isExist(moduleNodePath) ? new SystemContentWrapper(hm.getContent(moduleNodePath))
                    : null;
        } catch (RepositoryException e) {
            log.error("Wasn't able to acquire module node " + moduleNodePath + ": " + e.getMessage(), e);
        }

        final String moduleConfigPath = "/modules/" + moduleDefinition.getName() + "/config";
        Content configNode = null;
        try {
            configNode = hm.isExist(moduleConfigPath) ? new SystemContentWrapper(hm.getContent(moduleConfigPath))
                    : null;
        } catch (RepositoryException e) {
            log.error("Wasn't able to acquire module config node " + moduleConfigPath + ": " + e.getMessage(), e);
        }

        final Map<String, Object> moduleProperties = new HashMap<String, Object>();
        moduleProperties.put("moduleDefinition", moduleDefinition);
        moduleProperties.put("name", moduleDefinition.getName());
        moduleProperties.put("moduleNode", moduleNode);
        moduleProperties.put("configNode", configNode);

        return moduleProperties;
    }

    protected void populateModuleInstance(Object moduleInstance, Map<String, Object> moduleProperties) {

        try {
            BeanUtils.populate(moduleInstance, moduleProperties);
        } catch (Throwable e) {
            log.error("Can't initialize module " + moduleInstance + ": " + e.getMessage(), e);
        }

        Content content = (Content) moduleProperties.get("configNode");
        if (content != null) {
            try {
                nodeToBean.setProperties(moduleInstance, content.getJCRNode(), true, new Node2BeanTransformerImpl(),
                        Components.getComponentProvider());
            } catch (Node2BeanException e) {
                log.error("Wasn't able to configure module " + moduleInstance + ": " + e.getMessage(), e);
            } catch (RepositoryException e) {
                log.error("Can't read module configuration " + moduleInstance + ": " + e.getMessage(), e);
            }
        }
    }

    @Override
    public void stopModules() {
        // TODO we should keep only one instance of the lifecycle context
        final ModuleLifecycleContextImpl lifecycleContext = new ModuleLifecycleContextImpl();
        lifecycleContext.setPhase(ModuleLifecycleContext.PHASE_SYSTEM_SHUTDOWN);
        if (orderedModuleDescriptors != null) {
            // if module descriptors were read, let's shut down modules in reverse order
            final ArrayList<ModuleDefinition> shutdownOrder = new ArrayList<ModuleDefinition>(
                    orderedModuleDescriptors);
            Collections.reverse(shutdownOrder);
            for (ModuleDefinition md : shutdownOrder) {
                Object module = registry.getModuleInstance(md.getName());
                if (module instanceof ModuleLifecycle) {
                    stopModule(module, md, lifecycleContext);
                }

            }
        }
    }

    protected void installOrUpdateModule(ModuleAndDeltas moduleAndDeltas, InstallContextImpl ctx) {
        final ModuleDefinition moduleDef = moduleAndDeltas.getModule();
        final List<Delta> deltas = moduleAndDeltas.getDeltas();
        ctx.setCurrentModule(moduleDef);
        log.debug("Install/update for {} is starting: {}", moduleDef, moduleAndDeltas);
        applyDeltas(moduleDef, deltas, ctx);
        log.debug("Install/update for {} has finished", moduleDef, moduleAndDeltas);
    }

    /**
     * Applies to given deltas for the given module. It is NOT responsible for setting the given
     * module as being the current module in the given context, but it is responsible for unsetting
     * it when done, and for saving upon success.
     */
    protected void applyDeltas(ModuleDefinition moduleDef, List<Delta> deltas, InstallContextImpl ctx) {
        boolean success = true;
        Task currentTask = null;
        try {
            for (Delta delta : deltas) {
                final List<Task> tasks = delta.getTasks();
                for (Task task : tasks) {
                    currentTask = task;
                    log.debug("Module {}, executing {}", moduleDef, currentTask);
                    task.execute(ctx);
                    ctx.incExecutedTaskCount();
                }
            }
        } catch (TaskExecutionException e) {
            ctx.error("Could not install or update " + moduleDef.getName() + " module. Task '"
                    + currentTask.getName() + "' failed. (" + ExceptionUtils.getRootCauseMessage(e) + ")", e);
            success = false;
        } catch (RuntimeException e) {
            ctx.error(
                    "Error while installing or updating " + moduleDef.getName() + " module. Task '"
                            + currentTask.getName() + "' failed. (" + ExceptionUtils.getRootCauseMessage(e) + ")",
                    e);
            throw e;
        } finally {
            // TODO : ctx.info("Successful installation/update."); after save ?
            ctx.setCurrentModule(null);
        }

        saveChanges(success);
    }

    /**
     * Save changes to jcr, or revert them if something went wrong.
     * @param persist if <code>true</code>, all workspaces are save; if <code>false</code> changes will be reverted.
     */
    private void saveChanges(boolean persist) {
        // save all repositories once a module was properly installed/updated, or rollback changes.
        final Iterator<String> reposIt = ContentRepository.getAllRepositoryNames();
        while (reposIt.hasNext()) {
            final String repoName = reposIt.next();
            log.debug((persist ? "Saving" : "Rolling back") + " repository " + repoName);
            final HierarchyManager hm = MgnlContext.getHierarchyManager(repoName);
            try {
                // don't call save or refresh if useless
                if (hm.getWorkspace().getSession().hasPendingChanges()) {
                    if (persist) {
                        hm.save();
                    } else {
                        hm.refresh(false);
                    }
                }
            } catch (RepositoryException e) {
                throw new RuntimeException(e); // TODO
            }
        }
    }

    /**
     * Initializes repositories and workspaces defined by modules.
     * Perform repository registration tasks (create repositories or workspace, setup nodetypes) that should be done
     * always before starting the new module.
     */
    private void loadModulesRepositories() {
        for (ModuleDefinition def : orderedModuleDescriptors) {
            // register repositories
            for (final RepositoryDefinition repDef : def.getRepositories()) {
                final String repositoryName = repDef.getName();

                final String nodetypeFile = repDef.getNodeTypeFile();

                final List<String> wsList = repDef.getWorkspaces();
                String[] workSpaces = wsList.toArray(new String[wsList.size()]);

                loadRepository(repositoryName, nodetypeFile, workSpaces);
            }
        }
    }

    /**
     * Loads a single repository plus its workspaces, register nodetypes and grant permissions to superuser.
     */
    private void loadRepository(String repositoryNameFromModuleDescriptor, String nodeTypeFile,
            String[] workspaces) {

        if (workspaces == null || workspaces.length == 0) {
            log.error("Trying to register the repository {} without any workspace.",
                    repositoryNameFromModuleDescriptor);
            return;
        }

        final String DEFAULT_REPOSITORY_NAME = "magnolia";
        String repositoryName = repositoryNameFromModuleDescriptor;

        if (workspaces.length > 0) {
            // get the repository name from the mapping, users may want to manually add it here if needed
            info.magnolia.repository.definition.RepositoryDefinition repositoryMapping = ContentRepository
                    .getRepositoryMapping(workspaces[0]);
            if (repositoryMapping != null) {
                repositoryName = repositoryMapping.getName();
            }
        }

        info.magnolia.repository.definition.RepositoryDefinition rm = ContentRepository
                .getRepositoryMapping(repositoryName);

        if (rm == null) {

            final info.magnolia.repository.definition.RepositoryDefinition defaultRepositoryMapping = ContentRepository
                    .getRepositoryMapping(DEFAULT_REPOSITORY_NAME);
            final Map<String, String> defaultParameters = defaultRepositoryMapping.getParameters();

            rm = new info.magnolia.repository.definition.RepositoryDefinition();
            rm.setName(repositoryName);
            rm.setProvider(defaultRepositoryMapping.getProvider());
            rm.setLoadOnStartup(true);

            final Map<String, String> parameters = new HashMap<String, String>();
            parameters.putAll(defaultParameters);

            // override changed parameters
            final String bindName = repositoryName
                    + StringUtils.replace(defaultParameters.get("bindName"), "magnolia", "");
            final String repositoryHome = StringUtils.substringBeforeLast(defaultParameters.get("configFile"), "/")
                    + "/" + repositoryName;

            parameters.put("repositoryHome", repositoryHome);
            parameters.put("bindName", bindName);
            parameters.put("customNodeTypes", nodeTypeFile);

            rm.setParameters(parameters);

            try {
                ContentRepository.loadRepository(rm);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }

        if (nodeTypeFile != null) {
            // register nodetypes
            registerNodeTypeFile(repositoryName, nodeTypeFile);
            // if this repo is not the default one, register nodetypes on default repo (MAGNOLIA-3189)
            if (!DEFAULT_REPOSITORY_NAME.equals(repositoryName)) {
                registerNodeTypeFile(DEFAULT_REPOSITORY_NAME, nodeTypeFile);
            }
        }

        if (workspaces != null) {
            for (String workspace : workspaces) {
                if (!rm.getWorkspaces().contains(workspace)) {
                    log.debug("Loading new workspace: {}", workspace);

                    try {
                        ContentRepository.loadWorkspace(repositoryName, workspace);
                    } catch (RepositoryException e) {
                        // should never happen, the only exception we can get here is during login
                        log.error(e.getMessage(), e);
                    }
                }
            }
        }

    }

    /**
     * Register nodeType file in repository.
     * @param repositoryName repository name
     * @param nodeTypeFile nodeType file
     */
    private void registerNodeTypeFile(String repositoryName, String nodeTypeFile) {
        Provider provider = ContentRepository.getRepositoryProvider(repositoryName);
        try {
            provider.registerNodeTypes(nodeTypeFile);
        } catch (RepositoryException e) {
            log.error(e.getMessage(), e);
        }
    }
}