View Javadoc

1   /*
2    * Copyright 2005-2008 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.kns.service.impl;
17  
18  import java.util.ArrayList;
19  import java.util.Iterator;
20  import java.util.List;
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.apache.log4j.Logger;
24  import org.kuali.rice.kns.bo.AdHocRoutePerson;
25  import org.kuali.rice.kns.bo.AdHocRouteWorkgroup;
26  import org.kuali.rice.kns.document.Document;
27  import org.kuali.rice.kns.document.MaintenanceDocument;
28  import org.kuali.rice.kns.document.TransactionalDocument;
29  import org.kuali.rice.kns.exception.InfrastructureException;
30  import org.kuali.rice.kns.rule.BusinessRule;
31  import org.kuali.rice.kns.rule.event.AddAdHocRoutePersonEvent;
32  import org.kuali.rice.kns.rule.event.AddAdHocRouteWorkgroupEvent;
33  import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
34  import org.kuali.rice.kns.service.DataDictionaryService;
35  import org.kuali.rice.kns.service.DictionaryValidationService;
36  import org.kuali.rice.kns.service.KualiRuleService;
37  import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
38  import org.kuali.rice.kns.service.TransactionalDocumentDictionaryService;
39  import org.kuali.rice.kns.util.GlobalVariables;
40  import org.kuali.rice.kns.util.KNSConstants;
41  import org.kuali.rice.kns.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 TransactionalDocumentDictionaryService transactionalDocumentDictionaryService;
52      private MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
53      private DictionaryValidationService dictionaryValidationService;
54      private DataDictionaryService dataDictionaryService;
55  
56      /**
57       * @see org.kuali.rice.kns.service.KualiRuleService#applyRules(org.kuali.rice.kns.rule.event.KualiDocumentEvent)
58       */
59      public boolean applyRules(KualiDocumentEvent event) {
60          if (event == null) {
61              throw new IllegalArgumentException("invalid (null) event");
62          }
63  
64          event.validate();
65          if ( LOG.isDebugEnabled() ) {
66          	LOG.debug("calling applyRules for event " + event);
67          }
68  
69          BusinessRule rule = (BusinessRule) getBusinessRulesInstance(event.getDocument(), event.getRuleInterfaceClass());
70  
71          boolean success = true;
72          if (rule != null) {
73          	if ( LOG.isDebugEnabled() ) {	
74          		LOG.debug("processing " + event.getName() + " with rule " + rule.getClass().getName());
75          	}
76              increaseErrorPath(event.getErrorPathPrefix());
77  
78              // get any child events and apply rules
79              List events = event.generateEvents();
80              for (Iterator iter = events.iterator(); iter.hasNext();) {
81                  KualiDocumentEvent element = (KualiDocumentEvent) iter.next();
82                  success &= applyRules(element);
83              }
84  
85              // now call the event rule method
86              success &= event.invokeRuleMethod(rule);
87  
88              decreaseErrorPath(event.getErrorPathPrefix());
89  
90              // report failures
91              if (!success) {
92              	if ( LOG.isDebugEnabled() ) { // NO, this is not a type - only log if in debug mode - this is not an error in production
93              		LOG.error(event.getName() + " businessRule " + rule.getClass().getName() + " failed");
94              	}
95              }
96              else {
97              	if ( LOG.isDebugEnabled() ) {
98              		LOG.debug("processed " + event.getName() + " for rule " + rule.getClass().getName());
99              	}
100             }
101 
102         }
103         return success;
104     }
105 
106     /**
107      * Builds a list containing AddAdHocRoutePersonEvents since the validation done for an AdHocRouteRecipient is the same for all
108      * events.
109      * 
110      * @see org.kuali.rice.kns.service.KualiRuleService#generateAdHocRoutePersonEvents(org.kuali.rice.kns.document.Document)
111      */
112     public List generateAdHocRoutePersonEvents(Document document) {
113         List adHocRoutePersons = document.getAdHocRoutePersons();
114 
115         List events = new ArrayList();
116 
117         for (int i = 0; i < adHocRoutePersons.size(); i++) {
118             events.add(new AddAdHocRoutePersonEvent(KNSConstants.EXISTING_AD_HOC_ROUTE_PERSON_PROPERTY_NAME + "[" + i + "]", document, (AdHocRoutePerson) adHocRoutePersons.get(i)));
119         }
120 
121         return events;
122     }
123 
124     /**
125      * Builds a list containing AddAdHocRoutePersonEvents since the validation done for an AdHocRouteRecipient is the same for all
126      * events.
127      * 
128      * @see org.kuali.rice.kns.service.KualiRuleService#generateAdHocRouteWorkgroupEvents(org.kuali.rice.kns.document.Document)
129      */
130     public List generateAdHocRouteWorkgroupEvents(Document document) {
131         List adHocRouteWorkgroups = document.getAdHocRouteWorkgroups();
132 
133         List events = new ArrayList();
134 
135         for (int i = 0; i < adHocRouteWorkgroups.size(); i++) {
136             events.add(new AddAdHocRouteWorkgroupEvent(KNSConstants.EXISTING_AD_HOC_ROUTE_WORKGROUP_PROPERTY_NAME + "[" + i + "]", document, (AdHocRouteWorkgroup) adHocRouteWorkgroups.get(i)));
137         }
138 
139         return events;
140     }
141     
142 
143 
144 
145 
146 
147     /**
148      * @param document
149      * @param ruleInterface
150      * @return instance of the businessRulesClass for the given document's type, if that businessRulesClass implements the given
151      *         ruleInterface
152      */
153     public BusinessRule getBusinessRulesInstance(Document document, Class ruleInterface) {
154         // get the businessRulesClass
155         Class businessRulesClass = null;
156         if (document instanceof TransactionalDocument) {
157             TransactionalDocument transactionalDocument = (TransactionalDocument) document;
158 
159             businessRulesClass = transactionalDocumentDictionaryService.getBusinessRulesClass(transactionalDocument);
160         }
161         else if (document instanceof MaintenanceDocument) {
162             MaintenanceDocument maintenanceDocument = (MaintenanceDocument) document;
163 
164             businessRulesClass = maintenanceDocumentDictionaryService.getBusinessRulesClass(maintenanceDocument);
165         }
166         else {
167             LOG.error("unable to get businessRulesClass for unknown document type '" + document.getClass().getName() + "'");
168         }
169 
170         // instantiate and return it if it implements the given ruleInterface
171         BusinessRule rule = null;
172         if (businessRulesClass != null) {
173             try {
174                 if (ruleInterface.isAssignableFrom(businessRulesClass)) {
175                     rule = (BusinessRule) businessRulesClass.newInstance();
176                 }
177             }
178             catch (IllegalAccessException e) {
179                 throw new InfrastructureException("error processing business rules", e);
180             }
181             catch (InstantiationException e) {
182                 throw new InfrastructureException("error processing business rules", e);
183             }
184         }
185 
186         return rule;
187     }
188 
189     /**
190      * This method increases the registered error path, so that field highlighting can occur on the appropriate object attribute.
191      * 
192      * @param errorPathPrefix
193      */
194     private void increaseErrorPath(String errorPathPrefix) {
195         MessageMap errorMap = GlobalVariables.getMessageMap();
196 
197         if (!StringUtils.isBlank(errorPathPrefix)) {
198             errorMap.addToErrorPath(errorPathPrefix);
199         }
200     }
201 
202     /**
203      * This method decreases the registered error path, so that field highlighting can occur on the appropriate object attribute.
204      * 
205      * @param errorPathPrefix
206      */
207     private void decreaseErrorPath(String errorPathPrefix) {
208         MessageMap errorMap = GlobalVariables.getMessageMap();
209 
210         if (!StringUtils.isBlank(errorPathPrefix)) {
211             errorMap.removeFromErrorPath(errorPathPrefix);
212         }
213     }
214 
215     /* Spring service injection */
216 
217     /**
218      * @param maintenanceDocumentDictionaryService
219      */
220     public void setMaintenanceDocumentDictionaryService(MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService) {
221         this.maintenanceDocumentDictionaryService = maintenanceDocumentDictionaryService;
222     }
223 
224     /**
225      * @return MaintenanceDocumentDictionaryService
226      */
227     public MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
228         return maintenanceDocumentDictionaryService;
229     }
230 
231     /**
232      * @param transactionalDocumentDictionaryService
233      */
234     public void setTransactionalDocumentDictionaryService(TransactionalDocumentDictionaryService transactionalDocumentDictionaryService) {
235         this.transactionalDocumentDictionaryService = transactionalDocumentDictionaryService;
236     }
237 
238     /**
239      * @return TransactionalDocumentDictionaryService
240      */
241     public TransactionalDocumentDictionaryService getTransactionalDocumentDictionaryService() {
242         return transactionalDocumentDictionaryService;
243     }
244 
245     /**
246      * @return DictionaryValidationService
247      */
248     public DictionaryValidationService getDictionaryValidationService() {
249         return dictionaryValidationService;
250     }
251 
252     /**
253      * @param dictionaryValidationService
254      */
255     public void setDictionaryValidationService(DictionaryValidationService dictionaryValidationService) {
256         this.dictionaryValidationService = dictionaryValidationService;
257     }
258 
259     /**
260      * @return DataDictionaryService
261      */
262     public DataDictionaryService getDataDictionaryService() {
263         return dataDictionaryService;
264     }
265 
266     /**
267      * @param dataDictionaryService
268      */
269     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
270         this.dataDictionaryService = dataDictionaryService;
271     }
272 }