From f5063cb8eb2eeacff40b6573e9deb867c9526adb Mon Sep 17 00:00:00 2001 From: Mark Hibbins Date: Wed, 11 Jun 2014 07:29:21 +0000 Subject: [PATCH] RM-1456, disposition lifecycle executor now does not execute cutoff after undo cutoff git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@73541 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../model/recordsModel.xml | 4 + .../action/impl/CutOffAction.java | 43 +++++- .../action/impl/UnCutoffAction.java | 4 +- .../disposition/DispositionServiceImpl.java | 19 +++ .../model/RecordsManagementModel.java | 3 + .../model/rma/aspect/UncutoffAspect.java | 56 +++++++ .../integration/disposition/CutOffTest.java | 137 +++++++++++++++--- 7 files changed, 242 insertions(+), 24 deletions(-) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/UncutoffAspect.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml index d3329582f4..fc5f506434 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/recordsModel.xml @@ -881,6 +881,10 @@ + + Uncut Off + + Transferring diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/CutOffAction.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/CutOffAction.java index 7641f9df01..1c542990d7 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/CutOffAction.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/CutOffAction.java @@ -18,6 +18,7 @@ */ package org.alfresco.module.org_alfresco_module_rm.action.impl; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.module.org_alfresco_module_rm.action.RMDispositionActionExecuterAbstractBase; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.repository.NodeRef; @@ -38,8 +39,11 @@ public class CutOffAction extends RMDispositionActionExecuterAbstractBase @Override protected void executeRecordFolderLevelDisposition(Action action, NodeRef recordFolder) { - // Mark the folder as cut off - dispositionService.cutoffDisposableItem(recordFolder); + if(checkUncutOffStatus(action, recordFolder)) + { + // Mark the folder as cut off + dispositionService.cutoffDisposableItem(recordFolder); + } } /** @@ -48,7 +52,38 @@ public class CutOffAction extends RMDispositionActionExecuterAbstractBase @Override protected void executeRecordLevelDisposition(Action action, NodeRef record) { - // Mark the record as cut off - dispositionService.cutoffDisposableItem(record); + if(checkUncutOffStatus(action, record)) + { + // Mark the record as cut off + dispositionService.cutoffDisposableItem(record); + } + } + + /** + * Check if the record or folder has been uncut off. If it has and this cut off action is an + * automated disposition action then the cut off isn't run. If it has and this is a manual + * cut off action then the uncut off aspect is removed prior to the uncut action. + * + * @param action The cut off action + * @param recordOrFolder The record or folder to be cut off + * @return True if the record or folder can be cut off + */ + private boolean checkUncutOffStatus(Action action, NodeRef recordOrFolder) + { + boolean okToCutOff = true; + if(nodeService.hasAspect(recordOrFolder, ASPECT_UNCUT_OFF)) + { + if(action.getParameterValue(PARAM_NO_ERROR_CHECK) != null) + { + // this exception stops the cut off disposition schedule action taking place and because we're + // running from the schedule (PARAM_NO_ERROR_CHECK is set) then the exception will not be reported + throw new AlfrescoRuntimeException("Cannot cut off from schedule when uncut off aspect is present"); + } + else + { + nodeService.removeAspect(recordOrFolder, ASPECT_UNCUT_OFF); + } + } + return okToCutOff; } } \ No newline at end of file diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/UnCutoffAction.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/UnCutoffAction.java index 3635e751a4..d0efeba546 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/UnCutoffAction.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/UnCutoffAction.java @@ -56,14 +56,16 @@ public class UnCutoffAction extends RMActionExecuterAbstractBase throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_UNDO_NOT_LAST)); } - // Remove the cutoff aspect + // Remove the cutoff aspect and add the uncutoff aspect nodeService.removeAspect(actionedUponNodeRef, ASPECT_CUT_OFF); + nodeService.addAspect(actionedUponNodeRef, ASPECT_UNCUT_OFF, null); if (recordFolderService.isRecordFolder(actionedUponNodeRef)) { List records = recordService.getRecords(actionedUponNodeRef); for (NodeRef record : records) { nodeService.removeAspect(record, ASPECT_CUT_OFF); + nodeService.addAspect(record, ASPECT_UNCUT_OFF, null); } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImpl.java index 3d6c7d6744..7b71044cce 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionServiceImpl.java @@ -95,6 +95,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl * * @param nodeService the node service */ + @Override public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; @@ -105,6 +106,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl * * @param dictionaryServic the dictionary service */ + @Override public void setDictionaryService(DictionaryService dictionaryService) { this.dictionaryService = dictionaryService; @@ -252,6 +254,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl /** * @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getDispositionSchedule(org.alfresco.service.cmr.repository.NodeRef) */ + @Override public DispositionSchedule getDispositionSchedule(NodeRef nodeRef) { DispositionSchedule di = null; @@ -302,6 +305,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl /** * @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getAssociatedDispositionSchedule(org.alfresco.service.cmr.repository.NodeRef) */ + @Override public DispositionSchedule getAssociatedDispositionSchedule(NodeRef nodeRef) { DispositionSchedule ds = null; @@ -400,6 +404,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl /** * @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getDisposableItems(org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule) */ + @Override public List getDisposableItems(DispositionSchedule dispositionSchedule) { ParameterCheck.mandatory("dispositionSchedule", dispositionSchedule); @@ -528,6 +533,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl /** * */ + @Override public DispositionActionDefinition addDispositionActionDefinition( DispositionSchedule schedule, Map actionDefinitionParams) @@ -557,6 +563,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl /** * @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#removeDispositionActionDefinition(org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule, org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition) */ + @Override public void removeDispositionActionDefinition(DispositionSchedule schedule, DispositionActionDefinition actionDefinition) { // check first whether action definitions can be removed @@ -579,6 +586,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl * @param actionDefinitionParams Map of parameters to use to update the action definition * @return The updated DispositionActionDefinition */ + @Override public DispositionActionDefinition updateDispositionActionDefinition( DispositionActionDefinition actionDefinition, Map actionDefinitionParams) @@ -665,6 +673,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl /** * @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#isNextDispositionActionEligible(org.alfresco.service.cmr.repository.NodeRef) */ + @Override public boolean isNextDispositionActionEligible(NodeRef nodeRef) { boolean result = false; @@ -748,6 +757,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl /** * @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getNextDispositionAction(org.alfresco.service.cmr.repository.NodeRef) */ + @Override public DispositionAction getNextDispositionAction(NodeRef nodeRef) { DispositionAction result = null; @@ -766,6 +776,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl /** * @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getCompletedDispositionActions(org.alfresco.service.cmr.repository.NodeRef) */ + @Override public List getCompletedDispositionActions(NodeRef nodeRef) { List assocs = nodeService.getChildAssocs(nodeRef, ASSOC_DISPOSITION_ACTION_HISTORY, RegexQNamePattern.MATCH_ALL); @@ -781,6 +792,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl /** * @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getLastCompletedDispostionAction(org.alfresco.service.cmr.repository.NodeRef) */ + @Override public DispositionAction getLastCompletedDispostionAction(NodeRef nodeRef) { DispositionAction result = null; @@ -968,6 +980,12 @@ public class DispositionServiceImpl extends ServiceBaseImpl // apply cut off applyCutoff(nodeRef); + // remove uncut off aspect if applied + if(nodeService.hasAspect(nodeRef, ASPECT_UNCUT_OFF)) + { + nodeService.removeAspect(nodeRef, ASPECT_UNCUT_OFF); + } + // close the record folder if it isn't already closed! if (recordFolderService.isRecordFolder(nodeRef) && !recordFolderService.isRecordFolderClosed(nodeRef)) @@ -991,6 +1009,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl { AuthenticationUtil.runAsSystem(new RunAsWork() { + @Override public Void doWork() { // Apply the cut off aspect and set cut off date diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java index 96d57ef4d0..ea5cf3cf75 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java @@ -130,6 +130,9 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel QName ASPECT_CUT_OFF = QName.createQName(RM_URI, "cutOff"); QName PROP_CUT_OFF_DATE = QName.createQName(RM_URI, "cutOffDate"); + // Uncut off aspect + QName ASPECT_UNCUT_OFF = QName.createQName(RM_URI, "uncutOff"); + // Transferred aspect QName ASPECT_TRANSFERRED = QName.createQName(RM_URI, "transferred"); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/UncutoffAspect.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/UncutoffAspect.java new file mode 100644 index 0000000000..f417ba639e --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/aspect/UncutoffAspect.java @@ -0,0 +1,56 @@ +/* + * 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.module.org_alfresco_module_rm.model.rma.aspect; + +import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; +import org.alfresco.repo.copy.CopyBehaviourCallback; +import org.alfresco.repo.copy.CopyDetails; +import org.alfresco.repo.copy.DoNothingCopyBehaviourCallback; +import org.alfresco.repo.policy.annotation.Behaviour; +import org.alfresco.repo.policy.annotation.BehaviourBean; +import org.alfresco.repo.policy.annotation.BehaviourKind; +import org.alfresco.service.namespace.QName; + +/** + * rma:uncutoff behaviour bean + * + * @author Mark Hibbins + * @since 2.2 + */ +@BehaviourBean +( + defaultType = "rma:uncutOff" +) +public class UncutoffAspect extends BaseBehaviourBean +{ + /** + * Copy callback. + * + * Uncutoff aspect should not be copied. + */ + @Behaviour + ( + kind = BehaviourKind.CLASS, + policy = "alf:getCopyCallback" + ) + public CopyBehaviourCallback getCopyCallback(QName classRef, CopyDetails copyDetails) + { + return new DoNothingCopyBehaviourCallback(); + } +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/CutOffTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/CutOffTest.java index ec434698ff..2534fa64c4 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/CutOffTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/CutOffTest.java @@ -22,6 +22,8 @@ import java.io.Serializable; import java.util.HashMap; import java.util.Map; +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.module.org_alfresco_module_rm.action.RMDispositionActionExecuterAbstractBase; import org.alfresco.module.org_alfresco_module_rm.action.impl.CompleteEventAction; import org.alfresco.module.org_alfresco_module_rm.action.impl.CutOffAction; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; @@ -31,12 +33,12 @@ import org.springframework.extensions.webscripts.GUID; /** * Cut off integration tests. - * + * * @author Roy Wetherall * @since 2.2 */ public class CutOffTest extends BaseRMTestCase -{ +{ /** * given we have a record folder that is eligible for cutoff ensure that the * record can be cut off successfully. @@ -46,37 +48,40 @@ public class CutOffTest extends BaseRMTestCase doBehaviourDrivenTest(new BehaviourDrivenTest() { NodeRef recordFolder = null; - + + @Override public void given() { //create record folder recordFolder = recordFolderService.createRecordFolder(rmContainer, GUID.generate()); - + // TODO add some records - + // make eligible for cutoff Map params = new HashMap(1); params.put(CompleteEventAction.PARAM_EVENT_NAME, CommonRMTestUtils.DEFAULT_EVENT_NAME); rmActionService.executeRecordsManagementAction(recordFolder, CompleteEventAction.NAME, params); } - + + @Override public void when() { // complete event - rmActionService.executeRecordsManagementAction(recordFolder, CutOffAction.NAME, null); + rmActionService.executeRecordsManagementAction(recordFolder, CutOffAction.NAME, null); } - + + @Override public void then() { // ensure the record folder is cut off assertTrue(dispositionService.isDisposableItemCutoff(recordFolder)); } }); - + } - + /** - * given that we have a closed record folder eligible for cut off ensure that it can + * given that we have a closed record folder eligible for cut off ensure that it can * be cut off. *

* relates to https://issues.alfresco.com/jira/browse/RM-1340 @@ -86,34 +91,128 @@ public class CutOffTest extends BaseRMTestCase doBehaviourDrivenTest(new BehaviourDrivenTest() { NodeRef recordFolder = null; - + + @Override public void given() { //create record folder recordFolder = recordFolderService.createRecordFolder(rmContainer, GUID.generate()); - + // TODO add some records - + // make eligible for cutoff Map params = new HashMap(1); params.put(CompleteEventAction.PARAM_EVENT_NAME, CommonRMTestUtils.DEFAULT_EVENT_NAME); rmActionService.executeRecordsManagementAction(recordFolder, CompleteEventAction.NAME, params); - + // close the record folder recordFolderService.closeRecordFolder(recordFolder); } - + + @Override public void when() { // complete event - rmActionService.executeRecordsManagementAction(recordFolder, CutOffAction.NAME, null); + rmActionService.executeRecordsManagementAction(recordFolder, CutOffAction.NAME, null); } - + + @Override public void then() { // ensure the record folder is cut off assertTrue(dispositionService.isDisposableItemCutoff(recordFolder)); } }); - } + } + + /** + * given we have a record folder that is eligible for cutoff ensure that the + * record can be cut off successfully. + */ + public void testCutOffUncutOffRecordFolder() + { + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + NodeRef recordFolder = null; + + @Override + public void given() + { + //create record folder + recordFolder = recordFolderService.createRecordFolder(rmContainer, GUID.generate()); + nodeService.addAspect(recordFolder, ASPECT_UNCUT_OFF, null); + + // TODO add some records + + // make eligible for cutoff + Map params = new HashMap(1); + params.put(CompleteEventAction.PARAM_EVENT_NAME, CommonRMTestUtils.DEFAULT_EVENT_NAME); + rmActionService.executeRecordsManagementAction(recordFolder, CompleteEventAction.NAME, params); + } + + @Override + public void when() + { + // complete event + rmActionService.executeRecordsManagementAction(recordFolder, CutOffAction.NAME, null); + } + + @Override + public void then() + { + // ensure the record folder is cut off + assertTrue(dispositionService.isDisposableItemCutoff(recordFolder)); + } + }); + + } + + /** + * given we have a record folder that is eligible for cutoff ensure that the + * record can be cut off successfully. + */ + public void testCutOffUncutOffRecordFolderFromSchedule() + { + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + NodeRef recordFolder = null; + + @Override + public void given() + { + //create record folder + recordFolder = recordFolderService.createRecordFolder(rmContainer, GUID.generate()); + nodeService.addAspect(recordFolder, ASPECT_UNCUT_OFF, null); + + // TODO add some records + + // make eligible for cutoff + Map params = new HashMap(1); + params.put(CompleteEventAction.PARAM_EVENT_NAME, CommonRMTestUtils.DEFAULT_EVENT_NAME); + rmActionService.executeRecordsManagementAction(recordFolder, CompleteEventAction.NAME, params); + } + + @Override + public void when() + { + // complete event + Map params = new HashMap(1); + params.put(RMDispositionActionExecuterAbstractBase.PARAM_NO_ERROR_CHECK, Boolean.FALSE); + try + { + rmActionService.executeRecordsManagementAction(recordFolder, CutOffAction.NAME, params); + } + catch(AlfrescoRuntimeException e) { } // expected + } + + @Override + public void then() + { + // ensure the record folder is cut off + assertFalse(dispositionService.isDisposableItemCutoff(recordFolder)); + } + }); + + } + }