View Javadoc

1   /**
2    * Copyright 2005-2013 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.krad.service.impl;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.apache.commons.lang.StringUtils;
22  import org.apache.log4j.Logger;
23  import org.kuali.rice.krad.bo.AdHocRoutePerson;
24  import org.kuali.rice.krad.bo.AdHocRouteWorkgroup;
25  import org.kuali.rice.krad.document.Document;
26  import org.kuali.rice.krad.maintenance.MaintenanceDocument;
27  import org.kuali.rice.krad.document.TransactionalDocument;
28  import org.kuali.rice.krad.exception.InfrastructureException;
29  import org.kuali.rice.krad.rules.MaintenanceDocumentRuleBase;
30  import org.kuali.rice.krad.rules.TransactionalDocumentRuleBase;
31  import org.kuali.rice.krad.rules.rule.BusinessRule;
32  import org.kuali.rice.krad.rules.rule.event.AddAdHocRoutePersonEvent;
33  import org.kuali.rice.krad.rules.rule.event.AddAdHocRouteWorkgroupEvent;
34  import org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent;
35  import org.kuali.rice.krad.service.DataDictionaryService;
36  import org.kuali.rice.krad.service.DocumentDictionaryService;
37  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
38  import org.kuali.rice.krad.service.KualiRuleService;
39  import org.kuali.rice.krad.util.GlobalVariables;
40  import org.kuali.rice.krad.util.KRADConstants;
41  import org.kuali.rice.krad.util.MessageMap;
42  
43  /**
44   * This class represents a rule evaluator for Kuali. This class is to be used for evaluating business rule checks. The class defines
45   * one method right now - applyRules() which takes in a Document and a DocumentEvent and does the proper business rule checks based
46   * on the context of the event and the document type.
47   */
48  public class KualiRuleServiceImpl implements KualiRuleService {
49      private static final Logger LOG = Logger.getLogger(KualiRuleServiceImpl.class);
50  
51      private DocumentDictionaryService documentDictionaryService;
52      private DataDictionaryService dataDictionaryService;
53  
54      /**
55       * @see org.kuali.rice.krad.service.KualiRuleService#applyRules(org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent)
56       */
57      public boolean applyRules(KualiDocumentEvent event) {
58          if (event == null) {
59              throw new IllegalArgumentException("invalid (null) event");
60          }
61  
62          event.validate();
63          if ( LOG.isDebugEnabled() ) {
64          	LOG.debug("calling applyRules for event " + event);
65          }
66  
67          BusinessRule rule = getBusinessRulesInstance(event.getDocument(), event.getRuleInterfaceClass());
68  
69          boolean success = true;
70          if (rule != null) {
71          	if ( LOG.isDebugEnabled() ) {	
72          		LOG.debug("processing " + event.getName() + " with rule " + rule.getClass().getName());
73          	}
74              increaseErrorPath(event.getErrorPathPrefix());
75  
76              // get any child events and apply rules
77              List<KualiDocumentEvent> events = event.generateEvents();
78              for (KualiDocumentEvent generatedEvent : events) {
79                  success &= applyRules(generatedEvent);
80              }
81  
82              // now call the event rule method
83              success &= event.invokeRuleMethod(rule);
84  
85              decreaseErrorPath(event.getErrorPathPrefix());
86  
87              // KULRICE-7930  Check for field validation errors
88              if(GlobalVariables.getMessageMap().hasErrors()) {
89                 success = false;
90              }
91  
92              // report failures
93              if (!success) {
94              	if ( LOG.isDebugEnabled() ) { // NO, this is not a type - only log if in debug mode - this is not an error in production
95              		LOG.debug(event.getName() + " businessRule " + rule.getClass().getName() + " failed");
96              	}
97              }
98              else {
99              	if ( LOG.isDebugEnabled() ) {
100             		LOG.debug("processed " + event.getName() + " for rule " + rule.getClass().getName());
101             	}
102             }
103 
104         }
105         return success;
106     }
107 
108     /**
109      * Builds a list containing AddAdHocRoutePersonEvents since the validation done for an AdHocRouteRecipient is the same for all
110      * events.
111      * 
112      * @see org.kuali.rice.krad.service.KualiRuleService#generateAdHocRoutePersonEvents(org.kuali.rice.krad.document.Document)
113      */
114     public List<AddAdHocRoutePersonEvent> generateAdHocRoutePersonEvents(Document document) {
115         List<AdHocRoutePerson> adHocRoutePersons = document.getAdHocRoutePersons();
116 
117         List<AddAdHocRoutePersonEvent> events = new ArrayList<AddAdHocRoutePersonEvent>();
118 
119         for (int i = 0; i < adHocRoutePersons.size(); i++) {
120             events.add(new AddAdHocRoutePersonEvent(
121                     KRADConstants.EXISTING_AD_HOC_ROUTE_PERSON_PROPERTY_NAME + "[" + i + "]", document, adHocRoutePersons.get(i)));
122         }
123 
124         return events;
125     }
126 
127     /**
128      * Builds a list containing AddAdHocRoutePersonEvents since the validation done for an AdHocRouteRecipient is the same for all
129      * events.
130      * 
131      * @see org.kuali.rice.krad.service.KualiRuleService#generateAdHocRouteWorkgroupEvents(org.kuali.rice.krad.document.Document)
132      */
133     public List<AddAdHocRouteWorkgroupEvent> generateAdHocRouteWorkgroupEvents(Document document) {
134         List<AdHocRouteWorkgroup> adHocRouteWorkgroups = document.getAdHocRouteWorkgroups();
135 
136         List<AddAdHocRouteWorkgroupEvent> events = new ArrayList<AddAdHocRouteWorkgroupEvent>();
137 
138         for (int i = 0; i < adHocRouteWorkgroups.size(); i++) {
139             events.add(new AddAdHocRouteWorkgroupEvent(
140                     KRADConstants.EXISTING_AD_HOC_ROUTE_WORKGROUP_PROPERTY_NAME + "[" + i + "]", document, adHocRouteWorkgroups.get(i)));
141         }
142 
143         return events;
144     }
145     
146 
147 
148 
149 
150 
151     /**
152      * @param document
153      * @param ruleInterface
154      * @return instance of the businessRulesClass for the given document's type, if that businessRulesClass implements the given
155      *         ruleInterface
156      */
157     public BusinessRule getBusinessRulesInstance(Document document, Class<? extends BusinessRule> ruleInterface) {
158         // get the businessRulesClass
159         Class<? extends BusinessRule> businessRulesClass = null;
160         if (document instanceof TransactionalDocument) {
161             TransactionalDocument transactionalDocument = (TransactionalDocument) document;
162 
163             businessRulesClass = getDocumentDictionaryService().getBusinessRulesClass(transactionalDocument);
164             if (businessRulesClass == null) {
165                 return new TransactionalDocumentRuleBase(); // default to a generic rule that will enforce Required fields
166             }
167         }
168         else if (document instanceof MaintenanceDocument) {
169             MaintenanceDocument maintenanceDocument = (MaintenanceDocument) document;
170 
171             businessRulesClass = getDocumentDictionaryService().getBusinessRulesClass(maintenanceDocument);
172             if (businessRulesClass == null) {
173                 return new MaintenanceDocumentRuleBase(); // default to a generic rule that will enforce Required fields
174             }
175         }
176         else {
177             LOG.error("unable to get businessRulesClass for unknown document type '" + document.getClass().getName() + "'");
178         }
179 
180         // instantiate and return it if it implements the given ruleInterface
181         BusinessRule rule = null;
182         if (businessRulesClass != null) {
183             try {
184                 if (ruleInterface.isAssignableFrom(businessRulesClass)) {
185                     rule = businessRulesClass.newInstance();
186                 }
187             }
188             catch (IllegalAccessException e) {
189                 throw new InfrastructureException("error processing business rules", e);
190             }
191             catch (InstantiationException e) {
192                 throw new InfrastructureException("error processing business rules", e);
193             }
194         }
195 
196         return rule;
197     }
198 
199     /**
200      * This method increases the registered error path, so that field highlighting can occur on the appropriate object attribute.
201      * 
202      * @param errorPathPrefix
203      */
204     private void increaseErrorPath(String errorPathPrefix) {
205         MessageMap errorMap = GlobalVariables.getMessageMap();
206 
207         if (!StringUtils.isBlank(errorPathPrefix)) {
208             errorMap.addToErrorPath(errorPathPrefix);
209         }
210     }
211 
212     /**
213      * This method decreases the registered error path, so that field highlighting can occur on the appropriate object attribute.
214      * 
215      * @param errorPathPrefix
216      */
217     private void decreaseErrorPath(String errorPathPrefix) {
218         MessageMap errorMap = GlobalVariables.getMessageMap();
219 
220         if (!StringUtils.isBlank(errorPathPrefix)) {
221             errorMap.removeFromErrorPath(errorPathPrefix);
222         }
223     }
224 
225     public DocumentDictionaryService getDocumentDictionaryService() {
226         if (documentDictionaryService == null) {
227             this.documentDictionaryService = KRADServiceLocatorWeb.getDocumentDictionaryService();
228         }
229         return documentDictionaryService;
230     }
231 
232     public void setDocumentDictionaryService(DocumentDictionaryService documentDictionaryService) {
233         this.documentDictionaryService = documentDictionaryService;
234     }
235 
236     public DataDictionaryService getDataDictionaryService() {
237         return dataDictionaryService;
238     }
239 
240     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
241         this.dataDictionaryService = dataDictionaryService;
242     }
243 }