001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.core.service.impl;
017:
018: import java.util.ArrayList;
019: import java.util.Iterator;
020: import java.util.List;
021:
022: import org.apache.commons.lang.StringUtils;
023: import org.apache.log4j.Logger;
024: import org.kuali.RiceConstants;
025: import org.kuali.core.bo.AdHocRoutePerson;
026: import org.kuali.core.bo.AdHocRouteWorkgroup;
027: import org.kuali.core.document.Document;
028: import org.kuali.core.document.MaintenanceDocument;
029: import org.kuali.core.document.TransactionalDocument;
030: import org.kuali.core.exceptions.InfrastructureException;
031: import org.kuali.core.rule.BusinessRule;
032: import org.kuali.core.rule.event.AddAdHocRoutePersonEvent;
033: import org.kuali.core.rule.event.AddAdHocRouteWorkgroupEvent;
034: import org.kuali.core.rule.event.KualiDocumentEvent;
035: import org.kuali.core.service.DataDictionaryService;
036: import org.kuali.core.service.DictionaryValidationService;
037: import org.kuali.core.service.KualiRuleService;
038: import org.kuali.core.service.MaintenanceDocumentDictionaryService;
039: import org.kuali.core.service.TransactionalDocumentDictionaryService;
040: import org.kuali.core.util.ErrorMap;
041: import org.kuali.core.util.GlobalVariables;
042: import org.springframework.transaction.annotation.Transactional;
043:
044: /**
045: * This class represents a rule evaluator for Kuali. This class is to be used for evaluating business rule checks. The class defines
046: * one method right now - applyRules() which takes in a Document and a DocumentEvent and does the proper business rule checks based
047: * on the context of the event and the document type.
048: */
049: @Transactional
050: public class KualiRuleServiceImpl implements KualiRuleService {
051: private static final Logger LOG = Logger
052: .getLogger(KualiRuleServiceImpl.class);
053:
054: private TransactionalDocumentDictionaryService transactionalDocumentDictionaryService;
055: private MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
056: private DictionaryValidationService dictionaryValidationService;
057: private DataDictionaryService dataDictionaryService;
058:
059: /**
060: * @see org.kuali.core.service.KualiRuleService#applyRules(org.kuali.core.rule.event.KualiDocumentEvent)
061: */
062: public boolean applyRules(KualiDocumentEvent event) {
063: if (event == null) {
064: throw new IllegalArgumentException("invalid (null) event");
065: }
066:
067: event.validate();
068: LOG.debug("calling applyRules for event " + event);
069:
070: BusinessRule rule = (BusinessRule) getBusinessRulesInstance(
071: event.getDocument(), event.getRuleInterfaceClass());
072:
073: boolean success = true;
074: if (rule != null) {
075: LOG.debug("processing " + event.getName() + " with rule "
076: + rule.getClass().getName());
077: increaseErrorPath(event.getErrorPathPrefix());
078:
079: // get any child events and apply rules
080: List events = event.generateEvents();
081: for (Iterator iter = events.iterator(); iter.hasNext();) {
082: KualiDocumentEvent element = (KualiDocumentEvent) iter
083: .next();
084: success &= applyRules(element);
085: }
086:
087: // now call the event rule method
088: success &= event.invokeRuleMethod(rule);
089:
090: decreaseErrorPath(event.getErrorPathPrefix());
091:
092: // report failures
093: if (!success) {
094: LOG.error(event.getName() + " businessRule "
095: + rule.getClass().getName() + " failed");
096: } else {
097: LOG.debug("processed " + event.getName() + " for rule "
098: + rule.getClass().getName());
099: }
100:
101: }
102: return success;
103: }
104:
105: /**
106: * Builds a list containing AddAdHocRoutePersonEvents since the validation done for an AdHocRouteRecipient is the same for all
107: * events.
108: *
109: * @see org.kuali.core.service.KualiRuleService#generateAdHocRoutePersonEvents(org.kuali.core.document.Document)
110: */
111: public List generateAdHocRoutePersonEvents(Document document) {
112: List adHocRoutePersons = document.getAdHocRoutePersons();
113:
114: List events = new ArrayList();
115:
116: for (int i = 0; i < adHocRoutePersons.size(); i++) {
117: events
118: .add(new AddAdHocRoutePersonEvent(
119: RiceConstants.EXISTING_AD_HOC_ROUTE_PERSON_PROPERTY_NAME
120: + "[" + i + "]", document,
121: (AdHocRoutePerson) 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.core.service.KualiRuleService#generateAdHocRouteWorkgroupEvents(org.kuali.core.document.Document)
132: */
133: public List generateAdHocRouteWorkgroupEvents(Document document) {
134: List adHocRouteWorkgroups = document.getAdHocRouteWorkgroups();
135:
136: List events = new ArrayList();
137:
138: for (int i = 0; i < adHocRouteWorkgroups.size(); i++) {
139: events
140: .add(new AddAdHocRouteWorkgroupEvent(
141: RiceConstants.EXISTING_AD_HOC_ROUTE_WORKGROUP_PROPERTY_NAME
142: + "[" + i + "]", document,
143: (AdHocRouteWorkgroup) adHocRouteWorkgroups
144: .get(i)));
145: }
146:
147: return events;
148: }
149:
150: /**
151: * @param document
152: * @param ruleInterface
153: * @return instance of the businessRulesClass for the given document's type, if that businessRulesClass implements the given
154: * ruleInterface
155: */
156: public BusinessRule getBusinessRulesInstance(Document document,
157: Class ruleInterface) {
158: // get the businessRulesClass
159: Class businessRulesClass = null;
160: if (document instanceof TransactionalDocument) {
161: TransactionalDocument transactionalDocument = (TransactionalDocument) document;
162:
163: businessRulesClass = transactionalDocumentDictionaryService
164: .getBusinessRulesClass(transactionalDocument);
165: }
166: // else if (document instanceof AccountingDocument) {
167: // AccountingDocument financialDocument = (AccountingDocument) document;
168: //
169: // businessRulesClass = transactionalDocumentDictionaryService.getBusinessRulesClass(financialDocument);
170: // }
171: else if (document instanceof MaintenanceDocument) {
172: MaintenanceDocument maintenanceDocument = (MaintenanceDocument) document;
173:
174: businessRulesClass = maintenanceDocumentDictionaryService
175: .getBusinessRulesClass(maintenanceDocument);
176: } else {
177: LOG
178: .error("unable to get businessRulesClass for unknown document type '"
179: + document.getClass().getName() + "'");
180: }
181:
182: // instantiate and return it if it implements the given ruleInterface
183: BusinessRule rule = null;
184: if (businessRulesClass != null) {
185: try {
186: if (ruleInterface.isAssignableFrom(businessRulesClass)) {
187: rule = (BusinessRule) businessRulesClass
188: .newInstance();
189: }
190: } catch (IllegalAccessException e) {
191: throw new InfrastructureException(
192: "error processing business rules", e);
193: } catch (InstantiationException e) {
194: throw new InfrastructureException(
195: "error processing business rules", e);
196: }
197: }
198:
199: return rule;
200: }
201:
202: /**
203: * This method increases the registered error path, so that field highlighting can occur on the appropriate object attribute.
204: *
205: * @param errorPathPrefix
206: */
207: private void increaseErrorPath(String errorPathPrefix) {
208: ErrorMap errorMap = GlobalVariables.getErrorMap();
209:
210: if (!StringUtils.isBlank(errorPathPrefix)) {
211: errorMap.addToErrorPath(errorPathPrefix);
212: }
213: }
214:
215: /**
216: * This method decreases the registered error path, so that field highlighting can occur on the appropriate object attribute.
217: *
218: * @param errorPathPrefix
219: */
220: private void decreaseErrorPath(String errorPathPrefix) {
221: ErrorMap errorMap = GlobalVariables.getErrorMap();
222:
223: if (!StringUtils.isBlank(errorPathPrefix)) {
224: errorMap.removeFromErrorPath(errorPathPrefix);
225: }
226: }
227:
228: /* Spring service injection */
229:
230: /**
231: * @param maintenanceDocumentDictionaryService
232: */
233: public void setMaintenanceDocumentDictionaryService(
234: MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService) {
235: this .maintenanceDocumentDictionaryService = maintenanceDocumentDictionaryService;
236: }
237:
238: /**
239: * @return MaintenanceDocumentDictionaryService
240: */
241: public MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
242: return maintenanceDocumentDictionaryService;
243: }
244:
245: /**
246: * @param transactionalDocumentDictionaryService
247: */
248: public void setTransactionalDocumentDictionaryService(
249: TransactionalDocumentDictionaryService transactionalDocumentDictionaryService) {
250: this .transactionalDocumentDictionaryService = transactionalDocumentDictionaryService;
251: }
252:
253: /**
254: * @return TransactionalDocumentDictionaryService
255: */
256: public TransactionalDocumentDictionaryService getTransactionalDocumentDictionaryService() {
257: return transactionalDocumentDictionaryService;
258: }
259:
260: /**
261: * @return DictionaryValidationService
262: */
263: public DictionaryValidationService getDictionaryValidationService() {
264: return dictionaryValidationService;
265: }
266:
267: /**
268: * @param dictionaryValidationService
269: */
270: public void setDictionaryValidationService(
271: DictionaryValidationService dictionaryValidationService) {
272: this .dictionaryValidationService = dictionaryValidationService;
273: }
274:
275: /**
276: * @return DataDictionaryService
277: */
278: public DataDictionaryService getDataDictionaryService() {
279: return dataDictionaryService;
280: }
281:
282: /**
283: * @param dataDictionaryService
284: */
285: public void setDataDictionaryService(
286: DataDictionaryService dataDictionaryService) {
287: this.dataDictionaryService = dataDictionaryService;
288: }
289: }
|