RM-2072: Concurrency exceptions and deadlocks on Records Management "File to" rule

* unit test provides easy way to reproduce (number of batches and size configurable)
* 500 docs now being added via described scenario
* extended security props no longer being set up the hierarchy (which was leading to terminal deadlocks)

+review RM @taksoy



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/BRANCHES/V2.2.1.x@102486 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2015-04-24 04:16:59 +00:00
parent 249ca23989
commit 9a558be701
11 changed files with 349 additions and 244 deletions

View File

@@ -211,8 +211,11 @@ public class CreateRecordAction extends AuditableActionExecuterAbstractBase
hideRecord = hideRecordValue.booleanValue(); hideRecord = hideRecordValue.booleanValue();
} }
// create record from existing document synchronized (this)
recordService.createRecord(filePlan, actionedUponNodeRef, !hideRecord); {
// create record from existing document
recordService.createRecord(filePlan, actionedUponNodeRef, !hideRecord);
}
} }
} }

View File

@@ -17,7 +17,6 @@ import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
@@ -144,15 +143,21 @@ public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstr
{ {
public NodeRef execute() throws Throwable public NodeRef execute() throws Throwable
{ {
NodeRef result = null;
try try
{ {
// get the reference to the record folder based on the relative path synchronized (this)
return createOrResolvePath(action, actionedUponNodeRef, finaltargetIsUnfiledRecords); {
// get the reference to the record folder based on the relative path
result = createOrResolvePath(action, actionedUponNodeRef, finaltargetIsUnfiledRecords);
}
} }
catch (DuplicateChildNodeNameException ex) catch (DuplicateChildNodeNameException ex)
{ {
throw new ConcurrencyFailureException("Cannot create or resolve path.", ex); throw new ConcurrencyFailureException("Cannot create or resolve path.", ex);
} }
return result;
} }
}, false, true); }, false, true);
} }
@@ -168,18 +173,22 @@ public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstr
{ {
try try
{ {
if(getMode() == CopyMoveLinkFileToActionMode.MOVE) synchronized (this)
{ {
fileFolderService.move(actionedUponNodeRef, finalRecordFolder, null); if(getMode() == CopyMoveLinkFileToActionMode.MOVE)
} {
else if(getMode() == CopyMoveLinkFileToActionMode.COPY) fileFolderService.move(actionedUponNodeRef, finalRecordFolder, null);
{ }
fileFolderService.copy(actionedUponNodeRef, finalRecordFolder, null); else if(getMode() == CopyMoveLinkFileToActionMode.COPY)
} {
else if(getMode() == CopyMoveLinkFileToActionMode.LINK) fileFolderService.copy(actionedUponNodeRef, finalRecordFolder, null);
{ }
recordService.link(actionedUponNodeRef, finalRecordFolder); else if(getMode() == CopyMoveLinkFileToActionMode.LINK)
} {
recordService.link(actionedUponNodeRef, finalRecordFolder);
}
}
} }
catch (FileNotFoundException fileNotFound) catch (FileNotFoundException fileNotFound)
{ {
@@ -361,18 +370,7 @@ public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstr
*/ */
private NodeRef getChild(NodeRef parent, String childName) private NodeRef getChild(NodeRef parent, String childName)
{ {
NodeRef child = null; return nodeService.getChildByName(parent, ContentModel.ASSOC_CONTAINS, childName);
List<ChildAssociationRef> children = nodeService.getChildAssocs(parent);
for (ChildAssociationRef childAssoc : children) {
NodeRef childNodeRef = childAssoc.getChildRef();
String existingChildName = (String)nodeService.getProperty(childNodeRef, ContentModel.PROP_NAME);
if(existingChildName.equals(childName))
{
child = childNodeRef;
break;
}
}
return child;
} }
/** /**
@@ -392,22 +390,31 @@ public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstr
@Override @Override
public NodeRef doWork() public NodeRef doWork()
{ {
NodeRef child = null; // double check that the child hasn't been created by another thread
if(targetisUnfiledRecords) NodeRef child = getChild(parent, childName);
if (child == null)
{ {
child = fileFolderService.create(parent, childName, RecordsManagementModel.TYPE_UNFILED_RECORD_FOLDER).getNodeRef(); if(targetisUnfiledRecords)
} {
else if(lastAsFolder) // create unfiled folder
{ child = fileFolderService.create(parent, childName, RecordsManagementModel.TYPE_UNFILED_RECORD_FOLDER).getNodeRef();
child = recordFolderService.createRecordFolder(parent, childName); }
} else if(lastAsFolder)
else {
{ // create record folder
if(RecordsManagementModel.TYPE_RECORD_FOLDER.equals(nodeService.getType(parent))) child = recordFolderService.createRecordFolder(parent, childName);
{ }
throw new AlfrescoRuntimeException("Unable to execute " + action.getActionDefinitionName() + " action, because the destination path could not be created."); else
} {
child = filePlanService.createRecordCategory(parent, childName); // ensure we are not trying to create a record categtory in a record folder
if(RecordsManagementModel.TYPE_RECORD_FOLDER.equals(nodeService.getType(parent)))
{
throw new AlfrescoRuntimeException("Unable to execute " + action.getActionDefinitionName() + " action, because the destination path has a record category within a record folder.");
}
// create record category
child = filePlanService.createRecordCategory(parent, childName);
}
} }
return child; return child;
} }

View File

@@ -329,38 +329,44 @@ public class JSONConversionComponent extends org.alfresco.repo.jscript.app.JSONC
* @return * @return
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private JSONObject setRmNodeValues(NodeRef nodeRef, boolean useShortQName) private JSONObject setRmNodeValues(final NodeRef nodeRef, final boolean useShortQName)
{ {
JSONObject rmNodeValues = new JSONObject(); return AuthenticationUtil.runAsSystem(new RunAsWork<JSONObject>()
// UI convenience type
rmNodeValues.put("uiType", getUIType(nodeRef));
// Get the 'kind' of the file plan component
FilePlanComponentKind kind = filePlanService.getFilePlanComponentKind(nodeRef);
rmNodeValues.put("kind", kind.toString());
// File plan node reference
NodeRef filePlan = filePlanService.getFilePlan(nodeRef);
rmNodeValues.put("filePlan", filePlan.toString());
// Unfiled container node reference
NodeRef unfiledRecordContainer = filePlanService.getUnfiledContainer(filePlan);
if (unfiledRecordContainer != null)
{ {
rmNodeValues.put("unfiledRecordContainer", unfiledRecordContainer.toString()); public JSONObject doWork()
rmNodeValues.put("properties", propertiesToJSON(unfiledRecordContainer, nodeService.getProperties(unfiledRecordContainer), useShortQName)); {
QName type = fileFolderService.getFileInfo(unfiledRecordContainer).getType(); JSONObject rmNodeValues = new JSONObject();
rmNodeValues.put("type", useShortQName ? type.toPrefixString(namespaceService) : type.toString());
}
// Set the indicators array // UI convenience type
setIndicators(rmNodeValues, nodeRef); rmNodeValues.put("uiType", getUIType(nodeRef));
// Set the actions array // Get the 'kind' of the file plan component
setActions(rmNodeValues, nodeRef); FilePlanComponentKind kind = filePlanService.getFilePlanComponentKind(nodeRef);
rmNodeValues.put("kind", kind.toString());
return rmNodeValues; // File plan node reference
NodeRef filePlan = filePlanService.getFilePlan(nodeRef);
rmNodeValues.put("filePlan", filePlan.toString());
// Unfiled container node reference
NodeRef unfiledRecordContainer = filePlanService.getUnfiledContainer(filePlan);
if (unfiledRecordContainer != null)
{
rmNodeValues.put("unfiledRecordContainer", unfiledRecordContainer.toString());
rmNodeValues.put("properties", propertiesToJSON(unfiledRecordContainer, nodeService.getProperties(unfiledRecordContainer), useShortQName));
QName type = fileFolderService.getFileInfo(unfiledRecordContainer).getType();
rmNodeValues.put("type", useShortQName ? type.toPrefixString(namespaceService) : type.toString());
}
// Set the indicators array
setIndicators(rmNodeValues, nodeRef);
// Set the actions array
setActions(rmNodeValues, nodeRef);
return rmNodeValues;
}
});
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@@ -46,8 +46,7 @@ import org.alfresco.service.namespace.QName;
( (
defaultType = "rma:extendedSecurity" defaultType = "rma:extendedSecurity"
) )
public class ExtendedSecurityAspect extends BaseBehaviourBean public class ExtendedSecurityAspect extends BaseBehaviourBean
implements NodeServicePolicies.OnMoveNodePolicy
{ {
/** extended security service */ /** extended security service */
protected ExtendedSecurityService extendedSecurityService; protected ExtendedSecurityService extendedSecurityService;
@@ -74,40 +73,4 @@ public class ExtendedSecurityAspect extends BaseBehaviourBean
{ {
return new DoNothingCopyBehaviourCallback(); return new DoNothingCopyBehaviourCallback();
} }
/**
* Update extended security when moving a node.
*
* @see org.alfresco.repo.node.NodeServicePolicies.OnMoveNodePolicy#onMoveNode(org.alfresco.service.cmr.repository.ChildAssociationRef, org.alfresco.service.cmr.repository.ChildAssociationRef)
*/
@Override
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT
)
public void onMoveNode(final ChildAssociationRef origAssoc, final ChildAssociationRef newAssoc)
{
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
{
@Override
public Void doWork()
{
NodeRef record = newAssoc.getChildRef();
NodeRef newParent = newAssoc.getParentRef();
NodeRef oldParent = origAssoc.getParentRef();
Set<String> readers = extendedSecurityService.getExtendedReaders(record);
Set<String> writers = extendedSecurityService.getExtendedWriters(record);
extendedSecurityService.addExtendedSecurity(newParent, readers, writers);
extendedSecurityService.removeExtendedSecurity(oldParent, readers, writers);
return null;
}
});
}
} }

View File

@@ -973,7 +973,7 @@ public class RecordServiceImpl extends BaseBehaviourBean
* @see org.alfresco.module.org_alfresco_module_rm.disposableitem.RecordService#isFiled(org.alfresco.service.cmr.repository.NodeRef) * @see org.alfresco.module.org_alfresco_module_rm.disposableitem.RecordService#isFiled(org.alfresco.service.cmr.repository.NodeRef)
*/ */
@Override @Override
public boolean isFiled(NodeRef nodeRef) public boolean isFiled(final NodeRef nodeRef)
{ {
ParameterCheck.mandatory("nodeRef", nodeRef); ParameterCheck.mandatory("nodeRef", nodeRef);
@@ -981,15 +981,24 @@ public class RecordServiceImpl extends BaseBehaviourBean
if (isRecord(nodeRef)) if (isRecord(nodeRef))
{ {
ChildAssociationRef childAssocRef = nodeService.getPrimaryParent(nodeRef); result = AuthenticationUtil.runAsSystem(new RunAsWork<Boolean>()
if (childAssocRef != null) {
{ public Boolean doWork() throws Exception
NodeRef parent = childAssocRef.getParentRef(); {
if (parent != null && recordFolderService.isRecordFolder(parent)) boolean result = false;
{ ChildAssociationRef childAssocRef = nodeService.getPrimaryParent(nodeRef);
result = true; if (childAssocRef != null)
} {
} NodeRef parent = childAssocRef.getParentRef();
if (parent != null && recordFolderService.isRecordFolder(parent))
{
result = true;
}
}
return result;
}
});
} }
return result; return result;

View File

@@ -40,6 +40,7 @@ import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamic
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority; import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authority.RMAuthority; import org.alfresco.repo.security.authority.RMAuthority;
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
@@ -835,7 +836,14 @@ public class FilePlanRoleServiceImpl implements FilePlanRoleService,
if (!getAllAssignedToRole(filePlan, role).contains(authorityName)) if (!getAllAssignedToRole(filePlan, role).contains(authorityName))
{ {
String roleAuthority = authorityService.getName(AuthorityType.GROUP, getFullRoleName(role, filePlan)); String roleAuthority = authorityService.getName(AuthorityType.GROUP, getFullRoleName(role, filePlan));
authorityService.addAuthority(roleAuthority, authorityName); try
{
authorityService.addAuthority(roleAuthority, authorityName);
}
catch (DuplicateChildNodeNameException exception)
{
// ignore, because the work has already been performed
}
} }
return null; return null;

View File

@@ -46,10 +46,6 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
implements ExtendedSecurityService, implements ExtendedSecurityService,
RecordsManagementModel RecordsManagementModel
{ {
/** Ad hoc properties used for reference counting */
private static final QName PROP_EXTENDED_READER_ROLE = QName.createQName(RM_URI, "extendedReaderRole");
private static final QName PROP_EXTENDED_WRITER_ROLE = QName.createQName(RM_URI, "extendedWriterRole");
/** File plan service */ /** File plan service */
private FilePlanService filePlanService; private FilePlanService filePlanService;
@@ -72,7 +68,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
this.filePlanRoleService = filePlanRoleService; this.filePlanRoleService = filePlanRoleService;
} }
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#hasExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef) * @see org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService#hasExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef)
*/ */
public boolean hasExtendedSecurity(NodeRef nodeRef) public boolean hasExtendedSecurity(NodeRef nodeRef)
@@ -137,6 +133,9 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
if (nodeRef != null) if (nodeRef != null)
{ {
addExtendedSecurityImpl(nodeRef, readers, writers, applyToParents); addExtendedSecurityImpl(nodeRef, readers, writers, applyToParents);
// add to the extended security roles
addExtendedSecurityRoles(nodeRef, readers, writers);
} }
} }
@@ -149,36 +148,36 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
* @param applyToParents * @param applyToParents
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void addExtendedSecurityImpl(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents) private void addExtendedSecurityImpl(final NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents)
{ {
ParameterCheck.mandatory("nodeRef", nodeRef); ParameterCheck.mandatory("nodeRef", nodeRef);
ParameterCheck.mandatory("applyToParents", applyToParents); ParameterCheck.mandatory("applyToParents", applyToParents);
// add the aspect if missing // get the properties
if (!nodeService.hasAspect(nodeRef, ASPECT_EXTENDED_SECURITY)) final Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
{
nodeService.addAspect(nodeRef, ASPECT_EXTENDED_SECURITY, null);
}
// update the readers map // update the readers map
if (readers != null && readers.size() != 0) if (readers != null && readers.size() != 0)
{ {
// get reader map // get reader map
Map<String, Integer> readersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_READERS); Map<String, Integer> readersMap = (Map<String, Integer>)properties.get(PROP_READERS);
// set the readers property (this will in turn apply the aspect if required) // set the readers property (this will in turn apply the aspect if required)
nodeService.setProperty(nodeRef, PROP_READERS, (Serializable)addToMap(readersMap, readers)); properties.put(PROP_READERS, (Serializable)addToMap(readersMap, readers));
} }
// update the writers map // update the writers map
if (writers != null && writers.size() != 0) if (writers != null && writers.size() != 0)
{ {
// get writer map // get writer map
Map<String, Integer> writersMap = (Map<String, Integer>)nodeService.getProperty(nodeRef, PROP_WRITERS); Map<String, Integer> writersMap = (Map<String, Integer>)properties.get(PROP_WRITERS);
// set the writers property (this will in turn apply the aspect if required) // set the writers property (this will in turn apply the aspect if required)
nodeService.setProperty(nodeRef, PROP_WRITERS, (Serializable)addToMap(writersMap, writers)); properties.put(PROP_WRITERS, (Serializable)addToMap(writersMap, writers));
} }
// set properties
nodeService.setProperties(nodeRef, properties);
// apply the readers to any renditions of the content // apply the readers to any renditions of the content
if (isRecord(nodeRef)) if (isRecord(nodeRef))
@@ -190,21 +189,6 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
addExtendedSecurityImpl(child, readers, writers, false); addExtendedSecurityImpl(child, readers, writers, false);
} }
} }
// add to the extended security roles
addExtendedSecurityRoles(nodeRef, readers, writers);
if (applyToParents)
{
// apply the extended readers up the file plan primary hierarchy
NodeRef parent = nodeService.getPrimaryParent(nodeRef).getParentRef();
if (parent != null &&
filePlanService.isFilePlanComponent(parent))
{
addExtendedSecurityImpl(parent, readers, null, applyToParents);
addExtendedSecurityImpl(parent, writers, null, applyToParents);
}
}
} }
/** /**
@@ -217,37 +201,29 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
{ {
NodeRef filePlan = filePlanService.getFilePlan(nodeRef); NodeRef filePlan = filePlanService.getFilePlan(nodeRef);
addExtendedSecurityRolesImpl(filePlan, readers, PROP_EXTENDED_READER_ROLE, FilePlanRoleService.ROLE_EXTENDED_READERS); addExtendedSecurityRolesImpl(filePlan, readers, FilePlanRoleService.ROLE_EXTENDED_READERS);
addExtendedSecurityRolesImpl(filePlan, writers, PROP_EXTENDED_WRITER_ROLE, FilePlanRoleService.ROLE_EXTENDED_WRITERS); addExtendedSecurityRolesImpl(filePlan, writers, FilePlanRoleService.ROLE_EXTENDED_WRITERS);
} }
/** /**
* Add extended security roles implementation
* *
* @param filePlan * @param filePlan file plan
* @param authorities * @param authorities authorities
* @param propertyName * @param roleName role name
* @param roleName
*/ */
@SuppressWarnings("unchecked") private void addExtendedSecurityRolesImpl(NodeRef filePlan, Set<String> authorities, String roleName)
private void addExtendedSecurityRolesImpl(NodeRef filePlan, Set<String> authorities, QName propertyName, String roleName)
{ {
if (authorities != null) if (authorities != null)
{ {
// get the reference count
Map<String, Integer> referenceCountMap = (Map<String, Integer>)nodeService.getProperty(filePlan, propertyName);
for (String authority : authorities) for (String authority : authorities)
{ {
if ((!authority.equals(PermissionService.ALL_AUTHORITIES) && !authority.equals(PermissionService.OWNER_AUTHORITY)) && if ((!authority.equals(PermissionService.ALL_AUTHORITIES) && !authority.equals(PermissionService.OWNER_AUTHORITY)))
(referenceCountMap == null || !referenceCountMap.containsKey(authority)))
{ {
// add the authority to the role // add the authority to the role
filePlanRoleService.assignRoleToAuthority(filePlan, roleName, authority); filePlanRoleService.assignRoleToAuthority(filePlan, roleName, authority);
} }
} }
// update the reference count
nodeService.setProperty(filePlan, propertyName, (Serializable)addToMap(referenceCountMap, authorities));
} }
} }

View File

@@ -0,0 +1,182 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.test.integration.issue;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.action.dm.CreateRecordAction;
import org.alfresco.module.org_alfresco_module_rm.action.impl.FileToAction;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.rule.Rule;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.rule.RuleType;
/**
* System test for RM-2072: Concurrency exceptions and deadlocks on Records Management "File to" rule
*
* @author Roy Wetherall
* @since 2.2.1.1
*/
public class RM2072Test extends BaseRMTestCase
{
private static final int NUMBER_OF_BATCHES = 1;
private static final int NUMBER_IN_BATCH = 500;
private RuleService ruleService;
private NodeRef ruleFolder;
@Override
protected void initServices()
{
super.initServices();
ruleService = (RuleService)applicationContext.getBean("RuleService");
}
@Override
protected boolean isCollaborationSiteTest()
{
return true;
}
@Override
protected boolean isRecordTest()
{
return true;
}
/**
* Given that I have auto declare configured
* And that I have auto file configured to a path where only the record folder needs to be created
* When I add lots of documents in the same transaction
* Then the rules should fire
* And the documents should be filed in the new record folder
*/
public void testAutoDeclareAutoFileCreateRecordFolderOnly() throws Exception
{
doTestInTransaction(new Test<Void>()
{
@Override
public Void run()
{
// create the folder
ruleFolder = fileFolderService.create(documentLibrary, "mytestfolder", ContentModel.TYPE_FOLDER).getNodeRef();
// create record category
NodeRef nodeRefA = filePlanService.createRecordCategory(filePlan, "A");
NodeRef nodeRefB = filePlanService.createRecordCategory(nodeRefA, "B");
filePlanService.createRecordCategory(nodeRefB, "C");
Action action = actionService.createAction(CreateRecordAction.NAME);
action.setParameterValue(CreateRecordAction.PARAM_FILE_PLAN, filePlan);
Rule rule = new Rule();
rule.setRuleType(RuleType.INBOUND);
rule.setTitle("my rule");
rule.setAction(action);
rule.setExecuteAsynchronously(true);
ruleService.saveRule(ruleFolder, rule);
Action fileAction = actionService.createAction(FileToAction.NAME);
fileAction.setParameterValue(FileToAction.PARAM_PATH, "/A/B/C/{date.year.long}/{date.month.long}/{date.day.month}");
fileAction.setParameterValue(FileToAction.PARAM_CREATE_RECORD_PATH, true);
Rule fileRule = new Rule();
fileRule.setRuleType(RuleType.INBOUND);
fileRule.setTitle("my rule");
fileRule.setAction(fileAction);
fileRule.setExecuteAsynchronously(true);
ruleService.saveRule(filePlanService.getUnfiledContainer(filePlan), fileRule);
return null;
}
@Override
public void test(Void result) throws Exception
{
assertFalse(ruleService.getRules(ruleFolder).isEmpty());
}
});
List<NodeRef> records = new ArrayList<NodeRef>(NUMBER_OF_BATCHES*NUMBER_IN_BATCH);
for (int i = 0; i < NUMBER_OF_BATCHES; i++)
{
final int finali = i;
records.addAll(doTestInTransaction(new Test<List<NodeRef>>()
{
@Override
public List<NodeRef> run() throws Exception
{
List<NodeRef> records = new ArrayList<NodeRef>(NUMBER_IN_BATCH);
for (int j = 0; j < NUMBER_IN_BATCH; j++)
{
int count = (finali+1)*(j+1);
String name = "content" + count + ".txt";
System.out.println(name + " - creating");
NodeRef record = fileFolderService.create(ruleFolder, name, ContentModel.TYPE_CONTENT).getNodeRef();
records.add(record);
}
return records;
}
}));
}
try
{
while(!records.isEmpty())
{
Thread.sleep(1000);
final Iterator<NodeRef> temp = records.iterator();
doTestInTransaction(new Test<Void>()
{
@Override
public Void run() throws Exception
{
while (temp.hasNext())
{
NodeRef record = temp.next();
if (nodeService.hasAspect(record, ASPECT_RECORD) && recordService.isFiled(record))
{
String name = (String) nodeService.getProperty(record, ContentModel.PROP_NAME);
System.out.println(name + " - complete");
temp.remove();
}
}
return null;
}
});
}
}
catch (Exception exception)
{
exception.printStackTrace();
throw exception;
}
}
}

View File

@@ -29,6 +29,7 @@ import org.alfresco.module.org_alfresco_module_rm.action.impl.FileToAction;
import org.alfresco.module.org_alfresco_module_rm.capability.Capability; import org.alfresco.module.org_alfresco_module_rm.capability.Capability;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
@@ -113,9 +114,17 @@ public class FileToActionTest extends BaseRMTestCase
assertTrue(recordService.isRecord(dmDocument)); assertTrue(recordService.isRecord(dmDocument));
assertFalse(recordService.isFiled(dmDocument)); assertFalse(recordService.isFiled(dmDocument));
// is the unfiled container the primary parent of the filed record AuthenticationUtil.runAsSystem(new AuthenticationUtil.RunAsWork<Void>()
NodeRef parent = nodeService.getPrimaryParent(dmDocument).getParentRef(); {
assertEquals(filePlanService.getUnfiledContainer(filePlan), parent); public Void doWork() throws Exception
{
// is the unfiled container the primary parent of the filed record
NodeRef parent = nodeService.getPrimaryParent(dmDocument).getParentRef();
assertEquals(filePlanService.getUnfiledContainer(filePlan), parent);
// TODO Auto-generated method stub
return null;
}});
return null; return null;
} }

View File

@@ -105,9 +105,6 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
testMap.put(monkey, Integer.valueOf(1)); testMap.put(monkey, Integer.valueOf(1));
testMap.put(elephant, Integer.valueOf(1)); testMap.put(elephant, Integer.valueOf(1));
checkExtendedReaders(filePlan, testMap);
checkExtendedReaders(rmContainer, testMap);
checkExtendedReaders(rmFolder, testMap);
checkExtendedReaders(record, testMap); checkExtendedReaders(record, testMap);
Set<String> extendedReadersToo = new HashSet<String>(2); Set<String> extendedReadersToo = new HashSet<String>(2);
@@ -125,9 +122,6 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
testMapThree.put(elephant, Integer.valueOf(1)); testMapThree.put(elephant, Integer.valueOf(1));
testMapThree.put(snake, Integer.valueOf(1)); testMapThree.put(snake, Integer.valueOf(1));
checkExtendedReaders(filePlan, testMapThree);
checkExtendedReaders(rmContainer, testMapThree);
checkExtendedReaders(rmFolder, testMapThree);
checkExtendedReaders(recordToo, testMapToo); checkExtendedReaders(recordToo, testMapToo);
// test remove (with no parent inheritance) // test remove (with no parent inheritance)
@@ -142,9 +136,6 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
testMapFour.put(monkey, Integer.valueOf(1)); testMapFour.put(monkey, Integer.valueOf(1));
testMapFour.put(snake, Integer.valueOf(1)); testMapFour.put(snake, Integer.valueOf(1));
checkExtendedReaders(filePlan, testMapThree);
checkExtendedReaders(rmContainer, testMapThree);
checkExtendedReaders(rmFolder, testMapFour);
checkExtendedReaders(recordToo, testMapToo); checkExtendedReaders(recordToo, testMapToo);
// test remove (apply to parents) // test remove (apply to parents)
@@ -158,9 +149,6 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
testMapFour.remove(snake); testMapFour.remove(snake);
testMapToo.remove(snake); testMapToo.remove(snake);
checkExtendedReaders(filePlan, testMapThree);
checkExtendedReaders(rmContainer, testMapThree);
checkExtendedReaders(rmFolder, testMapFour);
checkExtendedReaders(recordToo, testMapToo); checkExtendedReaders(recordToo, testMapToo);
return null; return null;
@@ -197,9 +185,6 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
extendedSecurityService.addExtendedSecurity(record, extendedReaders, null); extendedSecurityService.addExtendedSecurity(record, extendedReaders, null);
checkExtendedReaders(filePlan, testMap);
checkExtendedReaders(rmContainer, testMap);
checkExtendedReaders(rmFolder, testMap);
checkExtendedReaders(record, testMap); checkExtendedReaders(record, testMap);
assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordCategory)); assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordCategory));
assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordFolder)); assertFalse(extendedSecurityService.hasExtendedSecurity(moveRecordFolder));
@@ -212,11 +197,6 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
@Override @Override
public void test(Void result) throws Exception public void test(Void result) throws Exception
{ {
checkExtendedReaders(filePlan, testMap);
assertFalse(extendedSecurityService.hasExtendedSecurity(rmContainer));
// assertEquals(0, extendedSecurityService.getExtendedReaders(rmFolder).size());
checkExtendedReaders(moveRecordCategory, testMap);
checkExtendedReaders(moveRecordFolder, testMap);
checkExtendedReaders(record, testMap); checkExtendedReaders(record, testMap);
} }
}); });

View File

@@ -28,7 +28,6 @@ import org.alfresco.module.org_alfresco_module_rm.capability.Capability;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
import org.alfresco.module.org_alfresco_module_rm.role.Role; import org.alfresco.module.org_alfresco_module_rm.role.Role;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority; import org.alfresco.module.org_alfresco_module_rm.security.ExtendedReaderDynamicAuthority;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority; import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamicAuthority;
@@ -38,7 +37,6 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID; import org.alfresco.util.GUID;
@@ -304,15 +302,12 @@ public class RecordServiceImplTest extends BaseRMTestCase
public void test(Void result) public void test(Void result)
{ {
checkPermissions(READ_RECORDS, AccessStatus.ALLOWED, // file checkPermissions(READ_RECORDS, AccessStatus.DENIED, // file plan
// plan AccessStatus.DENIED, // unfiled container
AccessStatus.ALLOWED, // unfiled container
AccessStatus.DENIED, // record category AccessStatus.DENIED, // record category
AccessStatus.DENIED, // record folder AccessStatus.DENIED, // record folder
AccessStatus.ALLOWED); // doc/record AccessStatus.ALLOWED); // doc/record
permissionReport();
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan, assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(filePlan,
RMPermissionModel.VIEW_RECORDS)); RMPermissionModel.VIEW_RECORDS));
@@ -362,9 +357,8 @@ public class RecordServiceImplTest extends BaseRMTestCase
@Override @Override
public Void run() public Void run()
{ {
checkPermissions(READ_RECORDS, AccessStatus.ALLOWED, // file checkPermissions(READ_RECORDS, AccessStatus.DENIED, // file plan
// plan AccessStatus.DENIED, // unfiled container
AccessStatus.ALLOWED, // unfiled container
AccessStatus.DENIED, // record category AccessStatus.DENIED, // record category
AccessStatus.DENIED, // record folder AccessStatus.DENIED, // record folder
AccessStatus.ALLOWED); // doc/record AccessStatus.ALLOWED); // doc/record
@@ -394,38 +388,6 @@ public class RecordServiceImplTest extends BaseRMTestCase
}, dmConsumer); }, dmConsumer);
} }
private void permissionReport()
{
Set<String> writers = extendedSecurityService.getExtendedWriters(dmDocument);
for (String writer : writers)
{
System.out.println("writer: " + writer);
}
System.out.println("Users assigned to extended writers role:");
Set<String> assignedUsers = filePlanRoleService.getUsersAssignedToRole(filePlan, FilePlanRoleService.ROLE_EXTENDED_WRITERS);
for (String assignedUser : assignedUsers)
{
System.out.println(" ... " + assignedUser);
}
Set<AccessPermission> perms = permissionService.getAllSetPermissions(filePlan);
for (AccessPermission perm : perms)
{
if (perm.getPermission().contains(RMPermissionModel.EDIT_NON_RECORD_METADATA))
{
System.out.println(" ... " + perm.getAuthority() + " - " + perm.getPermission() + " - " + perm.getAccessStatus().toString());
}
}
for (AccessPermission perm : perms)
{
if (perm.getPermission().contains(RMPermissionModel.VIEW_RECORDS))
{
System.out.println(" ... " + perm.getAuthority() + " - " + perm.getPermission() + " - " + perm.getAccessStatus().toString());
}
}
}
public void testCreateRecordNoLink() throws Exception public void testCreateRecordNoLink() throws Exception
{ {
// show that users without WRITE can not create a record from a document // show that users without WRITE can not create a record from a document