View Javadoc

1   /**
2    * Copyright 2005-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.rule;
17  
18  import org.joda.time.DateTime;
19  import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
20  import org.kuali.rice.kew.api.KewApiServiceLocator;
21  import org.kuali.rice.kew.api.WorkflowRuntimeException;
22  import org.kuali.rice.kew.api.extension.ExtensionDefinition;
23  import org.kuali.rice.kew.api.extension.ExtensionUtils;
24  import org.kuali.rice.kew.api.rule.RuleTemplate;
25  import org.kuali.rice.kew.api.rule.RuleTemplateAttribute;
26  import org.kuali.rice.kew.engine.RouteContext;
27  import org.kuali.rice.kew.engine.node.RouteNodeInstance;
28  import org.kuali.rice.kew.framework.KewFrameworkServiceLocator;
29  import org.kuali.rice.kew.framework.rule.attribute.WorkflowRuleAttributeHandlerService;
30  import org.kuali.rice.kew.routeheader.DocumentContent;
31  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
32  import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
33  import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
34  import org.kuali.rice.kew.service.KEWServiceLocator;
35  import org.kuali.rice.kew.util.PerformanceLogger;
36  
37  import java.sql.Timestamp;
38  import java.util.ArrayList;
39  import java.util.Collections;
40  import java.util.HashSet;
41  import java.util.List;
42  import java.util.Set;
43  
44  /**
45   * Rule selector that selects rules based on configured template name 
46   * @author Kuali Rice Team (rice.collab@kuali.org)
47   */
48  class TemplateRuleSelector implements RuleSelector {
49      /**
50       * Records the number of selected rules, prior to MassRuleAttribute filtering
51       */
52      private int numberOfSelectedRules;
53  
54      /**
55       * @return the number of selected rules, prior to MassRuleAttribute filtering
56       */
57      int getNumberOfSelectedRules() {
58  	return numberOfSelectedRules;
59      }
60  
61      public List<Rule> selectRules(RouteContext context, DocumentRouteHeaderValue routeHeader, RouteNodeInstance nodeInstance, String selectionCriterion, Timestamp effectiveDate) {
62          // for TemplateRuleSelector, the criterion is taken as a ruletemplate name
63          final String ruleTemplateName = selectionCriterion;
64  
65          Set<MassRuleAttribute> massRules = new HashSet<MassRuleAttribute>();
66          RuleTemplate template = KewApiServiceLocator.getRuleService().getRuleTemplateByName(ruleTemplateName);
67          if (template == null) {
68              throw new WorkflowRuntimeException("Could not locate the rule template with name " + ruleTemplateName + " on document " + routeHeader.getDocumentId());
69          }
70          for (RuleTemplateAttribute templateAttribute : template.getActiveRuleTemplateAttributes()) {
71              String ruleAttributeName = templateAttribute.getRuleAttribute().getName();
72              WorkflowRuleAttributeHandlerService wrahs = KewFrameworkServiceLocator.getWorkflowRuleAttributeHandlerService();
73              if (!wrahs.isWorkflowRuleAttribute(ruleAttributeName)) {
74                  continue;
75              }
76              ExtensionDefinition extensionDefinition = KewApiServiceLocator.getExtensionRepositoryService().getExtensionByName(ruleAttributeName);
77              Object attribute = ExtensionUtils.loadExtension(extensionDefinition);
78              if (attribute == null) {
79                  throw new RiceIllegalArgumentException("Failed to load WorkflowRuleAttribute for: " + extensionDefinition);
80              }
81              if (!WorkflowRuleAttribute.class.isAssignableFrom(attribute.getClass())) {
82                  throw new RiceIllegalArgumentException("Failed to locate a WorkflowRuleAttribute with the given name: " + ruleAttributeName);
83              }
84              if (attribute instanceof XmlConfiguredAttribute) {
85                  ((XmlConfiguredAttribute)attribute).setExtensionDefinition(extensionDefinition);
86              }
87  
88              WorkflowRuleAttribute ruleAttribute = (WorkflowRuleAttribute)attribute;
89              if (ruleAttribute instanceof MassRuleAttribute) {
90                  massRules.add((MassRuleAttribute) attribute);
91              }
92  
93          }
94  
95          List<org.kuali.rice.kew.api.rule.Rule> rules = Collections.emptyList();
96          if (effectiveDate == null) {
97              rules = KewApiServiceLocator.getRuleService()
98                      .getRulesByTemplateNameAndDocumentTypeName(ruleTemplateName,
99                              routeHeader.getDocumentType().getName());
100         } else {
101             rules = KewApiServiceLocator.getRuleService()
102                     .getRulesByTemplateNameAndDocumentTypeNameAndEffectiveDate(ruleTemplateName,
103                             routeHeader.getDocumentType().getName(), new DateTime(effectiveDate.getTime()));
104         }
105         numberOfSelectedRules = rules.size();
106 
107         // TODO really the route context just needs to be able to support nested create and clears
108         // (i.e. a Stack model similar to transaction intercepting in Spring) and we wouldn't have to do this
109         if (context.getDocument() == null) {
110             context.setDocument(routeHeader);
111         }
112         if (context.getNodeInstance() == null) {
113             context.setNodeInstance(nodeInstance);
114         }
115         DocumentContent documentContent = context.getDocumentContent();
116         PerformanceLogger performanceLogger = new PerformanceLogger();
117         // have all mass rule attributes filter the list of non applicable rules
118         for (MassRuleAttribute massRuleAttribute : massRules) {
119             rules = massRuleAttribute.filterNonMatchingRules(context, rules);
120         }
121         performanceLogger.log("Time to filter massRules for template " + template.getName());
122 
123         List<Rule> ruleList = new ArrayList<Rule>(rules.size());
124         for (org.kuali.rice.kew.api.rule.Rule ruleDefinition: rules) {
125             ruleList.add(new RuleImpl(ruleDefinition));
126         }
127         return ruleList;
128     }
129 
130 }