diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml
index 7a31fd1b76..da41dd3d0e 100644
--- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml
+++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-webscript-context.xml
@@ -585,6 +585,19 @@
+
+
+
+
+
+
+
+
+
+
+
+ Get webscript for removing dynamic authorities from RM
+ Gets the result after removing dynamic authorities from RM.
+ /api/rm/rm-dynamicauthorities?batchsize={batchsize}
+ argument
+ user
+ required
+
\ No newline at end of file
diff --git a/rm-server/config/alfresco/templates/webscripts/org/alfresco/repository/roles/rm-dynamicauthorities.get.json.ftl b/rm-server/config/alfresco/templates/webscripts/org/alfresco/repository/roles/rm-dynamicauthorities.get.json.ftl
new file mode 100644
index 0000000000..10971542cb
--- /dev/null
+++ b/rm-server/config/alfresco/templates/webscripts/org/alfresco/repository/roles/rm-dynamicauthorities.get.json.ftl
@@ -0,0 +1,4 @@
+{
+ "responsestatus" : "${responsestatus?json_string}",
+ "message" : "${message?json_string}"
+}
\ No newline at end of file
diff --git a/rm-server/source/java/org/alfresco/repo/web/scripts/roles/DynamicAuthoritiesGet.java b/rm-server/source/java/org/alfresco/repo/web/scripts/roles/DynamicAuthoritiesGet.java
new file mode 100644
index 0000000000..67e77045c9
--- /dev/null
+++ b/rm-server/source/java/org/alfresco/repo/web/scripts/roles/DynamicAuthoritiesGet.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2005-2014 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * 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 .
+ */
+package org.alfresco.repo.web.scripts.roles;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
+import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
+import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
+import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
+import org.alfresco.repo.domain.node.NodeDAO;
+import org.alfresco.repo.domain.patch.PatchDAO;
+import org.alfresco.repo.domain.qname.QNameDAO;
+import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.service.transaction.TransactionService;
+import org.alfresco.util.Pair;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.extensions.webscripts.Cache;
+import org.springframework.extensions.webscripts.DeclarativeWebScript;
+import org.springframework.extensions.webscripts.Status;
+import org.springframework.extensions.webscripts.WebScriptRequest;
+
+/**
+ * Webscript used for removing dynamic authorities from the records.
+ *
+ * @author Silviu Dinuta
+ * @since 2.3.0.7
+ */
+@SuppressWarnings("deprecation")
+public class DynamicAuthoritiesGet extends DeclarativeWebScript implements RecordsManagementModel
+{
+
+ private static final String MESSAGE_PROCESSING_BEGIN = "Processing - BEGIN";
+ private static final String MESSAGE_PROCESSING_END = "Processing - END";
+ private static final String MESSAGE_PROCESSING_RECORD_END_TEMPLATE = "Processing record {0} - END";
+ private static final String MESSAGE_PROCESSING_RECORD_BEGIN_TEMPLATE = "Processing record {0} - BEGIN";
+ private static final String MESSAGE_BATCHSIZE_IS_INVALID = "Parameter batchsize is invalid.";
+ private static final String MESSAGE_BATCHSIZE_IS_MANDATORY = "Parameter batchsize is mandatory";
+ private static final String SUCCESS_STATUS = "success";
+ private static final String FAILED_STATUS = "failed";
+ /**
+ * The logger
+ */
+ private static Log logger = LogFactory.getLog(DynamicAuthoritiesGet.class);
+ private static final String BATCH_SIZE = "batchsize";
+ private static final String TOTAL_NUMBER_TO_PROCESS = "maxProcessedRecords";
+ private static final String MODEL_STATUS = "responsestatus";
+ private static final String MODEL_MESSAGE = "message";
+ private static final String MESSAGE_ALL_TEMPLATE = "Processed {0} records.";
+ private static final String MESSAGE_PARTIAL_TEMPLATE = "Processed first {0} records.";
+ private static final String MESSAGE_NO_RECORDS_TO_PROCESS = "There where no records to be processed.";
+
+
+ /** services */
+ private PatchDAO patchDAO;
+ private NodeDAO nodeDAO;
+ private QNameDAO qnameDAO;
+ private NodeService nodeService;
+ private PermissionService permissionService;
+ private ExtendedSecurityService extendedSecurityService;
+ private TransactionService transactionService;
+
+ /** service setters */
+ public void setPatchDAO(PatchDAO patchDAO) { this.patchDAO = patchDAO; }
+ public void setNodeDAO(NodeDAO nodeDAO) { this.nodeDAO = nodeDAO; }
+ public void setQnameDAO(QNameDAO qnameDAO) { this.qnameDAO = qnameDAO; }
+ public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; }
+ public void setPermissionService(PermissionService permissionService) { this.permissionService = permissionService; }
+ public void setExtendedSecurityService(ExtendedSecurityService extendedSecurityService) { this.extendedSecurityService = extendedSecurityService; }
+ public void setTransactionService(TransactionService transactionService) { this.transactionService = transactionService; }
+
+ @Override
+ protected Map executeImpl(WebScriptRequest req, Status status, Cache cache)
+ {
+ Map model = new HashMap();
+ String batchSizeStr = req.getParameter(BATCH_SIZE);
+ String totalToBeProcessedRecordsStr = req.getParameter(TOTAL_NUMBER_TO_PROCESS);
+
+ Long size = 0L;
+ if (batchSizeStr == null || batchSizeStr.length() == 0)
+ {
+ model.put(MODEL_STATUS, FAILED_STATUS);
+ model.put(MODEL_MESSAGE, MESSAGE_BATCHSIZE_IS_MANDATORY);
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(MESSAGE_BATCHSIZE_IS_MANDATORY);
+ }
+ return model;
+ }
+ try
+ {
+ size = Long.parseLong(batchSizeStr);
+ }
+ catch(NumberFormatException ex)
+ {
+ model.put(MODEL_STATUS, FAILED_STATUS);
+ model.put(MODEL_MESSAGE, MESSAGE_BATCHSIZE_IS_INVALID);
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(MESSAGE_BATCHSIZE_IS_INVALID);
+ }
+ return model;
+ }
+ final Long batchSize = size;
+ // get the max node id and the extended security aspect
+ Long maxNodeId = patchDAO.getMaxAdmNodeID();
+ final Pair recordAspectPair = qnameDAO.getQName(ASPECT_EXTENDED_SECURITY);
+ if(recordAspectPair == null)
+ {
+ model.put(MODEL_STATUS, SUCCESS_STATUS);
+ model.put(MODEL_MESSAGE, MESSAGE_NO_RECORDS_TO_PROCESS);
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(MESSAGE_NO_RECORDS_TO_PROCESS);
+ }
+ return model;
+ }
+
+ Long totalNumberOfRecordsToProcess = 0L;
+ if (totalToBeProcessedRecordsStr != null && totalToBeProcessedRecordsStr.length() != 0)
+ {
+ try
+ {
+ totalNumberOfRecordsToProcess = Long.parseLong(totalToBeProcessedRecordsStr);
+ }
+ catch(NumberFormatException ex)
+ {
+ //do nothing here, the value will remain 0L in this case
+ }
+ }
+
+ final Long maxRecordsToProcess = totalNumberOfRecordsToProcess;
+ final List processedNodes = new ArrayList();
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(MESSAGE_PROCESSING_BEGIN);
+ }
+ // by batch size
+ for (Long i = 0L; i < maxNodeId; i+=batchSize)
+ {
+ if(maxRecordsToProcess != 0 && processedNodes.size() >= maxRecordsToProcess)
+ {
+ break;
+ }
+ final Long currentIndex = i;
+
+ transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ // get the nodes with the extended security aspect applied
+ List nodeIds = patchDAO.getNodesByAspectQNameId(recordAspectPair.getFirst(), currentIndex, currentIndex + batchSize);
+
+ // process each one
+ for (Long nodeId : nodeIds)
+ {
+ if(maxRecordsToProcess != 0 && processedNodes.size() >= maxRecordsToProcess)
+ {
+ break;
+ }
+ NodeRef record = nodeDAO.getNodePair(nodeId).getSecond();
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(MessageFormat.format(MESSAGE_PROCESSING_RECORD_BEGIN_TEMPLATE, (String) nodeService.getProperty(record, ContentModel.PROP_NAME)));
+ }
+ processNode(record);
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(MessageFormat.format(MESSAGE_PROCESSING_RECORD_END_TEMPLATE, (String) nodeService.getProperty(record, ContentModel.PROP_NAME)));
+ }
+ processedNodes.add(record);
+ }
+
+ return null;
+ }
+ },
+ false, // read only
+ true); // requires new
+ }
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(MESSAGE_PROCESSING_END);
+ }
+ int processedNodesSize = processedNodes.size();
+ String message = "";
+ if(totalNumberOfRecordsToProcess == 0 || (totalNumberOfRecordsToProcess > 0 && processedNodesSize < totalNumberOfRecordsToProcess))
+ {
+ message = MessageFormat.format(MESSAGE_ALL_TEMPLATE, processedNodesSize);
+ }
+ if (totalNumberOfRecordsToProcess > 0 && totalNumberOfRecordsToProcess == processedNodesSize)
+ {
+ message = MessageFormat.format(MESSAGE_PARTIAL_TEMPLATE, totalNumberOfRecordsToProcess);
+ }
+ model.put(MODEL_STATUS, SUCCESS_STATUS);
+ model.put(MODEL_MESSAGE, message);
+ if (logger.isDebugEnabled())
+ {
+ logger.debug(message);
+ }
+ return model;
+ }
+
+ /**
+ * Process each node
+ *
+ * @param nodeRef
+ */
+ @SuppressWarnings({ "unchecked"})
+ private void processNode(NodeRef nodeRef)
+ {
+ // get the reader/writer data
+ Map readers = (Map)nodeService.getProperty(nodeRef, PROP_READERS);
+ Map writers = (Map)nodeService.getProperty(nodeRef, PROP_WRITERS);
+
+ // remove extended security aspect
+ nodeService.removeAspect(nodeRef, ASPECT_EXTENDED_SECURITY);
+
+ // remove dynamic authority permissions
+ permissionService.clearPermission(nodeRef, ExtendedReaderDynamicAuthority.EXTENDED_READER);
+ permissionService.clearPermission(nodeRef, ExtendedWriterDynamicAuthority.EXTENDED_WRITER);
+
+ // if record then ...
+ if (nodeService.hasAspect(nodeRef, ASPECT_RECORD))
+ {
+ // re-set extended security via API
+ extendedSecurityService.set(nodeRef, readers.keySet(), writers.keySet());
+ }
+ }
+}