1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.portal.service.csv;
35
36 import au.com.bytecode.opencsv.CSVReader;
37
38 import fr.paris.lutece.portal.business.file.File;
39 import fr.paris.lutece.portal.business.physicalfile.PhysicalFile;
40 import fr.paris.lutece.portal.business.physicalfile.PhysicalFileHome;
41 import fr.paris.lutece.portal.service.i18n.I18nService;
42 import fr.paris.lutece.portal.service.util.AppLogService;
43 import fr.paris.lutece.portal.service.util.AppPropertiesService;
44
45 import org.apache.commons.fileupload.FileItem;
46
47 import java.io.ByteArrayInputStream;
48 import java.io.FileNotFoundException;
49 import java.io.FileReader;
50 import java.io.IOException;
51 import java.io.InputStream;
52 import java.io.InputStreamReader;
53 import java.io.Reader;
54
55 import java.util.ArrayList;
56 import java.util.Collections;
57 import java.util.Iterator;
58 import java.util.List;
59 import java.util.Locale;
60
61
62
63
64
65
66
67
68 public abstract class CSVReaderService
69 {
70 private static final String MESSAGE_NO_FILE_FOUND = "portal.util.message.noFileFound";
71 private static final String MESSAGE_ERROR_READING_FILE = "portal.util.message.errorReadingFile";
72 private static final String MESSAGE_ERROR_NUMBER_COLUMNS = "portal.xsl.message.errorNumberColumns";
73 private static final String MESSAGE_UNKOWN_ERROR = "portal.xsl.message.errorUnknown";
74 private static final String PROPERTY_DEFAULT_CSV_SEPARATOR = "lutece.csvReader.defaultCSVSeparator";
75 private static final String PROPERTY_DEFAULT_CSV_ESCAPE_CHARACTER = "lutece.csvReader.defaultCSVEscapeCharacter";
76 private static final String CONSTANT_DEFAULT_CSV_SEPARATOR = ";";
77 private static final String CONSTANT_DEFAULT_CSV_ESCAPE_CHARACTER = "\"";
78 private Character _strCSVSeparator;
79 private Character _strCSVEscapeCharacter;
80
81
82
83
84
85
86
87
88
89 protected abstract List<CSVMessageDescriptor> readLineOfCSVFile( String[] strLineDataArray, int nLineNumber,
90 Locale locale, String strBaseUrl );
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 protected abstract List<CSVMessageDescriptor> checkLineOfCSVFile( String[] strLineDataArray, int nLineNumber,
107 Locale locale );
108
109
110
111
112
113
114
115
116
117 protected abstract List<CSVMessageDescriptor> getEndOfProcessMessages( int nNbLineParses,
118 int nNbLinesWithoutErrors, Locale locale );
119
120
121
122
123
124
125 public static Character getDefaultCSVSeparator( )
126 {
127 return AppPropertiesService.getProperty( PROPERTY_DEFAULT_CSV_SEPARATOR, CONSTANT_DEFAULT_CSV_SEPARATOR )
128 .charAt( 0 );
129 }
130
131
132
133
134
135
136 public static Character getDefaultCSVEscapeCharacter( )
137 {
138 return AppPropertiesService.getProperty( PROPERTY_DEFAULT_CSV_ESCAPE_CHARACTER,
139 CONSTANT_DEFAULT_CSV_ESCAPE_CHARACTER ).charAt( 0 );
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 public List<CSVMessageDescriptor> readCSVFile( FileItem fileItem, int nColumnNumber,
169 boolean bCheckFileBeforeProcessing, boolean bExitOnError, boolean bSkipFirstLine, Locale locale,
170 String strBaseUrl )
171 {
172 if ( fileItem != null )
173 {
174 InputStreamReader inputStreamReader = null;
175
176 try
177 {
178 inputStreamReader = new InputStreamReader( fileItem.getInputStream( ) );
179 }
180 catch ( IOException e )
181 {
182 AppLogService.error( e.getMessage( ), e );
183 }
184
185 if ( inputStreamReader != null )
186 {
187 CSVReader csvReader = new CSVReader( inputStreamReader, getCSVSeparator( ), getCSVEscapeCharacter( ) );
188
189 return readCSVFile( inputStreamReader, csvReader, nColumnNumber, bCheckFileBeforeProcessing,
190 bExitOnError, bSkipFirstLine, locale, strBaseUrl );
191 }
192 }
193
194 List<CSVMessageDescriptor> listErrors = new ArrayList<CSVMessageDescriptor>( );
195 CSVMessageDescriptor errorDescription = new CSVMessageDescriptor( CSVMessageLevel.ERROR, 0,
196 I18nService.getLocalizedString( MESSAGE_NO_FILE_FOUND, locale ) );
197 listErrors.add( errorDescription );
198
199 return listErrors;
200 }
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226 public List<CSVMessageDescriptor> readCSVFile( String strPath, int nColumnNumber,
227 boolean bCheckFileBeforeProcessing, boolean bExitOnError, boolean bSkipFirstLine, Locale locale,
228 String strBaseUrl )
229 {
230 java.io.File file = new java.io.File( strPath );
231
232 try
233 {
234 FileReader fileReader = new FileReader( file );
235 CSVReader csvReader = new CSVReader( fileReader, getCSVSeparator( ), getCSVEscapeCharacter( ) );
236
237 return readCSVFile( fileReader, csvReader, nColumnNumber, bCheckFileBeforeProcessing, bExitOnError,
238 bSkipFirstLine, locale, strBaseUrl );
239 }
240 catch ( FileNotFoundException e )
241 {
242 AppLogService.error( e.getMessage( ), e );
243 }
244
245 List<CSVMessageDescriptor> listErrors = new ArrayList<CSVMessageDescriptor>( );
246 CSVMessageDescriptor errorDescription = new CSVMessageDescriptor( CSVMessageLevel.ERROR, 0,
247 I18nService.getLocalizedString( MESSAGE_NO_FILE_FOUND, locale ) );
248 listErrors.add( errorDescription );
249
250 return listErrors;
251 }
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278 public List<CSVMessageDescriptor> readCSVFile( File file, int nColumnNumber, boolean bCheckFileBeforeProcessing,
279 boolean bExitOnError, boolean bSkipFirstLine, Locale locale, String strBaseUrl )
280 {
281 return readCSVFile( file.getPhysicalFile( ), nColumnNumber, bCheckFileBeforeProcessing, bExitOnError,
282 bSkipFirstLine, locale, strBaseUrl );
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311 public List<CSVMessageDescriptor> readCSVFile( PhysicalFile physicalFile, int nColumnNumber,
312 boolean bCheckFileBeforeProcessing, boolean bExitOnError, boolean bSkipFirstLine, Locale locale,
313 String strBaseUrl )
314 {
315 PhysicalFile importedPhysicalFile = physicalFile;
316
317 if ( ( importedPhysicalFile != null ) && ( importedPhysicalFile.getValue( ) == null ) )
318 {
319 if ( importedPhysicalFile.getValue( ) == null )
320 {
321 importedPhysicalFile = PhysicalFileHome.findByPrimaryKey( importedPhysicalFile.getIdPhysicalFile( ) );
322 }
323
324 if ( ( importedPhysicalFile != null ) && ( importedPhysicalFile.getValue( ) == null ) )
325 {
326 InputStream inputStream = new ByteArrayInputStream( importedPhysicalFile.getValue( ) );
327 InputStreamReader inputStreamReader = new InputStreamReader( inputStream );
328 CSVReader csvReader = new CSVReader( inputStreamReader, getCSVSeparator( ), getCSVEscapeCharacter( ) );
329
330 return readCSVFile( inputStreamReader, csvReader, nColumnNumber, bCheckFileBeforeProcessing,
331 bExitOnError, bSkipFirstLine, locale, strBaseUrl );
332 }
333 }
334
335 List<CSVMessageDescriptor> listErrors = new ArrayList<CSVMessageDescriptor>( );
336 CSVMessageDescriptor errorDescription = new CSVMessageDescriptor( CSVMessageLevel.ERROR, 0,
337 I18nService.getLocalizedString( MESSAGE_NO_FILE_FOUND, locale ) );
338 listErrors.add( errorDescription );
339
340 return listErrors;
341 }
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368 protected List<CSVMessageDescriptor> readCSVFile( Reader reader, CSVReader csvReader, int nColumnNumber,
369 boolean bCheckFileBeforeProcessing, boolean bExitOnError, boolean bSkipFirstLine, Locale locale,
370 String strBaseUrl )
371 {
372 List<CSVMessageDescriptor> listMessages = new ArrayList<CSVMessageDescriptor>( );
373 int nLineNumber = 0;
374
375 if ( bSkipFirstLine )
376 {
377 try
378 {
379 nLineNumber++;
380 csvReader.readNext( );
381 }
382 catch ( IOException e )
383 {
384 AppLogService.error( e.getMessage( ), e );
385
386 CSVMessageDescriptor error = new CSVMessageDescriptor( CSVMessageLevel.ERROR, 1,
387 I18nService.getLocalizedString( MESSAGE_ERROR_READING_FILE, locale ) );
388 listMessages.add( error );
389
390 if ( bExitOnError )
391 {
392 try
393 {
394 csvReader.close( );
395 reader.close( );
396 }
397 catch ( IOException ex )
398 {
399 AppLogService.error( ex.getMessage( ), ex );
400 }
401
402 return listMessages;
403 }
404 }
405 }
406
407 List<String[]> listLines = null;
408
409 if ( bCheckFileBeforeProcessing )
410 {
411 listLines = new ArrayList<String[]>( );
412
413 String[] strLine = null;
414
415 do
416 {
417 try
418 {
419 nLineNumber++;
420 strLine = csvReader.readNext( );
421 }
422 catch ( IOException e )
423 {
424 AppLogService.error( e.getMessage( ), e );
425
426 CSVMessageDescriptor error = new CSVMessageDescriptor( CSVMessageLevel.ERROR, nLineNumber,
427 I18nService.getLocalizedString( MESSAGE_ERROR_READING_FILE, locale ) );
428 listMessages.add( error );
429
430 if ( bExitOnError )
431 {
432 try
433 {
434 csvReader.close( );
435 reader.close( );
436 }
437 catch ( IOException ex )
438 {
439 AppLogService.error( ex.getMessage( ), ex );
440 }
441
442 Collections.sort( listMessages );
443
444 return listMessages;
445 }
446 }
447
448 if ( strLine != null )
449 {
450 listLines.add( strLine );
451 }
452 }
453 while ( strLine != null );
454
455 List<CSVMessageDescriptor> listCheckErrors = checkCSVFileValidity( listLines, nColumnNumber,
456 bSkipFirstLine, locale );
457
458 if ( listCheckErrors.size( ) > 0 )
459 {
460 if ( doesListMessageContainError( listCheckErrors ) )
461 {
462 listCheckErrors.addAll( 0, listMessages );
463
464 try
465 {
466 csvReader.close( );
467 reader.close( );
468 }
469 catch ( IOException ex )
470 {
471 AppLogService.error( ex.getMessage( ), ex );
472 }
473
474 Collections.sort( listMessages );
475
476 return listCheckErrors;
477 }
478 }
479
480 nLineNumber = 0;
481 }
482
483 boolean bHasMoreLines = true;
484 int nNbLinesWithoutErrors = 0;
485 String[] strLine = null;
486 Iterator<String[]> iterator = null;
487
488 if ( listLines != null )
489 {
490 iterator = listLines.iterator( );
491 }
492
493 while ( bHasMoreLines )
494 {
495 nLineNumber++;
496
497 if ( iterator != null )
498 {
499 if ( iterator.hasNext( ) )
500 {
501 strLine = iterator.next( );
502 }
503 else
504 {
505 strLine = null;
506 bHasMoreLines = false;
507 }
508 }
509 else
510 {
511 try
512 {
513 strLine = csvReader.readNext( );
514 }
515 catch ( IOException e )
516 {
517 strLine = null;
518 AppLogService.error( e.getMessage( ), e );
519
520 CSVMessageDescriptor error = new CSVMessageDescriptor( CSVMessageLevel.ERROR, nLineNumber,
521 I18nService.getLocalizedString( MESSAGE_ERROR_READING_FILE, locale ) );
522 listMessages.add( error );
523
524 if ( bExitOnError )
525 {
526 bHasMoreLines = false;
527 }
528 }
529 }
530
531 if ( strLine != null )
532 {
533 try
534 {
535 List<CSVMessageDescriptor> listLinesMessages = null;
536
537 if ( !bCheckFileBeforeProcessing )
538 {
539 listLinesMessages = checkCSVLineColumnNumber( strLine, nColumnNumber, nLineNumber, locale );
540
541 if ( !doesListMessageContainError( listLinesMessages ) )
542 {
543 List<CSVMessageDescriptor> listFileCheckMessages = checkLineOfCSVFile( strLine,
544 nLineNumber, locale );
545
546 if ( ( listFileCheckMessages != null ) && ( listFileCheckMessages.size( ) > 0 ) )
547 {
548 if ( ( listLinesMessages != null ) && ( listLinesMessages.size( ) > 0 ) )
549 {
550 listLinesMessages.addAll( listFileCheckMessages );
551 }
552 else
553 {
554 listLinesMessages = listFileCheckMessages;
555 }
556 }
557 }
558
559 if ( ( listLinesMessages != null ) && ( listLinesMessages.size( ) > 0 ) )
560 {
561 listMessages.addAll( listLinesMessages );
562 }
563 }
564
565
566 if ( !doesListMessageContainError( listLinesMessages ) )
567 {
568 List<CSVMessageDescriptor> listMessagesOfCurrentLine = readLineOfCSVFile( strLine, nLineNumber,
569 locale, strBaseUrl );
570
571 if ( ( listMessagesOfCurrentLine != null ) && ( listMessagesOfCurrentLine.size( ) > 0 ) )
572 {
573 listMessages.addAll( listMessagesOfCurrentLine );
574 }
575
576 if ( doesListMessageContainError( listMessagesOfCurrentLine ) )
577 {
578 if ( bExitOnError )
579 {
580 bHasMoreLines = false;
581 }
582 }
583 else
584 {
585 nNbLinesWithoutErrors++;
586 }
587 }
588 }
589 catch ( Exception e )
590 {
591 AppLogService.error( e.getMessage( ), e );
592
593 CSVMessageDescriptor error = new CSVMessageDescriptor( CSVMessageLevel.ERROR, nLineNumber,
594 I18nService.getLocalizedString( MESSAGE_UNKOWN_ERROR, locale ) );
595 listMessages.add( error );
596
597 if ( bExitOnError )
598 {
599 bHasMoreLines = false;
600 }
601 }
602 }
603 else
604 {
605 bHasMoreLines = false;
606 }
607 }
608
609 try
610 {
611 csvReader.close( );
612 reader.close( );
613 }
614 catch ( IOException ex )
615 {
616 AppLogService.error( ex.getMessage( ), ex );
617 }
618
619
620 nLineNumber--;
621
622 if ( bSkipFirstLine )
623 {
624 nLineNumber--;
625 }
626
627 List<CSVMessageDescriptor> listMessagesEndOfProcess = getEndOfProcessMessages( nLineNumber,
628 nNbLinesWithoutErrors, locale );
629
630 if ( ( listMessagesEndOfProcess != null ) && ( listMessagesEndOfProcess.size( ) > 0 ) )
631 {
632 listMessages.addAll( 0, listMessagesEndOfProcess );
633 }
634
635 Collections.sort( listMessages );
636
637 return listMessages;
638 }
639
640
641
642
643
644
645
646
647
648
649 protected List<CSVMessageDescriptor> checkCSVFileValidity( List<String[]> listLines, int nColumnNumber,
650 boolean bSkipFirstLine, Locale locale )
651 {
652 List<CSVMessageDescriptor> listErrors = new ArrayList<CSVMessageDescriptor>( );
653 int nLineNumber = 0;
654
655 if ( bSkipFirstLine )
656 {
657 nLineNumber++;
658 }
659
660 for ( String[] strLine : listLines )
661 {
662 nLineNumber++;
663
664 List<CSVMessageDescriptor> listMessages = checkCSVLineColumnNumber( strLine, nColumnNumber, nLineNumber,
665 locale );
666
667 if ( ( listMessages != null ) && ( listMessages.size( ) > 0 ) )
668 {
669 listErrors.addAll( listMessages );
670 }
671
672 if ( !doesListMessageContainError( listMessages ) )
673 {
674 listMessages = checkLineOfCSVFile( strLine, nLineNumber, locale );
675
676 if ( ( listMessages != null ) && ( listMessages.size( ) > 0 ) )
677 {
678 listErrors.addAll( listMessages );
679 }
680 }
681 }
682
683 return listErrors;
684 }
685
686
687
688
689
690
691
692
693
694 protected List<CSVMessageDescriptor> checkCSVLineColumnNumber( String[] strLine, int nColumnNumber,
695 int nLineNumber, Locale locale )
696 {
697 if ( ( strLine == null ) || ( ( nColumnNumber > 0 ) && ( strLine.length != nColumnNumber ) ) )
698 {
699 List<CSVMessageDescriptor> listMessages = new ArrayList<CSVMessageDescriptor>( );
700 Object[] args = { ( strLine == null ) ? 0 : strLine.length, nColumnNumber };
701 String strErrorMessage = I18nService.getLocalizedString( MESSAGE_ERROR_NUMBER_COLUMNS, args, locale );
702 CSVMessageDescriptor error = new CSVMessageDescriptor( CSVMessageLevel.ERROR, nLineNumber, strErrorMessage );
703 listMessages.add( error );
704
705 return listMessages;
706 }
707
708 return null;
709 }
710
711
712
713
714
715
716
717 public Character getCSVSeparator( )
718 {
719 if ( this._strCSVSeparator == null )
720 {
721 this._strCSVSeparator = getDefaultCSVSeparator( );
722 }
723
724 return _strCSVSeparator;
725 }
726
727
728
729
730
731 public void setCSVSeparator( Character strCSVSeparator )
732 {
733 this._strCSVSeparator = strCSVSeparator;
734 }
735
736
737
738
739
740
741
742 public Character getCSVEscapeCharacter( )
743 {
744 if ( this._strCSVEscapeCharacter == null )
745 {
746 this._strCSVEscapeCharacter = getDefaultCSVEscapeCharacter( );
747 }
748
749 return _strCSVEscapeCharacter;
750 }
751
752
753
754
755
756 public void setCSVEscapeCharacter( Character strCSVEscapeCharacter )
757 {
758 this._strCSVEscapeCharacter = strCSVEscapeCharacter;
759 }
760
761
762
763
764
765
766
767
768 private boolean doesListMessageContainError( List<CSVMessageDescriptor> listMessageOfCurrentLine )
769 {
770 if ( ( listMessageOfCurrentLine != null ) && ( listMessageOfCurrentLine.size( ) > 0 ) )
771 {
772 for ( CSVMessageDescriptor message : listMessageOfCurrentLine )
773 {
774 if ( message.getMessageLevel( ) == CSVMessageLevel.ERROR )
775 {
776 return true;
777 }
778 }
779 }
780
781 return false;
782 }
783 }