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.util.Iterator; 019import java.util.Map; 020import java.util.Set; 021 022import org.apache.commons.lang.StringUtils; 023import org.kuali.ole.sys.OLEConstants; 024import org.kuali.ole.sys.OLEKeyConstants; 025import org.kuali.ole.sys.OLEPropertyConstants; 026import org.kuali.ole.sys.businessobject.AccountingLine; 027import org.kuali.ole.sys.businessobject.FinancialSystemDocumentHeader; 028import org.kuali.ole.sys.document.AccountingDocument; 029import org.kuali.ole.sys.document.Correctable; 030import org.kuali.ole.sys.document.authorization.AccountingLineAuthorizer; 031import org.kuali.ole.sys.document.authorization.AccountingLineAuthorizerBase; 032import org.kuali.ole.sys.document.datadictionary.AccountingLineGroupDefinition; 033import org.kuali.ole.sys.document.datadictionary.FinancialSystemTransactionalDocumentEntry; 034import org.kuali.ole.sys.document.validation.GenericValidation; 035import org.kuali.ole.sys.document.validation.event.AddAccountingLineEvent; 036import org.kuali.ole.sys.document.validation.event.AttributedDocumentEvent; 037import org.kuali.ole.sys.document.validation.event.DeleteAccountingLineEvent; 038import org.kuali.ole.sys.document.validation.event.UpdateAccountingLineEvent; 039import org.kuali.rice.kim.api.identity.Person; 040import org.kuali.rice.krad.service.DataDictionaryService; 041import org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent; 042import org.kuali.rice.krad.util.GlobalVariables; 043 044/** 045 * A validation that checks whether the given accounting line is accessible to the given user or not 046 */ 047public class AccountingLineAccessibleValidation extends GenericValidation { 048 protected DataDictionaryService dataDictionaryService; 049 protected AccountingDocument accountingDocumentForValidation; 050 protected AccountingLine accountingLineForValidation; 051 052 /** 053 * Indicates what is being done to an accounting line. This allows the same method to be used for different actions. 054 */ 055 public enum AccountingLineAction { 056 ADD(OLEKeyConstants.ERROR_ACCOUNTINGLINE_INACCESSIBLE_ADD), DELETE(OLEKeyConstants.ERROR_ACCOUNTINGLINE_INACCESSIBLE_DELETE), UPDATE(OLEKeyConstants.ERROR_ACCOUNTINGLINE_INACCESSIBLE_UPDATE); 057 058 public final String accessibilityErrorKey; 059 060 AccountingLineAction(String accessabilityErrorKey) { 061 this.accessibilityErrorKey = accessabilityErrorKey; 062 } 063 } 064 065 /** 066 * Validates that the given accounting line is accessible for editing by the current user. 067 * <strong>This method expects a document as the first parameter and an accounting line as the second</strong> 068 * @see org.kuali.ole.sys.document.validation.Validation#validate(java.lang.Object[]) 069 */ 070 public boolean validate(AttributedDocumentEvent event) { 071 final Person currentUser = GlobalVariables.getUserSession().getPerson(); 072 073 if (accountingDocumentForValidation instanceof Correctable) { 074 final String errorDocumentNumber = ((FinancialSystemDocumentHeader)accountingDocumentForValidation.getDocumentHeader()).getFinancialDocumentInErrorNumber(); 075 if (StringUtils.isNotBlank(errorDocumentNumber)) 076 return true; 077 } 078 079 final AccountingLineAuthorizer accountingLineAuthorizer = lookupAccountingLineAuthorizer(); 080 final boolean lineIsAccessible = accountingLineAuthorizer.hasEditPermissionOnAccountingLine(accountingDocumentForValidation, accountingLineForValidation, getAccountingLineCollectionProperty(), currentUser, true); 081 final boolean isAccessible = accountingLineAuthorizer.hasEditPermissionOnField(accountingDocumentForValidation, accountingLineForValidation, getAccountingLineCollectionProperty(), OLEPropertyConstants.ACCOUNT_NUMBER, lineIsAccessible, true, currentUser); 082 083 // report errors 084 if (!isAccessible) { 085 final String principalName = currentUser.getPrincipalName(); 086 087 final String[] chartErrorParams = new String[] { getDataDictionaryService().getAttributeLabel(accountingLineForValidation.getClass(), OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE), accountingLineForValidation.getChartOfAccountsCode(), principalName}; 088 GlobalVariables.getMessageMap().putError(OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE, convertEventToMessage(event), chartErrorParams); 089 090 final String[] accountErrorParams = new String[] { getDataDictionaryService().getAttributeLabel(accountingLineForValidation.getClass(), OLEPropertyConstants.ACCOUNT_NUMBER), accountingLineForValidation.getAccountNumber(), principalName }; 091 GlobalVariables.getMessageMap().putError(OLEPropertyConstants.ACCOUNT_NUMBER, convertEventToMessage(event), accountErrorParams); 092 } 093 094 return isAccessible; 095 } 096 097 /** 098 * Returns the name of the accounting line group which holds the proper authorizer to do the KIM check 099 * @return the name of the accouting line group to get the authorizer from 100 */ 101 protected String getGroupName() { 102 return (accountingLineForValidation.isSourceAccountingLine() ? OLEConstants.SOURCE_ACCOUNTING_LINES_GROUP_NAME : OLEConstants.TARGET_ACCOUNTING_LINES_GROUP_NAME); 103 } 104 105 /** 106 * @return hopefully, the best accounting line authorizer implementation to do the KIM check for to see if lines are accessible 107 */ 108 protected AccountingLineAuthorizer lookupAccountingLineAuthorizer() { 109 final String groupName = getGroupName(); 110 final Map<String, AccountingLineGroupDefinition> groups = ((FinancialSystemTransactionalDocumentEntry)dataDictionaryService.getDataDictionary().getDictionaryObjectEntry(accountingDocumentForValidation.getClass().getName())).getAccountingLineGroups(); 111 112 if (groups.isEmpty()) return new AccountingLineAuthorizerBase(); // no groups? just use the default... 113 if (groups.containsKey(groupName)) return groups.get(groupName).getAccountingLineAuthorizer(); // we've got the group 114 115 final Set<String> groupNames = groups.keySet(); // we've got groups, just not the proper name; try our luck and get the first group iterator 116 final Iterator<String> groupNameIterator = groupNames.iterator(); 117 final String firstGroupName = groupNameIterator.next(); 118 return groups.get(firstGroupName).getAccountingLineAuthorizer(); 119 } 120 121 /** 122 * Determines the property of the accounting line collection from the error prefixes 123 * @return the accounting line collection property 124 */ 125 protected String getAccountingLineCollectionProperty() { 126 String propertyName = null; 127 if (GlobalVariables.getMessageMap().getErrorPath().size() > 0) { 128 propertyName = ((String)GlobalVariables.getMessageMap().getErrorPath().get(0)).replaceFirst(".*?document\\.", ""); 129 } else { 130 propertyName = accountingLineForValidation.isSourceAccountingLine() ? OLEConstants.PermissionAttributeValue.SOURCE_ACCOUNTING_LINES.value : OLEConstants.PermissionAttributeValue.TARGET_ACCOUNTING_LINES.value; 131 } 132 if (propertyName.equals("newSourceLine")) return OLEConstants.PermissionAttributeValue.SOURCE_ACCOUNTING_LINES.value; 133 if (propertyName.equals("newTargetLine")) return OLEConstants.PermissionAttributeValue.TARGET_ACCOUNTING_LINES.value; 134 return propertyName; 135 } 136 137 /** 138 * Determines what error message should be shown based on the event that required this validation 139 * @param event the event to use to determine the error message 140 * @return the key of the error message to display 141 */ 142 protected String convertEventToMessage(KualiDocumentEvent event) { 143 if (event instanceof AddAccountingLineEvent) { 144 return AccountingLineAction.ADD.accessibilityErrorKey; 145 } else if (event instanceof UpdateAccountingLineEvent) { 146 return AccountingLineAction.UPDATE.accessibilityErrorKey; 147 } else if (event instanceof DeleteAccountingLineEvent) { 148 return AccountingLineAction.DELETE.accessibilityErrorKey; 149 } else { 150 return ""; 151 } 152 } 153 154 /** 155 * Gets the accountingDocumentForValidation attribute. 156 * @return Returns the accountingDocumentForValidation. 157 */ 158 public AccountingDocument getAccountingDocumentForValidation() { 159 return accountingDocumentForValidation; 160 } 161 162 /** 163 * Sets the accountingDocumentForValidation attribute value. 164 * @param accountingDocumentForValidation The accountingDocumentForValidation to set. 165 */ 166 public void setAccountingDocumentForValidation(AccountingDocument accountingDocumentForValidation) { 167 this.accountingDocumentForValidation = accountingDocumentForValidation; 168 } 169 170 /** 171 * Gets the accountingLineForValidation attribute. 172 * @return Returns the accountingLineForValidation. 173 */ 174 public AccountingLine getAccountingLineForValidation() { 175 return accountingLineForValidation; 176 } 177 178 /** 179 * Sets the accountingLineForValidation attribute value. 180 * @param accountingLineForValidation The accountingLineForValidation to set. 181 */ 182 public void setAccountingLineForValidation(AccountingLine accountingLineForValidation) { 183 this.accountingLineForValidation = accountingLineForValidation; 184 } 185 186 /** 187 * Gets the dataDictionaryService attribute. 188 * @return Returns the dataDictionaryService. 189 */ 190 public DataDictionaryService getDataDictionaryService() { 191 return dataDictionaryService; 192 } 193 194 /** 195 * Sets the dataDictionaryService attribute value. 196 * @param dataDictionaryService The dataDictionaryService to set. 197 */ 198 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { 199 this.dataDictionaryService = dataDictionaryService; 200 } 201 202} 203