FIXED : ALF-12777: MMT should not install AMPs which override pre-existing files in the war file, unless -force is provided

The MMT is moving toward more of a validation phase (checks things, calculate changes) then an execution phase (makes the changes).


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@33880 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Gethin James
2012-02-14 10:50:04 +00:00
parent 703e769bd8
commit 4f1d0adc4d
4 changed files with 166 additions and 118 deletions

View File

@@ -26,6 +26,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import org.alfresco.error.AlfrescoRuntimeException;
@@ -196,7 +197,7 @@ public class ModuleManagementTool implements LogOutput
* @param warFileLocation the location of the WAR file into which the AMP file is to be installed.
* @param preview indicates whether this should be a preview install. This means that the process of
* installation will be followed and reported, but the WAR file will not be modified.
* @param forceInstall indicates whether the installed files will be replaces reguarless of the currently installed
* @param forceInstall indicates whether the installed files will be replaces regardless of the currently installed
* version of the AMP. Generally used during development of the AMP.
* @param backupWAR indicates whether we should backup the war we are modifying or not
*/
@@ -240,6 +241,68 @@ public class ModuleManagementTool implements LogOutput
// Try to find an installed module by the ID
ModuleDetails installedModuleDetails = warHelper.getModuleDetailsOrAlias(theWar, installingModuleDetails);
uninstallIfNecessary(warFileLocation, installedModuleDetails, preview, forceInstall, installingVersion);
outputMessage("Adding files relating to version '" + installingVersion + "' of module '" + installingId + "'");
InstalledFiles installedFiles = new InstalledFiles(warFileLocation, installingId);
Properties directoryChanges = calculateChanges(ampFileLocation, warFileLocation, preview, forceInstall, installedFiles);
if (preview == false)
{
//Now actually do the changes
if (directoryChanges != null && directoryChanges.size() > 0)
{
for (Entry<Object, Object> entry : directoryChanges.entrySet())
{
File destination = new File((String) entry.getValue(), DETECTOR_AMP_AND_WAR);
File source = new File((String) entry.getKey(), DETECTOR_AMP_AND_WAR);
//Do the bulk copy since this is quicker than copying files one by one
//The changes aren't actuall "committed" until the File.update() is called (below)
destination.copyAllFrom(source);
}
}
// Save the installed file list
installedFiles.save();
// Update the installed module details
installingModuleDetails.setInstallState(ModuleInstallState.INSTALLED);
installingModuleDetails.setInstallDate(new Date());
ModuleDetailsHelper.saveModuleDetails(warFileLocation, installingModuleDetails);
// Update the zip files
File.update();
// Set the modified date
java.io.File warFile = new java.io.File(warFileLocation);
if (warFile.exists())
{
warFile.setLastModified(System.currentTimeMillis());
}
}
}
catch (ZipWarningException ignore)
{
// Only instances of the class ZipWarningException exist in the chain of
// exceptions. We choose to ignore this.
}
catch (ZipControllerException exception)
{
// At least one exception occured which is not just a ZipWarningException.
// This is a severe situation that needs to be handled.
throw new ModuleManagementToolException("A Zip error was encountered during deployment of the AEP into the WAR", exception);
}
catch (IOException exception)
{
throw new ModuleManagementToolException("An IO error was encountered during deployment of the AEP into the WAR", exception);
}
}
private void uninstallIfNecessary(String warFileLocation, ModuleDetails installedModuleDetails, boolean preview,
boolean forceInstall, VersionNumber installingVersion)
{
// Now clean up the old instance
if (installedModuleDetails != null)
{
@@ -275,6 +338,14 @@ public class ModuleManagementTool implements LogOutput
uninstallModule(installedId, warFileLocation, preview, true);
}
}
}
/**
*/
private Properties calculateChanges(String ampFileLocation, String warFileLocation, boolean preview,
boolean forceInstall, InstalledFiles installedFiles) throws IOException
{
Properties dirChanges = new Properties();
// Check if a custom mapping file has been defined
Properties fileMappingProperties = null;
@@ -297,8 +368,6 @@ public class ModuleManagementTool implements LogOutput
}
// Copy the files from the AMP file into the WAR file
outputMessage("Adding files relating to version '" + installingVersion + "' of module '" + installingId + "'");
InstalledFiles installedFiles = new InstalledFiles(warFileLocation, installingId);
for (Map.Entry<Object, Object> entry : fileMappingProperties.entrySet())
{
// The file mappings are expected to start with "/"
@@ -317,62 +386,21 @@ public class ModuleManagementTool implements LogOutput
mappingTarget = mappingTarget.trim(); //trim whitespace
// Run throught the files one by one figuring out what we are going to do during the copy
copyToWar(ampFileLocation, warFileLocation, mappingSource, mappingTarget, installedFiles, preview);
calculateCopyToWar(ampFileLocation, warFileLocation, mappingSource, mappingTarget, installedFiles, preview, forceInstall);
if (preview == false)
{
// Get a reference to the source folder (if it isn't present don't do anything)
File source = new File(ampFileLocation + "/" + mappingSource, DETECTOR_AMP_AND_WAR);
if (source != null && source.list() != null)
{
// Get a reference to the destination folder
File destination = new File(warFileLocation + "/" + mappingTarget, DETECTOR_AMP_AND_WAR);
if (destination == null)
{
throw new ModuleManagementToolException("The destination folder '" + mappingTarget + "' as specified in mapping properties does not exist in the war");
}
// Do the bulk copy since this is quicker than copying files one by one
destination.copyAllFrom(source);
}
}
// Add to the list of directory changes so we can implement the changes later.
String sourceDir = ampFileLocation + mappingSource;
String destinationDir = warFileLocation + mappingTarget;
dirChanges.put(sourceDir, destinationDir);
}
if (preview == false)
{
// Save the installed file list
installedFiles.save();
}
// Update the installed module details
installingModuleDetails.setInstallState(ModuleInstallState.INSTALLED);
installingModuleDetails.setInstallDate(new Date());
ModuleDetailsHelper.saveModuleDetails(warFileLocation, installingModuleDetails);
// Update the zip files
File.update();
// Set the modified date
java.io.File warFile = new java.io.File(warFileLocation);
if (warFile.exists())
{
warFile.setLastModified(System.currentTimeMillis());
}
}
}
catch (ZipWarningException ignore)
{
// Only instances of the class ZipWarningException exist in the chain of
// exceptions. We choose to ignore this.
}
catch (ZipControllerException exception)
{
// At least one exception occured which is not just a ZipWarningException.
// This is a severe situation that needs to be handled.
throw new ModuleManagementToolException("A Zip error was encountered during deployment of the AEP into the WAR", exception);
}
catch (IOException exception)
{
throw new ModuleManagementToolException("An IO error was encountered during deployment of the AEP into the WAR", exception);
}
return dirChanges;
}
private void backupWar(String warFileLocation, boolean backupWAR)
@@ -511,9 +539,11 @@ public class ModuleManagementTool implements LogOutput
* @param destinationDir the directory in the WAR to copy to. It must start with "/".
* @param installedFiles a list of the currently installed files
* @param preview indicates whether this is a preview install or not
* @param forceInstall indicates whether the installed files will be replaces regardless of the currently installed
* version of the AMP.
* @throws IOException throws any IOExpceptions thar are raised
*/
private void copyToWar(String ampFileLocation, String warFileLocation, String sourceDir, String destinationDir, InstalledFiles installedFiles, boolean preview)
private void calculateCopyToWar(String ampFileLocation, String warFileLocation, String sourceDir, String destinationDir, InstalledFiles installedFiles, boolean preview, boolean forceInstall)
throws IOException
{
if (sourceDir.length() == 0 || !sourceDir.startsWith("/"))
@@ -554,6 +584,8 @@ public class ModuleManagementTool implements LogOutput
createFile = true;
}
else
{
if (forceInstall)
{
// Backup file about to be updated
backupLocation = BACKUP_DIR + "/" + generateGuid() + ".bin";
@@ -562,6 +594,14 @@ public class ModuleManagementTool implements LogOutput
File backupFile = new File(warFileLocation + backupLocation, DETECTOR_AMP_AND_WAR);
backupFile.copyFrom(destinationChild);
}
} else {
//Not a forced install, there is an existing file in the war, lets rollback the transaction,
//throw an error and explain the problem.
// File.
// ZipController zipController = ZipController.getInstance(warFile);
// zipController.reset();
throw new ModuleManagementToolException("ERROR: The amp will overwrite an existing file in the war '" + destinationDir + "/" + sourceChild.getName() + "'. Execution halted. By specifying -force , you can force installation of AMP regardless of the current war state.");
}
}
if (createFile == true)
@@ -583,8 +623,8 @@ public class ModuleManagementTool implements LogOutput
mkdir = true;
}
copyToWar(ampFileLocation, warFileLocation, sourceDir + "/" + sourceChild.getName(),
destinationDir + "/" + sourceChild.getName(), installedFiles, preview);
calculateCopyToWar(ampFileLocation, warFileLocation, sourceDir + "/" + sourceChild.getName(),
destinationDir + "/" + sourceChild.getName(), installedFiles, preview, forceInstall);
if (mkdir == true)
{
installedFiles.addMkdir(destinationDir + "/" + sourceChild.getName());

View File

@@ -81,18 +81,8 @@ public class ModuleManagementToolTest extends TestCase
InstalledFiles installed0 = new InstalledFiles(warLocation, "test");
installed0.load();
assertNotNull(installed0);
assertEquals(8, installed0.getAdds().size());
assertEquals(9, installed0.getAdds().size());
assertEquals(1, installed0.getMkdirs().size());
assertEquals(1, installed0.getUpdates().size());
String backup = null;
String orig = null;
for (Map.Entry<String, String> update : installed0.getUpdates().entrySet())
{
checkContentsOfFile(warLocation + update.getKey(), "VERSIONONE");
checkContentsOfFile(warLocation + update.getValue(), "ORIGIONAL");
backup = update.getValue();
orig = update.getKey();
}
// Try and install same version
try
@@ -129,7 +119,6 @@ public class ModuleManagementToolTest extends TestCase
files3.add("/scripts/test.js");
files3.add("/jsp/test.jsp");
files3.add("/extra.txt");
files3.add(backup);
checkForFileNonExistance(warLocation, files3);
// Check the intstalled files
@@ -140,9 +129,6 @@ public class ModuleManagementToolTest extends TestCase
assertEquals(1, installed1.getMkdirs().size());
assertEquals(0, installed1.getUpdates().size());
// Ensure the file has been reverted as it isnt updated in the v2.0
checkContentsOfFile(warLocation + orig, "ORIGIONAL");
/**
* Try and install an earlier version over a later version
*/
@@ -269,6 +255,28 @@ public class ModuleManagementToolTest extends TestCase
}
}
public void testExistingFilesInWar() throws Exception
{
manager.setVerbose(true);
String warLocation = getFileLocation(".war", "module/test.war");
String ampLocation = getFileLocation(".amp", "module/test_v4.amp");
try
{
this.manager.installModule(ampLocation, warLocation, false, false, true);
}
catch(ModuleManagementToolException exception)
{
assertTrue(exception.getMessage().contains("will overwrite an existing file in the war"));
}
this.manager.installModule(ampLocation, warLocation, false, true, true); //Now force it
checkContentsOfFile(warLocation + "/jsp/relogin.jsp", "VERSIONONE");
checkContentsOfFile(warLocation + "/css/main.css", "p{margin-bottom:1em;}");
}
public void testWhiteSpaceInCustomMapping()
throws Exception
{

Binary file not shown.