mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Repository startup support for module dependencies.
Modules are started in in order of their dependencies. Components that don't execute due to incorrect registration are detected. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5606 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -4,13 +4,17 @@ module.msg.found_modules=Found {0} module(s).
|
|||||||
module.msg.starting= Starting module ''{0}'' version {1}.
|
module.msg.starting= Starting module ''{0}'' version {1}.
|
||||||
module.msg.installing= Installing module ''{0}'' version {1}.
|
module.msg.installing= Installing module ''{0}'' version {1}.
|
||||||
module.msg.upgrading= Upgrading module ''{0}'' version {1} (was {2}).
|
module.msg.upgrading= Upgrading module ''{0}'' version {1} (was {2}).
|
||||||
module.msg.missing= A previously-installed module ''{0}'' (version {1}) is not present in your distribution.
|
module.msg.missing= A previously-installed module ''{0}'' (version {1}) is not present in your distribution.
|
||||||
|
module.msg.dependencies= Module ''{0}'' version {1} has the following dependencies: {1}
|
||||||
|
|
||||||
module.warn.no_install_version=Module ''{0}'' had no install version. Assuming version {1} was installed.
|
module.warn.no_install_version=Module ''{0}'' had no install version. Assuming version {1} was installed.
|
||||||
|
|
||||||
|
module.err.missing_dependency=\nModule ''{0}'' version {1} depends on module ''{2}'', which has not been installed.
|
||||||
module.err.downgrading_not_supported=\nDowngrading of modules is not supported.\nModule ''{0}'' version {1} is currently installed and must be uninstalled before version {2} can be installed.
|
module.err.downgrading_not_supported=\nDowngrading of modules is not supported.\nModule ''{0}'' version {1} is currently installed and must be uninstalled before version {2} can be installed.
|
||||||
module.err.unsupported_repo_version=\nModule ''{0}'' version {1} is incompatible with the current repository version {2}.\n The repository version required must be in range [{3} : {4}].
|
module.err.unsupported_repo_version=\nModule ''{0}'' version {1} is incompatible with the current repository version {2}.\n The repository version required must be in range [{3} : {4}].
|
||||||
module.err.already_executed=The module component has already been executed: {0}.{1}
|
module.err.already_executed=The module component has already been executed: {0}.{1}
|
||||||
module.err.execution_failed=A module component ''{0}'' failed to execute: {1}
|
module.err.execution_failed=A module component ''{0}'' failed to execute: {1}
|
||||||
module.err.component_already_registered=A component named ''{0}'' has already been registered for module ''{1}''.
|
module.err.component_already_registered=A component named ''{0}'' has already been registered for module ''{1}''.
|
||||||
module.err.unable_to_open_module_properties=The module properties file ''{0}'' could not be read.
|
module.err.unable_to_open_module_properties=The module properties file ''{0}'' could not be read.
|
||||||
|
module.err.component_in_missing_module=The component ''{0}'' belongs to a non-existent module ''{1}''.
|
||||||
|
module.err.orphaned_components={0} module components were not considered for execution.
|
||||||
|
105
source/java/org/alfresco/repo/module/LoggerModuleComponent.java
Normal file
105
source/java/org/alfresco/repo/module/LoggerModuleComponent.java
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
* As a special exception to the terms and conditions of version 2.0 of
|
||||||
|
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||||
|
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||||
|
* FLOSS exception. You should have recieved a copy of the text describing
|
||||||
|
* the FLOSS exception, and it is also available here:
|
||||||
|
* http://www.alfresco.com/legal/licensing"
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.module;
|
||||||
|
|
||||||
|
import org.alfresco.util.PropertyCheck;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module component that logs a message on startup. The log category
|
||||||
|
* used will be the ID of the module that contains the component and the
|
||||||
|
* name of the component itself. For example:
|
||||||
|
* <pre>
|
||||||
|
* log4j.logger.org.alfresco.modules.MyModule.DumpMessageComponent=INFO
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author Derek Hulley
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
public class LoggerModuleComponent extends AbstractModuleComponent
|
||||||
|
{
|
||||||
|
private enum LogLevel
|
||||||
|
{
|
||||||
|
INFO, WARN, ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LogLevel logLevel;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public LoggerModuleComponent()
|
||||||
|
{
|
||||||
|
logLevel = LogLevel.INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the level at which the bean must log the message.
|
||||||
|
* @param logLevel One of the {@link LogLevel values}.
|
||||||
|
* The default is {@link LogLevel#INFO}.
|
||||||
|
*/
|
||||||
|
public void setLogLevel(String logLevel)
|
||||||
|
{
|
||||||
|
this.logLevel = LogLevel.valueOf(logLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the message that must be logged. This can be a message string
|
||||||
|
* or an ID of an internationalized string.
|
||||||
|
*
|
||||||
|
* @param message a message to log at the {@link #setLogLevel(String) log level}
|
||||||
|
*/
|
||||||
|
public void setMessage(String message)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkProperties()
|
||||||
|
{
|
||||||
|
PropertyCheck.mandatory(this, "message", message);
|
||||||
|
// fulfil contract of override
|
||||||
|
super.checkProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void executeInternal() throws Throwable
|
||||||
|
{
|
||||||
|
String moduleId = super.getModuleId();
|
||||||
|
String name = super.getName();
|
||||||
|
Log logger = LogFactory.getLog(moduleId + "." + name);
|
||||||
|
switch (logLevel)
|
||||||
|
{
|
||||||
|
case INFO:
|
||||||
|
logger.info(message);
|
||||||
|
break;
|
||||||
|
case WARN:
|
||||||
|
logger.warn(message);
|
||||||
|
break;
|
||||||
|
case ERROR:
|
||||||
|
logger.error(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -43,6 +43,7 @@ import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
|||||||
import org.alfresco.repo.transaction.TransactionUtil;
|
import org.alfresco.repo.transaction.TransactionUtil;
|
||||||
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
|
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
|
||||||
import org.alfresco.service.ServiceRegistry;
|
import org.alfresco.service.ServiceRegistry;
|
||||||
|
import org.alfresco.service.cmr.module.ModuleDependency;
|
||||||
import org.alfresco.service.cmr.module.ModuleDetails;
|
import org.alfresco.service.cmr.module.ModuleDetails;
|
||||||
import org.alfresco.service.cmr.module.ModuleService;
|
import org.alfresco.service.cmr.module.ModuleService;
|
||||||
import org.alfresco.service.descriptor.DescriptorService;
|
import org.alfresco.service.descriptor.DescriptorService;
|
||||||
@@ -71,11 +72,15 @@ public class ModuleComponentHelper
|
|||||||
private static final String MSG_STARTING = "module.msg.starting";
|
private static final String MSG_STARTING = "module.msg.starting";
|
||||||
private static final String MSG_INSTALLING = "module.msg.installing";
|
private static final String MSG_INSTALLING = "module.msg.installing";
|
||||||
private static final String MSG_UPGRADING = "module.msg.upgrading";
|
private static final String MSG_UPGRADING = "module.msg.upgrading";
|
||||||
|
private static final String MSG_DEPENDENCIES = "module.msg.dependencies";
|
||||||
|
private static final String MSG_MISSING = "module.msg.missing";
|
||||||
private static final String WARN_NO_INSTALL_VERSION = "module.warn.no_install_version";
|
private static final String WARN_NO_INSTALL_VERSION = "module.warn.no_install_version";
|
||||||
|
private static final String ERR_MISSING_DEPENDENCY = "module.err.missing_dependency";
|
||||||
private static final String ERR_UNSUPPORTED_REPO_VERSION = "module.err.unsupported_repo_version";
|
private static final String ERR_UNSUPPORTED_REPO_VERSION = "module.err.unsupported_repo_version";
|
||||||
private static final String ERR_NO_DOWNGRADE = "module.err.downgrading_not_supported";
|
private static final String ERR_NO_DOWNGRADE = "module.err.downgrading_not_supported";
|
||||||
private static final String ERR_COMPONENT_ALREADY_REGISTERED = "module.err.component_already_registered";
|
private static final String ERR_COMPONENT_ALREADY_REGISTERED = "module.err.component_already_registered";
|
||||||
private static final String MSG_MISSING = "module.msg.missing";
|
private static final String ERR_COMPONENT_IN_MISSING_MODULE = "module.err.component_in_missing_module";
|
||||||
|
private static final String ERR_ORPHANED_COMPONENTS = "module.err.orphaned_components";
|
||||||
|
|
||||||
private static Log logger = LogFactory.getLog(ModuleComponentHelper.class);
|
private static Log logger = LogFactory.getLog(ModuleComponentHelper.class);
|
||||||
private static Log loggerService = LogFactory.getLog(ModuleServiceImpl.class);
|
private static Log loggerService = LogFactory.getLog(ModuleServiceImpl.class);
|
||||||
@@ -207,26 +212,25 @@ public class ModuleComponentHelper
|
|||||||
loggerService.info(I18NUtil.getMessage(MSG_FOUND_MODULES, modules.size()));
|
loggerService.info(I18NUtil.getMessage(MSG_FOUND_MODULES, modules.size()));
|
||||||
// Process each module in turn. Ordering is not important.
|
// Process each module in turn. Ordering is not important.
|
||||||
final Set<ModuleComponent> executedComponents = new HashSet<ModuleComponent>(10);
|
final Set<ModuleComponent> executedComponents = new HashSet<ModuleComponent>(10);
|
||||||
|
final Set<String> startedModules = new HashSet<String>(2);
|
||||||
for (final ModuleDetails module : modules)
|
for (final ModuleDetails module : modules)
|
||||||
{
|
{
|
||||||
TransactionWork<Object> startModuleWork = new TransactionWork<Object>()
|
TransactionWork<Object> startModuleWork = new TransactionWork<Object>()
|
||||||
{
|
{
|
||||||
public Object doWork() throws Exception
|
public Object doWork() throws Exception
|
||||||
{
|
{
|
||||||
startModule(module, executedComponents);
|
startModule(module, startedModules, executedComponents);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, startModuleWork);
|
TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, startModuleWork);
|
||||||
}
|
}
|
||||||
// We have finished executing any components
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("Executed " + executedComponents.size() + " components");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for missing modules.
|
// Check for missing modules.
|
||||||
checkForMissingModules();
|
checkForMissingModules();
|
||||||
|
|
||||||
|
// Check that all components where executed, or considered for execution
|
||||||
|
checkForOrphanComponents(executedComponents);
|
||||||
|
|
||||||
// Restore the original authentication
|
// Restore the original authentication
|
||||||
authenticationComponent.setCurrentAuthentication(authentication);
|
authenticationComponent.setCurrentAuthentication(authentication);
|
||||||
@@ -237,6 +241,46 @@ public class ModuleComponentHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that all components have been executed or considered for execution.
|
||||||
|
* @param executedComponents
|
||||||
|
*/
|
||||||
|
private void checkForOrphanComponents(Set<ModuleComponent> executedComponents)
|
||||||
|
{
|
||||||
|
Set<ModuleComponent> missedComponents = new HashSet<ModuleComponent>(executedComponents);
|
||||||
|
|
||||||
|
// Iterate over each module registered by components
|
||||||
|
for (Map.Entry<String, Map<String, ModuleComponent>> entry : componentsByNameByModule.entrySet())
|
||||||
|
{
|
||||||
|
String moduleId = entry.getKey();
|
||||||
|
Map<String, ModuleComponent> componentsByName = entry.getValue();
|
||||||
|
// Iterate over each component registered against the module ID
|
||||||
|
for (Map.Entry<String, ModuleComponent> entryInner : componentsByName.entrySet())
|
||||||
|
{
|
||||||
|
String componentName = entryInner.getKey();
|
||||||
|
ModuleComponent component = entryInner.getValue();
|
||||||
|
// Check if it has been executed
|
||||||
|
if (executedComponents.contains(component))
|
||||||
|
{
|
||||||
|
// It was executed, so remove it from the missed components set
|
||||||
|
missedComponents.remove(component);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String msg = I18NUtil.getMessage(
|
||||||
|
ERR_COMPONENT_IN_MISSING_MODULE,
|
||||||
|
componentName, moduleId);
|
||||||
|
logger.error(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Dump if there were orphans
|
||||||
|
if (missedComponents.size() > 0)
|
||||||
|
{
|
||||||
|
throw AlfrescoRuntimeException.create(ERR_ORPHANED_COMPONENTS, missedComponents.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks to see if there are any modules registered as installed that aren't in the
|
* Checks to see if there are any modules registered as installed that aren't in the
|
||||||
* list of modules taken from the WAR.
|
* list of modules taken from the WAR.
|
||||||
@@ -329,12 +373,62 @@ public class ModuleComponentHelper
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Does the actual work without fussing about transactions and authentication.
|
* Does the actual work without fussing about transactions and authentication.
|
||||||
|
* Module dependencies will be started first, but a module will only be started
|
||||||
|
* once.
|
||||||
|
*
|
||||||
|
* @param module the module to start
|
||||||
|
* @param startedModules the IDs of modules that have already started
|
||||||
|
* @param executedComponents keep track of the executed components
|
||||||
*/
|
*/
|
||||||
private void startModule(ModuleDetails module, Set<ModuleComponent> executedComponents)
|
private void startModule(ModuleDetails module, Set<String> startedModules, Set<ModuleComponent> executedComponents)
|
||||||
{
|
{
|
||||||
String moduleId = module.getId();
|
String moduleId = module.getId();
|
||||||
VersionNumber moduleNewVersion = module.getVersion();
|
VersionNumber moduleNewVersion = module.getVersion();
|
||||||
|
|
||||||
|
// Double check whether we have done this module already
|
||||||
|
if (startedModules.contains(moduleId))
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Module '" + module + "' already started");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start dependencies
|
||||||
|
List<ModuleDependency> moduleDependencies = module.getDependencies();
|
||||||
|
for (ModuleDependency moduleDependency : moduleDependencies)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Module '" + module + "' depends on: " + moduleDependency);
|
||||||
|
}
|
||||||
|
// Get the dependency
|
||||||
|
String moduleDependencyId = moduleDependency.getDependencyId();
|
||||||
|
ModuleDetails moduleDependencyDetails = moduleService.getModule(moduleDependencyId);
|
||||||
|
// Check that it is there
|
||||||
|
if (moduleDependencyDetails == null)
|
||||||
|
{
|
||||||
|
// The dependency is not there
|
||||||
|
// List required dependencies
|
||||||
|
StringBuilder sb = new StringBuilder(128);
|
||||||
|
for (ModuleDependency dependency : moduleDependencies)
|
||||||
|
{
|
||||||
|
sb.append("\n").append(dependency);
|
||||||
|
}
|
||||||
|
String msg = I18NUtil.getMessage(
|
||||||
|
MSG_DEPENDENCIES,
|
||||||
|
moduleId, moduleNewVersion, sb.toString());
|
||||||
|
logger.info(msg);
|
||||||
|
// Now fail
|
||||||
|
throw AlfrescoRuntimeException.create(
|
||||||
|
ERR_MISSING_DEPENDENCY,
|
||||||
|
moduleId, moduleNewVersion, moduleDependency);
|
||||||
|
}
|
||||||
|
// The dependency is installed, so start it
|
||||||
|
startModule(moduleDependencyDetails, startedModules, executedComponents);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the module needs a rename first
|
// Check if the module needs a rename first
|
||||||
renameModule(module);
|
renameModule(module);
|
||||||
|
|
||||||
@@ -404,10 +498,13 @@ public class ModuleComponentHelper
|
|||||||
executeComponent(moduleId, moduleInstallVersion, component, executedComponents);
|
executeComponent(moduleId, moduleInstallVersion, component, executedComponents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep track of the ID as it started successfully
|
||||||
|
startedModules.add(moduleId);
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Started module: " + module);
|
logger.debug("Started module '" + module + "' including " + executedComponents.size() + "components.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,6 +528,8 @@ public class ModuleComponentHelper
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Keep track of the fact that we considered it for execution
|
||||||
|
executedComponents.add(component);
|
||||||
|
|
||||||
// Check the version applicability
|
// Check the version applicability
|
||||||
VersionNumber minVersion = component.getAppliesFromVersionNumber();
|
VersionNumber minVersion = component.getAppliesFromVersionNumber();
|
||||||
@@ -478,8 +577,7 @@ public class ModuleComponentHelper
|
|||||||
}
|
}
|
||||||
// Execute the component itself
|
// Execute the component itself
|
||||||
component.execute();
|
component.execute();
|
||||||
// Keep track of it in the registry and in this run
|
// Keep track of it in the registry
|
||||||
executedComponents.add(component);
|
|
||||||
registryService.addProperty(executionDateKey, new Date());
|
registryService.addProperty(executionDateKey, new Date());
|
||||||
// Done
|
// Done
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
|
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user