001/* 002 * Copyright 2008 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.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/ecl2.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 */ 016package org.kuali.ole.sys.document.validation.impl; 017 018import java.lang.reflect.InvocationTargetException; 019import java.util.LinkedList; 020import java.util.Queue; 021 022import org.apache.commons.beanutils.PropertyUtils; 023import org.apache.commons.lang.StringUtils; 024import org.kuali.ole.sys.businessobject.AccountingLine; 025import org.kuali.ole.sys.businessobject.SourceAccountingLine; 026import org.kuali.ole.sys.context.SpringContext; 027import org.kuali.ole.sys.document.AccountingDocument; 028import org.kuali.ole.sys.document.validation.GenericValidation; 029import org.kuali.ole.sys.document.validation.event.AttributedDocumentEvent; 030import org.kuali.ole.sys.service.impl.OleParameterConstants; 031import org.kuali.rice.core.api.parameter.ParameterEvaluatorService; 032import org.kuali.rice.coreservice.framework.parameter.ParameterService; 033import org.kuali.rice.krad.bo.PersistableBusinessObject; 034import org.kuali.rice.krad.util.ObjectUtils; 035 036/** 037 * A validation which uses parameters to determine if a value on an accounting line is valid. 038 */ 039public class AccountingLineValueAllowedValidation extends GenericValidation { 040 protected String propertyPath; 041 protected String parameterToCheckAgainst; 042 protected ParameterService parameterService; 043 protected String responsibleProperty; 044 protected AccountingDocument accountingDocumentForValidation; 045 protected AccountingLine accountingLineForValidation; 046 047 /** 048 * Checks if a value in a given accounting line is allowed, based on system parameters. 049 * <strong>Expects an accounting document as the first parameter and accounting line as the second</strong> 050 * @see org.kuali.ole.sys.document.validation.GenericValidation#validate(java.lang.Object[]) 051 */ 052 public boolean validate(AttributedDocumentEvent event) { 053 054 if (!StringUtils.isBlank(propertyPath)) { 055 refreshByPath(accountingLineForValidation); 056 } 057 058 return isAccountingLineValueAllowed(accountingDocumentForValidation.getDocumentClassForAccountingLineValueAllowedValidation(), accountingLineForValidation, parameterToCheckAgainst, propertyPath, (responsibleProperty != null ? responsibleProperty : propertyPath)); 059 } 060 061 /** 062 * Checks that a value on an accounting line is valid, based on parameters, for a document of the given class 063 * @param documentClass the class of the document to check 064 * @param accountingLine the accounting line to check 065 * @param parameterName the name of the parameter to check 066 * @param propertyName the name of the property to check 067 * @param userEnteredPropertyName the value the user entered on the line 068 * @return true if this passes validation, false otherwise 069 */ 070 protected boolean isAccountingLineValueAllowed(Class documentClass, AccountingLine accountingLine, String parameterName, String propertyName, String userEnteredPropertyName) { 071 boolean isAllowed = true; 072 String exceptionMessage = "Invalue property name provided to AccountingDocumentRuleBase isAccountingLineValueAllowed method: " + propertyName; 073 try { 074 String propertyValue = (String) PropertyUtils.getProperty(accountingLine, propertyName); 075 if (getParameterService().parameterExists(OleParameterConstants.FINANCIAL_PROCESSING_DOCUMENT.class, parameterName)) { 076 isAllowed = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(OleParameterConstants.FINANCIAL_PROCESSING_DOCUMENT.class, parameterName, propertyValue).evaluateAndAddError(SourceAccountingLine.class, propertyName, userEnteredPropertyName); 077 } 078 if (getParameterService().parameterExists(documentClass, parameterName)) { 079 isAllowed = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(documentClass, parameterName, propertyValue).evaluateAndAddError(SourceAccountingLine.class, propertyName, userEnteredPropertyName); 080 } 081 } 082 catch (IllegalAccessException e) { 083 throw new RuntimeException(exceptionMessage, e); 084 } 085 catch (InvocationTargetException e) { 086 throw new RuntimeException(exceptionMessage, e); 087 } 088 catch (NoSuchMethodException e) { 089 throw new RuntimeException(exceptionMessage, e); 090 } 091 return isAllowed; 092 } 093 094 /** 095 * Refreshes a value on the accounting line, using the propertyPath to decided what to refresh 096 * @param line the accounting line to refresh a property on 097 */ 098 public void refreshByPath(AccountingLine line) { 099 refreshByQueue(line, convertPathToQueue(propertyPath)); 100 } 101 102 /** 103 * Creates a Queue which represents a FIFO path of what properties to visit, based on the given property path 104 * @param path the path to convert to a Queue 105 * @return a Queue representing the path 106 */ 107 protected Queue<String> convertPathToQueue(String path) { 108 Queue<String> pathQueue = new LinkedList<String>(); 109 for (String property: path.split("\\.")) { 110 pathQueue.add(property); 111 } 112 return pathQueue; 113 } 114 115 /** 116 * Recursively refreshes a property given by the queue path 117 * @param bo the business object to refresh 118 * @param path the path, in Queue form, of properties to refresh 119 */ 120 protected void refreshByQueue(PersistableBusinessObject bo, Queue<String> path) { 121 if (path.size() > 1) { // we know that the last thing on our list is a code. why refresh that? 122 String currentProperty = path.remove(); 123 bo.refreshReferenceObject(currentProperty); 124 PersistableBusinessObject childBO = (PersistableBusinessObject)ObjectUtils.getPropertyValue(bo, currentProperty); 125 if (!ObjectUtils.isNull(childBO)) { 126 refreshByQueue(childBO, path); 127 } 128 } 129 } 130 131 /** 132 * Gets the propertyPath attribute. This is the path to the value to check, e. g. "accountNumber.subFundGroup.fundGroupCode" 133 * @return Returns the propertyPath. 134 */ 135 public String getPropertyPath() { 136 return propertyPath; 137 } 138 139 /** 140 * Sets the propertyPath attribute value. This is the path to the value to check, e. g. "accountNumber.subFundGroup.fundGroupCode" 141 * @param propertyPath The propertyPath to set. 142 */ 143 public void setPropertyPath(String refreshPath) { 144 this.propertyPath = refreshPath; 145 } 146 147 /** 148 * Gets the parameterService attribute. 149 * @return Returns the parameterService. 150 */ 151 public ParameterService getParameterService() { 152 return parameterService; 153 } 154 155 /** 156 * Sets the parameterService attribute value. 157 * @param parameterService The parameterService to set. 158 */ 159 public void setParameterService(ParameterService parameterService) { 160 this.parameterService = parameterService; 161 } 162 163 /** 164 * Gets the parameterToCheckAgainst attribute. This is the name of the parameter which has the values to validate against. 165 * @return Returns the parameterToCheckAgainst. 166 */ 167 public String getParameterToCheckAgainst() { 168 return parameterToCheckAgainst; 169 } 170 171 /** 172 * Sets the parameterToCheckAgainst attribute value. This is the name of the parameter which has the values to validate against. 173 * @param parameterToCheckAgainst The parameterToCheckAgainst to set. 174 */ 175 public void setParameterToCheckAgainst(String parameterToCheckAgainst) { 176 this.parameterToCheckAgainst = parameterToCheckAgainst; 177 } 178 179 /** 180 * Gets the responsibleProperty attribute. This is the property on the accounting line to show the error on. 181 * @return Returns the responsibleProperty. 182 */ 183 public String getResponsibleProperty() { 184 return responsibleProperty; 185 } 186 187 /** 188 * Sets the responsibleProperty attribute value. This is the property on the accounting line to show the error on. 189 * @param responsibleProperty The responsibleProperty to set. 190 */ 191 public void setResponsibleProperty(String responsibleProperty) { 192 this.responsibleProperty = responsibleProperty; 193 } 194 195 /** 196 * Gets the accountingDocumentForValidation attribute. 197 * @return Returns the accountingDocumentForValidation. 198 */ 199 public AccountingDocument getAccountingDocumentForValidation() { 200 return accountingDocumentForValidation; 201 } 202 203 /** 204 * Sets the accountingDocumentForValidation attribute value. 205 * @param accountingDocumentForValidation The accountingDocumentForValidation to set. 206 */ 207 public void setAccountingDocumentForValidation(AccountingDocument accountingDocumentForValidation) { 208 this.accountingDocumentForValidation = accountingDocumentForValidation; 209 } 210 211 /** 212 * Gets the accountingLineForValidation attribute. 213 * @return Returns the accountingLineForValidation. 214 */ 215 public AccountingLine getAccountingLineForValidation() { 216 return accountingLineForValidation; 217 } 218 219 /** 220 * Sets the accountingLineForValidation attribute value. 221 * @param accountingLineForValidation The accountingLineForValidation to set. 222 */ 223 public void setAccountingLineForValidation(AccountingLine accountingLineForValidation) { 224 this.accountingLineForValidation = accountingLineForValidation; 225 } 226}