mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Support for renaming of modules
- When a module ID changes, the old ID gets put in a list against property 'module.aliases'. - The tool and the repo startup detect the existing installation against the alias and perform a rename. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5559 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -66,7 +66,6 @@ public class ModuleComponentHelper
|
|||||||
private static final String REGISTRY_PROPERTY_CURRENT_VERSION = "currentVersion";
|
private static final String REGISTRY_PROPERTY_CURRENT_VERSION = "currentVersion";
|
||||||
private static final String REGISTRY_PATH_COMPONENTS = "components";
|
private static final String REGISTRY_PATH_COMPONENTS = "components";
|
||||||
private static final String REGISTRY_PROPERTY_EXECUTION_DATE = "executionDate";
|
private static final String REGISTRY_PROPERTY_EXECUTION_DATE = "executionDate";
|
||||||
private static final String REGISTRY_PROPERTY_DUMMY = "dummy";
|
|
||||||
|
|
||||||
private static final String MSG_FOUND_MODULES = "module.msg.found_modules";
|
private static final String MSG_FOUND_MODULES = "module.msg.found_modules";
|
||||||
private static final String MSG_STARTING = "module.msg.starting";
|
private static final String MSG_STARTING = "module.msg.starting";
|
||||||
@@ -248,7 +247,7 @@ public class ModuleComponentHelper
|
|||||||
// Get the IDs of all modules from the registry
|
// Get the IDs of all modules from the registry
|
||||||
RegistryKey moduleKeyAllIds = new RegistryKey(
|
RegistryKey moduleKeyAllIds = new RegistryKey(
|
||||||
ModuleComponentHelper.URI_MODULES_1_0,
|
ModuleComponentHelper.URI_MODULES_1_0,
|
||||||
REGISTRY_PATH_MODULES, REGISTRY_PROPERTY_DUMMY);
|
REGISTRY_PATH_MODULES, null);
|
||||||
Collection<String> moduleIds = registryService.getChildElements(moduleKeyAllIds);
|
Collection<String> moduleIds = registryService.getChildElements(moduleKeyAllIds);
|
||||||
|
|
||||||
// Check that each module is present in the distribution
|
// Check that each module is present in the distribution
|
||||||
@@ -268,13 +267,65 @@ public class ModuleComponentHelper
|
|||||||
RegistryKey moduleKeyCurrentVersion = new RegistryKey(
|
RegistryKey moduleKeyCurrentVersion = new RegistryKey(
|
||||||
ModuleComponentHelper.URI_MODULES_1_0,
|
ModuleComponentHelper.URI_MODULES_1_0,
|
||||||
REGISTRY_PATH_MODULES, moduleId, REGISTRY_PROPERTY_CURRENT_VERSION);
|
REGISTRY_PATH_MODULES, moduleId, REGISTRY_PROPERTY_CURRENT_VERSION);
|
||||||
VersionNumber versionCurrent = (VersionNumber) registryService.getValue(moduleKeyCurrentVersion);
|
VersionNumber versionCurrent = (VersionNumber) registryService.getProperty(moduleKeyCurrentVersion);
|
||||||
// The module is missing, so warn
|
// The module is missing, so warn
|
||||||
loggerService.warn(I18NUtil.getMessage(MSG_MISSING, moduleId, versionCurrent));
|
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<String> 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<String> 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.
|
* Does the actual work without fussing about transactions and authentication.
|
||||||
*/
|
*/
|
||||||
@@ -283,7 +334,10 @@ public class ModuleComponentHelper
|
|||||||
String moduleId = module.getId();
|
String moduleId = module.getId();
|
||||||
VersionNumber moduleVersion = module.getVersion();
|
VersionNumber moduleVersion = module.getVersion();
|
||||||
|
|
||||||
// First check that the module version is fundamentall compatible with the repository
|
// 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 repoVersionNumber = descriptorService.getServerDescriptor().getVersionNumber();
|
||||||
VersionNumber minRepoVersionNumber = module.getRepoVersionMin();
|
VersionNumber minRepoVersionNumber = module.getRepoVersionMin();
|
||||||
VersionNumber maxRepoVersionNumber = module.getRepoVersionMax();
|
VersionNumber maxRepoVersionNumber = module.getRepoVersionMax();
|
||||||
@@ -303,13 +357,13 @@ public class ModuleComponentHelper
|
|||||||
RegistryKey moduleKeyCurrentVersion = new RegistryKey(
|
RegistryKey moduleKeyCurrentVersion = new RegistryKey(
|
||||||
ModuleComponentHelper.URI_MODULES_1_0,
|
ModuleComponentHelper.URI_MODULES_1_0,
|
||||||
REGISTRY_PATH_MODULES, moduleId, REGISTRY_PROPERTY_CURRENT_VERSION);
|
REGISTRY_PATH_MODULES, moduleId, REGISTRY_PROPERTY_CURRENT_VERSION);
|
||||||
VersionNumber versionCurrent = (VersionNumber) registryService.getValue(moduleKeyCurrentVersion);
|
VersionNumber versionCurrent = (VersionNumber) registryService.getProperty(moduleKeyCurrentVersion);
|
||||||
String msg = null;
|
String msg = null;
|
||||||
if (versionCurrent == null) // There is no current version
|
if (versionCurrent == null) // There is no current version
|
||||||
{
|
{
|
||||||
msg = I18NUtil.getMessage(MSG_INSTALLING, moduleId, moduleVersion);
|
msg = I18NUtil.getMessage(MSG_INSTALLING, moduleId, moduleVersion);
|
||||||
// Record the install version
|
// Record the install version
|
||||||
registryService.addValue(moduleKeyInstalledVersion, moduleVersion);
|
registryService.addProperty(moduleKeyInstalledVersion, moduleVersion);
|
||||||
}
|
}
|
||||||
else // It is an upgrade or is the same
|
else // It is an upgrade or is the same
|
||||||
{
|
{
|
||||||
@@ -328,7 +382,7 @@ public class ModuleComponentHelper
|
|||||||
}
|
}
|
||||||
loggerService.info(msg);
|
loggerService.info(msg);
|
||||||
// Record the current version
|
// Record the current version
|
||||||
registryService.addValue(moduleKeyCurrentVersion, moduleVersion);
|
registryService.addProperty(moduleKeyCurrentVersion, moduleVersion);
|
||||||
|
|
||||||
Map<String, ModuleComponent> componentsByName = getComponents(moduleId);
|
Map<String, ModuleComponent> componentsByName = getComponents(moduleId);
|
||||||
for (ModuleComponent component : componentsByName.values())
|
for (ModuleComponent component : componentsByName.values())
|
||||||
@@ -387,7 +441,7 @@ public class ModuleComponentHelper
|
|||||||
REGISTRY_PATH_MODULES, moduleId, REGISTRY_PATH_COMPONENTS, name, REGISTRY_PROPERTY_EXECUTION_DATE);
|
REGISTRY_PATH_MODULES, moduleId, REGISTRY_PATH_COMPONENTS, name, REGISTRY_PROPERTY_EXECUTION_DATE);
|
||||||
|
|
||||||
// Check if the component has been executed
|
// Check if the component has been executed
|
||||||
Date executionDate = (Date) registryService.getValue(executionDateKey);
|
Date executionDate = (Date) registryService.getProperty(executionDateKey);
|
||||||
if (executionDate != null && component.isExecuteOnceOnly())
|
if (executionDate != null && component.isExecuteOnceOnly())
|
||||||
{
|
{
|
||||||
// It has been executed and is scheduled for a single execution - leave it
|
// It has been executed and is scheduled for a single execution - leave it
|
||||||
@@ -410,7 +464,7 @@ public class ModuleComponentHelper
|
|||||||
component.execute();
|
component.execute();
|
||||||
// Keep track of it in the registry and in this run
|
// Keep track of it in the registry and in this run
|
||||||
executedComponents.add(component);
|
executedComponents.add(component);
|
||||||
registryService.addValue(executionDateKey, new Date());
|
registryService.addProperty(executionDateKey, new Date());
|
||||||
// Done
|
// Done
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
|
@@ -27,7 +27,9 @@ package org.alfresco.repo.module;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
import org.alfresco.service.cmr.module.ModuleDetails;
|
import org.alfresco.service.cmr.module.ModuleDetails;
|
||||||
@@ -48,6 +50,7 @@ import org.alfresco.util.VersionNumber;
|
|||||||
public class ModuleDetailsImpl implements ModuleDetails
|
public class ModuleDetailsImpl implements ModuleDetails
|
||||||
{
|
{
|
||||||
private String id;
|
private String id;
|
||||||
|
private List<String> aliases;
|
||||||
private VersionNumber version;
|
private VersionNumber version;
|
||||||
private String title;
|
private String title;
|
||||||
private String description;
|
private String description;
|
||||||
@@ -56,53 +59,102 @@ public class ModuleDetailsImpl implements ModuleDetails
|
|||||||
private Date installDate;
|
private Date installDate;
|
||||||
private ModuleInstallState installState;
|
private ModuleInstallState installState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Private constructor to set default values.
|
||||||
|
*/
|
||||||
|
private ModuleDetailsImpl()
|
||||||
|
{
|
||||||
|
aliases = new ArrayList<String>(0);
|
||||||
|
repoVersionMin = new VersionNumber("0.0.0");
|
||||||
|
repoVersionMax = new VersionNumber("999.999.999");
|
||||||
|
this.installState = ModuleInstallState.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the instance from a set of properties. All the property values are trimmed
|
||||||
|
* and empty string values are removed from the set. In other words, zero length or
|
||||||
|
* whitespace strings are not supported.
|
||||||
|
*
|
||||||
* @param properties the set of properties
|
* @param properties the set of properties
|
||||||
*/
|
*/
|
||||||
public ModuleDetailsImpl(Properties properties)
|
public ModuleDetailsImpl(Properties properties)
|
||||||
{
|
{
|
||||||
|
// Set defaults
|
||||||
|
this();
|
||||||
|
// Copy the properties so they don't get modified
|
||||||
|
Properties trimmedProperties = new Properties();
|
||||||
|
// Trim all the property values
|
||||||
|
for (Map.Entry entry : properties.entrySet())
|
||||||
|
{
|
||||||
|
String key = (String) entry.getKey();
|
||||||
|
String value = (String) entry.getValue();
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
// Don't copy nulls over
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String trimmedValue = value.trim();
|
||||||
|
if (trimmedValue.length() == 0)
|
||||||
|
{
|
||||||
|
// Don't copy empty strings over
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// It is a real value
|
||||||
|
trimmedProperties.setProperty(key, trimmedValue);
|
||||||
|
}
|
||||||
|
|
||||||
// Check that the required properties are present
|
// Check that the required properties are present
|
||||||
List<String> missingProperties = new ArrayList<String>(1);
|
List<String> missingProperties = new ArrayList<String>(1);
|
||||||
// ID
|
// ID
|
||||||
id = properties.getProperty(PROP_ID);
|
id = trimmedProperties.getProperty(PROP_ID);
|
||||||
if (id == null) { missingProperties.add(PROP_ID); }
|
if (id == null)
|
||||||
|
{
|
||||||
|
missingProperties.add(PROP_ID);
|
||||||
|
}
|
||||||
|
// ALIASES
|
||||||
|
String aliasesStr = trimmedProperties.getProperty(PROP_ALIASES);
|
||||||
|
if (aliasesStr != null)
|
||||||
|
{
|
||||||
|
StringTokenizer st = new StringTokenizer(aliasesStr, ",");
|
||||||
|
while (st.hasMoreTokens())
|
||||||
|
{
|
||||||
|
String alias = st.nextToken().trim();
|
||||||
|
if (alias.length() == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
aliases.add(alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
// VERSION
|
// VERSION
|
||||||
if (properties.getProperty(PROP_VERSION) == null)
|
if (trimmedProperties.getProperty(PROP_VERSION) == null)
|
||||||
{
|
{
|
||||||
missingProperties.add(PROP_VERSION);
|
missingProperties.add(PROP_VERSION);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
version = new VersionNumber(properties.getProperty(PROP_VERSION));
|
version = new VersionNumber(trimmedProperties.getProperty(PROP_VERSION));
|
||||||
}
|
}
|
||||||
// TITLE
|
// TITLE
|
||||||
title = properties.getProperty(PROP_TITLE);
|
title = trimmedProperties.getProperty(PROP_TITLE);
|
||||||
if (title == null) { missingProperties.add(PROP_TITLE); }
|
if (title == null) { missingProperties.add(PROP_TITLE); }
|
||||||
// DESCRIPTION
|
// DESCRIPTION
|
||||||
description = properties.getProperty(PROP_DESCRIPTION);
|
description = trimmedProperties.getProperty(PROP_DESCRIPTION);
|
||||||
if (description == null) { missingProperties.add(PROP_DESCRIPTION); }
|
if (description == null) { missingProperties.add(PROP_DESCRIPTION); }
|
||||||
// REPO MIN
|
// REPO MIN
|
||||||
if (properties.getProperty(PROP_REPO_VERSION_MIN) == null)
|
if (trimmedProperties.getProperty(PROP_REPO_VERSION_MIN) != null)
|
||||||
{
|
{
|
||||||
repoVersionMin = new VersionNumber("0.0.0");
|
repoVersionMin = new VersionNumber(trimmedProperties.getProperty(PROP_REPO_VERSION_MIN));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
repoVersionMin = new VersionNumber(properties.getProperty(PROP_REPO_VERSION_MIN));
|
|
||||||
}
|
}
|
||||||
// REPO MAX
|
// REPO MAX
|
||||||
if (properties.getProperty(PROP_REPO_VERSION_MAX) == null)
|
if (trimmedProperties.getProperty(PROP_REPO_VERSION_MAX) != null)
|
||||||
{
|
{
|
||||||
repoVersionMax = new VersionNumber("999.999.999");
|
repoVersionMax = new VersionNumber(trimmedProperties.getProperty(PROP_REPO_VERSION_MAX));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
repoVersionMax = new VersionNumber(properties.getProperty(PROP_REPO_VERSION_MAX));
|
|
||||||
}
|
}
|
||||||
// INSTALL DATE
|
// INSTALL DATE
|
||||||
if (properties.getProperty(PROP_INSTALL_DATE) != null)
|
if (trimmedProperties.getProperty(PROP_INSTALL_DATE) != null)
|
||||||
{
|
{
|
||||||
String installDateStr = properties.getProperty(PROP_INSTALL_DATE);
|
String installDateStr = trimmedProperties.getProperty(PROP_INSTALL_DATE);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
installDate = ISO8601DateFormat.parse(installDateStr);
|
installDate = ISO8601DateFormat.parse(installDateStr);
|
||||||
@@ -112,6 +164,19 @@ public class ModuleDetailsImpl implements ModuleDetails
|
|||||||
throw new AlfrescoRuntimeException("Unable to parse install date: " + installDateStr, e);
|
throw new AlfrescoRuntimeException("Unable to parse install date: " + installDateStr, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// INSTALL STATE
|
||||||
|
if (trimmedProperties.getProperty(PROP_INSTALL_STATE) != null)
|
||||||
|
{
|
||||||
|
String installStateStr = trimmedProperties.getProperty(PROP_INSTALL_STATE);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
installState = ModuleInstallState.valueOf(installStateStr);
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("Unable to parse install state: " + installStateStr, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Check
|
// Check
|
||||||
if (missingProperties.size() > 0)
|
if (missingProperties.size() > 0)
|
||||||
{
|
{
|
||||||
@@ -124,9 +189,11 @@ public class ModuleDetailsImpl implements ModuleDetails
|
|||||||
" Min repo version: " + repoVersionMin + "\n" +
|
" Min repo version: " + repoVersionMin + "\n" +
|
||||||
" Max repo version: " + repoVersionMax);
|
" Max repo version: " + repoVersionMax);
|
||||||
}
|
}
|
||||||
|
if (id.matches(INVALID_ID_REGEX))
|
||||||
// Set other defaults
|
{
|
||||||
installState = ModuleInstallState.INSTALLED;
|
throw new AlfrescoRuntimeException(
|
||||||
|
"The module ID '" + id + "' is invalid. It may consist of valid characters, numbers, '.', '_' and '-'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,6 +204,9 @@ public class ModuleDetailsImpl implements ModuleDetails
|
|||||||
*/
|
*/
|
||||||
public ModuleDetailsImpl(String id, VersionNumber versionNumber, String title, String description)
|
public ModuleDetailsImpl(String id, VersionNumber versionNumber, String title, String description)
|
||||||
{
|
{
|
||||||
|
// Set defaults
|
||||||
|
this();
|
||||||
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.version = versionNumber;
|
this.version = versionNumber;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
@@ -170,6 +240,21 @@ public class ModuleDetailsImpl implements ModuleDetails
|
|||||||
String installStateStr = installState.toString();
|
String installStateStr = installState.toString();
|
||||||
properties.setProperty(PROP_INSTALL_STATE, installStateStr);
|
properties.setProperty(PROP_INSTALL_STATE, installStateStr);
|
||||||
}
|
}
|
||||||
|
if (aliases.size() > 0)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
boolean first = true;
|
||||||
|
for (String oldId : aliases)
|
||||||
|
{
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
sb.append(oldId);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
properties.setProperty(PROP_ALIASES, sb.toString());
|
||||||
|
}
|
||||||
// Done
|
// Done
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
@@ -185,6 +270,11 @@ public class ModuleDetailsImpl implements ModuleDetails
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getAliases()
|
||||||
|
{
|
||||||
|
return aliases;
|
||||||
|
}
|
||||||
|
|
||||||
public VersionNumber getVersion()
|
public VersionNumber getVersion()
|
||||||
{
|
{
|
||||||
return version;
|
return version;
|
||||||
|
108
source/java/org/alfresco/repo/module/ModuleDetailsImplTest.java
Normal file
108
source/java/org/alfresco/repo/module/ModuleDetailsImplTest.java
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* 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 java.util.Properties;
|
||||||
|
|
||||||
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
|
import org.alfresco.service.cmr.module.ModuleDetails;
|
||||||
|
import org.alfresco.service.cmr.module.ModuleInstallState;
|
||||||
|
import org.alfresco.util.VersionNumber;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.alfresco.repo.module.ModuleDetailsImpl
|
||||||
|
*
|
||||||
|
* @author Derek Hulley
|
||||||
|
*/
|
||||||
|
public class ModuleDetailsImplTest extends TestCase
|
||||||
|
{
|
||||||
|
private Properties defaultProperties;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception
|
||||||
|
{
|
||||||
|
defaultProperties = new Properties();
|
||||||
|
defaultProperties.setProperty(ModuleDetails.PROP_ID, "org.alfresco.module.Test");
|
||||||
|
defaultProperties.setProperty(ModuleDetails.PROP_ALIASES, "test, Test");
|
||||||
|
defaultProperties.setProperty(ModuleDetails.PROP_TITLE, "Test");
|
||||||
|
defaultProperties.setProperty(ModuleDetails.PROP_DESCRIPTION, "Test description");
|
||||||
|
defaultProperties.setProperty(ModuleDetails.PROP_VERSION, "1.0.0");
|
||||||
|
defaultProperties.setProperty(ModuleDetails.PROP_REPO_VERSION_MIN, new VersionNumber("1.2").toString());
|
||||||
|
defaultProperties.setProperty(ModuleDetails.PROP_REPO_VERSION_MAX, new VersionNumber("1.4.3").toString());
|
||||||
|
defaultProperties.setProperty(ModuleDetails.PROP_INSTALL_STATE, ModuleInstallState.INSTALLED.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public void testDefaults()
|
||||||
|
{
|
||||||
|
ModuleDetails details = new ModuleDetailsImpl(defaultProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWriteAndReadProperties()
|
||||||
|
{
|
||||||
|
ModuleDetails details = new ModuleDetailsImpl(defaultProperties);
|
||||||
|
// convert back to properties
|
||||||
|
Properties processedProperties = details.getProperties();
|
||||||
|
assertEquals("The number of properties changed", defaultProperties.size(), processedProperties.size());
|
||||||
|
assertEquals("The properties are different", defaultProperties, processedProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTrimming() throws Exception
|
||||||
|
{
|
||||||
|
defaultProperties.setProperty(ModuleDetails.PROP_INSTALL_STATE, " ");
|
||||||
|
ModuleDetails details = new ModuleDetailsImpl(defaultProperties);
|
||||||
|
assertEquals("Expected the install state to be UNKNOWN", ModuleInstallState.UNKNOWN, details.getInstallState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testInvalidIds() throws Exception
|
||||||
|
{
|
||||||
|
String[] invalidIds = new String[] {"", " ", "$", "module$Test", "module.Test$", "org alfresco module Test"};
|
||||||
|
for (String invalidId : invalidIds)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
defaultProperties.setProperty(ModuleDetails.PROP_ID, invalidId);
|
||||||
|
new ModuleDetailsImpl(defaultProperties);
|
||||||
|
fail("Invalid ID not detected: " + invalidId);
|
||||||
|
}
|
||||||
|
catch (AlfrescoRuntimeException e)
|
||||||
|
{
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testValidIds() throws Exception
|
||||||
|
{
|
||||||
|
String[] validIds = new String[] {"abc123", " abc123 ", "a-b-c", "a.b.c", "a_b_c", "A.1.2.3"};
|
||||||
|
for (String validId : validIds)
|
||||||
|
{
|
||||||
|
defaultProperties.setProperty(ModuleDetails.PROP_ID, validId);
|
||||||
|
new ModuleDetailsImpl(defaultProperties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -74,7 +74,6 @@ public class ModuleServiceImpl implements ModuleService
|
|||||||
private static Log logger = LogFactory.getLog(ModuleServiceImpl.class);
|
private static Log logger = LogFactory.getLog(ModuleServiceImpl.class);
|
||||||
|
|
||||||
private ServiceRegistry serviceRegistry;
|
private ServiceRegistry serviceRegistry;
|
||||||
private DescriptorService descriptorService;
|
|
||||||
private AuthenticationComponent authenticationComponent;
|
private AuthenticationComponent authenticationComponent;
|
||||||
private ModuleComponentHelper moduleComponentHelper;
|
private ModuleComponentHelper moduleComponentHelper;
|
||||||
/** A cache of module details by module ID */
|
/** A cache of module details by module ID */
|
||||||
@@ -95,7 +94,6 @@ public class ModuleServiceImpl implements ModuleService
|
|||||||
|
|
||||||
public void setDescriptorService(DescriptorService descriptorService)
|
public void setDescriptorService(DescriptorService descriptorService)
|
||||||
{
|
{
|
||||||
this.descriptorService = descriptorService;
|
|
||||||
this.moduleComponentHelper.setDescriptorService(descriptorService);
|
this.moduleComponentHelper.setDescriptorService(descriptorService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -148,9 +148,17 @@ public class InstalledFiles
|
|||||||
*
|
*
|
||||||
* @return the file location
|
* @return the file location
|
||||||
*/
|
*/
|
||||||
private String getFileLocation()
|
public String getFileLocation()
|
||||||
{
|
{
|
||||||
return this.warLocation + ModuleManagementTool.MODULE_DIR + "/" + this.moduleId + "/modifications.install";
|
return this.warLocation + getFilePathInWar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the path of the install file within the WAR
|
||||||
|
*/
|
||||||
|
public String getFilePathInWar()
|
||||||
|
{
|
||||||
|
return ModuleManagementTool.MODULE_DIR + "/" + this.moduleId + "/modifications.install";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -75,7 +75,7 @@ public class ModuleDetailsHelper
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
File file = new File(location, ModuleManagementTool.DETECTOR_AMP_AND_WAR);
|
File file = new File(location, ModuleManagementTool.DETECTOR_AMP_AND_WAR);
|
||||||
if (file.exists() == true)
|
if (file.exists())
|
||||||
{
|
{
|
||||||
InputStream is = new FileInputStream(file);
|
InputStream is = new FileInputStream(file);
|
||||||
result = createModuleDetailsFromPropertiesStream(is);
|
result = createModuleDetailsFromPropertiesStream(is);
|
||||||
@@ -102,6 +102,19 @@ public class ModuleDetailsHelper
|
|||||||
return ModuleDetailsHelper.createModuleDetailsFromPropertyLocation(modulePropertiesFileLocation);
|
return ModuleDetailsHelper.createModuleDetailsFromPropertyLocation(modulePropertiesFileLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param warLocation the location of the WAR file
|
||||||
|
* @param moduleId the module ID within the WAR
|
||||||
|
* @return Returns a file handle to the module properties file within the given WAR.
|
||||||
|
* The file may or may not exist.
|
||||||
|
*/
|
||||||
|
public static File getModuleDetailsFileFromWarAndId(String warLocation, String moduleId)
|
||||||
|
{
|
||||||
|
String location = ModuleDetailsHelper.getModulePropertiesFileLocation(warLocation, moduleId);
|
||||||
|
File file = new File(location, ModuleManagementTool.DETECTOR_AMP_AND_WAR);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the file location
|
* Gets the file location
|
||||||
*
|
*
|
||||||
@@ -109,9 +122,18 @@ public class ModuleDetailsHelper
|
|||||||
* @param moduleId the module id
|
* @param moduleId the module id
|
||||||
* @return the file location
|
* @return the file location
|
||||||
*/
|
*/
|
||||||
private static String getModulePropertiesFileLocation(String warLocation, String moduleId)
|
public static String getModulePropertiesFileLocation(String warLocation, String moduleId)
|
||||||
{
|
{
|
||||||
return warLocation + ModuleManagementTool.MODULE_DIR + "/" + moduleId + "/" + "module.properties";
|
return warLocation + getModulePropertiesFilePathInWar(moduleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param moduleId the module ID
|
||||||
|
* @return Returns the path of the module file within a WAR
|
||||||
|
*/
|
||||||
|
public static String getModulePropertiesFilePathInWar(String moduleId)
|
||||||
|
{
|
||||||
|
return ModuleManagementTool.MODULE_DIR + "/" + moduleId + "/" + "module.properties";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -31,6 +31,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
@@ -229,7 +230,7 @@ public class ModuleManagementTool
|
|||||||
backUpDir.mkdir();
|
backUpDir.mkdir();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a backup of the war we are oging to modify
|
// Make a backup of the war we are going to modify
|
||||||
if (backupWAR == true)
|
if (backupWAR == true)
|
||||||
{
|
{
|
||||||
java.io.File warFile = new java.io.File(warFileLocation);
|
java.io.File warFile = new java.io.File(warFileLocation);
|
||||||
@@ -255,8 +256,28 @@ public class ModuleManagementTool
|
|||||||
String installingId = installingModuleDetails.getId();
|
String installingId = installingModuleDetails.getId();
|
||||||
VersionNumber installingVersion = installingModuleDetails.getVersion();
|
VersionNumber installingVersion = installingModuleDetails.getVersion();
|
||||||
|
|
||||||
// Get the detail of the installed module
|
// Try to find an installed module by the ID
|
||||||
ModuleDetails installedModuleDetails = ModuleDetailsHelper.createModuleDetailsFromWarAndId(warFileLocation, installingModuleDetails.getId());
|
ModuleDetails installedModuleDetails = ModuleDetailsHelper.createModuleDetailsFromWarAndId(warFileLocation, installingId);
|
||||||
|
if (installedModuleDetails == null)
|
||||||
|
{
|
||||||
|
// It might be there as one of the aliases
|
||||||
|
List<String> installingAliases = installingModuleDetails.getAliases();
|
||||||
|
for (String installingAlias : installingAliases)
|
||||||
|
{
|
||||||
|
ModuleDetails installedAliasModuleDetails = ModuleDetailsHelper.createModuleDetailsFromWarAndId(warFileLocation, installingAlias);
|
||||||
|
if (installedAliasModuleDetails == null)
|
||||||
|
{
|
||||||
|
// There is nothing by that alias
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// We found an alias and will treat it as the same module
|
||||||
|
installedModuleDetails = installedAliasModuleDetails;
|
||||||
|
outputMessage("Module '" + installingAlias + "' is installed and is an alias of '" + installingId + "'");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now clean up the old instance
|
||||||
if (installedModuleDetails != null)
|
if (installedModuleDetails != null)
|
||||||
{
|
{
|
||||||
String installedId = installedModuleDetails.getId();
|
String installedId = installedModuleDetails.getId();
|
||||||
@@ -453,6 +474,12 @@ public class ModuleManagementTool
|
|||||||
|
|
||||||
outputMessage("Recovering file '" + update.getKey() + "' from backup '" + update.getValue() + "'", true);
|
outputMessage("Recovering file '" + update.getKey() + "' from backup '" + update.getValue() + "'", true);
|
||||||
}
|
}
|
||||||
|
// Now remove the installed files list
|
||||||
|
String installedFilesPathInWar = installedFiles.getFilePathInWar();
|
||||||
|
removeFile(warFileLocation, installedFilesPathInWar, preview);
|
||||||
|
// Remove the module properties
|
||||||
|
String modulePropertiesFileLocationInWar = ModuleDetailsHelper.getModulePropertiesFilePathInWar(moduleId);
|
||||||
|
removeFile(warFileLocation, modulePropertiesFileLocationInWar, preview);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -478,7 +505,7 @@ public class ModuleManagementTool
|
|||||||
outputMessage("The file '" + filePath + "' was expected for removal but was not present in the war", true);
|
outputMessage("The file '" + filePath + "' was expected for removal but was not present in the war", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies a file from the AMP location to the correct location in the WAR, interating on directories where appropraite.
|
* Copies a file from the AMP location to the correct location in the WAR, interating on directories where appropraite.
|
||||||
*
|
*
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# The default AEP => WAR file mappings
|
# The default AMP => WAR file mappings
|
||||||
/config=/WEB-INF/classes
|
/config=/WEB-INF/classes
|
||||||
/lib=/WEB-INF/lib
|
/lib=/WEB-INF/lib
|
||||||
/licenses=/WEB-INF/licenses
|
/licenses=/WEB-INF/licenses
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
package org.alfresco.service.cmr.module;
|
package org.alfresco.service.cmr.module;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.alfresco.util.VersionNumber;
|
import org.alfresco.util.VersionNumber;
|
||||||
@@ -38,6 +39,7 @@ import org.alfresco.util.VersionNumber;
|
|||||||
public interface ModuleDetails
|
public interface ModuleDetails
|
||||||
{
|
{
|
||||||
static final String PROP_ID = "module.id";
|
static final String PROP_ID = "module.id";
|
||||||
|
static final String PROP_ALIASES = "module.aliases";
|
||||||
static final String PROP_VERSION = "module.version";
|
static final String PROP_VERSION = "module.version";
|
||||||
static final String PROP_TITLE = "module.title";
|
static final String PROP_TITLE = "module.title";
|
||||||
static final String PROP_DESCRIPTION = "module.description";
|
static final String PROP_DESCRIPTION = "module.description";
|
||||||
@@ -46,6 +48,8 @@ public interface ModuleDetails
|
|||||||
static final String PROP_INSTALL_DATE = "module.installDate";
|
static final String PROP_INSTALL_DATE = "module.installDate";
|
||||||
static final String PROP_INSTALL_STATE = "module.installState";
|
static final String PROP_INSTALL_STATE = "module.installState";
|
||||||
|
|
||||||
|
static final String INVALID_ID_REGEX = ".*[^\\w.-].*";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all defined properties.
|
* Get all defined properties.
|
||||||
*
|
*
|
||||||
@@ -60,6 +64,11 @@ public interface ModuleDetails
|
|||||||
*/
|
*/
|
||||||
String getId();
|
String getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns a list of IDs by which this module may once have been known
|
||||||
|
*/
|
||||||
|
List<String> getAliases();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the version number of the module
|
* Get the version number of the module
|
||||||
*
|
*
|
||||||
|
@@ -32,7 +32,7 @@ package org.alfresco.service.cmr.module;
|
|||||||
public enum ModuleInstallState
|
public enum ModuleInstallState
|
||||||
{
|
{
|
||||||
/** The state of the module is unknown */
|
/** The state of the module is unknown */
|
||||||
UKNOWN,
|
UNKNOWN,
|
||||||
/** The module is installed */
|
/** The module is installed */
|
||||||
INSTALLED,
|
INSTALLED,
|
||||||
/** The module is disabled */
|
/** The module is disabled */
|
||||||
|
Reference in New Issue
Block a user