diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index 0c4e6e1714..b36727ef8f 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -241,6 +241,15 @@ class="org.alfresco.module.org_alfresco_module_rm.model.clf.aspect.ClassifiedAspect" parent="rm.baseBehaviour"> + + + + + + + diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml index 9e2d78befd..6c0d892a66 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml @@ -11,6 +11,12 @@ + + + + + + diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/clf/ClassifiedRenditions.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/clf/ClassifiedRenditions.java new file mode 100644 index 0000000000..84fc9fe741 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/model/clf/ClassifiedRenditions.java @@ -0,0 +1,91 @@ +/* + * 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; + +import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; +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.CoreServicesExtras; +import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.policy.Behaviour.NotificationFrequency; +import org.alfresco.repo.policy.annotation.Behaviour; +import org.alfresco.repo.policy.annotation.BehaviourBean; +import org.alfresco.repo.policy.annotation.BehaviourKind; +import org.alfresco.service.cmr.rendition.RenditionService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; + +/** + * Behaviour bean for classified rendition nodes. + * + * @since 3.0.a + */ +@BehaviourBean +( + defaultType = "rn:rendition" +) +public class ClassifiedRenditions extends BaseBehaviourBean + implements NodeServicePolicies.OnAddAspectPolicy, + ClassifiedContentModel +{ + private ContentClassificationService contentClassificationService; + private CoreServicesExtras servicesExtras; + private RenditionService renditionService; + + public void setContentClassificationService(ContentClassificationService service) + { + this.contentClassificationService = service; + } + + public void setCoreServicesExtras(CoreServicesExtras extras) + { + this.servicesExtras = extras; + } + + public void setRenditionService(RenditionService service) + { + this.renditionService = service; + } + + /** + * Behaviour associated with creating a rendition of an already classified node. + */ + @Override + @Behaviour + ( + kind = BehaviourKind.CLASS, + notificationFrequency = NotificationFrequency.EVERY_EVENT + ) + public void onAddAspect(final NodeRef renditionNodeRef, final QName aspectTypeQName) + { + authenticationUtil.runAs(new org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork() + { + public Void doWork() + { + final NodeRef sourceNode = renditionService.getSourceNode(renditionNodeRef).getParentRef(); + if (contentClassificationService.isClassified(sourceNode)) + { + // All renditions should be given the same classification as their source node + servicesExtras.copyAspect(sourceNode, renditionNodeRef, ASPECT_CLASSIFIED); + } + return null; + } + }, authenticationUtil.getSystemUserName()); + } +} 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 402beb0181..97f71efddd 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 @@ -30,6 +30,7 @@ import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationS 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.CoreServicesExtras; import org.alfresco.module.org_alfresco_module_rm.util.RMCollectionUtils.Difference; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.policy.Behaviour.NotificationFrequency; @@ -38,6 +39,8 @@ import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourKind; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.service.cmr.rendition.RenditionService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; @@ -51,15 +54,28 @@ import org.alfresco.service.namespace.QName; defaultType = "clf:classified" ) public class ClassifiedAspect extends BaseBehaviourBean implements NodeServicePolicies.OnUpdatePropertiesPolicy, - NodeServicePolicies.OnAddAspectPolicy, ClassifiedContentModel + NodeServicePolicies.OnAddAspectPolicy, + ClassifiedContentModel { private ClassificationSchemeService classificationSchemeService; + private RenditionService renditionService; + private CoreServicesExtras servicesExtras; public void setClassificationSchemeService(ClassificationSchemeService service) { this.classificationSchemeService = service; } + public void setRenditionService(RenditionService service) + { + this.renditionService = service; + } + + public void setCoreServicesExtras(CoreServicesExtras extras) + { + this.servicesExtras = extras; + } + /** * Behaviour associated with updating the classified aspect properties. *

@@ -104,6 +120,8 @@ public class ClassifiedAspect extends BaseBehaviourBean implements NodeServicePo checkConsistencyOfProperties(nodeRef); + copyClassifiedPropertiesToRenditions(nodeRef); + return null; } }, AuthenticationUtil.getSystemUserName()); @@ -127,11 +145,24 @@ public class ClassifiedAspect extends BaseBehaviourBean implements NodeServicePo public Void doWork() { checkConsistencyOfProperties(nodeRef); + + copyClassifiedPropertiesToRenditions(nodeRef); + return null; } }, AuthenticationUtil.getSystemUserName()); } + private void copyClassifiedPropertiesToRenditions(NodeRef nodeRef) + { + // All renditions should be given the same classification as their source node + for (final ChildAssociationRef chAssRef : renditionService.getRenditions(nodeRef)) + { + final NodeRef renditionNode = chAssRef.getChildRef(); + servicesExtras.copyAspect(nodeRef, renditionNode, ASPECT_CLASSIFIED); + } + } + /** * Check the consistency of the classification properties and throw an exception if they are invalid. * diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/util/CoreServicesExtras.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/util/CoreServicesExtras.java new file mode 100644 index 0000000000..bba48d78eb --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/util/CoreServicesExtras.java @@ -0,0 +1,83 @@ +/* + * 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.util; + +import static org.alfresco.util.collections.CollectionUtils.filterKeys; + +import org.alfresco.service.cmr.dictionary.AspectDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryException; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.collections.Function; + +import java.io.Serializable; +import java.util.Map; +import java.util.Set; + +/** + * Provides additional methods of general use that could (in principle) be moved to the core services. + * + * @author Neil Mc Erlean + * @since 3.0.a + */ +public class CoreServicesExtras +{ + private DictionaryService dictionaryService; + private NodeService nodeService; + + public void setDictionaryService(DictionaryService service) + { + this.dictionaryService = service; + } + + public void setNodeService(NodeService service) + { + this.nodeService = service; + } + + /** + * This method copies the property values for the specified aspect from one node to another. + * All associations are ignored. + * + * @param from the node whose property values are to be read. + * @param to the node to which the property values are to be written. + * @return a Map of the property values which were copied. + */ + public Map copyAspect(NodeRef from, NodeRef to, QName aspectQName) + { + final AspectDefinition aspectDefn = dictionaryService.getAspect(aspectQName); + + if (aspectDefn == null) { throw new DictionaryException("Unknown aspect: " + aspectQName); } + + final Set aspectProperties = aspectDefn.getProperties().keySet(); + + final Map nodeProperties = nodeService.getProperties(from); + final Map relevantPropVals = filterKeys(nodeProperties, new Function() + { + @Override public Boolean apply(QName value) + { + return aspectProperties.contains(value); + } + }); + nodeService.setProperties(to, relevantPropVals); + return relevantPropVals; + } +} diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/clf/ClassifiedRenditionsUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/clf/ClassifiedRenditionsUnitTest.java new file mode 100644 index 0000000000..b0ad04bef7 --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/clf/ClassifiedRenditionsUnitTest.java @@ -0,0 +1,96 @@ +/* + * 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; + +import static java.util.Arrays.asList; + +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import org.alfresco.model.RenditionModel; +import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; +import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel; +import org.alfresco.module.org_alfresco_module_rm.model.clf.aspect.ClassifiedAspect; +import org.alfresco.module.org_alfresco_module_rm.test.util.MockAuthenticationUtilHelper; +import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; +import org.alfresco.module.org_alfresco_module_rm.util.CoreServicesExtras; +import org.alfresco.service.cmr.rendition.RenditionService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +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 {@link ClassifiedRenditions}. + * + * @since 3.0.a + */ +public class ClassifiedRenditionsUnitTest implements ClassifiedContentModel +{ + private static final NodeRef SOURCE_NODE = new NodeRef("node://ref/"); + private static final NodeRef RENDITION_1 = new NodeRef("node://rendition1/"); + private static final NodeRef RENDITION_2 = new NodeRef("node://rendition2/"); + + @InjectMocks ClassifiedAspect classifiedAspect; + + @Mock AuthenticationUtil mockAuthenticationUtil; + @Mock ContentClassificationService mockContentClassificationService; + @Mock CoreServicesExtras mockCoreServicesExtras; + @Mock NodeService mockNodeService; + @Mock RenditionService mockRenditionService; + + @Before + public void setUp() + { + initMocks(this); + + MockAuthenticationUtilHelper.setup(mockAuthenticationUtil); + } + + @Test public void newRenditionOfClassifiedNodeShouldItselfBeClassified() + { + when(mockRenditionService.getRenditions(eq(SOURCE_NODE))) + .thenReturn(asList(rendition(SOURCE_NODE, RENDITION_1), rendition(SOURCE_NODE, RENDITION_2))); + when(mockRenditionService.getSourceNode(eq(RENDITION_1))).thenReturn(rendition(SOURCE_NODE, RENDITION_1)); + when(mockRenditionService.getSourceNode(eq(RENDITION_2))).thenReturn(rendition(SOURCE_NODE, RENDITION_2)); + when(mockContentClassificationService.isClassified(eq(SOURCE_NODE))).thenReturn(true); + + final ClassifiedRenditions behaviour = new ClassifiedRenditions(); + behaviour.setAuthenticationUtil(mockAuthenticationUtil); + behaviour.setContentClassificationService(mockContentClassificationService); + behaviour.setCoreServicesExtras(mockCoreServicesExtras); + behaviour.setNodeService(mockNodeService); + behaviour.setRenditionService(mockRenditionService); + + behaviour.onAddAspect(RENDITION_2, RenditionModel.ASPECT_RENDITION); + + verify(mockCoreServicesExtras).copyAspect(eq(SOURCE_NODE), eq(RENDITION_2), eq(ClassifiedContentModel.ASPECT_CLASSIFIED)); + } + + /** Creates a mock Rendition ChildAssociationRef. */ + private ChildAssociationRef rendition(NodeRef source, NodeRef rendition) + { + return new ChildAssociationRef(RenditionModel.ASSOC_RENDITION, source, RenditionModel.ASSOC_RENDITION, rendition); + } +} 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 index 86ab1bd54c..e27de66301 100644 --- 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 @@ -18,15 +18,29 @@ */ package org.alfresco.module.org_alfresco_module_rm.model.clf.aspect; +import static java.util.Arrays.asList; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; +import java.io.Serializable; import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import org.alfresco.model.RenditionModel; 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.model.ClassifiedContentModel; +import org.alfresco.module.org_alfresco_module_rm.util.CoreServicesExtras; +import org.alfresco.service.cmr.rendition.RenditionService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; @@ -40,10 +54,17 @@ import org.mockito.Mock; */ public class ClassifiedAspectUnitTest implements ClassifiedContentModel { - private static final NodeRef NODE_REF = new NodeRef("node://Ref/"); + private static final NodeRef NODE_REF = new NodeRef("node://Ref/"); + private static final NodeRef RENDITION_1 = new NodeRef("node://rendition1/"); + private static final NodeRef RENDITION_2 = new NodeRef("node://rendition2/"); + private static final ClassificationLevel TOP_SECRET = new ClassificationLevel("Top Secret", "Top Secret"); + private static final ClassificationLevel SECRET = new ClassificationLevel("Secret", "Secret"); @InjectMocks ClassifiedAspect classifiedAspect; - @Mock NodeService mockNodeService; + @Mock ClassificationSchemeService mockClassificationSchemeService; + @Mock CoreServicesExtras mockCoreServicesExtras; + @Mock NodeService mockNodeService; + @Mock RenditionService mockRenditionService; @Before public void setUp() @@ -103,11 +124,67 @@ public class ClassifiedAspectUnitTest implements ClassifiedContentModel @Test(expected = MissingDowngradeInstructions.class) public void testCheckConsistencyOfProperties_emptyStringsSupplied() { - when(mockNodeService.hasAspect(NODE_REF, ASPECT_CLASSIFIED)).thenReturn(true); + for (NodeRef n : asList(NODE_REF, RENDITION_1, RENDITION_2)) + { + when(mockNodeService.hasAspect(n, ASPECT_CLASSIFIED)).thenReturn(true); + } when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_DATE)).thenReturn(""); when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_EVENT)).thenReturn("Event"); when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_INSTRUCTIONS)).thenReturn(""); classifiedAspect.checkConsistencyOfProperties(NODE_REF); } + + /** Check that when a node is classified, its renditions are also classified. */ + @Test public void classificationOfNodeShouldClassifyRenditions() + { + for (NodeRef n : asList(NODE_REF, RENDITION_1, RENDITION_2)) + { + when(mockNodeService.hasAspect(n, ASPECT_CLASSIFIED)).thenReturn(true); + } + when(mockClassificationSchemeService.getClassificationLevelById(eq("Top Secret"))).thenReturn(TOP_SECRET); + when(mockClassificationSchemeService.getClassificationLevelById(eq("Secret"))).thenReturn(SECRET); + when(mockClassificationSchemeService.getReclassification(any(), any())).thenReturn(ClassificationSchemeService.Reclassification.DOWNGRADE); + when(mockRenditionService.getRenditions(eq(NODE_REF))) + .thenReturn(asList(rendition(NODE_REF, RENDITION_1), rendition(NODE_REF, RENDITION_2))); + + classifiedAspect.onAddAspect(NODE_REF, ASPECT_CLASSIFIED); + + for (NodeRef rendition : asList(RENDITION_1, RENDITION_2)) + { + verify(mockCoreServicesExtras).copyAspect(eq(NODE_REF), eq(rendition), eq(ClassifiedContentModel.ASPECT_CLASSIFIED)); + } + } + + @Test public void reclassificationOfNodeShouldReclassifyRenditions() + { + for (NodeRef n : asList(NODE_REF, RENDITION_1, RENDITION_2)) + { + when(mockNodeService.hasAspect(n, ASPECT_CLASSIFIED)).thenReturn(true); + } + when(mockClassificationSchemeService.getClassificationLevelById(eq("Top Secret"))).thenReturn(TOP_SECRET); + when(mockClassificationSchemeService.getClassificationLevelById(eq("Secret"))).thenReturn(SECRET); + when(mockClassificationSchemeService.getReclassification(any(), any())).thenReturn(ClassificationSchemeService.Reclassification.DOWNGRADE); + when(mockRenditionService.getRenditions(eq(NODE_REF))) + .thenReturn(asList(rendition(NODE_REF, RENDITION_1), rendition(NODE_REF, RENDITION_2))); + + Map oldProps = new HashMap<>(); + oldProps.put(PROP_CLASSIFIED_BY, "userone"); + oldProps.put(PROP_CURRENT_CLASSIFICATION, "Top Secret"); + Map newProps = new HashMap<>(oldProps); + newProps.put(PROP_CURRENT_CLASSIFICATION, "Secret"); + + classifiedAspect.onUpdateProperties(NODE_REF, oldProps, newProps); + + for (NodeRef rendition : asList(RENDITION_1, RENDITION_2)) + { + verify(mockCoreServicesExtras).copyAspect(eq(NODE_REF), eq(rendition), eq(ClassifiedContentModel.ASPECT_CLASSIFIED)); + } + } + + /** Creates a mock Rendition ChildAssociationRef. */ + private ChildAssociationRef rendition(NodeRef source, NodeRef rendition) + { + return new ChildAssociationRef(RenditionModel.ASSOC_RENDITION, source, RenditionModel.ASSOC_RENDITION, rendition); + } } diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/util/CoreServicesExtrasUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/util/CoreServicesExtrasUnitTest.java new file mode 100644 index 0000000000..d8551a3494 --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/util/CoreServicesExtrasUnitTest.java @@ -0,0 +1,122 @@ +/* + * 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.util; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.mock; + +import static org.alfresco.module.org_alfresco_module_rm.test.util.ExceptionUtils.expectedException; +import static org.junit.Assert.assertEquals; + +import org.alfresco.service.cmr.dictionary.AspectDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryException; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.QName; +import org.junit.Before; +import org.junit.Test; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Unit tests for {@link CoreServicesExtras}. + * + * @author Neil Mc Erlean + * @since 3.0.a + */ +public class CoreServicesExtrasUnitTest +{ + private CoreServicesExtras serviceExtras; + + private final QName testAspect = QName.createQName("test", "aspect"); + private final QName testProp1 = QName.createQName("test", "prop1"); + private final QName testProp2 = QName.createQName("test", "prop2"); + private final QName testProp3 = QName.createQName("test", "prop3"); + private final NodeRef testNode1 = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "1"); + private final NodeRef testNode2 = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "2"); + + @Before public void setUp() + { + serviceExtras = new CoreServicesExtras(); + } + + @Test public void copyingAnUnknownAspectShouldResultInAnException() + { + final DictionaryService mockDS = mock(DictionaryService.class); + + when(mockDS.getAspect(any(QName.class))).thenReturn(null); + serviceExtras.setDictionaryService(mockDS); + + expectedException(DictionaryException.class, () -> serviceExtras.copyAspect(testNode1, testNode2, testAspect)); + } + + @Test public void copyingAnAspectWithNoProperties() + { + final DictionaryService mockDS = mock(DictionaryService.class); + final NodeService mockNS = mock(NodeService.class); + + final AspectDefinition mockAspect = mock(AspectDefinition.class); + when(mockAspect.getProperties()).thenReturn(Collections.emptyMap()); + + when(mockDS.getAspect(eq(testAspect))).thenReturn(mockAspect); + when(mockNS.getProperties(eq(testNode1))).thenReturn(Collections.emptyMap()); + serviceExtras.setDictionaryService(mockDS); + serviceExtras.setNodeService(mockNS); + + assertEquals(Collections.emptyMap(), serviceExtras.copyAspect(testNode1, testNode2, testAspect)); + } + + @Test public void copyingAnAspectWithProperties() + { + final DictionaryService mockDS = mock(DictionaryService.class); + final NodeService mockNS = mock(NodeService.class); + + final AspectDefinition mockAspect = mock(AspectDefinition.class); + final Map props = new HashMap<>(); + final PropertyDefinition mockProp1 = mock(PropertyDefinition.class); + final PropertyDefinition mockProp2 = mock(PropertyDefinition.class); + props.put(testProp1, mockProp1); + props.put(testProp2, mockProp2); + when(mockAspect.getProperties()).thenReturn(props); + + final Map propVals = new HashMap<>(); + propVals.put(testProp1, "one"); + propVals.put(testProp2, "two"); + propVals.put(testProp3, "three"); // Not defined on the aspect above. + when(mockDS.getAspect(eq(testAspect))).thenReturn(mockAspect); + when(mockNS.getProperties(eq(testNode1))).thenReturn(propVals); + + serviceExtras.setDictionaryService(mockDS); + serviceExtras.setNodeService(mockNS); + + Map expected = new HashMap<>(); + expected.put(testProp1, "one"); + expected.put(testProp2, "two"); + assertEquals(expected, serviceExtras.copyAspect(testNode1, testNode2, testAspect)); + } +}