diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/BaseBehaviourBean.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/BaseBehaviourBean.java index d2d21414d4..80eaf57274 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/BaseBehaviourBean.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/BaseBehaviourBean.java @@ -27,16 +27,22 @@ package org.alfresco.module.org_alfresco_module_rm.model; +import java.security.InvalidParameterException; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.annotation.BehaviourRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import com.google.common.collect.Sets; + /** * Convenient base class for behaviour beans. * @@ -87,4 +93,28 @@ public abstract class BaseBehaviourBean extends ServiceBaseImpl return behaviours.get(name); } + /** + * Helper method that checks if the newly created child association complies with the RM rules + * @param parent the parent node + * @param childType the child node + * @param acceptedUniqueChildType a list of node types that are accepted as children of the provided parent only once + * @param acceptedMultipleChildType a list of node types that are accepted as children of the provided parent multiple times + * @throws InvalidParameterException if the child association doesn't comply with the RM rules + */ + protected void validateNewChildAssociation(NodeRef parent, NodeRef child, List acceptedUniqueChildType, List acceptedMultipleChildType) throws InvalidParameterException + { + QName childType = getInternalNodeService().getType(child); + if(acceptedUniqueChildType.contains(childType)) + { + // check the user is not trying to create multiple children of a type that is only accepted once + if(nodeService.getChildAssocs(parent, Sets.newHashSet(childType)).size() > 1) + { + throw new InvalidParameterException("Operation failed. Multiple children of this type are not allowed."); + } + } + else if(!acceptedMultipleChildType.contains(childType)) + { + throw new InvalidParameterException("Operation failed. Children of type " + childType + " are not allowed"); + } + } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/FilePlanType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/FilePlanType.java index e2e7ddafac..9ff345353b 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/FilePlanType.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/FilePlanType.java @@ -27,8 +27,10 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type; -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.model.ContentModel; +import java.security.InvalidParameterException; +import java.util.Arrays; +import java.util.List; + import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; @@ -45,6 +47,9 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; + +import com.google.common.collect.Sets; /** * rma:filePlan behaviour bean @@ -61,6 +66,9 @@ public class FilePlanType extends BaseBehaviourBean NodeServicePolicies.OnCreateNodePolicy, NodeServicePolicies.OnDeleteNodePolicy { + private static List ACCEPTED_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_HOLD_CONTAINER, TYPE_TRANSFER_CONTAINER, TYPE_UNFILED_RECORD_CONTAINER); + private static List ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_RECORD_CATEGORY); + /** file plan service */ private FilePlanService filePlanService; @@ -147,20 +155,8 @@ public class FilePlanType extends BaseBehaviourBean @Override public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew) { - // ensure we are not trying to put content in the file plan root node - NodeRef nodeRef = childAssocRef.getChildRef(); - if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT)) - { - throw new AlfrescoRuntimeException("Operation failed, because you can't place content in the root of the file plan."); - } - - // ensure we are not trying to put a record folder in the root of the file plan - NodeRef parent = childAssocRef.getParentRef(); - if (getFilePlanService().isFilePlan(parent) && getRecordFolderService().isRecordFolder(nodeRef)) - { - throw new AlfrescoRuntimeException("Operation failed, because you can not place a record folder in the root of the file plan."); - } - + // check the created child is of an accepted type + validateNewChildAssociation(childAssocRef.getParentRef(), childAssocRef.getChildRef(), ACCEPTED_UNIQUE_CHILD_TYPES, ACCEPTED_NON_UNIQUE_CHILD_TYPES); } /** diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/FilePlanTypeUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/FilePlanTypeUnitTest.java new file mode 100644 index 0000000000..bdad80df6e --- /dev/null +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/FilePlanTypeUnitTest.java @@ -0,0 +1,193 @@ +/* + * #%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.model.rma.type; + +import static org.mockito.Mockito.when; + +import java.security.InvalidParameterException; +import java.util.Arrays; + +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; + +import com.google.common.collect.Sets; + +/** + * Unit test that test the conditions enforced by FilePlanType behavior bean + * + * @author Ana Bozianu + * @since 2.6 + */ +public class FilePlanTypeUnitTest extends BaseUnitTest +{ + + /** test object */ + private @InjectMocks FilePlanType filePlanType; + + /** existing fileplan node */ + private NodeRef filePlanContainer; + + @Before + public void setup() + { + filePlanContainer = generateNodeRef(TYPE_FILE_PLAN, true); + } + + /** + * Having the Fileplan container + * When adding a child of type TYPE_FILE_PLAN + * Then an error should be thrown + */ + @Test (expected = InvalidParameterException.class) + public void testAddFileplanToFileplan() + { + ChildAssociationRef childAssoc = createFileplanContainerChild(TYPE_FILE_PLAN); + filePlanType.onCreateChildAssociation(childAssoc, true); + } + + /** + * Having the Fileplan container + * When adding multiple child of type TYPE_RECORD_CATEGORY + * Then child associations should be created + */ + @Test + public void testAddCategoriesToFileplan() + { + // add the first child + ChildAssociationRef childAssoc1 = createFileplanContainerChild(TYPE_RECORD_CATEGORY); + filePlanType.onCreateChildAssociation(childAssoc1, true); + + // add the second child + ChildAssociationRef childAssoc2 = createFileplanContainerChild(TYPE_RECORD_CATEGORY); + filePlanType.onCreateChildAssociation(childAssoc2, true); + } + + /** + * Having the Fileplan container + * When creating the first child of type TYPE_HOLD_CONTAINER + * Then the fileplan behavior bean shouldn't complain + */ + @Test + public void testCreateHoldContainers() + { + ChildAssociationRef childAssoc = createFileplanContainerChild(TYPE_HOLD_CONTAINER); + + when(mockedNodeService.getChildAssocs(filePlanContainer, Sets.newHashSet(TYPE_HOLD_CONTAINER))).thenReturn(Arrays.asList(childAssoc)); + filePlanType.onCreateChildAssociation(childAssoc, true); + } + + /** + * Having the Fileplan container with a child of type TYPE_HOLD_CONTAINER + * When adding another child of type TYPE_HOLD_CONTAINER + * Then an error should be thrown + */ + @Test (expected = InvalidParameterException.class) + public void testCreateMultipleHoldContainers() + { + ChildAssociationRef existingHoldAssoc = createFileplanContainerChild(TYPE_HOLD_CONTAINER); + ChildAssociationRef childAssoc = createFileplanContainerChild(TYPE_HOLD_CONTAINER); + + when(mockedNodeService.getChildAssocs(filePlanContainer, Sets.newHashSet(TYPE_HOLD_CONTAINER))).thenReturn(Arrays.asList(existingHoldAssoc, childAssoc)); + filePlanType.onCreateChildAssociation(childAssoc, true); + } + + /** + * Having the Fileplan container + * When creating the first child of type TYPE_TRANSFER_CONTAINER + * Then the fileplan behavior bean shouldn't complain + */ + @Test + public void testCreateTransferContainers() + { + ChildAssociationRef childAssoc = createFileplanContainerChild(TYPE_TRANSFER_CONTAINER); + + when(mockedNodeService.getChildAssocs(filePlanContainer, Sets.newHashSet(TYPE_TRANSFER_CONTAINER))).thenReturn(Arrays.asList(childAssoc)); + filePlanType.onCreateChildAssociation(childAssoc, true); + } + + /** + * Having the Fileplan container with a child of type TYPE_TRANSFER_CONTAINER + * When adding another child of type TYPE_TRANSFER_CONTAINER + * Then an error should be thrown + */ + @Test (expected = InvalidParameterException.class) + public void testCreateMultipleTransferContainers() + { + ChildAssociationRef existingHoldAssoc = createFileplanContainerChild(TYPE_TRANSFER_CONTAINER); + ChildAssociationRef childAssoc = createFileplanContainerChild(TYPE_TRANSFER_CONTAINER); + + when(mockedNodeService.getChildAssocs(filePlanContainer, Sets.newHashSet(TYPE_TRANSFER_CONTAINER))).thenReturn(Arrays.asList(existingHoldAssoc, childAssoc)); + filePlanType.onCreateChildAssociation(childAssoc, true); + } + + /** + * Having the Fileplan container + * When creating the first child of type TYPE_UNFILED_RECORD_CONTAINER + * Then the fileplan behavior bean shouldn't complain + */ + @Test + public void testCreateUnfiledRecordsContainers() + { + ChildAssociationRef childAssoc = createFileplanContainerChild(TYPE_UNFILED_RECORD_CONTAINER); + + when(mockedNodeService.getChildAssocs(filePlanContainer, Sets.newHashSet(TYPE_UNFILED_RECORD_CONTAINER))).thenReturn(Arrays.asList(childAssoc)); + filePlanType.onCreateChildAssociation(childAssoc, true); + } + + /** + * Having the Fileplan container with a child of type TYPE_UNFILED_RECORD_CONTAINER + * When adding another child of type TYPE_UNFILED_RECORD_CONTAINER + * Then an error should be thrown + */ + @Test (expected = InvalidParameterException.class) + public void testCreateMultipleUnfiledRecordsContainers() + { + ChildAssociationRef existingHoldAssoc = createFileplanContainerChild(TYPE_UNFILED_RECORD_CONTAINER); + ChildAssociationRef childAssoc = createFileplanContainerChild(TYPE_UNFILED_RECORD_CONTAINER); + + when(mockedNodeService.getChildAssocs(filePlanContainer, Sets.newHashSet(TYPE_UNFILED_RECORD_CONTAINER))).thenReturn(Arrays.asList(existingHoldAssoc, childAssoc)); + filePlanType.onCreateChildAssociation(childAssoc, true); + } + + /** + * Helper method that creates a child of the fileplan container with the provided type + * @param childType the node type of the child to be created + * @return the child association between the fileplan and the created node + */ + private ChildAssociationRef createFileplanContainerChild(QName childType) + { + NodeRef child = generateNodeRef(childType); + return new ChildAssociationRef( ContentModel.ASSOC_CONTAINS, filePlanContainer, childType, child); + } +}