From 3609b0a3f15b8ed10df131ce63e810c053cff07d Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Mon, 9 Jan 2017 11:59:27 +0000 Subject: [PATCH] RM-4586 (Record can be declared a record) / RM-4587 (Folder in collaboration site can be declared a record) --- .../org_alfresco_module_rm/action-context.xml | 5 +- .../action/dm/CreateRecordAction.java | 158 +------------- .../record/RecordService.java | 2 +- .../record/RecordServiceImpl.java | 198 ++++++++++++++++-- 4 files changed, 186 insertions(+), 177 deletions(-) diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/action-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/action-context.xml index 7a6053d037..d1dda0a2e9 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/action-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/action-context.xml @@ -16,16 +16,13 @@ - - - {http://www.alfresco.org/model/content/1.0}content - + diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java index 086883657e..5ee4cff8b6 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/dm/CreateRecordAction.java @@ -29,24 +29,14 @@ package org.alfresco.module.org_alfresco_module_rm.action.dm; import java.util.List; -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.action.AuditableActionExecuterAbstractBase; -import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService; import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.repo.action.ParameterDefinitionImpl; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ParameterDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -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.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * Creates a new record from an existing content object. @@ -58,9 +48,6 @@ import org.apache.commons.logging.LogFactory; public class CreateRecordAction extends AuditableActionExecuterAbstractBase implements RecordsManagementModel { - /** Logger */ - private static Log logger = LogFactory.getLog(CreateRecordAction.class); - /** Action name */ public static final String NAME = "create-record"; @@ -68,23 +55,9 @@ public class CreateRecordAction extends AuditableActionExecuterAbstractBase public static final String PARAM_FILE_PLAN = "file-plan"; public static final String PARAM_HIDE_RECORD = "hide-record"; - /** Sync Model URI */ - static final String SYNC_MODEL_1_0_URI = "http://www.alfresco.org/model/sync/1.0"; - /** Synced aspect */ - static final QName ASPECT_SYNCED = QName.createQName(SYNC_MODEL_1_0_URI, "synced"); - /** Record service */ private RecordService recordService; - /** Node service */ - private NodeService nodeService; - - /** File plan service */ - private FilePlanService filePlanService; - - /** Dictionary service */ - private DictionaryService dictionaryService; - /** * @param recordService record service */ @@ -93,138 +66,26 @@ public class CreateRecordAction extends AuditableActionExecuterAbstractBase this.recordService = recordService; } - /** - * @param nodeService node service - */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - /** - * @param filePlanService file plan service - */ - public void setFilePlanService(FilePlanService filePlanService) - { - this.filePlanService = filePlanService; - } - - /** - * @param dictionaryService dictionary service - */ - public void setDictionaryService(DictionaryService dictionaryService) - { - this.dictionaryService = dictionaryService; - } - /** * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef) */ @Override protected void executeImpl(final Action action, final NodeRef actionedUponNodeRef) { + NodeRef filePlan = (NodeRef) action.getParameterValue(PARAM_FILE_PLAN); - if (!nodeService.exists(actionedUponNodeRef)) + // indicate whether the record should be hidden or not (default not) + boolean hideRecord = false; + Boolean hideRecordValue = ((Boolean) action.getParameterValue(PARAM_HIDE_RECORD)); + if (hideRecordValue != null) { - // do not create record if the actioned upon node does not exist! - if (logger.isDebugEnabled()) - { - logger.debug("Can not create record, because " + actionedUponNodeRef.toString() + " does not exist."); - } + hideRecord = hideRecordValue.booleanValue(); } - else if (!dictionaryService.isSubClass(nodeService.getType(actionedUponNodeRef), ContentModel.TYPE_CONTENT)) - { - // TODO eventually we should support other types .. either as record folders or as composite records - if (logger.isDebugEnabled()) - { - logger.debug("Can not create record, because " + actionedUponNodeRef.toString() + " is not a supported type."); - } - } - else if (nodeService.hasAspect(actionedUponNodeRef, ASPECT_RECORD)) - { - // Do not create record if the actioned upon node is already a record! - if (logger.isDebugEnabled()) - { - logger.debug("Can not create record, because " + actionedUponNodeRef.toString() + " is already a record."); - } - } - else if (nodeService.hasAspect(actionedUponNodeRef, ContentModel.ASPECT_WORKING_COPY)) - { - // We can not create records from working copies - if (logger.isDebugEnabled()) - { - logger.debug("Can node create record, because " + actionedUponNodeRef.toString() + " is a working copy."); - } - } - else if (nodeService.hasAspect(actionedUponNodeRef, ASPECT_RECORD_REJECTION_DETAILS)) + synchronized (this) { - // can not create a record from a previously rejected one - if (logger.isDebugEnabled()) - { - logger.debug("Can not create record, because " + actionedUponNodeRef.toString() + " has previously been rejected."); - } - } - else if (nodeService.hasAspect(actionedUponNodeRef, ASPECT_SYNCED)) - { - // can't declare the record if the node is sync'ed - if (logger.isDebugEnabled()) - { - logger.debug("Can't declare as record, because " + actionedUponNodeRef.toString() + " is synched content."); - } - } - else - { - NodeRef filePlan = (NodeRef)action.getParameterValue(PARAM_FILE_PLAN); - if (filePlan == null) - { - // TODO .. eventually make the file plan parameter required - - filePlan = AuthenticationUtil.runAs(new RunAsWork() - { - @Override - public NodeRef doWork() - { - return filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID); - } - }, AuthenticationUtil.getAdminUserName()); - - // if the file plan is still null, raise an exception - if (filePlan == null) - { - if (logger.isDebugEnabled()) - { - logger.debug("Can not create record, because the default file plan can not be determined. Make sure at least one file plan has been created."); - } - throw new AlfrescoRuntimeException("Can not create record, because the default file plan can not be determined."); - } - } - else - { - // verify that the provided file plan is actually a file plan - if (!filePlanService.isFilePlan(filePlan)) - { - if (logger.isDebugEnabled()) - { - logger.debug("Can not create record, because the provided file plan node reference is not a file plan."); - } - throw new AlfrescoRuntimeException("Can not create record, because the provided file plan node reference is not a file plan."); - } - } - - // indicate whether the record should be hidden or not (default not) - boolean hideRecord = false; - Boolean hideRecordValue = ((Boolean)action.getParameterValue(PARAM_HIDE_RECORD)); - if (hideRecordValue != null) - { - hideRecord = hideRecordValue.booleanValue(); - } - - synchronized (this) - { - // create record from existing document - recordService.createRecord(filePlan, actionedUponNodeRef, !hideRecord); - } + // create record from existing document + recordService.createRecord(filePlan, actionedUponNodeRef, !hideRecord); } } @@ -238,5 +99,4 @@ public class CreateRecordAction extends AuditableActionExecuterAbstractBase //params.add(new ParameterDefinitionImpl(PARAM_FILE_PLAN, DataTypeDefinition.NODE_REF, false, getParamDisplayLabel(PARAM_FILE_PLAN))); params.add(new ParameterDefinitionImpl(PARAM_HIDE_RECORD, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_HIDE_RECORD))); } - } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java index 0d049b6598..52c2711314 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordService.java @@ -165,7 +165,7 @@ public interface RecordService * Note that the node reference of the record will be the same as the original * document. * - * @param filePlan The filePlan in which the record should be placed + * @param filePlan The filePlan in which the record should be placed. filePlan can be null in this case the default RM site will be used. * @param nodeRef The node from which the record will be created * @param isLinked indicates if the newly created record is linked to it's original location or not. */ diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java index fc5491a03c..2f6459ff9f 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/record/RecordServiceImpl.java @@ -135,6 +135,13 @@ public class RecordServiceImpl extends BaseBehaviourBean /** Logger */ private static Log logger = LogFactory.getLog(RecordServiceImpl.class); + + /** Sync Model URI */ + private static final String SYNC_MODEL_1_0_URI = "http://www.alfresco.org/model/sync/1.0"; + + /** Synced aspect */ + private static final QName ASPECT_SYNCED = QName.createQName(SYNC_MODEL_1_0_URI, "synced"); + /** transation data key */ private static final String KEY_IGNORE_ON_UPDATE = "ignoreOnUpdate"; private static final String KEY_PENDING_FILLING = "pendingFilling"; @@ -238,10 +245,10 @@ public class RecordServiceImpl extends BaseBehaviourBean /** records management container type */ private RecordsManagementContainerType recordsManagementContainerType; - + /** recordable version service */ private RecordableVersionService recordableVersionService; - + /** list of available record meta-data aspects and the file plan types the are applicable to */ private Map> recordMetaDataAspects; @@ -390,7 +397,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { this.recordsManagementContainerType = recordsManagementContainerType; } - + /** * @param recordableVersionService recordable version service */ @@ -398,7 +405,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { this.recordableVersionService = recordableVersionService; } - + /** * Init method */ @@ -854,19 +861,12 @@ public class RecordServiceImpl extends BaseBehaviourBean @Override public void createRecord(final NodeRef filePlan, final NodeRef nodeRef, final boolean isLinked) { - ParameterCheck.mandatory("filePlan", filePlan); + // filePlan can be null. In this case the default RM site will be used. ParameterCheck.mandatory("nodeRef", nodeRef); ParameterCheck.mandatory("isLinked", isLinked); - // first we do a sanity check to ensure that the user has at least write permissions on the document - if (extendedPermissionService.hasPermission(nodeRef, PermissionService.WRITE) != AccessStatus.ALLOWED) - { - throw new AccessDeniedException("Can not create record from document, because the user " + - AuthenticationUtil.getRunAsUser() + - " does not have Write permissions on the doucment " + - nodeRef.toString()); - } - + recordCreationSanityCheckOnNode(nodeRef); + recordCreationSanityCheckOnFilePlan(filePlan); // do the work of creating the record as the system user AuthenticationUtil.runAsSystem(new RunAsWork() @@ -961,6 +961,158 @@ public class RecordServiceImpl extends BaseBehaviourBean }); } + /** + * Helper method to check the given file plan before trying to determine the unfiled records container. + * + * @param filePlan The reference of the file plan node + */ + private void recordCreationSanityCheckOnFilePlan(NodeRef filePlan) + { + if (filePlan == null) + { + // TODO .. eventually make the file plan parameter required + + filePlan = AuthenticationUtil.runAs(new RunAsWork() + { + @Override + public NodeRef doWork() + { + return filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID); + } + }, AuthenticationUtil.getAdminUserName()); + + // if the file plan is still null, raise an exception + if (filePlan == null) + { + String msg = "Can not create record, because the default file plan can not be determined. Make sure at least one file plan has been created."; + + if (logger.isDebugEnabled()) + { + logger.debug(msg); + } + + throw new AlfrescoRuntimeException(msg); + } + } + else + { + // verify that the provided file plan is actually a file plan + if (!filePlanService.isFilePlan(filePlan)) + { + String msg = "Can not create record, because the provided file plan node reference is not a file plan."; + + if (logger.isDebugEnabled()) + { + logger.debug(msg); + } + + throw new AlfrescoRuntimeException(msg); + } + } + } + + /** + * Helper method to check the given node before trying to declare it as record + * + * @param nodeRef The reference of the node which will be declared as record + */ + private void recordCreationSanityCheckOnNode(NodeRef nodeRef) + { + // first we do a sanity check to ensure that the user has at least write permissions on the document + if (extendedPermissionService.hasPermission(nodeRef, PermissionService.WRITE) != AccessStatus.ALLOWED) + { + String msg = "Can not create record from document, because the user " + + AuthenticationUtil.getRunAsUser() + + " does not have Write permissions on the doucment " + + nodeRef.toString(); + + if (logger.isDebugEnabled()) + { + logger.debug(msg); + } + + throw new AccessDeniedException(msg); + } + + // do not create record if the node does not exist! + if (!nodeService.exists(nodeRef)) + { + String msg = "Can not create record, because " + nodeRef.toString() + " does not exist."; + + if (logger.isDebugEnabled()) + { + logger.debug(msg); + } + + throw new AlfrescoRuntimeException(msg); + } + + // TODO eventually we should support other types .. either as record folders or as composite records + if (!dictionaryService.isSubClass(nodeService.getType(nodeRef), ContentModel.TYPE_CONTENT)) + { + String msg = "Can not create record, because " + nodeRef.toString() + " is not a supported type."; + + if (logger.isDebugEnabled()) + { + logger.debug(msg); + } + + throw new AlfrescoRuntimeException(msg); + } + + // Do not create record if the node is already a record! + if (nodeService.hasAspect(nodeRef, ASPECT_RECORD)) + { + String msg = "Can not create record, because " + nodeRef.toString() + " is already a record."; + + if (logger.isDebugEnabled()) + { + logger.debug(msg); + } + + throw new AlfrescoRuntimeException(msg); + } + + // We can not create records from working copies + if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY)) + { + String msg = "Can node create record, because " + nodeRef.toString() + " is a working copy."; + + if (logger.isDebugEnabled()) + { + logger.debug(msg); + } + + throw new AlfrescoRuntimeException(msg); + } + + // can not create a record from a previously rejected one + if (nodeService.hasAspect(nodeRef, ASPECT_RECORD_REJECTION_DETAILS)) + { + String msg = "Can not create record, because " + nodeRef.toString() + " has previously been rejected."; + + if (logger.isDebugEnabled()) + { + logger.debug(msg); + } + + throw new AlfrescoRuntimeException(msg); + } + + // can't declare the record if the node is sync'ed + if (nodeService.hasAspect(nodeRef, ASPECT_SYNCED)) + { + String msg = "Can't declare as record, because " + nodeRef.toString() + " is synched content."; + + if (logger.isDebugEnabled()) + { + logger.debug(msg); + } + + throw new AlfrescoRuntimeException(msg); + } + } + /** * @see org.alfresco.module.org_alfresco_module_rm.record.RecordService#createRecordFromCopy(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef) */ @@ -999,7 +1151,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { recordsManagementContainerType.enable(); } - + // if versionable, then remove without destroying version history, // because it is being shared with the originating document behaviourFilter.disableBehaviour(ContentModel.ASPECT_VERSIONABLE); @@ -1011,7 +1163,7 @@ public class RecordServiceImpl extends BaseBehaviourBean { behaviourFilter.enableBehaviour(ContentModel.ASPECT_VERSIONABLE); } - + // make record makeRecord(record); @@ -1060,8 +1212,8 @@ public class RecordServiceImpl extends BaseBehaviourBean private NodeRef getLatestVersionRecord(NodeRef nodeRef) { NodeRef versionRecord = null; - - + + recordableVersionService.createSnapshotVersion(nodeRef); // wire record up to previous record VersionHistory versionHistory = versionService.getVersionHistory(nodeRef); @@ -1739,7 +1891,7 @@ public class RecordServiceImpl extends BaseBehaviourBean record, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name)); - + // recalculate disposition schedule for the record when linking it dispositionService.recalculateNextDispositionStep(record); } @@ -1758,10 +1910,10 @@ public class RecordServiceImpl extends BaseBehaviourBean private void validateLinkConditions(NodeRef record, NodeRef recordFolder) { // ensure that the linking record folders have compatible disposition schedules - + // get the origin disposition schedule for the record, not the calculated one DispositionSchedule recordDispositionSchedule = dispositionService.getOriginDispositionSchedule(record); - + if (recordDispositionSchedule != null) { DispositionSchedule recordFolderDispositionSchedule = dispositionService.getDispositionSchedule(recordFolder); @@ -1798,7 +1950,7 @@ public class RecordServiceImpl extends BaseBehaviourBean // remove the link nodeService.removeChild(recordFolder, record); - + // recalculate disposition schedule for record after unlinking it dispositionService.recalculateNextDispositionStep(record); } @@ -1807,5 +1959,5 @@ public class RecordServiceImpl extends BaseBehaviourBean // can only unlink a record from a record folder throw new RecordLinkRuntimeException("Can only unlink a record from a record folder."); } - } + } }