[MNT-24623] fix for unzipping zip files having accent chars (#3321)

This commit is contained in:
SatyamSah5
2025-04-18 09:45:21 +05:30
committed by GitHub
parent 6e5b64be12
commit b51374532e
3 changed files with 610 additions and 559 deletions

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited * Copyright (C) 2005 - 2025 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -41,6 +41,11 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.zip.ZipException; import java.util.zip.ZipException;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.utils.InputStreamStatistics;
import org.apache.commons.lang3.StringUtils;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ApplicationModel; import org.alfresco.model.ApplicationModel;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
@@ -62,10 +67,6 @@ import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.view.Location; import org.alfresco.service.cmr.view.Location;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.TempFileProvider; import org.alfresco.util.TempFileProvider;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.utils.InputStreamStatistics;
import org.apache.commons.lang3.StringUtils;
/** /**
* Importer action executor * Importer action executor
@@ -110,7 +111,8 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
/** /**
* Sets the ImporterService to use * Sets the ImporterService to use
* *
* @param importerService The ImporterService * @param importerService
* The ImporterService
*/ */
public void setImporterService(ImporterService importerService) public void setImporterService(ImporterService importerService)
{ {
@@ -120,27 +122,30 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
/** /**
* Sets the NodeService to use * Sets the NodeService to use
* *
* @param nodeService The NodeService * @param nodeService
* The NodeService
*/ */
public void setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
{ {
this.nodeService = nodeService; this.nodeService = nodeService;
} }
/** /**
* Sets the ContentService to use * Sets the ContentService to use
* *
* @param contentService The ContentService * @param contentService
* The ContentService
*/ */
public void setContentService(ContentService contentService) public void setContentService(ContentService contentService)
{ {
this.contentService = contentService; this.contentService = contentService;
} }
/** /**
* Sets the FileFolderService to use * Sets the FileFolderService to use
* *
* @param fileFolderService The FileFolderService * @param fileFolderService
* The FileFolderService
*/ */
public void setFileFolderService(FileFolderService fileFolderService) public void setFileFolderService(FileFolderService fileFolderService)
{ {
@@ -152,19 +157,21 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
*/ */
public boolean isHighByteZip() public boolean isHighByteZip()
{ {
return this.highByteZip; return this.highByteZip;
} }
/** /**
* @param highByteZip the encoding switch for high-byte ZIP filenames to set * @param highByteZip
* the encoding switch for high-byte ZIP filenames to set
*/ */
public void setHighByteZip(boolean highByteZip) public void setHighByteZip(boolean highByteZip)
{ {
this.highByteZip = highByteZip; this.highByteZip = highByteZip;
} }
/** /**
* @param ratioThreshold the compression ratio threshold for Zip bomb detection * @param ratioThreshold
* the compression ratio threshold for Zip bomb detection
*/ */
public void setRatioThreshold(long ratioThreshold) public void setRatioThreshold(long ratioThreshold)
{ {
@@ -172,10 +179,10 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
} }
/** /**
* This method sets a value for the uncompressed bytes limit. If the string does not {@link Long#parseLong(String) parse} to a * This method sets a value for the uncompressed bytes limit. If the string does not {@link Long#parseLong(String) parse} to a java long.
* java long.
* *
* @param limit a String representing a valid Java long. * @param limit
* a String representing a valid Java long.
*/ */
public void setUncompressedBytesLimit(String limit) public void setUncompressedBytesLimit(String limit)
{ {
@@ -200,110 +207,112 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
{ {
if (this.nodeService.exists(actionedUponNodeRef) == true) if (this.nodeService.exists(actionedUponNodeRef) == true)
{ {
// The node being passed in should be an Alfresco content package // The node being passed in should be an Alfresco content package
ContentReader reader = this.contentService.getReader(actionedUponNodeRef, ContentModel.PROP_CONTENT); ContentReader reader = this.contentService.getReader(actionedUponNodeRef, ContentModel.PROP_CONTENT);
if (reader != null) if (reader != null)
{ {
NodeRef importDest = (NodeRef)ruleAction.getParameterValue(PARAM_DESTINATION_FOLDER); NodeRef importDest = (NodeRef) ruleAction.getParameterValue(PARAM_DESTINATION_FOLDER);
if (MimetypeMap.MIMETYPE_ACP.equals(reader.getMimetype())) if (MimetypeMap.MIMETYPE_ACP.equals(reader.getMimetype()))
{ {
// perform an import of an Alfresco ACP file (special format ZIP structure) // perform an import of an Alfresco ACP file (special format ZIP structure)
File zipFile = null; File zipFile = null;
try try
{ {
// unfortunately a ZIP file can not be read directly from an input stream so we have to create // unfortunately a ZIP file can not be read directly from an input stream so we have to create
// a temporary file first // a temporary file first
zipFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX_ACP); zipFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX_ACP);
reader.getContent(zipFile); reader.getContent(zipFile);
ACPImportPackageHandler importHandler = new ACPImportPackageHandler(zipFile, ACPImportPackageHandler importHandler = new ACPImportPackageHandler(zipFile,
(String)ruleAction.getParameterValue(PARAM_ENCODING)); (String) ruleAction.getParameterValue(PARAM_ENCODING));
this.importerService.importView(importHandler, new Location(importDest), null, null); this.importerService.importView(importHandler, new Location(importDest), null, null);
} }
finally finally
{ {
// now the import is done, delete the temporary file // now the import is done, delete the temporary file
if (zipFile != null) if (zipFile != null)
{ {
zipFile.delete(); zipFile.delete();
} }
} }
} }
else if (MimetypeMap.MIMETYPE_ZIP.equals(reader.getMimetype())) else if (MimetypeMap.MIMETYPE_ZIP.equals(reader.getMimetype()))
{ {
// perform an import of a standard ZIP file // perform an import of a standard ZIP file
ZipFile zipFile = null; ZipFile zipFile = null;
File tempFile = null; File tempFile = null;
try try
{ {
tempFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX_ACP); tempFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX_ACP);
reader.getContent(tempFile); reader.getContent(tempFile);
// NOTE: This encoding allows us to workaround bug: // NOTE: This encoding allows us to workaround bug:
// http://bugs.sun.com/bugdatabase/view_bug.do;:WuuT?bug_id=4820807 // http://bugs.sun.com/bugdatabase/view_bug.do;:WuuT?bug_id=4820807
// We also try to use the extra encoding information if present // We also try to use the extra encoding information if present
String encoding = (String) ruleAction.getParameterValue(PARAM_ENCODING); String encoding = (String) ruleAction.getParameterValue(PARAM_ENCODING);
if (encoding == null) if (encoding == null)
{ {
encoding = "UTF-8"; encoding = "UTF-8";
} }
else else
{ {
if (encoding.equalsIgnoreCase("default")) if (encoding.equalsIgnoreCase("default"))
{ {
encoding = null; encoding = null;
} }
} }
zipFile = new ZipFile(tempFile, encoding, false); zipFile = new ZipFile(tempFile, encoding, false);
// build a temp dir name based on the ID of the noderef we are importing // build a temp dir name based on the ID of the noderef we are importing
// also use the long life temp folder as large ZIP files can take a while // also use the long life temp folder as large ZIP files can take a while
File alfTempDir = TempFileProvider.getLongLifeTempDir("import"); File alfTempDir = TempFileProvider.getLongLifeTempDir("import");
File tempDir = new File(alfTempDir.getPath() + File.separatorChar + actionedUponNodeRef.getId()); File tempDir = new File(alfTempDir.getPath() + File.separatorChar + actionedUponNodeRef.getId());
try try
{ {
// TODO: improve this code to directly pipe the zip stream output into the repo objects - // TODO: improve this code to directly pipe the zip stream output into the repo objects -
// to remove the need to expand to the filesystem first? // to remove the need to expand to the filesystem first?
extractFile(zipFile, tempDir.getPath(), new ZipBombProtection(ratioThreshold, uncompressedBytesLimit)); extractFile(zipFile, tempDir.getPath(), new ZipBombProtection(ratioThreshold, uncompressedBytesLimit));
importDirectory(tempDir.getPath(), importDest); importDirectory(tempDir.getPath(), importDest);
} }
finally finally
{ {
deleteDir(tempDir); deleteDir(tempDir);
} }
} }
catch (IOException ioErr) catch (IOException ioErr)
{ {
throw new AlfrescoRuntimeException("Failed to import ZIP file.", ioErr); throw new AlfrescoRuntimeException("Failed to import ZIP file.", ioErr);
} }
finally finally
{ {
// now the import is done, delete the temporary file // now the import is done, delete the temporary file
if (tempFile != null) if (tempFile != null)
{ {
tempFile.delete(); tempFile.delete();
} }
if (zipFile != null) if (zipFile != null)
{ {
try try
{ {
zipFile.close(); zipFile.close();
} }
catch (IOException e) catch (IOException e)
{ {
throw new AlfrescoRuntimeException("Failed to close zip package.", e); throw new AlfrescoRuntimeException("Failed to close zip package.", e);
} }
} }
} }
} }
} }
} }
} }
/** /**
* Recursively import a directory structure into the specified root node * Recursively import a directory structure into the specified root node
* *
* @param dir The directory of files and folders to import * @param dir
* @param root The root node to import into * The directory of files and folders to import
* @param root
* The root node to import into
*/ */
private void importDirectory(String dir, NodeRef root) private void importDirectory(String dir, NodeRef root)
{ {
@@ -368,16 +377,18 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
protected void addParameterDefinitions(List<ParameterDefinition> paramList) protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{ {
paramList.add(new ParameterDefinitionImpl(PARAM_DESTINATION_FOLDER, DataTypeDefinition.NODE_REF, paramList.add(new ParameterDefinitionImpl(PARAM_DESTINATION_FOLDER, DataTypeDefinition.NODE_REF,
true, getParamDisplayLabel(PARAM_DESTINATION_FOLDER))); true, getParamDisplayLabel(PARAM_DESTINATION_FOLDER)));
paramList.add(new ParameterDefinitionImpl(PARAM_ENCODING, DataTypeDefinition.TEXT, paramList.add(new ParameterDefinitionImpl(PARAM_ENCODING, DataTypeDefinition.TEXT,
false, getParamDisplayLabel(PARAM_ENCODING))); false, getParamDisplayLabel(PARAM_ENCODING)));
} }
/** /**
* Extract the file and folder structure of a ZIP file into the specified directory * Extract the file and folder structure of a ZIP file into the specified directory
* *
* @param archive The ZIP archive to extract * @param archive
* @param extractDir The directory to extract into * The ZIP archive to extract
* @param extractDir
* The directory to extract into
*/ */
public static void extractFile(ZipFile archive, String extractDir) public static void extractFile(ZipFile archive, String extractDir)
{ {
@@ -387,9 +398,12 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
/** /**
* Extract the file and folder structure of a ZIP file into the specified directory using a progress tracker * Extract the file and folder structure of a ZIP file into the specified directory using a progress tracker
* *
* @param archive The ZIP archive to extract * @param archive
* @param extractDir The directory to extract into * The ZIP archive to extract
* @param tracker The extraction progress tracker to check against during the extraction process * @param extractDir
* The directory to extract into
* @param tracker
* The extraction progress tracker to check against during the extraction process
*/ */
public static void extractFile(ZipFile archive, String extractDir, ExtractionProgressTracker tracker) public static void extractFile(ZipFile archive, String extractDir, ExtractionProgressTracker tracker)
{ {
@@ -407,7 +421,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
ZipArchiveEntry entry = e.nextElement(); ZipArchiveEntry entry = e.nextElement();
if (!entry.isDirectory()) if (!entry.isDirectory())
{ {
fileName = StringUtils.stripAccents(entry.getName()).replaceAll("\\?","_"); fileName = StringUtils.stripAccents(entry.getName()).replaceAll("\\?", "_");
fileName = fileName.replace('/', File.separatorChar); fileName = fileName.replace('/', File.separatorChar);
if (fileName.startsWith("/") || fileName.indexOf(":" + File.separator) == 1 || fileName.contains(".." + File.separator)) if (fileName.startsWith("/") || fileName.indexOf(":" + File.separator) == 1 || fileName.contains(".." + File.separator))
@@ -421,12 +435,13 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
if (parent != null) if (parent != null)
{ {
File parentFile = new File(parent); File parentFile = new File(parent);
if (!parentFile.exists()) parentFile.mkdirs(); if (!parentFile.exists())
parentFile.mkdirs();
} }
try (InputStream zis = archive.getInputStream(entry); try (InputStream zis = archive.getInputStream(entry);
InputStream in = new BufferedInputStream(zis, BUFFER_SIZE); InputStream in = new BufferedInputStream(zis, BUFFER_SIZE);
OutputStream out = new BufferedOutputStream(new FileOutputStream(destFileName), BUFFER_SIZE)) OutputStream out = new BufferedOutputStream(new FileOutputStream(destFileName), BUFFER_SIZE))
{ {
final InputStreamStatistics entryStats = (InputStreamStatistics) zis; final InputStreamStatistics entryStats = (InputStreamStatistics) zis;
int count; int count;
@@ -441,7 +456,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
} }
else else
{ {
File newdir = new File(extractDir + entry.getName()); File newdir = new File(extractDir + StringUtils.stripAccents(entry.getName()).replaceAll("\\?", "_"));
newdir.mkdirs(); newdir.mkdirs();
} }
} }
@@ -463,7 +478,8 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
/** /**
* Recursively delete a dir of files and directories * Recursively delete a dir of files and directories
* *
* @param dir directory to delete * @param dir
* directory to delete
*/ */
public static void deleteDir(File dir) public static void deleteDir(File dir)
{ {
@@ -478,8 +494,10 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
{ {
for (File file : files) for (File file : files)
{ {
if (file.isFile()) file.delete(); if (file.isFile())
else deleteDir(file); file.delete();
else
deleteDir(file);
} }
} }
@@ -525,8 +543,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
{ {
void reportProgress(long compressedBytesCount, long uncompressedBytesCount); void reportProgress(long compressedBytesCount, long uncompressedBytesCount);
ExtractionProgressTracker NONE = new ExtractionProgressTracker() ExtractionProgressTracker NONE = new ExtractionProgressTracker() {
{
@Override @Override
public void reportProgress(long compressedBytesCount, long uncompressedBytesCount) public void reportProgress(long compressedBytesCount, long uncompressedBytesCount)
{ {

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited * Copyright (C) 2005 - 2025 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -34,6 +34,10 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.ActionImpl; import org.alfresco.repo.action.ActionImpl;
@@ -44,7 +48,6 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -53,15 +56,13 @@ import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID; import org.alfresco.util.GUID;
import org.alfresco.util.test.junitrules.ApplicationContextInit; import org.alfresco.util.test.junitrules.ApplicationContextInit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
/** /**
* This class contains tests for {@link ImporterActionExecuter}. * This class contains tests for {@link ImporterActionExecuter}.
* *
* @author abalmus * @author abalmus
*/ */
@SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
public class ImporterActionExecuterTest public class ImporterActionExecuterTest
{ {
// Rule to initialise the default Alfresco spring configuration // Rule to initialise the default Alfresco spring configuration
@@ -87,8 +88,7 @@ public class ImporterActionExecuterTest
AuthenticationUtil.setRunAsUserSystem(); AuthenticationUtil.setRunAsUserSystem();
// we need a store // we need a store
storeRef = serviceRegistry.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<StoreRef>() storeRef = serviceRegistry.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<StoreRef>() {
{
public StoreRef execute() public StoreRef execute()
{ {
StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.nanoTime()); StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.nanoTime());
@@ -102,8 +102,7 @@ public class ImporterActionExecuterTest
{ {
try try
{ {
serviceRegistry.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>() serviceRegistry.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>() {
{
public Void execute() public Void execute()
{ {
if (storeRef != null) if (storeRef != null)
@@ -125,8 +124,7 @@ public class ImporterActionExecuterTest
{ {
final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper(); final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper();
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
{
public Void execute() public Void execute()
{ {
NodeRef rootNodeRef = nodeService.getRootNode(storeRef); NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
@@ -162,8 +160,7 @@ public class ImporterActionExecuterTest
} }
/** /**
* MNT-16292: Unzipped files which have folders do not get the cm:titled * MNT-16292: Unzipped files which have folders do not get the cm:titled aspect applied
* aspect applied
* *
* @throws IOException * @throws IOException
*/ */
@@ -172,8 +169,7 @@ public class ImporterActionExecuterTest
{ {
final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper(); final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper();
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
{
public Void execute() public Void execute()
{ {
NodeRef rootNodeRef = nodeService.getRootNode(storeRef); NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
@@ -199,7 +195,7 @@ public class ImporterActionExecuterTest
assertTrue("folder didn't get the cm:titled aspect applied", hasAspectTitled); assertTrue("folder didn't get the cm:titled aspect applied", hasAspectTitled);
// MNT-17017 check ContentModel.PROP_TITLE is not set on the top level folder, just like Share // MNT-17017 check ContentModel.PROP_TITLE is not set on the top level folder, just like Share
String title = (String)nodeService.getProperty(importedFolder, ContentModel.PROP_TITLE); String title = (String) nodeService.getProperty(importedFolder, ContentModel.PROP_TITLE);
assertNull("The title should not have cm:title set", title); assertNull("The title should not have cm:title set", title);
} }
finally finally
@@ -224,8 +220,7 @@ public class ImporterActionExecuterTest
{ {
final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper(); final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper();
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
{
public Void execute() public Void execute()
{ {
NodeRef rootNodeRef = nodeService.getRootNode(storeRef); NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
@@ -270,8 +265,7 @@ public class ImporterActionExecuterTest
{ {
final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper(); final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper();
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
{
public Void execute() public Void execute()
{ {
NodeRef rootNodeRef = nodeService.getRootNode(storeRef); NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
@@ -306,6 +300,46 @@ public class ImporterActionExecuterTest
}); });
} }
@Test
public void testUnzipZipFileHavingAccentCharInFolderName() throws IOException
{
final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper();
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
@Override
public Void execute() throws Throwable
{
NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
// create test data
NodeRef zipFileNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_CONTENT).getChildRef();
NodeRef targetFolderNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_FOLDER).getChildRef();
putContent(zipFileNodeRef, "import-archive-test/accentCharTestZip.zip");
Action action = createAction(zipFileNodeRef, "ImporterActionExecuterTestActionDefinition", targetFolderNodeRef);
try
{
importerActionExecuter.setUncompressedBytesLimit("100000");
importerActionExecuter.execute(action, zipFileNodeRef);
NodeRef importedFolder = nodeService.getChildByName(targetFolderNodeRef, ContentModel.ASSOC_CONTAINS, "accentCharTestZip");
assertNotNull("unzip action failed", importedFolder);
assertTrue("multiple folder structure created", nodeService.getChildAssocs(importedFolder).size() == 1);
}
finally
{
// clean test data
nodeService.deleteNode(targetFolderNodeRef);
nodeService.deleteNode(zipFileNodeRef);
}
return null;
}
});
}
private void putContent(NodeRef zipFileNodeRef, String resource) private void putContent(NodeRef zipFileNodeRef, String resource)
{ {
URL url = AbstractContentTransformerTest.class.getClassLoader().getResource(resource); URL url = AbstractContentTransformerTest.class.getClassLoader().getResource(resource);