1
2
3
4
5
6
7
8
9
10
11
12
13
14 package olg.csv.bean.annotations.processor;
15
16 import java.lang.reflect.Field;
17 import java.lang.reflect.InvocationTargetException;
18 import java.lang.reflect.Method;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Map.Entry;
24
25 import olg.csv.base.csv.CSVSettings;
26 import olg.csv.base.ods.ODSSettings;
27 import olg.csv.bean.IBeanProcessor;
28 import olg.csv.bean.IPropertyProcessor;
29 import olg.csv.bean.IRowProcessor;
30 import olg.csv.bean.annotations.CSVProperty;
31 import olg.csv.bean.annotations.Column;
32 import olg.csv.bean.annotations.Embedded;
33 import olg.csv.bean.annotations.ODSProperty;
34 import olg.csv.bean.annotations.Param;
35 import olg.csv.bean.annotations.RowBean;
36 import olg.csv.bean.impl.BeanProcessor;
37 import olg.csv.bean.impl.CellProcessor;
38 import olg.csv.bean.impl.RowProcessor;
39 import olg.csv.bean.parser.AbstractParser;
40 import olg.csv.bean.parser.ParseException;
41
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45
46
47
48
49
50
51
52 public final class RowBeanProcessor<T> {
53
54
55
56 private static final Logger LOGGER = LoggerFactory.getLogger(RowBeanProcessor.class);
57
58
59
60
61 private ODSPropertyType[] ODSReadingProperties = ODSPropertyType.values();
62
63
64
65 private ODSPropertyType[] ODSWritingProperties = { ODSPropertyType.SHEETNAME, ODSPropertyType.BEGIN_AT_ROW,
66 ODSPropertyType.BEGIN_AT_COLUMN, ODSPropertyType.HEADERS};
67
68
69
70 private CSVPropertyType[] CSVReadingProperties = { CSVPropertyType.DELIMITER, CSVPropertyType.SEPARATOR,
71 CSVPropertyType.CHARSETNAME, CSVPropertyType.HEADERS};
72
73
74
75 private CSVPropertyType[] CSVWritingProperties = { CSVPropertyType.DELIMITER, CSVPropertyType.SEPARATOR,
76 CSVPropertyType.CHARSETNAME, CSVPropertyType.LINE_SEPARATOR, CSVPropertyType.HEADERS};
77
78
79
80
81
82
83 private enum ODSPropertyType {
84
85
86
87 HEADERS(ODSProperty.HEADERS, "withHeaders", new AbstractParser<Boolean>() {
88
89 @Override
90 public Boolean parse(String str) {
91 if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("false")) {
92 return Boolean.valueOf(str);
93 } else {
94 LOGGER.error("{} ODS Property only supports \"true\" or \"false\" value", ODSProperty.HEADERS);
95 throw new ParseException();
96 }
97 }
98 }),
99
100
101
102 SHEETNUM(ODSProperty.SHEETNUM, "sheetNum", new AbstractParser<Integer>() {
103
104 @Override
105 public Integer parse(String str) {
106 try {
107 return Integer.valueOf(str);
108 } catch (NumberFormatException ex) {
109 LOGGER.error("{} ODS Property only supports integer value", ODSProperty.SHEETNUM);
110 throw new ParseException();
111 }
112 }
113
114 }),
115
116
117
118 SHEETNAME(ODSProperty.SHEETNAME, "sheetName", null),
119
120
121
122 BEGIN_AT_ROW(ODSProperty.BEGIN_AT_ROW, "beginAtRow", new AbstractParser<Integer>() {
123 @Override
124 public Integer parse(String str) {
125 try {
126 return Integer.valueOf(str);
127 } catch (NumberFormatException ex) {
128 LOGGER.error("{} ODS Property only supports integer value", ODSProperty.BEGIN_AT_ROW);
129 throw new ParseException();
130 }
131 }
132 }),
133
134
135
136
137 END_AT_ROW(ODSProperty.END_AT_ROW, "endAtRow", new AbstractParser<Integer>() {
138 @Override
139 public Integer parse(String str) {
140 try {
141 return Integer.valueOf(str);
142 } catch (NumberFormatException ex) {
143 LOGGER.error("{} ODS Property only supports integer value", ODSProperty.END_AT_ROW);
144 throw new ParseException();
145 }
146 }
147 }),
148
149
150
151
152 BEGIN_AT_COLUMN(ODSProperty.BEGIN_AT_COLUMN, "beginAtColumn", null),
153
154
155
156
157 END_AT_COLUMN(ODSProperty.END_AT_COLUMN, "endAtColumn", null);
158
159
160
161
162 private String code;
163
164
165
166 private AbstractParser<?> parser;
167
168
169
170 private Method setter;
171
172
173
174
175 private String property;
176
177
178
179
180
181
182
183
184
185
186 private ODSPropertyType(String code, String property, AbstractParser<?> parser) {
187 this.code = code;
188 this.parser = parser;
189 this.property = property;
190 Method[] methods = ODSSettings.class.getMethods();
191
192 String setterName = "set" + property.substring(0, 1).toUpperCase() + (property.substring(1));
193
194 for (Method methode : methods) {
195 if (methode.getName().equals(setterName) && methode.getParameterTypes().length == 1) {
196 this.setter = methode;
197 break;
198 }
199 }
200
201 }
202
203
204
205
206
207
208
209 static ODSPropertyType getByCode(String code) {
210 ODSPropertyType retour = null;
211 for (ODSPropertyType type : ODSPropertyType.values()) {
212 if (type.code.equals(code)) {
213 retour = type;
214 break;
215 }
216 }
217 return retour;
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231 ODSSettings setParam(ODSSettings settings, String value) throws AnnotationProcessorException {
232
233 try {
234 setter.invoke(settings, (parser != null ? parser.parse(value) : value));
235 } catch (IllegalAccessException e) {
236 LOGGER.error("Hmm, I thought it couldn't happen", e);
237 } catch (IllegalArgumentException e) {
238 LOGGER.error("Hmm, I thought it couldn't happen", e);
239 } catch (InvocationTargetException e) {
240 LOGGER.error("ODSSettings error on {} setting ", property, e.getTargetException());
241 throw new AnnotationProcessorException();
242 } catch (ParseException e) {
243 throw new AnnotationProcessorException();
244 }
245 return settings;
246 }
247 };
248
249
250
251
252
253
254 private enum CSVPropertyType {
255
256
257
258 HEADERS(CSVProperty.HEADERS, "withHeaders", new AbstractParser<Boolean>() {
259
260 @Override
261 public Boolean parse(String str) {
262 if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("false")) {
263 return Boolean.valueOf(str);
264 } else {
265 LOGGER.error("{} CSV Property only supports \"true\" or \"false\" value, not [{}]",
266 CSVProperty.HEADERS, str);
267 throw new ParseException();
268 }
269 }
270 }
271
272 ),
273
274
275
276 SEPARATOR(CSVProperty.SEPARATOR, "separator", new AbstractParser<Character>() {
277 @Override
278 public Character parse(String str) {
279 Character retour = null;
280
281 if (str.trim().length() != 1) {
282 LOGGER.error("{} CSVProperty only supports String as char, not [{}]", CSVProperty.SEPARATOR, str);
283 throw new ParseException();
284 }
285 retour = str.trim().charAt(0);
286
287 return retour;
288 }
289 }),
290
291
292
293
294 DELIMITER(CSVProperty.DELIMITER, "delimiter", new AbstractParser<Character>() {
295 @Override
296 public Character parse(String str) {
297 Character retour = null;
298
299 if (str.trim().length() != 1) {
300 LOGGER.error("{} CSVProperty only supports String as char, not [{}]", CSVProperty.SEPARATOR, str);
301 throw new ParseException();
302 }
303 retour = str.trim().charAt(0);
304
305 return retour;
306
307 }
308 }),
309
310
311
312 CHARSETNAME(CSVProperty.CHARSETNAME, "charsetName", null),
313
314
315
316 LINE_SEPARATOR(CSVProperty.LINE_SEPARATOR, "lineSeparator", null);
317
318
319
320
321 private String code;
322
323
324
325
326 private AbstractParser<?> parser;
327
328
329
330 private Method setter;
331
332
333
334 private String property;
335
336
337
338
339
340
341
342
343
344
345 private CSVPropertyType(String code, String property, AbstractParser<?> parser) {
346 this.code = code;
347 this.parser = parser;
348 this.property = property;
349
350 Method[] methods = CSVSettings.class.getMethods();
351
352 String setterName = "set" + property.substring(0, 1).toUpperCase() + (property.substring(1));
353
354 for (Method methode : methods) {
355 if (methode.getName().equals(setterName) && methode.getParameterTypes().length == 1) {
356 this.setter = methode;
357 break;
358 }
359 }
360 }
361
362
363
364
365
366
367
368 public static CSVPropertyType getByCode(String code) {
369 CSVPropertyType retour = null;
370 for (CSVPropertyType type : CSVPropertyType.values()) {
371 if (type.code.equals(code)) {
372 retour = type;
373 break;
374 }
375 }
376 return retour;
377 }
378
379
380
381
382
383
384
385
386
387
388
389
390 public CSVSettings setParam(CSVSettings settings, String value) throws AnnotationProcessorException {
391
392 try {
393 setter.invoke(settings, (parser != null ? parser.parse(value) : value));
394 } catch (IllegalAccessException e) {
395 LOGGER.error("Hmm, I thought it couldn't happen", e);
396 } catch (IllegalArgumentException e) {
397 LOGGER.error("Hmm, I thought it couldn't happen", e);
398 } catch (InvocationTargetException e) {
399 LOGGER.error("CSVSettings error on {} setting ", property, e.getTargetException());
400 throw new AnnotationProcessorException();
401 } catch (ParseException e) {
402 throw new AnnotationProcessorException();
403 }
404 return settings;
405 }
406 };
407
408
409
410
411 private Class<T> clazz;
412
413
414
415
416 private ColumnProcessor<T> columnProcessor;
417
418
419
420
421 private EmbeddedProcessor<T> embeddedProcessor;
422
423
424
425
426
427
428
429 public RowBeanProcessor(Class<T> clazz) {
430 super();
431 this.clazz = clazz;
432 this.columnProcessor = new ColumnProcessor<T>(clazz);
433 this.embeddedProcessor = new EmbeddedProcessor<T>(clazz);
434 }
435
436
437
438
439
440
441 public boolean hasRowBeanAnnotation() {
442 return clazz.getAnnotation(RowBean.class) != null;
443 }
444
445
446
447
448
449
450
451
452 public ODSSettings getReadingODSSettings() throws AnnotationProcessorException {
453 RowBean rowBean = clazz.getAnnotation(RowBean.class);
454 Param[] odsReadingParams = rowBean.ODSReadingParams();
455 return getODSSettings(odsReadingParams, ODSReadingProperties, "ODSReadingParam");
456
457 }
458
459
460
461
462
463
464
465
466
467 public ODSSettings getWritingODSSettings() throws AnnotationProcessorException {
468 RowBean rowBean = clazz.getAnnotation(RowBean.class);
469 Param[] odsWritingParams = rowBean.ODSWritingParams();
470 return getODSSettings(odsWritingParams, ODSWritingProperties, "ODSWritingParam");
471
472 }
473
474
475
476
477
478
479
480
481
482 public CSVSettings getReadingCSVSettings() throws AnnotationProcessorException {
483 RowBean rowBean = clazz.getAnnotation(RowBean.class);
484 Param[] csvReadinggParams = rowBean.CSVReadingParams();
485 return getCSVSettings(csvReadinggParams, CSVReadingProperties, "CSVReadingParam");
486
487 }
488
489
490
491
492
493
494
495
496 public CSVSettings getWritingCSVSettings() throws AnnotationProcessorException {
497 RowBean rowBean = clazz.getAnnotation(RowBean.class);
498 Param[] csvWritingParams = rowBean.CSVWritingParams();
499 return getCSVSettings(csvWritingParams, CSVWritingProperties, "CSVWritingParam");
500 }
501
502
503
504
505
506
507
508
509 public IBeanProcessor<T> getBeanProcessor() throws AnnotationProcessorException {
510
511 Map<Integer, Integer> map = new HashMap<Integer, Integer>();
512 List<IPropertyProcessor<T>> propertyProcessors = new ArrayList<IPropertyProcessor<T>>();
513 boolean noError = getReadingProcessor(0, propertyProcessors, map);
514 BeanProcessor<T> beanProcessor = new BeanProcessor<T>(this.clazz);
515
516 for (Entry<Integer, Integer> entry : map.entrySet()) {
517 if (entry.getValue() > 1) {
518 LOGGER.error("For column {}, {} fields match. Only one is supported", entry.getKey(), entry.getValue());
519 noError = false;
520 }
521 }
522
523 if (noError) {
524 beanProcessor.addAll(propertyProcessors);
525 return beanProcessor;
526 } else {
527 throw new AnnotationProcessorException(
528 "Some error occured on BeanProcessor loading. See logs for more details");
529 }
530
531 }
532
533
534
535
536
537
538
539 public IRowProcessor<T> getRowProcessor() throws AnnotationProcessorException {
540 Map<Integer, List<CellProcessor<T>>> map = new HashMap<Integer, List<CellProcessor<T>>>();
541 boolean noError = getWritingProcessor(map);
542 List<CellProcessor<T>> cellProcessors = new ArrayList<CellProcessor<T>>();
543
544 if (noError) {
545
546 for (Entry<Integer, List<CellProcessor<T>>> entry : map.entrySet()) {
547
548 if (entry.getValue().size() > 1) {
549 LOGGER.error("For column {}, {} fields match. Only one is supported", entry.getKey(), entry
550 .getValue().size());
551 noError = false;
552 } else {
553 cellProcessors.add(entry.getValue().iterator().next());
554 }
555 }
556 }
557 if (noError) {
558 return new RowProcessor<T>(cellProcessors);
559 } else {
560 throw new AnnotationProcessorException(
561 "Some error occured on RowProcessor loading. See logs for more details");
562 }
563 }
564
565
566
567
568
569
570
571
572
573 protected boolean getWritingProcessor(Map<Integer, List<CellProcessor<T>>> map) {
574 if (hasRowBeanAnnotation()) {
575 return getWritingProcessor(this.clazz, map);
576 } else {
577 LOGGER.error("@RowBean Annotation not found on {} class", this.clazz.getSimpleName());
578 return false;
579 }
580 }
581
582
583
584
585
586
587
588
589
590
591
592
593
594 protected boolean getReadingProcessor(int translate, List<IPropertyProcessor<T>> processors,
595 Map<Integer, Integer> map) {
596 if (hasRowBeanAnnotation()) {
597 return getReadingProcessor(this.clazz, translate, processors, map);
598 } else {
599 LOGGER.error("@RowBean Annotation not found on {} class", this.clazz.getSimpleName());
600 return false;
601 }
602 }
603
604
605
606
607
608
609
610
611
612
613
614
615 private boolean getWritingProcessor(Class<? super T> beanClass, Map<Integer, List<CellProcessor<T>>> map) {
616 boolean noError = true;
617
618 if (beanClass.getAnnotation(RowBean.class) != null) {
619
620 if (beanClass.getSuperclass() != null) {
621 noError &= getWritingProcessor(beanClass.getSuperclass(), map);
622 }
623
624 Field[] fields = beanClass.getDeclaredFields();
625
626 for (Field field : fields) {
627 if (!checkField(field, beanClass)) {
628 noError = false;
629 continue;
630 }
631
632 noError &= this.columnProcessor.getWritingProcessor(field, map);
633
634 noError &= this.embeddedProcessor.getWritingProcessor(field, map);
635
636 }
637 }
638
639 return noError;
640
641 }
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657 private boolean getReadingProcessor(Class<? super T> beanClass, int translate,
658 List<IPropertyProcessor<T>> processors, Map<Integer, Integer> map) {
659 boolean noError = true;
660
661 if (beanClass.getAnnotation(RowBean.class) != null) {
662 if (beanClass.getSuperclass() != null) {
663
664 noError &= getReadingProcessor(beanClass.getSuperclass(), translate, processors, map);
665 }
666 }
667
668 Field[] fields = beanClass.getDeclaredFields();
669
670 for (Field field : fields) {
671 if (!checkField(field, beanClass)) {
672 noError = false;
673 continue;
674 }
675
676 noError &= this.columnProcessor.getReadingProcessor(translate, field, processors, map);
677 noError &= this.embeddedProcessor.getReadingProcessor(translate, field, processors, map);
678
679 }
680 return noError;
681 }
682
683
684
685
686
687
688
689
690
691
692 private boolean checkField(Field field, Class<? super T> beanClass) {
693 if (field.getAnnotation(Column.class) != null && field.getAnnotation(Embedded.class) != null) {
694 LOGGER.error("{}.{} : A field must not have both the column annotation and the embedded annotation",
695 beanClass.getSimpleName(), field.getName());
696 return false;
697 }
698
699 return true;
700 }
701
702
703
704
705
706
707
708
709
710
711 private ODSPropertyType identifyPermittedProperty(Param param, ODSPropertyType[] permittedProperties) {
712 ODSPropertyType propertyType = ODSPropertyType.getByCode(param.name());
713 if (propertyType != null) {
714 boolean find = false;
715 for (ODSPropertyType permittedProperty : permittedProperties) {
716 if (propertyType == permittedProperty) {
717 find = true;
718 break;
719 }
720 }
721 propertyType = (find ? propertyType : null);
722 }
723 return propertyType;
724 }
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739 private ODSSettings getODSSettings(Param[] odsParams, ODSPropertyType[] properties, String type)
740 throws AnnotationProcessorException {
741
742 ODSSettings settings = new ODSSettings();
743 boolean exceptionOnProcess = false;
744
745 if (odsParams != null && odsParams.length > 0) {
746 for (Param param : odsParams) {
747 ODSPropertyType propertyType = identifyPermittedProperty(param, properties);
748
749 if (propertyType != null) {
750 if ("".equals(param.value())) {
751 LOGGER.warn("{}@RowBean : empty string is not a legal value for {} {}", new Object[] {
752 this.clazz.getSimpleName(), param.name(), type});
753 } else {
754 try {
755 propertyType.setParam(settings, param.value());
756 } catch (AnnotationProcessorException ex) {
757 exceptionOnProcess = true;
758 }
759 }
760 } else {
761 LOGGER.warn("{}@RowBean : {} is not a legal {}, it will be ignored",
762 new Object[] { this.clazz.getSimpleName(), param.name(), type});
763 }
764 }
765 }
766 if (exceptionOnProcess) {
767 throw new AnnotationProcessorException("See logs for more details");
768 }
769 return settings;
770 }
771
772
773
774
775
776
777
778
779
780
781 private CSVPropertyType identifyPermittedProperty(final Param param, CSVPropertyType[] permittedProperties) {
782 CSVPropertyType propertyType = CSVPropertyType.getByCode(param.name());
783 if (propertyType != null) {
784 boolean find = false;
785 for (CSVPropertyType permittedProperty : permittedProperties) {
786 if (propertyType == permittedProperty) {
787 find = true;
788 break;
789 }
790 }
791 propertyType = (find ? propertyType : null);
792 }
793 return propertyType;
794 }
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809 private CSVSettings getCSVSettings(final Param[] csvParams, CSVPropertyType[] properties, String type)
810 throws AnnotationProcessorException {
811
812 CSVSettings settings = new CSVSettings();
813 boolean exceptionOnProcess = false;
814
815 if (csvParams != null && csvParams.length > 0) {
816 for (Param param : csvParams) {
817 CSVPropertyType propertyType = identifyPermittedProperty(param, properties);
818
819 if (propertyType != null) {
820 if ("".equals(param.value())) {
821 LOGGER.warn("{}@RowBean : empty string is not a legal value for {} {}", new Object[] {
822 this.clazz.getSimpleName(), param.name(), type});
823 } else {
824 try {
825 propertyType.setParam(settings, param.value());
826 } catch (AnnotationProcessorException ex) {
827 exceptionOnProcess = true;
828 }
829 }
830 } else {
831 LOGGER.warn("{}@RowBean : {} is not a legal {}, it will be ignored",
832 new Object[] { this.clazz.getSimpleName(), param.name(), type});
833 }
834 }
835 }
836 if (exceptionOnProcess) {
837 throw new AnnotationProcessorException("See logs for more details");
838 }
839 return settings;
840 }
841
842 }