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.service.impl; 017 018 import java.lang.reflect.InvocationTargetException; 019 import java.util.ArrayList; 020 import java.util.List; 021 import java.util.Map; 022 023 import javax.servlet.jsp.PageContext; 024 025 import org.apache.commons.beanutils.PropertyUtils; 026 import org.kuali.kfs.coa.service.AccountService; 027 import org.kuali.kfs.sys.KFSConstants; 028 import org.kuali.kfs.sys.businessobject.AccountingLine; 029 import org.kuali.kfs.sys.context.SpringContext; 030 import org.kuali.kfs.sys.document.AccountingDocument; 031 import org.kuali.kfs.sys.document.authorization.FinancialSystemTransactionalDocumentAuthorizerBase; 032 import org.kuali.kfs.sys.document.authorization.FinancialSystemTransactionalDocumentPresentationController; 033 import org.kuali.kfs.sys.document.datadictionary.AccountingLineGroupDefinition; 034 import org.kuali.kfs.sys.document.datadictionary.AccountingLineViewFieldDefinition; 035 import org.kuali.kfs.sys.document.service.AccountingLineAuthorizationTransformer; 036 import org.kuali.kfs.sys.document.service.AccountingLineFieldRenderingTransformation; 037 import org.kuali.kfs.sys.document.service.AccountingLineRenderingService; 038 import org.kuali.kfs.sys.document.service.AccountingLineRenderingTransformation; 039 import org.kuali.kfs.sys.document.service.AccountingLineTableTransformation; 040 import org.kuali.kfs.sys.document.web.AccountingLineTableRow; 041 import org.kuali.kfs.sys.document.web.TableJoining; 042 import org.kuali.kfs.sys.document.web.renderers.CheckboxRenderer; 043 import org.kuali.kfs.sys.document.web.renderers.CurrencyRenderer; 044 import org.kuali.kfs.sys.document.web.renderers.DateRenderer; 045 import org.kuali.kfs.sys.document.web.renderers.DropDownRenderer; 046 import org.kuali.kfs.sys.document.web.renderers.DynamicReadOnlyRender; 047 import org.kuali.kfs.sys.document.web.renderers.FieldRenderer; 048 import org.kuali.kfs.sys.document.web.renderers.HiddenRenderer; 049 import org.kuali.kfs.sys.document.web.renderers.RadioButtonGroupRenderer; 050 import org.kuali.kfs.sys.document.web.renderers.ReadOnlyRenderer; 051 import org.kuali.kfs.sys.document.web.renderers.TextAreaRenderer; 052 import org.kuali.kfs.sys.document.web.renderers.TextRenderer; 053 import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase; 054 import org.kuali.rice.kns.datadictionary.AttributeDefinition; 055 import org.kuali.rice.kns.datadictionary.BusinessObjectEntry; 056 import org.kuali.rice.kns.datadictionary.MaintainableFieldDefinition; 057 import org.kuali.rice.kns.datadictionary.validation.ValidationPattern; 058 import org.kuali.rice.kns.datadictionary.validation.fieldlevel.DateValidationPattern; 059 import org.kuali.rice.kns.service.DataDictionaryService; 060 import org.kuali.rice.kns.service.DocumentHelperService; 061 import org.kuali.rice.kns.util.GlobalVariables; 062 import org.kuali.rice.kns.web.ui.Field; 063 064 /** 065 * The default implementation of the AccountingLineRenderingService 066 */ 067 public class AccountingLineRenderingServiceImpl implements AccountingLineRenderingService { 068 protected final String KUALI_FORM_NAME = "KualiForm"; 069 070 private List<AccountingLineFieldRenderingTransformation> fieldTransformations; 071 private DataDictionaryService dataDictionaryService; 072 private AccountingLineAuthorizationTransformer accountingLineAuthorizationTransformer; 073 private List<AccountingLineRenderingTransformation> preTablificationTransformations; 074 private List<AccountingLineTableTransformation> postTablificationTransformations; 075 private DocumentHelperService documentHelperService; 076 077 /** 078 * @see org.kuali.kfs.sys.document.service.AccountingLineRenderingService#performPreTablificationTransformations(java.util.List, org.kuali.kfs.sys.document.datadictionary.AccountingLineGroupDefinition, org.kuali.kfs.sys.document.AccountingDocument, org.kuali.kfs.sys.businessobject.AccountingLine, boolean, java.util.Map, java.lang.String) 079 */ 080 public void performPreTablificationTransformations(List<TableJoining> elements, AccountingLineGroupDefinition groupDefinition, AccountingDocument accountingDocument, AccountingLine accountingLine, boolean newLine, Map unconvertedValues, String accountingLinePropertyName) { 081 performAuthorizationTransformations(elements, groupDefinition, accountingDocument, accountingLine, newLine, accountingLinePropertyName); 082 performFieldTransformations(elements, accountingDocument, accountingLine, unconvertedValues); 083 for (AccountingLineRenderingTransformation transformation : preTablificationTransformations) { 084 transformation.transformElements(elements, accountingLine); 085 } 086 } 087 088 /** 089 * @see org.kuali.kfs.sys.document.service.AccountingLineRenderingService#performPostTablificationTransformations(java.util.List, org.kuali.kfs.sys.document.datadictionary.AccountingLineGroupDefinition, org.kuali.kfs.sys.document.AccountingDocument, org.kuali.kfs.sys.businessobject.AccountingLine, boolean) 090 */ 091 public void performPostTablificationTransformations(List<AccountingLineTableRow> rows, AccountingLineGroupDefinition groupDefinition, AccountingDocument document, AccountingLine accountingLine, boolean newLine) { 092 for (AccountingLineTableTransformation transformation : postTablificationTransformations) { 093 transformation.transformRows(rows); 094 } 095 } 096 097 098 /** 099 * Performs the authorization transformations 100 * @param elements the layout elements which we are authorizing 101 * @param accountingLineGroupDefinition the data dictionary definition of the accounting line group 102 * @param accountingDocument the accounting line document we're rendering accounting lines for 103 * @param accountingLine the accounting line we're rendering 104 * @param newLine true if the accounting line is not yet on the form yet, false otherwise 105 */ 106 protected void performAuthorizationTransformations(List<TableJoining> elements, AccountingLineGroupDefinition accountingLineGroupDefinition, AccountingDocument accountingDocument, AccountingLine accountingLine, boolean newLine, String accountingLinePropertyName) { 107 accountingLineAuthorizationTransformer.transformElements(elements, accountingLine, accountingDocument, accountingLineGroupDefinition.getAccountingLineAuthorizer(), newLine, accountingLinePropertyName); 108 } 109 110 /** 111 * Performs field transformations for pre-rendering 112 * @param elements the layout elements that hold fields to transform 113 * @param accountingDocument the accounting document with the line we are rendering 114 * @param accountingLine the accounting line we are rendering 115 * @param unconvertedValues any unconverted values 116 */ 117 protected void performFieldTransformations(List<TableJoining> elements, AccountingDocument accountingDocument, AccountingLine accountingLine, Map unconvertedValues) { 118 for (TableJoining layoutElement : elements) { 119 layoutElement.performFieldTransformations(fieldTransformations, accountingLine, unconvertedValues); 120 } 121 } 122 123 /** 124 * Creates an accounting document authorizer for the given accounting document 125 * @param document the document to get an authorizer for 126 * @return an authorizer for the document 127 */ 128 protected FinancialSystemTransactionalDocumentAuthorizerBase getDocumentAuthorizer(AccountingDocument document) { 129 final FinancialSystemTransactionalDocumentAuthorizerBase authorizer = (FinancialSystemTransactionalDocumentAuthorizerBase) getDocumentHelperService().getDocumentAuthorizer(document); 130 return authorizer; 131 } 132 133 /** 134 * @param document the document to get the presentation controller for 135 * @return the proper presentation controller 136 */ 137 protected FinancialSystemTransactionalDocumentPresentationController getPresentationController(AccountingDocument document) { 138 final FinancialSystemTransactionalDocumentPresentationController presentationController = (FinancialSystemTransactionalDocumentPresentationController) getDocumentHelperService().getDocumentPresentationController(document); 139 return presentationController; 140 } 141 142 /** 143 * Simplify the tree so that it is made up of only table elements and fields 144 * @see org.kuali.kfs.sys.document.service.AccountingLineRenderingService#tablify(java.util.List) 145 */ 146 public List<AccountingLineTableRow> tablify(List<TableJoining> elements) { 147 List<AccountingLineTableRow> rows = createBlankTableRows(getMaxRowCount(elements)); 148 tablifyElements(elements, rows); 149 return rows; 150 } 151 152 /** 153 * Gets the maximum number of rows needed by any child element 154 * @param elements the elements to turn into table rows 155 * @return the maximum number of rows requested 156 */ 157 protected int getMaxRowCount(List<TableJoining> elements) { 158 int maxRowCount = 0; 159 for (TableJoining element : elements) { 160 int rowCount = element.getRequestedRowCount(); 161 if (rowCount > maxRowCount) { 162 maxRowCount = rowCount; 163 } 164 } 165 return maxRowCount; 166 } 167 168 /** 169 * This method creates a List of blank table rows, based on the requested count 170 * @param count the count of table rows 171 * @return a List of table rows ready for population 172 */ 173 protected List<AccountingLineTableRow> createBlankTableRows(int count) { 174 List<AccountingLineTableRow> rows = new ArrayList<AccountingLineTableRow>(); 175 for (int i = 0; i < count; i++) { 176 rows.add(new AccountingLineTableRow()); 177 } 178 return rows; 179 } 180 181 /** 182 * Requests each of the given elements to join the table 183 * @param elements the elements to join to the table 184 * @param rows the table rows to join to 185 */ 186 protected void tablifyElements(List<TableJoining> elements, List<AccountingLineTableRow> rows) { 187 for (TableJoining element : elements) { 188 element.joinTable(rows); 189 } 190 } 191 192 /** 193 * @see org.kuali.kfs.sys.document.service.AccountingLineRenderingService#getFieldRendererForField(org.kuali.rice.kns.web.ui.Field, org.kuali.kfs.sys.businessobject.AccountingLine) 194 */ 195 public FieldRenderer getFieldRendererForField(Field field, AccountingLine accountingLineToRender) { 196 FieldRenderer renderer = null; 197 198 if (field.isReadOnly() || field.getFieldType().equals(Field.READONLY)) { 199 renderer = new ReadOnlyRenderer(); 200 } /* 201 else if (field.getPropertyName().equals(KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME) && !SpringContext.getBean(AccountService.class).accountsCanCrossCharts()) { 202 // the special case for rendering chart of accounts code when accounts can't cross charts 203 renderer = new DynamicReadOnlyRender(); 204 } */ 205 else if (field.getFieldType().equals(Field.TEXT)) { 206 if (field.isDatePicker() || usesDateValidation(field.getPropertyName(), accountingLineToRender)) { // are we a date? 207 renderer = new DateRenderer(); 208 } else { 209 renderer = new TextRenderer(); 210 } 211 } else if (field.getFieldType().equals(Field.TEXT_AREA)) { 212 renderer = new TextAreaRenderer(); 213 } else if (field.getFieldType().equals(Field.HIDDEN)) { 214 renderer = new HiddenRenderer(); 215 } else if (field.getFieldType().equals(Field.CURRENCY)) { 216 renderer = new CurrencyRenderer(); 217 } else if (field.getFieldType().equals(Field.DROPDOWN)) { 218 renderer = new DropDownRenderer(); 219 } else if (field.getFieldType().equals(Field.RADIO)) { 220 renderer = new RadioButtonGroupRenderer(); 221 } else if (field.getFieldType().equals(Field.CHECKBOX)) { 222 renderer = new CheckboxRenderer(); 223 } 224 225 return renderer; 226 } 227 228 /** 229 * Determines if this method uses a date validation pattern, in which case, a date picker should be rendered 230 * @param propertyName the property of the field being checked from the command line 231 * @param accountingLineToRender the accounting line which is being rendered 232 * @return true if the property does use date validation, false otherwise 233 */ 234 protected boolean usesDateValidation(String propertyName, Object businessObject) { 235 final BusinessObjectEntry entry = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(businessObject.getClass().getName()); 236 AttributeDefinition attributeDefinition = entry.getAttributeDefinition(propertyName); 237 238 if (attributeDefinition == null) { 239 if (!propertyName.contains(".")) return false; 240 final int firstNestingPoint = propertyName.indexOf("."); 241 final String toNestingPoint = propertyName.substring(0, firstNestingPoint); 242 final String fromNestingPoint = propertyName.substring(firstNestingPoint+1); 243 Object childObject = null; 244 try { 245 final Class childClass = PropertyUtils.getPropertyType(businessObject, toNestingPoint); 246 childObject = childClass.newInstance(); 247 } 248 catch (IllegalAccessException iae) { 249 new UnsupportedOperationException(iae); 250 } 251 catch (InvocationTargetException ite) { 252 new UnsupportedOperationException(ite); 253 } 254 catch (NoSuchMethodException nsme) { 255 new UnsupportedOperationException(nsme); 256 } 257 catch (InstantiationException ie) { 258 throw new UnsupportedOperationException(ie); 259 } 260 return usesDateValidation(fromNestingPoint, childObject); 261 } 262 263 final ValidationPattern validationPattern = attributeDefinition.getValidationPattern(); 264 if (validationPattern == null) return false; // no validation for sure means we ain't using date validation 265 return validationPattern instanceof DateValidationPattern; 266 } 267 268 /** 269 * @see org.kuali.kfs.sys.document.service.AccountingLineRenderingService#createGenericAccountingLineViewFieldDefinition(org.kuali.rice.kns.datadictionary.MaintainableFieldDefinition) 270 */ 271 public AccountingLineViewFieldDefinition createGenericAccountingLineViewFieldDefinition(MaintainableFieldDefinition currentDefinition) { 272 AccountingLineViewFieldDefinition fieldDefinition = new AccountingLineViewFieldDefinition(); 273 274 fieldDefinition.setRequired(currentDefinition.isRequired()); 275 fieldDefinition.setUnconditionallyReadOnly(currentDefinition.isUnconditionallyReadOnly()); 276 fieldDefinition.setReadOnlyAfterAdd(currentDefinition.isReadOnlyAfterAdd()); 277 fieldDefinition.setNoLookup(currentDefinition.isNoLookup()); 278 279 fieldDefinition.setDefaultValue(currentDefinition.getDefaultValue()); 280 fieldDefinition.setTemplate(currentDefinition.getTemplate()); 281 fieldDefinition.setDefaultValueFinderClass(currentDefinition.getDefaultValueFinderClass()); 282 283 fieldDefinition.setOverrideLookupClass(currentDefinition.getOverrideLookupClass()); 284 fieldDefinition.setOverrideFieldConversions(currentDefinition.getOverrideFieldConversions()); 285 286 return fieldDefinition; 287 } 288 289 /** 290 * Gets the fieldTransformations attribute. 291 * @return Returns the fieldTransformations. 292 */ 293 public List<AccountingLineFieldRenderingTransformation> getFieldTransformations() { 294 return fieldTransformations; 295 } 296 297 /** 298 * Sets the fieldTransformations attribute value. 299 * @param fieldTransformations The fieldTransformations to set. 300 */ 301 public void setFieldTransformations(List<AccountingLineFieldRenderingTransformation> fieldTransformations) { 302 this.fieldTransformations = fieldTransformations; 303 } 304 305 /** 306 * Gets the accountingLineAuthorizationTransformer attribute. 307 * @return Returns the accountingLineAuthorizationTransformer. 308 */ 309 public AccountingLineAuthorizationTransformer getAccountingLineAuthorizationTransformer() { 310 return accountingLineAuthorizationTransformer; 311 } 312 313 /** 314 * Sets the accountingLineAuthorizationTransformer attribute value. 315 * @param accountingLineAuthorizationTransformer The accountingLineAuthorizationTransformer to set. 316 */ 317 public void setAccountingLineAuthorizationTransformer(AccountingLineAuthorizationTransformer accountingLineAuthorizationTransformer) { 318 this.accountingLineAuthorizationTransformer = accountingLineAuthorizationTransformer; 319 } 320 321 /** 322 * Gets the dataDictionaryService attribute. 323 * @return Returns the dataDictionaryService. 324 */ 325 public DataDictionaryService getDataDictionaryService() { 326 return dataDictionaryService; 327 } 328 329 /** 330 * Sets the dataDictionaryService attribute value. 331 * @param dataDictionaryService The dataDictionaryService to set. 332 */ 333 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { 334 this.dataDictionaryService = dataDictionaryService; 335 } 336 337 /** 338 * Gets the postTablificationTransformations attribute. 339 * @return Returns the postTablificationTransformations. 340 */ 341 public List<AccountingLineTableTransformation> getPostTablificationTransformations() { 342 return postTablificationTransformations; 343 } 344 345 /** 346 * Sets the postTablificationTransformations attribute value. 347 * @param postTablificationTransformations The postTablificationTransformations to set. 348 */ 349 public void setPostTablificationTransformations(List<AccountingLineTableTransformation> postTablificationTransformations) { 350 this.postTablificationTransformations = postTablificationTransformations; 351 } 352 353 /** 354 * Gets the preTablificationTransformations attribute. 355 * @return Returns the preTablificationTransformations. 356 */ 357 public List<AccountingLineRenderingTransformation> getPreTablificationTransformations() { 358 return preTablificationTransformations; 359 } 360 361 /** 362 * Sets the preTablificationTransformations attribute value. 363 * @param preTablificationTransformations The preTablificationTransformations to set. 364 */ 365 public void setPreTablificationTransformations(List<AccountingLineRenderingTransformation> preTablificationTransformations) { 366 this.preTablificationTransformations = preTablificationTransformations; 367 } 368 369 /** 370 * @see org.kuali.kfs.sys.document.service.AccountingLineRenderingService#findForm(javax.servlet.jsp.PageContext) 371 */ 372 public KualiAccountingDocumentFormBase findForm(PageContext pageContext) { 373 if (pageContext.getRequest().getAttribute(KUALI_FORM_NAME) != null) return (KualiAccountingDocumentFormBase)pageContext.getRequest().getAttribute(KUALI_FORM_NAME); 374 375 if (pageContext.getSession().getAttribute(KUALI_FORM_NAME) != null) return (KualiAccountingDocumentFormBase)pageContext.getSession().getAttribute(KUALI_FORM_NAME); 376 377 return (KualiAccountingDocumentFormBase)GlobalVariables.getKualiForm(); 378 } 379 380 protected DocumentHelperService getDocumentHelperService() { 381 if (documentHelperService == null) { 382 documentHelperService = SpringContext.getBean(DocumentHelperService.class); 383 } 384 return documentHelperService; 385 } 386 } 387