1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.ole.sys.report;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.apache.commons.beanutils.PropertyUtils;
25  import org.apache.commons.lang.StringUtils;
26  import org.kuali.ole.sys.OLEConstants;
27  import org.kuali.rice.core.web.format.BigDecimalFormatter;
28  import org.kuali.rice.core.web.format.CurrencyFormatter;
29  import org.kuali.rice.core.web.format.Formatter;
30  import org.kuali.rice.core.web.format.IntegerFormatter;
31  import org.kuali.rice.core.web.format.KualiIntegerCurrencyFormatter;
32  import org.kuali.rice.core.web.format.LongFormatter;
33  import org.kuali.rice.core.web.format.PercentageFormatter;
34  import org.kuali.rice.kns.service.DataDictionaryService;
35  import org.kuali.rice.krad.bo.BusinessObject;
36  import org.kuali.rice.krad.util.ObjectUtils;
37  
38  
39  
40  
41  
42  
43  
44  public class BusinessObjectReportHelper {
45      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BusinessObjectReportHelper.class);
46  
47      protected int minimumMessageLength;
48      protected String messageLabel;
49      protected Class<? extends BusinessObject> dataDictionaryBusinessObjectClass;
50      protected Map<String, String> orderedPropertyNameToHeaderLabelMap;
51      protected DataDictionaryService dataDictionaryService;
52  
53      private int columnCount = 0;
54      private Map<String, Integer> columnSpanDefinition;
55      
56      public final static String LEFT_ALIGNMENT = "LEFT"; 
57      public final static String RIGHT_ALIGNMENT = "RIGHT"; 
58      public final static String LINE_BREAK = "\n";
59  
60      
61  
62  
63  
64  
65  
66      public List<Object> getValues(BusinessObject businessObject) {
67          List<Object> keys = new ArrayList<Object>();
68  
69          for (Iterator<String> propertyNames = orderedPropertyNameToHeaderLabelMap.keySet().iterator(); propertyNames.hasNext();) {
70              String propertyName = propertyNames.next();
71              keys.add(retrievePropertyValue(businessObject, propertyName));
72          }
73  
74          return keys;
75      }
76  
77      
78  
79  
80  
81  
82  
83  
84      protected Object retrievePropertyValue(BusinessObject businessObject, String propertyName) {
85          try {
86              return PropertyUtils.getProperty(businessObject, propertyName);
87          }
88          catch (Exception e) {
89              throw new RuntimeException("Failed getting propertyName=" + propertyName + " from businessObjecName=" + businessObject.getClass().getName(), e);
90          }
91      }
92  
93      
94  
95  
96  
97  
98  
99  
100     protected int retrievePropertyValueMaximumLength(Class<? extends BusinessObject> businessObjectClass, String propertyName) {
101         return dataDictionaryService.getAttributeMaxLength(businessObjectClass, propertyName);
102     }
103     
104     
105 
106 
107 
108 
109 
110 
111     protected Class<? extends Formatter> retrievePropertyFormatterClass(Class<? extends BusinessObject> businessObjectClass, String propertyName) {
112         return dataDictionaryService.getAttributeFormatter(businessObjectClass, propertyName);
113     }
114 
115     
116 
117 
118 
119 
120 
121 
122     public List<Object> getBlankValues(BusinessObject businessObject) {
123         List<Object> keys = new ArrayList<Object>();
124 
125         for (Iterator<String> propertyNames = orderedPropertyNameToHeaderLabelMap.keySet().iterator(); propertyNames.hasNext();) {
126             String propertyName = propertyNames.next();
127 
128             keys.add("");
129         }
130 
131         return keys;
132     }
133 
134     
135 
136 
137 
138 
139 
140 
141 
142     public List<String> getTableHeader(int maximumPageWidth) {
143         String separatorLine = StringUtils.EMPTY;
144         String messageFormat = StringUtils.EMPTY;
145 
146         
147         for (Iterator<Map.Entry<String, String>> entries = orderedPropertyNameToHeaderLabelMap.entrySet().iterator(); entries.hasNext();) {
148             Map.Entry<String, String> entry = entries.next();
149 
150             int longest;
151             try {
152                 longest = retrievePropertyValueMaximumLength(dataDictionaryBusinessObjectClass, entry.getKey());
153             }
154             catch (Exception e) {
155                 throw new RuntimeException("Failed getting propertyName=" + entry.getKey() + " from businessObjecName=" + dataDictionaryBusinessObjectClass.getName(), e);
156             }
157             if (entry.getValue().length() > longest) {
158                 longest = entry.getValue().length();
159             }
160 
161             separatorLine = separatorLine + StringUtils.rightPad("", longest, OLEConstants.DASH) + " ";
162             messageFormat = messageFormat + "%-" + longest + "s ";
163         }
164 
165         
166         int availableWidth = maximumPageWidth - (separatorLine.length() + 1);
167         if (availableWidth < minimumMessageLength) {
168             availableWidth = minimumMessageLength;
169         }
170         separatorLine = separatorLine + StringUtils.rightPad("", availableWidth, OLEConstants.DASH);
171         messageFormat = messageFormat + "%-" + availableWidth + "s";
172 
173         
174         List<Object> formatterArgs = new ArrayList<Object>();
175         formatterArgs.addAll(orderedPropertyNameToHeaderLabelMap.values());
176         formatterArgs.add(messageLabel);
177         String tableHeaderLine = String.format(messageFormat, formatterArgs.toArray());
178 
179         
180         List<String> tableHeader = new ArrayList<String>();
181         tableHeader.add(tableHeaderLine);
182         tableHeader.add(separatorLine);
183         tableHeader.add(messageFormat);
184 
185         return tableHeader;
186     }
187 
188     
189 
190 
191 
192 
193     public Map<String, String> getTableDefinition() {       
194         List<Integer> cellWidthList = this.getTableCellWidth();
195         
196         String separatorLine = this.getSepartorLine(cellWidthList);       
197         String tableCellFormat = this.getTableCellFormat(false, true, null);
198         String tableHeaderLineFormat = this.getTableCellFormat(false, false, separatorLine);
199 
200         
201         int numberOfCell = cellWidthList.size();
202         List<String> tableHeaderLabelValues = new ArrayList<String>(orderedPropertyNameToHeaderLabelMap.values());
203         this.paddingTableCellValues(numberOfCell, tableHeaderLabelValues);
204 
205         String tableHeaderLine = String.format(tableHeaderLineFormat, tableHeaderLabelValues.toArray());
206 
207         Map<String, String> tableDefinition = new HashMap<String, String>();
208         tableDefinition.put(OLEConstants.ReportConstants.TABLE_HEADER_LINE_KEY, tableHeaderLine);
209         tableDefinition.put(OLEConstants.ReportConstants.SEPARATOR_LINE_KEY, separatorLine);
210         tableDefinition.put(OLEConstants.ReportConstants.TABLE_CELL_FORMAT_KEY, tableCellFormat);
211 
212         return tableDefinition;
213     }
214 
215     
216 
217 
218 
219 
220 
221 
222 
223     public List<String> getTableCellValues(BusinessObject businessObject, boolean allowColspan) {
224         List<String> tableCellValues = new ArrayList<String>();
225 
226         for (Map.Entry<String, String> entry : orderedPropertyNameToHeaderLabelMap.entrySet()) {
227             String attributeName = entry.getKey();
228 
229             if (attributeName.startsWith(OLEConstants.ReportConstants.EMPTY_CELL_ENTRY_KEY_PREFIX)) {
230                 tableCellValues.add(StringUtils.EMPTY);
231             }
232             else {
233                 try {
234                     Object propertyValue = retrievePropertyValue(businessObject, attributeName);
235                     
236                     if (ObjectUtils.isNotNull(propertyValue)) {
237                         Formatter formatter = Formatter.getFormatter(propertyValue.getClass());
238                         if(ObjectUtils.isNotNull(formatter) && ObjectUtils.isNotNull(propertyValue)) {
239                             propertyValue = formatter.format(propertyValue);
240                         }
241                         else {
242                             propertyValue = StringUtils.EMPTY;
243                         }
244                     } else {
245                         propertyValue = StringUtils.EMPTY;
246                     }
247                     
248                     tableCellValues.add(propertyValue.toString());
249                 }
250                 catch (Exception e) {
251                     throw new RuntimeException("Failed getting propertyName=" + entry.getKey() + " from businessObjecName=" + dataDictionaryBusinessObjectClass.getName(), e);
252                 }
253             }
254         }
255         
256         if(allowColspan) {
257             this.applyColspanOnCellValues(tableCellValues);
258         }
259 
260         return tableCellValues;
261     }
262 
263     
264 
265 
266 
267 
268 
269 
270 
271 
272     public String getTableCellFormat(boolean allowColspan, boolean allowRightAlignment, String separatorLine) {
273         List<Integer> cellWidthList = this.getTableCellWidth();
274         List<String> cellAlignmentList = this.getTableCellAlignment();
275         
276         if(allowColspan) {
277             this.applyColspanOnCellWidth(cellWidthList);
278         }
279 
280         int numberOfCell = cellWidthList.size();
281         int rowCount = (int) Math.ceil(numberOfCell * 1.0 / columnCount);
282 
283         StringBuffer tableCellFormat = new StringBuffer();
284         for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
285             StringBuffer singleRowFormat = new StringBuffer();
286             
287             for (int columnIndex = 0; columnIndex < this.columnCount; columnIndex++) {
288                 int index = columnCount * rowIndex + columnIndex; 
289                 
290                 if(index >= numberOfCell) {
291                     break;
292                 }
293                 
294                 int width = cellWidthList.get(index);
295                 String alignment = (allowRightAlignment && cellAlignmentList.get(index).equals(RIGHT_ALIGNMENT)) ? StringUtils.EMPTY : "-";
296                 if(width > 0) {
297                     
298                     singleRowFormat = singleRowFormat.append("%").append(alignment).append(width).append("." + width).append("s ");
299                 }
300             }
301             
302             tableCellFormat = tableCellFormat.append(singleRowFormat).append(LINE_BREAK);
303             if(StringUtils.isNotBlank(separatorLine)) {
304                 tableCellFormat = tableCellFormat.append(separatorLine).append(LINE_BREAK);
305             }
306         }
307 
308         return tableCellFormat.toString();
309     }
310     
311     
312 
313 
314 
315 
316     public String getSepartorLine(List<Integer> cellWidthList) {
317         StringBuffer separatorLine = new StringBuffer();
318         
319         for (int index = 0; index < this.columnCount; index++) {
320             Integer cellWidth = cellWidthList.get(index);
321             separatorLine = separatorLine.append(StringUtils.rightPad(StringUtils.EMPTY, cellWidth, OLEConstants.DASH)).append(" ");
322         }
323         
324         return separatorLine.toString();
325     }
326 
327     
328 
329 
330 
331 
332     public void applyColspanOnCellWidth(List<Integer> cellWidthList) {
333         if(ObjectUtils.isNull(columnSpanDefinition)) {
334             return;
335         }
336         
337         int indexOfCurrentCell = 0;
338         for (Map.Entry<String, String> entry : orderedPropertyNameToHeaderLabelMap.entrySet()) {
339             String attributeName = entry.getKey();
340 
341             if (columnSpanDefinition.containsKey(attributeName)) {
342                 int columnSpan = columnSpanDefinition.get(attributeName);
343 
344                 int widthOfCurrentNonEmptyCell = cellWidthList.get(indexOfCurrentCell);
345                 for (int i = 1; i < columnSpan; i++) {
346                     widthOfCurrentNonEmptyCell += cellWidthList.get(indexOfCurrentCell + i);
347                     cellWidthList.set(indexOfCurrentCell + i, 0);
348                 }
349                 cellWidthList.set(indexOfCurrentCell, widthOfCurrentNonEmptyCell + columnSpan - 1);
350             }
351 
352             indexOfCurrentCell++;
353         }
354     }
355     
356     
357 
358 
359 
360 
361     public void applyColspanOnCellValues(List<String> cellValues) {
362         if(ObjectUtils.isNull(columnSpanDefinition)) {
363             return;
364         }
365         
366         String REMOVE_ME = "REMOVE-ME-!";
367         
368         int indexOfCurrentCell = 0;
369         for (Map.Entry<String, String> entry : orderedPropertyNameToHeaderLabelMap.entrySet()) {
370             String attributeName = entry.getKey();
371 
372             if (columnSpanDefinition.containsKey(attributeName)) {
373                 int columnSpan = columnSpanDefinition.get(attributeName);
374 
375                 for (int i = 1; i < columnSpan; i++) {
376                     cellValues.set(indexOfCurrentCell + i, REMOVE_ME);
377                 }
378             }
379 
380             indexOfCurrentCell++;
381         }
382         
383         int originalLength = cellValues.size();
384         for(int index = originalLength -1; index>=0; index-- ) {
385             if(StringUtils.equals(cellValues.get(index), REMOVE_ME)) {
386                 cellValues.remove(index);
387             }
388         }
389     }
390 
391     
392 
393 
394 
395 
396 
397 
398     public List<String> getTableCellValuesPaddingWithEmptyCell(BusinessObject businessObject, boolean allowColspan) {
399         List<String> tableCellValues = this.getTableCellValues(businessObject, allowColspan);
400 
401         int numberOfCell = orderedPropertyNameToHeaderLabelMap.entrySet().size();
402         this.paddingTableCellValues(numberOfCell, tableCellValues);
403 
404         return tableCellValues;
405     }
406 
407     
408 
409 
410 
411 
412     public List<Integer> getTableCellWidth() {
413         List<Integer> cellWidthList = new ArrayList<Integer>();
414         for (Map.Entry<String, String> entry : orderedPropertyNameToHeaderLabelMap.entrySet()) {
415             String attributeName = entry.getKey();
416             String attributeValue = entry.getValue();
417 
418             int cellWidth = attributeValue.length();
419             if (!attributeName.startsWith(OLEConstants.ReportConstants.EMPTY_CELL_ENTRY_KEY_PREFIX)) {
420                 try {
421                     cellWidth = retrievePropertyValueMaximumLength(dataDictionaryBusinessObjectClass, attributeName);
422                 }
423                 catch (Exception e) {
424                     throw new RuntimeException("Failed getting propertyName=" + attributeName + " from businessObjecName=" + dataDictionaryBusinessObjectClass.getName(), e);
425                 }
426             }
427 
428             if (attributeValue.length() > cellWidth) {
429                 cellWidth = attributeValue.length();
430             }
431 
432             cellWidthList.add(cellWidth);
433         }
434 
435         int numberOfCell = cellWidthList.size();
436         int rowCount = (int) Math.ceil(numberOfCell * 1.0 / columnCount);
437         for (int colIndex = 0; colIndex < columnCount; colIndex++) {
438             int longestLength = cellWidthList.get(colIndex);
439 
440             for (int rowIndex = 1; rowIndex < rowCount; rowIndex++) {
441                 int currentIndex = rowIndex * columnCount + colIndex;
442                 if (currentIndex >= numberOfCell) {
443                     break;
444                 }
445 
446                 int currentLength = cellWidthList.get(currentIndex);
447                 if (currentLength > longestLength) {
448                     cellWidthList.set(colIndex, currentLength);
449                 }
450             }
451         }
452 
453         for (int colIndex = 0; colIndex < columnCount; colIndex++) {
454             int longestLength = cellWidthList.get(colIndex);
455 
456             for (int rowIndex = 1; rowIndex < rowCount; rowIndex++) {
457                 int currentIndex = rowIndex * columnCount + colIndex;
458                 if (currentIndex >= numberOfCell) {
459                     break;
460                 }
461 
462                 cellWidthList.set(currentIndex, longestLength);
463             }
464         }
465 
466         return cellWidthList;
467     }
468     
469     
470 
471 
472 
473 
474     public List<String> getTableCellAlignment() {
475         List<String> cellWidthList = new ArrayList<String>();
476         List<Class<? extends Formatter>> numberFormatters = this.getNumberFormatters();
477         
478         for (Map.Entry<String, String> entry : orderedPropertyNameToHeaderLabelMap.entrySet()) {
479             String attributeName = entry.getKey();
480             
481             boolean isNumber = false;
482             if (!attributeName.startsWith(OLEConstants.ReportConstants.EMPTY_CELL_ENTRY_KEY_PREFIX)) {
483                 try {
484                     Class<? extends Formatter> formatterClass = this.retrievePropertyFormatterClass(dataDictionaryBusinessObjectClass, attributeName);
485                     
486                     isNumber = numberFormatters.contains(formatterClass);
487                 }
488                 catch (Exception e) {
489                     throw new RuntimeException("Failed getting propertyName=" + attributeName + " from businessObjecName=" + dataDictionaryBusinessObjectClass.getName(), e);
490                 }
491             }
492 
493             cellWidthList.add(isNumber ? RIGHT_ALIGNMENT : LEFT_ALIGNMENT);
494         }
495         
496         return cellWidthList;
497     }
498 
499     
500     protected void paddingTableCellValues(int numberOfCell, List<String> tableCellValues) {
501         int reminder = columnCount - numberOfCell % columnCount;
502         if (reminder < columnCount) {
503             List<String> paddingObject = new ArrayList<String>(reminder);
504             for (int index = 0; index < reminder; index++) {
505                 paddingObject.add(StringUtils.EMPTY);
506             }
507 
508             tableCellValues.addAll(paddingObject);
509         }
510     }
511     
512     
513 
514 
515 
516 
517     protected List<Class<? extends Formatter>> getNumberFormatters(){
518         List<Class<? extends Formatter>> numberFormatters = new ArrayList<Class<? extends Formatter>>();
519         
520         numberFormatters.add(BigDecimalFormatter.class);
521         numberFormatters.add(CurrencyFormatter.class); 
522         numberFormatters.add(KualiIntegerCurrencyFormatter.class);
523         numberFormatters.add(PercentageFormatter.class);
524         numberFormatters.add(IntegerFormatter.class);
525         numberFormatters.add(LongFormatter.class);
526         
527         return numberFormatters;
528     }
529 
530     
531 
532 
533 
534 
535     public void setMinimumMessageLength(int minimumMessageLength) {
536         this.minimumMessageLength = minimumMessageLength;
537     }
538 
539     
540 
541 
542 
543 
544     public void setMessageLabel(String messageLabel) {
545         this.messageLabel = messageLabel;
546     }
547 
548     
549 
550 
551 
552 
553     public void setDataDictionaryBusinessObjectClass(Class<? extends BusinessObject> dataDictionaryBusinessObjectClass) {
554         this.dataDictionaryBusinessObjectClass = dataDictionaryBusinessObjectClass;
555     }
556 
557     
558 
559 
560 
561 
562     public void setOrderedPropertyNameToHeaderLabelMap(Map<String, String> orderedPropertyNameToHeaderLabelMap) {
563         this.orderedPropertyNameToHeaderLabelMap = orderedPropertyNameToHeaderLabelMap;
564     }
565 
566     
567 
568 
569 
570 
571     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
572         this.dataDictionaryService = dataDictionaryService;
573     }
574 
575     
576 
577 
578 
579 
580     public void setColumnCount(int columnCount) {
581         this.columnCount = columnCount;
582     }
583 
584     
585 
586 
587 
588 
589     public void setColumnSpanDefinition(Map<String, Integer> columnSpanDefinition) {
590         this.columnSpanDefinition = columnSpanDefinition;
591     }
592 }