RM-1039: Can't move folder to Category with disposition schedule.

* improve general reliability of record folder move
  * fix up some issues with the way composite capabilities where being evaluated
  * use capabilities to enforce conditions of move .. not behavior .. this improves the visibility of the move action in the UI
  * unit test
  * reproduced and fixed up UI issue .. was showing No Items red banner in a very specific edge case



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@56373 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2013-10-08 04:22:34 +00:00
parent e84549afce
commit 48bcd03bd9
11 changed files with 309 additions and 75 deletions

View File

@@ -91,25 +91,35 @@ public class CompositeCapability extends DeclarativeCapability
{
int result = AccessDecisionVoter.ACCESS_ABSTAIN;
if (targetCapability != null)
// Check we are dealing with a file plan component
if (filePlanService.isFilePlanComponent(source) == true &&
filePlanService.isFilePlanComponent(target) == true)
{
result = super.evaluate(source, target);
}
else
{
// Check each capability using 'OR' logic
for (Capability capability : capabilities)
// Check the kind of the object, the permissions and the conditions
if (checkKinds(source) == true && checkPermissions(source) == true && checkConditions(source) == true)
{
int capabilityResult = capability.evaluate(source, target);
if (capabilityResult != AccessDecisionVoter.ACCESS_DENIED)
if (targetCapability != null)
{
result = AccessDecisionVoter.ACCESS_ABSTAIN;
if (isUndetermined() == false && capabilityResult == AccessDecisionVoter.ACCESS_GRANTED)
{
result = AccessDecisionVoter.ACCESS_GRANTED;
}
break;
result = targetCapability.evaluate(target);
}
if (AccessDecisionVoter.ACCESS_DENIED != result)
{
// Check each capability using 'OR' logic
for (Capability capability : capabilities)
{
result = capability.evaluate(source, target);
if (result == AccessDecisionVoter.ACCESS_GRANTED)
{
break;
}
}
}
}
else
{
result = AccessDecisionVoter.ACCESS_DENIED;
}
}

View File

@@ -327,14 +327,10 @@ public class DeclarativeCapability extends AbstractCapability
@Override
public int evaluate(NodeRef source, NodeRef target)
{
int result = AccessDecisionVoter.ACCESS_ABSTAIN;
if (targetCapability != null)
int result = evaluate(source);
if (targetCapability != null && result != AccessDecisionVoter.ACCESS_DENIED)
{
result = evaluate(source);
if (result != AccessDecisionVoter.ACCESS_DENIED)
{
result = targetCapability.evaluate(target);
}
result = targetCapability.evaluate(target);
}
return result;
}

View File

@@ -208,21 +208,34 @@ public class DispositionServiceImpl implements
{
if (nodeService.exists(nodeRef) == true)
{
// get this disposition instructions for the node
DispositionSchedule di = getDispositionSchedule(nodeRef);
if (di != null)
{
List<DispositionActionDefinition> dispositionActionDefinitions = di.getDispositionActionDefinitions();
if (dispositionActionDefinitions.isEmpty() == false)
{
// get the first disposition action definition
DispositionActionDefinition nextDispositionActionDefinition = dispositionActionDefinitions.get(0);
// initialise the details of the next disposition action
initialiseDispositionAction(nodeRef, nextDispositionActionDefinition);
}
refreshDispositionAction(nodeRef);
}
}
/**
* Helper method used to refresh the dispostion action details of the given node.
*
* @param nodeRef node reference
*/
public void refreshDispositionAction(NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
// get this disposition instructions for the node
DispositionSchedule di = getDispositionSchedule(nodeRef);
if (di != null)
{
List<DispositionActionDefinition> dispositionActionDefinitions = di.getDispositionActionDefinitions();
if (dispositionActionDefinitions.isEmpty() == false)
{
// get the first disposition action definition
DispositionActionDefinition nextDispositionActionDefinition = dispositionActionDefinitions.get(0);
// initialise the details of the next disposition action
initialiseDispositionAction(nodeRef, nextDispositionActionDefinition);
}
}
}
/** ========= Disposition Property Methods ========= */
@@ -733,33 +746,37 @@ public class DispositionServiceImpl implements
if (result == false)
{
DispositionAction da = new DispositionActionImpl(serviceRegistry, nextDa);
boolean firstComplete = da.getDispositionActionDefinition().eligibleOnFirstCompleteEvent();
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(nextDa, ASSOC_EVENT_EXECUTIONS, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef assoc : assocs)
DispositionActionDefinition dad = da.getDispositionActionDefinition();
if (dad != null)
{
NodeRef eventExecution = assoc.getChildRef();
Boolean isCompleteValue = (Boolean)this.nodeService.getProperty(eventExecution, PROP_EVENT_EXECUTION_COMPLETE);
boolean isComplete = false;
if (isCompleteValue != null)
boolean firstComplete = dad.eligibleOnFirstCompleteEvent();
List<ChildAssociationRef> assocs = this.nodeService.getChildAssocs(nextDa, ASSOC_EVENT_EXECUTIONS, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef assoc : assocs)
{
isComplete = isCompleteValue.booleanValue();
// implement AND and OR combination of event completions
if (isComplete == true)
NodeRef eventExecution = assoc.getChildRef();
Boolean isCompleteValue = (Boolean)this.nodeService.getProperty(eventExecution, PROP_EVENT_EXECUTION_COMPLETE);
boolean isComplete = false;
if (isCompleteValue != null)
{
result = true;
if (firstComplete == true)
isComplete = isCompleteValue.booleanValue();
// implement AND and OR combination of event completions
if (isComplete == true)
{
break;
result = true;
if (firstComplete == true)
{
break;
}
}
}
else
{
result = false;
if (firstComplete == false)
else
{
break;
result = false;
if (firstComplete == false)
{
break;
}
}
}
}

View File

@@ -25,31 +25,36 @@ import java.util.Map;
import org.alfresco.module.org_alfresco_module_rm.RecordsManagementService;
import org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionServiceImpl;
import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService;
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.recordfolder.RecordFolderServiceImpl;
import org.alfresco.repo.copy.CopyBehaviourCallback;
import org.alfresco.repo.copy.CopyDetails;
import org.alfresco.repo.copy.DefaultCopyBehaviourCallback;
import org.alfresco.repo.copy.DoNothingCopyBehaviourCallback;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
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.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* Class containing behaviour for the vitalRecordDefinition aspect.
*
* @author neilm
*/
public class RecordCopyBehaviours implements RecordsManagementModel
public class RecordCopyBehaviours implements RecordsManagementModel,
ApplicationContextAware
{
/** The policy component */
private PolicyComponent policyComponent;
@@ -63,6 +68,18 @@ public class RecordCopyBehaviours implements RecordsManagementModel
/** List of aspects to remove during move and copy */
private List<QName> unwantedAspects = new ArrayList<QName>(5);
/** Application context */
private ApplicationContext applicationContext;
/**
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
/**
* Set the policy component
*
@@ -193,7 +210,7 @@ public class RecordCopyBehaviours implements RecordsManagementModel
{
if (!oldChildAssocRef.getParentRef().equals(newChildAssocRef.getParentRef()))
{
final NodeRef oldNodeRef = oldChildAssocRef.getChildRef();
//final NodeRef oldNodeRef = oldChildAssocRef.getChildRef();
final NodeRef newNodeRef = newChildAssocRef.getChildRef();
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
@@ -201,26 +218,37 @@ public class RecordCopyBehaviours implements RecordsManagementModel
public Object doWork() throws Exception
{
final RecordsManagementService rmService = rmServiceRegistry.getRecordsManagementService();
final DispositionService rmDispositionService = rmServiceRegistry.getDispositionService();
final RecordService rmRecordService = rmServiceRegistry.getRecordService();
if (rmDispositionService.getDispositionSchedule(oldNodeRef) != null || rmService.isCutoff(oldNodeRef))
{
throw new UnsupportedOperationException("Moving a record folder that has a disposition schedule or is cutoff is not suported.");
}
else
final RecordFolderServiceImpl recordFolderService = (RecordFolderServiceImpl)applicationContext.getBean("recordFolderService");
final DispositionServiceImpl dispositionService = (DispositionServiceImpl)applicationContext.getBean("dispositionService");
behaviourFilter.disableBehaviour();
try
{
// Remove unwanted aspects
removeUnwantedAspects(nodeService, newNodeRef);
// reinitialise the record folder
recordFolderService.initialiseRecordFolder(newNodeRef);
// reinitialise the record folder disposition action details
dispositionService.refreshDispositionAction(newNodeRef);
// Sort out the child records
for (NodeRef record : rmService.getRecords(newNodeRef))
{
// Remove unwanted aspects
removeUnwantedAspects(nodeService, record);
// Re-initiate the records in the new folder.
rmRecordService.file(record);
}
}
finally
{
behaviourFilter.enableBehaviour();
}
return null;
}
}, AuthenticationUtil.getSystemUserName());
@@ -428,5 +456,5 @@ public class RecordCopyBehaviours implements RecordsManagementModel
result = "0" + result;
}
return result;
}
}
}

View File

@@ -891,7 +891,6 @@ public class RecordServiceImpl implements RecordService,
@Override
public void file(NodeRef record)
{
ParameterCheck.mandatory("item", record);
// we only support filling of content items

View File

@@ -28,5 +28,5 @@ package org.alfresco.module.org_alfresco_module_rm.recordfolder;
*/
public interface RecordFolderService
{
// TODO see RecordManagementService for Record Folder methods that need moving into this interface
}