From 80c64b59ebef64a7581aa00477fd5e120ded954e Mon Sep 17 00:00:00 2001 From: Roxana Lucanu-Ghetu Date: Fri, 17 Jun 2016 08:25:27 +0100 Subject: [PATCH 01/17] Merge branch 'feature-2.4/RM-3060' into 'release/V2.4' Feature 2.4/rm 3060 - Record linked to folder with the same disposition schedule couldn't be cut off Added search by name for current disposition action; when the record has multiple disposition schedules the current disposition action may not be found by id. See merge request !157 (cherry picked from commit d9883a3b02db165aaa6ddf1317c699262e881ac5) --- .../UpdateNextDispositionActionTest.java | 148 ++++++++++++++++++ .../EditDispositionActionAsOfDateAction.java | 3 + .../disposition/DispositionServiceImpl.java | 7 + .../test/util/CommonRMTestUtils.java | 1 + 4 files changed, 159 insertions(+) create mode 100644 rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java new file mode 100644 index 0000000000..462198f5a7 --- /dev/null +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java @@ -0,0 +1,148 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * 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 . + * #L% + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.disposition; + +import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_DISPOSITION_DESCRIPTION; +import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_DISPOSITION_INSTRUCTIONS; +import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_EVENT_NAME; +import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.PERIOD_ONE_WEEK; +import static org.alfresco.util.GUID.generate; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.module.org_alfresco_module_rm.action.impl.CutOffAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.DestroyAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.EditDispositionActionAsOfDateAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.TransferAction; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; + +/** +* Update next disposition step integration tests. +* +* @author Roxana Lucanu +* @since 2.4.1 +*/ +public class UpdateNextDispositionActionTest extends BaseRMTestCase +{ + /** + * Given a record with multiple dispositions + * When updating the next step + * Then the action is available + *

+ * relates to https://issues.alfresco.com/jira/browse/RM-3060 + */ + public void testUpdateNextDispositionAction_RM3060() throws Exception + { + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + NodeRef record; + NodeRef folder2; + + @Override + public void given() + { + // create category1 + NodeRef category1 = filePlanService.createRecordCategory(filePlan, generate()); + + // create disposition schedule for category1 + createDispositionSchedule(category1); + + // create category2 + NodeRef category2 = filePlanService.createRecordCategory(filePlan, generate()); + + // create disposition schedule for category2 + createDispositionSchedule(category2); + + // create folder2 inside category2 + folder2 = recordFolderService.createRecordFolder(category2, generate()); + + // create folder1 inside category1 + NodeRef folder1 = recordFolderService.createRecordFolder(category1, generate()); + + // create record inside folder1 + record = utils.createRecord(folder1, generate(), generate()); + + } + @Override + public void when() throws Exception + { + // link the record to folder2 + recordService.link(record, folder2); + + // complete record + utils.completeRecord(record); + + // set the disposition as of date to now on the record + rmActionService.executeRecordsManagementAction(record, + EditDispositionActionAsOfDateAction.NAME, + Collections.singletonMap(EditDispositionActionAsOfDateAction.PARAM_AS_OF_DATE, new Date())); + + // cut off + rmActionService.executeRecordsManagementAction(record, CutOffAction.NAME, null); + } + + @Override + public void then() throws Exception + { + assertTrue(nodeService.hasAspect(record, ASPECT_CUT_OFF)); + } + }); + } + + private void createDispositionSchedule(NodeRef category) + { + DispositionSchedule ds = utils.createDispositionSchedule(category, DEFAULT_DISPOSITION_INSTRUCTIONS, DEFAULT_DISPOSITION_DESCRIPTION, true, false, false); + + // create the properties for CUTOFF action and add it to the disposition action definition + Map cutOff = new HashMap(3); + cutOff.put(PROP_DISPOSITION_ACTION_NAME, CutOffAction.NAME); + cutOff.put(PROP_DISPOSITION_DESCRIPTION, generate()); + cutOff.put(PROP_DISPOSITION_PERIOD, PERIOD_ONE_WEEK); + dispositionService.addDispositionActionDefinition(ds, cutOff); + + // create the properties for TRANSFER action and add it to the disposition action definition + Map transfer = new HashMap(3); + transfer.put(PROP_DISPOSITION_ACTION_NAME, TransferAction.NAME); + transfer.put(PROP_DISPOSITION_DESCRIPTION, generate()); + transfer.put(PROP_DISPOSITION_EVENT, (Serializable)Collections.singletonList(DEFAULT_EVENT_NAME)); + dispositionService.addDispositionActionDefinition(ds, transfer); + + // create the properties for DESTROY action and add it to the disposition action definition + Map destroy = new HashMap(3); + destroy.put(PROP_DISPOSITION_ACTION_NAME, DestroyAction.NAME); + destroy.put(PROP_DISPOSITION_DESCRIPTION, generate()); + destroy.put(PROP_DISPOSITION_PERIOD, PERIOD_ONE_WEEK); + dispositionService.addDispositionActionDefinition(ds, destroy); + } +} \ No newline at end of file diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/EditDispositionActionAsOfDateAction.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/EditDispositionActionAsOfDateAction.java index 59976aa365..1d4ae1aba9 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/EditDispositionActionAsOfDateAction.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/EditDispositionActionAsOfDateAction.java @@ -38,6 +38,9 @@ public class EditDispositionActionAsOfDateAction extends RMActionExecuterAbstrac private static final String MSG_VALID_DATE_DISP_ASOF = "rm.action.valid-date-disp-asof"; private static final String MSG_DISP_ASOF_LIFECYCLE_APPLIED = "rm.action.disp-asof-lifecycle-applied"; + /** Action name */ + public static final String NAME = "editDispositionActionAsOfDate"; + /** Action parameters */ public static final String PARAM_AS_OF_DATE = "asOfDate"; 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 70f0a43957..75158f558d 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 @@ -880,6 +880,13 @@ public class DispositionServiceImpl extends ServiceBaseImpl // Get the current action String currentADId = (String) nodeService.getProperty(currentDispositionAction, PROP_DISPOSITION_ACTION_ID); currentDispositionActionDefinition = di.getDispositionActionDefinition(currentADId); + // When the record has multiple disposition schedules the current disposition action may not be found by id + // In this case it will be searched by name + if(currentDispositionActionDefinition == null) + { + String currentADName = (String) nodeService.getProperty(currentDispositionAction, PROP_DISPOSITION_ACTION); + currentDispositionActionDefinition = di.getDispositionActionDefinitionByName(currentADName); + } // Get the next disposition action int index = currentDispositionActionDefinition.getIndex(); diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java index 3d66cb81bb..c8530a1ede 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java @@ -76,6 +76,7 @@ public class CommonRMTestUtils implements RecordsManagementModel public static final String DEFAULT_EVENT_NAME = "case_closed"; public static final String PERIOD_NONE = "none|0"; public static final String PERIOD_IMMEDIATELY = "immediately|0"; + public static final String PERIOD_ONE_WEEK = "week|1"; /** * Constructor From db231f62db9444851d086b5e12154370871f7a79 Mon Sep 17 00:00:00 2001 From: roxana Date: Tue, 4 Oct 2016 10:34:08 +0300 Subject: [PATCH 02/17] Added implementation for handling multiple dispositions schedule record based. --- .../disposition/DispositionService.java | 11 + .../disposition/DispositionServiceImpl.java | 208 +++++++++++++++++- 2 files changed, 212 insertions(+), 7 deletions(-) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java index 295397f1bd..b0e153b495 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java @@ -20,6 +20,7 @@ package org.alfresco.module.org_alfresco_module_rm.disposition; import java.io.Serializable; import java.util.Collection; +import java.util.Date; import java.util.List; import java.util.Map; @@ -232,4 +233,14 @@ public interface DispositionService * @param nodeRef node reference */ void refreshDispositionAction(NodeRef nodeRef); + + /** + * Gets date of the disposition action for the given + * disposition schedule with the given action name + * + * @param dispositionSchedule nodeRef + * @param dispositionActionName + * @return date + */ + Date getDispositionActionDate(NodeRef dispositionSchedule, String dispositionActionName); } 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 75158f558d..c4308d14ad 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 @@ -21,14 +21,19 @@ package org.alfresco.module.org_alfresco_module_rm.disposition; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSelectionStrategy.DispositionableNodeRefComparator; import org.alfresco.module.org_alfresco_module_rm.disposition.property.DispositionProperty; import org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEvent; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanComponentKind; @@ -267,16 +272,37 @@ 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) + public DispositionSchedule getDispositionSchedule(final NodeRef nodeRef) { - DispositionSchedule di = null; + DispositionSchedule ds = null; NodeRef diNodeRef = null; if (isRecord(nodeRef)) { // Get the record folders for the record List recordFolders = recordFolderService.getRecordFolders(nodeRef); - // At this point, we may have disposition instruction objects from 1..n folders. - diNodeRef = dispositionSelectionStrategy.selectDispositionScheduleFrom(recordFolders); + + DispositionAction nextDispositionAction = getNextDispositionAction(nodeRef); + + // the record is not created yet or it doesn't have DS + if (nextDispositionAction == null) + { + // calculate nextAction to be the longest first action step + DispositionScheduleAndNextAction dsNodeRef = getNextDispositionActionFromParents(recordFolders); + if (dsNodeRef != null) + { + nextDispositionAction = dsNodeRef.getNextAction(); + diNodeRef = dsNodeRef.getDispositionNodeRef(); + } + } + else + { + diNodeRef = setRecordNextDispositionActionLatestDate(nodeRef, recordFolders, nextDispositionAction); + } + + if (nextDispositionAction == null) + { + return null; + } } else { @@ -286,12 +312,15 @@ public class DispositionServiceImpl extends ServiceBaseImpl if (diNodeRef != null) { - di = new DispositionScheduleImpl(serviceRegistry, nodeService, diNodeRef); + ds = new DispositionScheduleImpl(serviceRegistry, nodeService, diNodeRef); } - - return di; + + return ds; } + + + /** * This method returns a NodeRef * Gets the disposition instructions @@ -880,6 +909,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl // Get the current action String currentADId = (String) nodeService.getProperty(currentDispositionAction, PROP_DISPOSITION_ACTION_ID); currentDispositionActionDefinition = di.getDispositionActionDefinition(currentADId); + // When the record has multiple disposition schedules the current disposition action may not be found by id // In this case it will be searched by name if(currentDispositionActionDefinition == null) @@ -1030,6 +1060,31 @@ public class DispositionServiceImpl extends ServiceBaseImpl } } + public Date getDispositionActionDate(NodeRef dispositionSchedule, String dispositionActionName) + { + List assocs = nodeService.getChildAssocs(dispositionSchedule); + if (assocs != null && assocs.size() > 0) + { + for (ChildAssociationRef assoc : assocs) + { + if (assoc != null && assoc.getQName().getLocalName().contains(dispositionActionName)) + { + Date newAsOfDate = null; + Period dispositionPeriod = (Period) nodeService.getProperty(assoc.getChildRef(), PROP_DISPOSITION_PERIOD); + Date actionCreationDate = (Date)nodeService.getProperty(assoc.getChildRef(), ContentModel.PROP_CREATED); + + if (dispositionPeriod != null) + { + // calculate the new as of date as we have been provided a new period + newAsOfDate = dispositionPeriod.getNextDate(actionCreationDate); + } + return newAsOfDate; + } + } + } + return null;// throw exception? poate nu are actiuni cu numele dat ca param + } + /** * Helper method to determine if a node is frozen or has frozen children * @@ -1077,4 +1132,143 @@ public class DispositionServiceImpl extends ServiceBaseImpl } }); } + + class DispositionScheduleAndNextAction + { + private NodeRef dispositionNodeRef; + + private DispositionAction nextAction; + + public DispositionScheduleAndNextAction(NodeRef dispositionNodeRef, DispositionAction nextAction) + { + this.dispositionNodeRef = dispositionNodeRef; + this.nextAction = nextAction; + } + + public NodeRef getDispositionNodeRef() + { + return dispositionNodeRef; + } + + public void setDispositionNodeRef(NodeRef dispositionNodeRef) + { + this.dispositionNodeRef = dispositionNodeRef; + } + + public DispositionAction getNextAction() + { + return nextAction; + } + + public void setNextAction(DispositionAction nextAction) + { + this.nextAction = nextAction; + } + + } + + /** + * Get the longest period for the given action + * + * @param recordNodeRef + * @param recordFolders + * @param nextDispositionAction + * @return + */ + private NodeRef setRecordNextDispositionActionLatestDate(final NodeRef recordNodeRef, List recordFolders, DispositionAction nextDispositionAction) + { + String recordnextDispositionActionName = nextDispositionAction.getName(); + Date recordNextDispositionActionDate = nextDispositionAction.getAsOfDate(); + Date nextDispositionActionDate = null; + NodeRef dispositionNodeRef = null; + + for (NodeRef folder : recordFolders) + { + NodeRef dsNodeRef = getDispositionScheduleImpl(folder); + if (dsNodeRef != null) + { + Date dispActionDate = getDispositionActionDate(dsNodeRef, recordnextDispositionActionName); + if (nextDispositionActionDate == null || nextDispositionActionDate.before(dispActionDate)) + { + nextDispositionActionDate = dispActionDate; + dispositionNodeRef = dsNodeRef; + } + } + } + // set only on record creation or when linking + if (!nextDispositionActionDate.equals(recordNextDispositionActionDate) && recordNextDispositionActionDate.before(nextDispositionActionDate)) + { + final Date nextDADate = nextDispositionActionDate; + + AuthenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() + { + nodeService.setProperty(recordNodeRef, PROP_DISPOSITION_AS_OF, nextDADate); + return null; + } + }); + } + return dispositionNodeRef; + } + + /** + * Calculate next disposition action for a record with the given parents + * + * @param recordFolders parent folders + * @return next disposition action and the disposition associated + */ + private DispositionScheduleAndNextAction getNextDispositionActionFromParents(List recordFolders) + { + NodeRef newAction = null; + String newDispositionActionName = null; + Date newDispositionActionDate = null; + NodeRef dispositionNodeRef = null; + for (NodeRef folder : recordFolders) + { + NodeRef folderDS = getDispositionScheduleImpl(folder); + if (folderDS != null) + { + List assocs = nodeService.getChildAssocs(folderDS); + if (assocs != null && assocs.size() > 0) + { + NodeRef firstAction = assocs.get(0).getChildRef(); + DispositionAction firstDispositionAction = new DispositionActionImpl(serviceRegistry, firstAction); + + if (newAction == null) + { + newAction = firstAction; + newDispositionActionName = (String)nodeService.getProperty(newAction, PROP_DISPOSITION_ACTION_NAME); + newDispositionActionDate = getDispositionActionDate(folderDS, newDispositionActionName); + dispositionNodeRef = folderDS; + } + else if (firstDispositionAction.getAsOfDate() != null && newDispositionActionDate.before(firstDispositionAction.getAsOfDate())) + { + newDispositionActionName = (String)nodeService.getProperty(firstAction, PROP_DISPOSITION_ACTION_NAME); + newDispositionActionDate = firstDispositionAction.getAsOfDate(); + dispositionNodeRef = folderDS; + } + } + } + } + if (newAction != null) { + final NodeRef action = newAction; + final String dispositionActionName = newDispositionActionName; + final Date dispositionActionDate = newDispositionActionDate; + AuthenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() + { + nodeService.setProperty(action, PROP_DISPOSITION_ACTION_NAME, dispositionActionName); + nodeService.setProperty(action, PROP_DISPOSITION_AS_OF, dispositionActionDate); + return null; + } + }); + DispositionAction dsAction = new DispositionActionImpl(serviceRegistry, action); + return new DispositionScheduleAndNextAction(dispositionNodeRef, dsAction); + } + return null; + } } From 6b916b977fedfc12eab62c47f6280dfa44e66a39 Mon Sep 17 00:00:00 2001 From: roxana Date: Fri, 7 Oct 2016 10:45:49 +0300 Subject: [PATCH 03/17] Changed a bit the methods to be more readable. --- .../disposition/DispositionServiceImpl.java | 281 ++++++++++-------- 1 file changed, 155 insertions(+), 126 deletions(-) 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 c4308d14ad..22f3c6fc6f 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 @@ -21,19 +21,15 @@ package org.alfresco.module.org_alfresco_module_rm.disposition; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; -import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry; -import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSelectionStrategy.DispositionableNodeRefComparator; import org.alfresco.module.org_alfresco_module_rm.disposition.property.DispositionProperty; import org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEvent; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanComponentKind; @@ -74,6 +70,8 @@ public class DispositionServiceImpl extends ServiceBaseImpl { /** Logger */ private static Log logger = LogFactory.getLog(DispositionServiceImpl.class); + + public enum WriteMode {ReadOnly, DateOnly, DateAndName}; /** Behaviour filter */ private BehaviourFilter behaviourFilter; @@ -275,44 +273,42 @@ public class DispositionServiceImpl extends ServiceBaseImpl public DispositionSchedule getDispositionSchedule(final NodeRef nodeRef) { DispositionSchedule ds = null; - NodeRef diNodeRef = null; + NodeRef dsNodeRef = null; if (isRecord(nodeRef)) { - // Get the record folders for the record - List recordFolders = recordFolderService.getRecordFolders(nodeRef); + final NextActionFromDisposition dsNextAction = getDispositionActionByNameForRecord(nodeRef); - DispositionAction nextDispositionAction = getNextDispositionAction(nodeRef); - - // the record is not created yet or it doesn't have DS - if (nextDispositionAction == null) + if (!dsNextAction.getWriteMode().equals(WriteMode.ReadOnly)) { - // calculate nextAction to be the longest first action step - DispositionScheduleAndNextAction dsNodeRef = getNextDispositionActionFromParents(recordFolders); - if (dsNodeRef != null) - { - nextDispositionAction = dsNodeRef.getNextAction(); - diNodeRef = dsNodeRef.getDispositionNodeRef(); - } + final NodeRef action = dsNextAction.getNextActionNodeRef(); + final String dispositionActionName = dsNextAction.getNextActionName(); + final Date dispositionActionDate = dsNextAction.getNextActionDateAsOf(); + + AuthenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() + { + nodeService.setProperty(action, PROP_DISPOSITION_AS_OF, dispositionActionDate); + if (dsNextAction.getWriteMode().equals(WriteMode.DateAndName)) + { + nodeService.setProperty(action, PROP_DISPOSITION_ACTION_NAME, dispositionActionName); + } + return null; + } + }); } - else - { - diNodeRef = setRecordNextDispositionActionLatestDate(nodeRef, recordFolders, nextDispositionAction); - } - - if (nextDispositionAction == null) - { - return null; - } + dsNodeRef = dsNextAction.getDispositionNodeRef(); } else { // Get the disposition instructions for the node reference provided - diNodeRef = getDispositionScheduleImpl(nodeRef); + dsNodeRef = getDispositionScheduleImpl(nodeRef); } - if (diNodeRef != null) + if (dsNodeRef != null) { - ds = new DispositionScheduleImpl(serviceRegistry, nodeService, diNodeRef); + ds = new DispositionScheduleImpl(serviceRegistry, nodeService, dsNodeRef); } return ds; @@ -1082,7 +1078,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl } } } - return null;// throw exception? poate nu are actiuni cu numele dat ca param + return null; } /** @@ -1133,16 +1129,47 @@ public class DispositionServiceImpl extends ServiceBaseImpl }); } - class DispositionScheduleAndNextAction + class NextActionFromDisposition { + public NextActionFromDisposition(NodeRef dispositionNodeRef, NodeRef nextActionNodeRef, + String nextActionName, Date nextActionDateAsOf, WriteMode writeMode) + { + super(); + this.dispositionNodeRef = dispositionNodeRef; + this.nextActionNodeRef = nextActionNodeRef; + this.nextActionName = nextActionName; + this.nextActionDateAsOf = nextActionDateAsOf; + this.writeMode = writeMode; + } + private NodeRef dispositionNodeRef; - private DispositionAction nextAction; - - public DispositionScheduleAndNextAction(NodeRef dispositionNodeRef, DispositionAction nextAction) + private NodeRef nextActionNodeRef; + + private String nextActionName; + + private Date nextActionDateAsOf; + + private WriteMode writeMode; + + public WriteMode getWriteMode() { - this.dispositionNodeRef = dispositionNodeRef; - this.nextAction = nextAction; + return writeMode; + } + + public void setWriteMode(WriteMode writeMode) + { + this.writeMode = writeMode; + } + + public NodeRef getNextActionNodeRef() + { + return nextActionNodeRef; + } + + public void setNextActionNodeRef(NodeRef nextActionNodeRef) + { + this.nextActionNodeRef = nextActionNodeRef; } public NodeRef getDispositionNodeRef() @@ -1155,120 +1182,122 @@ public class DispositionServiceImpl extends ServiceBaseImpl this.dispositionNodeRef = dispositionNodeRef; } - public DispositionAction getNextAction() + public String getNextActionName() { - return nextAction; + return nextActionName; } - public void setNextAction(DispositionAction nextAction) + public void setNextActionName(String nextActionName) { - this.nextAction = nextAction; + this.nextActionName = nextActionName; + } + + public Date getNextActionDateAsOf() + { + return nextActionDateAsOf; + } + + public void setNextActionDateAsOf(Date nextActionDateAsOf) + { + this.nextActionDateAsOf = nextActionDateAsOf; } - } - /** - * Get the longest period for the given action - * - * @param recordNodeRef - * @param recordFolders - * @param nextDispositionAction - * @return - */ - private NodeRef setRecordNextDispositionActionLatestDate(final NodeRef recordNodeRef, List recordFolders, DispositionAction nextDispositionAction) + /** + * Calculate next disposition action for a record + * + * @param record + * @return next disposition action (name, date) and the disposition associated + */ + + protected NextActionFromDisposition getDispositionActionByNameForRecord(NodeRef record) { - String recordnextDispositionActionName = nextDispositionAction.getName(); - Date recordNextDispositionActionDate = nextDispositionAction.getAsOfDate(); - Date nextDispositionActionDate = null; - NodeRef dispositionNodeRef = null; + List recordFolders = recordFolderService.getRecordFolders(record); + DispositionAction nextDispositionAction = getNextDispositionAction(record); - for (NodeRef folder : recordFolders) + if (nextDispositionAction == null) { - NodeRef dsNodeRef = getDispositionScheduleImpl(folder); - if (dsNodeRef != null) + NodeRef newAction = null; + String newDispositionActionName = null; + Date newDispositionActionDateAsOf = null; + NodeRef dispositionNodeRef = null; + for (NodeRef folder : recordFolders) { - Date dispActionDate = getDispositionActionDate(dsNodeRef, recordnextDispositionActionName); - if (nextDispositionActionDate == null || nextDispositionActionDate.before(dispActionDate)) + NodeRef folderDS = getDispositionScheduleImpl(folder); + if (folderDS != null) { - nextDispositionActionDate = dispActionDate; - dispositionNodeRef = dsNodeRef; - } + List assocs = nodeService.getChildAssocs(folderDS); + if (assocs != null && assocs.size() > 0) + { + NodeRef firstAction = assocs.get(0).getChildRef(); + DispositionAction firstDispositionAction = new DispositionActionImpl(serviceRegistry, firstAction); + + if (newAction == null) + { + newAction = firstAction; + newDispositionActionName = (String)nodeService.getProperty(newAction, PROP_DISPOSITION_ACTION_NAME); + newDispositionActionDateAsOf = getDispositionActionDate(folderDS, newDispositionActionName); + } + else if (firstDispositionAction.getAsOfDate() != null && newDispositionActionDateAsOf.before(firstDispositionAction.getAsOfDate())) + { + newDispositionActionName = (String)nodeService.getProperty(firstAction, PROP_DISPOSITION_ACTION_NAME); + newDispositionActionDateAsOf = firstDispositionAction.getAsOfDate(); + } + dispositionNodeRef = folderDS; + } + } + } + if (newDispositionActionName != null && newDispositionActionDateAsOf != null + && dispositionNodeRef != null && newAction != null) + { + return new NextActionFromDisposition(dispositionNodeRef, newAction, + newDispositionActionName, newDispositionActionDateAsOf, WriteMode.DateAndName); + } + else + { + return null; } } - // set only on record creation or when linking - if (!nextDispositionActionDate.equals(recordNextDispositionActionDate) && recordNextDispositionActionDate.before(nextDispositionActionDate)) + else { - final Date nextDADate = nextDispositionActionDate; + // get the longest period for the given action name + String recordNextDispositionActionName = nextDispositionAction.getName(); + Date recordNextDispositionActionDate = nextDispositionAction.getAsOfDate(); + Date nextDispositionActionDate = null; + NodeRef dispositionNodeRef = null; - AuthenticationUtil.runAsSystem(new RunAsWork() + for (NodeRef folder : recordFolders) { - @Override - public Void doWork() + NodeRef dsNodeRef = getDispositionScheduleImpl(folder); + if (dsNodeRef != null) { - nodeService.setProperty(recordNodeRef, PROP_DISPOSITION_AS_OF, nextDADate); - return null; - } - }); - } - return dispositionNodeRef; - } - - /** - * Calculate next disposition action for a record with the given parents - * - * @param recordFolders parent folders - * @return next disposition action and the disposition associated - */ - private DispositionScheduleAndNextAction getNextDispositionActionFromParents(List recordFolders) - { - NodeRef newAction = null; - String newDispositionActionName = null; - Date newDispositionActionDate = null; - NodeRef dispositionNodeRef = null; - for (NodeRef folder : recordFolders) - { - NodeRef folderDS = getDispositionScheduleImpl(folder); - if (folderDS != null) - { - List assocs = nodeService.getChildAssocs(folderDS); - if (assocs != null && assocs.size() > 0) - { - NodeRef firstAction = assocs.get(0).getChildRef(); - DispositionAction firstDispositionAction = new DispositionActionImpl(serviceRegistry, firstAction); - - if (newAction == null) + Date dispActionDate = getDispositionActionDate(dsNodeRef, recordNextDispositionActionName); + if (nextDispositionActionDate == null || nextDispositionActionDate.before(dispActionDate)) { - newAction = firstAction; - newDispositionActionName = (String)nodeService.getProperty(newAction, PROP_DISPOSITION_ACTION_NAME); - newDispositionActionDate = getDispositionActionDate(folderDS, newDispositionActionName); - dispositionNodeRef = folderDS; - } - else if (firstDispositionAction.getAsOfDate() != null && newDispositionActionDate.before(firstDispositionAction.getAsOfDate())) - { - newDispositionActionName = (String)nodeService.getProperty(firstAction, PROP_DISPOSITION_ACTION_NAME); - newDispositionActionDate = firstDispositionAction.getAsOfDate(); - dispositionNodeRef = folderDS; + nextDispositionActionDate = dispActionDate; + dispositionNodeRef = dsNodeRef; } } } - } - if (newAction != null) { - final NodeRef action = newAction; - final String dispositionActionName = newDispositionActionName; - final Date dispositionActionDate = newDispositionActionDate; - AuthenticationUtil.runAsSystem(new RunAsWork() + if (nextDispositionActionDate != null && dispositionNodeRef != null) { - @Override - public Void doWork() + WriteMode mode = null; + if (!nextDispositionActionDate.equals(recordNextDispositionActionDate) + && recordNextDispositionActionDate.before(nextDispositionActionDate)) { - nodeService.setProperty(action, PROP_DISPOSITION_ACTION_NAME, dispositionActionName); - nodeService.setProperty(action, PROP_DISPOSITION_AS_OF, dispositionActionDate); - return null; + mode = WriteMode.DateOnly; } - }); - DispositionAction dsAction = new DispositionActionImpl(serviceRegistry, action); - return new DispositionScheduleAndNextAction(dispositionNodeRef, dsAction); + else + { + mode = WriteMode.ReadOnly; + } + return new NextActionFromDisposition(dispositionNodeRef, nextDispositionAction.getNodeRef(), + recordNextDispositionActionName, nextDispositionActionDate, mode); + } + else + { + return null; + } } - return null; } } From f0370a443b4f4aa6b1278effa87fedb01ff1d928 Mon Sep 17 00:00:00 2001 From: roxana Date: Sun, 9 Oct 2016 20:50:28 +0300 Subject: [PATCH 04/17] Addresed code review comments. --- .../DispositionSelectionStrategy.java | 199 ------------- .../disposition/DispositionServiceImpl.java | 264 +++++++----------- .../NextActionFromDisposition.java | 80 ++++++ 3 files changed, 177 insertions(+), 366 deletions(-) delete mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionSelectionStrategy.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/NextActionFromDisposition.java diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionSelectionStrategy.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionSelectionStrategy.java deleted file mode 100644 index d341c71295..0000000000 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionSelectionStrategy.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * 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.disposition; - -import java.util.Comparator; -import java.util.Date; -import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; - -import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; -import org.alfresco.service.cmr.repository.NodeRef; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class offers the default implementation of a strategy for selection of - * disposition schedule for a record when there is more than one which is applicable. - * An example of where this strategy might be used would be in the case of a record - * which was multiply filed. - * - * @author neilm - */ -public class DispositionSelectionStrategy implements RecordsManagementModel -{ - /** Logger */ - private static Log logger = LogFactory.getLog(DispositionSelectionStrategy.class); - - /** Disposition service */ - private DispositionService dispositionService; - - /** - * Set the disposition service - * - * @param dispositionService disposition service - */ - public void setDispositionService(DispositionService dispositionService) - { - this.dispositionService = dispositionService; - } - - /** - * Select the disposition schedule to use given there is more than one - * - * @param recordFolders - * @return - */ - public NodeRef selectDispositionScheduleFrom(List recordFolders) - { - if (recordFolders == null || recordFolders.isEmpty()) - { - return null; - } - else - { - // 46 CHAPTER 2 - // Records assigned more than 1 disposition must be retained and linked to the record folder (category) with the longest - // retention period. - - // Assumption: an event-based disposition action has a longer retention - // period than a time-based one - as we cannot know when an event will occur - // TODO Automatic events? - - NodeRef recordFolder = null; - if (recordFolders.size() == 1) - { - recordFolder = recordFolders.get(0); - } - else - { - SortedSet sortedFolders = new TreeSet(new DispositionableNodeRefComparator()); - sortedFolders.addAll(recordFolders); - recordFolder = sortedFolders.first(); - } - - DispositionSchedule dispSchedule = dispositionService.getDispositionSchedule(recordFolder); - - if (logger.isDebugEnabled()) - { - logger.debug("Selected disposition schedule: " + dispSchedule); - } - - NodeRef result = null; - if (dispSchedule != null) - { - result = dispSchedule.getNodeRef(); - } - return result; - } - } - - /** - * This class defines a natural comparison order between NodeRefs that have - * the dispositionLifecycle aspect applied. - * This order has the following meaning: NodeRefs with a 'lesser' value are considered - * to have a shorter retention period, although the actual retention period may - * not be straightforwardly determined in all cases. - */ - class DispositionableNodeRefComparator implements Comparator - { - public int compare(final NodeRef f1, final NodeRef f2) - { - // Run as admin user - return AuthenticationUtil.runAs(new RunAsWork() - { - public Integer doWork() - { - return compareImpl(f1, f2); - } - }, AuthenticationUtil.getAdminUserName()); - } - - private int compareImpl(NodeRef f1, NodeRef f2) - { - // quick check to see if the node references are the same - if (f1.equals(f2)) - { - return 0; - } - - // get the disposition schedules for the folders - DispositionSchedule ds1 = dispositionService.getDispositionSchedule(f1); - DispositionSchedule ds2 = dispositionService.getDispositionSchedule(f2); - - // make sure each folder has a disposition schedule - if (ds1 == null && ds2 != null) - { - return 1; - } - else if (ds1 != null && ds2 == null) - { - return -1; - } - else if (ds1 == null && ds2 == null) - { - return 0; - } - - // TODO this won't work correctly if we are trying to compare schedules that are record based!! - DispositionAction da1 = dispositionService.getNextDispositionAction(f1); - DispositionAction da2 = dispositionService.getNextDispositionAction(f2); - - if (da1 != null && da2 != null) - { - Date asOfDate1 = da1.getAsOfDate(); - Date asOfDate2 = da2.getAsOfDate(); - // If both record(Folder)s have asOfDates, then use these to compare - if (asOfDate1 != null && asOfDate2 != null) - { - return asOfDate1.compareTo(asOfDate2); - } - // If one has a date and the other doesn't, the one with the date is "less". - // (Defined date is 'shorter' than undefined date as an undefined date means it may be retained forever - theoretically) - else if (asOfDate1 != null || asOfDate2 != null) - { - return asOfDate1 == null ? +1 : -1; - } - else - { - // Neither has an asOfDate. (Somewhat arbitrarily) we'll use the number of events to compare now. - DispositionActionDefinition dad1 = da1.getDispositionActionDefinition(); - DispositionActionDefinition dad2 = da2.getDispositionActionDefinition(); - int eventsCount1 = 0; - int eventsCount2 = 0; - - if (dad1 != null) - { - eventsCount1 = dad1.getEvents().size(); - } - if (dad2 != null) - { - eventsCount2 = dad2.getEvents().size(); - } - return Integer.valueOf(eventsCount1).compareTo(eventsCount2); - } - } - - return 0; - } - } -} \ No newline at end of file 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 22f3c6fc6f..79e86ec705 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 @@ -71,7 +71,8 @@ public class DispositionServiceImpl extends ServiceBaseImpl /** Logger */ private static Log logger = LogFactory.getLog(DispositionServiceImpl.class); - public enum WriteMode {ReadOnly, DateOnly, DateAndName}; + /** Transaction mode for setting next action */ + public enum WriteMode {READ_ONLY, DATE_ONLY, DATE_AND_NAME}; /** Behaviour filter */ private BehaviourFilter behaviourFilter; @@ -79,9 +80,6 @@ public class DispositionServiceImpl extends ServiceBaseImpl /** Records management service registry */ private RecordsManagementServiceRegistry serviceRegistry; - /** Disposition selection strategy */ - private DispositionSelectionStrategy dispositionSelectionStrategy; - /** File plan service */ private FilePlanService filePlanService; @@ -171,16 +169,6 @@ public class DispositionServiceImpl extends ServiceBaseImpl this.freezeService = freezeService; } - /** - * Set the dispositionSelectionStrategy bean. - * - * @param dispositionSelectionStrategy - */ - public void setDispositionSelectionStrategy(DispositionSelectionStrategy dispositionSelectionStrategy) - { - this.dispositionSelectionStrategy = dispositionSelectionStrategy; - } - /** * Behavior to initialize the disposition schedule of a newly filed record. * @@ -278,7 +266,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl { final NextActionFromDisposition dsNextAction = getDispositionActionByNameForRecord(nodeRef); - if (!dsNextAction.getWriteMode().equals(WriteMode.ReadOnly)) + if (dsNextAction != null && !dsNextAction.getWriteMode().equals(WriteMode.READ_ONLY)) { final NodeRef action = dsNextAction.getNextActionNodeRef(); final String dispositionActionName = dsNextAction.getNextActionName(); @@ -290,7 +278,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl public Void doWork() { nodeService.setProperty(action, PROP_DISPOSITION_AS_OF, dispositionActionDate); - if (dsNextAction.getWriteMode().equals(WriteMode.DateAndName)) + if (dsNextAction.getWriteMode().equals(WriteMode.DATE_AND_NAME)) { nodeService.setProperty(action, PROP_DISPOSITION_ACTION_NAME, dispositionActionName); } @@ -1129,79 +1117,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl }); } - class NextActionFromDisposition - { - public NextActionFromDisposition(NodeRef dispositionNodeRef, NodeRef nextActionNodeRef, - String nextActionName, Date nextActionDateAsOf, WriteMode writeMode) - { - super(); - this.dispositionNodeRef = dispositionNodeRef; - this.nextActionNodeRef = nextActionNodeRef; - this.nextActionName = nextActionName; - this.nextActionDateAsOf = nextActionDateAsOf; - this.writeMode = writeMode; - } - - private NodeRef dispositionNodeRef; - - private NodeRef nextActionNodeRef; - - private String nextActionName; - - private Date nextActionDateAsOf; - - private WriteMode writeMode; - - public WriteMode getWriteMode() - { - return writeMode; - } - - public void setWriteMode(WriteMode writeMode) - { - this.writeMode = writeMode; - } - - public NodeRef getNextActionNodeRef() - { - return nextActionNodeRef; - } - - public void setNextActionNodeRef(NodeRef nextActionNodeRef) - { - this.nextActionNodeRef = nextActionNodeRef; - } - - public NodeRef getDispositionNodeRef() - { - return dispositionNodeRef; - } - - public void setDispositionNodeRef(NodeRef dispositionNodeRef) - { - this.dispositionNodeRef = dispositionNodeRef; - } - - public String getNextActionName() - { - return nextActionName; - } - - public void setNextActionName(String nextActionName) - { - this.nextActionName = nextActionName; - } - - public Date getNextActionDateAsOf() - { - return nextActionDateAsOf; - } - - public void setNextActionDateAsOf(Date nextActionDateAsOf) - { - this.nextActionDateAsOf = nextActionDateAsOf; - } - } + /** * Calculate next disposition action for a record @@ -1217,87 +1133,101 @@ public class DispositionServiceImpl extends ServiceBaseImpl if (nextDispositionAction == null) { - NodeRef newAction = null; - String newDispositionActionName = null; - Date newDispositionActionDateAsOf = null; - NodeRef dispositionNodeRef = null; - for (NodeRef folder : recordFolders) - { - NodeRef folderDS = getDispositionScheduleImpl(folder); - if (folderDS != null) - { - List assocs = nodeService.getChildAssocs(folderDS); - if (assocs != null && assocs.size() > 0) - { - NodeRef firstAction = assocs.get(0).getChildRef(); - DispositionAction firstDispositionAction = new DispositionActionImpl(serviceRegistry, firstAction); - - if (newAction == null) - { - newAction = firstAction; - newDispositionActionName = (String)nodeService.getProperty(newAction, PROP_DISPOSITION_ACTION_NAME); - newDispositionActionDateAsOf = getDispositionActionDate(folderDS, newDispositionActionName); - } - else if (firstDispositionAction.getAsOfDate() != null && newDispositionActionDateAsOf.before(firstDispositionAction.getAsOfDate())) - { - newDispositionActionName = (String)nodeService.getProperty(firstAction, PROP_DISPOSITION_ACTION_NAME); - newDispositionActionDateAsOf = firstDispositionAction.getAsOfDate(); - } - dispositionNodeRef = folderDS; - } - } - } - if (newDispositionActionName != null && newDispositionActionDateAsOf != null - && dispositionNodeRef != null && newAction != null) - { - return new NextActionFromDisposition(dispositionNodeRef, newAction, - newDispositionActionName, newDispositionActionDateAsOf, WriteMode.DateAndName); - } - else - { - return null; - } + return getFirstDispositionAction(recordFolders); } else { - // get the longest period for the given action name - String recordNextDispositionActionName = nextDispositionAction.getName(); - Date recordNextDispositionActionDate = nextDispositionAction.getAsOfDate(); - Date nextDispositionActionDate = null; - NodeRef dispositionNodeRef = null; - - for (NodeRef folder : recordFolders) - { - NodeRef dsNodeRef = getDispositionScheduleImpl(folder); - if (dsNodeRef != null) - { - Date dispActionDate = getDispositionActionDate(dsNodeRef, recordNextDispositionActionName); - if (nextDispositionActionDate == null || nextDispositionActionDate.before(dispActionDate)) - { - nextDispositionActionDate = dispActionDate; - dispositionNodeRef = dsNodeRef; - } - } - } - if (nextDispositionActionDate != null && dispositionNodeRef != null) - { - WriteMode mode = null; - if (!nextDispositionActionDate.equals(recordNextDispositionActionDate) - && recordNextDispositionActionDate.before(nextDispositionActionDate)) - { - mode = WriteMode.DateOnly; - } - else - { - mode = WriteMode.ReadOnly; - } - return new NextActionFromDisposition(dispositionNodeRef, nextDispositionAction.getNodeRef(), - recordNextDispositionActionName, nextDispositionActionDate, mode); - } - else - { - return null; - } + return getNextDispositionAction(recordFolders, nextDispositionAction); } } + + /** + * Calculate next disposition action when the record already has one + * @param recordFolders + * @param nextDispositionAction + * @return next disposition action and the associated disposition schedule + */ + private NextActionFromDisposition getNextDispositionAction(List recordFolders, DispositionAction nextDispositionAction) + { + String recordNextDispositionActionName = nextDispositionAction.getName(); + Date recordNextDispositionActionDate = nextDispositionAction.getAsOfDate(); + Date nextDispositionActionDate = null; + NodeRef dispositionNodeRef = null; + + for (NodeRef folder : recordFolders) + { + NodeRef dsNodeRef = getDispositionScheduleImpl(folder); + if (dsNodeRef != null) + { + Date dispActionDate = getDispositionActionDate(dsNodeRef, recordNextDispositionActionName); + if (nextDispositionActionDate == null || nextDispositionActionDate.before(dispActionDate)) + { + nextDispositionActionDate = dispActionDate; + dispositionNodeRef = dsNodeRef; + } + } + } + if (nextDispositionActionDate == null || dispositionNodeRef == null) + { + return null; + } + WriteMode mode = null; + if (!nextDispositionActionDate.equals(recordNextDispositionActionDate) + && recordNextDispositionActionDate.before(nextDispositionActionDate)) + { + mode = WriteMode.DATE_ONLY; + } + else + { + mode = WriteMode.READ_ONLY; + } + return new NextActionFromDisposition(dispositionNodeRef, nextDispositionAction.getNodeRef(), + recordNextDispositionActionName, nextDispositionActionDate, mode); + } + + /** + * Calculate first disposition action when the record doesn't have one + * @param recordFolders + * @return next disposition action and the associated disposition schedule + */ + private NextActionFromDisposition getFirstDispositionAction(List recordFolders) + { + NodeRef newAction = null; + String newDispositionActionName = null; + Date newDispositionActionDateAsOf = null; + NodeRef dispositionNodeRef = null; + for (NodeRef folder : recordFolders) + { + NodeRef folderDS = getDispositionScheduleImpl(folder); + if (folderDS != null) + { + List assocs = nodeService.getChildAssocs(folderDS); + if (assocs != null && assocs.size() > 0) + { + NodeRef firstAction = assocs.get(0).getChildRef(); + DispositionAction firstDispositionAction = new DispositionActionImpl(serviceRegistry, firstAction); + + if (newAction == null) + { + newAction = firstAction; + newDispositionActionName = (String)nodeService.getProperty(newAction, PROP_DISPOSITION_ACTION_NAME); + newDispositionActionDateAsOf = getDispositionActionDate(folderDS, newDispositionActionName); + } + else if (firstDispositionAction.getAsOfDate() != null && newDispositionActionDateAsOf.before(firstDispositionAction.getAsOfDate())) + { + newDispositionActionName = (String)nodeService.getProperty(firstAction, PROP_DISPOSITION_ACTION_NAME); + newDispositionActionDateAsOf = firstDispositionAction.getAsOfDate(); + } + dispositionNodeRef = folderDS; + } + } + } + if (newDispositionActionName == null || newDispositionActionDateAsOf == null + || dispositionNodeRef == null || newAction == null) + { + return null; + } + return new NextActionFromDisposition(dispositionNodeRef, newAction, + newDispositionActionName, newDispositionActionDateAsOf, WriteMode.DATE_AND_NAME); + } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/NextActionFromDisposition.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/NextActionFromDisposition.java new file mode 100644 index 0000000000..377b0a23fd --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/NextActionFromDisposition.java @@ -0,0 +1,80 @@ +package org.alfresco.module.org_alfresco_module_rm.disposition; + +import java.util.Date; + +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionServiceImpl.WriteMode; +import org.alfresco.service.cmr.repository.NodeRef; + +public class NextActionFromDisposition +{ + public NextActionFromDisposition(NodeRef dispositionNodeRef, NodeRef nextActionNodeRef, String nextActionName, Date nextActionDateAsOf, + WriteMode writeMode) + { + super(); + this.dispositionNodeRef = dispositionNodeRef; + this.nextActionNodeRef = nextActionNodeRef; + this.nextActionName = nextActionName; + this.nextActionDateAsOf = nextActionDateAsOf; + this.writeMode = writeMode; + } + + private NodeRef dispositionNodeRef; + + private NodeRef nextActionNodeRef; + + private String nextActionName; + + private Date nextActionDateAsOf; + + private WriteMode writeMode; + + public WriteMode getWriteMode() + { + return writeMode; + } + + public void setWriteMode(WriteMode writeMode) + { + this.writeMode = writeMode; + } + + public NodeRef getNextActionNodeRef() + { + return nextActionNodeRef; + } + + public void setNextActionNodeRef(NodeRef nextActionNodeRef) + { + this.nextActionNodeRef = nextActionNodeRef; + } + + public NodeRef getDispositionNodeRef() + { + return dispositionNodeRef; + } + + public void setDispositionNodeRef(NodeRef dispositionNodeRef) + { + this.dispositionNodeRef = dispositionNodeRef; + } + + public String getNextActionName() + { + return nextActionName; + } + + public void setNextActionName(String nextActionName) + { + this.nextActionName = nextActionName; + } + + public Date getNextActionDateAsOf() + { + return nextActionDateAsOf; + } + + public void setNextActionDateAsOf(Date nextActionDateAsOf) + { + this.nextActionDateAsOf = nextActionDateAsOf; + } +} From 181ab39f2d96af505ebd6a94ef072feb40479ed3 Mon Sep 17 00:00:00 2001 From: roxana Date: Sun, 9 Oct 2016 21:51:09 +0300 Subject: [PATCH 05/17] Removed disposition selection strategy. --- .../module/org_alfresco_module_rm/rm-service-context.xml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml index 0ed6c73149..c94fdde3ae 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml @@ -39,12 +39,6 @@ - - - - - @@ -96,9 +90,6 @@ - - - From f55111fe6cf8d4a13a2d519163d27c13672a0ff9 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 10 Oct 2016 14:45:06 +0100 Subject: [PATCH 06/17] RM-2526 Fix NPE found by integration tests. --- .../disposition/DispositionServiceImpl.java | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) 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 141a2cc5f6..e6995670cf 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 @@ -70,7 +70,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl { /** Logger */ private static final Logger LOGGER = LoggerFactory.getLogger(DispositionServiceImpl.class); - + /** Transaction mode for setting next action */ public enum WriteMode {READ_ONLY, DATE_ONLY, DATE_AND_NAME}; @@ -265,28 +265,28 @@ public class DispositionServiceImpl extends ServiceBaseImpl if (isRecord(nodeRef)) { final NextActionFromDisposition dsNextAction = getDispositionActionByNameForRecord(nodeRef); - + if (dsNextAction != null && !dsNextAction.getWriteMode().equals(WriteMode.READ_ONLY)) { final NodeRef action = dsNextAction.getNextActionNodeRef(); final String dispositionActionName = dsNextAction.getNextActionName(); final Date dispositionActionDate = dsNextAction.getNextActionDateAsOf(); - - AuthenticationUtil.runAsSystem(new RunAsWork() + + AuthenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() { - @Override - public Void doWork() + nodeService.setProperty(action, PROP_DISPOSITION_AS_OF, dispositionActionDate); + if (dsNextAction.getWriteMode().equals(WriteMode.DATE_AND_NAME)) { - nodeService.setProperty(action, PROP_DISPOSITION_AS_OF, dispositionActionDate); - if (dsNextAction.getWriteMode().equals(WriteMode.DATE_AND_NAME)) - { - nodeService.setProperty(action, PROP_DISPOSITION_ACTION_NAME, dispositionActionName); - } - return null; + nodeService.setProperty(action, PROP_DISPOSITION_ACTION_NAME, dispositionActionName); } - }); + return null; + } + }); + dsNodeRef = dsNextAction.getDispositionNodeRef(); } - dsNodeRef = dsNextAction.getDispositionNodeRef(); } else { @@ -298,12 +298,12 @@ public class DispositionServiceImpl extends ServiceBaseImpl { ds = new DispositionScheduleImpl(serviceRegistry, nodeService, dsNodeRef); } - + return ds; } - - + + /** * This method returns a NodeRef @@ -909,7 +909,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl // Get the current action String currentADId = (String) nodeService.getProperty(currentDispositionAction, PROP_DISPOSITION_ACTION_ID); currentDispositionActionDefinition = di.getDispositionActionDefinition(currentADId); - + // When the record has multiple disposition schedules the current disposition action may not be found by id // In this case it will be searched by name if(currentDispositionActionDefinition == null) @@ -1076,21 +1076,21 @@ public class DispositionServiceImpl extends ServiceBaseImpl } }); } - - - + + + /** * Calculate next disposition action for a record - * + * * @param record * @return next disposition action (name, date) and the disposition associated */ - - protected NextActionFromDisposition getDispositionActionByNameForRecord(NodeRef record) + + protected NextActionFromDisposition getDispositionActionByNameForRecord(NodeRef record) { List recordFolders = recordFolderService.getRecordFolders(record); DispositionAction nextDispositionAction = getNextDispositionAction(record); - + if (nextDispositionAction == null) { return getFirstDispositionAction(recordFolders); @@ -1113,7 +1113,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl Date recordNextDispositionActionDate = nextDispositionAction.getAsOfDate(); Date nextDispositionActionDate = null; NodeRef dispositionNodeRef = null; - + for (NodeRef folder : recordFolders) { NodeRef dsNodeRef = getDispositionScheduleImpl(folder); @@ -1132,7 +1132,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl return null; } WriteMode mode = null; - if (!nextDispositionActionDate.equals(recordNextDispositionActionDate) + if (!nextDispositionActionDate.equals(recordNextDispositionActionDate) && recordNextDispositionActionDate.before(nextDispositionActionDate)) { mode = WriteMode.DATE_ONLY; @@ -1141,7 +1141,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl { mode = WriteMode.READ_ONLY; } - return new NextActionFromDisposition(dispositionNodeRef, nextDispositionAction.getNodeRef(), + return new NextActionFromDisposition(dispositionNodeRef, nextDispositionAction.getNodeRef(), recordNextDispositionActionName, nextDispositionActionDate, mode); } @@ -1156,7 +1156,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl String newDispositionActionName = null; Date newDispositionActionDateAsOf = null; NodeRef dispositionNodeRef = null; - for (NodeRef folder : recordFolders) + for (NodeRef folder : recordFolders) { NodeRef folderDS = getDispositionScheduleImpl(folder); if (folderDS != null) @@ -1166,13 +1166,13 @@ public class DispositionServiceImpl extends ServiceBaseImpl { NodeRef firstAction = assocs.get(0).getChildRef(); DispositionAction firstDispositionAction = new DispositionActionImpl(serviceRegistry, firstAction); - + if (newAction == null) { newAction = firstAction; newDispositionActionName = (String)nodeService.getProperty(newAction, PROP_DISPOSITION_ACTION_NAME); newDispositionActionDateAsOf = getDispositionActionDate(folderDS, newDispositionActionName); - } + } else if (firstDispositionAction.getAsOfDate() != null && newDispositionActionDateAsOf.before(firstDispositionAction.getAsOfDate())) { newDispositionActionName = (String)nodeService.getProperty(firstAction, PROP_DISPOSITION_ACTION_NAME); @@ -1182,12 +1182,12 @@ public class DispositionServiceImpl extends ServiceBaseImpl } } } - if (newDispositionActionName == null || newDispositionActionDateAsOf == null + if (newDispositionActionName == null || newDispositionActionDateAsOf == null || dispositionNodeRef == null || newAction == null) { return null; } - return new NextActionFromDisposition(dispositionNodeRef, newAction, + return new NextActionFromDisposition(dispositionNodeRef, newAction, newDispositionActionName, newDispositionActionDateAsOf, WriteMode.DATE_AND_NAME); } } From 6b2183fb67a2cd61a4a3abcfc04298493dfd518b Mon Sep 17 00:00:00 2001 From: roxana Date: Mon, 10 Oct 2016 16:50:21 +0300 Subject: [PATCH 07/17] Moved UpdateNextDispositionActionTest/ --- .../disposition/DispositionServiceImpl.java | 2 +- .../UpdateNextDispositionActionTest.java | 140 ++++++++++++++++++ 2 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java 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 79e86ec705..920bc24eb3 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 @@ -285,8 +285,8 @@ public class DispositionServiceImpl extends ServiceBaseImpl return null; } }); + dsNodeRef = dsNextAction.getDispositionNodeRef(); } - dsNodeRef = dsNextAction.getDispositionNodeRef(); } else { diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java new file mode 100644 index 0000000000..81e5043c9f --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java @@ -0,0 +1,140 @@ +/* + * 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.test.integration.disposition; + +import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_DISPOSITION_DESCRIPTION; +import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_DISPOSITION_INSTRUCTIONS; +import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_EVENT_NAME; +import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.PERIOD_ONE_WEEK; +import static org.alfresco.util.GUID.generate; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.module.org_alfresco_module_rm.action.impl.CutOffAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.DestroyAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.EditDispositionActionAsOfDateAction; +import org.alfresco.module.org_alfresco_module_rm.action.impl.TransferAction; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; + +/** +* Update next disposition step integration tests. +* +* @author Roxana Lucanu +* @since 2.3.1 +*/ +public class UpdateNextDispositionActionTest extends BaseRMTestCase +{ + /** + * Given a record with multiple dispositions + * When updating the next step + * Then the action is available + *

+ * relates to https://issues.alfresco.com/jira/browse/RM-3060 + */ + public void testUpdateNextDispositionAction_RM3060() throws Exception + { + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + NodeRef record; + NodeRef folder2; + + @Override + public void given() + { + // create category1 + NodeRef category1 = filePlanService.createRecordCategory(filePlan, generate()); + + // create disposition schedule for category1 + createDispositionSchedule(category1); + + // create category2 + NodeRef category2 = filePlanService.createRecordCategory(filePlan, generate()); + + // create disposition schedule for category2 + createDispositionSchedule(category2); + + // create folder2 inside category2 + folder2 = recordFolderService.createRecordFolder(category2, generate()); + + // create folder1 inside category1 + NodeRef folder1 = recordFolderService.createRecordFolder(category1, generate()); + + // create record inside folder1 + record = utils.createRecord(folder1, generate(), generate()); + + } + @Override + public void when() throws Exception + { + // link the record to folder2 + recordService.link(record, folder2); + + // complete record + utils.completeRecord(record); + + // set the disposition as of date to now on the record + rmActionService.executeRecordsManagementAction(record, + EditDispositionActionAsOfDateAction.NAME, + Collections.singletonMap(EditDispositionActionAsOfDateAction.PARAM_AS_OF_DATE, new Date())); + + // cut off + rmActionService.executeRecordsManagementAction(record, CutOffAction.NAME, null); + } + + @Override + public void then() throws Exception + { + assertTrue("Record " + record + " doesn't have the cutOff aspect.", nodeService.hasAspect(record, ASPECT_CUT_OFF)); + } + }); + } + + private void createDispositionSchedule(NodeRef category) + { + DispositionSchedule ds = utils.createDispositionSchedule(category, DEFAULT_DISPOSITION_INSTRUCTIONS, DEFAULT_DISPOSITION_DESCRIPTION, true, false, false); + + // create the properties for CUTOFF action and add it to the disposition action definition + Map cutOff = new HashMap(3); + cutOff.put(PROP_DISPOSITION_ACTION_NAME, CutOffAction.NAME); + cutOff.put(PROP_DISPOSITION_DESCRIPTION, generate()); + cutOff.put(PROP_DISPOSITION_PERIOD, PERIOD_ONE_WEEK); + dispositionService.addDispositionActionDefinition(ds, cutOff); + + // create the properties for TRANSFER action and add it to the disposition action definition + Map transfer = new HashMap(3); + transfer.put(PROP_DISPOSITION_ACTION_NAME, TransferAction.NAME); + transfer.put(PROP_DISPOSITION_DESCRIPTION, generate()); + transfer.put(PROP_DISPOSITION_EVENT, (Serializable)Collections.singletonList(DEFAULT_EVENT_NAME)); + dispositionService.addDispositionActionDefinition(ds, transfer); + + // create the properties for DESTROY action and add it to the disposition action definition + Map destroy = new HashMap(3); + destroy.put(PROP_DISPOSITION_ACTION_NAME, DestroyAction.NAME); + destroy.put(PROP_DISPOSITION_DESCRIPTION, generate()); + destroy.put(PROP_DISPOSITION_PERIOD, PERIOD_ONE_WEEK); + dispositionService.addDispositionActionDefinition(ds, destroy); + } +} \ No newline at end of file From 2b125f75932b6d218e2aab79651bcba202f52ae6 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 10 Oct 2016 15:20:45 +0100 Subject: [PATCH 08/17] RM-2526 Remove unwanted extra copy of cherry-picked test file. --- .../UpdateNextDispositionActionTest.java | 148 ------------------ 1 file changed, 148 deletions(-) delete mode 100644 rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java deleted file mode 100644 index 462198f5a7..0000000000 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * #%L - * Alfresco Records Management Module - * %% - * 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 . - * #L% - */ -package org.alfresco.module.org_alfresco_module_rm.test.integration.disposition; - -import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_DISPOSITION_DESCRIPTION; -import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_DISPOSITION_INSTRUCTIONS; -import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.DEFAULT_EVENT_NAME; -import static org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils.PERIOD_ONE_WEEK; -import static org.alfresco.util.GUID.generate; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import org.alfresco.module.org_alfresco_module_rm.action.impl.CutOffAction; -import org.alfresco.module.org_alfresco_module_rm.action.impl.DestroyAction; -import org.alfresco.module.org_alfresco_module_rm.action.impl.EditDispositionActionAsOfDateAction; -import org.alfresco.module.org_alfresco_module_rm.action.impl.TransferAction; -import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; -import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.namespace.QName; - -/** -* Update next disposition step integration tests. -* -* @author Roxana Lucanu -* @since 2.4.1 -*/ -public class UpdateNextDispositionActionTest extends BaseRMTestCase -{ - /** - * Given a record with multiple dispositions - * When updating the next step - * Then the action is available - *

- * relates to https://issues.alfresco.com/jira/browse/RM-3060 - */ - public void testUpdateNextDispositionAction_RM3060() throws Exception - { - doBehaviourDrivenTest(new BehaviourDrivenTest() - { - NodeRef record; - NodeRef folder2; - - @Override - public void given() - { - // create category1 - NodeRef category1 = filePlanService.createRecordCategory(filePlan, generate()); - - // create disposition schedule for category1 - createDispositionSchedule(category1); - - // create category2 - NodeRef category2 = filePlanService.createRecordCategory(filePlan, generate()); - - // create disposition schedule for category2 - createDispositionSchedule(category2); - - // create folder2 inside category2 - folder2 = recordFolderService.createRecordFolder(category2, generate()); - - // create folder1 inside category1 - NodeRef folder1 = recordFolderService.createRecordFolder(category1, generate()); - - // create record inside folder1 - record = utils.createRecord(folder1, generate(), generate()); - - } - @Override - public void when() throws Exception - { - // link the record to folder2 - recordService.link(record, folder2); - - // complete record - utils.completeRecord(record); - - // set the disposition as of date to now on the record - rmActionService.executeRecordsManagementAction(record, - EditDispositionActionAsOfDateAction.NAME, - Collections.singletonMap(EditDispositionActionAsOfDateAction.PARAM_AS_OF_DATE, new Date())); - - // cut off - rmActionService.executeRecordsManagementAction(record, CutOffAction.NAME, null); - } - - @Override - public void then() throws Exception - { - assertTrue(nodeService.hasAspect(record, ASPECT_CUT_OFF)); - } - }); - } - - private void createDispositionSchedule(NodeRef category) - { - DispositionSchedule ds = utils.createDispositionSchedule(category, DEFAULT_DISPOSITION_INSTRUCTIONS, DEFAULT_DISPOSITION_DESCRIPTION, true, false, false); - - // create the properties for CUTOFF action and add it to the disposition action definition - Map cutOff = new HashMap(3); - cutOff.put(PROP_DISPOSITION_ACTION_NAME, CutOffAction.NAME); - cutOff.put(PROP_DISPOSITION_DESCRIPTION, generate()); - cutOff.put(PROP_DISPOSITION_PERIOD, PERIOD_ONE_WEEK); - dispositionService.addDispositionActionDefinition(ds, cutOff); - - // create the properties for TRANSFER action and add it to the disposition action definition - Map transfer = new HashMap(3); - transfer.put(PROP_DISPOSITION_ACTION_NAME, TransferAction.NAME); - transfer.put(PROP_DISPOSITION_DESCRIPTION, generate()); - transfer.put(PROP_DISPOSITION_EVENT, (Serializable)Collections.singletonList(DEFAULT_EVENT_NAME)); - dispositionService.addDispositionActionDefinition(ds, transfer); - - // create the properties for DESTROY action and add it to the disposition action definition - Map destroy = new HashMap(3); - destroy.put(PROP_DISPOSITION_ACTION_NAME, DestroyAction.NAME); - destroy.put(PROP_DISPOSITION_DESCRIPTION, generate()); - destroy.put(PROP_DISPOSITION_PERIOD, PERIOD_ONE_WEEK); - dispositionService.addDispositionActionDefinition(ds, destroy); - } -} \ No newline at end of file From d13850dd6ecc9c4c5a7777b7c65f0fc57eb61e84 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 10 Oct 2016 15:29:38 +0100 Subject: [PATCH 09/17] RM-2526 Add cherry-picked test to test suite. Nb. The test currently fails at the moment. --- .../test/integration/disposition/DispositionTestSuite.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionTestSuite.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionTestSuite.java index e1938d1d28..a2bbacb70d 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionTestSuite.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/DispositionTestSuite.java @@ -32,7 +32,8 @@ import org.junit.runners.Suite.SuiteClasses; @SuiteClasses( { CutOffTest.class, - UpdateDispositionScheduleTest.class + UpdateDispositionScheduleTest.class, + UpdateNextDispositionActionTest.class }) public class DispositionTestSuite { From d9bb9b2e00f12b31674c9a567046712276fa7df7 Mon Sep 17 00:00:00 2001 From: roxana Date: Tue, 11 Oct 2016 12:28:07 +0300 Subject: [PATCH 10/17] I've changed the method that calculates the as of date to take in consideration the record creation date instead of the action creation date. --- .../disposition/DispositionService.java | 3 ++- .../disposition/DispositionServiceImpl.java | 18 +++++++++--------- .../UpdateNextDispositionActionTest.java | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java index f5f6489cc8..4c0136733c 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java @@ -238,11 +238,12 @@ public interface DispositionService * Gets date of the disposition action for the given * disposition schedule with the given action name * + * @param record * @param dispositionSchedule nodeRef * @param dispositionActionName * @return date */ - Date getDispositionActionDate(NodeRef dispositionSchedule, String dispositionActionName); + Date getDispositionActionDate(NodeRef record, NodeRef dispositionSchedule, String dispositionActionName); /** * Compute the "disposition as of" date (if necessary) for a disposition action and a node. 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 e6995670cf..c18528b397 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 @@ -1004,7 +1004,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl } } - public Date getDispositionActionDate(NodeRef dispositionSchedule, String dispositionActionName) + public Date getDispositionActionDate(NodeRef record, NodeRef dispositionSchedule, String dispositionActionName) { List assocs = nodeService.getChildAssocs(dispositionSchedule); if (assocs != null && assocs.size() > 0) @@ -1015,12 +1015,12 @@ public class DispositionServiceImpl extends ServiceBaseImpl { Date newAsOfDate = null; Period dispositionPeriod = (Period) nodeService.getProperty(assoc.getChildRef(), PROP_DISPOSITION_PERIOD); - Date actionCreationDate = (Date)nodeService.getProperty(assoc.getChildRef(), ContentModel.PROP_CREATED); + Date recordCreationDate = (Date)nodeService.getProperty(record, ContentModel.PROP_CREATED); if (dispositionPeriod != null) { // calculate the new as of date as we have been provided a new period - newAsOfDate = dispositionPeriod.getNextDate(actionCreationDate); + newAsOfDate = dispositionPeriod.getNextDate(recordCreationDate); } return newAsOfDate; } @@ -1093,11 +1093,11 @@ public class DispositionServiceImpl extends ServiceBaseImpl if (nextDispositionAction == null) { - return getFirstDispositionAction(recordFolders); + return getFirstDispositionAction(record, recordFolders); } else { - return getNextDispositionAction(recordFolders, nextDispositionAction); + return getNextDispositionAction(record, recordFolders, nextDispositionAction); } } @@ -1107,7 +1107,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl * @param nextDispositionAction * @return next disposition action and the associated disposition schedule */ - private NextActionFromDisposition getNextDispositionAction(List recordFolders, DispositionAction nextDispositionAction) + private NextActionFromDisposition getNextDispositionAction(NodeRef record, List recordFolders, DispositionAction nextDispositionAction) { String recordNextDispositionActionName = nextDispositionAction.getName(); Date recordNextDispositionActionDate = nextDispositionAction.getAsOfDate(); @@ -1119,7 +1119,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl NodeRef dsNodeRef = getDispositionScheduleImpl(folder); if (dsNodeRef != null) { - Date dispActionDate = getDispositionActionDate(dsNodeRef, recordNextDispositionActionName); + Date dispActionDate = getDispositionActionDate(record, dsNodeRef, recordNextDispositionActionName); if (nextDispositionActionDate == null || nextDispositionActionDate.before(dispActionDate)) { nextDispositionActionDate = dispActionDate; @@ -1150,7 +1150,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl * @param recordFolders * @return next disposition action and the associated disposition schedule */ - private NextActionFromDisposition getFirstDispositionAction(List recordFolders) + private NextActionFromDisposition getFirstDispositionAction(NodeRef record, List recordFolders) { NodeRef newAction = null; String newDispositionActionName = null; @@ -1171,7 +1171,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl { newAction = firstAction; newDispositionActionName = (String)nodeService.getProperty(newAction, PROP_DISPOSITION_ACTION_NAME); - newDispositionActionDateAsOf = getDispositionActionDate(folderDS, newDispositionActionName); + newDispositionActionDateAsOf = getDispositionActionDate(record, folderDS, newDispositionActionName); } else if (firstDispositionAction.getAsOfDate() != null && newDispositionActionDateAsOf.before(firstDispositionAction.getAsOfDate())) { diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java index 81e5043c9f..b8d6dcb618 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java @@ -98,7 +98,7 @@ public class UpdateNextDispositionActionTest extends BaseRMTestCase // set the disposition as of date to now on the record rmActionService.executeRecordsManagementAction(record, EditDispositionActionAsOfDateAction.NAME, - Collections.singletonMap(EditDispositionActionAsOfDateAction.PARAM_AS_OF_DATE, new Date())); + Collections.singletonMap(EditDispositionActionAsOfDateAction.PARAM_AS_OF_DATE, (Serializable)new Date())); // cut off rmActionService.executeRecordsManagementAction(record, CutOffAction.NAME, null); From fa042c81aeb86cdb9c88f459de39e97cdfd0d7f3 Mon Sep 17 00:00:00 2001 From: roxana Date: Wed, 12 Oct 2016 02:13:53 +0300 Subject: [PATCH 11/17] Changed calculating as of date --- .../disposition/DispositionServiceImpl.java | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) 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 c18528b397..317733d922 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 @@ -266,25 +266,28 @@ public class DispositionServiceImpl extends ServiceBaseImpl { final NextActionFromDisposition dsNextAction = getDispositionActionByNameForRecord(nodeRef); - if (dsNextAction != null && !dsNextAction.getWriteMode().equals(WriteMode.READ_ONLY)) + if (dsNextAction != null) { - final NodeRef action = dsNextAction.getNextActionNodeRef(); - final String dispositionActionName = dsNextAction.getNextActionName(); - final Date dispositionActionDate = dsNextAction.getNextActionDateAsOf(); - - AuthenticationUtil.runAsSystem(new RunAsWork() + if (!dsNextAction.getWriteMode().equals(WriteMode.READ_ONLY)) { - @Override - public Void doWork() + final NodeRef action = dsNextAction.getNextActionNodeRef(); + final String dispositionActionName = dsNextAction.getNextActionName(); + final Date dispositionActionDate = dsNextAction.getNextActionDateAsOf(); + + AuthenticationUtil.runAsSystem(new RunAsWork() { - nodeService.setProperty(action, PROP_DISPOSITION_AS_OF, dispositionActionDate); - if (dsNextAction.getWriteMode().equals(WriteMode.DATE_AND_NAME)) + @Override + public Void doWork() { - nodeService.setProperty(action, PROP_DISPOSITION_ACTION_NAME, dispositionActionName); + nodeService.setProperty(action, PROP_DISPOSITION_AS_OF, dispositionActionDate); + if (dsNextAction.getWriteMode().equals(WriteMode.DATE_AND_NAME)) + { + nodeService.setProperty(action, PROP_DISPOSITION_ACTION_NAME, dispositionActionName); + } + return null; } - return null; - } - }); + }); + } dsNodeRef = dsNextAction.getDispositionNodeRef(); } } @@ -696,9 +699,16 @@ public class DispositionServiceImpl extends ServiceBaseImpl } else { - // for now use 'NOW' as the default context date - // TODO set the default period property ... cut off date or last disposition date depending on context - contextDate = new Date(); + if (period.getPeriodType().equals("immediately")) + { + contextDate = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_CREATED); + } + else + { + // for now use 'NOW' as the default context date + // TODO set the default period property ... cut off date or last disposition date depending on context + contextDate = new Date(); + } } // Calculate the as of date @@ -1006,6 +1016,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl public Date getDispositionActionDate(NodeRef record, NodeRef dispositionSchedule, String dispositionActionName) { + DispositionSchedule ds = new DispositionScheduleImpl(serviceRegistry, nodeService, dispositionSchedule); List assocs = nodeService.getChildAssocs(dispositionSchedule); if (assocs != null && assocs.size() > 0) { @@ -1013,16 +1024,8 @@ public class DispositionServiceImpl extends ServiceBaseImpl { if (assoc != null && assoc.getQName().getLocalName().contains(dispositionActionName)) { - Date newAsOfDate = null; - Period dispositionPeriod = (Period) nodeService.getProperty(assoc.getChildRef(), PROP_DISPOSITION_PERIOD); - Date recordCreationDate = (Date)nodeService.getProperty(record, ContentModel.PROP_CREATED); - - if (dispositionPeriod != null) - { - // calculate the new as of date as we have been provided a new period - newAsOfDate = dispositionPeriod.getNextDate(recordCreationDate); - } - return newAsOfDate; + DispositionActionDefinition actionDefinition = ds.getDispositionActionDefinition(assoc.getChildRef().getId()); + return calculateAsOfDate(record, actionDefinition, true); } } } From 3ea86fa1480aa9b205792a62d5fd07dfbdf9b606 Mon Sep 17 00:00:00 2001 From: roxana Date: Mon, 17 Oct 2016 11:01:22 +0300 Subject: [PATCH 12/17] Fixed tests (for disposition schedules with event based actions). --- .../disposition/DispositionServiceImpl.java | 66 ++++++++++++++----- .../UpdateNextDispositionActionTest.java | 8 +-- .../service/DispositionServiceImplTest.java | 2 +- 3 files changed, 51 insertions(+), 25 deletions(-) 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 317733d922..f46a83d810 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 @@ -70,6 +70,8 @@ public class DispositionServiceImpl extends ServiceBaseImpl { /** Logger */ private static final Logger LOGGER = LoggerFactory.getLogger(DispositionServiceImpl.class); + + private static final String PERIOD_IMMEDIATELY = "immediately"; /** Transaction mode for setting next action */ public enum WriteMode {READ_ONLY, DATE_ONLY, DATE_AND_NAME}; @@ -636,8 +638,14 @@ public class DispositionServiceImpl extends ServiceBaseImpl * @param dispositionActionDefinition disposition action definition * @param allowContextFromAsOf true if the context date is allowed to be obtained from the disposition "as of" property. */ - private void initialiseDispositionAction(NodeRef nodeRef, DispositionActionDefinition dispositionActionDefinition, boolean allowContextFromAsOf) + private DispositionAction initialiseDispositionAction(NodeRef nodeRef, DispositionActionDefinition dispositionActionDefinition, boolean allowContextFromAsOf) { + List childAssocs = nodeService.getChildAssocs(nodeRef, ASSOC_NEXT_DISPOSITION_ACTION, ASSOC_NEXT_DISPOSITION_ACTION, 1, true); + if (childAssocs != null && childAssocs.size() > 0) + { + return new DispositionActionImpl(serviceRegistry, childAssocs.get(0).getChildRef()); + } + // Create the properties Map props = new HashMap(10); @@ -667,6 +675,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl // For every event create an entry on the action da.addEventCompletionDetails(event); } + return da; } /** @@ -699,7 +708,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl } else { - if (period.getPeriodType().equals("immediately")) + if (period.getPeriodType().equals(PERIOD_IMMEDIATELY)) { contextDate = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_CREATED); } @@ -1130,20 +1139,36 @@ public class DispositionServiceImpl extends ServiceBaseImpl } } } - if (nextDispositionActionDate == null || dispositionNodeRef == null) + if (dispositionNodeRef == null) { return null; } WriteMode mode = null; - if (!nextDispositionActionDate.equals(recordNextDispositionActionDate) - && recordNextDispositionActionDate.before(nextDispositionActionDate)) + if (recordNextDispositionActionDate != null) { - mode = WriteMode.DATE_ONLY; + if ((nextDispositionActionDate == null) + || (!nextDispositionActionDate.equals(recordNextDispositionActionDate) + && recordNextDispositionActionDate.before(nextDispositionActionDate))) + { + mode = WriteMode.DATE_ONLY; + } + else + { + mode = WriteMode.READ_ONLY; + } } else { - mode = WriteMode.READ_ONLY; + if (nextDispositionActionDate != null) + { + mode = WriteMode.DATE_ONLY; + } + else + { + mode = WriteMode.READ_ONLY; + } } + return new NextActionFromDisposition(dispositionNodeRef, nextDispositionAction.getNodeRef(), recordNextDispositionActionName, nextDispositionActionDate, mode); } @@ -1164,28 +1189,33 @@ public class DispositionServiceImpl extends ServiceBaseImpl NodeRef folderDS = getDispositionScheduleImpl(folder); if (folderDS != null) { - List assocs = nodeService.getChildAssocs(folderDS); - if (assocs != null && assocs.size() > 0) + DispositionSchedule ds = new DispositionScheduleImpl(serviceRegistry, nodeService, folderDS); + List dispositionActionDefinitions = ds.getDispositionActionDefinitions(); + + if (dispositionActionDefinitions != null && dispositionActionDefinitions.size() > 0) { - NodeRef firstAction = assocs.get(0).getChildRef(); - DispositionAction firstDispositionAction = new DispositionActionImpl(serviceRegistry, firstAction); + DispositionActionDefinition firstDispositionActionDef = dispositionActionDefinitions.get(0); if (newAction == null) { - newAction = firstAction; + DispositionAction firstDispositionAction = initialiseDispositionAction(record, firstDispositionActionDef, true); + newAction = firstDispositionAction.getNodeRef(); newDispositionActionName = (String)nodeService.getProperty(newAction, PROP_DISPOSITION_ACTION_NAME); - newDispositionActionDateAsOf = getDispositionActionDate(record, folderDS, newDispositionActionName); - } - else if (firstDispositionAction.getAsOfDate() != null && newDispositionActionDateAsOf.before(firstDispositionAction.getAsOfDate())) - { - newDispositionActionName = (String)nodeService.getProperty(firstAction, PROP_DISPOSITION_ACTION_NAME); newDispositionActionDateAsOf = firstDispositionAction.getAsOfDate(); } + else if (firstDispositionActionDef.getPeriod() != null) { + Date firstActionDate = calculateAsOfDate(record, firstDispositionActionDef, true); + if (newDispositionActionDateAsOf.before(firstActionDate)) + { + newDispositionActionName =firstDispositionActionDef.getName(); + newDispositionActionDateAsOf = firstActionDate; + } + } dispositionNodeRef = folderDS; } } } - if (newDispositionActionName == null || newDispositionActionDateAsOf == null + if (newDispositionActionName == null || dispositionNodeRef == null || newAction == null) { return null; diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java index b8d6dcb618..d8dbb0b078 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/disposition/UpdateNextDispositionActionTest.java @@ -36,6 +36,7 @@ import org.alfresco.module.org_alfresco_module_rm.action.impl.EditDispositionAct import org.alfresco.module.org_alfresco_module_rm.action.impl.TransferAction; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.module.org_alfresco_module_rm.test.util.CommonRMTestUtils; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; @@ -95,11 +96,6 @@ public class UpdateNextDispositionActionTest extends BaseRMTestCase // complete record utils.completeRecord(record); - // set the disposition as of date to now on the record - rmActionService.executeRecordsManagementAction(record, - EditDispositionActionAsOfDateAction.NAME, - Collections.singletonMap(EditDispositionActionAsOfDateAction.PARAM_AS_OF_DATE, (Serializable)new Date())); - // cut off rmActionService.executeRecordsManagementAction(record, CutOffAction.NAME, null); } @@ -120,7 +116,7 @@ public class UpdateNextDispositionActionTest extends BaseRMTestCase Map cutOff = new HashMap(3); cutOff.put(PROP_DISPOSITION_ACTION_NAME, CutOffAction.NAME); cutOff.put(PROP_DISPOSITION_DESCRIPTION, generate()); - cutOff.put(PROP_DISPOSITION_PERIOD, PERIOD_ONE_WEEK); + cutOff.put(PROP_DISPOSITION_PERIOD, CommonRMTestUtils.PERIOD_IMMEDIATELY); dispositionService.addDispositionActionDefinition(ds, cutOff); // create the properties for TRANSFER action and add it to the disposition action definition diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/DispositionServiceImplTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/DispositionServiceImplTest.java index e3853bfc30..29ab764296 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/DispositionServiceImplTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/DispositionServiceImplTest.java @@ -657,7 +657,7 @@ public class DispositionServiceImplTest extends BaseRMTestCase checkDisposableItemChanged(mhRecordFolder42); checkDisposableItemChanged(record43); checkDisposableItemUnchanged(mhRecordFolder44); - checkDisposableItemUnchanged(record45);; + checkDisposableItemUnchanged(record45); } }); From 531f10c458fa960e425f7d383fc2e950f6ef917c Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 17 Oct 2016 15:27:43 +0100 Subject: [PATCH 13/17] RM-2526 Treat null as the largest date possible. If a disposition step has an "as of" date of null then it requires human interaction. Consequently there is no length of time we can wait before the step triggers - so we treat it as the latest step if there are multiple disposition schedules. --- .../disposition/DispositionServiceImpl.java | 110 +++++++++++------- 1 file changed, 69 insertions(+), 41 deletions(-) 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 f46a83d810..7d841d2c49 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 @@ -39,6 +39,7 @@ 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.RecordFolderService; import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; +import org.alfresco.repo.dictionary.types.period.Immediately; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.BehaviourBean; @@ -70,11 +71,20 @@ public class DispositionServiceImpl extends ServiceBaseImpl { /** Logger */ private static final Logger LOGGER = LoggerFactory.getLogger(DispositionServiceImpl.class); - - private static final String PERIOD_IMMEDIATELY = "immediately"; /** Transaction mode for setting next action */ - public enum WriteMode {READ_ONLY, DATE_ONLY, DATE_AND_NAME}; + public enum WriteMode + { + /** Do not update any data. */ + READ_ONLY, + /** Only set the "disposition as of" date. */ + DATE_ONLY, + /** + * Set the "disposition as of" date and the name of the next action. This only happens during the creation of a + * disposition schedule impl node under a record or folder. + */ + DATE_AND_NAME + }; /** Behaviour filter */ private BehaviourFilter behaviourFilter; @@ -645,7 +655,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl { return new DispositionActionImpl(serviceRegistry, childAssocs.get(0).getChildRef()); } - + // Create the properties Map props = new HashMap(10); @@ -708,7 +718,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl } else { - if (period.getPeriodType().equals(PERIOD_IMMEDIATELY)) + if (period.getPeriodType().equals(Immediately.PERIOD_TYPE)) { contextDate = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_CREATED); } @@ -1123,19 +1133,27 @@ public class DispositionServiceImpl extends ServiceBaseImpl { String recordNextDispositionActionName = nextDispositionAction.getName(); Date recordNextDispositionActionDate = nextDispositionAction.getAsOfDate(); - Date nextDispositionActionDate = null; + // We're looking for the latest date, so initially start with a very early one. + Date nextDispositionActionDate = new Date(Long.MIN_VALUE); NodeRef dispositionNodeRef = null; + // Find the latest "disposition as of" date from all the schedules this record is subject to. for (NodeRef folder : recordFolders) { NodeRef dsNodeRef = getDispositionScheduleImpl(folder); if (dsNodeRef != null) { Date dispActionDate = getDispositionActionDate(record, dsNodeRef, recordNextDispositionActionName); - if (nextDispositionActionDate == null || nextDispositionActionDate.before(dispActionDate)) + if (dispActionDate == null || (nextDispositionActionDate != null + && nextDispositionActionDate.before(dispActionDate))) { nextDispositionActionDate = dispActionDate; dispositionNodeRef = dsNodeRef; + if (dispActionDate == null) + { + // Treat null as the latest date possible (so stop searching further). + break; + } } } } @@ -1143,34 +1161,37 @@ public class DispositionServiceImpl extends ServiceBaseImpl { return null; } - WriteMode mode = null; - if (recordNextDispositionActionDate != null) + WriteMode mode = determineWriteMode(recordNextDispositionActionDate, nextDispositionActionDate); + + return new NextActionFromDisposition(dispositionNodeRef, nextDispositionAction.getNodeRef(), + recordNextDispositionActionName, nextDispositionActionDate, mode); + } + + /** + * Determine what should be updated for an existing disposition schedule impl. We only update the date if the + * existing date is earlier than the calculated one. + * + * @param recordNextDispositionActionDate The next action date found on the record node (or folder node). + * @param nextDispositionActionDate The next action date calculated from the current disposition schedule(s) + * affecting the node. + * @return READ_ONLY if nothing should be updated, or DATE_ONLY if the date needs updating. + */ + private WriteMode determineWriteMode(Date recordNextDispositionActionDate, Date nextDispositionActionDate) + { + // Treat null dates as being the latest possible date. + Date maxDate = new Date(Long.MAX_VALUE); + Date recordDate = (recordNextDispositionActionDate != null ? recordNextDispositionActionDate : maxDate); + Date calculatedDate = (nextDispositionActionDate != null ? recordNextDispositionActionDate : maxDate); + + // We only need to update the date if the current one is too early. + if (recordDate.before(calculatedDate)) { - if ((nextDispositionActionDate == null) - || (!nextDispositionActionDate.equals(recordNextDispositionActionDate) - && recordNextDispositionActionDate.before(nextDispositionActionDate))) - { - mode = WriteMode.DATE_ONLY; - } - else - { - mode = WriteMode.READ_ONLY; - } + return WriteMode.DATE_ONLY; } else { - if (nextDispositionActionDate != null) - { - mode = WriteMode.DATE_ONLY; - } - else - { - mode = WriteMode.READ_ONLY; - } + return WriteMode.READ_ONLY; } - - return new NextActionFromDisposition(dispositionNodeRef, nextDispositionAction.getNodeRef(), - recordNextDispositionActionName, nextDispositionActionDate, mode); } /** @@ -1182,7 +1203,8 @@ public class DispositionServiceImpl extends ServiceBaseImpl { NodeRef newAction = null; String newDispositionActionName = null; - Date newDispositionActionDateAsOf = null; + // We're looking for the latest date, so start with a very early one. + Date newDispositionActionDateAsOf = new Date(Long.MIN_VALUE); NodeRef dispositionNodeRef = null; for (NodeRef folder : recordFolders) { @@ -1191,10 +1213,11 @@ public class DispositionServiceImpl extends ServiceBaseImpl { DispositionSchedule ds = new DispositionScheduleImpl(serviceRegistry, nodeService, folderDS); List dispositionActionDefinitions = ds.getDispositionActionDefinitions(); - + if (dispositionActionDefinitions != null && dispositionActionDefinitions.size() > 0) { DispositionActionDefinition firstDispositionActionDef = dispositionActionDefinitions.get(0); + dispositionNodeRef = folderDS; if (newAction == null) { @@ -1203,20 +1226,25 @@ public class DispositionServiceImpl extends ServiceBaseImpl newDispositionActionName = (String)nodeService.getProperty(newAction, PROP_DISPOSITION_ACTION_NAME); newDispositionActionDateAsOf = firstDispositionAction.getAsOfDate(); } - else if (firstDispositionActionDef.getPeriod() != null) { + else if (firstDispositionActionDef.getPeriod() != null) + { Date firstActionDate = calculateAsOfDate(record, firstDispositionActionDef, true); - if (newDispositionActionDateAsOf.before(firstActionDate)) + if (firstActionDate == null || (newDispositionActionDateAsOf != null + && newDispositionActionDateAsOf.before(firstActionDate))) { - newDispositionActionName =firstDispositionActionDef.getName(); + newDispositionActionName = firstDispositionActionDef.getName(); newDispositionActionDateAsOf = firstActionDate; + if (firstActionDate == null) + { + // Treat null as the latest date possible, so there's no point searching further. + break; + } } } - dispositionNodeRef = folderDS; - } - } - } - if (newDispositionActionName == null - || dispositionNodeRef == null || newAction == null) + } + } + } + if (newDispositionActionName == null || dispositionNodeRef == null || newAction == null) { return null; } From c827e843ed2581d48e792ea875917e6314dcf5e6 Mon Sep 17 00:00:00 2001 From: roxana Date: Mon, 17 Oct 2016 17:50:12 +0300 Subject: [PATCH 14/17] Added check for adding disposition lifecycle aspect. --- .../disposition/DispositionServiceImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 7d841d2c49..58198244e1 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 @@ -1221,7 +1221,12 @@ public class DispositionServiceImpl extends ServiceBaseImpl if (newAction == null) { - DispositionAction firstDispositionAction = initialiseDispositionAction(record, firstDispositionActionDef, true); + NodeRef recordOrFolder = record; + if (!ds.isRecordLevelDisposition()) + { + recordOrFolder = folder; + } + DispositionAction firstDispositionAction = initialiseDispositionAction(recordOrFolder, firstDispositionActionDef, true); newAction = firstDispositionAction.getNodeRef(); newDispositionActionName = (String)nodeService.getProperty(newAction, PROP_DISPOSITION_ACTION_NAME); newDispositionActionDateAsOf = firstDispositionAction.getAsOfDate(); From 891ea3595628d707574bebd083f94a0961a8c030 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 17 Oct 2016 16:46:51 +0100 Subject: [PATCH 15/17] RM-2526 Fix copy/paste error. --- .../disposition/DispositionServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 58198244e1..332f06e6ba 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 @@ -1181,7 +1181,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl // Treat null dates as being the latest possible date. Date maxDate = new Date(Long.MAX_VALUE); Date recordDate = (recordNextDispositionActionDate != null ? recordNextDispositionActionDate : maxDate); - Date calculatedDate = (nextDispositionActionDate != null ? recordNextDispositionActionDate : maxDate); + Date calculatedDate = (nextDispositionActionDate != null ? nextDispositionActionDate : maxDate); // We only need to update the date if the current one is too early. if (recordDate.before(calculatedDate)) From 1dea4c9d2de86c9332bcf3f1884c10032890c4c0 Mon Sep 17 00:00:00 2001 From: roxana Date: Tue, 18 Oct 2016 10:57:08 +0300 Subject: [PATCH 16/17] Modified validation for link conditions to compare the original disposition of the record with the target one. --- .../rm-service-context.xml | 1 + .../disposition/DispositionService.java | 9 ++++++++ .../disposition/DispositionServiceImpl.java | 22 +++++++++++++++++++ .../record/RecordServiceImpl.java | 18 ++++++++++++++- 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml index 2e2b192760..97f6a97480 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml @@ -130,6 +130,7 @@ org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.registerDispositionProperty=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.getDispositionProperties=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.getDispositionSchedule=RM.Read.0 + org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.getOriginDispositionSchedule=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.getAssociatedDispositionSchedule=RM.Read.0 org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.getAssociatedRecordsManagementContainer=RM_ALLOW org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService.hasDisposableItems=RM_ALLOW diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java index 4c0136733c..ed2ed79ecd 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/disposition/DispositionService.java @@ -255,4 +255,13 @@ public interface DispositionService */ Date calculateAsOfDate(NodeRef nodeRef, DispositionActionDefinition dispositionActionDefinition, boolean allowContextFromAsOf); + + /** + * Gets the origin disposition schedule for the record, not the calculated one + * in case of multiple dispositions applied to record + * + * @param nodeRef record + * @return the initial disposition + */ + DispositionSchedule getOriginDispositionSchedule(NodeRef nodeRef); } 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 332f06e6ba..3cce643ec3 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 @@ -341,6 +341,28 @@ public class DispositionServiceImpl extends ServiceBaseImpl } return result; } + + public DispositionSchedule getOriginDispositionSchedule(NodeRef nodeRef) + { + NodeRef parent = this.nodeService.getPrimaryParent(nodeRef).getParentRef(); + if (parent != null) + { + if (filePlanService.isRecordCategory(parent)) + { + NodeRef result = getAssociatedDispositionScheduleImpl(parent); + if (result == null) + { + return null; + } + return new DispositionScheduleImpl(serviceRegistry, nodeService, result); + } + else + { + return getOriginDispositionSchedule(parent); + } + } + return null; + } /** * @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getAssociatedDispositionSchedule(org.alfresco.service.cmr.repository.NodeRef) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java index f4fa00e1d0..0a256eea17 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java @@ -34,12 +34,14 @@ import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.BeforeFileRecord; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnFileRecord; import org.alfresco.module.org_alfresco_module_rm.capability.Capability; import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionScheduleImpl; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; import org.alfresco.module.org_alfresco_module_rm.dod5015.DOD5015Model; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; @@ -228,6 +230,9 @@ public class RecordServiceImpl extends BaseBehaviourBean /** recordable version service */ private RecordableVersionService recordableVersionService; + + /** Records management service registry */ + private RecordsManagementServiceRegistry serviceRegistry; /** list of available record meta-data aspects and the file plan types the are applicable to */ private Map> recordMetaDataAspects; @@ -385,6 +390,14 @@ public class RecordServiceImpl extends BaseBehaviourBean { this.recordableVersionService = recordableVersionService; } + + /** + * @param serviceRegistry records management registry service + */ + public void setRecordsManagementServiceRegistry(RecordsManagementServiceRegistry serviceRegistry) + { + this.serviceRegistry = serviceRegistry; + } /** * Init method @@ -1732,7 +1745,10 @@ public class RecordServiceImpl extends BaseBehaviourBean private void validateLinkConditions(NodeRef record, NodeRef recordFolder) { // ensure that the linking record folders have compatible disposition schedules - DispositionSchedule recordDispositionSchedule = dispositionService.getDispositionSchedule(record); + + // get the origin disposition schedule for the record, not the calculated one + DispositionSchedule recordDispositionSchedule = dispositionService.getOriginDispositionSchedule(record); + if (recordDispositionSchedule != null) { DispositionSchedule recordFolderDispositionSchedule = dispositionService.getDispositionSchedule(recordFolder); From d82c27e6a44cce45870f2f978c26da2eb0b8cc16 Mon Sep 17 00:00:00 2001 From: roxana Date: Tue, 18 Oct 2016 11:49:15 +0300 Subject: [PATCH 17/17] Fixed unit test for linking. --- .../record/RecordServiceImpl.java | 11 ----------- .../record/RecordServiceImplUnitTest.java | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java index 0a256eea17..a523ac93b6 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java @@ -231,9 +231,6 @@ public class RecordServiceImpl extends BaseBehaviourBean /** recordable version service */ private RecordableVersionService recordableVersionService; - /** Records management service registry */ - private RecordsManagementServiceRegistry serviceRegistry; - /** list of available record meta-data aspects and the file plan types the are applicable to */ private Map> recordMetaDataAspects; @@ -391,14 +388,6 @@ public class RecordServiceImpl extends BaseBehaviourBean this.recordableVersionService = recordableVersionService; } - /** - * @param serviceRegistry records management registry service - */ - public void setRecordsManagementServiceRegistry(RecordsManagementServiceRegistry serviceRegistry) - { - this.serviceRegistry = serviceRegistry; - } - /** * Init method */ diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java index 76b0f0cf11..38e0a3e4f6 100755 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImplUnitTest.java @@ -263,7 +263,7 @@ public class RecordServiceImplUnitTest extends BaseUnitTest DispositionSchedule recordDispositionSchedule = mock(DispositionSchedule.class); when(recordDispositionSchedule.isRecordLevelDisposition()) .thenReturn(true); - when(mockedDispositionService.getDispositionSchedule(record)) + when(mockedDispositionService.getOriginDispositionSchedule(record)) .thenReturn(recordDispositionSchedule); DispositionSchedule recordFolderDispositionSchedule = mock(DispositionSchedule.class);