KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > repo > rule > RuleServiceImpl


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.repo.rule;
18
19 import java.io.Serializable JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Date JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.HashSet JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.Set JavaDoc;
27
28 import org.alfresco.model.ContentModel;
29 import org.alfresco.repo.action.ActionModel;
30 import org.alfresco.repo.action.RuntimeActionService;
31 import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
32 import org.alfresco.repo.transaction.TransactionListener;
33 import org.alfresco.service.cmr.action.ActionService;
34 import org.alfresco.service.cmr.action.ActionServiceException;
35 import org.alfresco.service.cmr.dictionary.DictionaryService;
36 import org.alfresco.service.cmr.repository.ChildAssociationRef;
37 import org.alfresco.service.cmr.repository.NodeRef;
38 import org.alfresco.service.cmr.repository.NodeService;
39 import org.alfresco.service.cmr.rule.Rule;
40 import org.alfresco.service.cmr.rule.RuleService;
41 import org.alfresco.service.cmr.rule.RuleServiceException;
42 import org.alfresco.service.cmr.rule.RuleType;
43 import org.alfresco.service.cmr.search.SearchService;
44 import org.alfresco.service.namespace.DynamicNamespacePrefixResolver;
45 import org.alfresco.service.namespace.NamespaceService;
46 import org.alfresco.service.namespace.QName;
47 import org.alfresco.service.namespace.RegexQNamePattern;
48 import org.alfresco.util.GUID;
49 import org.apache.commons.logging.Log;
50 import org.apache.commons.logging.LogFactory;
51
52 /**
53  * Rule service implementation.
54  * <p>
55  * This service automatically binds to the transaction flush hooks. It will
56  * therefore participate in any flushes that occur during the transaction as
57  * well.
58  *
59  * @author Roy Wetherall
60  */

61 public class RuleServiceImpl implements RuleService, RuntimeRuleService
62 {
63     /** key against which to store rules pending on the current transaction */
64     private static final String JavaDoc KEY_RULES_PENDING = "RuleServiceImpl.PendingRules";
65     
66     /** key against which to store executed rules on the current transaction */
67     private static final String JavaDoc KEY_RULES_EXECUTED = "RuleServiceImpl.ExecutedRules";
68     
69     /** qname of assoc to rules */
70     private QName ASSOC_NAME_RULES = QName.createQName(RuleModel.RULE_MODEL_URI, "rules");
71     
72     /**
73      * The logger
74      */

75     private static Log logger = LogFactory.getLog(RuleServiceImpl.class);
76     
77     /**
78      * The permission-safe node service
79      */

80     private NodeService nodeService;
81     
82     /**
83      * The runtime node service (ignores permissions)
84      */

85     private NodeService runtimeNodeService;
86     
87     /**
88      * The action service
89      */

90     private ActionService actionService;
91     
92     /**
93      * The search service
94      */

95     private SearchService searchService;
96     
97     /**
98      * The dictionary service
99      */

100     private DictionaryService dictionaryService;
101     
102     /**
103      * The action service implementation which we need for some things.
104      */

105     RuntimeActionService runtimeActionService;
106        
107     /**
108      * List of disabled node refs. The rules associated with these nodes will node be added to the pending list, and
109      * therefore not fired. This list is transient.
110      */

111     private Set JavaDoc<NodeRef> disabledNodeRefs = new HashSet JavaDoc<NodeRef>(5);
112     
113     /**
114      * List of disabled rules. Any rules that appear in this list will not be added to the pending list and therefore
115      * not fired.
116      */

117     private Set JavaDoc<Rule> disabledRules = new HashSet JavaDoc<Rule>(5);
118
119     /**
120      * All the rule type currently registered
121      */

122     private Map JavaDoc<String JavaDoc, RuleType> ruleTypes = new HashMap JavaDoc<String JavaDoc, RuleType>();
123
124     /**
125      * The rule transaction listener
126      */

127     private TransactionListener ruleTransactionListener = new RuleTransactionListener(this);
128     
129     /**
130      * Set the permission-safe node service
131      *
132      * @param nodeService the permission-safe node service
133      */

134     public void setNodeService(NodeService nodeService)
135     {
136         this.nodeService = nodeService;
137     }
138     
139     /**
140      * Set the direct node service
141      *
142      * @param nodeService the node service
143      */

144     public void setRuntimeNodeService(NodeService runtimeNodeService)
145     {
146         this.runtimeNodeService = runtimeNodeService;
147     }
148     
149     /**
150      * Set the action service
151      *
152      * @param actionService the action service
153      */

154     public void setActionService(ActionService actionService)
155     {
156         this.actionService = actionService;
157     }
158     
159     /**
160      * Set the runtime action service
161      *
162      * @param actionRegistration the action service
163      */

164     public void setRuntimeActionService(RuntimeActionService runtimeActionService)
165     {
166         this.runtimeActionService = runtimeActionService;
167     }
168     
169     /**
170      * Set the search service
171      *
172      * @param searchService the search service
173      */

174     public void setSearchService(SearchService searchService)
175     {
176         this.searchService = searchService;
177     }
178     
179     /**
180      * Set the dictionary service
181      *
182      * @param dictionaryService the dictionary service
183      */

184     public void setDictionaryService(DictionaryService dictionaryService)
185     {
186         this.dictionaryService = dictionaryService;
187     }
188     
189     /**
190      * Gets the saved rule folder reference
191      *
192      * @param nodeRef the node reference
193      * @return the node reference
194      */

195     private NodeRef getSavedRuleFolderRef(NodeRef nodeRef)
196     {
197         NodeRef result = null;
198         
199         List JavaDoc<ChildAssociationRef> assocs = this.runtimeNodeService.getChildAssocs(
200                 nodeRef,
201                 RegexQNamePattern.MATCH_ALL,
202                 RuleModel.ASSOC_RULE_FOLDER);
203         if (assocs.size() > 1)
204         {
205             throw new ActionServiceException("There is more than one rule folder, which is invalid.");
206         }
207         else if (assocs.size() == 1)
208         {
209             result = assocs.get(0).getChildRef();
210         }
211         
212         return result;
213     }
214     
215     /**
216      * @see org.alfresco.repo.rule.RuleService#getRuleTypes()
217      */

218     public List JavaDoc<RuleType> getRuleTypes()
219     {
220         return new ArrayList JavaDoc<RuleType>(this.ruleTypes.values());
221     }
222     
223     /**
224      * @see org.alfresco.repo.rule.RuleService#getRuleType(java.lang.String)
225      */

226     public RuleType getRuleType(String JavaDoc name)
227     {
228         return this.ruleTypes.get(name);
229     }
230     
231     /**
232      * @see org.alfresco.service.cmr.rule.RuleService#rulesEnabled(NodeRef)
233      */

234     public boolean rulesEnabled(NodeRef nodeRef)
235     {
236         return (this.disabledNodeRefs.contains(nodeRef) == false);
237     }
238
239     /**
240      * @see org.alfresco.service.cmr.rule.RuleService#disableRules(NodeRef)
241      */

242     public void disableRules(NodeRef nodeRef)
243     {
244         // Add the node to the set of disabled nodes
245
this.disabledNodeRefs.add(nodeRef);
246     }
247
248     /**
249      * @see org.alfresco.service.cmr.rule.RuleService#enableRules(NodeRef)
250      */

251     public void enableRules(NodeRef nodeRef)
252     {
253         // Remove the node from the set of disabled nodes
254
this.disabledNodeRefs.remove(nodeRef);
255     }
256     
257     /**
258      * @see org.alfresco.service.cmr.rule.RuleService#disableRule(org.alfresco.service.cmr.rule.Rule)
259      */

260     public void disableRule(Rule rule)
261     {
262         this.disabledRules.add(rule);
263     }
264     
265     /**
266      * @see org.alfresco.service.cmr.rule.RuleService#enableRule(org.alfresco.service.cmr.rule.Rule)
267      */

268     public void enableRule(Rule rule)
269     {
270         this.disabledRules.remove(rule);
271     }
272     
273     /**
274      * @see org.alfresco.service.cmr.rule.RuleService#hasRules(org.alfresco.repo.ref.NodeRef)
275      */

276     public boolean hasRules(NodeRef nodeRef)
277     {
278         return getRules(nodeRef).size() != 0;
279     }
280
281     /**
282      * @see org.alfresco.repo.rule.RuleService#getRules(org.alfresco.repo.ref.NodeRef)
283      */

284     public List JavaDoc<Rule> getRules(NodeRef nodeRef)
285     {
286         return getRules(nodeRef, true, null);
287     }
288
289     /**
290      * @see org.alfresco.repo.rule.RuleService#getRules(org.alfresco.repo.ref.NodeRef, boolean)
291      */

292     public List JavaDoc<Rule> getRules(NodeRef nodeRef, boolean includeInherited)
293     {
294         return getRules(nodeRef, includeInherited, null);
295     }
296     
297     /**
298      * @see org.alfresco.repo.rule.RuleService#getRulesByRuleType(org.alfresco.repo.ref.NodeRef, org.alfresco.repo.rule.RuleType)
299      */

300     public List JavaDoc<Rule> getRules(NodeRef nodeRef, boolean includeInherited, String JavaDoc ruleTypeName)
301     {
302         List JavaDoc<Rule> rules = new ArrayList JavaDoc<Rule>();
303         
304         if (this.runtimeNodeService.exists(nodeRef) == true && checkNodeType(nodeRef) == true)
305         {
306             if (includeInherited == true)
307             {
308                 // Get any inherited rules
309
for (Rule rule : getInheritedRules(nodeRef, ruleTypeName, null))
310                 {
311                     // Ensure rules are not duplicated in the list
312
if (rules.contains(rule) == false)
313                     {
314                         rules.add(rule);
315                     }
316                 }
317             }
318             
319             if (this.runtimeNodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true)
320             {
321                 NodeRef ruleFolder = getSavedRuleFolderRef(nodeRef);
322                 if (ruleFolder != null)
323                 {
324                     List JavaDoc<Rule> allRules = new ArrayList JavaDoc<Rule>();
325                     
326                     // Get the rules for this node
327
List JavaDoc<ChildAssociationRef> ruleChildAssocRefs =
328                         this.runtimeNodeService.getChildAssocs(ruleFolder, RegexQNamePattern.MATCH_ALL, ASSOC_NAME_RULES);
329                     for (ChildAssociationRef ruleChildAssocRef : ruleChildAssocRefs)
330                     {
331                         // Create the rule and add to the list
332
NodeRef ruleNodeRef = ruleChildAssocRef.getChildRef();
333                         Rule rule = createRule(nodeRef, ruleNodeRef);
334                         allRules.add(rule);
335                     }
336                     
337                     // Build the list of rules that is returned to the client
338
for (Rule rule : allRules)
339                     {
340                         if ((rules.contains(rule) == false) &&
341                                 (ruleTypeName == null || ruleTypeName.equals(rule.getRuleTypeName()) == true))
342                         {
343                             rules.add(rule);
344                         }
345                     }
346                 }
347             }
348         }
349         
350         return rules;
351     }
352     
353     /**
354      * @see org.alfresco.service.cmr.rule.RuleService#countRules(org.alfresco.service.cmr.repository.NodeRef)
355      */

356     public int countRules(NodeRef nodeRef)
357     {
358         int ruleCount = 0;
359         
360         if (this.runtimeNodeService.exists(nodeRef) == true && checkNodeType(nodeRef) == true)
361         {
362             if (this.runtimeNodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true)
363             {
364                 NodeRef ruleFolder = getSavedRuleFolderRef(nodeRef);
365                 if (ruleFolder != null)
366                 {
367                     // Get the rules for this node
368
List JavaDoc<ChildAssociationRef> ruleChildAssocRefs =
369                         this.runtimeNodeService.getChildAssocs(ruleFolder, RegexQNamePattern.MATCH_ALL, ASSOC_NAME_RULES);
370                     
371                     ruleCount = ruleChildAssocRefs.size();
372                 }
373             }
374         }
375         
376         return ruleCount;
377     }
378
379     /**
380      * Looks at the type of the node and indicates whether the node can have rules associated with it
381      *
382      * @param nodeRef the node reference
383      * @return true if the node can have rule associated with it (inherited or otherwise)
384      */

385     private boolean checkNodeType(NodeRef nodeRef)
386     {
387         boolean result = true;
388         
389         QName nodeType = this.runtimeNodeService.getType(nodeRef);
390         if (this.dictionaryService.isSubClass(nodeType, ContentModel.TYPE_SYSTEM_FOLDER) == true ||
391             this.dictionaryService.isSubClass(nodeType, ActionModel.TYPE_ACTION) == true ||
392             this.dictionaryService.isSubClass(nodeType, ActionModel.TYPE_ACTION_CONDITION) == true ||
393             this.dictionaryService.isSubClass(nodeType, ActionModel.TYPE_ACTION_PARAMETER) == true)
394         {
395             result = false;
396             
397             if (logger.isDebugEnabled() == true)
398             {
399                 logger.debug("A node of type " + nodeType.toString() + " was checked and can not have rules.");
400             }
401         }
402         
403         return result;
404     }
405     
406     /**
407      * Gets the inherited rules for a given node reference
408      *
409      * @param nodeRef the nodeRef
410      * @param ruleTypeName the rule type (null if all applicable)
411      * @return a list of inherited rules (empty if none)
412      */

413     private List JavaDoc<Rule> getInheritedRules(NodeRef nodeRef, String JavaDoc ruleTypeName, Set JavaDoc<NodeRef> visitedNodeRefs)
414     {
415         List JavaDoc<Rule> inheritedRules = new ArrayList JavaDoc<Rule>();
416         
417         // Create the visited nodes set if it has not already been created
418
if (visitedNodeRefs == null)
419         {
420             visitedNodeRefs = new HashSet JavaDoc<NodeRef>();
421         }
422         
423         // This check prevents stack over flow when we have a cyclic node graph
424
if (visitedNodeRefs.contains(nodeRef) == false)
425         {
426             visitedNodeRefs.add(nodeRef);
427             
428             List JavaDoc<Rule> allInheritedRules = new ArrayList JavaDoc<Rule>();
429             List JavaDoc<ChildAssociationRef> parents = this.runtimeNodeService.getParentAssocs(nodeRef);
430             for (ChildAssociationRef parent : parents)
431             {
432                 List JavaDoc<Rule> rules = getRules(parent.getParentRef(), false);
433                 for (Rule rule : rules)
434                 {
435                     // Add is we hanvn't already added and it should be applied to the children
436
if (rule.isAppliedToChildren() == true && allInheritedRules.contains(rule) == false)
437                     {
438                         allInheritedRules.add(rule);
439                     }
440                 }
441                 
442                 for (Rule rule : getInheritedRules(parent.getParentRef(), ruleTypeName, visitedNodeRefs))
443                 {
444                     // Ensure that we don't get any rule duplication (don't use a set cos we want to preserve order)
445
if (allInheritedRules.contains(rule) == false)
446                     {
447                         allInheritedRules.add(rule);
448                     }
449                 }
450             }
451             
452             if (ruleTypeName == null)
453             {
454                 inheritedRules = allInheritedRules;
455             }
456             else
457             {
458                 // Filter the rule list by rule type
459
for (Rule rule : allInheritedRules)
460                 {
461                     if (rule.getRuleTypeName().equals(ruleTypeName) == true)
462                     {
463                         inheritedRules.add(rule);
464                     }
465                 }
466             }
467         }
468         
469         return inheritedRules;
470     }
471
472     /**
473      * @see org.alfresco.repo.rule.RuleService#getRule(String)
474      */

475     public Rule getRule(NodeRef nodeRef, String JavaDoc ruleId)
476     {
477         Rule rule = null;
478         
479         if (this.runtimeNodeService.exists(nodeRef) == true)
480         {
481             NodeRef ruleNodeRef = getRuleNodeRefFromId(nodeRef, ruleId);
482             if (ruleNodeRef != null)
483             {
484                 rule = createRule(nodeRef, ruleNodeRef);
485             }
486         }
487         
488         return rule;
489     }
490     
491     /**
492      * Gets the rule node ref from the action id
493      *
494      * @param nodeRef the node reference
495      * @param actionId the rule id
496      * @return the rule node reference
497      */

498     private NodeRef getRuleNodeRefFromId(NodeRef nodeRef, String JavaDoc ruleId)
499     {
500         NodeRef result = null;
501         if (this.runtimeNodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true)
502         {
503             NodeRef ruleFolder = getSavedRuleFolderRef(nodeRef);
504             if (ruleFolder != null)
505             {
506                 DynamicNamespacePrefixResolver namespacePrefixResolver = new DynamicNamespacePrefixResolver();
507                 namespacePrefixResolver.registerNamespace(NamespaceService.SYSTEM_MODEL_PREFIX, NamespaceService.SYSTEM_MODEL_1_0_URI);
508                 
509                 List JavaDoc<NodeRef> nodeRefs = searchService.selectNodes(
510                         ruleFolder,
511                         "*[@sys:" + ContentModel.PROP_NODE_UUID.getLocalName() + "='" + ruleId + "']",
512                         null,
513                         namespacePrefixResolver,
514                         false);
515                 if (nodeRefs.size() != 0)
516                 {
517                     result = nodeRefs.get(0);
518                 }
519             }
520         }
521         
522         return result;
523     }
524
525     /**
526      * Create the rule object from the rule node reference
527      *
528      * @param ruleNodeRef the rule node reference
529      * @return the rule
530      */

531     private Rule createRule(NodeRef owningNodeRef, NodeRef ruleNodeRef)
532     {
533         // Get the rule properties
534
Map JavaDoc<QName, Serializable JavaDoc> props = this.nodeService.getProperties(ruleNodeRef);
535         
536         // Create the rule
537
String JavaDoc ruleTypeName = (String JavaDoc)props.get(RuleModel.PROP_RULE_TYPE);
538         Rule rule = new RuleImpl(ruleNodeRef.getId(), ruleTypeName, owningNodeRef);
539         
540         // Set the other rule properties
541
boolean isAppliedToChildren = false;
542         Boolean JavaDoc value = (Boolean JavaDoc)props.get(RuleModel.PROP_APPLY_TO_CHILDREN);
543         if (value != null)
544         {
545             isAppliedToChildren = value.booleanValue();
546         }
547         rule.applyToChildren(isAppliedToChildren);
548         
549         // Populate the composite action details
550
runtimeActionService.populateCompositeAction(ruleNodeRef, rule);
551         
552         return rule;
553     }
554
555     /**
556      * @see org.alfresco.repo.rule.RuleService#createRule(org.alfresco.repo.rule.RuleType)
557      */

558     public Rule createRule(String JavaDoc ruleTypeName)
559     {
560         // Create the new rule, giving it a unique rule id
561
String JavaDoc id = GUID.generate();
562         return new RuleImpl(id, ruleTypeName, null);
563     }
564
565     /**
566      * @see org.alfresco.repo.rule.RuleService#saveRule(org.alfresco.repo.ref.NodeRef, org.alfresco.repo.rule.Rule)
567      */

568     public void saveRule(NodeRef nodeRef, Rule rule)
569     {
570         if (this.nodeService.exists(nodeRef) == false)
571         {
572             throw new RuleServiceException("The node does not exist.");
573         }
574
575         NodeRef ruleNodeRef = getRuleNodeRefFromId(nodeRef, rule.getId());
576         if (ruleNodeRef == null)
577         {
578             if (this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == false)
579             {
580                 // Add the actionable aspect
581
this.nodeService.addAspect(nodeRef, RuleModel.ASPECT_RULES, null);
582             }
583             
584             Map JavaDoc<QName, Serializable JavaDoc> props = new HashMap JavaDoc<QName, Serializable JavaDoc>(3);
585             props.put(RuleModel.PROP_RULE_TYPE, rule.getRuleTypeName());
586             props.put(ActionModel.PROP_DEFINITION_NAME, rule.getActionDefinitionName());
587             props.put(ContentModel.PROP_NODE_UUID, rule.getId());
588             
589             // Create the action node
590
ruleNodeRef = this.nodeService.createNode(
591                     getSavedRuleFolderRef(nodeRef),
592                     ContentModel.ASSOC_CONTAINS,
593                     ASSOC_NAME_RULES,
594                     RuleModel.TYPE_RULE,
595                     props).getChildRef();
596             
597             // Update the created details
598
((RuleImpl)rule).setCreator((String JavaDoc)this.nodeService.getProperty(ruleNodeRef, ContentModel.PROP_CREATOR));
599             ((RuleImpl)rule).setCreatedDate((Date JavaDoc)this.nodeService.getProperty(ruleNodeRef, ContentModel.PROP_CREATED));
600         }
601         
602         // Update the properties of the rule
603
this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_APPLY_TO_CHILDREN, rule.isAppliedToChildren());
604         
605         // Save the remainder of the rule as a composite action
606
runtimeActionService.saveActionImpl(nodeRef, ruleNodeRef, rule);
607     }
608     
609     /**
610      * @see org.alfresco.repo.rule.RuleService#removeRule(org.alfresco.repo.ref.NodeRef, org.alfresco.repo.rule.RuleImpl)
611      */

612     public void removeRule(NodeRef nodeRef, Rule rule)
613     {
614         if (this.nodeService.exists(nodeRef) == true &&
615             this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true)
616         {
617             disableRules(nodeRef);
618             try
619             {
620                 NodeRef ruleNodeRef = getRuleNodeRefFromId(nodeRef, rule.getId());
621                 if (ruleNodeRef != null)
622                 {
623                     this.nodeService.removeChild(getSavedRuleFolderRef(nodeRef), ruleNodeRef);
624                 }
625             }
626             finally
627             {
628                 enableRules(nodeRef);
629             }
630         }
631     }
632     
633     /**
634      * @see org.alfresco.repo.rule.RuleService#removeAllRules(NodeRef)
635      */

636     public void removeAllRules(NodeRef nodeRef)
637     {
638         if (this.nodeService.exists(nodeRef) == true &&
639             this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true)
640         {
641             NodeRef folder = getSavedRuleFolderRef(nodeRef);
642             if (folder != null)
643             {
644                 List JavaDoc<ChildAssociationRef> ruleChildAssocs = this.nodeService.getChildAssocs(
645                                                                             folder,
646                                                                             RegexQNamePattern.MATCH_ALL, ASSOC_NAME_RULES);
647                 for (ChildAssociationRef ruleChildAssoc : ruleChildAssocs)
648                 {
649                     this.nodeService.removeChild(folder, ruleChildAssoc.getChildRef());
650                 }
651             }
652         }
653     }
654     
655     @SuppressWarnings JavaDoc("unchecked")
656     public void addRulePendingExecution(NodeRef actionableNodeRef, NodeRef actionedUponNodeRef, Rule rule)
657     {
658         addRulePendingExecution(actionableNodeRef, actionedUponNodeRef, rule, false);
659     }
660
661     @SuppressWarnings JavaDoc("unchecked")
662     public void addRulePendingExecution(NodeRef actionableNodeRef, NodeRef actionedUponNodeRef, Rule rule, boolean executeAtEnd)
663     {
664         // First check to see if the node has been disabled
665
if (this.disabledNodeRefs.contains(rule.getOwningNodeRef()) == false &&
666             this.disabledRules.contains(rule) == false)
667         {
668             PendingRuleData pendingRuleData = new PendingRuleData(actionableNodeRef, actionedUponNodeRef, rule, executeAtEnd);
669             Set JavaDoc<ExecutedRuleData> executedRules =
670                     (Set JavaDoc<ExecutedRuleData>) AlfrescoTransactionSupport.getResource(KEY_RULES_EXECUTED);
671             
672             if (executedRules == null || executedRules.contains(new ExecutedRuleData(actionableNodeRef, rule)) == false)
673             {
674                 Set JavaDoc<PendingRuleData> pendingRules =
675                     (Set JavaDoc<PendingRuleData>) AlfrescoTransactionSupport.getResource(KEY_RULES_PENDING);
676                 if (pendingRules == null)
677                 {
678                     // bind pending rules to the current transaction
679
pendingRules = new HashSet JavaDoc<PendingRuleData>();
680                     AlfrescoTransactionSupport.bindResource(KEY_RULES_PENDING, pendingRules);
681                     // bind the rule transaction listener
682
AlfrescoTransactionSupport.bindListener(this.ruleTransactionListener);
683                     
684                     if (logger.isDebugEnabled() == true)
685                     {
686                         logger.debug("Rule '" + rule.getTitle() + "' has been added pending execution to action upon node '" + actionedUponNodeRef.getId() + "'");
687                     }
688                 }
689                 
690                 // Prevent hte same rule being executed more than one in the same transaction
691
pendingRules.add(pendingRuleData);
692             }
693         }
694         else
695         {
696             if (logger.isDebugEnabled() == true)
697             {
698                 logger.debug("The rule '" + rule.getTitle() + "' or the node '" + rule.getOwningNodeRef().getId() + "' has been disabled.");
699             }
700         }
701     }
702
703     /**
704      * @see org.alfresco.repo.rule.RuleService#executePendingRules()
705      */

706     public void executePendingRules()
707     {
708         AlfrescoTransactionSupport.bindResource(KEY_RULES_EXECUTED, new HashSet JavaDoc<ExecutedRuleData>());
709         try
710         {
711             List JavaDoc<PendingRuleData> executeAtEndRules = new ArrayList JavaDoc<PendingRuleData>();
712             executePendingRulesImpl(executeAtEndRules);
713             for (PendingRuleData data : executeAtEndRules)
714             {
715                 executePendingRule(data);
716             }
717         }
718         finally
719         {
720             AlfrescoTransactionSupport.unbindResource(KEY_RULES_EXECUTED);
721         }
722     }
723     
724     /**
725      * Executes the pending rules, iterating until all pending rules have been executed
726      */

727     @SuppressWarnings JavaDoc("unchecked")
728     private void executePendingRulesImpl(List JavaDoc<PendingRuleData> executeAtEndRules)
729     {
730         // get the transaction-local rules to execute
731
Set JavaDoc<PendingRuleData> pendingRules =
732                 (Set JavaDoc<PendingRuleData>) AlfrescoTransactionSupport.getResource(KEY_RULES_PENDING);
733         // only execute if there are rules present
734
if (pendingRules != null && !pendingRules.isEmpty())
735         {
736             PendingRuleData[] pendingRulesArr = pendingRules.toArray(new PendingRuleData[0]);
737             // remove all pending rules from the transaction
738
AlfrescoTransactionSupport.unbindResource(KEY_RULES_PENDING);
739             // execute each rule
740
for (PendingRuleData pendingRule : pendingRulesArr)
741             {
742                 if (pendingRule.getExecuteAtEnd() == false)
743                 {
744                     executePendingRule(pendingRule);
745                 }
746                 else
747                 {
748                     executeAtEndRules.add(pendingRule);
749                 }
750             }
751             
752             // Run any rules that have been marked as pending during execution
753
executePendingRulesImpl(executeAtEndRules);
754         }
755     }
756     
757     /**
758      * Executes a pending rule
759      *
760      * @param pendingRule the pending rule data object
761      */

762     @SuppressWarnings JavaDoc("unchecked")
763     private void executePendingRule(PendingRuleData pendingRule)
764     {
765         NodeRef actionableNodeRef = pendingRule.getActionableNodeRef();
766         NodeRef actionedUponNodeRef = pendingRule.getActionedUponNodeRef();
767         Rule rule = pendingRule.getRule();
768           
769         // Evaluate the condition
770
if (this.actionService.evaluateAction(rule, actionedUponNodeRef) == true)
771         {
772             // Add the rule to the executed rule list
773
// (do this before this is executed to prevent rules being added to the pending list)
774
Set JavaDoc<ExecutedRuleData> executedRules =
775                     (Set JavaDoc<ExecutedRuleData>) AlfrescoTransactionSupport.getResource(KEY_RULES_EXECUTED);
776             executedRules.add(new ExecutedRuleData(actionableNodeRef, rule));
777             
778             // Execute the rule
779
this.actionService.executeAction(rule, actionedUponNodeRef);
780         }
781     }
782     
783     /**
784      * Register the rule type
785      *
786      * @param ruleTypeAdapter the rule type adapter
787      */

788     public void registerRuleType(RuleType ruleType)
789     {
790         this.ruleTypes.put(ruleType.getName(), ruleType);
791     }
792     
793     /**
794      * Helper class to contain the information about a rule that is executed
795      *
796      * @author Roy Wetherall
797      */

798     private class ExecutedRuleData
799     {
800
801         protected NodeRef actionableNodeRef;
802         protected Rule rule;
803         
804         public ExecutedRuleData(NodeRef actionableNodeRef, Rule rule)
805         {
806             this.actionableNodeRef = actionableNodeRef;
807             this.rule = rule;
808         }
809
810         public NodeRef getActionableNodeRef()
811         {
812             return actionableNodeRef;
813         }
814
815         public Rule getRule()
816         {
817             return rule;
818         }
819         
820         @Override JavaDoc
821         public int hashCode()
822         {
823             int i = actionableNodeRef.hashCode();
824             i = (i*37) + rule.hashCode();
825             return i;
826         }
827         
828         @Override JavaDoc
829         public boolean equals(Object JavaDoc obj)
830         {
831             if (this == obj)
832             {
833                 return true;
834             }
835             if (obj instanceof ExecutedRuleData)
836             {
837                 ExecutedRuleData that = (ExecutedRuleData) obj;
838                 return (this.actionableNodeRef.equals(that.actionableNodeRef) &&
839                         this.rule.equals(that.rule));
840             }
841             else
842             {
843                 return false;
844             }
845         }
846     }
847
848     /**
849      * Helper class to contain the information about a rule that is pending execution
850      *
851      * @author Roy Wetherall
852      */

853     private class PendingRuleData extends ExecutedRuleData
854     {
855         private NodeRef actionedUponNodeRef;
856         private boolean executeAtEnd = false;
857             
858         public PendingRuleData(NodeRef actionableNodeRef, NodeRef actionedUponNodeRef, Rule rule, boolean executeAtEnd)
859         {
860             super(actionableNodeRef, rule);
861             this.actionedUponNodeRef = actionedUponNodeRef;
862             this.executeAtEnd = executeAtEnd;
863         }
864         
865         public NodeRef getActionedUponNodeRef()
866         {
867             return actionedUponNodeRef;
868         }
869         
870         public boolean getExecuteAtEnd()
871         {
872             return this.executeAtEnd;
873         }
874         
875         @Override JavaDoc
876         public int hashCode()
877         {
878             int i = super.hashCode();
879             i = (i*37) + actionedUponNodeRef.hashCode();
880             return i;
881         }
882         
883         @Override JavaDoc
884         public boolean equals(Object JavaDoc obj)
885         {
886             if (this == obj)
887             {
888                 return true;
889             }
890             if (obj instanceof PendingRuleData)
891             {
892                 PendingRuleData that = (PendingRuleData) obj;
893                 return (this.actionableNodeRef.equals(that.actionableNodeRef) &&
894                         this.actionedUponNodeRef.equals(that.actionedUponNodeRef) &&
895                         this.rule.equals(that.rule));
896             }
897             else
898             {
899                 return false;
900             }
901         }
902     }
903 }
904
Popular Tags