diff --git a/pom.xml b/pom.xml index ba6897da96..550e431e07 100644 --- a/pom.xml +++ b/pom.xml @@ -43,11 +43,6 @@ alfresco-internal https://artifacts.alfresco.com/nexus/content/groups/private - - - alfresco-internal-staging - https://artifacts.alfresco.com/nexus/content/repositories/5.1-EA - diff --git a/rm-automation/pom.xml b/rm-automation/pom.xml index d43e77013b..4ba2ae972f 100644 --- a/rm-automation/pom.xml +++ b/rm-automation/pom.xml @@ -72,7 +72,7 @@ org.alfresco.test dataprep - 1.4 + 1.8 org.alfresco.test diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/module-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/module-context.xml index b0317256f9..50e505c39f 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/module-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/module-context.xml @@ -7,6 +7,12 @@ http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> + + + + + + diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml index 342e5dff92..0c2510f0a8 100644 --- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml +++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml @@ -791,6 +791,7 @@ + @@ -819,6 +820,7 @@ + @@ -847,6 +849,7 @@ + diff --git a/rm-community/rm-community-repo/source/compatibility/org/alfresco/module/org_alfresco_module_rm/caveat/RMCaveatConfigComponentImpl.java b/rm-community/rm-community-repo/source/compatibility/org/alfresco/module/org_alfresco_module_rm/caveat/RMCaveatConfigComponentImpl.java index 3462c5028c..c2733a9c98 100644 --- a/rm-community/rm-community-repo/source/compatibility/org/alfresco/module/org_alfresco_module_rm/caveat/RMCaveatConfigComponentImpl.java +++ b/rm-community/rm-community-repo/source/compatibility/org/alfresco/module/org_alfresco_module_rm/caveat/RMCaveatConfigComponentImpl.java @@ -45,6 +45,7 @@ import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.content.ContentServicePolicies; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.policy.Behaviour.NotificationFrequency; import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourKind; @@ -219,9 +220,14 @@ public class RMCaveatConfigComponentImpl implements ContentServicePolicies.OnCon /** * @see org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy#onContentUpdate(org.alfresco.service.cmr.repository.NodeRef, boolean) + * RM-2770 - this method has to be fired on transaction commit to be able to validate the content when the content store is encrypted */ @Override - @Behaviour(kind = BehaviourKind.CLASS) + @Behaviour + ( + kind = BehaviourKind.CLASS, + notificationFrequency = NotificationFrequency.TRANSACTION_COMMIT + ) public void onContentUpdate(NodeRef nodeRef, boolean newContent) { if (logger.isInfoEnabled()) diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/CopyMoveLinkFileToBaseAction.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/CopyMoveLinkFileToBaseAction.java index abc881889f..8ba3b055b1 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/CopyMoveLinkFileToBaseAction.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/action/impl/CopyMoveLinkFileToBaseAction.java @@ -116,7 +116,7 @@ public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstr * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef) */ @Override - protected synchronized void executeImpl(final Action action, final NodeRef actionedUponNodeRef) + protected synchronized void executeImpl(Action action, final NodeRef actionedUponNodeRef) { String actionName = action.getActionDefinitionName(); if (isOkToProceedWithAction(actionedUponNodeRef, actionName)) @@ -139,24 +139,7 @@ public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstr if (recordFolder == null) { final boolean finaltargetIsUnfiledRecords = targetIsUnfiledRecords; - recordFolder = retryingTransactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() - { - public NodeRef execute() throws Throwable - { - NodeRef result = null; - try - { - // get the reference to the record folder based on the relative path - result = createOrResolvePath(action, actionedUponNodeRef, finaltargetIsUnfiledRecords); - } - catch (DuplicateChildNodeNameException ex) - { - throw new ConcurrencyFailureException("Cannot create or resolve path.", ex); - } - - return result; - } - }, false, true); + recordFolder = createOrResolvePath(action, actionedUponNodeRef, finaltargetIsUnfiledRecords); } // now we have the reference to the target folder we can do some final checks to see if the action is valid @@ -282,23 +265,39 @@ public abstract class CopyMoveLinkFileToBaseAction extends RMActionExecuterAbstr * @param targetisUnfiledRecords true is the target is in unfiled records * @return */ - private NodeRef createOrResolvePath(Action action, NodeRef actionedUponNodeRef, boolean targetisUnfiledRecords) + private NodeRef createOrResolvePath(final Action action, final NodeRef actionedUponNodeRef, final boolean targetisUnfiledRecords) { // get the starting context - NodeRef context = getContext(action, actionedUponNodeRef, targetisUnfiledRecords); + final NodeRef context = getContext(action, actionedUponNodeRef, targetisUnfiledRecords); NodeRef path = context; // get the path we wish to resolve String pathParameter = (String)action.getParameterValue(PARAM_PATH); - String[] pathElementsArray = StringUtils.tokenizeToStringArray(pathParameter, "/", false, true); + final String[] pathElementsArray = StringUtils.tokenizeToStringArray(pathParameter, "/", false, true); if((pathElementsArray != null) && (pathElementsArray.length > 0)) { // get the create parameter Boolean createValue = (Boolean)action.getParameterValue(PARAM_CREATE_RECORD_PATH); - boolean create = createValue == null ? false : createValue.booleanValue(); + final boolean create = createValue == null ? false : createValue.booleanValue(); // create or resolve the specified path - path = createOrResolvePath(action, context, actionedUponNodeRef, Arrays.asList(pathElementsArray), targetisUnfiledRecords, create, false); + path = retryingTransactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + public NodeRef execute() throws Throwable + { + NodeRef path = null; + try + { + path = createOrResolvePath(action, context, actionedUponNodeRef, Arrays.asList(pathElementsArray), targetisUnfiledRecords, + create, false); + } + catch (DuplicateChildNodeNameException ex) + { + throw new ConcurrencyFailureException("Cannot create or resolve path.", ex); + } + return path; + } + }, false, true); } return path; } diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ModuleCompatibilityComponent.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ModuleCompatibilityComponent.java new file mode 100644 index 0000000000..c5fedd96c4 --- /dev/null +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ModuleCompatibilityComponent.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2005-2016 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +package org.alfresco.module.org_alfresco_module_rm.bootstrap; + +import org.alfresco.service.cmr.admin.RepoUsage.LicenseMode; +import org.alfresco.service.cmr.module.ModuleService; +import org.alfresco.service.descriptor.DescriptorService; +import org.alfresco.service.license.LicenseDescriptor; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.event.ContextRefreshedEvent; + +/** + * Module compatibility component. + *

+ * Checks that the currently installed RM AMP licence mode matches that of the + * underlying repository. + * + * @author Roy Wetherall + * @since 2.4 + */ +public class ModuleCompatibilityComponent implements ApplicationListener +{ + /** Logger */ + private static Log logger = LogFactory.getLog(ModuleCompatibilityComponent.class); + + // TODO get this from somewhere + private static final String RM_ENT_MODULE_ID = "alfresco-rm-enterprise-repo"; + + /** descriptor service */ + private DescriptorService descriptorService; + + /** module service */ + private ModuleService moduleService; + + /** + * @param descriptorService descriptor service + */ + public void setDescriptorService(DescriptorService descriptorService) + { + this.descriptorService = descriptorService; + } + + /** + * @param moduleService module service + */ + public void setModuleService(ModuleService moduleService) + { + this.moduleService = moduleService; + } + + /** + * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) + */ + @Override + public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) + { + // license mode + LicenseMode licenseMode = LicenseMode.UNKNOWN; + + // grab the application context + ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext(); + + // get the license mode + LicenseDescriptor license = descriptorService.getLicenseDescriptor(); + if (license != null) + { + licenseMode = license.getLicenseMode(); + } + + // determine whether RM Enterprise is installed or not + boolean isRMEnterprise = isRMEnterprise(); + + // debug log + if (logger.isDebugEnabled()) + { + logger.debug("Module compatibility information:"); + logger.debug(" Repository licence mode = " + licenseMode.toString()); + logger.debug(" RM Enterprise installed = " + isRMEnterprise); + } + + if (LicenseMode.ENTERPRISE.equals(licenseMode) && !isRMEnterprise) + { + // running enterprise rm on community core so close application + // context + closeApplicationContext(applicationContext, + "Running Community Records Management Module on Enterprise Alfresco One is not a supported configuration."); + + } + else if (!LicenseMode.ENTERPRISE.equals(licenseMode) && isRMEnterprise) + { + // running community rm on enterprise core so close application + // context + closeApplicationContext(applicationContext, + "Running Enterprise Records Management module on Community Alfresco One is not a supported configuration."); + } + } + + /** + * Indicates whether RM Enterprise module is installed or not. + * + * @return boolean true if RM Enterprise is installed, false otherwise + */ + private boolean isRMEnterprise() + { + return (moduleService.getModule(RM_ENT_MODULE_ID) != null); + } + + /** + * Close application context, logging message. + * + * @param applicationContext application context + * @param message closure message + */ + private void closeApplicationContext(ApplicationContext applicationContext, String message) + { + // log closure message + if (logger.isErrorEnabled()) + { + logger.error(message); + } + + // close the application context! + ((ConfigurableApplicationContext) applicationContext).close(); + } +} diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/content/ContentDestructionComponent.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/content/ContentDestructionComponent.java index ee60e787ad..01982b6665 100644 --- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/content/ContentDestructionComponent.java +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/content/ContentDestructionComponent.java @@ -168,8 +168,9 @@ public class ContentDestructionComponent // We want to remove the rn:renditioned aspect, but due to the possibility // that there is Alfresco 3.2-era data with the cm:thumbnailed aspect // applied, we must consider removing it too. - if (getNodeService().hasAspect(nodeRef, RenditionModel.ASPECT_RENDITIONED) || - getNodeService().hasAspect(nodeRef, ContentModel.ASPECT_THUMBNAILED)) + if (includeRenditions + && (getNodeService().hasAspect(nodeRef, RenditionModel.ASPECT_RENDITIONED) + || getNodeService().hasAspect(nodeRef, ContentModel.ASPECT_THUMBNAILED))) { // get the rendition assoc types Set childAssocTypes = dictionaryService.getAspect(RenditionModel.ASPECT_RENDITIONED).getChildAssociations().keySet(); @@ -179,6 +180,9 @@ public class ContentDestructionComponent { // destroy renditions content destroyContent(child.getChildRef(), false); + + //delete the rendition node + getNodeService().deleteNode(child.getChildRef()); } } } diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ModuleCompatibilityComponentUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ModuleCompatibilityComponentUnitTest.java new file mode 100644 index 0000000000..e4c7eef75c --- /dev/null +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ModuleCompatibilityComponentUnitTest.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2005-2016 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.bootstrap; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.alfresco.service.cmr.admin.RepoUsage.LicenseMode; +import org.alfresco.service.cmr.module.ModuleDetails; +import org.alfresco.service.cmr.module.ModuleService; +import org.alfresco.service.descriptor.DescriptorService; +import org.alfresco.service.license.LicenseDescriptor; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.event.ContextRefreshedEvent; + +/** + * Module compatibility component unit test + * + * @author Roy Wetherall + * @since 2.4 + */ +public class ModuleCompatibilityComponentUnitTest +{ + /** mocks */ + @Mock private DescriptorService mockedDescriptorService; + @Mock private ModuleService mockedModuleService; + @Mock private ContextRefreshedEvent mockedContextRefreshedEvent; + @Mock private ConfigurableApplicationContext mockedApplicationContext; + @Mock private ModuleDetails mockedModuleDetails; + @Mock private LicenseDescriptor mockedDescriptor; + + /** object under test */ + @InjectMocks private ModuleCompatibilityComponent moduleCompatibilityComponent; + + /** + * Before test execution + */ + @Before + public void before() + { + MockitoAnnotations.initMocks(this); + + when(mockedContextRefreshedEvent.getApplicationContext()) + .thenReturn(mockedApplicationContext); + when(mockedDescriptorService.getLicenseDescriptor()) + .thenReturn(mockedDescriptor); + } + + /** + * Given that core community is installed + * And that RM community is installed + * When the application context is loaded + * Then it is successful + */ + @Test + public void communityOnCommunity() + { + // community core installed + when(mockedDescriptor.getLicenseMode()) + .thenReturn(LicenseMode.UNKNOWN); + + // community RM installed + when(mockedModuleService.getModule(anyString())) + .thenReturn(null); + + // on app context refresh + moduleCompatibilityComponent.onApplicationEvent(mockedContextRefreshedEvent); + + // verify close never called + verify(mockedApplicationContext, never()).close(); + + } + + /** + * Given that core community is installed + * And that RM enterprise is installed + * When the application context is loaded + * Then it fails + */ + @Test + public void enterpriseOnCommunity() + { + // community core installed + when(mockedDescriptor.getLicenseMode()) + .thenReturn(LicenseMode.UNKNOWN); + + // enterprise RM installed + when(mockedModuleService.getModule(anyString())) + .thenReturn(mockedModuleDetails); + + // on app context refresh + moduleCompatibilityComponent.onApplicationEvent(mockedContextRefreshedEvent); + + // verify close is called + verify(mockedApplicationContext).close(); + + } + + /** + * Given that core enterprise is installed + * And that RM community is installed + * When the application context is loaded + * Then it fails + */ + @Test + public void communityOnEnterprise() + { + // enterprise core installed + when(mockedDescriptor.getLicenseMode()) + .thenReturn(LicenseMode.ENTERPRISE); + + // community RM installed + when(mockedModuleService.getModule(anyString())) + .thenReturn(null); + + // on app context refresh + moduleCompatibilityComponent.onApplicationEvent(mockedContextRefreshedEvent); + + // verify close is called + verify(mockedApplicationContext).close(); + } + + /** + * Given that core enterprise is installed + * And that RM enterprise is installed + * When the application context is loaded + * Then it is successful + */ + @Test + public void enterpriseOnEnterprise() + { + // enterprise core installed + when(mockedDescriptor.getLicenseMode()) + .thenReturn(LicenseMode.ENTERPRISE); + + // enterprise RM installed + when(mockedModuleService.getModule(anyString())) + .thenReturn(mockedModuleDetails); + + // on app context refresh + moduleCompatibilityComponent.onApplicationEvent(mockedContextRefreshedEvent); + + // verify close never called + verify(mockedApplicationContext, never()).close(); + + } +}