View Javadoc

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