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