getRegistryModuleIDs()
{
// Get the IDs of all modules from the registry
RegistryKey moduleKeyAllIds = new RegistryKey(
ModuleComponentHelper.URI_MODULES_1_0,
REGISTRY_PATH_MODULES, null);
return registryService.getChildElements(moduleKeyAllIds);
}
/**
* Returns the version number of a module from the Registry.
*
* @param moduleId
* @return
*/
ModuleVersionNumber getVersion(String moduleId)
{
RegistryKey moduleKeyCurrentVersion = new RegistryKey(
ModuleComponentHelper.URI_MODULES_1_0,
REGISTRY_PATH_MODULES, moduleId, REGISTRY_PROPERTY_CURRENT_VERSION);
Serializable versionCurrent = registryService.getProperty(moduleKeyCurrentVersion);
return getModuleVersionNumber(versionCurrent);
}
/**
* Checks to see if there are any modules registered as installed that aren't in the
* list of modules taken from the WAR.
*
* Currently, the behaviour specified is that a warning is generated only.
*/
private void checkForMissingModules()
{
// Get the IDs of all modules from the registry
Collection moduleIds = getRegistryModuleIDs();
// Check that each module is present in the distribution
for (String moduleId : moduleIds)
{
ModuleDetails moduleDetails = moduleService.getModule(moduleId);
if (moduleDetails != null)
{
if (logger.isDebugEnabled())
{
logger.debug("Installed module found in distribution: " + moduleId);
}
}
else
{
// Get the specifics of the missing module
ModuleVersionNumber versionCurrent = getVersion(moduleId);
// The module is missing, so warn
loggerService.warn(I18NUtil.getMessage(MSG_MISSING, moduleId, versionCurrent));
}
}
}
/**
* Copies, where necessary, the module registry details from the alias details
* and removes the alias details.
*/
private void renameModule(ModuleDetails module)
{
String moduleId = module.getId();
List moduleAliases = module.getAliases();
// Get the IDs of all modules from the registry
RegistryKey moduleKeyAllIds = new RegistryKey(
ModuleComponentHelper.URI_MODULES_1_0,
REGISTRY_PATH_MODULES, null);
Collection registeredModuleIds = registryService.getChildElements(moduleKeyAllIds);
// Firstly, is the module installed?
if (registeredModuleIds.contains(moduleId))
{
// It is there, so we do nothing
return;
}
// Check if any of the registered modules are on the alias list
for (String moduleAlias : moduleAliases)
{
// Is this alias registered?
if (!registeredModuleIds.contains(moduleAlias))
{
// No alias registered
continue;
}
// We found an alias and have to rename it to the new module ID
RegistryKey moduleKeyNew = new RegistryKey(
ModuleComponentHelper.URI_MODULES_1_0,
REGISTRY_PATH_MODULES, moduleId, null);
RegistryKey moduleKeyOld = new RegistryKey(
ModuleComponentHelper.URI_MODULES_1_0,
REGISTRY_PATH_MODULES, moduleAlias, null);
// Copy it all
registryService.copy(moduleKeyOld, moduleKeyNew);
// Remove the source
registryService.delete(moduleKeyOld);
// Done
if (logger.isDebugEnabled())
{
logger.debug("Moved old module alias to new module ID: \n" +
" Alias: " + moduleAlias + "\n" +
" Module: " + moduleId);
}
break;
}
}
/**
* 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 startedModules, Set executedComponents)
{
String moduleId = module.getId();
ModuleVersionNumber moduleNewVersion = module.getModuleVersionNumber();
// 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 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
renameModule(module);
// First check that the module version is fundamentally compatible with the repository
VersionNumber repoVersionNumber = descriptorService.getServerDescriptor().getVersionNumber();
VersionNumber minRepoVersionNumber = module.getRepoVersionMin();
VersionNumber maxRepoVersionNumber = module.getRepoVersionMax();
if ((minRepoVersionNumber != null && repoVersionNumber.compareTo(minRepoVersionNumber) < 0) ||
(maxRepoVersionNumber != null && repoVersionNumber.compareTo(maxRepoVersionNumber) > 0))
{
// The current repo version is not supported
throw AlfrescoRuntimeException.create(
ERR_UNSUPPORTED_REPO_VERSION,
moduleId, moduleNewVersion, repoVersionNumber, minRepoVersionNumber, maxRepoVersionNumber);
}
// Get the module details from the registry
RegistryKey moduleKeyInstalledVersion = new RegistryKey(
ModuleComponentHelper.URI_MODULES_1_0,
REGISTRY_PATH_MODULES, moduleId, REGISTRY_PROPERTY_INSTALLED_VERSION);
RegistryKey moduleKeyCurrentVersion = new RegistryKey(
ModuleComponentHelper.URI_MODULES_1_0,
REGISTRY_PATH_MODULES, moduleId, REGISTRY_PROPERTY_CURRENT_VERSION);
Serializable moduleInstallVersion = registryService.getProperty(moduleKeyInstalledVersion);
Serializable moduleCurrentVersion = registryService.getProperty(moduleKeyCurrentVersion);
String msg = null;
if (moduleCurrentVersion == null) // No previous record of it
{
msg = I18NUtil.getMessage(MSG_INSTALLING, moduleId, moduleNewVersion);
// Record the install version
registryService.addProperty(moduleKeyInstalledVersion, moduleNewVersion);
moduleInstallVersion = moduleNewVersion;
moduleCurrentVersion = moduleNewVersion;
}
else // It is an upgrade or is the same
{
ModuleVersionNumber currentModuleVersion = getModuleVersionNumber(moduleCurrentVersion);
// Check that we have an installed version
if (moduleInstallVersion == null)
{
// A current version, but no installed version
logger.warn(I18NUtil.getMessage(WARN_NO_INSTALL_VERSION, moduleId, moduleCurrentVersion));
// Record the install version
registryService.addProperty(moduleKeyInstalledVersion, currentModuleVersion);
moduleInstallVersion = moduleCurrentVersion;
}
if (currentModuleVersion.compareTo(moduleNewVersion) == 0) // The current version is the same
{
msg = I18NUtil.getMessage(MSG_STARTING, moduleId, moduleNewVersion);
}
else if (currentModuleVersion.compareTo(moduleNewVersion) > 0) // Downgrading not supported
{
throw AlfrescoRuntimeException.create(ERR_NO_DOWNGRADE, moduleId, moduleCurrentVersion, moduleNewVersion);
}
else // This is an upgrade
{
msg = I18NUtil.getMessage(MSG_UPGRADING, moduleId, moduleNewVersion, moduleCurrentVersion);
}
}
loggerService.info(msg);
// Record the current version
registryService.addProperty(moduleKeyCurrentVersion, moduleNewVersion);
Map componentsByName = getComponents(moduleId);
for (ModuleComponent component : componentsByName.values())
{
executeComponent(moduleId, moduleNewVersion, component, executedComponents);
}
// Keep track of the ID as it started successfully
startedModules.add(moduleId);
// Done
if (logger.isDebugEnabled())
{
logger.debug("Started module '" + module + "' including " + executedComponents.size() + "components.");
}
}
protected ModuleVersionNumber getModuleVersionNumber(Serializable moduleVersion)
{
if (moduleVersion instanceof ModuleVersionNumber) return (ModuleVersionNumber) moduleVersion;
if (moduleVersion instanceof VersionNumber) return new ModuleVersionNumber((VersionNumber)moduleVersion);
if (moduleVersion instanceof String) return new ModuleVersionNumber((String)moduleVersion);
throw new ModuleManagementToolException("Invalid moduleVersion");
}
/**
* Execute the component, respecting dependencies.
*/
private void executeComponent(
String moduleId,
ModuleVersionNumber currentVersion,
ModuleComponent component,
Set executedComponents)
{
// Ignore if it has been executed in this run already
if (executedComponents.contains(component))
{
// Already done
if (logger.isDebugEnabled())
{
logger.debug("Skipping component already executed in this run: \n" +
" Component: " + component);
}
return;
}
// Keep track of the fact that we considered it for execution
executedComponents.add(component);
// Check the version applicability
ModuleVersionNumber minVersion = component.getAppliesFromVersionNumber();
ModuleVersionNumber maxVersion = component.getAppliesToVersionNumber();
if (currentVersion.compareTo(minVersion) < 0 || currentVersion.compareTo(maxVersion) > 0)
{
// It is out of the allowable range for execution so we just ignore it
if (logger.isDebugEnabled())
{
logger.debug("Skipping component that doesn't apply to the module installation version: \n" +
" Component: " + component + "\n" +
" Module: " + moduleId + "\n" +
" Current Version: " + currentVersion + "\n" +
" Applies From : " + minVersion + "\n" +
" Applies To : " + maxVersion);
}
return;
}
// Construct the registry key to store the execution date
String name = component.getName();
RegistryKey executionDateKey = new RegistryKey(
ModuleComponentHelper.URI_MODULES_1_0,
REGISTRY_PATH_MODULES, moduleId, REGISTRY_PATH_COMPONENTS, name, REGISTRY_PROPERTY_EXECUTION_DATE);
// Check if the component has been executed
Date executionDate = (Date) registryService.getProperty(executionDateKey);
if (executionDate != null && component.isExecuteOnceOnly())
{
// It has been executed and is scheduled for a single execution - leave it
if (logger.isDebugEnabled())
{
logger.debug("Skipping already-executed module component: \n" +
" Component: " + component + "\n" +
" Execution Time: " + executionDate);
}
return;
}
// It may have been executed, but not in this run and it is allowed to be repeated
// Check for dependencies
List dependencies = component.getDependsOn();
for (ModuleComponent dependency : dependencies)
{
executeComponent(moduleId, currentVersion, dependency, executedComponents);
}
// Execute the component itself
component.execute();
// Keep track of it in the registry
registryService.addProperty(executionDateKey, new Date());
// Done
if (logger.isDebugEnabled())
{
logger.debug("Executed module component: \n" +
" Component: " + component);
}
}
}