From 1712bac9957a223f816ad547db2f178cb0264b1c Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Mon, 12 Jun 2017 16:17:24 +0100 Subject: [PATCH] RM-4689 (Can delete all RM site content through Repository browser) Manually backported following changes: RM-4293 734c1b2a82d900c9468028700ce54a0f47f61d4f RM-4326 a4aac053a86ad58ca163836047edd5ee5a3a6e0e c6ca74ab26a37b0fd0fc7c56bb8b3311c9ce90cf --- .gitignore | 3 + .../rm-capabilities-fileplan-context.xml | 31 +++++ .../rm-capabilities-group-context.xml | 2 + .../rm-model-context.xml | 12 ++ .../rm-service-context.xml | 8 +- .../model/BaseBehaviourBean.java | 61 ++++++++- .../model/rma/type/FilePlanType.java | 125 +++++++++++++++--- .../model/rma/type/HoldContainerType.java | 41 +++++- .../model/rma/type/RecordCategoryType.java | 21 ++- .../model/rma/type/RmSiteType.java | 79 ++++++++++- .../model/rma/type/TransferContainerType.java | 53 ++++++-- .../model/rma/type/TransferType.java | 79 +++++++++++ .../rma/type/UnfiledRecordContainerType.java | 97 ++++++++++++++ .../rma/type/UnfiledRecordFolderType.java | 70 ++++++++++ .../transfer/TransferServiceImpl.java | 57 +++++--- .../test/integration/issue/RM3341Test.java | 24 ++-- .../test/integration/issue/RM4293Test.java | 125 ++++++++++++++++++ .../type/TransferContainerTypeUnitTest.java | 54 ++++---- 18 files changed, 831 insertions(+), 111 deletions(-) create mode 100644 rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferType.java create mode 100644 rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordContainerType.java create mode 100644 rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordFolderType.java create mode 100644 rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM4293Test.java diff --git a/.gitignore b/.gitignore index dfdc3e2322..f5146b465f 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ test-output /rm-enterprise/rm-automation-enterprise/root rm-automation/src/test/resources/webdriver.properties + +/rm-community/rm-community-rest-api-explorer/overlays +/rm-enterprise/rm-enterprise-rest-api-explorer/overlays \ No newline at end of file diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-fileplan-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-fileplan-context.xml index e8eeae8602..b7d1e33fd6 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-fileplan-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-fileplan-context.xml @@ -94,4 +94,35 @@ + + + + + TRANSFER_CONTAINER + + + + + + + + + + + + + + + HOLD_CONTAINER + + + + + + + + + \ No newline at end of file diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-group-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-group-context.xml index 91a50ef89d..3b67d92639 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-group-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/capability/rm-capabilities-group-context.xml @@ -25,6 +25,8 @@ + + diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml index 7eb9c17eda..8fe840ba94 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-model-context.xml @@ -76,6 +76,9 @@ + + + @@ -84,6 +87,14 @@ + + + + + + + @@ -105,6 +116,7 @@ + diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml index 0298088a35..f7e95ba278 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml @@ -173,6 +173,8 @@ + + @@ -579,9 +581,9 @@ parent="baseService"> - - - + + + 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 bd09ccb6b1..4fc2b96b93 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,15 +27,20 @@ package org.alfresco.module.org_alfresco_module_rm.model; +import com.google.common.collect.Sets; 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.node.integrity.IntegrityException; 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 org.springframework.extensions.surf.util.I18NUtil; /** * Convenient base class for behaviour beans. @@ -50,6 +55,12 @@ public abstract class BaseBehaviourBean extends ServiceBaseImpl /** Logger */ protected static final Log LOGGER = LogFactory.getLog(BaseBehaviourBean.class); + /** + * I18N + */ + protected static final String UNIQUE_CHILD_TYPE_ERROR = "rm.action.unique.child.type-error-message"; + protected static final String MULTIPLE_CHILDREN_TYPE_ERROR = "rm.action.multiple.children.type-error-message"; + /** behaviour filter */ protected BehaviourFilter behaviourFilter; @@ -87,4 +98,52 @@ 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 IntegrityException if the child association doesn't comply with the RM rules + */ + protected void validateNewChildAssociation(NodeRef parent, NodeRef child, List acceptedUniqueChildType, List acceptedMultipleChildType) throws IntegrityException + { + 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 IntegrityException(I18NUtil.getMessage(UNIQUE_CHILD_TYPE_ERROR), null); + } + } + else if (!acceptedMultipleChildType.contains(childType)) + { + throw new IntegrityException(I18NUtil.getMessage(MULTIPLE_CHILDREN_TYPE_ERROR, childType), null); + } + } + + /** + * Helper method that checks if the newly created child association is between the sub-types of accepted types. + * + * @param child the child node + * @param acceptedMultipleChildType a list of node types that are accepted as children of the provided parent multiple times + * @throws IntegrityException if the child association isn't between the sub-types of accepted types + */ + protected void validateNewChildAssociationSubTypesIncluded(NodeRef child, List acceptedMultipleChildType) + throws IntegrityException + { + QName childType = getInternalNodeService().getType(child); + for (QName type : acceptedMultipleChildType) + { + if (instanceOf(childType, type)) + { + return; + } + } + //no match was found in sub-types of permitted types list + throw new IntegrityException(I18NUtil.getMessage(MULTIPLE_CHILDREN_TYPE_ERROR, childType), null); + } } 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 8344e8f696..485c7b5543 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,7 +27,8 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type; -import org.alfresco.error.AlfrescoRuntimeException; +import java.util.Arrays; +import java.util.List; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.identifier.IdentifierService; @@ -36,6 +37,7 @@ import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService; import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService; import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.BehaviourBean; @@ -45,6 +47,7 @@ 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; /** * rma:filePlan behaviour bean @@ -59,8 +62,13 @@ import org.alfresco.service.cmr.repository.NodeRef; public class FilePlanType extends BaseBehaviourBean implements NodeServicePolicies.OnCreateChildAssociationPolicy, NodeServicePolicies.OnCreateNodePolicy, - NodeServicePolicies.OnDeleteNodePolicy + NodeServicePolicies.OnDeleteNodePolicy, + NodeServicePolicies.BeforeDeleteNodePolicy { + private final static List ACCEPTED_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_HOLD_CONTAINER, TYPE_TRANSFER_CONTAINER, TYPE_UNFILED_RECORD_CONTAINER); + private final static List ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_RECORD_CATEGORY); + private static final String BEHAVIOUR_NAME = "onDeleteFilePlan"; + /** file plan service */ private FilePlanService filePlanService; @@ -73,6 +81,21 @@ public class FilePlanType extends BaseBehaviourBean /** file plan role service */ private FilePlanRoleService filePlanRoleService; + /** + * Unfiled Record Container Type behaviour bean + */ + private UnfiledRecordContainerType unfilerRecordContainerType; + + /** + * Transfer Container Type behaviour bean + */ + private TransferContainerType transferContainerType; + + /** + * Hold Container Type behaviour bean + */ + private HoldContainerType holdContainerType; + /** * @return File plan service */ @@ -137,6 +160,46 @@ public class FilePlanType extends BaseBehaviourBean this.filePlanRoleService = filePlanRoleService; } + /** + * @param unfilerRecordContainerType - unfiled record container type behaviour bean + */ + public void setUnfilerRecordContainerType(UnfiledRecordContainerType unfilerRecordContainerType) + { + this.unfilerRecordContainerType = unfilerRecordContainerType; + } + + /** + * @param transferContainerType - transfer container type behaviour bean + */ + public void setTransferContainerType(TransferContainerType transferContainerType) + { + this.transferContainerType = transferContainerType; + } + + /** + * @param holdContainerType - hold container type behaviour bean + */ + public void setHoldContainerType(HoldContainerType holdContainerType) + { + this.holdContainerType = holdContainerType; + } + + /** + * Disable the behaviours for this transaction + */ + public void disable() + { + getBehaviour(BEHAVIOUR_NAME).disable(); + } + + /** + * Enable behaviours for this transaction + */ + public void enable() + { + getBehaviour(BEHAVIOUR_NAME).enable(); + } + /** * @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean) */ @@ -147,20 +210,17 @@ 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)) + // We need to automatically cast the created folder to category if it is a plain folder + // This occurs if the RM folder has been created via IMap, WebDav, etc. Don't check subtypes. + // Some modules use hidden files to store information (see RM-3283) + if (nodeService.getType(childAssocRef.getChildRef()) + .equals(ContentModel.TYPE_FOLDER)) { - 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."); + nodeService.setType(childAssocRef.getChildRef(), TYPE_RECORD_CATEGORY); } + // check the created child is of an accepted type + validateNewChildAssociation(childAssocRef.getParentRef(), childAssocRef.getChildRef(), ACCEPTED_UNIQUE_CHILD_TYPES, ACCEPTED_NON_UNIQUE_CHILD_TYPES); } /** @@ -182,8 +242,8 @@ public class FilePlanType extends BaseBehaviourBean { // ensure rules are not inherited nodeService.addAspect(filePlan, RuleModel.ASPECT_IGNORE_INHERITED_RULES, null); - - // set the identifier + + // set the identifier if (nodeService.getProperty(filePlan, PROP_IDENTIFIER) == null) { String id = getIdentifierService().generateIdentifier(filePlan); @@ -201,15 +261,40 @@ public class FilePlanType extends BaseBehaviourBean /** * @see org.alfresco.repo.node.NodeServicePolicies.OnDeleteNodePolicy#onDeleteNode(org.alfresco.service.cmr.repository.ChildAssociationRef, boolean) */ - @Behaviour - ( - kind = BehaviourKind.CLASS, - notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT - ) @Override + @Behaviour(kind = BehaviourKind.CLASS, + notificationFrequency = NotificationFrequency.FIRST_EVENT, + name = BEHAVIOUR_NAME) public void onDeleteNode(ChildAssociationRef childAssocRef, boolean archived) + { + unfilerRecordContainerType.enable(); + transferContainerType.enable(); + holdContainerType.enable(); + throw new IntegrityException("Operation failed. Deletion of File Plan is not allowed.", null); + } + + /** + * @see org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy#beforeDeleteNode(org.alfresco.service.cmr.repository.NodeRef) + */ + @Override + @Behaviour(kind = BehaviourKind.CLASS, + notificationFrequency = NotificationFrequency.FIRST_EVENT) + public void beforeDeleteNode(NodeRef nodeRef) + { + unfilerRecordContainerType.disable(); + transferContainerType.disable(); + holdContainerType.disable(); + } + + @Behaviour(kind = BehaviourKind.CLASS, + policy = "alf:onDeleteNode", + notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT) + public void onDeleteNodeOnCommit(ChildAssociationRef childAssocRef, boolean archived) { // tear down the file plan roles getFilePlanRoleService().tearDownFilePlanRoles(childAssocRef.getChildRef()); + unfilerRecordContainerType.enable(); + transferContainerType.enable(); + holdContainerType.enable(); } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/HoldContainerType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/HoldContainerType.java index 16e233e3aa..937f5de737 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/HoldContainerType.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/HoldContainerType.java @@ -26,15 +26,19 @@ */ package org.alfresco.module.org_alfresco_module_rm.model.rma.type; +import java.util.Arrays; +import java.util.List; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.node.integrity.IntegrityException; 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.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; import org.springframework.extensions.surf.util.I18NUtil; /** @@ -45,9 +49,29 @@ import org.springframework.extensions.surf.util.I18NUtil; */ @BehaviourBean(defaultType = "rma:holdContainer") public class HoldContainerType extends BaseBehaviourBean - implements NodeServicePolicies.OnCreateChildAssociationPolicy, NodeServicePolicies.OnCreateNodePolicy + implements NodeServicePolicies.OnCreateChildAssociationPolicy, + NodeServicePolicies.OnCreateNodePolicy, + NodeServicePolicies.OnDeleteNodePolicy { private final static String MSG_ERROR_ADD_CONTENT_CONTAINER = "rm.service.error-add-content-container"; + private final static List ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_HOLD); + private static final String DELETE_BEHAVIOUR_NAME = "onDeleteHoldContainer"; + + /** + * Disable the behaviours for this transaction + */ + public void disable() + { + getBehaviour(DELETE_BEHAVIOUR_NAME).disable(); + } + + /** + * Enable behaviours for this transaction + */ + public void enable() + { + getBehaviour(DELETE_BEHAVIOUR_NAME).enable(); + } /** * On every event @@ -59,11 +83,8 @@ public class HoldContainerType extends BaseBehaviourBean @Behaviour(kind = BehaviourKind.ASSOCIATION) public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew) { - - NodeRef nodeRef = childAssocRef.getChildRef(); - if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT) == true) { throw new AlfrescoRuntimeException( - I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER)); } - + // check the created child is of an accepted type + validateNewChildAssociationSubTypesIncluded(childAssocRef.getChildRef(), ACCEPTED_NON_UNIQUE_CHILD_TYPES); } @Override @@ -74,4 +95,12 @@ public class HoldContainerType extends BaseBehaviourBean I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER)); } } + + @Override + @Behaviour(kind = BehaviourKind.CLASS, + name = DELETE_BEHAVIOUR_NAME) + public void onDeleteNode(ChildAssociationRef childAssocRef, boolean isNodeArchived) + { + throw new IntegrityException("Operation failed. Deletion of Hold Container is not allowed.", null); + } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java index 81dc259b95..eee8199119 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RecordCategoryType.java @@ -27,6 +27,9 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; @@ -62,6 +65,9 @@ public class RecordCategoryType extends BaseBehaviourBean NodeServicePolicies.OnCreateNodePolicy, NodeServicePolicies.OnMoveNodePolicy { + private final static List ACCEPTED_UNIQUE_CHILD_TYPES = new ArrayList(); + private final static List ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_RECORD_CATEGORY, TYPE_RECORD_FOLDER); + /** vital record service */ protected VitalRecordService vitalRecordService; @@ -107,17 +113,22 @@ public class RecordCategoryType extends BaseBehaviourBean ) public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew) { - // ensure content is not placed directly into a record category - NodeRef nodeRef = childAssocRef.getChildRef(); - if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT)) + QName childType = nodeService.getType(childAssocRef.getChildRef()); + + // We need to automatically cast the created folder to record folder if it is a plain folder + // This occurs if the RM folder has been created via IMap, WebDav, etc. Don't check subtypes. + // Some modules use hidden folders to store information (see RM-3283). + if (childType.equals(ContentModel.TYPE_FOLDER)) { - throw new AlfrescoRuntimeException("Operation failed, because you can't place content directly into a record category."); + nodeService.setType(childAssocRef.getChildRef(), TYPE_RECORD_FOLDER); } + validateNewChildAssociation(childAssocRef.getParentRef(), childAssocRef.getChildRef(), ACCEPTED_UNIQUE_CHILD_TYPES, ACCEPTED_NON_UNIQUE_CHILD_TYPES); + if (bNew) { // setup the record folder - recordFolderService.setupRecordFolder(nodeRef); + recordFolderService.setupRecordFolder(childAssocRef.getChildRef()); } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteType.java index 63fb27c048..682589598a 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteType.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/RmSiteType.java @@ -27,15 +27,20 @@ package org.alfresco.module.org_alfresco_module_rm.model.rma.type; +import com.google.common.collect.Sets; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; - import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; import org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchService; import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.BehaviourBean; @@ -54,6 +59,7 @@ import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.service.namespace.QName; import org.alfresco.util.ParameterCheck; import org.alfresco.util.PropertyMap; +import org.springframework.extensions.surf.util.I18NUtil; /** * Behaviour associated with the RM Site type @@ -68,12 +74,14 @@ import org.alfresco.util.PropertyMap; public class RmSiteType extends BaseBehaviourBean implements NodeServicePolicies.OnCreateNodePolicy, NodeServicePolicies.OnUpdatePropertiesPolicy, - NodeServicePolicies.BeforeDeleteNodePolicy + NodeServicePolicies.BeforeDeleteNodePolicy, + NodeServicePolicies.OnCreateChildAssociationPolicy { - /** Constant values */ - public static final String COMPONENT_DOCUMENT_LIBRARY = "documentLibrary"; + /** Constant values */ + public static final String COMPONENT_DOCUMENT_LIBRARY = "documentLibrary"; public static final String DEFAULT_SITE_NAME = "rm"; public static final QName DEFAULT_FILE_PLAN_TYPE = TYPE_FILE_PLAN; + private final static List ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(ContentModel.TYPE_FOLDER); /** Site service */ protected SiteService siteService; @@ -87,6 +95,8 @@ public class RmSiteType extends BaseBehaviourBean /** Authority service */ private AuthorityService authorityService; + private FilePlanType filePlanType; + /** Map of file plan type's key'ed by corresponding site types */ protected Map mapFilePlanType = new HashMap(3); @@ -123,6 +133,11 @@ public class RmSiteType extends BaseBehaviourBean this.authorityService = authorityService; } + public void setFilePlanType(FilePlanType filePlanType) + { + this.filePlanType = filePlanType; + } + /** * Registers a file plan type for a specific site type. * @@ -292,7 +307,63 @@ public class RmSiteType extends BaseBehaviourBean return null; } }); + filePlanType.disable(); } } } + + /** + * Add the limitation of creating only one rma:filePlan or one dod:filePlan depending on the type of rm site. + * Also added the limitation of crating two cm:folder type under rm site. + * Other than this nothing can be created under rm site nodeRef + * + * @author Silviu Dinuta + * @since 2.6 + */ + @Override + @Behaviour(kind = BehaviourKind.ASSOCIATION) + public void onCreateChildAssociation(final ChildAssociationRef childAssocRef, boolean isNewNode) + { + AuthenticationUtil.runAsSystem(new RunAsWork() + { + @Override + public Void doWork() + { + final NodeRef child = childAssocRef.getChildRef(); + final NodeRef parent = childAssocRef.getParentRef(); + List acceptedUniqueChildTypes = new ArrayList(); + SiteInfo siteInfo = siteService.getSite(parent); + acceptedUniqueChildTypes.add(getFilePlanType(siteInfo)); + // check the created child is of an accepted type + validateNewChildAssociation(parent, child, acceptedUniqueChildTypes, ACCEPTED_NON_UNIQUE_CHILD_TYPES); + return null; + } + }); + } + + /** + * Overridden this because in this case we need to have multiple cm:folder types but not more than two of them. + * The two mentioned folders are created when rm site is created and one of them is Saved Searches and the other surf-config folder. + * After that creation of cm:folder should not be allowed under rm site node + */ + @Override + protected void validateNewChildAssociation(NodeRef parent, NodeRef child, List acceptedUniqueChildType, + List acceptedMultipleChildType) throws IntegrityException + { + super.validateNewChildAssociation(parent, child, acceptedUniqueChildType, acceptedMultipleChildType); + + // check the user is not trying to create more than 2 folders that are created by default. + if (nodeService.getChildAssocs(parent, Sets.newHashSet(ContentModel.TYPE_FOLDER)).size() > 2) + { + throw new IntegrityException(I18NUtil.getMessage(MULTIPLE_CHILDREN_TYPE_ERROR, ContentModel.TYPE_FOLDER), null); + } + } + + @Behaviour(kind = BehaviourKind.CLASS, + policy = "alf:onDeleteNode", + notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT) + public void onDeleteNodeOnCommit(ChildAssociationRef childAssocRef, boolean isNodeArchived) + { + filePlanType.enable(); + } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerType.java index 753e4b2036..06694e3308 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerType.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerType.java @@ -30,6 +30,7 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourKind; @@ -45,31 +46,61 @@ import org.springframework.extensions.surf.util.I18NUtil; */ @BehaviourBean(defaultType = "rma:transferContainer") public class TransferContainerType extends BaseBehaviourBean - implements NodeServicePolicies.OnCreateChildAssociationPolicy, NodeServicePolicies.OnCreateNodePolicy + implements NodeServicePolicies.OnCreateChildAssociationPolicy, + NodeServicePolicies.OnCreateNodePolicy, + NodeServicePolicies.OnDeleteNodePolicy { private final static String MSG_ERROR_ADD_CONTENT_CONTAINER = "rm.service.error-add-content-container"; + private final static String MSG_ERROR_ADD_CHILD_TO_TRANSFER_CONTAINER = "rm.action.create.transfer.container.child-error-message"; + private static final String BEHAVIOUR_NAME = "onCreateChildAssocsForTransferContainer"; + private static final String DELETE_BEHAVIOUR_NAME = "onDeleteTransferContainer"; /** - * On every event + * Disable the behaviours for this transaction + */ + public void disable() + { + getBehaviour(BEHAVIOUR_NAME).disable(); + getBehaviour(DELETE_BEHAVIOUR_NAME).disable(); + } + + /** + * Enable behaviours for this transaction + */ + public void enable() + { + getBehaviour(BEHAVIOUR_NAME).enable(); + getBehaviour(DELETE_BEHAVIOUR_NAME).enable(); + } + + /** + * Prevent creating a node inside transfer container, this will be possible only through internal services in a controlled manner. * - * @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, - * boolean) + * @see org.alfresco.repo.node.NodeServicePolicies.OnCreateChildAssociationPolicy#onCreateChildAssociation(org.alfresco.service.cmr.repository.ChildAssociationRef, * boolean) */ @Override - @Behaviour(kind = BehaviourKind.ASSOCIATION) + @Behaviour(kind = BehaviourKind.ASSOCIATION, + name = BEHAVIOUR_NAME) public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean bNew) { - // ensure not content to be added in Holdsfolder - NodeRef nodeRef = childAssocRef.getChildRef(); - if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT) == true) { throw new AlfrescoRuntimeException( - I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER)); } + throw new IntegrityException(I18NUtil.getMessage(MSG_ERROR_ADD_CHILD_TO_TRANSFER_CONTAINER), null); } @Override public void onCreateNode(ChildAssociationRef childAssocRef) { NodeRef nodeRef = childAssocRef.getChildRef(); - if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT) == true) { throw new AlfrescoRuntimeException( - I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER)); } + if (instanceOf(nodeRef, ContentModel.TYPE_CONTENT) == true) + { + throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER)); + } + } + + @Override + @Behaviour(kind = BehaviourKind.CLASS, + name = DELETE_BEHAVIOUR_NAME) + public void onDeleteNode(ChildAssociationRef childAssocRef, boolean isNodeArchived) + { + throw new IntegrityException("Operation failed. Deletion of Transfer Container is not allowed.", null); } } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferType.java new file mode 100644 index 0000000000..ba0989bab0 --- /dev/null +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferType.java @@ -0,0 +1,79 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 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 org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; +import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.node.integrity.IntegrityException; +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.repository.ChildAssociationRef; +import org.springframework.extensions.surf.util.I18NUtil; + +/** + * rma:transfer behaviour bean + * + * @author Silviu Dinuta + * @since 2.6 + */ +@BehaviourBean(defaultType = "rma:transfer") +public class TransferType extends BaseBehaviourBean + implements NodeServicePolicies.OnCreateChildAssociationPolicy +{ + private final static String MSG_ERROR_ADD_CHILD_TO_TRANSFER = "rm.action.create.transfer.child-error-message"; + + private static final String CREATE_CHILD_BEHAVIOUR_NAME = "onCreateChildAssocsForTransferType"; + + /** + * Disable the behaviours for this transaction + */ + public void disable() + { + getBehaviour(CREATE_CHILD_BEHAVIOUR_NAME).disable(); + } + + /** + * Enable behaviours for this transaction + */ + public void enable() + { + getBehaviour(CREATE_CHILD_BEHAVIOUR_NAME).enable(); + } + + /** + * Prevent creating a node inside transfer folder, this will be possible only through internal services in a controlled manner. + */ + @Override + @Behaviour(kind = BehaviourKind.ASSOCIATION, + name = CREATE_CHILD_BEHAVIOUR_NAME) + public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode) + { + throw new IntegrityException(I18NUtil.getMessage(MSG_ERROR_ADD_CHILD_TO_TRANSFER), null); + } +} diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordContainerType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordContainerType.java new file mode 100644 index 0000000000..4c051465e4 --- /dev/null +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordContainerType.java @@ -0,0 +1,97 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 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 java.util.Arrays; +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; +import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.node.integrity.IntegrityException; +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.repository.ChildAssociationRef; +import org.alfresco.service.namespace.QName; + +/** + * rma:unfiledRecordContainer behaviour bean + * + * @author Silviu Dinuta + * @since 2.6 + */ +@BehaviourBean(defaultType = "rma:unfiledRecordContainer") +public class UnfiledRecordContainerType extends BaseBehaviourBean + implements NodeServicePolicies.OnCreateChildAssociationPolicy, + NodeServicePolicies.OnDeleteNodePolicy +{ + private static final String BEHAVIOUR_NAME = "onDeleteUnfiledRecordContainer"; + private final static List ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_UNFILED_RECORD_FOLDER, ContentModel.TYPE_CONTENT, TYPE_NON_ELECTRONIC_DOCUMENT); + + /** + * Disable the behaviours for this transaction + */ + public void disable() + { + getBehaviour(BEHAVIOUR_NAME).disable(); + } + + /** + * Enable behaviours for this transaction + */ + public void enable() + { + getBehaviour(BEHAVIOUR_NAME).enable(); + } + + @Override + @Behaviour(kind = BehaviourKind.ASSOCIATION) + public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode) + { + // We need to automatically cast the created folder to record folder if it is a plain folder + // This occurs if the RM folder has been created via IMap, WebDav, etc. Don't check subtypes. + // Some modules use hidden folder subtypes to store information (see RM-3283). + QName childType = nodeService.getType(childAssocRef.getChildRef()); + if (childType.equals(ContentModel.TYPE_FOLDER)) + { + nodeService.setType(childAssocRef.getChildRef(), TYPE_UNFILED_RECORD_FOLDER); + } + + // check the created child is of an accepted type + validateNewChildAssociationSubTypesIncluded(childAssocRef.getChildRef(), ACCEPTED_NON_UNIQUE_CHILD_TYPES); + } + + @Override + @Behaviour(kind = BehaviourKind.CLASS, + name = BEHAVIOUR_NAME) + public void onDeleteNode(ChildAssociationRef childAssocRef, boolean isNodeArchived) + { + throw new IntegrityException("Operation failed. Deletion of Unfiled Record Container is not allowed.", null); + } +} \ No newline at end of file diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordFolderType.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordFolderType.java new file mode 100644 index 0000000000..51f4f62981 --- /dev/null +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/UnfiledRecordFolderType.java @@ -0,0 +1,70 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 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 java.util.Arrays; +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.model.BaseBehaviourBean; +import org.alfresco.repo.node.NodeServicePolicies; +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.repository.ChildAssociationRef; +import org.alfresco.service.namespace.QName; + +/** + * rma:unfiledRecordFolder behaviour bean + * + * @author Silviu Dinuta + * @since 2.6 + */ +@BehaviourBean(defaultType = "rma:unfiledRecordFolder") +public class UnfiledRecordFolderType extends BaseBehaviourBean + implements NodeServicePolicies.OnCreateChildAssociationPolicy +{ + private final static List ACCEPTED_NON_UNIQUE_CHILD_TYPES = Arrays.asList(TYPE_UNFILED_RECORD_FOLDER, ContentModel.TYPE_CONTENT, TYPE_NON_ELECTRONIC_DOCUMENT); + + @Override + @Behaviour(kind = BehaviourKind.ASSOCIATION) + public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNewNode) + { + // We need to automatically cast the created folder to record folder if it is a plain folder + // This occurs if the RM folder has been created via IMap, WebDav, etc. Don't check subtypes. + // Some modules use hidden folder subtypes to store information (see RM-3283). + QName childType = nodeService.getType(childAssocRef.getChildRef()); + if (childType.equals(ContentModel.TYPE_FOLDER)) + { + nodeService.setType(childAssocRef.getChildRef(), TYPE_UNFILED_RECORD_FOLDER); + } + + // check the created child is of an accepted type + validateNewChildAssociationSubTypesIncluded(childAssocRef.getChildRef(), ACCEPTED_NON_UNIQUE_CHILD_TYPES); + } +} diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/transfer/TransferServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/transfer/TransferServiceImpl.java index ad25cb8239..652df3b6c5 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/transfer/TransferServiceImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/transfer/TransferServiceImpl.java @@ -32,7 +32,6 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; - import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionAction; @@ -41,6 +40,8 @@ import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.freeze.FreezeService; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; +import org.alfresco.module.org_alfresco_module_rm.model.rma.type.TransferContainerType; +import org.alfresco.module.org_alfresco_module_rm.model.rma.type.TransferType; 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; @@ -87,6 +88,10 @@ public class TransferServiceImpl extends ServiceBaseImpl /** Freeze Service */ protected FreezeService freezeService; + protected TransferContainerType transferContainerType; + + protected TransferType transferType; + /** * @param filePlanService file plan service */ @@ -127,6 +132,16 @@ public class TransferServiceImpl extends ServiceBaseImpl this.freezeService = freezeService; } + public void setTransferContainerType(TransferContainerType transferContainerType) + { + this.transferContainerType = transferContainerType; + } + + public void setTransferType(TransferType transferType) + { + this.transferType = transferType; + } + /** * @see org.alfresco.module.org_alfresco_module_rm.transfer.TransferService#transfer(NodeRef, boolean) */ @@ -164,11 +179,19 @@ public class TransferServiceImpl extends ServiceBaseImpl } NodeRef transferContainer = filePlanService.getTransferContainer(root); - transferNodeRef = nodeService.createNode(transferContainer, - ContentModel.ASSOC_CONTAINS, - QName.createQName(RM_URI, transferName), - TYPE_TRANSFER, - transferProps).getChildRef(); + + transferContainerType.disable(); + try + { + transferNodeRef = nodeService.createNode(transferContainer, ContentModel.ASSOC_CONTAINS, + QName.createQName(RM_URI, transferName), TYPE_TRANSFER, transferProps) + .getChildRef(); + + } + finally + { + transferContainerType.enable(); + } // Bind the hold node reference to the transaction AlfrescoTransactionSupport.bindResource(KEY_TRANSFER_NODEREF, transferNodeRef); @@ -188,13 +211,17 @@ public class TransferServiceImpl extends ServiceBaseImpl } // Link the record to the trasnfer object - nodeService.addChild(transferNodeRef, - nodeRef, - ASSOC_TRANSFERRED, - ASSOC_TRANSFERRED); - - // Set PDF indicator flag - setPDFIndicationFlag(transferNodeRef, nodeRef); + transferType.disable(); + try + { + nodeService.addChild(transferNodeRef, nodeRef, ASSOC_TRANSFERRED, ASSOC_TRANSFERRED); + // Set PDF indicator flag + setPDFIndicationFlag(transferNodeRef, nodeRef); + } + finally + { + transferType.enable(); + } // Set the transferring indicator aspect nodeService.addAspect(nodeRef, ASPECT_TRANSFERRING, null); @@ -253,12 +280,12 @@ public class TransferServiceImpl extends ServiceBaseImpl { throw new AlfrescoRuntimeException("Could not complete a transfer that contains held folders"); } - + if(freezeService.hasFrozenChildren(assoc.getChildRef())) { throw new AlfrescoRuntimeException("Cound not complete a transfer that contains folders with held children"); } - + markComplete(assoc.getChildRef(), accessionIndicator, transferLocation); } diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3341Test.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3341Test.java index b954591d18..30e3c76578 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3341Test.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM3341Test.java @@ -25,16 +25,15 @@ * #L% * */ + package org.alfresco.module.org_alfresco_module_rm.test.integration.issue; -import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; -import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.AccessStatus; -import org.springframework.extensions.surf.util.I18NUtil; /** * Unit test for RM-3341 .. can copy to hold and transfer folder @@ -43,9 +42,6 @@ import org.springframework.extensions.surf.util.I18NUtil; */ public class RM3341Test extends BaseRMTestCase { - - private final static String MSG_ERROR_ADD_CONTENT_CONTAINER = "rm.service.error-add-content-container"; - public void testCopyingContentsInHoldandTransfer() throws Exception { doTestInTransaction(new Test() @@ -59,9 +55,9 @@ public class RM3341Test extends BaseRMTestCase assertNotNull(transferContainer); assertEquals(AccessStatus.ALLOWED, - permissionService.hasPermission(holdContainer, RMPermissionModel.FILING)); + permissionService.hasPermission(holdContainer, RMPermissionModel.FILING)); assertEquals(AccessStatus.ALLOWED, - permissionService.hasPermission(transferContainer, RMPermissionModel.FILING)); + permissionService.hasPermission(transferContainer, RMPermissionModel.FILING)); return null; } @@ -79,13 +75,12 @@ public class RM3341Test extends BaseRMTestCase try { - FileInfo copyInfo = fileFolderService.create(holdContainer, "test file", ContentModel.TYPE_CONTENT); + fileFolderService.create(holdContainer, "test file", ContentModel.TYPE_CONTENT); fail("This should have thrown an exception"); } - catch (AlfrescoRuntimeException e) + catch (IntegrityException e) { - // ("Content can't be added to a record container. Use record folders to file content.") - assertEquals(I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER), e.getMsgId()); + // ("Content can't be added to a hold container. Use record folders to file content.") } return null; } @@ -109,10 +104,9 @@ public class RM3341Test extends BaseRMTestCase fail("This should have thrown an exception"); } - catch (AlfrescoRuntimeException e) + catch (IntegrityException e) { - // ("Content can't be added to a record container. Use record folders to file content.") - assertEquals(I18NUtil.getMessage(MSG_ERROR_ADD_CONTENT_CONTAINER), e.getMsgId()); + // ("Content can't be added to a transfer container. Use record folders to file content.") } return null; } diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM4293Test.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM4293Test.java new file mode 100644 index 0000000000..d39fbadcd8 --- /dev/null +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/issue/RM4293Test.java @@ -0,0 +1,125 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2017 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.issue; + +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.repo.node.integrity.IntegrityException; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Test for RM-4293 + * + * @author Silviu Dinuta + * @since 2.6 + */ +public class RM4293Test extends BaseRMTestCase +{ + public void testDeleteSpecialContainers() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + NodeRef holdContainer = filePlanService.getHoldContainer(filePlan); + assertNotNull(holdContainer); + + try + { + fileFolderService.delete(holdContainer); + fail("This should have thrown an exception"); + } + catch (IntegrityException e) + { + // ("Hold Container can't be deleted.") + } + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + NodeRef transferContainer = filePlanService.getTransferContainer(filePlan); + assertNotNull(transferContainer); + try + { + fileFolderService.delete(transferContainer); + fail("This should have thrown an exception"); + } + catch (IntegrityException e) + { + // ("Transfer Container can't be deleted.") + } + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + NodeRef unfiledRecordContainer = filePlanService.getUnfiledContainer(filePlan); + assertNotNull(unfiledRecordContainer); + + try + { + fileFolderService.delete(unfiledRecordContainer); + fail("This should have thrown an exception"); + } + catch (IntegrityException e) + { + // ("Unfiled Record Container can't be deleted.") + } + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + try + { + fileFolderService.delete(filePlan); + fail("This should have thrown an exception"); + } + catch (IntegrityException e) + { + // ("FilePlan can't be deleted.") + } + return null; + } + }); + } +} \ No newline at end of file diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerTypeUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerTypeUnitTest.java index 2414556d3d..e797308c3e 100644 --- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerTypeUnitTest.java +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/model/rma/type/TransferContainerTypeUnitTest.java @@ -26,11 +26,16 @@ */ package org.alfresco.module.org_alfresco_module_rm.model.rma.type; -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.model.ContentModel; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + + +import org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; +import org.alfresco.repo.node.integrity.IntegrityException; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; import org.junit.Test; import org.mockito.InjectMocks; @@ -42,40 +47,27 @@ import org.mockito.InjectMocks; */ public class TransferContainerTypeUnitTest extends BaseUnitTest { - /** test object */ - private @InjectMocks TransferContainerType transferContainerType; + /** + * test object + */ + private @InjectMocks + TransferContainerType transferContainerType; /** - * Having the Unfilled Record container and a folder having the aspect ASPECT_HIDDEN When adding a child association - * between the folder and the container Then the folder type shouldn't be renamed + * Given that we try to add to transfer container, + * Then IntegrityException is thrown. */ - @Test(expected = AlfrescoRuntimeException.class) - public void testAddContentToTransferContainerTest() + @Test(expected = IntegrityException.class) + public void testAddToTransferContainerTest() { + NodeRef transferContainer = generateNodeRef(TYPE_TRANSFER_CONTAINER, true); - NodeRef transferContainer = createTransferContainer(); - - /* - * When adding a child association between the folder and the container - */ - NodeRef record = generateNodeRef(ContentModel.TYPE_CONTENT); - ChildAssociationRef childAssoc = new ChildAssociationRef(ContentModel.TYPE_CONTENT, transferContainer, - ContentModel.TYPE_CONTENT, record); - - transferContainerType.onCreateChildAssociation(childAssoc, true); + QName type = AlfMock.generateQName(); + NodeRef nodeRef = AlfMock.generateNodeRef(mockedNodeService, type); + ChildAssociationRef mockedChildAssoc = mock(ChildAssociationRef.class); + when(mockedChildAssoc.getChildRef()).thenReturn(nodeRef); + when(mockedChildAssoc.getParentRef()).thenReturn(transferContainer); + transferContainerType.onCreateChildAssociation(mockedChildAssoc, true); } - - /** - * Generates a record management container - * - * @return reference to the generated container - */ - private NodeRef createTransferContainer() - { - NodeRef holdContainer = generateNodeRef(TYPE_TRANSFER, true); - - return holdContainer; - } - }