diff --git a/config/alfresco/rule-services-context.xml b/config/alfresco/rule-services-context.xml
index fe4077c3ae..79955d57a9 100644
--- a/config/alfresco/rule-services-context.xml
+++ b/config/alfresco/rule-services-context.xml
@@ -18,12 +18,12 @@
-
-
-
+
+ false
+
@@ -81,6 +81,7 @@
+
@@ -131,7 +132,19 @@
- onDeleteChildAssociation
+ beforeDeleteChildAssociation
+
+
+ true
+
+
+
+
+
+ beforeDeleteNode
+
+
+ true
diff --git a/source/java/org/alfresco/repo/action/ActionServiceImplTest.java b/source/java/org/alfresco/repo/action/ActionServiceImplTest.java
index 1d57a7eeba..fda3864dc0 100644
--- a/source/java/org/alfresco/repo/action/ActionServiceImplTest.java
+++ b/source/java/org/alfresco/repo/action/ActionServiceImplTest.java
@@ -330,7 +330,6 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
// Edit the properties of the action
Map properties = new HashMap(1);
properties.put(ContentModel.PROP_NAME, "testName");
- action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_PROPERTIES, (Serializable)properties);
action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_AUDITABLE);
// Set the compensating action
@@ -342,12 +341,8 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
Action savedAction2 = this.actionService.getAction(this.nodeRef, actionId);
// Check the updated properties
- assertEquals(2, savedAction2.getParameterValues().size());
+ assertEquals(1, savedAction2.getParameterValues().size());
assertEquals(ContentModel.ASPECT_AUDITABLE, savedAction2.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME));
- Map temp = (Map)savedAction2.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_PROPERTIES);
- assertNotNull(temp);
- assertEquals(1, temp.size());
- assertEquals("testName", temp.get(ContentModel.PROP_NAME));
// Check the compensating action
Action savedCompensatingAction = savedAction2.getCompensatingAction();
@@ -393,14 +388,8 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
// Save the action
this.actionService.saveAction(this.nodeRef, action);
- // Check the owning node ref
- //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());;
+ this.actionService.getAction(this.nodeRef, actionId);
}
/**
@@ -414,9 +403,6 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
// Set the parameters of the action
action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME, ContentModel.ASPECT_VERSIONABLE);
- Map properties = new HashMap(1);
- properties.put(ContentModel.PROP_NAME, "testName");
- action.setParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_PROPERTIES, (Serializable)properties);
// Set the conditions of the action
ActionCondition actionCondition = this.actionService.createActionCondition(NoConditionEvaluator.NAME);
@@ -439,10 +425,6 @@ public class ActionServiceImplTest extends BaseAlfrescoSpringTest
// Check the properties
assertEquals(action.getParameterValues().size(), savedAction.getParameterValues().size());
assertEquals(ContentModel.ASPECT_VERSIONABLE, savedAction.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_NAME));
- Map temp = (Map)savedAction.getParameterValue(AddFeaturesActionExecuter.PARAM_ASPECT_PROPERTIES);
- assertNotNull(temp);
- assertEquals(1, temp.size());
- assertEquals("testName", temp.get(ContentModel.PROP_NAME));
// Check the conditions
assertNotNull(savedAction.getActionConditions());
diff --git a/source/java/org/alfresco/repo/action/executer/AddFeaturesActionExecuter.java b/source/java/org/alfresco/repo/action/executer/AddFeaturesActionExecuter.java
index 13a8368083..73c6976f9c 100644
--- a/source/java/org/alfresco/repo/action/executer/AddFeaturesActionExecuter.java
+++ b/source/java/org/alfresco/repo/action/executer/AddFeaturesActionExecuter.java
@@ -41,7 +41,6 @@ public class AddFeaturesActionExecuter extends ActionExecuterAbstractBase
*/
public static final String NAME = "add-features";
public static final String PARAM_ASPECT_NAME = "aspect-name";
- public static final String PARAM_ASPECT_PROPERTIES = "aspect_properties";
/**
* The node service
diff --git a/source/java/org/alfresco/repo/rule/BaseRuleTest.java b/source/java/org/alfresco/repo/rule/BaseRuleTest.java
index ef176ab7fa..332f0495dd 100644
--- a/source/java/org/alfresco/repo/rule/BaseRuleTest.java
+++ b/source/java/org/alfresco/repo/rule/BaseRuleTest.java
@@ -156,6 +156,11 @@ public class BaseRuleTest extends BaseSpringTest
}
protected Rule createTestRule(boolean isAppliedToChildren)
+ {
+ return createTestRule(isAppliedToChildren, TITLE);
+ }
+
+ protected Rule createTestRule(boolean isAppliedToChildren, String title)
{
// Rule properties
Map conditionProps = new HashMap();
@@ -178,7 +183,7 @@ public class BaseRuleTest extends BaseSpringTest
// Create the rule
Rule rule = new Rule();
rule.setRuleTypes(ruleTypes);
- rule.setTitle(TITLE);
+ rule.setTitle(title);
rule.setDescription(DESCRIPTION);
rule.applyToChildren(isAppliedToChildren);
rule.setAction(action);
diff --git a/source/java/org/alfresco/repo/rule/RuleModel.java b/source/java/org/alfresco/repo/rule/RuleModel.java
index 125efcc03e..bb0d318cfd 100644
--- a/source/java/org/alfresco/repo/rule/RuleModel.java
+++ b/source/java/org/alfresco/repo/rule/RuleModel.java
@@ -18,7 +18,10 @@ public interface RuleModel
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 PROP_DISABLED = QName.createQName(RULE_MODEL_URI, "disabled");
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 QName ASPECT_IGNORE_INHERITED_RULES = QName.createQName(RULE_MODEL_URI, "ignoreInheritedRules");
}
\ 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 6fe7325ab5..c00ed1e840 100644
--- a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java
+++ b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java
@@ -85,9 +85,7 @@ import org.springframework.util.StopWatch;
*/
public class RuleServiceCoverageTest extends TestCase
{
- //private static final ContentData CONTENT_DATA_TEXT = new ContentData(null, MimetypeMap.MIMETYPE_TEXT_PLAIN, 0L, "UTF-8");
-
- /**
+ /**
* Application context used during the test
*/
static ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:alfresco/application-context.xml");
@@ -343,6 +341,46 @@ public class RuleServiceCoverageTest extends TestCase
// System.out.println(NodeStoreInspector.dumpNodeStore(this.nodeService, this.testStoreRef));
}
+ public void testDisableIndividualRules()
+ {
+ Map params = new HashMap(1);
+ params.put("aspect-name", ContentModel.ASPECT_CONFIGURABLE);
+
+ Rule rule = createRule(
+ RuleType.INBOUND,
+ AddFeaturesActionExecuter.NAME,
+ params,
+ NoConditionEvaluator.NAME,
+ null);
+ rule.setRuleDisabled(true);
+
+ this.ruleService.saveRule(this.nodeRef, rule);
+
+ NodeRef newNodeRef = this.nodeService.createNode(
+ this.nodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName(TEST_NAMESPACE, "children"),
+ ContentModel.TYPE_CONTENT,
+ getContentProperties()).getChildRef();
+ addContentToNode(newNodeRef);
+ assertFalse(this.nodeService.hasAspect(newNodeRef, ContentModel.ASPECT_CONFIGURABLE));
+
+ Rule rule2 = this.ruleService.getRule(rule.getNodeRef());
+ rule2.setRuleDisabled(false);
+ this.ruleService.saveRule(this.nodeRef, rule2);
+
+ // Re-try the test now the rule has been re-enabled
+ NodeRef newNodeRef2 = this.nodeService.createNode(
+ this.nodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName(TEST_NAMESPACE, "children"),
+ ContentModel.TYPE_CONTENT,
+ getContentProperties()).getChildRef();
+ addContentToNode(newNodeRef2);
+ assertTrue(this.nodeService.hasAspect(newNodeRef2, ContentModel.ASPECT_CONFIGURABLE));
+
+ }
+
public void testDisableRule()
{
this.nodeService.addAspect(this.nodeRef, ContentModel.ASPECT_LOCKABLE, null);
@@ -1597,36 +1635,8 @@ public class RuleServiceCoverageTest extends TestCase
tx.commit();
- Thread.sleep(10000);
- //System.out.println(NodeStoreInspector.dumpNodeStore(this.nodeService, this.testStoreRef));
-
- //AuthenticationComponent authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent");
- //authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
-
- // Check that the created node is still there
- //List origRefs = this.nodeService.getChildAssocs(
- // this.nodeRef,
- // RegexQNamePattern.MATCH_ALL, QName.createQName(TEST_NAMESPACE, "origional"));
- //assertNotNull(origRefs);
- //assertEquals(1, origRefs.size());
- //NodeRef origNodeRef = origRefs.get(0).getChildRef();
- //assertEquals(newNodeRef, origNodeRef);
-
- // Check that the created node has been copied
- //List copyChildAssocRefs = this.nodeService.getChildAssocs(
- // this.rootNodeRef,
- // RegexQNamePattern.MATCH_ALL, QName.createQName(TEST_NAMESPACE, "transformed"));
- //assertNotNull(copyChildAssocRefs);
- //assertEquals(1, copyChildAssocRefs.size());
- //NodeRef copyNodeRef = copyChildAssocRefs.get(0).getChildRef();
- //assertTrue(this.nodeService.hasAspect(copyNodeRef, ContentModel.ASPECT_COPIEDFROM));
- //NodeRef source = (NodeRef)this.nodeService.getProperty(copyNodeRef, ContentModel.PROP_COPY_REFERENCE);
- //assertEquals(newNodeRef, source);
-
- // Check the transformed content
- //ContentData contentData = (ContentData) nodeService.getProperty(copyNodeRef, ContentModel.PROP_CONTENT);
- //assertEquals(MimetypeMap.MIMETYPE_TEXT_PLAIN, contentData.getMimetype());
-
+ // Sleep to ensure work is done b4 execution is canceled
+ Thread.sleep(10000);
}
catch (Exception exception)
{
diff --git a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java
index 8f92e35eb6..2cb314b3f0 100644
--- a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java
+++ b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java
@@ -40,7 +40,6 @@ import org.alfresco.service.cmr.rule.Rule;
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.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.GUID;
@@ -88,11 +87,6 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
*/
private ActionService actionService;
- /**
- * The search service
- */
- private SearchService searchService;
-
/**
* The dictionary service
*/
@@ -126,10 +120,15 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
private TransactionListener ruleTransactionListener = new RuleTransactionListener(this);
/**
- * Indicates whether the rules are disabled for the curren thread
+ * Indicates whether the rules are disabled for the current thread
*/
private ThreadLocal rulesDisabled = new ThreadLocal();
+ /**
+ * Global flag that indicates whether the
+ */
+ private boolean globalRulesDisabled = false;
+
/**
* Set the permission-safe node service
*
@@ -170,16 +169,6 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
this.runtimeActionService = runtimeActionService;
}
- /**
- * Set the search service
- *
- * @param searchService the search service
- */
- public void setSearchService(SearchService searchService)
- {
- this.searchService = searchService;
- }
-
/**
* Set the dictionary service
*
@@ -189,6 +178,16 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
{
this.dictionaryService = dictionaryService;
}
+
+ /**
+ * Set the global rules disabled flag
+ *
+ * @param rulesDisabled true to disable allr ules, false otherwise
+ */
+ public void setRulesDisabled(boolean rulesDisabled)
+ {
+ this.globalRulesDisabled = rulesDisabled;
+ }
/**
* Gets the saved rule folder reference
@@ -253,7 +252,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
*/
public boolean isEnabled()
{
- return (this.rulesDisabled.get() == null);
+ return (this.globalRulesDisabled == false && this.rulesDisabled.get() == null);
}
/**
@@ -331,7 +330,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
if (this.runtimeNodeService.exists(nodeRef) == true && checkNodeType(nodeRef) == true)
{
- if (includeInherited == true)
+ if (includeInherited == true && this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_IGNORE_INHERITED_RULES) == false)
{
// Get any inherited rules
for (Rule rule : getInheritedRules(nodeRef, ruleTypeName, null))
@@ -441,58 +440,62 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
private List getInheritedRules(NodeRef nodeRef, String ruleTypeName, Set visitedNodeRefs)
{
List inheritedRules = new ArrayList();
-
- // Create the visited nodes set if it has not already been created
- if (visitedNodeRefs == null)
- {
- visitedNodeRefs = new HashSet();
- }
-
- // This check prevents stack over flow when we have a cyclic node graph
- if (visitedNodeRefs.contains(nodeRef) == false)
- {
- visitedNodeRefs.add(nodeRef);
-
- List allInheritedRules = new ArrayList();
- List parents = this.runtimeNodeService.getParentAssocs(nodeRef);
- for (ChildAssociationRef parent : parents)
- {
- List rules = getRules(parent.getParentRef(), false);
- for (Rule rule : rules)
- {
- // Add is we hanvn't already added and it should be applied to the children
- if (rule.isAppliedToChildren() == true && allInheritedRules.contains(rule) == false)
- {
- allInheritedRules.add(rule);
- }
- }
-
- for (Rule rule : getInheritedRules(parent.getParentRef(), ruleTypeName, visitedNodeRefs))
- {
- // Ensure that we don't get any rule duplication (don't use a set cos we want to preserve order)
- if (allInheritedRules.contains(rule) == false)
- {
- allInheritedRules.add(rule);
- }
- }
- }
-
- if (ruleTypeName == null)
- {
- inheritedRules = allInheritedRules;
- }
- else
- {
- // Filter the rule list by rule type
- for (Rule rule : allInheritedRules)
- {
- if (rule.getRuleTypes().contains(ruleTypeName) == true)
- {
- inheritedRules.add(rule);
- }
- }
- }
- }
+
+ if (this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_IGNORE_INHERITED_RULES) == false)
+ {
+ // Create the visited nodes set if it has not already been created
+ if (visitedNodeRefs == null)
+ {
+ visitedNodeRefs = new HashSet();
+ }
+
+ // This check prevents stack over flow when we have a cyclic node graph
+ if (visitedNodeRefs.contains(nodeRef) == false)
+ {
+ visitedNodeRefs.add(nodeRef);
+
+ List allInheritedRules = new ArrayList();
+ List parents = this.runtimeNodeService.getParentAssocs(nodeRef);
+ for (ChildAssociationRef parent : parents)
+ {
+ // Add the inherited rule first
+ for (Rule rule : getInheritedRules(parent.getParentRef(), ruleTypeName, visitedNodeRefs))
+ {
+ // Ensure that we don't get any rule duplication (don't use a set cos we want to preserve order)
+ if (allInheritedRules.contains(rule) == false)
+ {
+ allInheritedRules.add(rule);
+ }
+ }
+
+ List rules = getRules(parent.getParentRef(), false);
+ for (Rule rule : rules)
+ {
+ // Add is we hanvn't already added and it should be applied to the children
+ if (rule.isAppliedToChildren() == true && allInheritedRules.contains(rule) == false)
+ {
+ allInheritedRules.add(rule);
+ }
+ }
+ }
+
+ if (ruleTypeName == null)
+ {
+ inheritedRules = allInheritedRules;
+ }
+ else
+ {
+ // Filter the rule list by rule type
+ for (Rule rule : allInheritedRules)
+ {
+ if (rule.getRuleTypes().contains(ruleTypeName) == true)
+ {
+ inheritedRules.add(rule);
+ }
+ }
+ }
+ }
+ }
return inheritedRules;
}
@@ -511,9 +514,6 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
// Create the rule
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));
@@ -538,6 +538,15 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
executeAsync = value2.booleanValue();
}
rule.setExecuteAsynchronously(executeAsync);
+
+ // Set the disabled value
+ boolean ruleDisabled = false;
+ Boolean value3 = (Boolean)props.get(RuleModel.PROP_DISABLED);
+ if (value3 != null)
+ {
+ ruleDisabled = value3.booleanValue();
+ }
+ rule.setRuleDisabled(ruleDisabled);
// Get the action node reference
List actions = this.nodeService.getChildAssocs(ruleNodeRef, RuleModel.ASSOC_ACTION, RuleModel.ASSOC_ACTION);
@@ -597,6 +606,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
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());
+ this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_DISABLED, rule.getRuleDisabled());
// Save the rule's action
saveAction(ruleNodeRef, rule);
@@ -607,6 +617,12 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
}
}
+ /**
+ * Save the action related to the rule.
+ *
+ * @param ruleNodeRef the node reference representing the rule
+ * @param rule the rule
+ */
private void saveAction(NodeRef ruleNodeRef, Rule rule)
{
// Get the action definition from the rule
@@ -708,18 +724,18 @@ 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.rulesDisabled.get() == null &&
+ if (this.isEnabled() == true &&
this.disabledNodeRefs.contains(this.getOwningNodeRef(rule)) == false &&
this.disabledRules.contains(rule) == false)
{
PendingRuleData pendingRuleData = new PendingRuleData(actionableNodeRef, actionedUponNodeRef, rule, executeAtEnd);
- Set pendingRules =
- (Set) AlfrescoTransactionSupport.getResource(KEY_RULES_PENDING);
+ List pendingRules =
+ (List) AlfrescoTransactionSupport.getResource(KEY_RULES_PENDING);
if (pendingRules == null)
{
// bind pending rules to the current transaction
- pendingRules = new HashSet();
+ pendingRules = new ArrayList();
AlfrescoTransactionSupport.bindResource(KEY_RULES_PENDING, pendingRules);
// bind the rule transaction listener
AlfrescoTransactionSupport.bindListener(this.ruleTransactionListener);
@@ -730,8 +746,11 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
}
}
- // Prevent the same rule being executed more than once in the same transaction
- pendingRules.add(pendingRuleData);
+ // Prevent the same rule being executed more than once in the same transaction
+ if (pendingRules.contains(pendingRuleData) == false)
+ {
+ pendingRules.add(pendingRuleData);
+ }
}
else
{
@@ -773,8 +792,8 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
private void executePendingRulesImpl(List executeAtEndRules)
{
// get the transaction-local rules to execute
- Set pendingRules =
- (Set) AlfrescoTransactionSupport.getResource(KEY_RULES_PENDING);
+ List pendingRules =
+ (List) AlfrescoTransactionSupport.getResource(KEY_RULES_PENDING);
// only execute if there are rules present
if (pendingRules != null && !pendingRules.isEmpty())
{
@@ -815,29 +834,41 @@ 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(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)
- executedRules.add(new ExecutedRuleData(actionedUponNodeRef, rule));
- if (logger.isDebugEnabled() == true)
- {
- logger.debug(" ... Adding rule (" + rule.getTitle() + ") and nodeRef (" + actionedUponNodeRef.getId() + ") to executed list");
- }
-
- // Execute the rule
- boolean executeAsync = rule.getExecuteAsynchronously();
- this.actionService.executeAction(action, actionedUponNodeRef, true, executeAsync);
- }
+ executeRule(rule, actionedUponNodeRef, executedRules);
}
}
+
+ /**
+ * @see org.alfresco.repo.rule.RuntimeRuleService#executeRule(org.alfresco.service.cmr.rule.Rule, org.alfresco.service.cmr.repository.NodeRef, java.util.Set)
+ */
+ public void executeRule(Rule rule, NodeRef actionedUponNodeRef, Set executedRules)
+ {
+ // Get the action associated with the rule
+ 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(action, actionedUponNodeRef) == true)
+ {
+ if (executedRules != null)
+ {
+ // Add the rule to the executed rule list
+ // (do this before this is executed to prevent rules being added to the pending list)
+ executedRules.add(new ExecutedRuleData(actionedUponNodeRef, rule));
+ if (logger.isDebugEnabled() == true)
+ {
+ logger.debug(" ... Adding rule (" + rule.getTitle() + ") and nodeRef (" + actionedUponNodeRef.getId() + ") to executed list");
+ }
+ }
+
+ // Execute the rule
+ boolean executeAsync = rule.getExecuteAsynchronously();
+ this.actionService.executeAction(action, actionedUponNodeRef, true, executeAsync);
+ }
+ }
/**
* Determines whether the rule can be executed
diff --git a/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java b/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java
index 10e8134e00..10f34d4820 100644
--- a/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java
+++ b/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java
@@ -148,6 +148,127 @@ public class RuleServiceImplTest extends BaseRuleTest
assertEquals(1, conditions.size());
}
+ /** Ensure the rules are retrieved in the correct order **/
+ public void testGetRulesOrder()
+ {
+ for (int index = 0; index < 10; index++)
+ {
+ Rule newRule = createTestRule(true, Integer.toString(index));
+ this.ruleService.saveRule(this.nodeRef, newRule);
+ }
+
+ // Check that they are all returned in the correct order
+ List rules = this.ruleService.getRules(this.nodeRef);
+ int index = 0;
+ for (Rule rule : rules)
+ {
+ assertEquals(Integer.toString(index), rule.getTitle());
+ index++;
+ }
+
+ // Create a child node
+ NodeRef level1 = createNewNode(this.nodeRef);
+ for (int index2 = 10; index2 < 20; index2++)
+ {
+ Rule newRule = createTestRule(true, Integer.toString(index2));
+ this.ruleService.saveRule(level1, newRule);
+ }
+
+ // Check that they are all returned in the correct order
+ List rules2 = this.ruleService.getRules(level1);
+ int index2 = 0;
+ for (Rule rule : rules2)
+ {
+ assertEquals(Integer.toString(index2), rule.getTitle());
+ index2++;
+ }
+
+ // Create a child node
+ NodeRef level2 = createNewNode(level1);
+ for (int index3 = 20; index3 < 30; index3++)
+ {
+ Rule newRule = createTestRule(true, Integer.toString(index3));
+ this.ruleService.saveRule(level2, newRule);
+ }
+
+ // Check that they are all returned in the correct order
+ List rules3 = this.ruleService.getRules(level2);
+ int index3 = 0;
+ for (Rule rule : rules3)
+ {
+ //System.out.println(rule.getTitle());
+ assertEquals(Integer.toString(index3), rule.getTitle());
+ index3++;
+ }
+
+ // Update a couple of the rules
+ Rule rule1 = rules3.get(2);
+ rule1.setDescription("This has been changed");
+ this.ruleService.saveRule(this.nodeRef, rule1);
+ Rule rule2 = rules3.get(12);
+ rule2.setDescription("This has been changed");
+ this.ruleService.saveRule(level1, rule2);
+ Rule rule3 = rules3.get(22);
+ rule3.setDescription("This has been changed");
+ this.ruleService.saveRule(level2, rule3);
+
+ // Check that they are all returned in the correct order
+ List rules4 = this.ruleService.getRules(level2);
+ int index4 = 0;
+ for (Rule rule : rules4)
+ {
+ assertEquals(Integer.toString(index4), rule.getTitle());
+ index4++;
+ }
+ }
+
+ public void testIgnoreInheritedRules()
+ {
+ // Create the nodes and rules
+ this.ruleService.saveRule(this.nodeRef, createTestRule(true, "rule1"));
+ this.ruleService.saveRule(this.nodeRef, createTestRule(false, "rule2"));
+ NodeRef nodeRef1 = createNewNode(this.nodeRef);
+ this.ruleService.saveRule(nodeRef1, createTestRule(true, "rule3"));
+ this.ruleService.saveRule(nodeRef1, createTestRule(false, "rule4"));
+ NodeRef nodeRef2 = createNewNode(nodeRef1);
+ this.ruleService.saveRule(nodeRef2, createTestRule(true, "rule5"));
+ this.ruleService.saveRule(nodeRef2, createTestRule(false, "rule6"));
+
+ // Apply the ignore aspect
+ this.nodeService.addAspect(nodeRef1, RuleModel.ASPECT_IGNORE_INHERITED_RULES, null);
+
+ // Get the rules
+ List rules1 = this.ruleService.getRules(nodeRef2);
+ assertNotNull(rules1);
+ assertEquals(3, rules1.size());
+ assertEquals("rule3", rules1.get(0).getTitle());
+ assertEquals("rule5", rules1.get(1).getTitle());
+ assertEquals("rule6", rules1.get(2).getTitle());
+
+ // Apply the ignore aspect
+ this.nodeService.addAspect(nodeRef2, RuleModel.ASPECT_IGNORE_INHERITED_RULES, null);
+
+ // Get the rules
+ List rules2 = this.ruleService.getRules(nodeRef2);
+ assertNotNull(rules2);
+ assertEquals(2, rules2.size());
+ assertEquals("rule5", rules2.get(0).getTitle());
+ assertEquals("rule6", rules2.get(1).getTitle());
+
+ // Remove the ignore aspect
+ this.nodeService.removeAspect(nodeRef1, RuleModel.ASPECT_IGNORE_INHERITED_RULES);
+ this.nodeService.removeAspect(nodeRef2, RuleModel.ASPECT_IGNORE_INHERITED_RULES);
+
+ // Get the rules
+ List rules3 = this.ruleService.getRules(nodeRef2);
+ assertNotNull(rules3);
+ assertEquals(4, rules3.size());
+ assertEquals("rule1", rules3.get(0).getTitle());
+ assertEquals("rule3", rules3.get(1).getTitle());
+ assertEquals("rule5", rules3.get(2).getTitle());
+ assertEquals("rule6", rules3.get(3).getTitle());
+ }
+
/**
* Test disabling the rules
*/
@@ -167,13 +288,12 @@ public class RuleServiceImplTest extends BaseRuleTest
* @param parent the parent node
* @param isActionable indicates whether the node is actionable or not
*/
- private NodeRef createNewNode(NodeRef parent, boolean isActionable)
+ private NodeRef createNewNode(NodeRef parent)
{
- NodeRef newNodeRef = this.nodeService.createNode(parent,
+ return this.nodeService.createNode(parent,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{test}testnode"),
- ContentModel.TYPE_CONTAINER).getChildRef();
- return newNodeRef;
+ ContentModel.TYPE_CONTAINER).getChildRef();
}
/**
@@ -184,21 +304,21 @@ public class RuleServiceImplTest extends BaseRuleTest
{
// Create the nodes and rules
- NodeRef rootWithRules = createNewNode(this.rootNodeRef, true);
+ NodeRef rootWithRules = createNewNode(this.rootNodeRef);
Rule rule1 = createTestRule();
this.ruleService.saveRule(rootWithRules, rule1);
Rule rule2 = createTestRule(true);
this.ruleService.saveRule(rootWithRules, rule2);
- NodeRef nonActionableChild = createNewNode(rootWithRules, false);
+ NodeRef nonActionableChild = createNewNode(rootWithRules);
- NodeRef childWithRules = createNewNode(nonActionableChild, true);
+ NodeRef childWithRules = createNewNode(nonActionableChild);
Rule rule3 = createTestRule();
this.ruleService.saveRule(childWithRules, rule3);
Rule rule4 = createTestRule(true);
this.ruleService.saveRule(childWithRules, rule4);
- NodeRef rootWithRules2 = createNewNode(this.rootNodeRef, true);
+ NodeRef rootWithRules2 = createNewNode(this.rootNodeRef);
this.nodeService.addChild(
rootWithRules2,
childWithRules,
@@ -211,7 +331,7 @@ public class RuleServiceImplTest extends BaseRuleTest
// Check that the rules are inherited in the correct way
- List extends Rule> allRules = this.ruleService.getRules(childWithRules, true);
+ List extends Rule> allRules = this.ruleService.getRules(childWithRules);
assertNotNull(allRules);
assertEquals(4, allRules.size());
assertTrue(allRules.contains(rule2));
@@ -432,9 +552,9 @@ public class RuleServiceImplTest extends BaseRuleTest
public void testCyclicGraphWithInheritedRules()
throws Exception
{
- NodeRef nodeRef1 = createNewNode(this.rootNodeRef, true);
- NodeRef nodeRef2 = createNewNode(nodeRef1, true);
- NodeRef nodeRef3 = createNewNode(nodeRef2, true);
+ NodeRef nodeRef1 = createNewNode(this.rootNodeRef);
+ NodeRef nodeRef2 = createNewNode(nodeRef1);
+ NodeRef nodeRef3 = createNewNode(nodeRef2);
try
{
this.nodeService.addChild(nodeRef3, nodeRef1, ContentModel.ASSOC_CHILDREN, QName.createQName("{test}loop"));
@@ -480,10 +600,10 @@ public class RuleServiceImplTest extends BaseRuleTest
*/
public void testRuleDuplication()
{
- NodeRef nodeRef1 = createNewNode(this.rootNodeRef, true);
- NodeRef nodeRef2 = createNewNode(nodeRef1, true);
- NodeRef nodeRef3 = createNewNode(nodeRef2, true);
- NodeRef nodeRef4 = createNewNode(nodeRef1, true);
+ NodeRef nodeRef1 = createNewNode(this.rootNodeRef);
+ NodeRef nodeRef2 = createNewNode(nodeRef1);
+ NodeRef nodeRef3 = createNewNode(nodeRef2);
+ NodeRef nodeRef4 = createNewNode(nodeRef1);
this.nodeService.addChild(nodeRef4, nodeRef3, ContentModel.ASSOC_CHILDREN, QName.createQName("{test}test"));
Rule rule1 = createTestRule(true);
@@ -527,7 +647,7 @@ public class RuleServiceImplTest extends BaseRuleTest
public void testCyclicAsyncRules() throws Exception
{
- NodeRef nodeRef = createNewNode(this.rootNodeRef, true);
+ NodeRef nodeRef = createNewNode(this.rootNodeRef);
// Create the first rule
diff --git a/source/java/org/alfresco/repo/rule/RuleTypeImpl.java b/source/java/org/alfresco/repo/rule/RuleTypeImpl.java
index 015a6fbd4d..fdaf1bcf77 100644
--- a/source/java/org/alfresco/repo/rule/RuleTypeImpl.java
+++ b/source/java/org/alfresco/repo/rule/RuleTypeImpl.java
@@ -21,7 +21,6 @@ import java.util.List;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.action.CommonResourceAbstractBase;
import org.alfresco.repo.rule.ruletrigger.RuleTrigger;
-import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.rule.Rule;
import org.alfresco.service.cmr.rule.RuleService;
@@ -99,7 +98,7 @@ public class RuleTypeImpl extends CommonResourceAbstractBase implements RuleType
/**
* @see org.alfresco.service.cmr.rule.RuleType#triggerRuleType(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef)
*/
- public void triggerRuleType(NodeRef nodeRef, NodeRef actionedUponNodeRef)
+ public void triggerRuleType(NodeRef nodeRef, NodeRef actionedUponNodeRef, boolean executeRuleImmediately)
{
if (this.ruleService.isEnabled() == true)
{
@@ -121,8 +120,20 @@ public class RuleTypeImpl extends CommonResourceAbstractBase implements RuleType
}
}
- // Queue the rule to be executed at the end of the transaction (but still in the transaction)
- ((RuntimeRuleService)this.ruleService).addRulePendingExecution(nodeRef, actionedUponNodeRef, rule);
+ // Only queue if the rule is not disabled
+ if (rule.getRuleDisabled() == false)
+ {
+ if (executeRuleImmediately == false)
+ {
+ // 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
+ {
+ // Execute the rule now
+ ((RuntimeRuleService)this.ruleService).executeRule(rule, actionedUponNodeRef, null);
+ }
+ }
}
}
else
diff --git a/source/java/org/alfresco/repo/rule/RuleTypeImplTest.java b/source/java/org/alfresco/repo/rule/RuleTypeImplTest.java
index 120978c00b..e1d44dd068 100644
--- a/source/java/org/alfresco/repo/rule/RuleTypeImplTest.java
+++ b/source/java/org/alfresco/repo/rule/RuleTypeImplTest.java
@@ -129,7 +129,7 @@ public class RuleTypeImplTest extends BaseSpringTest
}
@Override
- public void triggerRuleType(NodeRef nodeRef, NodeRef actionedUponNodeRef)
+ public void triggerRuleType(NodeRef nodeRef, NodeRef actionedUponNodeRef, boolean executeRuleImmediately)
{
this.rulesTriggered = true;
}
diff --git a/source/java/org/alfresco/repo/rule/RuntimeRuleService.java b/source/java/org/alfresco/repo/rule/RuntimeRuleService.java
index bf447bf10d..9cfbb649eb 100644
--- a/source/java/org/alfresco/repo/rule/RuntimeRuleService.java
+++ b/source/java/org/alfresco/repo/rule/RuntimeRuleService.java
@@ -16,6 +16,9 @@
*/
package org.alfresco.repo.rule;
+import java.util.Set;
+
+import org.alfresco.repo.rule.RuleServiceImpl.ExecutedRuleData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.rule.Rule;
import org.alfresco.service.cmr.rule.RuleType;
@@ -25,6 +28,8 @@ import org.alfresco.service.cmr.rule.RuleType;
*/
public interface RuntimeRuleService
{
+ void executeRule(Rule rule, NodeRef actionedUponNodeRef, Set executedRules);
+
void addRulePendingExecution(NodeRef actionableNodeRef, NodeRef actionedUponNodeRef, Rule rule);
void addRulePendingExecution(NodeRef actionableNodeRef, NodeRef actionedUponNodeRef, Rule rule, boolean executeAtEnd);
diff --git a/source/java/org/alfresco/repo/rule/ruleModel.xml b/source/java/org/alfresco/repo/rule/ruleModel.xml
index cd64387663..d41bb8b0d6 100644
--- a/source/java/org/alfresco/repo/rule/ruleModel.xml
+++ b/source/java/org/alfresco/repo/rule/ruleModel.xml
@@ -16,7 +16,6 @@
-
@@ -36,6 +35,11 @@
d:boolean
true
+
+ d:boolean
+ true
+ false
+
@@ -68,6 +72,10 @@
+
+
+ Ignore Inherited Rules
+
diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java
index b684f496b6..bfd983b901 100644
--- a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java
+++ b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java
@@ -56,6 +56,12 @@ public abstract class RuleTriggerAbstractBase implements RuleTrigger
/** The dictionary service */
protected DictionaryService dictionaryService;
+ /**
+ * Indicates whether the rule should be executed immediately or at the end of the transaction.
+ * By default this is false as all rules are executed at the end of the transaction.
+ */
+ protected boolean executeRuleImmediately = false;
+
/**
* Set the policy component
*
@@ -96,6 +102,17 @@ public abstract class RuleTriggerAbstractBase implements RuleTrigger
this.dictionaryService = dictionaryService;
}
+ /**
+ * Sets the values that indicates whether the rule should be executed immediately
+ * or not.
+ *
+ * @param executeRuleImmediately true execute the rule immediaely, false otherwise
+ */
+ public void setExecuteRuleImmediately(boolean executeRuleImmediately)
+ {
+ this.executeRuleImmediately = executeRuleImmediately;
+ }
+
/**
* Registration of an interested rule type
*/
@@ -117,7 +134,7 @@ public abstract class RuleTriggerAbstractBase implements RuleTrigger
{
for (RuleType ruleType : this.ruleTypes)
{
- ruleType.triggerRuleType(nodeRef, actionedUponNodeRef);
+ ruleType.triggerRuleType(nodeRef, actionedUponNodeRef, this.executeRuleImmediately);
}
}
}
diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java
index d854b4746c..725fee2833 100644
--- a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java
+++ b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerTest.java
@@ -35,7 +35,6 @@ public class RuleTriggerTest extends BaseSpringTest
{
private static final String ON_CREATE_NODE_TRIGGER = "on-create-node-trigger";
private static final String ON_UPDATE_NODE_TRIGGER = "on-update-node-trigger";
- private static final String ON_DELETE_NODE_TRIGGER = "on-delete-node-trigger";
private static final String ON_CREATE_CHILD_ASSOCIATION_TRIGGER = "on-create-child-association-trigger";
private static final String ON_DELETE_CHILD_ASSOCIATION_TRIGGER = "on-delete-child-association-trigger";
private static final String ON_CREATE_ASSOCIATION_TRIGGER = "on-create-association-trigger";
@@ -287,7 +286,7 @@ public class RuleTriggerTest extends BaseSpringTest
return "displayLabel";
}
- public void triggerRuleType(NodeRef nodeRef, NodeRef actionedUponNodeRef)
+ public void triggerRuleType(NodeRef nodeRef, NodeRef actionedUponNodeRef, boolean executeRuleImmediately)
{
// Indicate that the rules have been triggered
this.rulesTriggered = true;
diff --git a/source/java/org/alfresco/service/cmr/rule/Rule.java b/source/java/org/alfresco/service/cmr/rule/Rule.java
index 9ae30414a2..c0945facca 100644
--- a/source/java/org/alfresco/service/cmr/rule/Rule.java
+++ b/source/java/org/alfresco/service/cmr/rule/Rule.java
@@ -68,63 +68,117 @@ public class Rule implements Serializable
*/
private boolean executeAsynchronously = false;
+ /** Indicates wehther the rule is marked as disabled or not */
+ private boolean ruleDisabled = 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;
+ /**
+ * Constructor
+ */
public Rule()
{
}
+ /**
+ * Constructor.
+ *
+ * @param nodeRef the rule node reference
+ */
public Rule(NodeRef nodeRef)
{
this.nodeRef = nodeRef;
}
+ /**
+ * Set the action
+ *
+ * @param action the action
+ */
public void setAction(Action action)
{
this.action = action;
}
+ /**
+ * Gets the action associatied with the rule
+ *
+ * @return the action
+ */
public Action getAction()
{
return action;
}
+ /**
+ * Set the node reference of the rule
+ *
+ * @param nodeRef the rule node reference
+ */
public void setNodeRef(NodeRef nodeRef)
{
this.nodeRef = nodeRef;
}
+ /**
+ * Get the node reference of the rule
+ *
+ * @return the rule node reference
+ */
public NodeRef getNodeRef()
{
return nodeRef;
}
+ /**
+ * Set the title of the rule
+ *
+ * @param title the title
+ */
public void setTitle(String title)
{
this.title = title;
}
+ /**
+ * Get the title of the rule
+ *
+ * @return the title
+ */
public String getTitle()
{
return title;
}
+ /**
+ * Set the description of the rule
+ *
+ * @param description the description
+ */
public void setDescription(String description)
{
this.description = description;
}
+ /**
+ * Get the description of the rule
+ *
+ * @return the description
+ */
public String getDescription()
{
return description;
}
/**
- * @see org.alfresco.service.cmr.rule.Rule#isAppliedToChildren()
+ * Indicates wehther this rule should be applied to the children of
+ * the owning space.
+ *
+ * @return true if the rule is to be applied to children, false otherwise
*/
public boolean isAppliedToChildren()
{
@@ -132,13 +186,22 @@ public class Rule implements Serializable
}
/**
- *@see org.alfresco.service.cmr.rule.Rule#applyToChildren(boolean)
+ * Sets the values that indicates whether this rule should be applied to the children
+ * of the owning space.
+ *
+ * @param isAppliedToChildren true if the rule is to be applied to children, false otherwise
*/
+
public void applyToChildren(boolean isAppliedToChildren)
{
this.isAppliedToChildren = isAppliedToChildren;
}
+ /**
+ * Helper method to set one rule type on the rule.
+ *
+ * @param ruleType the rule type
+ */
public void setRuleType(String ruleType)
{
List ruleTypes = new ArrayList(1);
@@ -146,26 +209,67 @@ public class Rule implements Serializable
this.ruleTypes = ruleTypes;
}
+ /**
+ * Set the rules rule types.
+ *
+ * @param ruleTypes list of rule types
+ */
public void setRuleTypes(List ruleTypes)
{
this.ruleTypes = ruleTypes;
}
+ /**
+ * Get the rules rule types.
+ *
+ * @return a list of rule types
+ */
public List getRuleTypes()
{
return ruleTypes;
}
+ /**
+ * Sets the value that indicates whether this associated action should be executed
+ * asynchrously or not
+ *
+ * @param executeAsynchronously true to execute action async, false otherwise
+ */
public void setExecuteAsynchronously(boolean executeAsynchronously)
{
this.executeAsynchronously = executeAsynchronously;
}
+ /**
+ * Indicates whether the associated action should be executed async or not
+ *
+ * @return true to execute async, false otherwise
+ */
public boolean getExecuteAsynchronously()
{
return this.executeAsynchronously;
}
+ /**
+ * Indicates wehther this rule has been disabled or not
+ *
+ * @return true if the rule has been disabled, false otherwise
+ */
+ public boolean getRuleDisabled()
+ {
+ return this.ruleDisabled;
+ }
+
+ /**
+ * Set the value that indicates wehther this rule has been disabled or not
+ *
+ * @param ruleDisabled true id the rule has been disabled, false otherwise
+ */
+ public void setRuleDisabled(boolean ruleDisabled)
+ {
+ this.ruleDisabled = ruleDisabled;
+ }
+
/**
* Hash code implementation
*/
diff --git a/source/java/org/alfresco/service/cmr/rule/RuleType.java b/source/java/org/alfresco/service/cmr/rule/RuleType.java
index 10fcb50d70..03c1fe8ab6 100644
--- a/source/java/org/alfresco/service/cmr/rule/RuleType.java
+++ b/source/java/org/alfresco/service/cmr/rule/RuleType.java
@@ -52,8 +52,9 @@ public interface RuleType
/**
* Trigger the rules of the rule type for the node on the actioned upon node.
*
- * @param nodeRef the node ref whos rule of rule type are to be triggered
- * @param actionedUponNodeRef the node ref that the triggered rule will action upon
+ * @param nodeRef the node ref whos rule of rule type are to be triggered
+ * @param actionedUponNodeRef the node ref that the triggered rule will action upon
+ * @prarm executeRuleImmediately indicates whether the rule should be executed immediately or not
*/
- public void triggerRuleType(NodeRef nodeRef, NodeRef actionedUponNodeRef);
+ public void triggerRuleType(NodeRef nodeRef, NodeRef actionedUponNodeRef, boolean executeRuleImmediately);
}
\ No newline at end of file