- Rules now fire in a more reliable way

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@3268 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall 2006-06-30 09:41:28 +00:00
parent cdc24b707a
commit 048bffec76

View File

@ -67,7 +67,8 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
private static final String KEY_RULES_EXECUTED = "RuleServiceImpl.ExecutedRules"; private static final String KEY_RULES_EXECUTED = "RuleServiceImpl.ExecutedRules";
/** qname of assoc to rules */ /** qname of assoc to rules */
private QName ASSOC_NAME_RULES = QName.createQName(RuleModel.RULE_MODEL_URI, "rules"); private String ASSOC_NAME_RULES_PREFIX = "rules";
private RegexQNamePattern ASSOC_NAME_RULES_REGEX = new RegexQNamePattern(RuleModel.RULE_MODEL_URI, "^" + ASSOC_NAME_RULES_PREFIX + ".*");
/** /**
* The logger * The logger
@ -325,7 +326,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
// Get the rules for this node // Get the rules for this node
List<ChildAssociationRef> ruleChildAssocRefs = List<ChildAssociationRef> ruleChildAssocRefs =
this.runtimeNodeService.getChildAssocs(ruleFolder, RegexQNamePattern.MATCH_ALL, ASSOC_NAME_RULES); this.runtimeNodeService.getChildAssocs(ruleFolder, RegexQNamePattern.MATCH_ALL, ASSOC_NAME_RULES_REGEX);
for (ChildAssociationRef ruleChildAssocRef : ruleChildAssocRefs) for (ChildAssociationRef ruleChildAssocRef : ruleChildAssocRefs)
{ {
// Create the rule and add to the list // Create the rule and add to the list
@ -366,7 +367,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
{ {
// Get the rules for this node // Get the rules for this node
List<ChildAssociationRef> ruleChildAssocRefs = List<ChildAssociationRef> ruleChildAssocRefs =
this.runtimeNodeService.getChildAssocs(ruleFolder, RegexQNamePattern.MATCH_ALL, ASSOC_NAME_RULES); this.runtimeNodeService.getChildAssocs(ruleFolder, RegexQNamePattern.MATCH_ALL, ASSOC_NAME_RULES_REGEX);
ruleCount = ruleChildAssocRefs.size(); ruleCount = ruleChildAssocRefs.size();
} }
@ -531,7 +532,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
private Rule createRule(NodeRef owningNodeRef, NodeRef ruleNodeRef) private Rule createRule(NodeRef owningNodeRef, NodeRef ruleNodeRef)
{ {
// Get the rule properties // Get the rule properties
Map<QName, Serializable> props = this.nodeService.getProperties(ruleNodeRef); Map<QName, Serializable> props = this.runtimeNodeService.getProperties(ruleNodeRef);
// Create the rule // Create the rule
String ruleTypeName = (String)props.get(RuleModel.PROP_RULE_TYPE); String ruleTypeName = (String)props.get(RuleModel.PROP_RULE_TYPE);
@ -590,7 +591,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
ruleNodeRef = this.nodeService.createNode( ruleNodeRef = this.nodeService.createNode(
getSavedRuleFolderRef(nodeRef), getSavedRuleFolderRef(nodeRef),
ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS,
ASSOC_NAME_RULES, QName.createQName(RuleModel.RULE_MODEL_URI, ASSOC_NAME_RULES_PREFIX + GUID.generate()),
RuleModel.TYPE_RULE, RuleModel.TYPE_RULE,
props).getChildRef(); props).getChildRef();
@ -643,7 +644,7 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
{ {
List<ChildAssociationRef> ruleChildAssocs = this.nodeService.getChildAssocs( List<ChildAssociationRef> ruleChildAssocs = this.nodeService.getChildAssocs(
folder, folder,
RegexQNamePattern.MATCH_ALL, ASSOC_NAME_RULES); RegexQNamePattern.MATCH_ALL, ASSOC_NAME_RULES_REGEX);
for (ChildAssociationRef ruleChildAssoc : ruleChildAssocs) for (ChildAssociationRef ruleChildAssoc : ruleChildAssocs)
{ {
this.nodeService.removeChild(folder, ruleChildAssoc.getChildRef()); this.nodeService.removeChild(folder, ruleChildAssoc.getChildRef());
@ -666,30 +667,25 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
this.disabledRules.contains(rule) == false) this.disabledRules.contains(rule) == false)
{ {
PendingRuleData pendingRuleData = new PendingRuleData(actionableNodeRef, actionedUponNodeRef, rule, executeAtEnd); PendingRuleData pendingRuleData = new PendingRuleData(actionableNodeRef, actionedUponNodeRef, rule, executeAtEnd);
Set<ExecutedRuleData> executedRules =
(Set<ExecutedRuleData>) AlfrescoTransactionSupport.getResource(KEY_RULES_EXECUTED); Set<PendingRuleData> pendingRules =
(Set<PendingRuleData>) AlfrescoTransactionSupport.getResource(KEY_RULES_PENDING);
if (executedRules == null || executedRules.contains(new ExecutedRuleData(actionableNodeRef, rule)) == false) if (pendingRules == null)
{ {
Set<PendingRuleData> pendingRules = // bind pending rules to the current transaction
(Set<PendingRuleData>) AlfrescoTransactionSupport.getResource(KEY_RULES_PENDING); pendingRules = new HashSet<PendingRuleData>();
if (pendingRules == null) AlfrescoTransactionSupport.bindResource(KEY_RULES_PENDING, pendingRules);
{ // bind the rule transaction listener
// bind pending rules to the current transaction AlfrescoTransactionSupport.bindListener(this.ruleTransactionListener);
pendingRules = new HashSet<PendingRuleData>();
AlfrescoTransactionSupport.bindResource(KEY_RULES_PENDING, pendingRules); if (logger.isDebugEnabled() == true)
// bind the rule transaction listener {
AlfrescoTransactionSupport.bindListener(this.ruleTransactionListener); logger.debug("Rule '" + rule.getTitle() + "' has been added pending execution to action upon node '" + actionedUponNodeRef.getId() + "'");
}
if (logger.isDebugEnabled() == true) }
{
logger.debug("Rule '" + rule.getTitle() + "' has been added pending execution to action upon node '" + actionedUponNodeRef.getId() + "'"); // Prevent hte same rule being executed more than one in the same transaction
} pendingRules.add(pendingRuleData);
}
// Prevent hte same rule being executed more than one in the same transaction
pendingRules.add(pendingRuleData);
}
} }
else else
{ {
@ -699,12 +695,18 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
} }
} }
} }
/** /**
* @see org.alfresco.repo.rule.RuleService#executePendingRules() * @see org.alfresco.repo.rule.RuleService#executePendingRules()
*/ */
public void executePendingRules() public void executePendingRules()
{ {
if (logger.isDebugEnabled() == true)
{
logger.debug("Creating the executed rules list");
}
AlfrescoTransactionSupport.bindResource(KEY_RULES_EXECUTED, new HashSet<ExecutedRuleData>()); AlfrescoTransactionSupport.bindResource(KEY_RULES_EXECUTED, new HashSet<ExecutedRuleData>());
try try
{ {
@ -718,6 +720,10 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
finally finally
{ {
AlfrescoTransactionSupport.unbindResource(KEY_RULES_EXECUTED); AlfrescoTransactionSupport.unbindResource(KEY_RULES_EXECUTED);
if (logger.isDebugEnabled() == true)
{
logger.debug("Unbinding resource");
}
} }
} }
@ -762,22 +768,121 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void executePendingRule(PendingRuleData pendingRule) private void executePendingRule(PendingRuleData pendingRule)
{ {
NodeRef actionableNodeRef = pendingRule.getActionableNodeRef(); Set<ExecutedRuleData> executedRules =
(Set<ExecutedRuleData>) AlfrescoTransactionSupport.getResource(KEY_RULES_EXECUTED);
NodeRef actionedUponNodeRef = pendingRule.getActionedUponNodeRef(); NodeRef actionedUponNodeRef = pendingRule.getActionedUponNodeRef();
Rule rule = pendingRule.getRule(); Rule rule = pendingRule.getRule();
// Evaluate the condition if (executedRules == null || canExecuteRule(executedRules, actionedUponNodeRef, rule) == true)
if (this.actionService.evaluateAction(rule, actionedUponNodeRef) == true) {
{ // Evaluate the condition
// Add the rule to the executed rule list if (this.actionService.evaluateAction(rule, actionedUponNodeRef) == true)
// (do this before this is executed to prevent rules being added to the pending list) {
Set<ExecutedRuleData> executedRules = // Add the rule to the executed rule list
(Set<ExecutedRuleData>) AlfrescoTransactionSupport.getResource(KEY_RULES_EXECUTED); // (do this before this is executed to prevent rules being added to the pending list)
executedRules.add(new ExecutedRuleData(actionableNodeRef, rule)); executedRules.add(new ExecutedRuleData(actionedUponNodeRef, rule));
if (logger.isDebugEnabled() == true)
// Execute the rule {
this.actionService.executeAction(rule, actionedUponNodeRef); logger.debug(" ... Adding rule (" + rule.getTitle() + ") and nodeRef (" + actionedUponNodeRef.getId() + ") to executed list");
} }
// Execute the rule
this.actionService.executeAction(rule, actionedUponNodeRef);
}
}
}
/**
* Determines whether the rule can be executed
*
* @param executedRules
* @param actionedUponNodeRef
* @param rule
* @return
*/
private boolean canExecuteRule(Set<ExecutedRuleData> executedRules, NodeRef actionedUponNodeRef, Rule rule)
{
boolean result = true;
if (logger.isDebugEnabled() == true)
{
logger.debug(" >> Current executed items count = " + executedRules.size());
}
if (executedRules != null)
{
if (executedRules.contains(new ExecutedRuleData(actionedUponNodeRef, rule)) == true)
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" >> Already executed this rule (" + rule.getTitle()+ ") on this nodeRef (" + actionedUponNodeRef.getId() + ")");
}
result = false;
}
else
{
result = checkForCopy(executedRules, actionedUponNodeRef, rule);
}
}
else
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" >> Executed this rule (" + rule.getTitle()+ ") on (" + actionedUponNodeRef.getId() + ") executed rule is null");
}
}
return result;
}
/**
* Checks to see if a copy exists in the executed rules list
*
* @param executedRules
* @param actionedUponNodeRef
* @param rule
* @return
*/
private boolean checkForCopy(Set<ExecutedRuleData> executedRules, NodeRef actionedUponNodeRef, Rule rule)
{
boolean result = true;
if (this.nodeService.hasAspect(actionedUponNodeRef, ContentModel.ASPECT_COPIEDFROM) == true)
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" >> Has the copied from aspect (" + actionedUponNodeRef.getId() + ")");
}
NodeRef copiedFrom = (NodeRef)this.nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_COPY_REFERENCE);
if (logger.isDebugEnabled() == true && copiedFrom != null) {logger.debug(" >> Got the copedFrom nodeRef (" + copiedFrom.getId() + ")");};
if (copiedFrom != null && executedRules.contains(new ExecutedRuleData(copiedFrom, rule)) == true)
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" >> Already executed this rule (" + rule.getTitle()+ ") on this the copied from nodeRef (" + copiedFrom.getId() + ")");
}
return false;
}
else
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" >> Executed this rule (" + rule.getTitle()+ ") on (" + actionedUponNodeRef.getId() + ") copiedFrom is not is list");
logger.debug(" > Checking copy");
}
result = checkForCopy(executedRules, copiedFrom, rule);
}
}
else
{
if (logger.isDebugEnabled() == true)
{
logger.debug(" >> Executed this rule (" + rule.getTitle()+ ") on (" + actionedUponNodeRef.getId() + ") no copied from aspect");
}
}
return result;
} }
/** /**