From 85a3c71849d10f9f2fe4bcf3ef83b25ef0779cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20=C5=BBurek?= Date: Wed, 29 Sep 2021 10:50:54 +0200 Subject: [PATCH] MNT-22611 - Fix bulk import parameters parsing (#699) --- ...AbstractBulkFileSystemImportWebScript.java | 215 ++++++++++++++- .../copy/BulkFilesystemImportWebScript.java | 179 +------------ .../org/alfresco/AppContext01TestSuite.java | 1 + .../BulkImportParametersExtractorTest.java | 252 ++++++++++++++++++ 4 files changed, 478 insertions(+), 169 deletions(-) create mode 100644 remote-api/src/test/java/org/alfresco/repo/web/scripts/bulkimport/BulkImportParametersExtractorTest.java diff --git a/remote-api/src/main/java/org/alfresco/repo/web/scripts/bulkimport/AbstractBulkFileSystemImportWebScript.java b/remote-api/src/main/java/org/alfresco/repo/web/scripts/bulkimport/AbstractBulkFileSystemImportWebScript.java index 3e98a9d142..08eb24db23 100644 --- a/remote-api/src/main/java/org/alfresco/repo/web/scripts/bulkimport/AbstractBulkFileSystemImportWebScript.java +++ b/remote-api/src/main/java/org/alfresco/repo/web/scripts/bulkimport/AbstractBulkFileSystemImportWebScript.java @@ -30,8 +30,19 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.function.Function; +import java.util.function.Supplier; + +import com.google.common.primitives.Ints; import org.alfresco.repo.bulkimport.BulkFilesystemImporter; +import org.alfresco.repo.bulkimport.BulkImportParameters; +import org.alfresco.repo.bulkimport.NodeImporter; +import org.alfresco.repo.bulkimport.impl.MultiThreadedBulkFilesystemImporter; import org.alfresco.repo.model.Repository; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; @@ -39,8 +50,12 @@ import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.NodeRef; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.I18NUtil; +import org.springframework.extensions.webscripts.Cache; import org.springframework.extensions.webscripts.DeclarativeWebScript; +import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.WebScriptException; +import org.springframework.extensions.webscripts.WebScriptRequest; /** * contains common fields and methods for the import web scripts. @@ -60,10 +75,10 @@ public class AbstractBulkFileSystemImportWebScript extends DeclarativeWebScript // Web scripts parameters (common) protected static final String PARAMETER_REPLACE_EXISTING = "replaceExisting"; protected static final String PARAMETER_EXISTING_FILE_MODE = "existingFileMode"; - protected static final String PARAMETER_VALUE_REPLACE_EXISTING = "replaceExisting"; + protected static final String PARAMETER_VALUE_REPLACE_EXISTING = "true"; protected static final String PARAMETER_SOURCE_DIRECTORY = "sourceDirectory"; protected static final String PARAMETER_DISABLE_RULES = "disableRules"; - protected static final String PARAMETER_VALUE_DISABLE_RULES = "disableRules"; + protected static final String PARAMETER_VALUE_DISABLE_RULES = "true"; protected static final String IMPORT_ALREADY_IN_PROGRESS_MODEL_KEY = "importInProgress"; protected static final String IMPORT_ALREADY_IN_PROGRESS_ERROR_KEY ="bfsit.error.importAlreadyInProgress"; @@ -75,7 +90,7 @@ public class AbstractBulkFileSystemImportWebScript extends DeclarativeWebScript protected Repository repository; protected volatile boolean importInProgress; - + protected NodeRef getTargetNodeRef(String targetNodeRefStr, String targetPath) throws FileNotFoundException { NodeRef targetNodeRef; @@ -219,4 +234,198 @@ public class AbstractBulkFileSystemImportWebScript extends DeclarativeWebScript this.repository = repository; } + protected class MultithreadedImportWebScriptLogic + { + private final MultiThreadedBulkFilesystemImporter bulkImporter; + private final Supplier nodeImporterFactory; + private final WebScriptRequest request; + private final Status status; + private final Cache cache; + + public MultithreadedImportWebScriptLogic(MultiThreadedBulkFilesystemImporter bulkImporter, Supplier nodeImporterFactory, WebScriptRequest request, Status status, Cache cache) + { + this.bulkImporter = Objects.requireNonNull(bulkImporter); + this.nodeImporterFactory = Objects.requireNonNull(nodeImporterFactory); + this.request = Objects.requireNonNull(request); + this.status = Objects.requireNonNull(status); + this.cache = Objects.requireNonNull(cache); + } + + public Map executeImport() + { + Map model = new HashMap<>(); + cache.setNeverCache(true); + String targetPath = null; + + try + { + targetPath = request.getParameter(PARAMETER_TARGET_PATH); + if (isRunning()) + { + model.put(IMPORT_ALREADY_IN_PROGRESS_MODEL_KEY, I18NUtil.getMessage(IMPORT_ALREADY_IN_PROGRESS_ERROR_KEY)); + return model; + } + + final BulkImportParameters bulkImportParameters = getBulkImportParameters(); + final NodeImporter nodeImporter = nodeImporterFactory.get(); + + bulkImporter.asyncBulkImport(bulkImportParameters, nodeImporter); + + waitForImportToBegin(); + + // redirect to the status Web Script + status.setCode(Status.STATUS_MOVED_TEMPORARILY); + status.setRedirect(true); + status.setLocation(request.getServiceContextPath() + WEB_SCRIPT_URI_BULK_FILESYSTEM_IMPORT_STATUS); + } + catch (WebScriptException | IllegalArgumentException e) + { + status.setCode(Status.STATUS_BAD_REQUEST, e.getMessage()); + status.setRedirect(true); + } + catch (FileNotFoundException fnfe) + { + status.setCode(Status.STATUS_BAD_REQUEST,"The repository path '" + targetPath + "' does not exist !"); + status.setRedirect(true); + } + catch (Throwable t) + { + throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, buildTextMessage(t), t); + } + + return model; + } + + private void waitForImportToBegin() throws InterruptedException + { + // ACE-3047 fix, since bulk import is started asynchronously there is a chance that client + // will get into the status page before import is actually started. + // In this case wrong information (for previous import) will be displayed. + // So lets ensure that import started before redirecting client to status page. + int i = 0; + while (!bulkImporter.getStatus().inProgress() && i < 10) + { + Thread.sleep(100); + i++; + } + } + + private BulkImportParameters getBulkImportParameters() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = new BulkImportParametersExtractor(request::getParameter, + AbstractBulkFileSystemImportWebScript.this::getTargetNodeRef, + bulkImporter.getDefaultBatchSize(), + bulkImporter.getDefaultNumThreads()); + return extractor.extract(); + } + + private boolean isRunning() + { + return bulkImporter.getStatus().inProgress(); + } + } + + protected static class BulkImportParametersExtractor + { + private final Function paramsProvider; + private final NodeRefCreator nodeRefCreator; + private final int defaultBatchSize; + private final int defaultNumThreads; + + public BulkImportParametersExtractor(final Function paramsProvider, final NodeRefCreator nodeRefCreator, + final int defaultBatchSize, final int defaultNumThreads) + { + this.paramsProvider = Objects.requireNonNull(paramsProvider); + this.nodeRefCreator = Objects.requireNonNull(nodeRefCreator); + this.defaultBatchSize = defaultBatchSize; + this.defaultNumThreads = defaultNumThreads; + } + + public BulkImportParameters extract() throws FileNotFoundException + { + BulkImportParameters result = new BulkImportParameters(); + + result.setTarget(getTargetNodeRef()); + setExistingFileMode(result); + result.setNumThreads(getOptionalPositiveInteger(PARAMETER_NUM_THREADS).orElse(defaultNumThreads)); + result.setBatchSize(getOptionalPositiveInteger(PARAMETER_BATCH_SIZE).orElse(defaultBatchSize)); + setDisableRules(result); + + return result; + } + + private void setExistingFileMode(BulkImportParameters params) + { + String replaceExistingStr = getParamStringValue(PARAMETER_REPLACE_EXISTING); + String existingFileModeStr = getParamStringValue(PARAMETER_EXISTING_FILE_MODE); + + if (!isNullOrEmpty(replaceExistingStr) && !isNullOrEmpty(existingFileModeStr)) + { + // Check that we haven't had both the deprecated and new (existingFileMode) + // parameters supplied. + throw new IllegalStateException( + String.format("Only one of these parameters may be used, not both: %s, %s", + PARAMETER_REPLACE_EXISTING, + PARAMETER_EXISTING_FILE_MODE)); + } + + if (!isNullOrEmpty(existingFileModeStr)) + { + params.setExistingFileMode(BulkImportParameters.ExistingFileMode.valueOf(existingFileModeStr)); + } + else + { + params.setReplaceExisting(PARAMETER_VALUE_REPLACE_EXISTING.equals(replaceExistingStr)); + } + } + + private void setDisableRules(final BulkImportParameters params) + { + final String disableRulesStr = getParamStringValue(PARAMETER_DISABLE_RULES); + params.setDisableRulesService(!isNullOrEmpty(disableRulesStr) && PARAMETER_VALUE_DISABLE_RULES.equals(disableRulesStr)); + } + + private NodeRef getTargetNodeRef() throws FileNotFoundException + { + String targetNodeRefStr = getParamStringValue(PARAMETER_TARGET_NODEREF); + String targetPath = getParamStringValue(PARAMETER_TARGET_PATH); + return nodeRefCreator.fromNodeRefAndPath(targetNodeRefStr, targetPath); + } + + private OptionalInt getOptionalPositiveInteger(final String paramName) + { + final String strValue = getParamStringValue(paramName); + if (isNullOrEmpty(strValue)) + { + return OptionalInt.empty(); + } + + final Integer asInt = Ints.tryParse(strValue); + if (asInt == null || asInt < 1) + { + throw new WebScriptException("Error: parameter '" + paramName + "' must be an integer > 0."); + } + + return OptionalInt.of(asInt); + } + + private String getParamStringValue(String paramName) + { + Objects.requireNonNull(paramName); + + return paramsProvider.apply(paramName); + } + + private boolean isNullOrEmpty(String str) + { + return str == null || str.trim().length() == 0; + } + + @FunctionalInterface + protected interface NodeRefCreator + { + NodeRef fromNodeRefAndPath(String nodeRef, String path) throws FileNotFoundException; + } + } + } \ No newline at end of file diff --git a/remote-api/src/main/java/org/alfresco/repo/web/scripts/bulkimport/copy/BulkFilesystemImportWebScript.java b/remote-api/src/main/java/org/alfresco/repo/web/scripts/bulkimport/copy/BulkFilesystemImportWebScript.java index ef7461193d..a0b692422a 100644 --- a/remote-api/src/main/java/org/alfresco/repo/web/scripts/bulkimport/copy/BulkFilesystemImportWebScript.java +++ b/remote-api/src/main/java/org/alfresco/repo/web/scripts/bulkimport/copy/BulkFilesystemImportWebScript.java @@ -27,17 +27,12 @@ package org.alfresco.repo.web.scripts.bulkimport.copy; import java.io.File; -import java.util.HashMap; import java.util.Map; -import org.alfresco.repo.bulkimport.BulkImportParameters; import org.alfresco.repo.bulkimport.NodeImporter; import org.alfresco.repo.bulkimport.impl.MultiThreadedBulkFilesystemImporter; import org.alfresco.repo.bulkimport.impl.StreamingNodeImporterFactory; import org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript; -import org.alfresco.service.cmr.model.FileNotFoundException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.springframework.extensions.surf.util.I18NUtil; import org.springframework.extensions.webscripts.Cache; import org.springframework.extensions.webscripts.Status; import org.springframework.extensions.webscripts.WebScriptException; @@ -69,170 +64,22 @@ public class BulkFilesystemImportWebScript extends AbstractBulkFileSystemImportW @Override protected Map executeImpl(final WebScriptRequest request, final Status status, final Cache cache) { - Map model = new HashMap(); - String targetNodeRefStr = null; - String targetPath = null; - String sourceDirectoryStr = null; - @Deprecated String replaceExistingStr = null; - String existingFileModeStr = null; - String batchSizeStr = null; - String numThreadsStr = null; - String disableRulesStr = null; + final MultithreadedImportWebScriptLogic importLogic = new MultithreadedImportWebScriptLogic(bulkImporter, + () -> createNodeImporter(request), request, status, cache); + return importLogic.executeImport(); + } - cache.setNeverCache(true); - - try + private NodeImporter createNodeImporter(WebScriptRequest request) + { + final String sourceDirectoryStr = request.getParameter(PARAMETER_SOURCE_DIRECTORY); + if (sourceDirectoryStr == null || sourceDirectoryStr.trim().length() == 0) { - if(!bulkImporter.getStatus().inProgress()) - { - NodeRef targetNodeRef = null; - File sourceDirectory = null; - boolean replaceExisting = false; - BulkImportParameters.ExistingFileMode existingFileMode = null; - int batchSize = bulkImporter.getDefaultBatchSize(); - int numThreads = bulkImporter.getDefaultNumThreads(); - boolean disableRules = false; - - // Retrieve, validate and convert parameters - targetNodeRefStr = request.getParameter(PARAMETER_TARGET_NODEREF); - targetPath = request.getParameter(PARAMETER_TARGET_PATH); - sourceDirectoryStr = request.getParameter(PARAMETER_SOURCE_DIRECTORY); - replaceExistingStr = request.getParameter(PARAMETER_REPLACE_EXISTING); - existingFileModeStr = request.getParameter(PARAMETER_EXISTING_FILE_MODE); - - batchSizeStr = request.getParameter(PARAMETER_BATCH_SIZE); - numThreadsStr = request.getParameter(PARAMETER_NUM_THREADS); - disableRulesStr = request.getParameter(PARAMETER_DISABLE_RULES); - - targetNodeRef = getTargetNodeRef(targetNodeRefStr, targetPath); - - if (sourceDirectoryStr == null || sourceDirectoryStr.trim().length() == 0) - { - throw new RuntimeException("Error: mandatory parameter '" + PARAMETER_SOURCE_DIRECTORY + "' was not provided."); - } - - sourceDirectory = new File(sourceDirectoryStr.trim()); - - if (replaceExistingStr != null && existingFileModeStr != null) - { - // Check that we haven't had both the deprecated and new (existingFileMode) - // parameters supplied. - throw new IllegalStateException( - String.format("Only one of these parameters may be used, not both: %s, %s", - PARAMETER_REPLACE_EXISTING, - PARAMETER_EXISTING_FILE_MODE)); - } - - if (replaceExistingStr != null && replaceExistingStr.trim().length() > 0) - { - replaceExisting = PARAMETER_VALUE_REPLACE_EXISTING.equals(replaceExistingStr); - } - - if (existingFileModeStr != null && existingFileModeStr.trim().length() > 0) - { - existingFileMode = BulkImportParameters.ExistingFileMode.valueOf(existingFileModeStr); - } - - if (disableRulesStr != null && disableRulesStr.trim().length() > 0) - { - disableRules = PARAMETER_VALUE_DISABLE_RULES.equals(disableRulesStr); - } - - // Initiate the import - NodeImporter nodeImporter = nodeImporterFactory.getNodeImporter(sourceDirectory); - BulkImportParameters bulkImportParameters = new BulkImportParameters(); - - if (numThreadsStr != null && numThreadsStr.trim().length() > 0) - { - try - { - numThreads = Integer.parseInt(numThreadsStr); - if(numThreads < 1) - { - throw new RuntimeException("Error: parameter '" + PARAMETER_NUM_THREADS + "' must be an integer > 0."); - } - bulkImportParameters.setNumThreads(numThreads); - } - catch(NumberFormatException e) - { - throw new RuntimeException("Error: parameter '" + PARAMETER_NUM_THREADS + "' must be an integer > 0."); - } - } - - if (batchSizeStr != null && batchSizeStr.trim().length() > 0) - { - try - { - batchSize = Integer.parseInt(batchSizeStr); - if(batchSize < 1) - { - throw new RuntimeException("Error: parameter '" + PARAMETER_BATCH_SIZE + "' must be an integer > 0."); - } - bulkImportParameters.setBatchSize(batchSize); - } - catch(NumberFormatException e) - { - throw new RuntimeException("Error: parameter '" + PARAMETER_BATCH_SIZE + "' must be an integer > 0."); - } - } - - if (existingFileMode != null) - { - bulkImportParameters.setExistingFileMode(existingFileMode); - } - else - { - // Fall back to the old/deprecated way. - bulkImportParameters.setReplaceExisting(replaceExisting); - } - - bulkImportParameters.setTarget(targetNodeRef); - bulkImportParameters.setDisableRulesService(disableRules); - - bulkImporter.asyncBulkImport(bulkImportParameters, nodeImporter); - - // ACE-3047 fix, since bulk import is started asynchronously there is a chance that client - // will get into the status page before import is actually started. - // In this case wrong information (for previous import) will be displayed. - // So lets ensure that import started before redirecting client to status page. - int i = 0; - while (!bulkImporter.getStatus().inProgress() && i < 10) - { - Thread.sleep(100); - i++; - } - - // redirect to the status Web Script - status.setCode(Status.STATUS_MOVED_TEMPORARILY); - status.setRedirect(true); - status.setLocation(request.getServiceContextPath() + WEB_SCRIPT_URI_BULK_FILESYSTEM_IMPORT_STATUS); - } - else - { - model.put(IMPORT_ALREADY_IN_PROGRESS_MODEL_KEY, I18NUtil.getMessage(IMPORT_ALREADY_IN_PROGRESS_ERROR_KEY)); - } + throw new WebScriptException("Error: mandatory parameter '" + PARAMETER_SOURCE_DIRECTORY + "' was not provided."); } - catch (WebScriptException wse) - { - status.setCode(Status.STATUS_BAD_REQUEST, wse.getMessage()); - status.setRedirect(true); - } - catch (FileNotFoundException fnfe) - { - status.setCode(Status.STATUS_BAD_REQUEST,"The repository path '" + targetPath + "' does not exist !"); - status.setRedirect(true); - } - catch(IllegalArgumentException iae) - { - status.setCode(Status.STATUS_BAD_REQUEST,iae.getMessage()); - status.setRedirect(true); - } - catch (Throwable t) - { - throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, buildTextMessage(t), t); - } - - return model; + + final File sourceDirectory = new File(sourceDirectoryStr.trim()); + + return nodeImporterFactory.getNodeImporter(sourceDirectory); } } diff --git a/remote-api/src/test/java/org/alfresco/AppContext01TestSuite.java b/remote-api/src/test/java/org/alfresco/AppContext01TestSuite.java index 699b999070..5a857d0e9d 100644 --- a/remote-api/src/test/java/org/alfresco/AppContext01TestSuite.java +++ b/remote-api/src/test/java/org/alfresco/AppContext01TestSuite.java @@ -42,6 +42,7 @@ import org.junit.runners.Suite; org.alfresco.rest.api.tests.TestPublicApiAtomPub10TCK.class, org.alfresco.rest.api.tests.TestPublicApiAtomPub11TCK.class, org.alfresco.rest.api.tests.TestPublicApiBrowser11TCK.class, + org.alfresco.repo.web.scripts.bulkimport.BulkImportParametersExtractorTest.class }) public class AppContext01TestSuite { diff --git a/remote-api/src/test/java/org/alfresco/repo/web/scripts/bulkimport/BulkImportParametersExtractorTest.java b/remote-api/src/test/java/org/alfresco/repo/web/scripts/bulkimport/BulkImportParametersExtractorTest.java new file mode 100644 index 0000000000..c01089cf1c --- /dev/null +++ b/remote-api/src/test/java/org/alfresco/repo/web/scripts/bulkimport/BulkImportParametersExtractorTest.java @@ -0,0 +1,252 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2021 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.repo.web.scripts.bulkimport; + +import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_BATCH_SIZE; +import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_DISABLE_RULES; +import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_NUM_THREADS; +import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_TARGET_NODEREF; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Map; + +import org.alfresco.repo.bulkimport.BulkImportParameters; +import org.alfresco.repo.bulkimport.BulkImportParameters.ExistingFileMode; +import org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.BulkImportParametersExtractor; +import org.alfresco.service.cmr.model.FileNotFoundException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.junit.Test; +import org.springframework.extensions.webscripts.WebScriptException; + +public class BulkImportParametersExtractorTest +{ + private static final String TEST_NODE_REF = "workspace://SpacesStore/this-is-just-a-test-ref"; + private static final String TEST_MISSING_NODE_REF = "workspace://SpacesStore/this-is-just-a-not-existing-test-ref"; + private static final Integer DEFAULT_BATCH_SIZE = 1234; + private static final Integer DEFAULT_NUMBER_OF_THREADS = 4321; + + @Test + public void shouldExtractTargetRef() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_NODE_REF)); + + final BulkImportParameters params = extractor.extract(); + + assertNotNull(params); + assertNotNull(params.getTarget()); + assertEquals(TEST_NODE_REF, params.getTarget().toString()); + } + + @Test + public void shouldFallbackToDefaultValues() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_NODE_REF)); + + final BulkImportParameters params = extractor.extract(); + + assertEquals(DEFAULT_BATCH_SIZE, params.getBatchSize()); + assertEquals(DEFAULT_NUMBER_OF_THREADS, params.getNumThreads()); + assertFalse(params.isDisableRulesService()); + assertEquals(ExistingFileMode.SKIP, params.getExistingFileMode()); + assertNull(params.getLoggingInterval()); + } + + @Test + public void shouldExtractDisableFolderRulesFlagWhenSetToTrue() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_NODE_REF, + PARAMETER_DISABLE_RULES, "true" + )); + + final BulkImportParameters params = extractor.extract(); + + assertTrue(params.isDisableRulesService()); + } + + @Test + public void shouldExtractDisableFolderRulesFlagWhenSetToFalse() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_NODE_REF, + PARAMETER_DISABLE_RULES, "false" + )); + + final BulkImportParameters params = extractor.extract(); + + assertFalse(params.isDisableRulesService()); + } + + @Test + public void shouldExtractDisableFolderRulesFlagWhenSetToNotBooleanValue() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_NODE_REF, + PARAMETER_DISABLE_RULES, "unknown" + )); + + final BulkImportParameters params = extractor.extract(); + + assertFalse(params.isDisableRulesService()); + } + + @Test + public void shouldPropagateFileNotFoundExceptionWhenTargetIsNotFound() + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_MISSING_NODE_REF)); + + assertThrows(FileNotFoundException.class, extractor::extract); + } + + @Test + public void shouldExtractValidBatchSize() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_NODE_REF, + PARAMETER_BATCH_SIZE, "1")); + + final BulkImportParameters params = extractor.extract(); + + assertEquals(Integer.valueOf(1), params.getBatchSize()); + } + + @Test + public void shouldFailWithWebScriptExceptionWhenInvalidBatchSizeIsRequested() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_NODE_REF, + PARAMETER_BATCH_SIZE, "not-a-number")); + + try + { + extractor.extract(); + } catch (WebScriptException e) + { + assertNotNull(e.getMessage()); + assertTrue(e.getMessage().contains(PARAMETER_BATCH_SIZE)); + return; + } + + fail("Expected exception to be thrown."); + } + + @Test + public void shouldFailWithWebScriptExceptionWhenNegativeBatchSizeIsRequested() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_NODE_REF, + PARAMETER_BATCH_SIZE, "-1")); + + try + { + extractor.extract(); + } catch (WebScriptException e) + { + assertNotNull(e.getMessage()); + assertTrue(e.getMessage().contains(PARAMETER_BATCH_SIZE)); + return; + } + + fail("Expected exception to be thrown."); + } + + @Test + public void shouldExtractValidNumberOfThreads() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_NODE_REF, + PARAMETER_NUM_THREADS, "1")); + + final BulkImportParameters params = extractor.extract(); + + assertEquals(Integer.valueOf(1), params.getNumThreads()); + } + + @Test + public void shouldFailWithWebScriptExceptionWhenInvalidNumberOfThreadsIsRequested() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_NODE_REF, + PARAMETER_NUM_THREADS, "not-a-number")); + + try + { + extractor.extract(); + } catch (WebScriptException e) + { + assertNotNull(e.getMessage()); + assertTrue(e.getMessage().contains(PARAMETER_NUM_THREADS)); + return; + } + + fail("Expected exception to be thrown."); + } + + @Test + public void shouldFailWithWebScriptExceptionWhenNegativeNumberOfThreadsIsRequested() throws FileNotFoundException + { + final BulkImportParametersExtractor extractor = givenExtractor(Map.of( + PARAMETER_TARGET_NODEREF, TEST_NODE_REF, + PARAMETER_NUM_THREADS, "-1")); + + try + { + extractor.extract(); + } catch (WebScriptException e) + { + assertNotNull(e.getMessage()); + assertTrue(e.getMessage().contains(PARAMETER_NUM_THREADS)); + return; + } + + fail("Expected exception to be thrown."); + } + + private BulkImportParametersExtractor givenExtractor(Map params) + { + + return new BulkImportParametersExtractor(params::get, this::testRefCreator, DEFAULT_BATCH_SIZE, DEFAULT_NUMBER_OF_THREADS); + } + + private NodeRef testRefCreator(String nodeRef, String path) throws FileNotFoundException + { + if (TEST_MISSING_NODE_REF.equals(nodeRef)) + { + throw new FileNotFoundException(new NodeRef(nodeRef)); + } + return new NodeRef(nodeRef); + } + +} \ No newline at end of file