diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationException.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationException.java index af33df5a8d..70e3f7d603 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationException.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationException.java @@ -130,4 +130,17 @@ public class ClassificationException extends AlfrescoRuntimeException super("Operation not permitted on node " + nodeRef + ", error message: " + message); } } + + /** A downgrade date or event has been specified, but there are no corresponding instructions. */ + public static class MissingDowngradeInstructions extends ClassificationException + { + /** serial version uid */ + private static final long serialVersionUID = -1561288436418050014L; + + public MissingDowngradeInstructions(NodeRef nodeRef) + { + super("A downgrade date or event has been specified, but there are no corresponding instructions for " + + nodeRef); + } + } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/clf/aspect/ClassifiedAspect.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/clf/aspect/ClassifiedAspect.java index 702e847064..ee81a503ed 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/clf/aspect/ClassifiedAspect.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/clf/aspect/ClassifiedAspect.java @@ -18,18 +18,19 @@ */ package org.alfresco.module.org_alfresco_module_rm.model.clf.aspect; -import static org.alfresco.module.org_alfresco_module_rm.classification.ClassificationSchemeService.Reclassification; -import static org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel.ASPECT_CLASSIFIED; -import static org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel.PROP_CURRENT_CLASSIFICATION; -import static org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel.PROP_LAST_RECLASSIFICATION_ACTION; -import static org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel.PROP_LAST_RECLASSIFY_AT; -import static org.alfresco.module.org_alfresco_module_rm.util.RMCollectionUtils.Difference; import static org.alfresco.module.org_alfresco_module_rm.util.RMCollectionUtils.diffKey; +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + +import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.MissingDowngradeInstructions; import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationLevel; import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationSchemeService; +import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationSchemeService.Reclassification; import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; +import org.alfresco.module.org_alfresco_module_rm.util.RMCollectionUtils.Difference; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.annotation.Behaviour; @@ -40,10 +41,6 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; -import java.io.Serializable; -import java.util.Date; -import java.util.Map; - /** * clf:classification behaviour bean * @@ -53,8 +50,8 @@ import java.util.Map; ( defaultType = "clf:classified" ) -public class ClassifiedAspect extends BaseBehaviourBean - implements NodeServicePolicies.OnUpdatePropertiesPolicy +public class ClassifiedAspect extends BaseBehaviourBean implements NodeServicePolicies.OnUpdatePropertiesPolicy, + NodeServicePolicies.OnAddAspectPolicy, ClassifiedContentModel { private ClassificationSchemeService classificationSchemeService; @@ -64,9 +61,13 @@ public class ClassifiedAspect extends BaseBehaviourBean } /** + * Behaviour associated with updating the classified aspect properties. + *

* Ensures that on reclassification of content (in other words a change in the value of the * {@link ClassifiedContentModel#PROP_CURRENT_CLASSIFICATION clf:currentClassification} property) * that various metadata are correctly updated as a side-effect. + *

+ * Validates the consistency of the properties. */ @Override @Behaviour @@ -100,8 +101,48 @@ public class ClassifiedAspect extends BaseBehaviourBean nodeService.setProperty(nodeRef, PROP_LAST_RECLASSIFY_AT, new Date()); } } + + checkConsistencyOfProperties(nodeRef); + return null; } }, AuthenticationUtil.getSystemUserName()); } + + /** + * Behaviour associated with updating the classified aspect properties. + *

+ * Validates the consistency of the properties. + */ + @Override + public void onAddAspect(final NodeRef nodeRef, final QName aspectTypeQName) + { + AuthenticationUtil.runAs(new RunAsWork() + { + public Void doWork() + { + checkConsistencyOfProperties(nodeRef); + return null; + } + }, AuthenticationUtil.getSystemUserName()); + } + + /** + * Check the consistency of the classification properties and throw an exception if they are invalid. + * + * @param nodeRef The classified node. + */ + protected void checkConsistencyOfProperties(NodeRef nodeRef) throws MissingDowngradeInstructions + { + if (nodeService.hasAspect(nodeRef, ASPECT_CLASSIFIED)) + { + Serializable downgradeDate = nodeService.getProperty(nodeRef, PROP_DOWNGRADE_DATE); + Serializable downgradeEvent = nodeService.getProperty(nodeRef, PROP_DOWNGRADE_EVENT); + Serializable downgradeInstructions = nodeService.getProperty(nodeRef, PROP_DOWNGRADE_INSTRUCTIONS); + if (downgradeInstructions == null && (downgradeDate != null || downgradeEvent != null)) + { + throw new MissingDowngradeInstructions(nodeRef); + } + } + } } diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/clf/aspect/ClassifiedAspectUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/clf/aspect/ClassifiedAspectUnitTest.java new file mode 100644 index 0000000000..e407e8682c --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/clf/aspect/ClassifiedAspectUnitTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.model.clf.aspect; + +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.Date; + +import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.MissingDowngradeInstructions; +import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +/** + * Unit tests for the {@link ClassifiedAspect}. + * + * @author Tom Page + * @since 3.0.a + */ +public class ClassifiedAspectUnitTest implements ClassifiedContentModel +{ + private static final NodeRef NODE_REF = new NodeRef("node://Ref/"); + + @InjectMocks ClassifiedAspect classifiedAspect; + @Mock NodeService mockNodeService; + + @Before + public void setUp() + { + initMocks(this); + } + + /** Check that providing an event and instructions is valid. */ + @Test + public void testCheckConsistencyOfProperties_success() + { + when(mockNodeService.hasAspect(NODE_REF, ASPECT_CLASSIFIED)).thenReturn(true); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_DATE)).thenReturn(null); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_EVENT)).thenReturn("Event"); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_INSTRUCTIONS)).thenReturn("Instructions"); + + classifiedAspect.checkConsistencyOfProperties(NODE_REF); + } + + /** Check that omitting all downgrade fields is valid. */ + @Test + public void testCheckConsistencyOfProperties_notSpecified() + { + when(mockNodeService.hasAspect(NODE_REF, ASPECT_CLASSIFIED)).thenReturn(true); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_DATE)).thenReturn(null); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_EVENT)).thenReturn(null); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_INSTRUCTIONS)).thenReturn(null); + + classifiedAspect.checkConsistencyOfProperties(NODE_REF); + } + + /** Check that a date without instructions throws an exception. */ + @Test(expected = MissingDowngradeInstructions.class) + public void testCheckConsistencyOfProperties_dateMissingInstructions() + { + when(mockNodeService.hasAspect(NODE_REF, ASPECT_CLASSIFIED)).thenReturn(true); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_DATE)).thenReturn(new Date(123)); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_EVENT)).thenReturn(null); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_INSTRUCTIONS)).thenReturn(null); + + classifiedAspect.checkConsistencyOfProperties(NODE_REF); + } + + /** Check that an event without instructions throws an exception. */ + @Test(expected = MissingDowngradeInstructions.class) + public void testCheckConsistencyOfProperties_eventMissingInstructions() + { + when(mockNodeService.hasAspect(NODE_REF, ASPECT_CLASSIFIED)).thenReturn(true); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_DATE)).thenReturn(null); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_EVENT)).thenReturn("Event"); + when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_INSTRUCTIONS)).thenReturn(null); + + classifiedAspect.checkConsistencyOfProperties(NODE_REF); + } +}