diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index 17eac74a1a..1ee0606d81 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -72,3 +72,6 @@ patch.topLevelGroupParentChildAssociationTypePatch.description=Ensure top level patch.topLevelGroupParentChildAssociationTypePatch.result=Fixed {0} top level groups child association types. patch.topLevelGroupParentChildAssociationTypePatch.err.sys_path_not_found=Required authority system path not found: {0} patch.topLevelGroupParentChildAssociationTypePatch.err.auth_path_not_found=Required authority path not found: {0} + +patch.actionRuleDecouplingPatch.description=Migrate existing rules to the updated model where rules are decoupled from actions. +patch.actionRuleDecouplingPatch.result=Updated {0} rules. \ No newline at end of file diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 2cca6f90f9..9cf5fd4909 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -37,6 +37,9 @@ + + + @@ -359,8 +362,7 @@ - - + patch.topLevelGroupParentChildAssociationTypePatch patch.topLevelGroupParentChildAssociationTypePatch.description @@ -369,4 +371,12 @@ 14 + + patch.actionRuleDecouplingPatch + patch.actionRuleDecouplingPatch.description + 0 + 14 + 15 + + diff --git a/config/alfresco/rule-services-context.xml b/config/alfresco/rule-services-context.xml index 634dd18fca..fe4077c3ae 100644 --- a/config/alfresco/rule-services-context.xml +++ b/config/alfresco/rule-services-context.xml @@ -55,10 +55,7 @@ - - - - + diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index c70169ae32..9069f83ce6 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -19,4 +19,4 @@ version.build=@build-number@ # Schema number -version.schema=14 +version.schema=15 diff --git a/source/java/org/alfresco/repo/action/ActionImpl.java b/source/java/org/alfresco/repo/action/ActionImpl.java index b92579f5ae..c568db742e 100644 --- a/source/java/org/alfresco/repo/action/ActionImpl.java +++ b/source/java/org/alfresco/repo/action/ActionImpl.java @@ -40,6 +40,9 @@ public class ActionImpl extends ParameterizedItemImpl */ private static final long serialVersionUID = 3258135760426186548L; + /** The node reference for the action */ + private NodeRef nodeRef; + /** * The title */ @@ -90,11 +93,6 @@ public class ActionImpl extends ParameterizedItemImpl */ private String runAsUserName; - /** - * The owning node reference - */ - private NodeRef owningNodeRef; - /** * The chain of actions that have lead to this action */ @@ -108,30 +106,32 @@ public class ActionImpl extends ParameterizedItemImpl /** * Constructor * + * @param nodeRef the action node reference (null if not saved) * @param id the action id * @param actionDefinitionName the name of the action definition */ - public ActionImpl(String id, String actionDefinitionName, NodeRef owningNodeRef) + public ActionImpl(NodeRef nodeRef, String id, String actionDefinitionName) { - this(id, actionDefinitionName, owningNodeRef, null); + this(nodeRef, id, actionDefinitionName, null); } /** * Constructor * + * @param nodeRef the action node reference (null if not saved) * @param id the action id * @param actionDefinitionName the action definition name * @param parameterValues the parameter values */ public ActionImpl( + NodeRef nodeRef, String id, String actionDefinitionName, - NodeRef owningNodeRef, Map parameterValues) { super(id, parameterValues); + this.nodeRef = nodeRef; this.actionDefinitionName = actionDefinitionName; - this.owningNodeRef = owningNodeRef; } /** @@ -165,19 +165,6 @@ public class ActionImpl extends ParameterizedItemImpl { this.description = description; } - - /** - * @see org.alfresco.service.cmr.action.Action#getOwningNodeRef() - */ - public NodeRef getOwningNodeRef() - { - return this.owningNodeRef; - } - - public void setOwningNodeRef(NodeRef owningNodeRef) - { - this.owningNodeRef = owningNodeRef; - } /** * @see org.alfresco.service.cmr.action.Action#getExecuteAsychronously() @@ -392,4 +379,22 @@ public class ActionImpl extends ParameterizedItemImpl { this.runAsUserName = runAsUserName; } + + /** + * @see org.alfresco.service.cmr.action.Action#getNodeRef() + */ + public NodeRef getNodeRef() + { + return this.nodeRef; + } + + /** + * Set the node reference + * + * @param nodeRef the node reference + */ + public void setNodeRef(NodeRef nodeRef) + { + this.nodeRef = nodeRef; + } } diff --git a/source/java/org/alfresco/repo/action/ActionImplTest.java b/source/java/org/alfresco/repo/action/ActionImplTest.java index 85bfbf764c..e6a3acfc90 100644 --- a/source/java/org/alfresco/repo/action/ActionImplTest.java +++ b/source/java/org/alfresco/repo/action/ActionImplTest.java @@ -41,9 +41,9 @@ public class ActionImplTest extends BaseParameterizedItemImplTest protected ParameterizedItemImpl create() { return new ActionImpl( + null, ID, NAME, - null, this.paramValues); } @@ -65,7 +65,7 @@ public class ActionImplTest extends BaseParameterizedItemImplTest action.setTitle("title"); action.setDescription("description"); action.setExecuteAsynchronously(true); - Action compensatingAction = new ActionImpl(GUID.generate(), "actionDefintionName", null); + Action compensatingAction = new ActionImpl(null, GUID.generate(), "actionDefintionName", null); action.setCompensatingAction(compensatingAction); // Check the values have been set diff --git a/source/java/org/alfresco/repo/action/ActionServiceImpl.java b/source/java/org/alfresco/repo/action/ActionServiceImpl.java index f7dad34e08..0ec6be6296 100644 --- a/source/java/org/alfresco/repo/action/ActionServiceImpl.java +++ b/source/java/org/alfresco/repo/action/ActionServiceImpl.java @@ -309,7 +309,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A */ public Action createAction(String name) { - return new ActionImpl(GUID.generate(),name, null); + return new ActionImpl(null, GUID.generate(),name, null); } /** @@ -327,7 +327,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A */ public CompositeAction createCompositeAction() { - return new CompositeActionImpl(GUID.generate(), null); + return new CompositeActionImpl(null, GUID.generate()); } /** @@ -594,42 +594,51 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A // Apply the actionable aspect this.nodeService.addAspect(nodeRef, ActionModel.ASPECT_ACTIONS, null); } - - Map props = new HashMap(2); - props.put(ActionModel.PROP_DEFINITION_NAME, action.getActionDefinitionName()); - props.put(ContentModel.PROP_NODE_UUID, action.getId()); - - QName actionType = ActionModel.TYPE_ACTION; - if(action instanceof CompositeAction) - { - actionType = ActionModel.TYPE_COMPOSITE_ACTION; - } - - // Create the action node - actionNodeRef = this.nodeService.createNode( - getSavedActionFolderRef(nodeRef), - ContentModel.ASSOC_CONTAINS, - ASSOC_NAME_ACTIONS, - actionType, - props).getChildRef(); - - // Update the created details - ((ActionImpl)action).setCreator((String)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_CREATOR)); - ((ActionImpl)action).setCreatedDate((Date)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_CREATED)); + + // Create the action nod reference + actionNodeRef = createActionNodeRef(action, + getSavedActionFolderRef(nodeRef), + ContentModel.ASSOC_CONTAINS, + ASSOC_NAME_ACTIONS); } - saveActionImpl(nodeRef, actionNodeRef, action); + saveActionImpl(actionNodeRef, action); } + public NodeRef createActionNodeRef(Action action, NodeRef parentNodeRef, QName assocTypeName, QName assocName) + { + Map props = new HashMap(2); + props.put(ActionModel.PROP_DEFINITION_NAME, action.getActionDefinitionName()); + props.put(ContentModel.PROP_NODE_UUID, action.getId()); + + QName actionType = ActionModel.TYPE_ACTION; + if(action instanceof CompositeAction) + { + actionType = ActionModel.TYPE_COMPOSITE_ACTION; + } + + // Create the action node + NodeRef actionNodeRef = this.nodeService.createNode( + parentNodeRef, + assocTypeName, + assocName, + actionType, + props).getChildRef(); + + // Update the created details and the node reference + ((ActionImpl)action).setCreator((String)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_CREATOR)); + ((ActionImpl)action).setCreatedDate((Date)this.nodeService.getProperty(actionNodeRef, ContentModel.PROP_CREATED)); + ((ActionImpl)action).setNodeRef(actionNodeRef); + + return actionNodeRef; + } + /** * @see org.alfresco.repo.action.RuntimeActionService#saveActionImpl(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.action.Action) */ - public void saveActionImpl(NodeRef owningNodeRef, NodeRef actionNodeRef, Action action) + public void saveActionImpl(NodeRef actionNodeRef, Action action) { - // Set the owning node ref - ((ActionImpl)action).setOwningNodeRef(owningNodeRef); - - // Save action properties + // Save action properties saveActionProperties(actionNodeRef, action); // Update the parameters of the action @@ -671,18 +680,20 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A { if (compensatingAction != null) { - Map props2 = new HashMap(2); - props2.put(ActionModel.PROP_DEFINITION_NAME, compensatingAction.getActionDefinitionName()); - props2.put(ContentModel.PROP_NODE_UUID, compensatingAction.getId()); + //Map props2 = new HashMap(2); + //props2.put(ActionModel.PROP_DEFINITION_NAME, compensatingAction.getActionDefinitionName()); + //props2.put(ContentModel.PROP_NODE_UUID, compensatingAction.getId()); - NodeRef compensatingActionNodeRef = this.nodeService.createNode( - actionNodeRef, - ActionModel.ASSOC_COMPENSATING_ACTION, - ActionModel.ASSOC_COMPENSATING_ACTION, - ActionModel.TYPE_ACTION, - props2).getChildRef(); - - saveActionImpl(compensatingAction.getOwningNodeRef(), compensatingActionNodeRef, compensatingAction); + //NodeRef compensatingActionNodeRef = this.nodeService.createNode( + /// actionNodeRef, + // ActionModel.ASSOC_COMPENSATING_ACTION, + // ActionModel.ASSOC_COMPENSATING_ACTION, + // ActionModel.TYPE_ACTION, + // props2).getChildRef(); + + // Create the compensating node reference + NodeRef compensatingActionNodeRef = createActionNodeRef(compensatingAction, actionNodeRef, ActionModel.ASSOC_COMPENSATING_ACTION, ActionModel.ASSOC_COMPENSATING_ACTION); + saveActionImpl(compensatingActionNodeRef, compensatingAction); } } else @@ -694,7 +705,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A } else { - saveActionImpl(compensatingAction.getOwningNodeRef(), assoc.getChildRef(), compensatingAction); + saveActionImpl(assoc.getChildRef(), compensatingAction); } } } @@ -730,7 +741,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A { // Update the action Action action = idToAction.get(actionNodeRef.getId()); - saveActionImpl(action.getOwningNodeRef(), actionNodeRef, action); + saveActionImpl(actionNodeRef, action); orderedIds.remove(actionNodeRef.getId()); } @@ -752,7 +763,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A ActionModel.TYPE_ACTION, props).getChildRef(); - saveActionImpl(action.getOwningNodeRef(), actionNodeRef, action); + saveActionImpl(actionNodeRef, action); } } @@ -889,7 +900,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A for (ChildAssociationRef action : actions) { NodeRef actionNodeRef = action.getChildRef(); - result.add(createAction(nodeRef, actionNodeRef)); + result.add(createAction(actionNodeRef)); } } @@ -902,7 +913,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A * @param actionNodeRef the action node reference * @return the action */ - private Action createAction(NodeRef owningNodeRef, NodeRef actionNodeRef) + public Action createAction(NodeRef actionNodeRef) { Action result = null; @@ -912,13 +923,13 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A if (ActionModel.TYPE_COMPOSITE_ACTION.equals(actionType) == true) { // Create a composite action - result = new CompositeActionImpl(actionNodeRef.getId(), owningNodeRef); + result = new CompositeActionImpl(actionNodeRef, actionNodeRef.getId()); populateCompositeAction(actionNodeRef, (CompositeAction)result); } else { // Create an action - result = new ActionImpl(actionNodeRef.getId(), (String)properties.get(ActionModel.PROP_DEFINITION_NAME), owningNodeRef); + result = new ActionImpl(actionNodeRef, actionNodeRef.getId(), (String)properties.get(ActionModel.PROP_DEFINITION_NAME)); populateAction(actionNodeRef, result); } @@ -978,7 +989,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A List assocs = this.nodeService.getChildAssocs(actionNodeRef, RegexQNamePattern.MATCH_ALL, ActionModel.ASSOC_COMPENSATING_ACTION); if (assocs.size() != 0) { - Action compensatingAction = createAction(action.getOwningNodeRef(), assocs.get(0).getChildRef()); + Action compensatingAction = createAction(assocs.get(0).getChildRef()); action.setCompensatingAction(compensatingAction); } } @@ -1039,7 +1050,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A for (ChildAssociationRef action : actions) { NodeRef actionNodeRef = action.getChildRef(); - compositeAction.addAction(createAction(compositeAction.getOwningNodeRef(), actionNodeRef)); + compositeAction.addAction(createAction(actionNodeRef)); } } @@ -1056,7 +1067,7 @@ public class ActionServiceImpl implements ActionService, RuntimeActionService, A NodeRef actionNodeRef = getActionNodeRefFromId(nodeRef, actionId); if (actionNodeRef != null) { - result = createAction(nodeRef, actionNodeRef); + result = createAction(actionNodeRef); } } diff --git a/source/java/org/alfresco/repo/action/ActionServiceImplTest.java b/source/java/org/alfresco/repo/action/ActionServiceImplTest.java index 6af845cda7..1d57a7eeba 100644 --- a/source/java/org/alfresco/repo/action/ActionServiceImplTest.java +++ b/source/java/org/alfresco/repo/action/ActionServiceImplTest.java @@ -388,19 +388,19 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest action.setExecuteAsynchronously(true); // Check the owning node ref - assertNull(action.getOwningNodeRef()); + //assertNull(action.getOwningNodeRef()); // Save the action this.actionService.saveAction(this.nodeRef, action); // Check the owning node ref - assertEquals(this.nodeRef, action.getOwningNodeRef()); + //assertEquals(this.nodeRef, action.getOwningNodeRef()); // Get the action Action savedAction = this.actionService.getAction(this.nodeRef, actionId); // Check the owning node ref - assertEquals(this.nodeRef, savedAction.getOwningNodeRef());; + //assertEquals(this.nodeRef, savedAction.getOwningNodeRef());; } /** diff --git a/source/java/org/alfresco/repo/action/CompositeActionImpl.java b/source/java/org/alfresco/repo/action/CompositeActionImpl.java index a761c9a9ad..55861c810c 100644 --- a/source/java/org/alfresco/repo/action/CompositeActionImpl.java +++ b/source/java/org/alfresco/repo/action/CompositeActionImpl.java @@ -46,9 +46,9 @@ public class CompositeActionImpl extends ActionImpl implements CompositeAction * * @param id the action id */ - public CompositeActionImpl(String id, NodeRef owningNodeRef) + public CompositeActionImpl(NodeRef nodeRef, String id) { - super(id, CompositeActionExecuter.NAME, owningNodeRef); + super(nodeRef, id, CompositeActionExecuter.NAME); } /** diff --git a/source/java/org/alfresco/repo/action/CompositeActionImplTest.java b/source/java/org/alfresco/repo/action/CompositeActionImplTest.java index 6d044a79e8..f09f5b5810 100644 --- a/source/java/org/alfresco/repo/action/CompositeActionImplTest.java +++ b/source/java/org/alfresco/repo/action/CompositeActionImplTest.java @@ -37,11 +37,11 @@ public class CompositeActionImplTest extends ActionImplTest public void testActions() { - Action action1 = new ActionImpl(ACTION1_ID, ACTION1_NAME, null); - Action action2 = new ActionImpl(ACTION2_ID, ACTION2_NAME, null); - Action action3 = new ActionImpl(ACTION3_ID, ACTION3_NAME, null); + Action action1 = new ActionImpl(null, ACTION1_ID, ACTION1_NAME, null); + Action action2 = new ActionImpl(null, ACTION2_ID, ACTION2_NAME, null); + Action action3 = new ActionImpl(null, ACTION3_ID, ACTION3_NAME, null); - CompositeAction compositeAction = new CompositeActionImpl(ID, null); + CompositeAction compositeAction = new CompositeActionImpl(null, ID); // Check has no action assertFalse(compositeAction.hasActions()); diff --git a/source/java/org/alfresco/repo/action/RuntimeActionService.java b/source/java/org/alfresco/repo/action/RuntimeActionService.java index 0ba0c5bdac..a69bb1462e 100644 --- a/source/java/org/alfresco/repo/action/RuntimeActionService.java +++ b/source/java/org/alfresco/repo/action/RuntimeActionService.java @@ -23,21 +23,38 @@ import org.alfresco.repo.action.ActionServiceImpl.PendingAction; import org.alfresco.repo.action.evaluator.ActionConditionEvaluator; import org.alfresco.repo.action.executer.ActionExecuter; import org.alfresco.service.cmr.action.Action; -import org.alfresco.service.cmr.action.CompositeAction; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; /** * @author Roy Wetherall */ public interface RuntimeActionService { + /** + * Get the asynchronous action queue. + * + * @return the asynchronous action queue + */ AsynchronousActionExecutionQueue getAsynchronousActionExecutionQueue(); + /** + * Register an action condition evaluator + * + * @param actionConditionEvaluator action condition evaluator + */ void registerActionConditionEvaluator(ActionConditionEvaluator actionConditionEvaluator); + /** + * Register an action executer + * + * @param actionExecuter action executer + */ void registerActionExecuter(ActionExecuter actionExecuter); - - void populateCompositeAction(NodeRef compositeNodeRef, CompositeAction compositeAction); + + Action createAction(NodeRef actionNodeRef); + + NodeRef createActionNodeRef(Action action, NodeRef parentNodeRef, QName assocTypeName, QName assocName); /** * Save action, used internally to store the details of an action on the aciton node. @@ -45,7 +62,7 @@ public interface RuntimeActionService * @param actionNodeRef the action node reference * @param action the action */ - void saveActionImpl(NodeRef owningNodeRef, NodeRef actionNodeRef, Action action); + void saveActionImpl(NodeRef actionNodeRef, Action action); /** * @@ -60,7 +77,18 @@ public interface RuntimeActionService boolean executedAsynchronously, Set actionChain); + /** + * Execute an action directly + * + * @param action the action + * @param actionedUponNodeRef the actioned upon node reference + */ public void directActionExecution(Action action, NodeRef actionedUponNodeRef); + /** + * Gets a list of the actions that are pending post transaction + * + * @return list of pending actions + */ public List getPostTransactionPendingActions(); } diff --git a/source/java/org/alfresco/repo/action/executer/AddFeaturesActionExecuterTest.java b/source/java/org/alfresco/repo/action/executer/AddFeaturesActionExecuterTest.java index 7e508183cd..935ca4bc73 100644 --- a/source/java/org/alfresco/repo/action/executer/AddFeaturesActionExecuterTest.java +++ b/source/java/org/alfresco/repo/action/executer/AddFeaturesActionExecuterTest.java @@ -100,7 +100,7 @@ public class AddFeaturesActionExecuterTest extends BaseSpringTest assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_CLASSIFIABLE)); // Execute the action - ActionImpl action = new ActionImpl(ID, AddFeaturesActionExecuter.NAME, null); + ActionImpl action = new ActionImpl(null, ID, AddFeaturesActionExecuter.NAME, null); action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE); this.executer.execute(action, this.nodeRef); diff --git a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracterTest.java b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracterTest.java index 6f5c500ebf..0d50b5c7c5 100644 --- a/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracterTest.java +++ b/source/java/org/alfresco/repo/action/executer/ContentMetadataExtracterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Jesper Steen Møller + * Copyright (C) 2005 Jesper Steen M�ller * * Licensed under the Mozilla Public License version 1.1 * with a permitted attribution clause. You may obtain a @@ -37,7 +37,7 @@ import org.alfresco.util.GUID; * Test of the ActionExecuter for extracting metadata. Note: This test makes * assumptions about the PDF test data for PdfBoxExtracter. * - * @author Jesper Steen Møller + * @author Jesper Steen M�ller */ public class ContentMetadataExtracterTest extends BaseSpringTest { @@ -102,7 +102,7 @@ public class ContentMetadataExtracterTest extends BaseSpringTest this.nodeService.setProperties(this.nodeRef, props); // Execute the action - ActionImpl action = new ActionImpl(ID, SetPropertyValueActionExecuter.NAME, null); + ActionImpl action = new ActionImpl(null, ID, SetPropertyValueActionExecuter.NAME, null); this.executer.execute(action, this.nodeRef); @@ -130,7 +130,7 @@ public class ContentMetadataExtracterTest extends BaseSpringTest this.nodeService.setProperties(this.nodeRef, props); // Execute the action - ActionImpl action = new ActionImpl(ID, SetPropertyValueActionExecuter.NAME, null); + ActionImpl action = new ActionImpl(null, ID, SetPropertyValueActionExecuter.NAME, null); this.executer.execute(action, this.nodeRef); diff --git a/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuter.java b/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuter.java index 2d9b0eb779..934b687be9 100644 --- a/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuter.java @@ -133,8 +133,11 @@ public class ExecuteAllRulesActionExecuter extends ActionExecuterAbstractBase { for (Rule rule : rules) { - // Apply the rule to the child node - this.actionService.executeAction(rule, child); + Action action = rule.getAction(); + if (action != null) + { + this.actionService.executeAction(action, child); + } } } } diff --git a/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuterTest.java b/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuterTest.java index 5b82fe00ab..aeccbf1d72 100644 --- a/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuterTest.java +++ b/source/java/org/alfresco/repo/action/executer/ExecuteAllRulesActionExecuterTest.java @@ -105,15 +105,18 @@ public class ExecuteAllRulesActionExecuterTest extends BaseSpringTest ContentModel.TYPE_CONTENT).getChildRef(); // Add a couple of rules to the folder - Rule rule1 = this.ruleService.createRule(RuleType.INBOUND); + Rule rule1 = new Rule(); + rule1.setRuleType(RuleType.INBOUND); Action action1 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); action1.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); - rule1.addAction(action1); + rule1.setAction(action1); this.ruleService.saveRule(folder, rule1); - Rule rule2 = this.ruleService.createRule(RuleType.INBOUND); + + Rule rule2 = new Rule(); + rule2.setRuleType(RuleType.INBOUND); Action action2 = this.actionService.createAction(AddFeaturesActionExecuter.NAME); action2.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE); - rule2.addAction(action2); + rule2.setAction(action2); this.ruleService.saveRule(folder, rule2); // Check the the docs don't have the aspects yet @@ -125,7 +128,7 @@ public class ExecuteAllRulesActionExecuterTest extends BaseSpringTest assertTrue(this.nodeService.exists(folder)); // Execute the action - ActionImpl action = new ActionImpl(ID, ExecuteAllRulesActionExecuter.NAME, null); + ActionImpl action = new ActionImpl(null, ID, ExecuteAllRulesActionExecuter.NAME, null); this.executer.execute(action, folder); assertTrue(this.nodeService.hasAspect(doc1, ContentModel.ASPECT_VERSIONABLE)); diff --git a/source/java/org/alfresco/repo/action/executer/RemoveFeaturesActionExecuterTest.java b/source/java/org/alfresco/repo/action/executer/RemoveFeaturesActionExecuterTest.java index 0d7ce950e0..c80a9b8e08 100644 --- a/source/java/org/alfresco/repo/action/executer/RemoveFeaturesActionExecuterTest.java +++ b/source/java/org/alfresco/repo/action/executer/RemoveFeaturesActionExecuterTest.java @@ -101,7 +101,7 @@ public class RemoveFeaturesActionExecuterTest extends BaseSpringTest assertTrue(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_CLASSIFIABLE)); // Execute the action - ActionImpl action = new ActionImpl(ID, RemoveFeaturesActionExecuter.NAME, null); + ActionImpl action = new ActionImpl(null, ID, RemoveFeaturesActionExecuter.NAME, null); action.setParameterValue(RemoveFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_CLASSIFIABLE); this.executer.execute(action, this.nodeRef); @@ -109,7 +109,7 @@ public class RemoveFeaturesActionExecuterTest extends BaseSpringTest assertFalse(this.nodeService.hasAspect(this.nodeRef, ContentModel.ASPECT_CLASSIFIABLE)); // Now try and remove an aspect that is not present - ActionImpl action2 = new ActionImpl(ID, RemoveFeaturesActionExecuter.NAME, null); + ActionImpl action2 = new ActionImpl(null, ID, RemoveFeaturesActionExecuter.NAME, null); action2.setParameterValue(RemoveFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); this.executer.execute(action2, this.nodeRef); } diff --git a/source/java/org/alfresco/repo/action/executer/ScriptActionExecutor.java b/source/java/org/alfresco/repo/action/executer/ScriptActionExecutor.java index cd3210cf6c..1815acecd3 100644 --- a/source/java/org/alfresco/repo/action/executer/ScriptActionExecutor.java +++ b/source/java/org/alfresco/repo/action/executer/ScriptActionExecutor.java @@ -79,7 +79,7 @@ public class ScriptActionExecutor extends ActionExecuterAbstractBase if (nodeService.exists(actionedUponNodeRef)) { NodeRef scriptRef = (NodeRef)action.getParameterValue(PARAM_SCRIPTREF); - NodeRef spaceRef = (NodeRef)action.getOwningNodeRef(); + NodeRef spaceRef = this.serviceRegistry.getRuleService().getOwningNodeRef(action); if (nodeService.exists(scriptRef)) { diff --git a/source/java/org/alfresco/repo/action/executer/SetPropertyValueActionExecuterTest.java b/source/java/org/alfresco/repo/action/executer/SetPropertyValueActionExecuterTest.java index 01e835a274..3e64439881 100644 --- a/source/java/org/alfresco/repo/action/executer/SetPropertyValueActionExecuterTest.java +++ b/source/java/org/alfresco/repo/action/executer/SetPropertyValueActionExecuterTest.java @@ -74,7 +74,7 @@ public class SetPropertyValueActionExecuterTest extends BaseSpringTest public void testExecution() { // Execute the action - ActionImpl action = new ActionImpl(ID, SetPropertyValueActionExecuter.NAME, null); + ActionImpl action = new ActionImpl(null, ID, SetPropertyValueActionExecuter.NAME, null); action.setParameterValue(SetPropertyValueActionExecuter.PARAM_PROPERTY, ContentModel.PROP_NAME); action.setParameterValue(SetPropertyValueActionExecuter.PARAM_VALUE, TEST_VALUE); this.executer.execute(action, this.nodeRef); diff --git a/source/java/org/alfresco/repo/action/executer/SpecialiseTypeActionExecuterTest.java b/source/java/org/alfresco/repo/action/executer/SpecialiseTypeActionExecuterTest.java index 101ef05f20..35b545b1ed 100644 --- a/source/java/org/alfresco/repo/action/executer/SpecialiseTypeActionExecuterTest.java +++ b/source/java/org/alfresco/repo/action/executer/SpecialiseTypeActionExecuterTest.java @@ -73,7 +73,7 @@ public class SpecialiseTypeActionExecuterTest extends BaseAlfrescoSpringTest assertEquals(ContentModel.TYPE_CONTENT, this.nodeService.getType(this.nodeRef)); // Execute the action - ActionImpl action = new ActionImpl(ID, SpecialiseTypeActionExecuter.NAME, null); + ActionImpl action = new ActionImpl(null, ID, SpecialiseTypeActionExecuter.NAME, null); action.setParameterValue(SpecialiseTypeActionExecuter.PARAM_TYPE_NAME, ContentModel.TYPE_FOLDER); this.executer.execute(action, this.nodeRef); diff --git a/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java b/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java index 0cae0f3a6c..3eba4c49fd 100644 --- a/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java +++ b/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java @@ -25,6 +25,7 @@ import java.util.Map; import org.alfresco.i18n.I18NUtil; import org.alfresco.repo.domain.AppliedPatch; import org.alfresco.service.cmr.admin.PatchException; +import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.descriptor.Descriptor; import org.alfresco.service.descriptor.DescriptorService; import org.apache.commons.logging.Log; @@ -50,6 +51,7 @@ public class PatchServiceImpl implements PatchService private static Log logger = LogFactory.getLog(PatchServiceImpl.class); private DescriptorService descriptorService; + private RuleService ruleService; private PatchDaoService patchDaoService; private List patches; @@ -67,6 +69,11 @@ public class PatchServiceImpl implements PatchService { this.patchDaoService = patchDaoService; } + + public void setRuleService(RuleService ruleService) + { + this.ruleService = ruleService; + } public void registerPatch(Patch patch) { @@ -75,31 +82,50 @@ public class PatchServiceImpl implements PatchService public boolean applyOutstandingPatches() { - // construct a map of all known patches by ID - Map allPatchesById = new HashMap(23); - for (Patch patch : patches) - { - allPatchesById.put(patch.getId(), patch); - } - // construct a list of executed patches by ID - Map appliedPatchesById = new HashMap(23); - List appliedPatches = patchDaoService.getAppliedPatches(); - for (AppliedPatch appliedPatch : appliedPatches) - { - appliedPatchesById.put(appliedPatch.getId(), appliedPatch); - } - // go through all the patches and apply them where necessary boolean success = true; - for (Patch patch : allPatchesById.values()) + + try { - // apply the patch - success = applyPatchAndDependencies(patch, appliedPatchesById); - if (!success) + // Diable rules whilst processing the patches + this.ruleService.disableRules(); + try + { + // construct a map of all known patches by ID + Map allPatchesById = new HashMap(23); + for (Patch patch : patches) { - // we failed to apply a patch or one of its dependencies - terminate - break; + allPatchesById.put(patch.getId(), patch); } + // construct a list of executed patches by ID + Map appliedPatchesById = new HashMap(23); + List appliedPatches = patchDaoService.getAppliedPatches(); + for (AppliedPatch appliedPatch : appliedPatches) + { + appliedPatchesById.put(appliedPatch.getId(), appliedPatch); + } + + // go through all the patches and apply them where necessary + for (Patch patch : allPatchesById.values()) + { + // apply the patch + success = applyPatchAndDependencies(patch, appliedPatchesById); + if (!success) + { + // we failed to apply a patch or one of its dependencies - terminate + break; + } + } } + finally + { + this.ruleService.enableRules(); + } + } + catch (Throwable exception) + { + exception.printStackTrace(); + } + // done return success; } diff --git a/source/java/org/alfresco/repo/admin/patch/impl/ActionRuleDecouplingPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/ActionRuleDecouplingPatch.java new file mode 100644 index 0000000000..8f4aab96c8 --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/impl/ActionRuleDecouplingPatch.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.admin.patch.impl; + +import java.io.Serializable; +import java.util.Map; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.action.ActionModel; +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.rule.RuleModel; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.namespace.QName; + +/** + * Patch to apply the model changes made when decoupling actions from rules. + * + * @author Roy Wetherall + */ +public class ActionRuleDecouplingPatch extends AbstractPatch +{ + private static final String MSG_RESULT = "patch.actionRuleDecouplingPatch.result"; + + /** + * @see org.alfresco.repo.admin.patch.AbstractPatch#applyInternal() + */ + @Override + protected String applyInternal() throws Exception + { + // Get a reference to the spaces store + StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"); + + // Get all the node's of type rule in the store + int updateCount = 0; + ResultSet resultSet = this.searchService.query(storeRef, "lucene", "TYPE:\"" + RuleModel.TYPE_RULE + "\""); + for (NodeRef origRuleNodeRef : resultSet.getNodeRefs()) + { + // Check that this rule need updated + Map origProperties = this.nodeService.getProperties(origRuleNodeRef); + if (origProperties.containsKey(RuleModel.PROP_EXECUTE_ASYNC) == false) + { + // 1) Change the type of the rule to be a composite action + this.nodeService.setType(origRuleNodeRef, ActionModel.TYPE_COMPOSITE_ACTION); + + // 2) Create a new rule node + ChildAssociationRef parentRef = this.nodeService.getPrimaryParent(origRuleNodeRef); + NodeRef newRuleNodeRef = this.nodeService.createNode( + parentRef.getParentRef(), + parentRef.getTypeQName(), + parentRef.getQName(), + RuleModel.TYPE_RULE).getChildRef(); + + // 3) Move the origional rule under the new rule + this.nodeService.moveNode( + origRuleNodeRef, + newRuleNodeRef, + RuleModel.ASSOC_ACTION, + RuleModel.ASSOC_ACTION); + + // 4) Move the various properties from the origional, onto the new rule + Map newProperties = this.nodeService.getProperties(newRuleNodeRef); + + // Set the rule type, execute async and applyToChildren properties on the rule + String ruleType = (String)origProperties.get(RuleModel.PROP_RULE_TYPE); + origProperties.remove(RuleModel.PROP_RULE_TYPE); + newProperties.put(RuleModel.PROP_RULE_TYPE, ruleType); + Boolean executeAsync = (Boolean)origProperties.get(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY); + origProperties.remove(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY); + newProperties.put(RuleModel.PROP_EXECUTE_ASYNC, executeAsync); + Boolean applyToChildren = (Boolean)origProperties.get(RuleModel.PROP_APPLY_TO_CHILDREN); + origProperties.remove(RuleModel.PROP_APPLY_TO_CHILDREN); + newProperties.put(RuleModel.PROP_APPLY_TO_CHILDREN, applyToChildren); + origProperties.remove(QName.createQName(RuleModel.RULE_MODEL_URI, "owningNodeRef")); + + // Move the action and description values from the composite action onto the rule + String title = (String)origProperties.get(ActionModel.PROP_ACTION_TITLE); + origProperties.remove(ActionModel.PROP_ACTION_TITLE); + String description = (String)origProperties.get(ActionModel.PROP_ACTION_DESCRIPTION); + origProperties.remove(ActionModel.PROP_ACTION_DESCRIPTION); + newProperties.put(ContentModel.PROP_TITLE, title); + newProperties.put(ContentModel.PROP_DESCRIPTION, description); + + // Set the updated property values + this.nodeService.setProperties(origRuleNodeRef, origProperties); + this.nodeService.setProperties(newRuleNodeRef, newProperties); + + // Increment the update count + updateCount++; + } + } + + // Done + String msg = I18NUtil.getMessage(MSG_RESULT, updateCount); + return msg; + } + +} diff --git a/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java b/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java index 93b42a7d8e..973ff0c827 100644 --- a/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java +++ b/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java @@ -376,17 +376,20 @@ public class CopyServiceImplTest extends BaseSpringTest public void testCopyNodeWithRules() { // Create a new rule and add it to the source noderef - Rule rule = this.ruleService.createRule(RuleType.INBOUND); + Rule rule = new Rule(); + rule.setRuleType(RuleType.INBOUND); Map props = new HashMap(1); props.put(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE); Action action = this.actionService.createAction(AddFeaturesActionExecuter.NAME, props); - rule.addAction(action); + rule.setAction(action); ActionCondition actionCondition = this.actionService.createActionCondition(NoConditionEvaluator.NAME); - rule.addActionCondition(actionCondition); + action.addActionCondition(actionCondition); this.ruleService.saveRule(this.sourceNodeRef, rule); + assertNotNull(rule.getNodeRef()); + assertEquals(this.sourceNodeRef, this.ruleService.getOwningNodeRef(rule)); //System.out.println( // NodeStoreInspector.dumpNodeStore(this.nodeService, this.storeRef)); @@ -403,20 +406,22 @@ public class CopyServiceImplTest extends BaseSpringTest //System.out.println( // NodeStoreInspector.dumpNodeStore(this.nodeService, this.storeRef)); - checkCopiedNode(this.sourceNodeRef, copy, true, true, true); - - //assertTrue(this.configurableService.isConfigurable(copy)); - //assertNotNull(this.configurableService.getConfigurationFolder(copy)); - //assertFalse(this.configurableService.getConfigurationFolder(this.sourceNodeRef) == this.configurableService.getConfigurationFolder(copy)); + checkCopiedNode(this.sourceNodeRef, copy, true, true, true); assertTrue(this.nodeService.hasAspect(copy, RuleModel.ASPECT_RULES)); assertTrue(this.ruleService.hasRules(copy)); assertTrue(this.ruleService.rulesEnabled(copy)); + List copiedRules = this.ruleService.getRules(copy); assertEquals(1, copiedRules.size()); Rule copiedRule = copiedRules.get(0); - assertFalse(rule.getId() == copiedRule.getId()); - assertEquals(rule.getAction(0).getActionDefinitionName(), copiedRule.getAction(0).getActionDefinitionName()); + + assertNotNull(copiedRule.getNodeRef()); + assertFalse(copiedRule.getNodeRef().equals(rule.getNodeRef())); + assertEquals(rule.getTitle(), copiedRule.getTitle()); + assertEquals(rule.getDescription(), copiedRule.getDescription()); + assertEquals(copy, this.ruleService.getOwningNodeRef(copiedRule)); + assertEquals(rule.getAction().getActionDefinitionName(), copiedRule.getAction().getActionDefinitionName()); // Now copy the node without copying the children and check that the rules have been copied NodeRef copy2 = this.copyService.copy( @@ -441,8 +446,11 @@ public class CopyServiceImplTest extends BaseSpringTest List copiedRules2 = this.ruleService.getRules(copy2); assertEquals(1, copiedRules.size()); Rule copiedRule2 = copiedRules2.get(0); - assertFalse(rule.getId() == copiedRule2.getId()); - assertEquals(rule.getAction(0).getActionDefinitionName(), copiedRule2.getAction(0).getActionDefinitionName()); + assertFalse(rule.getNodeRef().equals(copiedRule2.getNodeRef())); + assertEquals(rule.getTitle(), copiedRule2.getTitle()); + assertEquals(rule.getDescription(), copiedRule2.getDescription()); + assertEquals(this.ruleService.getOwningNodeRef(copiedRule2), copy2); + assertEquals(rule.getAction().getActionDefinitionName(), copiedRule2.getAction().getActionDefinitionName()); } public void testCopyToExistingNode() @@ -531,11 +539,12 @@ public class CopyServiceImplTest extends BaseSpringTest params.put(MoveActionExecuter.PARAM_DESTINATION_FOLDER, nodeTwo); params.put(MoveActionExecuter.PARAM_ASSOC_TYPE_QNAME, TEST_CHILD_ASSOC_TYPE_QNAME); params.put(MoveActionExecuter.PARAM_ASSOC_QNAME, QName.createQName("{test}ruleCopy")); - Rule rule = this.ruleService.createRule(RuleType.INBOUND); - ActionCondition condition = this.actionService.createActionCondition(NoConditionEvaluator.NAME); - rule.addActionCondition(condition); + Rule rule = new Rule(); + rule.setRuleType(RuleType.INBOUND); Action action = this.actionService.createAction(CopyActionExecuter.NAME, params); - rule.addAction(action); + ActionCondition condition = this.actionService.createActionCondition(NoConditionEvaluator.NAME); + action.addActionCondition(condition); + rule.setAction(action); this.ruleService.saveRule(nodeOne, rule); // Do a deep copy @@ -609,10 +618,8 @@ public class CopyServiceImplTest extends BaseSpringTest assertEquals(1, rules.size()); Rule copiedRule = rules.get(0); assertNotNull(copiedRule); - List ruleActions = copiedRule.getActions(); - assertNotNull(ruleActions); - assertEquals(1, ruleActions.size()); - Action ruleAction = ruleActions.get(0); + Action ruleAction = copiedRule.getAction(); + assertNotNull(ruleAction); NodeRef value = (NodeRef)ruleAction.getParameterValue(MoveActionExecuter.PARAM_DESTINATION_FOLDER); assertNotNull(value); assertEquals(nodeTwoCopy, value); diff --git a/source/java/org/alfresco/repo/rule/BaseRuleTest.java b/source/java/org/alfresco/repo/rule/BaseRuleTest.java index 18c5cb4cd4..ef176ab7fa 100644 --- a/source/java/org/alfresco/repo/rule/BaseRuleTest.java +++ b/source/java/org/alfresco/repo/rule/BaseRuleTest.java @@ -17,6 +17,7 @@ package org.alfresco.repo.rule; import java.io.Serializable; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -163,33 +164,40 @@ public class BaseRuleTest extends BaseSpringTest Map actionProps = new HashMap(); actionProps.put(ACTION_PROP_NAME_1, ACTION_PROP_VALUE_1); - // Create the rule - Rule rule = this.ruleService.createRule(this.ruleType.getName()); - rule.setTitle(TITLE); - rule.setDescription(DESCRIPTION); - rule.applyToChildren(isAppliedToChildren); + List ruleTypes = new ArrayList(1); + ruleTypes.add(this.ruleType.getName()); + + // Create the action + Action action = this.actionService.createAction(CONDITION_DEF_NAME); + action.setParameterValues(conditionProps); ActionCondition actionCondition = this.actionService.createActionCondition(CONDITION_DEF_NAME); actionCondition.setParameterValues(conditionProps); - rule.addActionCondition(actionCondition); + action.addActionCondition(actionCondition); - Action action = this.actionService.createAction(CONDITION_DEF_NAME); - action.setParameterValues(conditionProps); - rule.addAction(action); + // Create the rule + Rule rule = new Rule(); + rule.setRuleTypes(ruleTypes); + rule.setTitle(TITLE); + rule.setDescription(DESCRIPTION); + rule.applyToChildren(isAppliedToChildren); + rule.setAction(action); return rule; } - protected void checkRule(RuleImpl rule, String id) + protected void checkRule(Rule rule) { // Check the basic details of the rule - assertEquals(id, rule.getId()); - assertEquals(this.ruleType.getName(), rule.getRuleTypeName()); + assertEquals(this.ruleType.getName(), rule.getRuleTypes().get(0)); assertEquals(TITLE, rule.getTitle()); assertEquals(DESCRIPTION, rule.getDescription()); + Action ruleAction = rule.getAction(); + assertNotNull(ruleAction); + // Check conditions - List ruleConditions = rule.getActionConditions(); + List ruleConditions = ruleAction.getActionConditions(); assertNotNull(ruleConditions); assertEquals(1, ruleConditions.size()); assertEquals(CONDITION_DEF_NAME, ruleConditions.get(0) @@ -202,11 +210,8 @@ public class BaseRuleTest extends BaseSpringTest assertEquals(COND_PROP_VALUE_1, condParams.get(COND_PROP_NAME_1)); // Check the actions - List ruleActions = rule.getActions(); - assertNotNull(ruleActions); - assertEquals(1, ruleActions.size()); - assertEquals(ACTION_DEF_NAME, ruleActions.get(0).getActionDefinitionName()); - Map actionParams = ruleActions.get(0).getParameterValues(); + assertEquals(ACTION_DEF_NAME, ruleAction.getActionDefinitionName()); + Map actionParams = ruleAction.getParameterValues(); assertNotNull(actionParams); assertEquals(1, actionParams.size()); assertTrue(actionParams.containsKey(ACTION_PROP_NAME_1)); diff --git a/source/java/org/alfresco/repo/rule/RuleImpl.java b/source/java/org/alfresco/repo/rule/RuleImpl.java deleted file mode 100644 index 2bc76da74f..0000000000 --- a/source/java/org/alfresco/repo/rule/RuleImpl.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.rule; - -import java.io.Serializable; - -import org.alfresco.repo.action.CompositeActionImpl; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.rule.Rule; -import org.alfresco.util.ParameterCheck; - -/** - * Rule implementation class. - *

- * Encapsulates all the information about a rule. Can be creted or editied and - * then passed to the rule service to create/update a rule instance. - * - * @author Roy Wetherall - */ -public class RuleImpl extends CompositeActionImpl implements Serializable, Rule -{ - /** - * Serial version UID - */ - private static final long serialVersionUID = 3544385898889097524L; - - /** - * The rule type name - */ - private String ruleTypeName; - - /** - * Indicates whether the rule is applied to all the children of the associated node - * rather than just the node itself. - */ - private boolean isAppliedToChildren = false; - - /** - * Constructor - * - * @param ruleTypeName the rule type name - */ - public RuleImpl(String id, String ruleTypeName, NodeRef owningNodeRef) - { - super(id, owningNodeRef); - ParameterCheck.mandatory("ruleTypeName", ruleTypeName); - - this.ruleTypeName = ruleTypeName; - } - - /** - * @see org.alfresco.service.cmr.rule.Rule#isAppliedToChildren() - */ - public boolean isAppliedToChildren() - { - return this.isAppliedToChildren; - } - - /** - *@see org.alfresco.service.cmr.rule.Rule#applyToChildren(boolean) - */ - public void applyToChildren(boolean isAppliedToChildren) - { - this.isAppliedToChildren = isAppliedToChildren; - } - - /** - * @see org.alfresco.service.cmr.rule.Rule#getRuleTypeName() - */ - public String getRuleTypeName() - { - return this.ruleTypeName; - } -} - diff --git a/source/java/org/alfresco/repo/rule/RuleModel.java b/source/java/org/alfresco/repo/rule/RuleModel.java index 6f2da46721..125efcc03e 100644 --- a/source/java/org/alfresco/repo/rule/RuleModel.java +++ b/source/java/org/alfresco/repo/rule/RuleModel.java @@ -10,12 +10,15 @@ import org.alfresco.service.namespace.QName; public interface RuleModel { /** Rule model constants */ - static final String RULE_MODEL_URI = "http://www.alfresco.org/model/rule/1.0"; - static final String RULE_MODEL_PREFIX = "rule"; - static final QName TYPE_RULE = QName.createQName(RULE_MODEL_URI, "rule"); - static final QName PROP_RULE_TYPE = QName.createQName(RULE_MODEL_URI, "ruleType"); - static final QName TYPE_RULE_CONTENT = QName.createQName(RULE_MODEL_URI, "rulecontent"); - static final QName PROP_APPLY_TO_CHILDREN = QName.createQName(RULE_MODEL_URI, "applyToChildren"); - static final QName ASPECT_RULES = QName.createQName(RULE_MODEL_URI, "rules"); - static final QName ASSOC_RULE_FOLDER = QName.createQName(RULE_MODEL_URI, "ruleFolder"); + static final String RULE_MODEL_URI = "http://www.alfresco.org/model/rule/1.0"; + static final String RULE_MODEL_PREFIX = "rule"; + + static final QName TYPE_RULE = QName.createQName(RULE_MODEL_URI, "rule"); + static final QName PROP_RULE_TYPE = QName.createQName(RULE_MODEL_URI, "ruleType"); + static final QName PROP_APPLY_TO_CHILDREN = QName.createQName(RULE_MODEL_URI, "applyToChildren"); + static final QName PROP_EXECUTE_ASYNC = QName.createQName(RULE_MODEL_URI, "executeAsynchronously"); + static final QName ASSOC_ACTION = QName.createQName(RULE_MODEL_URI, "action"); + + static final QName ASPECT_RULES = QName.createQName(RULE_MODEL_URI, "rules"); + static final QName ASSOC_RULE_FOLDER = QName.createQName(RULE_MODEL_URI, "ruleFolder"); } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java index 4ad3a46a20..6fe7325ab5 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java @@ -81,7 +81,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.util.StopWatch; /** - * @author Roy Wetherall + * @author Roy Wetherall */ public class RuleServiceCoverageTest extends TestCase { @@ -109,6 +109,7 @@ public class RuleServiceCoverageTest extends TestCase private ActionService actionService; private ContentTransformerRegistry transformerRegistry; private CopyService copyService; + private AuthenticationComponent authenticationComponent; /** * Category related values @@ -147,9 +148,10 @@ public class RuleServiceCoverageTest extends TestCase this.actionService = serviceRegistry.getActionService(); this.transactionService = serviceRegistry.getTransactionService(); this.transformerRegistry = (ContentTransformerRegistry)applicationContext.getBean("contentTransformerRegistry"); + this.authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent"); - AuthenticationComponent authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent"); - authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); + //authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); + authenticationComponent.setSystemUserAsCurrentUser(); this.testStoreRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis()); this.rootNodeRef = this.nodeService.getRootNode(this.testStoreRef); @@ -159,11 +161,7 @@ public class RuleServiceCoverageTest extends TestCase this.rootNodeRef, ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN, - ContentModel.TYPE_CONTAINER).getChildRef(); - - // Create and authenticate the user used in the tests - //TestWithUserUtils.createUser(USER_NAME, PWD, this.rootNodeRef, this.nodeService, this.authenticationService); - //TestWithUserUtils.authenticateUser(USER_NAME, PWD, this.rootNodeRef, this.authenticationService); + ContentModel.TYPE_CONTAINER).getChildRef(); } private Rule createRule( @@ -173,11 +171,14 @@ public class RuleServiceCoverageTest extends TestCase String conditionName, Map conditionParams) { - Rule rule = this.ruleService.createRule(ruleTypeName); + Rule rule = new Rule(); + rule.setRuleType(ruleTypeName); + + Action action = this.actionService.createAction(actionName, actionParams); ActionCondition condition = this.actionService.createActionCondition(conditionName, conditionParams); - rule.addActionCondition(condition); - Action action = this.actionService.createAction(actionName, actionParams); - rule.addAction(action); + action.addActionCondition(condition); + rule.setAction(action); + return rule; } @@ -226,8 +227,8 @@ public class RuleServiceCoverageTest extends TestCase /** * Check async rule execution */ - public void testAsyncRuleExecution() - { + public void testAsyncRuleExecution() + { final NodeRef newNodeRef = TransactionUtil.executeInUserTransaction( this.transactionService, new TransactionUtil.TransactionWork() @@ -323,9 +324,9 @@ public class RuleServiceCoverageTest extends TestCase params2.put(ContentModel.PROP_APPROVE_MOVE.toString(), false); // Test that rule can be updated and execute correctly - rule.removeAllActions(); + //rule.removeAllActions(); Action action2 = this.actionService.createAction(AddFeaturesActionExecuter.NAME, params2); - rule.addAction(action2); + rule.setAction(action2); this.ruleService.saveRule(this.nodeRef, rule); NodeRef newNodeRef2 = this.nodeService.createNode( @@ -427,15 +428,15 @@ public class RuleServiceCoverageTest extends TestCase getContentProperties()).getChildRef(); addContentToNode(contentToCopy); - // Create the rule and add to folder Map params = new HashMap(1); - params.put("aspect-name", ContentModel.ASPECT_TEMPLATABLE); + params.put("aspect-name", ContentModel.ASPECT_TEMPLATABLE); + Rule rule = createRule( RuleType.INBOUND, AddFeaturesActionExecuter.NAME, params, NoConditionEvaluator.NAME, - null); + null); rule.applyToChildren(true); this.ruleService.saveRule(copyToFolder, rule); @@ -1232,9 +1233,9 @@ public class RuleServiceCoverageTest extends TestCase // Test begins with Map condParamsBegins = new HashMap(1); condParamsBegins.put(ComparePropertyValueEvaluator.PARAM_VALUE, "bob*"); - rule.removeAllActionConditions(); + rule.getAction().removeAllActionConditions(); ActionCondition condition1 = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME, condParamsBegins); - rule.addActionCondition(condition1); + rule.getAction().addActionCondition(condition1); this.ruleService.saveRule(this.nodeRef, rule); Map propsx = new HashMap(); propsx.put(ContentModel.PROP_NAME, "mybobbins.doc"); @@ -1264,9 +1265,9 @@ public class RuleServiceCoverageTest extends TestCase // Test ends with Map condParamsEnds = new HashMap(1); condParamsEnds.put(ComparePropertyValueEvaluator.PARAM_VALUE, "*s.doc"); - rule.removeAllActionConditions(); + rule.getAction().removeAllActionConditions(); ActionCondition condition2 = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME, condParamsEnds); - rule.addActionCondition(condition2); + rule.getAction().addActionCondition(condition2); this.ruleService.saveRule(this.nodeRef, rule); Map propsa = new HashMap(); propsa.put(ContentModel.PROP_NAME, "bobbins.document"); diff --git a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java index a950e8a62d..8f92e35eb6 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java @@ -18,7 +18,6 @@ package org.alfresco.repo.rule; import java.io.Serializable; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -30,6 +29,7 @@ import org.alfresco.repo.action.ActionModel; import org.alfresco.repo.action.RuntimeActionService; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.TransactionListener; +import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.action.ActionServiceException; import org.alfresco.service.cmr.dictionary.DictionaryService; @@ -41,8 +41,6 @@ import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.cmr.rule.RuleServiceException; import org.alfresco.service.cmr.rule.RuleType; import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.namespace.DynamicNamespacePrefixResolver; -import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.GUID; @@ -125,7 +123,12 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService /** * The rule transaction listener */ - private TransactionListener ruleTransactionListener = new RuleTransactionListener(this); + private TransactionListener ruleTransactionListener = new RuleTransactionListener(this); + + /** + * Indicates whether the rules are disabled for the curren thread + */ + private ThreadLocal rulesDisabled = new ThreadLocal(); /** * Set the permission-safe node service @@ -229,6 +232,30 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService return this.ruleTypes.get(name); } + /** + * @see org.alfresco.service.cmr.rule.RuleService#enableRules() + */ + public void enableRules() + { + this.rulesDisabled.remove(); + } + + /** + * @see org.alfresco.service.cmr.rule.RuleService#disableRules() + */ + public void disableRules() + { + this.rulesDisabled.set(Boolean.TRUE); + } + + /** + * @see org.alfresco.service.cmr.rule.RuleService#isEnabled() + */ + public boolean isEnabled() + { + return (this.rulesDisabled.get() == null); + } + /** * @see org.alfresco.service.cmr.rule.RuleService#rulesEnabled(NodeRef) */ @@ -331,7 +358,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService { // Create the rule and add to the list NodeRef ruleNodeRef = ruleChildAssocRef.getChildRef(); - Rule rule = createRule(nodeRef, ruleNodeRef); + Rule rule = getRule(ruleNodeRef); allRules.add(rule); } @@ -339,7 +366,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService for (Rule rule : allRules) { if ((rules.contains(rule) == false) && - (ruleTypeName == null || ruleTypeName.equals(rule.getRuleTypeName()) == true)) + (ruleTypeName == null || rule.getRuleTypes().contains(ruleTypeName) == true)) { rules.add(rule); } @@ -459,7 +486,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService // Filter the rule list by rule type for (Rule rule : allInheritedRules) { - if (rule.getRuleTypeName().equals(ruleTypeName) == true) + if (rule.getRuleTypes().contains(ruleTypeName) == true) { inheritedRules.add(rule); } @@ -470,75 +497,31 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService return inheritedRules; } - /** - * @see org.alfresco.repo.rule.RuleService#getRule(String) - */ - public Rule getRule(NodeRef nodeRef, String ruleId) - { - Rule rule = null; - - if (this.runtimeNodeService.exists(nodeRef) == true) - { - NodeRef ruleNodeRef = getRuleNodeRefFromId(nodeRef, ruleId); - if (ruleNodeRef != null) - { - rule = createRule(nodeRef, ruleNodeRef); - } - } - - return rule; - } - - /** - * Gets the rule node ref from the action id - * - * @param nodeRef the node reference - * @param actionId the rule id - * @return the rule node reference - */ - private NodeRef getRuleNodeRefFromId(NodeRef nodeRef, String ruleId) - { - NodeRef result = null; - if (this.runtimeNodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true) - { - NodeRef ruleFolder = getSavedRuleFolderRef(nodeRef); - if (ruleFolder != null) - { - DynamicNamespacePrefixResolver namespacePrefixResolver = new DynamicNamespacePrefixResolver(); - namespacePrefixResolver.registerNamespace(NamespaceService.SYSTEM_MODEL_PREFIX, NamespaceService.SYSTEM_MODEL_1_0_URI); - - List nodeRefs = searchService.selectNodes( - ruleFolder, - "*[@sys:" + ContentModel.PROP_NODE_UUID.getLocalName() + "='" + ruleId + "']", - null, - namespacePrefixResolver, - false); - if (nodeRefs.size() != 0) - { - result = nodeRefs.get(0); - } - } - } - - return result; - } - /** * Create the rule object from the rule node reference * * @param ruleNodeRef the rule node reference * @return the rule */ - private Rule createRule(NodeRef owningNodeRef, NodeRef ruleNodeRef) + public Rule getRule(NodeRef ruleNodeRef) { // Get the rule properties Map props = this.runtimeNodeService.getProperties(ruleNodeRef); // Create the rule - String ruleTypeName = (String)props.get(RuleModel.PROP_RULE_TYPE); - Rule rule = new RuleImpl(ruleNodeRef.getId(), ruleTypeName, owningNodeRef); - - // Set the other rule properties + Rule rule = new Rule(ruleNodeRef); + + // Set the owning node ref + //rule.setOwningNodeRef((NodeRef)props.get(RuleModel.PROP_OWNING_NODEREF)); + + // Set the title and description + rule.setTitle((String)props.get(ContentModel.PROP_TITLE)); + rule.setDescription((String)props.get(ContentModel.PROP_DESCRIPTION)); + + // Set the rule types + rule.setRuleTypes((List)props.get(RuleModel.PROP_RULE_TYPE)); + + // Set the applied to children value boolean isAppliedToChildren = false; Boolean value = (Boolean)props.get(RuleModel.PROP_APPLY_TO_CHILDREN); if (value != null) @@ -546,69 +529,125 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService isAppliedToChildren = value.booleanValue(); } rule.applyToChildren(isAppliedToChildren); + + // Set the execute asynchronously value + boolean executeAsync = false; + Boolean value2 = (Boolean)props.get(RuleModel.PROP_EXECUTE_ASYNC); + if (value2 != null) + { + executeAsync = value2.booleanValue(); + } + rule.setExecuteAsynchronously(executeAsync); - // Populate the composite action details - runtimeActionService.populateCompositeAction(ruleNodeRef, rule); + // Get the action node reference + List actions = this.nodeService.getChildAssocs(ruleNodeRef, RuleModel.ASSOC_ACTION, RuleModel.ASSOC_ACTION); + if (actions.size() == 0) + { + throw new RuleServiceException("Rule exists without a specified action"); + } + else if (actions.size() > 1) + { + throw new RuleServiceException("Rule exists with more than one specified action"); + } + NodeRef actionNodeRef = actions.get(0).getChildRef(); + // Here we need to create the action from the action node reference + Action action = runtimeActionService.createAction(actionNodeRef); + rule.setAction(action); + return rule; } - /** - * @see org.alfresco.repo.rule.RuleService#createRule(org.alfresco.repo.rule.RuleType) - */ - public Rule createRule(String ruleTypeName) - { - // Create the new rule, giving it a unique rule id - String id = GUID.generate(); - return new RuleImpl(id, ruleTypeName, null); - } - /** * @see org.alfresco.repo.rule.RuleService#saveRule(org.alfresco.repo.ref.NodeRef, org.alfresco.repo.rule.Rule) */ public void saveRule(NodeRef nodeRef, Rule rule) { - if (this.nodeService.exists(nodeRef) == false) - { - throw new RuleServiceException("The node does not exist."); - } - - NodeRef ruleNodeRef = getRuleNodeRefFromId(nodeRef, rule.getId()); - if (ruleNodeRef == null) - { - if (this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == false) - { - // Add the actionable aspect - this.nodeService.addAspect(nodeRef, RuleModel.ASPECT_RULES, null); - } - - Map props = new HashMap(3); - props.put(RuleModel.PROP_RULE_TYPE, rule.getRuleTypeName()); - props.put(ActionModel.PROP_DEFINITION_NAME, rule.getActionDefinitionName()); - props.put(ContentModel.PROP_NODE_UUID, rule.getId()); - - // Create the action node - ruleNodeRef = this.nodeService.createNode( - getSavedRuleFolderRef(nodeRef), - ContentModel.ASSOC_CONTAINS, - QName.createQName(RuleModel.RULE_MODEL_URI, ASSOC_NAME_RULES_PREFIX + GUID.generate()), - RuleModel.TYPE_RULE, - props).getChildRef(); - - // Update the created details - ((RuleImpl)rule).setCreator((String)this.nodeService.getProperty(ruleNodeRef, ContentModel.PROP_CREATOR)); - ((RuleImpl)rule).setCreatedDate((Date)this.nodeService.getProperty(ruleNodeRef, ContentModel.PROP_CREATED)); - } + disableRules(); + try + { + if (this.nodeService.exists(nodeRef) == false) + { + throw new RuleServiceException("The node does not exist."); + } + + NodeRef ruleNodeRef = rule.getNodeRef(); + if (ruleNodeRef == null) + { + if (this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == false) + { + // Add the actionable aspect + this.nodeService.addAspect(nodeRef, RuleModel.ASPECT_RULES, null); + } + + // Create the action node + ruleNodeRef = this.nodeService.createNode( + getSavedRuleFolderRef(nodeRef), + ContentModel.ASSOC_CONTAINS, + QName.createQName(RuleModel.RULE_MODEL_URI, ASSOC_NAME_RULES_PREFIX + GUID.generate()), + RuleModel.TYPE_RULE).getChildRef(); + + // Set the rule node reference and the owning node reference + rule.setNodeRef(ruleNodeRef); + } + + // Update the properties of the rule + this.nodeService.setProperty(ruleNodeRef, ContentModel.PROP_TITLE, rule.getTitle()); + this.nodeService.setProperty(ruleNodeRef, ContentModel.PROP_DESCRIPTION, rule.getDescription()); + this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_RULE_TYPE, (Serializable)rule.getRuleTypes()); + this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_APPLY_TO_CHILDREN, rule.isAppliedToChildren()); + this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_EXECUTE_ASYNC, rule.getExecuteAsynchronously()); + + // Save the rule's action + saveAction(ruleNodeRef, rule); + } + finally + { + enableRules(); + } + } + + private void saveAction(NodeRef ruleNodeRef, Rule rule) + { + // Get the action definition from the rule + Action action = rule.getAction(); + if (action == null) + { + throw new RuleServiceException("An action must be specified when defining a rule."); + } - // Update the properties of the rule - this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_APPLY_TO_CHILDREN, rule.isAppliedToChildren()); - - // Save the remainder of the rule as a composite action - runtimeActionService.saveActionImpl(nodeRef, ruleNodeRef, rule); + // Get the current action node reference + NodeRef actionNodeRef = null; + List actions = this.nodeService.getChildAssocs(ruleNodeRef, RuleModel.ASSOC_ACTION, RuleModel.ASSOC_ACTION); + if (actions.size() == 1) + { + // We need to check that the action is the same + actionNodeRef = actions.get(0).getChildRef(); + if (actionNodeRef.getId().equals(action.getId()) == false) + { + // Delete the old action + this.nodeService.deleteNode(actionNodeRef); + actionNodeRef = null; + } + } + else if (actions.size() > 1) + { + throw new RuleServiceException("The rule has become corrupt. More than one action is associated with the rule."); + } + + // Create the new action node reference + if (actionNodeRef == null) + { + actionNodeRef = this.runtimeActionService.createActionNodeRef(action, ruleNodeRef, RuleModel.ASSOC_ACTION, RuleModel.ASSOC_ACTION); + } + + // Update the action node + this.runtimeActionService.saveActionImpl(actionNodeRef, action); + } /** - * @see org.alfresco.repo.rule.RuleService#removeRule(org.alfresco.repo.ref.NodeRef, org.alfresco.repo.rule.RuleImpl) + * @see org.alfresco.repo.rule.RuleService#removeRule(org.alfresco.repo.ref.NodeRef, org.alfresco.service.cmr.rule.Rule) */ public void removeRule(NodeRef nodeRef, Rule rule) { @@ -618,7 +657,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService disableRules(nodeRef); try { - NodeRef ruleNodeRef = getRuleNodeRefFromId(nodeRef, rule.getId()); + NodeRef ruleNodeRef = rule.getNodeRef(); if (ruleNodeRef != null) { this.nodeService.removeChild(getSavedRuleFolderRef(nodeRef), ruleNodeRef); @@ -669,7 +708,8 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService public void addRulePendingExecution(NodeRef actionableNodeRef, NodeRef actionedUponNodeRef, Rule rule, boolean executeAtEnd) { // First check to see if the node has been disabled - if (this.disabledNodeRefs.contains(rule.getOwningNodeRef()) == false && + if (this.rulesDisabled.get() == null && + this.disabledNodeRefs.contains(this.getOwningNodeRef(rule)) == false && this.disabledRules.contains(rule) == false) { PendingRuleData pendingRuleData = new PendingRuleData(actionableNodeRef, actionedUponNodeRef, rule, executeAtEnd); @@ -697,7 +737,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService { if (logger.isDebugEnabled() == true) { - logger.debug("The rule '" + rule.getTitle() + "' or the node '" + rule.getOwningNodeRef().getId() + "' has been disabled."); + logger.debug("The rule '" + rule.getTitle() + "' or the node '" + this.getOwningNodeRef(rule).getId() + "' has been disabled."); } } } @@ -717,22 +757,12 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService { AlfrescoTransactionSupport.bindResource(KEY_RULES_EXECUTED, new HashSet()); } - try + + List executeAtEndRules = new ArrayList(); + executePendingRulesImpl(executeAtEndRules); + for (PendingRuleData data : executeAtEndRules) { - List executeAtEndRules = new ArrayList(); - executePendingRulesImpl(executeAtEndRules); - for (PendingRuleData data : executeAtEndRules) - { - executePendingRule(data); - } - } - finally - { - //AlfrescoTransactionSupport.unbindResource(KEY_RULES_EXECUTED); - //if (logger.isDebugEnabled() == true) - //{ - // logger.debug("Unbinding resource"); - // } + executePendingRule(data); } } @@ -785,8 +815,14 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService if (executedRules == null || canExecuteRule(executedRules, actionedUponNodeRef, rule) == true) { + Action action = rule.getAction(); + if (action == null) + { + throw new RuleServiceException("Attempting to execute a rule that does not have a rule specified."); + } + // Evaluate the condition - if (this.actionService.evaluateAction(rule, actionedUponNodeRef) == true) + if (this.actionService.evaluateAction(action, actionedUponNodeRef) == true) { // Add the rule to the executed rule list // (do this before this is executed to prevent rules being added to the pending list) @@ -797,7 +833,8 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService } // Execute the rule - this.actionService.executeAction(rule, actionedUponNodeRef); + boolean executeAsync = rule.getExecuteAsynchronously(); + this.actionService.executeAction(action, actionedUponNodeRef, true, executeAsync); } } } @@ -1014,4 +1051,70 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService } } } + + /** + * @see org.alfresco.service.cmr.rule.RuleService#getOwningNodeRef(org.alfresco.service.cmr.rule.Rule) + */ + public NodeRef getOwningNodeRef(Rule rule) + { + NodeRef result = null; + + NodeRef ruleNodeRef = rule.getNodeRef(); + if (ruleNodeRef != null) + { + result = getOwningNodeRefRuleImpl(ruleNodeRef); + } + + return result; + } + + /** + * @param ruleNodeRef + * @return + */ + private NodeRef getOwningNodeRefRuleImpl(NodeRef ruleNodeRef) + { + // Get the system folder parent + NodeRef systemFolder = this.nodeService.getPrimaryParent(ruleNodeRef).getParentRef(); + + // Get the owning node ref + return this.nodeService.getPrimaryParent(systemFolder).getParentRef(); + } + + /** + * @see org.alfresco.service.cmr.rule.RuleService#getOwningNodeRef(org.alfresco.service.cmr.action.Action) + */ + public NodeRef getOwningNodeRef(Action action) + { + NodeRef result = null; + NodeRef actionNodeRef = action.getNodeRef(); + if (actionNodeRef != null) + { + result = getOwningNodeRefActionImpl(actionNodeRef); + } + + return result; + } + + /** + * @param actionNodeRef + */ + private NodeRef getOwningNodeRefActionImpl(NodeRef actionNodeRef) + { + NodeRef result = null; + NodeRef parentNodeRef = this.nodeService.getPrimaryParent(actionNodeRef).getParentRef(); + if (parentNodeRef != null) + { + QName parentType = this.nodeService.getType(parentNodeRef); + if (RuleModel.TYPE_RULE.equals(parentType) == true) + { + result = getOwningNodeRefRuleImpl(parentNodeRef); + } + else if (ActionModel.TYPE_COMPOSITE_ACTION.equals(parentType) == true) + { + result = getOwningNodeRefActionImpl(parentNodeRef); + } + } + return result; + } } diff --git a/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java b/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java index f3216b9d8c..10e8134e00 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java @@ -60,17 +60,6 @@ public class RuleServiceImplTest extends BaseRuleTest } } - /** - * Test createRule - */ - public void testCreateRule() - { - Rule newRule = this.ruleService.createRule("ruleType1"); - assertNotNull(newRule); - assertNotNull(newRule.getId()); - assertEquals("ruleType1", newRule.getRuleTypeName()); - } - /** * Test addRule * @@ -78,17 +67,21 @@ public class RuleServiceImplTest extends BaseRuleTest public void testAddRule() { Rule newRule = createTestRule(); - String ruleId = newRule.getId(); - this.ruleService.saveRule(this.nodeRef, newRule); + this.ruleService.saveRule(this.nodeRef, newRule); + assertNotNull(newRule.getNodeRef()); - Rule savedRule = this.ruleService.getRule(this.nodeRef, ruleId); + // Check the owning node reference + assertNotNull(this.ruleService.getOwningNodeRef(newRule)); + assertEquals(this.nodeRef, this.ruleService.getOwningNodeRef(newRule)); + + Rule savedRule = this.ruleService.getRule(newRule.getNodeRef()); assertNotNull(savedRule); assertFalse(savedRule.isAppliedToChildren()); savedRule.applyToChildren(true); this.ruleService.saveRule(this.nodeRef, savedRule); - Rule savedRule2 = this.ruleService.getRule(this.nodeRef, ruleId); + Rule savedRule2 = this.ruleService.getRule(savedRule.getNodeRef()); assertNotNull(savedRule2); assertTrue(savedRule2.isAppliedToChildren()); } @@ -100,9 +93,9 @@ public class RuleServiceImplTest extends BaseRuleTest assertNotNull(rules1); assertEquals(0, rules1.size()); - Rule newRule = this.ruleService.createRule(ruleType.getName()); + Rule newRule = createTestRule(); //this.ruleService.createRule(ruleType.getName()); this.ruleService.saveRule(this.nodeRef, newRule); - Rule newRule2 = this.ruleService.createRule(ruleType.getName()); + Rule newRule2 = createTestRule(); //this.ruleService.createRule(ruleType.getName()); this.ruleService.saveRule(this.nodeRef, newRule2); List rules2 = this.ruleService.getRules(this.nodeRef); @@ -113,8 +106,7 @@ public class RuleServiceImplTest extends BaseRuleTest List rules3 = this.ruleService.getRules(this.nodeRef); assertNotNull(rules3); - assertEquals(0, rules3.size()); - + assertEquals(0, rules3.size()); } /** @@ -145,16 +137,15 @@ public class RuleServiceImplTest extends BaseRuleTest Rule rule = rules.get(0); assertEquals("title", rule.getTitle()); assertEquals("description", rule.getDescription()); - assertNotNull(rule.getCreatedDate()); - assertNotNull(rule.getModifiedDate()); + assertNotNull(this.nodeService.getProperty(rule.getNodeRef(), ContentModel.PROP_CREATED)); + assertNotNull(this.nodeService.getProperty(rule.getNodeRef(), ContentModel.PROP_CREATOR)); // Check that the condition action have been retireved correctly - List conditions = rule.getActionConditions(); + Action action = rule.getAction(); + assertNotNull(action); + List conditions = action.getActionConditions(); assertNotNull(conditions); - assertEquals(1, conditions.size()); - List actions = rule.getActions(); - assertNotNull(actions); - assertEquals(1, actions.size()); + assertEquals(1, conditions.size()); } /** @@ -232,7 +223,9 @@ public class RuleServiceImplTest extends BaseRuleTest int count = 0; for (Rule rule : allRules) { - if (rule.getOwningNodeRef() == childWithRules) + NodeRef owningNodeRef = this.ruleService.getOwningNodeRef(rule); + assertNotNull(owningNodeRef); + if (owningNodeRef.equals(childWithRules) == true) { count++; } @@ -547,17 +540,19 @@ public class RuleServiceImplTest extends BaseRuleTest actionProps.put(ImageTransformActionExecuter.PARAM_ASSOC_TYPE_QNAME, ContentModel.ASSOC_CHILDREN); actionProps.put(ImageTransformActionExecuter.PARAM_ASSOC_QNAME, ContentModel.ASSOC_CHILDREN); - Rule rule = this.ruleService.createRule(this.ruleType.getName()); + Rule rule = new Rule(); + rule.setRuleType(this.ruleType.getName()); rule.setTitle("Convert from *.jpg to *.gif"); rule.setExecuteAsynchronously(true); - ActionCondition actionCondition = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); - actionCondition.setParameterValues(conditionProps); - rule.addActionCondition(actionCondition); - Action action = this.actionService.createAction(ImageTransformActionExecuter.NAME); action.setParameterValues(actionProps); - rule.addAction(action); + + ActionCondition actionCondition = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); + actionCondition.setParameterValues(conditionProps); + action.addActionCondition(actionCondition); + + rule.setAction(action); // Create the next rule @@ -569,17 +564,19 @@ public class RuleServiceImplTest extends BaseRuleTest actionProps2.put(ImageTransformActionExecuter.PARAM_DESTINATION_FOLDER, nodeRef); actionProps2.put(ImageTransformActionExecuter.PARAM_ASSOC_QNAME, ContentModel.ASSOC_CHILDREN); - Rule rule2 = this.ruleService.createRule(this.ruleType.getName()); + Rule rule2 = new Rule(); + rule2.setRuleType(this.ruleType.getName()); rule2.setTitle("Convert from *.gif to *.jpg"); rule2.setExecuteAsynchronously(true); - ActionCondition actionCondition2 = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); - actionCondition2.setParameterValues(conditionProps2); - rule2.addActionCondition(actionCondition2); - Action action2 = this.actionService.createAction(ImageTransformActionExecuter.NAME); action2.setParameterValues(actionProps2); - rule2.addAction(action2); + + ActionCondition actionCondition2 = this.actionService.createActionCondition(ComparePropertyValueEvaluator.NAME); + actionCondition2.setParameterValues(conditionProps2); + action2.addActionCondition(actionCondition2); + + rule2.setAction(action2); // Save the rules this.ruleService.saveRule(nodeRef, rule); diff --git a/source/java/org/alfresco/repo/rule/RuleTypeImpl.java b/source/java/org/alfresco/repo/rule/RuleTypeImpl.java index 9980872562..015a6fbd4d 100644 --- a/source/java/org/alfresco/repo/rule/RuleTypeImpl.java +++ b/source/java/org/alfresco/repo/rule/RuleTypeImpl.java @@ -41,11 +41,6 @@ public class RuleTypeImpl extends CommonResourceAbstractBase implements RuleType */ private static Log logger = LogFactory.getLog(RuleTypeImpl.class); - /** - * The action service - */ - private ActionService actionService; - /** * The rule service */ @@ -67,16 +62,6 @@ public class RuleTypeImpl extends CommonResourceAbstractBase implements RuleType } } - /** - * Set the action service - * - * @param actionService the action service - */ - public void setActionService(ActionService actionService) - { - this.actionService = actionService; - } - /** * Set the rule service * @@ -116,29 +101,36 @@ public class RuleTypeImpl extends CommonResourceAbstractBase implements RuleType */ public void triggerRuleType(NodeRef nodeRef, NodeRef actionedUponNodeRef) { - if (this.ruleService.hasRules(nodeRef) == true) + if (this.ruleService.isEnabled() == true) { - List rules = this.ruleService.getRules( - nodeRef, - true, - this.name); - - for (Rule rule : rules) - { + if (this.ruleService.hasRules(nodeRef) == true) + { + List rules = this.ruleService.getRules( + nodeRef, + true, + this.name); + + for (Rule rule : rules) + { + if (logger.isDebugEnabled() == true) + { + NodeRef ruleNodeRef = rule.getNodeRef(); + if (nodeRef != null) + { + logger.debug("Triggering rule " + ruleNodeRef.toString()); + } + } + + // Queue the rule to be executed at the end of the transaction (but still in the transaction) + ((RuntimeRuleService)this.ruleService).addRulePendingExecution(nodeRef, actionedUponNodeRef, rule); + } + } + else + { if (logger.isDebugEnabled() == true) { - logger.debug("Triggering rule " + rule.getId()); + logger.debug("This node has no rules to trigger."); } - - // Queue the rule to be executed at the end of the transaction (but still in the transaction) - ((RuntimeRuleService)this.ruleService).addRulePendingExecution(nodeRef, actionedUponNodeRef, rule); - } - } - else - { - if (logger.isDebugEnabled() == true) - { - logger.debug("This node has no rules to trigger."); } } } diff --git a/source/java/org/alfresco/repo/rule/ruleModel.xml b/source/java/org/alfresco/repo/rule/ruleModel.xml index 053472cdaf..cd64387663 100644 --- a/source/java/org/alfresco/repo/rule/ruleModel.xml +++ b/source/java/org/alfresco/repo/rule/ruleModel.xml @@ -9,6 +9,7 @@ + @@ -20,17 +21,35 @@ Rule - act:compositeaction - + sys:base + d:text true + true d:boolean true - + + d:boolean + true + + + + + + act:action + true + false + + + + + cm:titled + cm:auditable + diff --git a/source/java/org/alfresco/service/cmr/action/Action.java b/source/java/org/alfresco/service/cmr/action/Action.java index d926a86bca..cca64b0ee4 100644 --- a/source/java/org/alfresco/service/cmr/action/Action.java +++ b/source/java/org/alfresco/service/cmr/action/Action.java @@ -29,6 +29,14 @@ import org.alfresco.service.cmr.repository.NodeRef; */ public interface Action extends ParameterizedItem { + /** + * Gets the node ref that represents the saved action node. + * Returns null id unsaved. + * + * @return the action node reference + */ + NodeRef getNodeRef(); + /** * Get the name of the action definition that relates to this action * @@ -63,16 +71,6 @@ public interface Action extends ParameterizedItem * @param description the description of the action */ void setDescription(String description); - - /** - * Get the node reference of the node that 'owns' this action. - *

- * The node that 'owns' the action is th one that stores it via its - * actionable aspect association. - * - * @return node reference - */ - NodeRef getOwningNodeRef(); /** * Gets a value indicating whether the action should be executed asychronously or not. diff --git a/source/java/org/alfresco/service/cmr/rule/Rule.java b/source/java/org/alfresco/service/cmr/rule/Rule.java index f358856fa4..9ae30414a2 100644 --- a/source/java/org/alfresco/service/cmr/rule/Rule.java +++ b/source/java/org/alfresco/service/cmr/rule/Rule.java @@ -14,43 +14,186 @@ * language governing permissions and limitations under the * License. */ - package org.alfresco.service.cmr.rule; -import org.alfresco.service.cmr.action.CompositeAction; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import org.alfresco.service.cmr.action.Action; +import org.alfresco.service.cmr.repository.NodeRef; /** - * Rule Interface + * Rule class. + *

+ * Encapsulates all the information about a rule. Can be creted or editied and + * then passed to the rule service to create/update a rule instance. * * @author Roy Wetherall */ -public interface Rule extends CompositeAction +public class Rule implements Serializable { - /** - * Indicates that the rule is applied to the children of the associated - * node, not just the node itself. - *

- * By default this will be set to false. - * - * @return true if the rule is applied to the children of the associated node, - * false otherwise - */ - boolean isAppliedToChildren(); - - /** - * Set whether the rule is applied to all children of the associated node - * rather than just the node itself. - * - * @param isAppliedToChildren true if the rule should be applied to the children, false - * otherwise - */ - void applyToChildren(boolean isAppliedToChildren); + /** + * Serial version UID + */ + private static final long serialVersionUID = 3544385898889097524L; /** - * Get the rule type name - * - * @return the rule type name + * The rule node reference */ - String getRuleTypeName(); - } \ No newline at end of file + private NodeRef nodeRef; + + /** + * The title of the rule + */ + private String title; + + /** + * The description of the rule + */ + private String description; + + /** + * The rule types + */ + private List ruleTypes; + + /** + * The associated action + */ + private Action action; + + /** + * Indicates whether the rule should execute the action asynchronously or not + */ + private boolean executeAsynchronously = false; + + /** + * Indicates whether the rule is applied to all the children of the associated node + * rather than just the node itself. + */ + private boolean isAppliedToChildren = false; + + public Rule() + { + } + + public Rule(NodeRef nodeRef) + { + this.nodeRef = nodeRef; + } + + public void setAction(Action action) + { + this.action = action; + } + + public Action getAction() + { + return action; + } + + public void setNodeRef(NodeRef nodeRef) + { + this.nodeRef = nodeRef; + } + + public NodeRef getNodeRef() + { + return nodeRef; + } + + public void setTitle(String title) + { + this.title = title; + } + + public String getTitle() + { + return title; + } + + public void setDescription(String description) + { + this.description = description; + } + + public String getDescription() + { + return description; + } + + /** + * @see org.alfresco.service.cmr.rule.Rule#isAppliedToChildren() + */ + public boolean isAppliedToChildren() + { + return this.isAppliedToChildren; + } + + /** + *@see org.alfresco.service.cmr.rule.Rule#applyToChildren(boolean) + */ + public void applyToChildren(boolean isAppliedToChildren) + { + this.isAppliedToChildren = isAppliedToChildren; + } + + public void setRuleType(String ruleType) + { + List ruleTypes = new ArrayList(1); + ruleTypes.add(ruleType); + this.ruleTypes = ruleTypes; + } + + public void setRuleTypes(List ruleTypes) + { + this.ruleTypes = ruleTypes; + } + + public List getRuleTypes() + { + return ruleTypes; + } + + public void setExecuteAsynchronously(boolean executeAsynchronously) + { + this.executeAsynchronously = executeAsynchronously; + } + + public boolean getExecuteAsynchronously() + { + return this.executeAsynchronously; + } + + /** + * Hash code implementation + */ + @Override + public int hashCode() + { + return this.nodeRef.hashCode(); + } + + /** + * Equals implementation + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (obj instanceof Rule) + { + Rule that = (Rule) obj; + return (this.nodeRef.equals(that.nodeRef)); + } + else + { + return false; + } + } +} + diff --git a/source/java/org/alfresco/service/cmr/rule/RuleService.java b/source/java/org/alfresco/service/cmr/rule/RuleService.java index 6117440b98..f14c871ee0 100644 --- a/source/java/org/alfresco/service/cmr/rule/RuleService.java +++ b/source/java/org/alfresco/service/cmr/rule/RuleService.java @@ -19,6 +19,7 @@ package org.alfresco.service.cmr.rule; import java.util.List; import org.alfresco.service.Auditable; +import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.repository.NodeRef; /** @@ -45,6 +46,26 @@ public interface RuleService @Auditable(parameters = {"name"}) public RuleType getRuleType(String name); + /** + * Enable rules for the current thread + */ + @Auditable + public void enableRules(); + + /** + * Diable rules for the current thread + */ + @Auditable + public void disableRules(); + + /** + * Indicates whether rules are currently enabled or not + * + * @return true if rules are enabled, false otherwise + */ + @Auditable + public boolean isEnabled(); + /** * Indicates wether the rules for a given node are enabled or not. If the * rules are not enabled then they will not be executed. @@ -150,26 +171,13 @@ public interface RuleService public int countRules(NodeRef nodeRef); /** - * Get the rule given its id. + * Get the rule given its node reference * * @param nodeRef the node reference - * @param ruleId the rule id - * @return the rule corresponding ot the id + * @return the rule corresponding to the node reference */ - @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef", "ruleId"}) - public Rule getRule(NodeRef nodeRef, String ruleId); - - /** - * Helper method to create a new rule. - *

- * Call add rule once the details of the rule have been specified in order - * to associate the rule with a node reference. - * - * @param ruleTypeName the name of the rule type - * @return the created rule - */ - @Auditable(parameters = {"ruleTypeName"}) - public Rule createRule(String ruleTypeName); + @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"}) + public Rule getRule(NodeRef nodeRef); /** * Saves the details of the rule to the specified node reference. @@ -198,4 +206,25 @@ public interface RuleService */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"}) public void removeAllRules(NodeRef nodeRef); + + /** + * Returns the owning node reference for a rule. + * + * @param rule the rule + * @return the owning node reference + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = {"rule"}) + public NodeRef getOwningNodeRef(Rule rule); + + /** + * Returns the owning node reference for an action. Returns null for an unsaved action or one that is not + * parented by a rule. + * + * NOTE: this method is temporary and will be removed in future versions. It should only be used with good reason. + * + * @param action the action + * @return the owning node reference + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = {"action"}) + public NodeRef getOwningNodeRef(Action action); }