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 }