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