mirror of
				https://github.com/Alfresco/alfresco-community-repo.git
				synced 2025-10-29 15:21:53 +00:00 
			
		
		
		
	Compare commits
	
		
			15 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 3f31e4b1a2 | ||
|  | 787a331869 | ||
|  | 5ce3a3ddd6 | ||
|  | 9ed96ec593 | ||
|  | 03b1fa8b09 | ||
|  | d69f9b52c3 | ||
|  | 72b910bb48 | ||
|  | cfaf3b280b | ||
|  | 00d814ec55 | ||
|  | becabb3a41 | ||
|  | 033157800b | ||
|  | b9c8ff91e4 | ||
|  | c54d46ab67 | ||
|  | dec514c5c2 | ||
|  | 7c5a8a1963 | 
| @@ -7,7 +7,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-community-repo-amps</artifactId> | ||||
|       <version>11.141-SNAPSHOT</version> | ||||
|       <version>12.4</version> | ||||
|    </parent> | ||||
|  | ||||
|    <modules> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-governance-services-community-parent</artifactId> | ||||
|       <version>11.141-SNAPSHOT</version> | ||||
|       <version>12.4</version> | ||||
|    </parent> | ||||
|  | ||||
|    <modules> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-governance-services-automation-community-repo</artifactId> | ||||
|       <version>11.141-SNAPSHOT</version> | ||||
|       <version>12.4</version> | ||||
|    </parent> | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -619,11 +619,27 @@ public class BaseRMRestTest extends RestTest | ||||
|      * @return | ||||
|      */ | ||||
|     public List<String> searchForContentAsUser(UserModel user, String term) | ||||
|     { | ||||
|         String query = "cm:name:*" + term + "*"; | ||||
|         return searchForContentAsUser(user,query,"afts"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns search results for the given search term | ||||
|      * | ||||
|      * @param user | ||||
|      * @param term | ||||
|      * @param query language | ||||
|      * @return | ||||
|      * @throws Exception | ||||
|      */ | ||||
|     public List<String> searchForContentAsUser(UserModel user, String q, String queryLanguage) | ||||
|     { | ||||
|         getRestAPIFactory().getRmRestWrapper().authenticateUser(user); | ||||
|         RestRequestQueryModel queryReq = new RestRequestQueryModel(); | ||||
|         SearchRequest query = new SearchRequest(queryReq); | ||||
|         queryReq.setQuery("cm:name:*" + term + "*"); | ||||
|         queryReq.setQuery(q); | ||||
|         queryReq.setLanguage(queryLanguage); | ||||
|  | ||||
|         List<String> names = new ArrayList<>(); | ||||
|         // wait for solr indexing | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-governance-services-community-parent</artifactId> | ||||
|       <version>11.141-SNAPSHOT</version> | ||||
|       <version>12.4</version> | ||||
|    </parent> | ||||
|  | ||||
|    <modules> | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-governance-services-community-repo-parent</artifactId> | ||||
|       <version>11.141-SNAPSHOT</version> | ||||
|       <version>12.4</version> | ||||
|    </parent> | ||||
|  | ||||
|    <properties> | ||||
|   | ||||
| @@ -306,7 +306,7 @@ public class RMAfterInvocationProvider extends RMSecurityCommon | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private boolean isUnfiltered(NodeRef nodeRef) | ||||
|     protected boolean isUnfiltered(NodeRef nodeRef) | ||||
|     { | ||||
|         return !nodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT); | ||||
|  | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-governance-services-community-repo-parent</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <build> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <modules> | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-amps</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <properties> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-community-repo</artifactId> | ||||
|       <version>11.141-SNAPSHOT</version> | ||||
|       <version>12.4</version> | ||||
|    </parent> | ||||
|  | ||||
|    <dependencies> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <properties> | ||||
|   | ||||
| @@ -9,6 +9,6 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-packaging</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
| </project> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-packaging</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <properties> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <modules> | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-packaging</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <modules> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-tests</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <developers> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-tests</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <developers> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-tests</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <developers> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-tests</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <developers> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-tests</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <developers> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-packaging</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <properties> | ||||
|   | ||||
							
								
								
									
										6
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <artifactId>alfresco-community-repo</artifactId> | ||||
|     <version>11.141-SNAPSHOT</version> | ||||
|     <version>12.4</version> | ||||
|     <packaging>pom</packaging> | ||||
|     <name>Alfresco Community Repo Parent</name> | ||||
|  | ||||
| @@ -24,7 +24,7 @@ | ||||
|     <properties> | ||||
|         <acs.version.major>7</acs.version.major> | ||||
|         <acs.version.minor>1</acs.version.minor> | ||||
|         <acs.version.revision>0</acs.version.revision> | ||||
|         <acs.version.revision>1</acs.version.revision> | ||||
|         <acs.version.label /> | ||||
|         <amp.min.version>${acs.version.major}.0.0</amp.min.version> | ||||
|  | ||||
| @@ -142,7 +142,7 @@ | ||||
|         <connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection> | ||||
|         <developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection> | ||||
|         <url>https://github.com/Alfresco/alfresco-community-repo</url> | ||||
|         <tag>HEAD</tag> | ||||
|         <tag>12.4</tag> | ||||
|     </scm> | ||||
|  | ||||
|     <distributionManagement> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <dependencies> | ||||
|   | ||||
| @@ -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<NodeImporter> nodeImporterFactory; | ||||
| 		private final WebScriptRequest request; | ||||
| 		private final Status status; | ||||
| 		private final Cache cache; | ||||
|  | ||||
| 		public MultithreadedImportWebScriptLogic(MultiThreadedBulkFilesystemImporter bulkImporter, Supplier<NodeImporter> 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<String, Object> executeImport() | ||||
| 		{ | ||||
| 			Map<String, Object> 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<String, String> paramsProvider; | ||||
| 		private final NodeRefCreator nodeRefCreator; | ||||
| 		private final int defaultBatchSize; | ||||
| 		private final int defaultNumThreads; | ||||
|  | ||||
| 		public BulkImportParametersExtractor(final Function<String, String> 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; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -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<String, Object> executeImpl(final WebScriptRequest request, final Status status, final Cache cache) | ||||
|     { | ||||
|         Map<String, Object> model  = new HashMap<String, Object>(); | ||||
|         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); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1070,7 +1070,7 @@ | ||||
|         <property name="enabled" value="${system.api.discovery.enabled}" /> | ||||
|         <property name="thumbnailService" ref="ThumbnailService" /> | ||||
|         <property name="restApiDirectUrlConfig" ref="restApiDirectUrlConfig" /> | ||||
|         <property name="contentService" ref="ContentService" /> | ||||
|         <property name="contentService" ref="contentService" /> | ||||
|     </bean> | ||||
|  | ||||
|     <bean id="org.alfresco.rest.api.probes.ProbeEntityResource.get" class="org.alfresco.rest.api.probes.ProbeEntityResource"> | ||||
|   | ||||
| @@ -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 | ||||
| { | ||||
|   | ||||
| @@ -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 <http://www.gnu.org/licenses/>. | ||||
|  * #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<String, String> 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); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo</artifactId> | ||||
|         <version>11.141-SNAPSHOT</version> | ||||
|         <version>12.4</version> | ||||
|     </parent> | ||||
|  | ||||
|     <dependencies> | ||||
|   | ||||
| @@ -1,30 +1,33 @@ | ||||
| /* | ||||
|  * #%L | ||||
|  * Alfresco Repository | ||||
|  * %% | ||||
|  * Copyright (C) 2005 - 2016 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 <http://www.gnu.org/licenses/>. | ||||
|  * #L% | ||||
|  */ | ||||
| /* | ||||
|  * #%L | ||||
|  * Alfresco Repository | ||||
|  * %% | ||||
|  * 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 <http://www.gnu.org/licenses/>. | ||||
|  * #L% | ||||
|  */ | ||||
| package org.alfresco.repo.security.permissions.impl.acegi; | ||||
|  | ||||
| import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.getNodeRef; | ||||
| import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.shouldAbstainOrDeny; | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.lang.reflect.Method; | ||||
| import java.util.ArrayList; | ||||
| @@ -46,8 +49,6 @@ import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; | ||||
| import org.alfresco.service.cmr.repository.ChildAssociationRef; | ||||
| import org.alfresco.service.cmr.repository.NodeRef; | ||||
| import org.alfresco.service.cmr.repository.NodeService; | ||||
| import org.alfresco.service.cmr.repository.StoreRef; | ||||
| import org.alfresco.service.cmr.security.AccessStatus; | ||||
| import org.alfresco.service.cmr.security.AuthenticationService; | ||||
| import org.alfresco.service.cmr.security.AuthorityService; | ||||
| import org.alfresco.service.cmr.security.OwnableService; | ||||
| @@ -59,6 +60,7 @@ import org.apache.commons.logging.Log; | ||||
| import org.apache.commons.logging.LogFactory; | ||||
| import org.springframework.beans.factory.InitializingBean; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * @author andyh | ||||
|  */ | ||||
| @@ -395,61 +397,53 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean | ||||
|                 { | ||||
|                     throw new ACLEntryVoterException("The specified parameter is not a NodeRef or ChildAssociationRef"); | ||||
|                 } | ||||
|                 else if (StoreRef.class.isAssignableFrom(params[cad.parameter[0]])) | ||||
|  | ||||
|                 if (List.class.isAssignableFrom(params[cad.parameter[0]])) | ||||
|                 { | ||||
|                     StoreRef storeRef = getArgument(invocation, cad.parameter[0]); | ||||
|                     if (storeRef != null) | ||||
|                     List<?> listArgument = getArgument(invocation, cad.parameter[0]); | ||||
|                     if (listArgument != null) | ||||
|                     { | ||||
|                         if (log.isDebugEnabled()) | ||||
|                         NodeRef listNodeRef; | ||||
|                         Integer accessAbstainOrDeny = null; | ||||
|                         for (Object listElement : listArgument) | ||||
|                         { | ||||
|                             log.debug("\tPermission test against the store - using permissions on the root node"); | ||||
|                         } | ||||
|                         if (nodeService.exists(storeRef)) | ||||
|                         { | ||||
|                             testNodeRef = nodeService.getRootNode(storeRef); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 else if (NodeRef.class.isAssignableFrom(params[cad.parameter[0]])) | ||||
|                 { | ||||
|                     testNodeRef = getArgument(invocation, cad.parameter[0]); | ||||
|                     if (log.isDebugEnabled()) | ||||
|                     { | ||||
|                         if (testNodeRef != null) | ||||
|                         { | ||||
|                             if (nodeService.exists(testNodeRef)) | ||||
|                             listNodeRef = getNodeRef(listElement, nodeService); | ||||
|                             Integer currentValue = shouldAbstainOrDeny(cad.required, listNodeRef, abstainForClassQNames, nodeService, permissionService); | ||||
|  | ||||
|                             if (currentValue != null) | ||||
|                             { | ||||
|                                 log.debug("\tPermission test on node " + nodeService.getPath(testNodeRef)); | ||||
|                                 if (currentValue == AccessDecisionVoter.ACCESS_DENIED) | ||||
|                                 { | ||||
|                                     return AccessDecisionVoter.ACCESS_DENIED; | ||||
|                                 } | ||||
|                                 else | ||||
|                                 { | ||||
|                                     accessAbstainOrDeny = currentValue; | ||||
|                                 } | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 log.debug("\tPermission test on non-existing node " +testNodeRef); | ||||
|                             }  | ||||
|  | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 else if (ChildAssociationRef.class.isAssignableFrom(params[cad.parameter[0]])) | ||||
|                 { | ||||
|                     ChildAssociationRef testChildRef = getArgument(invocation, cad.parameter[0]); | ||||
|                     if (testChildRef != null) | ||||
|                     { | ||||
|                         testNodeRef = testChildRef.getChildRef(); | ||||
|                         if (log.isDebugEnabled()) | ||||
|  | ||||
|                         if (accessAbstainOrDeny != null) | ||||
|                         { | ||||
|                             if (nodeService.exists(testNodeRef)) | ||||
|                             { | ||||
|                                 log.debug("\tPermission test on node " + nodeService.getPath(testNodeRef)); | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 log.debug("\tPermission test on non-existing node " + testNodeRef); | ||||
|                             } | ||||
|                             return accessAbstainOrDeny; | ||||
|                         } | ||||
|                         if((hasMethodEntry == null) || (hasMethodEntry.booleanValue())) | ||||
|                         { | ||||
|                             return AccessDecisionVoter.ACCESS_GRANTED; | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             return AccessDecisionVoter.ACCESS_DENIED; | ||||
|                         } | ||||
|  | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     throw new ACLEntryVoterException("The specified parameter is not a NodeRef or ChildAssociationRef"); | ||||
|                     Object testObject = getArgument(invocation, cad.parameter[0]); | ||||
|                     //If the execution reaches here, then testNodeRef is always null | ||||
|                     testNodeRef = getNodeRef(testObject, nodeService); | ||||
|                 } | ||||
|             } | ||||
|             else if (cad.typeString.equals(ACL_ITEM)) | ||||
| @@ -584,44 +578,10 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (testNodeRef != null) | ||||
|             Integer accessAbstainOrDeny = shouldAbstainOrDeny(cad.required, testNodeRef, abstainForClassQNames, nodeService, permissionService); | ||||
|             if (accessAbstainOrDeny != null) | ||||
|             { | ||||
|                 // now we know the node - we can abstain for certain types and aspects (eg. RM) | ||||
|                 if(abstainForClassQNames.size() > 0) | ||||
|                 { | ||||
|                     // check node exists | ||||
|                     if (nodeService.exists(testNodeRef)) | ||||
|                     { | ||||
|                         QName typeQName = nodeService.getType(testNodeRef); | ||||
|                         if(abstainForClassQNames.contains(typeQName)) | ||||
|                         { | ||||
|                             return AccessDecisionVoter.ACCESS_ABSTAIN; | ||||
|                         } | ||||
|                         | ||||
|                         Set<QName> aspectQNames = nodeService.getAspects(testNodeRef); | ||||
|                         for(QName abstain : abstainForClassQNames) | ||||
|                         { | ||||
|                             if(aspectQNames.contains(abstain)) | ||||
|                             { | ||||
|                                 return AccessDecisionVoter.ACCESS_ABSTAIN; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|                 if (log.isDebugEnabled()) | ||||
|                 { | ||||
|                     log.debug("\t\tNode ref is not null"); | ||||
|                 } | ||||
|                 if (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED) | ||||
|                 { | ||||
|                     if (log.isDebugEnabled()) | ||||
|                     { | ||||
|                         log.debug("\t\tPermission is denied"); | ||||
|                         Thread.dumpStack(); | ||||
|                     } | ||||
|                     return AccessDecisionVoter.ACCESS_DENIED; | ||||
|                 } | ||||
|                 return accessAbstainOrDeny; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,175 @@ | ||||
| /* | ||||
|  * #%L | ||||
|  * Alfresco Repository | ||||
|  * %% | ||||
|  * 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 <http://www.gnu.org/licenses/>. | ||||
|  * #L% | ||||
|  */ | ||||
| package org.alfresco.repo.security.permissions.impl.acegi; | ||||
|  | ||||
| import java.util.Set; | ||||
|  | ||||
| import net.sf.acegisecurity.vote.AccessDecisionVoter; | ||||
| import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; | ||||
| import org.alfresco.service.cmr.repository.ChildAssociationRef; | ||||
| import org.alfresco.service.cmr.repository.NodeRef; | ||||
| import org.alfresco.service.cmr.repository.NodeService; | ||||
| import org.alfresco.service.cmr.repository.StoreRef; | ||||
| import org.alfresco.service.cmr.security.AccessStatus; | ||||
| import org.alfresco.service.cmr.security.PermissionService; | ||||
| import org.alfresco.service.namespace.QName; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Utility methods extracted from AclEntryVoter | ||||
|  * | ||||
|  * @author Lev Belava | ||||
|  */ | ||||
| final class ACLEntryVoterUtils | ||||
| { | ||||
|     private static final Logger LOG = LoggerFactory.getLogger(ACLEntryVoterUtils.class); | ||||
|  | ||||
|     private ACLEntryVoterUtils() | ||||
|     { | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Gets NodeRef for testObject based on inferred type | ||||
|      * | ||||
|      * @param testObject                Tested object to work on | ||||
|      * @param nodeService               Node service to perform checks on refs | ||||
|      * @return                          NodeRef for testObject or null if (testObject is null or StoreRef from testObject does not exist in the provided NodeService) | ||||
|      * @throws ACLEntryVoterException   if testObject is not null and not one of a NodeRef or ChildAssociationRef types | ||||
|      */ | ||||
|     static NodeRef getNodeRef(Object testObject, NodeService nodeService) | ||||
|     { | ||||
|         if (testObject == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         if (StoreRef.class.isAssignableFrom(testObject.getClass())) | ||||
|         { | ||||
|             LOG.debug("Permission test against the store - using permissions on the root node"); | ||||
|             StoreRef storeRef = (StoreRef) testObject; | ||||
|             if (nodeService.exists(storeRef)) | ||||
|             { | ||||
|                 return nodeService.getRootNode(storeRef); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 LOG.debug("StoreRef does not exist"); | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (NodeRef.class.isAssignableFrom(testObject.getClass())) | ||||
|         { | ||||
|             NodeRef result = (NodeRef) testObject; | ||||
|             if (LOG.isDebugEnabled()) | ||||
|             { | ||||
|                 if (nodeService.exists(result)) | ||||
|                 { | ||||
|                     LOG.debug("Permission test on node {}", nodeService.getPath(result)); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     LOG.debug("Permission test on non-existing node {}", result); | ||||
|                 } | ||||
|             } | ||||
|             return result; | ||||
|         } | ||||
|  | ||||
|         if (ChildAssociationRef.class.isAssignableFrom(testObject.getClass())) | ||||
|         { | ||||
|             ChildAssociationRef testChildRef = (ChildAssociationRef) testObject; | ||||
|             NodeRef result = testChildRef.getChildRef(); | ||||
|             if (LOG.isDebugEnabled()) | ||||
|             { | ||||
|                 if (nodeService.exists(result)) | ||||
|                 { | ||||
|                     LOG.debug("Permission test on node {}", nodeService.getPath(result)); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     LOG.debug("Permission test on non-existing node {}", result); | ||||
|                 } | ||||
|             } | ||||
|             return result; | ||||
|         } | ||||
|  | ||||
|         throw new ACLEntryVoterException("The specified parameter is not a NodeRef or ChildAssociationRef"); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Checks if tested NodeRef instance is abstained or denied based on set of QNames to abstain and | ||||
|      * | ||||
|      * @param requiredPermissionReference           Required permissions | ||||
|      * @param testNodeRef                           NodeRef to be verified | ||||
|      * @param abstainForClassQNames                 Set of QNames to abstain | ||||
|      * @param nodeService                           Node service to perform checks on tested NodeRef | ||||
|      * @param permissionService                     Permission service to check for required permissions | ||||
|      * @return                                      null if testNodeRef is not abstained or denied, otherwise returns appropriate status. | ||||
|      */ | ||||
|     static Integer shouldAbstainOrDeny(SimplePermissionReference requiredPermissionReference, NodeRef testNodeRef, Set<QName> abstainForClassQNames, | ||||
|                                         NodeService nodeService, PermissionService permissionService) | ||||
|     { | ||||
|         if (testNodeRef == null) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         LOG.debug("Node ref is not null"); | ||||
|  | ||||
|         if (abstainForClassQNames.size() > 0 && nodeService.exists(testNodeRef)) | ||||
|         { | ||||
|             if (abstainForClassQNames.contains(nodeService.getType(testNodeRef))) | ||||
|             { | ||||
|                 return AccessDecisionVoter.ACCESS_ABSTAIN; | ||||
|             } | ||||
|             Set<QName> testNodeRefAspects = nodeService.getAspects(testNodeRef); | ||||
|             for (QName abstain : abstainForClassQNames) | ||||
|             { | ||||
|                 if (testNodeRefAspects.contains(abstain)) | ||||
|                 { | ||||
|                     return AccessDecisionVoter.ACCESS_ABSTAIN; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (AccessStatus.DENIED == permissionService.hasPermission(testNodeRef, requiredPermissionReference.toString())) | ||||
|         { | ||||
|             if (LOG.isDebugEnabled()) | ||||
|             { | ||||
|                 LOG.debug("Permission is denied"); | ||||
|                 Thread.dumpStack(); | ||||
|             } | ||||
|             return AccessDecisionVoter.ACCESS_DENIED; | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -3,7 +3,7 @@ | ||||
| repository.name=Main Repository | ||||
|  | ||||
| # Schema number | ||||
| version.schema=15002 | ||||
| version.schema=15100 | ||||
|  | ||||
| # Directory configuration | ||||
|  | ||||
|   | ||||
| @@ -209,6 +209,7 @@ import org.junit.runners.Suite; | ||||
|     org.alfresco.repo.security.authentication.AuthorizationTest.class, | ||||
|     org.alfresco.repo.security.permissions.PermissionCheckedCollectionTest.class, | ||||
|     org.alfresco.repo.security.permissions.impl.acegi.FilteringResultSetTest.class, | ||||
|     org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtilsTest.class, | ||||
|     org.alfresco.repo.security.authentication.ChainingAuthenticationServiceTest.class, | ||||
|     org.alfresco.repo.security.authentication.NameBasedUserNameGeneratorTest.class, | ||||
|     org.alfresco.repo.version.common.VersionImplTest.class, | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  * #%L | ||||
|  * Alfresco Repository | ||||
|  * %% | ||||
|  * Copyright (C) 2005 - 2016 Alfresco Software Limited | ||||
|  * 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  | ||||
| @@ -96,6 +96,8 @@ public abstract class AbstractPermissionTest extends TestCase | ||||
|  | ||||
|     protected NodeRef systemNodeRef; | ||||
|  | ||||
|     protected NodeRef abstainedNode; | ||||
|  | ||||
|     protected AuthenticationComponent authenticationComponent; | ||||
|  | ||||
|     protected ModelDAO permissionModelDAO; | ||||
| @@ -186,6 +188,8 @@ public abstract class AbstractPermissionTest extends TestCase | ||||
|         props = createPersonProperties(USER2_LEMUR); | ||||
|         nodeService.createNode(typesNodeRef, children, ContentModel.TYPE_PERSON, container, props).getChildRef(); | ||||
|  | ||||
|         abstainedNode= nodeService.createNode(rootNodeRef, ContentModel.ASSOC_FAILED_THUMBNAIL, system, ContentModel.TYPE_FAILED_THUMBNAIL).getChildRef(); | ||||
|  | ||||
|         // create an authentication object e.g. the user | ||||
|         if(authenticationDAO.userExists(USER1_ANDY)) | ||||
|         { | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,181 @@ | ||||
| /* | ||||
|  * #%L | ||||
|  * Alfresco Repository | ||||
|  * %% | ||||
|  * 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 <http://www.gnu.org/licenses/>. | ||||
|  * #L% | ||||
|  */ | ||||
| package org.alfresco.repo.security.permissions.impl.acegi; | ||||
|  | ||||
| import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.getNodeRef; | ||||
| import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.shouldAbstainOrDeny; | ||||
| import static org.hamcrest.CoreMatchers.is; | ||||
| import static org.hamcrest.CoreMatchers.nullValue; | ||||
| import static org.hamcrest.MatcherAssert.assertThat; | ||||
| import static org.mockito.ArgumentMatchers.eq; | ||||
| import static org.mockito.ArgumentMatchers.nullable; | ||||
| import static org.mockito.Mockito.when; | ||||
|  | ||||
| import java.util.Collections; | ||||
| import java.util.Set; | ||||
|  | ||||
| import net.sf.acegisecurity.vote.AccessDecisionVoter; | ||||
| import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; | ||||
| import org.alfresco.service.cmr.repository.ChildAssociationRef; | ||||
| import org.alfresco.service.cmr.repository.NodeRef; | ||||
| import org.alfresco.service.cmr.repository.NodeService; | ||||
| import org.alfresco.service.cmr.repository.StoreRef; | ||||
| import org.alfresco.service.cmr.security.AccessStatus; | ||||
| import org.alfresco.service.cmr.security.PermissionService; | ||||
| import org.alfresco.service.namespace.QName; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| import org.mockito.Mock; | ||||
| import org.mockito.junit.MockitoJUnitRunner; | ||||
|  | ||||
|  | ||||
| @RunWith(MockitoJUnitRunner.class) | ||||
| public class ACLEntryVoterUtilsTest | ||||
| { | ||||
|     private final NodeRef testNodeRef = new NodeRef("workspace://testNodeRef/testNodeRef"); | ||||
|     private final NodeRef rootNodeRef = new NodeRef("workspace://rootNodeRef/rootNodeRef"); | ||||
|     private final NodeRef refNodeForTestObject = new NodeRef("workspace://refNodeForTestObject/refNodeForTestObject"); | ||||
|     private final NodeRef childRefNode = new NodeRef("workspace://childRefNode/childRefNode"); | ||||
|     private final StoreRef testStoreNodeRef = new StoreRef("system://testStoreRefMock/testStoreRefMock"); | ||||
|     private final SimplePermissionReference simplePermissionReference = SimplePermissionReference.getPermissionReference(QName.createQName("uri", "local"), "Write"); | ||||
|     private final QName qNameToAbstain1 = QName.createQName("{test}testnode1"); | ||||
|     private final QName qNameToAbstain2 = QName.createQName("{test}testnode2"); | ||||
|     private final QName qNameToAbstain3 = QName.createQName("{test}testnode3"); | ||||
|     private final QName qNameNotFromTheAbstainSet = QName.createQName("{test}testnodeAbstain"); | ||||
|     private final Set<QName> qNamesToAbstain = Set.of(qNameToAbstain1, qNameToAbstain2, qNameToAbstain3); | ||||
|     @Mock | ||||
|     private PermissionService permissionServiceMock; | ||||
|     @Mock | ||||
|     private NodeService nodeServiceMock; | ||||
|     @Mock | ||||
|     private ChildAssociationRef childAssocRefMock; | ||||
|  | ||||
|     @Before | ||||
|     public void setUp() | ||||
|     { | ||||
|         when(nodeServiceMock.exists(testStoreNodeRef)).thenReturn(Boolean.TRUE); | ||||
|         when(nodeServiceMock.exists(testNodeRef)).thenReturn(Boolean.TRUE); | ||||
|         when(nodeServiceMock.getRootNode(testStoreNodeRef)).thenReturn(rootNodeRef); | ||||
|         when(nodeServiceMock.getType(testNodeRef)).thenReturn(qNameNotFromTheAbstainSet); | ||||
|         when(nodeServiceMock.getAspects(testNodeRef)).thenReturn(Set.of(qNameNotFromTheAbstainSet)); | ||||
|         when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.DENIED); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsAccessDeniedFromPermissionService() | ||||
|     { | ||||
|         assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock), | ||||
|                    is(AccessDecisionVoter.ACCESS_DENIED)); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsNullOnNullTestObject() | ||||
|     { | ||||
|         assertThat(getNodeRef(null, nodeServiceMock), is(nullValue())); | ||||
|     } | ||||
|  | ||||
|     @Test(expected = ACLEntryVoterException.class) | ||||
|     public void throwsExceptionWhenParameterIsNotNodeRefOrChildAssociationRef() | ||||
|     { | ||||
|         getNodeRef("TEST", nodeServiceMock); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsGivenTestNodeRefWhenStoreRefDoesNotExist() | ||||
|     { | ||||
|         when(nodeServiceMock.exists(testStoreNodeRef)).thenReturn(Boolean.FALSE); | ||||
|         assertThat(getNodeRef(testStoreNodeRef, nodeServiceMock), is(nullValue())); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsRootNode() | ||||
|     { | ||||
|         assertThat(getNodeRef(testStoreNodeRef, nodeServiceMock), is(rootNodeRef)); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsNodeRefFromTestObject() | ||||
|     { | ||||
|         assertThat(getNodeRef(refNodeForTestObject, nodeServiceMock), is(refNodeForTestObject)); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsChildRefFromChildAssocRef() | ||||
|     { | ||||
|         when(childAssocRefMock.getChildRef()).thenReturn(childRefNode); | ||||
|         assertThat(getNodeRef(childAssocRefMock, nodeServiceMock), is(childRefNode)); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsNullOnNullTestNodeRef() | ||||
|     { | ||||
|         assertThat(shouldAbstainOrDeny(simplePermissionReference, null, qNamesToAbstain, nodeServiceMock, permissionServiceMock), | ||||
|                    is(nullValue())); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsNullOnAbstainClassQnamesIsEmptyAndThereAreNoDeniedPermissions() | ||||
|     { | ||||
|         when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.ALLOWED); | ||||
|         assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, Collections.emptySet(), nodeServiceMock, permissionServiceMock), | ||||
|                    is(nullValue())); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsNullOnTestNodeRefDoesNotExistAndThereAreNoDeniedPermissions() | ||||
|     { | ||||
|         when(nodeServiceMock.exists(testNodeRef)).thenReturn(Boolean.FALSE); | ||||
|         when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.ALLOWED); | ||||
|         assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock), | ||||
|                    is(nullValue())); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsNullOnNodeTypeAndNodeAspectsAreNotInSetToAbstainAndThereAreNoDeniedPermissions() | ||||
|     { | ||||
|         when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.ALLOWED); | ||||
|         assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock), | ||||
|                    is(nullValue())); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsAbstainWhenNodeRefTypeIsInSetToAbstain() | ||||
|     { | ||||
|         when(nodeServiceMock.getType(testNodeRef)).thenReturn(qNameToAbstain2); | ||||
|         assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock), | ||||
|                    is(AccessDecisionVoter.ACCESS_ABSTAIN)); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void returnsAbstainWhenAtLeastOneAspectIsInSetToAbstain() | ||||
|     { | ||||
|         when(nodeServiceMock.getAspects(testNodeRef)).thenReturn(Set.of(qNameNotFromTheAbstainSet, qNameToAbstain3)); | ||||
|         assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock), | ||||
|                    is(AccessDecisionVoter.ACCESS_ABSTAIN)); | ||||
|     } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user