diff --git a/config/alfresco/action-services-context.xml b/config/alfresco/action-services-context.xml index a3647ea7b6..9ed10030d4 100644 --- a/config/alfresco/action-services-context.xml +++ b/config/alfresco/action-services-context.xml @@ -554,9 +554,6 @@ - - - diff --git a/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuter.java b/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuter.java index 1888f3395e..b49c30aee4 100644 --- a/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuter.java @@ -24,7 +24,6 @@ import org.alfresco.model.ContentModel; import org.alfresco.repo.action.ParameterDefinitionImpl; import org.alfresco.repo.rule.RuntimeRuleService; import org.alfresco.service.cmr.action.Action; -import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.action.ParameterDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; @@ -33,6 +32,7 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.rule.Rule; import org.alfresco.service.cmr.rule.RuleService; +import org.alfresco.service.namespace.QName; /** * This action executes all rules present on the actioned upon node @@ -46,6 +46,7 @@ public class ExecuteAllRulesActionExecuter extends ActionExecuterAbstractBase */ public static final String NAME = "execute-all-rules"; public static final String PARAM_EXECUTE_INHERITED_RULES = "execute-inherited-rules"; + public static final String PARAM_RUN_ALL_RULES_ON_CHILDREN = "run-all-rules-on-children"; /** * The node service @@ -62,11 +63,6 @@ public class ExecuteAllRulesActionExecuter extends ActionExecuterAbstractBase */ private RuntimeRuleService runtimeRuleService; - /** - * The action service - */ - private ActionService actionService; - /** The dictionary Service */ private DictionaryService dictionaryService; @@ -99,16 +95,6 @@ public class ExecuteAllRulesActionExecuter extends ActionExecuterAbstractBase { this.runtimeRuleService = runtimeRuleService; } - - /** - * Set the action service - * - * @param actionService the action service - */ - public void setActionService(ActionService actionService) - { - this.actionService = actionService; - } /** * Sets the dictionary service @@ -135,34 +121,49 @@ public class ExecuteAllRulesActionExecuter extends ActionExecuterAbstractBase includeInherited = includeInheritedValue.booleanValue(); } - // Get the rules - List rules = this.ruleService.getRules(actionedUponNodeRef, includeInherited); + boolean runAllChildren = false; + Boolean runAllChildrenValue = (Boolean)ruleAction.getParameterValue(PARAM_RUN_ALL_RULES_ON_CHILDREN); + if (runAllChildrenValue != null) + { + runAllChildren = runAllChildrenValue.booleanValue(); + } + + // Get the rules + List rules = ruleService.getRules(actionedUponNodeRef, includeInherited); if (rules != null && rules.isEmpty() == false) { // Get the child nodes for the actioned upon node - List children = this.nodeService.getChildAssocs(actionedUponNodeRef); + List children = nodeService.getChildAssocs(actionedUponNodeRef); for (ChildAssociationRef childAssoc : children) { // Get the child node reference NodeRef child = childAssoc.getChildRef(); // Only execute rules on non-system folders - if (this.dictionaryService.isSubClass(this.nodeService.getType(child), ContentModel.TYPE_SYSTEM_FOLDER) == false) + QName childType = nodeService.getType(child); + if (dictionaryService.isSubClass(childType, ContentModel.TYPE_SYSTEM_FOLDER) == false) { for (Rule rule : rules) { - // Only reapply rules that are enabled + // Only re-apply rules that are enabled if (rule.getRuleDisabled() == false) { Action action = rule.getAction(); if (action != null) { - //this.actionService.executeAction(action, child); - this.runtimeRuleService.addRulePendingExecution(actionedUponNodeRef, child, rule); + runtimeRuleService.addRulePendingExecution(actionedUponNodeRef, child, rule); } } } - } + + // If the child is a folder and we have asked to run rules on children + if (runAllChildren == true && + dictionaryService.isSubClass(childType, ContentModel.TYPE_FOLDER) == true) + { + // Recurse with the child folder + executeImpl(ruleAction, child); + } + } } } } @@ -175,5 +176,6 @@ public class ExecuteAllRulesActionExecuter extends ActionExecuterAbstractBase protected void addParameterDefinitions(List paramList) { paramList.add(new ParameterDefinitionImpl(PARAM_EXECUTE_INHERITED_RULES, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_EXECUTE_INHERITED_RULES))); + paramList.add(new ParameterDefinitionImpl(PARAM_RUN_ALL_RULES_ON_CHILDREN, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_RUN_ALL_RULES_ON_CHILDREN))); } } diff --git a/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuterTest.java b/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuterTest.java index 63cc569b2b..62bc76e743 100644 --- a/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuterTest.java +++ b/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuterTest.java @@ -21,6 +21,10 @@ package org.alfresco.repo.action.executer; import org.alfresco.model.ContentModel; import org.alfresco.repo.action.ActionImpl; import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.TransactionUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.repository.NodeRef; @@ -49,6 +53,8 @@ public class ExecuteAllRulesActionExecuterTest extends BaseSpringTest /** The action service */ private ActionService actionService; + private RetryingTransactionHelper transactionHelper; + /** The store reference */ private StoreRef testStoreRef; @@ -70,6 +76,7 @@ public class ExecuteAllRulesActionExecuterTest extends BaseSpringTest this.nodeService = (NodeService)this.applicationContext.getBean("nodeService"); this.ruleService = (RuleService)this.applicationContext.getBean("ruleService"); this.actionService = (ActionService)this.applicationContext.getBean("actionService"); + transactionHelper = (RetryingTransactionHelper)applicationContext.getBean("retryingTransactionHelper"); AuthenticationComponent authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent"); authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); @@ -90,21 +97,32 @@ public class ExecuteAllRulesActionExecuterTest extends BaseSpringTest public void testExecution() { // Create a folder and put a couple of documents in it - NodeRef folder = this.nodeService.createNode( + final NodeRef folder = this.nodeService.createNode( this.rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{test}folderOne"), ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef doc1 = this.nodeService.createNode( + final NodeRef doc1 = this.nodeService.createNode( folder, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CONTAINS, QName.createQName("{test}docOne"), ContentModel.TYPE_CONTENT).getChildRef(); - NodeRef doc2 = this.nodeService.createNode( + final NodeRef doc2 = this.nodeService.createNode( folder, - ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CONTAINS, QName.createQName("{test}docTwo"), ContentModel.TYPE_CONTENT).getChildRef(); + final NodeRef folder2 = this.nodeService.createNode( + folder, + ContentModel.ASSOC_CONTAINS, + QName.createQName("{test}folderTwo"), + ContentModel.TYPE_FOLDER).getChildRef(); + final NodeRef doc3 = this.nodeService.createNode( + folder2, + ContentModel.ASSOC_CONTAINS, + QName.createQName("{test}docThree"), + ContentModel.TYPE_CONTENT).getChildRef(); + // Add a couple of rules to the folder Rule rule1 = new Rule(); @@ -121,11 +139,23 @@ public class ExecuteAllRulesActionExecuterTest extends BaseSpringTest rule2.setAction(action2); this.ruleService.saveRule(folder, rule2); + Rule rule3 = new Rule(); + rule3.setRuleType(RuleType.INBOUND); + Action action3 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); + action3.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_TITLED); + rule3.setAction(action3); + this.ruleService.saveRule(folder2, rule3); + // Check the the docs don't have the aspects yet assertFalse(this.nodeService.hasAspect(doc1, ContentModel.ASPECT_VERSIONABLE)); assertFalse(this.nodeService.hasAspect(doc1, ContentModel.ASPECT_CLASSIFIABLE)); + assertFalse(this.nodeService.hasAspect(doc1, ContentModel.ASPECT_TITLED)); assertFalse(this.nodeService.hasAspect(doc2, ContentModel.ASPECT_VERSIONABLE)); assertFalse(this.nodeService.hasAspect(doc2, ContentModel.ASPECT_CLASSIFIABLE)); + assertFalse(this.nodeService.hasAspect(doc2, ContentModel.ASPECT_TITLED)); + assertFalse(nodeService.hasAspect(doc3, ContentModel.ASPECT_VERSIONABLE)); + assertFalse(nodeService.hasAspect(doc3, ContentModel.ASPECT_CLASSIFIABLE)); + assertFalse(nodeService.hasAspect(doc3, ContentModel.ASPECT_TITLED)); assertTrue(this.nodeService.exists(folder)); @@ -133,9 +163,81 @@ public class ExecuteAllRulesActionExecuterTest extends BaseSpringTest ActionImpl action = new ActionImpl(null, ID, ExecuteAllRulesActionExecuter.NAME, null); this.executer.execute(action, folder); - assertTrue(this.nodeService.hasAspect(doc1, ContentModel.ASPECT_VERSIONABLE)); - assertTrue(this.nodeService.hasAspect(doc1, ContentModel.ASPECT_CLASSIFIABLE)); - assertTrue(this.nodeService.hasAspect(doc2, ContentModel.ASPECT_VERSIONABLE)); - assertTrue(this.nodeService.hasAspect(doc2, ContentModel.ASPECT_CLASSIFIABLE)); + setComplete(); + endTransaction(); + + transactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + assertTrue(nodeService.hasAspect(doc1, ContentModel.ASPECT_VERSIONABLE)); + assertTrue(nodeService.hasAspect(doc1, ContentModel.ASPECT_CLASSIFIABLE)); + assertFalse(nodeService.hasAspect(doc2, ContentModel.ASPECT_TITLED)); + assertTrue(nodeService.hasAspect(doc2, ContentModel.ASPECT_VERSIONABLE)); + assertTrue(nodeService.hasAspect(doc2, ContentModel.ASPECT_CLASSIFIABLE)); + assertFalse(nodeService.hasAspect(doc2, ContentModel.ASPECT_TITLED)); + assertFalse(nodeService.hasAspect(doc3, ContentModel.ASPECT_VERSIONABLE)); + assertFalse(nodeService.hasAspect(doc3, ContentModel.ASPECT_CLASSIFIABLE)); + assertFalse(nodeService.hasAspect(doc3, ContentModel.ASPECT_TITLED)); + + clearAspects(doc1); + clearAspects(doc2); + clearAspects(doc3); + + return null; + } + }); + + transactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + assertFalse(nodeService.hasAspect(doc1, ContentModel.ASPECT_VERSIONABLE)); + assertFalse(nodeService.hasAspect(doc1, ContentModel.ASPECT_CLASSIFIABLE)); + assertFalse(nodeService.hasAspect(doc1, ContentModel.ASPECT_TITLED)); + assertFalse(nodeService.hasAspect(doc2, ContentModel.ASPECT_VERSIONABLE)); + assertFalse(nodeService.hasAspect(doc2, ContentModel.ASPECT_CLASSIFIABLE)); + assertFalse(nodeService.hasAspect(doc2, ContentModel.ASPECT_TITLED)); + assertFalse(nodeService.hasAspect(doc3, ContentModel.ASPECT_VERSIONABLE)); + assertFalse(nodeService.hasAspect(doc3, ContentModel.ASPECT_CLASSIFIABLE)); + assertFalse(nodeService.hasAspect(doc3, ContentModel.ASPECT_TITLED)); + + // Execute the action + ActionImpl action = new ActionImpl(null, ID, ExecuteAllRulesActionExecuter.NAME, null); + action.setParameterValue(ExecuteAllRulesActionExecuter.PARAM_RUN_ALL_RULES_ON_CHILDREN, Boolean.TRUE); + executer.execute(action, folder); + + return null; + } + }); + + transactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + assertTrue(nodeService.hasAspect(doc1, ContentModel.ASPECT_VERSIONABLE)); + assertTrue(nodeService.hasAspect(doc1, ContentModel.ASPECT_CLASSIFIABLE)); + assertFalse(nodeService.hasAspect(doc2, ContentModel.ASPECT_TITLED)); + assertTrue(nodeService.hasAspect(doc2, ContentModel.ASPECT_VERSIONABLE)); + assertTrue(nodeService.hasAspect(doc2, ContentModel.ASPECT_CLASSIFIABLE)); + assertFalse(nodeService.hasAspect(doc2, ContentModel.ASPECT_TITLED)); + assertFalse(nodeService.hasAspect(doc3, ContentModel.ASPECT_VERSIONABLE)); + assertFalse(nodeService.hasAspect(doc3, ContentModel.ASPECT_CLASSIFIABLE)); + assertTrue(nodeService.hasAspect(doc3, ContentModel.ASPECT_TITLED)); + + clearAspects(doc1); + clearAspects(doc2); + clearAspects(doc3); + + return null; + } + }); + } + + private void clearAspects(NodeRef nodeRef) + { + nodeService.removeAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE); + nodeService.removeAspect(nodeRef, ContentModel.ASPECT_CLASSIFIABLE); + nodeService.removeAspect(nodeRef, ContentModel.ASPECT_TITLED); } }