1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.ole.sys.document.web;
17  
18  import java.text.MessageFormat;
19  import java.util.List;
20  import java.util.Map;
21  
22  import javax.servlet.jsp.JspException;
23  import javax.servlet.jsp.PageContext;
24  import javax.servlet.jsp.tagext.Tag;
25  
26  import org.apache.commons.collections.BidiMap;
27  import org.apache.commons.collections.bidimap.DualHashBidiMap;
28  import org.apache.commons.lang.StringUtils;
29  import org.kuali.ole.coa.service.AccountService;
30  import org.kuali.ole.sys.OLEConstants;
31  import org.kuali.ole.sys.OLEKeyConstants;
32  import org.kuali.ole.sys.businessobject.AccountingLine;
33  import org.kuali.ole.sys.context.SpringContext;
34  import org.kuali.ole.sys.document.AccountingDocument;
35  import org.kuali.ole.sys.document.datadictionary.AccountingLineViewFieldDefinition;
36  import org.kuali.ole.sys.document.service.AccountingLineFieldRenderingTransformation;
37  import org.kuali.ole.sys.document.service.AccountingLineRenderingService;
38  import org.kuali.ole.sys.document.web.renderers.DynamicNameLabelRenderer;
39  import org.kuali.ole.sys.document.web.renderers.FieldRenderer;
40  import org.kuali.rice.core.api.config.property.ConfigurationService;
41  import org.kuali.rice.kns.lookup.LookupUtils;
42  import org.kuali.rice.kns.util.FieldUtils;
43  import org.kuali.rice.kns.web.ui.Field;
44  import org.kuali.rice.krad.bo.PersistableBusinessObject;
45  import org.kuali.rice.krad.service.PersistenceStructureService;
46  import org.kuali.rice.krad.util.ObjectUtils;
47  
48  
49  
50  
51  public class AccountingLineViewField extends FieldTableJoiningWithHeader implements HeaderLabelPopulating, ReadOnlyable {
52      public static final String ACCOUNTING_LINE_NAME_PREFIX_PLACE_HOLDER = "${accountingLineName}";
53  
54      private Field field;
55      private AccountingLineViewFieldDefinition definition;
56      private int arbitrarilyHighIndex;
57      private List<AccountingLineViewOverrideField> overrideFields;
58      private PersistenceStructureService persistenceStructureService;
59  
60      
61  
62  
63  
64  
65      public AccountingLineViewFieldDefinition getDefinition() {
66          return definition;
67      }
68  
69      
70  
71  
72  
73  
74      public void setDefinition(AccountingLineViewFieldDefinition definition) {
75          this.definition = definition;
76      }
77  
78      
79  
80  
81  
82  
83      private boolean shouldUseShortLabel() {
84          return definition.shouldUseShortLabel();
85      }
86  
87      
88  
89  
90  
91  
92  
93  
94      public Field getField() {
95          return field;
96      }
97  
98      
99  
100 
101 
102 
103 
104 
105     public void setField(Field field) {
106         this.field = field;
107     }
108 
109     
110 
111 
112 
113 
114     public List<AccountingLineViewOverrideField> getOverrideFields() {
115         return overrideFields;
116     }
117 
118     
119 
120 
121 
122 
123     public void setOverrideFields(List<AccountingLineViewOverrideField> overrideFields) {
124         this.overrideFields = overrideFields;
125     }
126 
127     
128 
129 
130 
131 
132     public boolean isHidden() {
133         return (field.getFieldType().equals(Field.HIDDEN) || definition.isHidden());
134     }
135 
136     
137 
138 
139 
140 
141 
142     public boolean isReadOnly() {
143         return field.isReadOnly() || isHidden();
144     }
145 
146     
147 
148 
149     public String getName() {
150         return field.getPropertyName();
151     }
152 
153     
154 
155 
156     public void readOnlyize() {
157         if (!isHidden()) {
158             this.field.setReadOnly(true);
159         }
160     }
161 
162     
163 
164 
165     public String getHeaderLabelProperty() {
166         return this.field.getPropertyName();
167     }
168 
169     
170 
171 
172 
173     public void renderElement(PageContext pageContext, Tag parentTag, AccountingLineRenderingContext renderingContext) throws JspException {
174         renderField(pageContext, parentTag, renderingContext);
175 
176         if (getOverrideFields() != null && getOverrideFields().size() > 0) {
177             renderOverrideFields(pageContext, parentTag, renderingContext);
178         }
179         if (shouldRenderDynamicFeldLabel() && renderingContext.fieldsCanRenderDynamicLabels()) {
180             renderDynamicNameLabel(pageContext, parentTag, renderingContext);
181         }
182     }
183 
184     
185 
186 
187 
188 
189 
190 
191 
192     protected void renderField(PageContext pageContext, Tag parentTag, AccountingLineRenderingContext renderingContext) throws JspException {
193         AccountingLine accountingLine = renderingContext.getAccountingLine();
194         String accountingLineProperty = renderingContext.getAccountingLinePropertyPath();
195         List<String> fieldNames = renderingContext.getFieldNamesForAccountingLine();
196         List errors = renderingContext.getErrors();
197         
198         this.getField().setPropertyPrefix(accountingLineProperty);
199         boolean chartSetByAccount = getName().equals(OLEConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME) && !SpringContext.getBean(AccountService.class).accountsCanCrossCharts();
200         
201         if (!renderingContext.isFieldModifyable(this.getName()) || chartSetByAccount) {
202             this.getField().setReadOnly(true);
203         }
204 
205         FieldRenderer renderer = SpringContext.getBean(AccountingLineRenderingService.class).getFieldRendererForField(getField(), accountingLine);
206         if (renderer != null) {
207             prepareFieldRenderer(renderer, getField(), renderingContext.getAccountingDocument(), accountingLine, accountingLineProperty, fieldNames);
208             if (fieldInError(errors)) {
209                 renderer.setShowError(true);
210             }
211 
212             if (!isHidden()) {
213                 renderer.openNoWrapSpan(pageContext, parentTag);
214             }
215 
216             
217             if (!this.isReadOnly()) {
218                 String accessibleTitle = getField().getFieldLabel();
219 
220                 if (renderingContext.isNewLine()) {
221                     String format = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(OLEKeyConstants.LABEL_NEW_ACCOUNTING_LINE_FIELD);
222                     accessibleTitle = MessageFormat.format(format, accessibleTitle, renderingContext.getGroupLabel());
223                 }
224                 else {
225                     Integer lineNumber = renderingContext.getCurrentLineCount() + 1;
226                     String format = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(OLEKeyConstants.LABEL_ACCOUNTING_LINE_FIELD);
227                     accessibleTitle = MessageFormat.format(format, accessibleTitle, renderingContext.getGroupLabel(), lineNumber);
228                 }
229 
230                 renderer.setAccessibleTitle(accessibleTitle);
231             }
232 
233             renderer.render(pageContext, parentTag);
234             if (!isHidden()) {
235                 renderer.closeNoWrapSpan(pageContext, parentTag);
236             }
237             renderer.clear();
238         }
239     }
240 
241     
242 
243 
244 
245 
246 
247 
248 
249 
250     protected void populateFieldForLookupAndInquiry(AccountingDocument accountingDocument, AccountingLine accountingLine, List<String> fieldNames, String accountingLinePrefix) {
251         if (!isHidden()) {
252             LookupUtils.setFieldQuickfinder(accountingLine, getField().getPropertyName(), getField(), fieldNames);
253 
254             
255             String overrideLookupParameters = definition.getOverrideLookupParameters();
256             if (StringUtils.isNotBlank(overrideLookupParameters)) {
257                 String lookupParameters = getField().getLookupParameters();
258 
259                 Map<String, String> lookupParametersMap = this.getActualParametersMap(lookupParameters, overrideLookupParameters, accountingLinePrefix);
260 
261                 getField().setLookupParameters(lookupParametersMap);
262 
263                 
264                 
265                 
266                 if (!lookupParametersMap.isEmpty()) {
267                     if (getDefinition().getOverrideLookupClass() != null) {
268                         getField().setQuickFinderClassNameImpl(getDefinition().getOverrideLookupClass().getName());
269                     }
270                 }
271             }
272 
273             
274             String overrideFieldConversions = definition.getOverrideFieldConversions();
275             if (StringUtils.isNotBlank(overrideFieldConversions)) {
276                 String fieldConversions = getField().getFieldConversions();
277 
278                 Map<String, String> fieldConversionsMap = this.getActualParametersMap(fieldConversions, overrideFieldConversions, accountingLinePrefix);
279 
280                 getField().setFieldConversions(fieldConversionsMap);
281             }
282 
283             if (isRenderingInquiry(accountingDocument, accountingLine)) {
284                 FieldUtils.setInquiryURL(getField(), accountingLine, getField().getPropertyName());
285             }
286         }
287     }
288 
289     
290 
291 
292 
293 
294     protected PersistenceStructureService getPersistenceStructureService() {
295         if (persistenceStructureService == null) {
296             persistenceStructureService = SpringContext.getBean(PersistenceStructureService.class);
297         }
298         return persistenceStructureService;
299     }
300 
301     
302 
303 
304 
305 
306 
307 
308 
309 
310 
311     protected void prepareFieldRenderer(FieldRenderer fieldRenderer, Field field, AccountingDocument document, AccountingLine accountingLine, String accountingLineProperty, List<String> fieldNames) {
312         fieldRenderer.setField(field);
313 
314         getField().setPropertyPrefix(accountingLineProperty);
315         populateFieldForLookupAndInquiry(document, accountingLine, fieldNames, getField().getPropertyPrefix());
316 
317         if (definition.getDynamicNameLabelGenerator() != null) {
318             fieldRenderer.overrideOnBlur(definition.getDynamicNameLabelGenerator().getDynamicNameLabelOnBlur(accountingLine, accountingLineProperty));
319         }
320         else if (!StringUtils.isBlank(definition.getDynamicLabelProperty())) {
321             fieldRenderer.setDynamicNameLabel(accountingLineProperty + "." + definition.getDynamicLabelProperty());
322         }
323 
324         fieldRenderer.setArbitrarilyHighTabIndex(arbitrarilyHighIndex);
325     }
326 
327     
328 
329 
330 
331 
332     protected boolean shouldRenderDynamicFeldLabel() {
333         return (!getField().getFieldType().equals(Field.HIDDEN) && ((!StringUtils.isBlank(getField().getWebOnBlurHandler()) && !StringUtils.isBlank(definition.getDynamicLabelProperty())) || definition.getDynamicNameLabelGenerator() != null));
334     }
335 
336     
337 
338 
339 
340     @Override
341     public void performFieldTransformations(List<AccountingLineFieldRenderingTransformation> fieldTransformations, AccountingLine accountingLine, Map unconvertedValues) {
342         for (AccountingLineFieldRenderingTransformation fieldTransformation : fieldTransformations) {
343             fieldTransformation.transformField(accountingLine, getField(), getDefinition(), unconvertedValues);
344             if (getOverrideFields() != null && getOverrideFields().size() > 0) {
345                 transformOverrideFields(fieldTransformation, accountingLine, unconvertedValues);
346             }
347         }
348     }
349 
350     
351 
352 
353 
354 
355 
356 
357 
358     protected void transformOverrideFields(AccountingLineFieldRenderingTransformation fieldTransformation, AccountingLine accountingLine, Map unconvertedValues) {
359         for (AccountingLineViewOverrideField overrideField : getOverrideFields()) {
360             overrideField.transformField(fieldTransformation, accountingLine, unconvertedValues);
361         }
362     }
363 
364     
365 
366 
367 
368 
369 
370 
371 
372 
373     public void renderOverrideFields(PageContext pageContext, Tag parentTag, AccountingLineRenderingContext renderingContext) throws JspException {
374         for (AccountingLineViewOverrideField overrideField : getOverrideFields()) {
375             overrideField.setAccountingLineProperty(renderingContext.getAccountingLinePropertyPath());
376             overrideField.renderElement(pageContext, parentTag, renderingContext);
377         }
378     }
379 
380     
381 
382 
383 
384 
385 
386 
387 
388     protected void renderDynamicNameLabel(PageContext pageContext, Tag parentTag, AccountingLineRenderingContext renderingContext) throws JspException {
389         AccountingLine accountingLine = renderingContext.getAccountingLine();
390         String accountingLinePropertyPath = renderingContext.getAccountingLinePropertyPath();
391 
392         DynamicNameLabelRenderer renderer = new DynamicNameLabelRenderer();
393         if (definition.getDynamicNameLabelGenerator() != null) {
394             renderer.setFieldName(definition.getDynamicNameLabelGenerator().getDynamicNameLabelFieldName(accountingLine, accountingLinePropertyPath));
395             renderer.setFieldValue(definition.getDynamicNameLabelGenerator().getDynamicNameLabelValue(accountingLine, accountingLinePropertyPath));
396         }
397         else {
398             if (!StringUtils.isBlank(getField().getPropertyValue())) {
399                 if (getField().isSecure()) {
400                     renderer.setFieldValue(getField().getDisplayMask().maskValue(getField().getPropertyValue()));
401                 }
402                 else {
403                     renderer.setFieldValue(getDynamicNameLabelDisplayedValue(accountingLine));
404                 }
405             }
406             renderer.setFieldName(accountingLinePropertyPath + "." + definition.getDynamicLabelProperty());
407         }
408         renderer.render(pageContext, parentTag);
409         renderer.clear();
410     }
411 
412     
413 
414 
415 
416 
417 
418     protected String getDynamicNameLabelDisplayedValue(AccountingLine accountingLine) {
419         String dynamicLabelProperty = definition.getDynamicLabelProperty();
420         Object value = accountingLine;
421         while (!ObjectUtils.isNull(value) && dynamicLabelProperty.indexOf('.') > -1) {
422             String currentProperty = StringUtils.substringBefore(dynamicLabelProperty, ".");
423             dynamicLabelProperty = StringUtils.substringAfter(dynamicLabelProperty, ".");
424             if (value instanceof PersistableBusinessObject) {
425                 ((PersistableBusinessObject) value).refreshReferenceObject(currentProperty);
426             }
427             value = ObjectUtils.getPropertyValue(value, currentProperty);
428         }
429         if (!ObjectUtils.isNull(value)) {
430             value = ObjectUtils.getPropertyValue(value, dynamicLabelProperty);
431             if (value != null)
432                 return value.toString();
433         }
434         return null;
435     }
436 
437     
438 
439 
440     public HeaderLabel createHeaderLabel() {
441         return new FieldHeaderLabel(this);
442     }
443 
444     
445 
446 
447 
448 
449 
450     protected void updateTableCellWithColSpanOverride(AccountingLineTableCell cell) {
451         if (definition.getOverrideColSpan() > 1 && cell.getColSpan() == 1) {
452             cell.setColSpan(definition.getOverrideColSpan());
453         }
454     }
455 
456     
457 
458 
459 
460 
461     @Override
462     protected AccountingLineTableCell createHeaderLabelTableCell() {
463         AccountingLineTableCell cell = super.createHeaderLabelTableCell();
464         updateTableCellWithColSpanOverride(cell);
465         return cell;
466     }
467 
468     
469 
470 
471 
472 
473     @Override
474     protected AccountingLineTableCell createTableCell() {
475         AccountingLineTableCell cell = super.createTableCell();
476         updateTableCellWithColSpanOverride(cell);
477         return cell;
478     }
479 
480     
481 
482 
483     public int getColSpanOverride() {
484         return definition.getOverrideColSpan();
485     }
486 
487     
488 
489 
490 
491     public void populateHeaderLabel(HeaderLabel headerLabel, AccountingLineRenderingContext renderingContext) {
492         FieldHeaderLabel label = (FieldHeaderLabel) headerLabel;
493         label.setLabel(getField().getFieldLabel());
494         label.setLabeledFieldEmptyOrHidden(isEmpty() || isHidden());
495         label.setReadOnly(getField().isReadOnly());
496         label.setRequired(getField().isFieldRequired());
497         if (renderingContext.fieldsShouldRenderHelp()) {
498             label.setFullClassNameForHelp(renderingContext.getAccountingLine().getClass().getName());
499             label.setAttributeEntryForHelp(getField().getPropertyName());
500         }
501     }
502 
503     
504 
505 
506 
507 
508 
509 
510     public void appendFields(List<Field> fields) {
511         fields.add(getField());
512         if (getOverrideFields() != null && getOverrideFields().size() > 0) {
513             for (AccountingLineViewOverrideField field : getOverrideFields()) {
514                 field.appendFields(fields);
515             }
516         }
517     }
518 
519     
520 
521 
522     public void populateWithTabIndexIfRequested(int reallyHighIndex) {
523         this.arbitrarilyHighIndex = reallyHighIndex;
524     }
525 
526     
527 
528 
529 
530 
531 
532 
533 
534     protected boolean fieldInError(List errors) {
535         if (errors != null) {
536             String fieldName = getField().getPropertyName();
537             if (!StringUtils.isBlank(getField().getPropertyPrefix())) {
538                 fieldName = getField().getPropertyPrefix() + "." + fieldName;
539             }
540             for (Object errorKeyAsObject : errors) {
541                 final String errorKey = (String) errorKeyAsObject;
542                 if (fieldName.equals(errorKey)) {
543                     return true;
544                 }
545             }
546         }
547         return false;
548     }
549 
550     
551 
552 
553     public void setEditable() {
554         if (!isHidden()) {
555             this.field.setReadOnly(false);
556         }
557     }
558 
559     
560 
561 
562 
563 
564 
565 
566     protected boolean isRenderingInquiry(AccountingDocument document, AccountingLine line) {
567         return isReadOnly();
568     }
569 
570     
571 
572 
573 
574 
575 
576 
577 
578     private Map<String, String> getActualParametersMap(String parameters, String overrideParameters, String accountingLinePrefix) {
579         BidiMap parametersMap = this.buildBidirecionalMapFromParameters(parameters, accountingLinePrefix);
580         BidiMap overrideParametersMap = this.buildBidirecionalMapFromParameters(overrideParameters, accountingLinePrefix);
581         parametersMap.putAll(overrideParametersMap);
582 
583         return parametersMap;
584     }
585 
586     
587 
588 
589 
590 
591 
592 
593     private BidiMap buildBidirecionalMapFromParameters(String parameters, String accountingLinePrefix) {
594         BidiMap parameterMap = new DualHashBidiMap();
595 
596         
597         if (StringUtils.isBlank(parameters)) {
598             return parameterMap;
599         }
600         
601         String[] parameterArray = StringUtils.split(parameters, OLEConstants.FIELD_CONVERSIONS_SEPERATOR);
602 
603         for (String parameter : parameterArray) {
604             String[] entrySet = StringUtils.split(parameter, OLEConstants.FIELD_CONVERSION_PAIR_SEPERATOR);
605 
606             if (entrySet != null) {
607                 String parameterKey = escapeAccountingLineName(entrySet[0], accountingLinePrefix);
608                 String parameterValue = escapeAccountingLineName(entrySet[1], accountingLinePrefix);
609 
610                 parameterMap.put(parameterKey, parameterValue);
611             }
612         }
613 
614         return parameterMap;
615     }
616 
617     
618 
619 
620 
621 
622 
623 
624     protected String escapeAccountingLineName(String propertyName, String accountingLinePrefix) {
625         return StringUtils.replace(propertyName, ACCOUNTING_LINE_NAME_PREFIX_PLACE_HOLDER, accountingLinePrefix + ".");
626     }
627 }