From a40aa2af338e73d98e2cf765e7b0ff2418fbe143 Mon Sep 17 00:00:00 2001 From: Roy Wetherall Date: Tue, 29 Mar 2016 13:09:56 +1100 Subject: [PATCH] RM-3114: Prevent access to custom map before it is ready - remove public init method from AdministrationService - make admin service impl ordered listener, always goes last - protect execution of service behaviours until custom map init'ed --- .gitignore | 1 + .../org_alfresco_module_rm/module-context.xml | 1 - .../rm-service-context.xml | 1 - .../admin/RecordsManagementAdminService.java | 5 - .../RecordsManagementAdminServiceImpl.java | 323 ++++++++++-------- .../bootstrap/RecordsManagementBootstrap.java | 12 +- 6 files changed, 185 insertions(+), 158 deletions(-) diff --git a/.gitignore b/.gitignore index 24be3fc3c1..4a0930f9db 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ test-output /rm-server/alfresco-solr.zip /rm-server/solr /rm-server/shared +/rm-server/alf_data # /rm-server/config/ /rm-server/config/alfresco-global.properties 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 1b1674c29f..4368604dde 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 @@ -168,7 +168,6 @@ - diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml index 4057ea3e2d..54cd8dda2e 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-service-context.xml @@ -813,7 +813,6 @@ , + Ordered { /** Logger */ private static Log logger = LogFactory.getLog(RecordsManagementAdminServiceImpl.class); @@ -162,6 +167,9 @@ public class RecordsManagementAdminServiceImpl implements RecordsManagementAdmin /** List of types that can be customisable */ private List pendingCustomisableTypes; private Map customisableTypes; + + /** indicates whether the custom map has been initialised or not */ + private boolean isCustomMapInit = false; /** * @param dictionaryService the dictionary service @@ -223,15 +231,39 @@ public class RecordsManagementAdminServiceImpl implements RecordsManagementAdmin onCreateReferenceDelegate = policyComponent.registerClassPolicy(OnCreateReference.class); beforeRemoveReferenceDelegate = policyComponent.registerClassPolicy(BeforeRemoveReference.class); onRemoveReferenceDelegate = policyComponent.registerClassPolicy(OnRemoveReference.class); + } + + /** + * Indicate that this application content listener must be executed with the highest + * precedence. + * + * @see Ordered#getOrder() + */ + @Override + public int getOrder() + { + return Ordered.LOWEST_PRECEDENCE; + } + + /** + * Load the custom properties map + * + * @see ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) + */ + @Override + public void onApplicationEvent(ContextRefreshedEvent event) + { + // initialise custom properties + initCustomMap(); } /** - * Invoke before create reference policy - * - * @param fromNodeRef - * @param toNodeRef - * @param reference - */ + * Invoke before create reference policy + * + * @param fromNodeRef + * @param toNodeRef + * @param reference + */ protected void invokeBeforeCreateReference(NodeRef fromNodeRef, NodeRef toNodeRef, QName reference) { // get qnames to invoke against @@ -301,22 +333,25 @@ public class RecordsManagementAdminServiceImpl implements RecordsManagementAdmin ) public void onAddAspect(final NodeRef nodeRef, final QName aspectTypeQName) { - AuthenticationUtil.runAs(new RunAsWork() + if (isCustomMapInit) { - @Override - public Void doWork() + AuthenticationUtil.runAs(new RunAsWork() { - if (nodeService.exists(nodeRef) && - dictionaryService.getAllModels().contains(RM_CUSTOM_MODEL) && - isCustomisable(aspectTypeQName)) + @Override + public Void doWork() { - QName customPropertyAspect = getCustomAspect(aspectTypeQName); - nodeService.addAspect(nodeRef, customPropertyAspect, null); + if (nodeService.exists(nodeRef) && + dictionaryService.getAllModels().contains(RM_CUSTOM_MODEL) && + isCustomisable(aspectTypeQName)) + { + QName customPropertyAspect = getCustomAspect(aspectTypeQName); + nodeService.addAspect(nodeRef, customPropertyAspect, null); + } + + return null; } - - return null; - } - }, AuthenticationUtil.getSystemUserName()); + }, AuthenticationUtil.getSystemUserName()); + } } /** @@ -331,21 +366,24 @@ public class RecordsManagementAdminServiceImpl implements RecordsManagementAdmin ) public void onRemoveAspect(final NodeRef nodeRef, final QName aspectTypeQName) { - AuthenticationUtil.runAs(new RunAsWork() + if (isCustomMapInit) { - @Override - public Void doWork() + AuthenticationUtil.runAs(new RunAsWork() { - if (nodeService.exists(nodeRef) && - isCustomisable(aspectTypeQName)) + @Override + public Void doWork() { - QName customPropertyAspect = getCustomAspect(aspectTypeQName); - nodeService.removeAspect(nodeRef, customPropertyAspect); + if (nodeService.exists(nodeRef) && + isCustomisable(aspectTypeQName)) + { + QName customPropertyAspect = getCustomAspect(aspectTypeQName); + nodeService.removeAspect(nodeRef, customPropertyAspect); + } + + return null; } - - return null; - } - }, AuthenticationUtil.getSystemUserName()); + }, AuthenticationUtil.getSystemUserName()); + } } /** @@ -362,47 +400,41 @@ public class RecordsManagementAdminServiceImpl implements RecordsManagementAdmin ) public void onCreateNode(final ChildAssociationRef childAssocRef) { - AuthenticationUtil.runAs(new RunAsWork() - { - @Override - public Void doWork() + if (isCustomMapInit) + { + AuthenticationUtil.runAs(new RunAsWork() { - if (dictionaryService.getAllModels().contains(RecordsManagementCustomModel.RM_CUSTOM_MODEL)) + @Override + public Void doWork() { - NodeRef nodeRef = childAssocRef.getChildRef(); - QName type = nodeService.getType(nodeRef); - while (type != null && !ContentModel.TYPE_CMOBJECT.equals(type)) + if (dictionaryService.getAllModels().contains(RecordsManagementCustomModel.RM_CUSTOM_MODEL)) { - if (isCustomisable(type)) + NodeRef nodeRef = childAssocRef.getChildRef(); + QName type = nodeService.getType(nodeRef); + while (type != null && !ContentModel.TYPE_CMOBJECT.equals(type)) { - QName customPropertyAspect = getCustomAspect(type); - nodeService.addAspect(nodeRef, customPropertyAspect, null); - } - - TypeDefinition def = dictionaryService.getType(type); - if (def != null) - { - type = def.getParentName(); - } - else - { - type = null; + if (isCustomisable(type)) + { + QName customPropertyAspect = getCustomAspect(type); + nodeService.addAspect(nodeRef, customPropertyAspect, null); + } + + TypeDefinition def = dictionaryService.getType(type); + if (def != null) + { + type = def.getParentName(); + } + else + { + type = null; + } } } + + return null; } - - return null; - } - }, AuthenticationUtil.getSystemUserName()); - } - - /** - * @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementAdminService#initialiseCustomModel() - */ - public void initialiseCustomModel() - { - // Initialise the map - getCustomisableMap(); + }, AuthenticationUtil.getSystemUserName()); + } } /** @@ -483,6 +515,92 @@ public class RecordsManagementAdminServiceImpl implements RecordsManagementAdmin return result; } + + /** + * Initialise custom type map + */ + private void initCustomMap() + { + customisableTypes = new HashMap(7); + Collection aspects = dictionaryService.getAspects(RM_CUSTOM_MODEL); + for (QName aspect : aspects) + { + AspectDefinition aspectDef = dictionaryService.getAspect(aspect); + String name = aspectDef.getName().getLocalName(); + if (name.endsWith("Properties")) + { + QName type = null; + String prefixString = aspectDef.getDescription(dictionaryService); + if (prefixString == null) + { + // Backward compatibility from previous RM V1.0 custom models + if (CompatibilityModel.NAME_CUSTOM_RECORD_PROPERTIES.equals(name)) + { + type = RecordsManagementModel.ASPECT_RECORD; + } + else if (CompatibilityModel.NAME_CUSTOM_RECORD_FOLDER_PROPERTIES.equals(name)) + { + type = RecordsManagementModel.TYPE_RECORD_FOLDER; + } + else if (CompatibilityModel.NAME_CUSTOM_RECORD_CATEGORY_PROPERTIES.equals(name)) + { + type = RecordsManagementModel.TYPE_RECORD_CATEGORY; + } + else if (CompatibilityModel.NAME_CUSTOM_RECORD_SERIES_PROPERTIES.equals(name) && + // Only add the deprecated record series type as customisable if + // a v1.0 installation has added custom properties + aspectDef.getProperties().size() != 0) + { + type = CompatibilityModel.TYPE_RECORD_SERIES; + } + } + else + { + type = QName.createQName(prefixString, namespaceService); + } + + // Add the customisable type to the map + if (type != null) + { + customisableTypes.put(type, aspect); + + // Remove customisable type from the pending list + if (pendingCustomisableTypes != null && pendingCustomisableTypes.contains(type)) + { + pendingCustomisableTypes.remove(type); + } + } + } + } + + // Deal with any pending types left over + if (pendingCustomisableTypes != null && pendingCustomisableTypes.size() != 0) + { + NodeRef modelRef = getCustomModelRef(RecordsManagementModel.RM_CUSTOM_URI); + M2Model model = readCustomContentModel(modelRef); + try + { + for (QName customisableType : pendingCustomisableTypes) + { + QName customAspect = getCustomAspectImpl(customisableType); + + // Create the new aspect to hold the custom properties + M2Aspect aspect = model.createAspect(customAspect.toPrefixString(namespaceService)); + aspect.setDescription(customisableType.toPrefixString(namespaceService)); + + // Make a record of the customisable type + customisableTypes.put(customisableType, customAspect); + } + } + finally + { + writeCustomContentModel(modelRef, model); + } + } + + // indicate map is initialised + isCustomMapInit = true; + } /** * Gets a map containing all the customisable types @@ -493,82 +611,7 @@ public class RecordsManagementAdminServiceImpl implements RecordsManagementAdmin { if (customisableTypes == null) { - customisableTypes = new HashMap(7); - Collection aspects = dictionaryService.getAspects(RM_CUSTOM_MODEL); - for (QName aspect : aspects) - { - AspectDefinition aspectDef = dictionaryService.getAspect(aspect); - String name = aspectDef.getName().getLocalName(); - if (name.endsWith("Properties")) - { - QName type = null; - String prefixString = aspectDef.getDescription(dictionaryService); - if (prefixString == null) - { - // Backward compatibility from previous RM V1.0 custom models - if (CompatibilityModel.NAME_CUSTOM_RECORD_PROPERTIES.equals(name)) - { - type = RecordsManagementModel.ASPECT_RECORD; - } - else if (CompatibilityModel.NAME_CUSTOM_RECORD_FOLDER_PROPERTIES.equals(name)) - { - type = RecordsManagementModel.TYPE_RECORD_FOLDER; - } - else if (CompatibilityModel.NAME_CUSTOM_RECORD_CATEGORY_PROPERTIES.equals(name)) - { - type = RecordsManagementModel.TYPE_RECORD_CATEGORY; - } - else if (CompatibilityModel.NAME_CUSTOM_RECORD_SERIES_PROPERTIES.equals(name) && - // Only add the deprecated record series type as customisable if - // a v1.0 installation has added custom properties - aspectDef.getProperties().size() != 0) - { - type = CompatibilityModel.TYPE_RECORD_SERIES; - } - } - else - { - type = QName.createQName(prefixString, namespaceService); - } - - // Add the customisable type to the map - if (type != null) - { - customisableTypes.put(type, aspect); - - // Remove customisable type from the pending list - if (pendingCustomisableTypes != null && pendingCustomisableTypes.contains(type)) - { - pendingCustomisableTypes.remove(type); - } - } - } - } - - // Deal with any pending types left over - if (pendingCustomisableTypes != null && pendingCustomisableTypes.size() != 0) - { - NodeRef modelRef = getCustomModelRef(RecordsManagementModel.RM_CUSTOM_URI); - M2Model model = readCustomContentModel(modelRef); - try - { - for (QName customisableType : pendingCustomisableTypes) - { - QName customAspect = getCustomAspectImpl(customisableType); - - // Create the new aspect to hold the custom properties - M2Aspect aspect = model.createAspect(customAspect.toPrefixString(namespaceService)); - aspect.setDescription(customisableType.toPrefixString(namespaceService)); - - // Make a record of the customisable type - customisableTypes.put(customisableType, customAspect); - } - } - finally - { - writeCustomContentModel(modelRef, model); - } - } + throw AlfrescoRuntimeException.create("Customisable map has not been initialised correctly."); } return customisableTypes; } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/RecordsManagementBootstrap.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/RecordsManagementBootstrap.java index 295059ead3..f681b9ef3a 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/RecordsManagementBootstrap.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/RecordsManagementBootstrap.java @@ -18,7 +18,6 @@ */ package org.alfresco.module.org_alfresco_module_rm.bootstrap; -import org.alfresco.module.org_alfresco_module_rm.admin.RecordsManagementAdminService; import org.alfresco.module.org_alfresco_module_rm.action.impl.SplitEmailAction; import org.alfresco.module.org_alfresco_module_rm.caveat.RMCaveatConfigService; import org.alfresco.module.org_alfresco_module_rm.email.CustomEmailMappingService; @@ -40,8 +39,7 @@ public class RecordsManagementBootstrap extends AbstractLifecycleBean private TransactionService transactionService; private RMCaveatConfigService caveatConfigService; private CustomEmailMappingService customEmailMappingService; - private RecordsManagementAdminService adminService; - + public void setTransactionService(TransactionService transactionService) { this.transactionService = transactionService; @@ -57,11 +55,6 @@ public class RecordsManagementBootstrap extends AbstractLifecycleBean this.customEmailMappingService = customEmailMappingService; } - public void setRecordsManagementAdminService(RecordsManagementAdminService adminService) - { - this.adminService = adminService; - } - public CustomEmailMappingService getCustomEmailMappingService() { return customEmailMappingService; @@ -82,9 +75,6 @@ public class RecordsManagementBootstrap extends AbstractLifecycleBean // initialise caveat config caveatConfigService.init(); - // Initialise the custom model - adminService.initialiseCustomModel(); - // Initialise the SplitEmailAction SplitEmailAction action = (SplitEmailAction)getApplicationContext().getBean("splitEmail"); action.bootstrap();