1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.jdtaus.banking.ri.blzdirectory;
22
23 import java.io.IOException;
24 import java.net.URL;
25 import java.text.DateFormat;
26 import java.text.DecimalFormat;
27 import java.text.NumberFormat;
28 import java.text.ParseException;
29 import java.text.SimpleDateFormat;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Date;
33 import java.util.Locale;
34 import java.util.regex.Pattern;
35 import java.util.regex.PatternSyntaxException;
36 import org.jdtaus.banking.Bankleitzahl;
37 import org.jdtaus.banking.BankleitzahlExpirationException;
38 import org.jdtaus.banking.BankleitzahlInfo;
39 import org.jdtaus.banking.BankleitzahlenVerzeichnis;
40 import org.jdtaus.banking.messages.OutdatedBankleitzahlenVerzeichnisMessage;
41 import org.jdtaus.banking.messages.ReadsBankleitzahlenDateiMessage;
42 import org.jdtaus.banking.messages.SearchesBankleitzahlInfosMessage;
43 import org.jdtaus.banking.util.BankleitzahlenDatei;
44 import org.jdtaus.core.container.ContainerFactory;
45 import org.jdtaus.core.container.PropertyException;
46 import org.jdtaus.core.logging.spi.Logger;
47 import org.jdtaus.core.monitor.spi.Task;
48 import org.jdtaus.core.monitor.spi.TaskMonitor;
49 import org.jdtaus.core.text.Message;
50 import org.jdtaus.core.text.MessageEvent;
51 import org.jdtaus.core.text.spi.ApplicationLogger;
52
53
54
55
56
57
58
59
60
61 public class BankfileBankleitzahlenVerzeichnis implements BankleitzahlenVerzeichnis
62 {
63
64
65 private boolean initialized;
66
67
68 private BankleitzahlenDatei bankFile;
69
70
71 private Date dateOfExpiration;
72
73
74 private long lastModificationCheck = System.currentTimeMillis();
75
76
77 private Long reloadIntervalMillis;
78
79
80 private BankfileProvider provider;
81
82
83 private long lastModifiedMillis;
84
85
86 private Long monitoringThreshold;
87
88
89
90
91
92
93
94
95 public BankfileBankleitzahlenVerzeichnis( final long reloadIntervalMillis, final long monitoringThreshold )
96 {
97 this();
98 if ( reloadIntervalMillis > 0 )
99 {
100 this.reloadIntervalMillis = new Long( reloadIntervalMillis );
101 }
102 if ( monitoringThreshold > 0 )
103 {
104 this.monitoringThreshold = new Long( monitoringThreshold );
105 }
106 }
107
108
109
110
111
112
113 public long getReloadIntervalMillis()
114 {
115 if ( this.reloadIntervalMillis == null )
116 {
117 this.reloadIntervalMillis = this.getDefaultReloadIntervalMillis();
118 }
119
120 return this.reloadIntervalMillis.longValue();
121 }
122
123
124
125
126
127
128 public long getMonitoringThreshold()
129 {
130 if ( this.monitoringThreshold == null )
131 {
132 this.monitoringThreshold = this.getDefaultMonitoringThreshold();
133 }
134
135 return this.monitoringThreshold.longValue();
136 }
137
138 public Date getDateOfExpiration()
139 {
140 this.assertValidProperties();
141 this.assertInitialized();
142 return (Date) this.dateOfExpiration.clone();
143 }
144
145 public BankleitzahlInfo getHeadOffice( final Bankleitzahl bankCode ) throws BankleitzahlExpirationException
146 {
147 if ( bankCode == null )
148 {
149 throw new NullPointerException( "bankCode" );
150 }
151
152 this.assertValidProperties();
153 this.assertInitialized();
154
155 BankleitzahlInfo headOffice = this.bankFile.getHeadOfficeRecord( bankCode );
156
157 if ( headOffice == null )
158 {
159 final BankleitzahlInfo deletedHeadOfficeRecord = this.bankFile.getDeletedHeadOfficeRecord( bankCode );
160 final BankleitzahlInfo replacementRecord = this.findReplacementBankeitzahlInfo( deletedHeadOfficeRecord );
161
162 if ( replacementRecord != null
163 && ( replacementRecord.getDeletionDate() == null
164 || replacementRecord.getDeletionDate().before( this.getDateOfExpiration() ) ) )
165 {
166 throw new BankleitzahlExpirationException( deletedHeadOfficeRecord, replacementRecord );
167 }
168 }
169
170 return headOffice;
171 }
172
173 public BankleitzahlInfo[] getBranchOffices( final Bankleitzahl bankCode ) throws BankleitzahlExpirationException
174 {
175 if ( bankCode == null )
176 {
177 throw new NullPointerException( "bankCode" );
178 }
179
180 this.assertValidProperties();
181 this.assertInitialized();
182
183 final BankleitzahlInfo[] branchOfficeRecords = this.bankFile.getBranchOfficeRecords( bankCode );
184
185 if ( branchOfficeRecords.length == 0 )
186 {
187 final BankleitzahlInfo deletedHeadOfficeRecord = this.bankFile.getDeletedHeadOfficeRecord( bankCode );
188 final BankleitzahlInfo replacementRecord = this.findReplacementBankeitzahlInfo( deletedHeadOfficeRecord );
189
190 if ( replacementRecord != null
191 && ( replacementRecord.getDeletionDate() == null
192 || replacementRecord.getDeletionDate().before( this.getDateOfExpiration() ) ) )
193 {
194 throw new BankleitzahlExpirationException( deletedHeadOfficeRecord, replacementRecord );
195 }
196 }
197
198 return branchOfficeRecords;
199 }
200
201 public final BankleitzahlInfo[] search( final String name, final String postalCode, final String city,
202 final boolean branchOffices )
203 {
204 return this.searchBankleitzahlInfos( name, postalCode, city, Boolean.valueOf( !branchOffices ),
205 Boolean.valueOf( branchOffices ) );
206
207 }
208
209 public BankleitzahlInfo[] searchBankleitzahlInfos( final String name, final String postalCode, final String city,
210 final Boolean headOffices, final Boolean branchOffices )
211 {
212 this.assertValidProperties();
213 this.assertInitialized();
214
215 final BankleitzahlInfo[] records =
216 this.bankFile == null ? new BankleitzahlInfo[ 0 ] : this.bankFile.getRecords();
217
218 final Collection col = new ArrayList( records.length );
219
220 if ( records.length > 0 )
221 {
222 final Task task = new Task();
223 task.setCancelable( true );
224 task.setDescription( new SearchesBankleitzahlInfosMessage() );
225 task.setIndeterminate( false );
226 task.setMinimum( 0 );
227 task.setMaximum( records.length - 1 );
228 task.setProgress( 0 );
229
230 try
231 {
232 if ( task.getMaximum() > this.getMonitoringThreshold() )
233 {
234 this.getTaskMonitor().monitor( task );
235 }
236
237 final NumberFormat plzFmt = new DecimalFormat( "00000" );
238 final Pattern namePattern =
239 name != null ? Pattern.compile( ".*" + name.toUpperCase() + ".*" ) : null;
240
241 final Pattern postalPattern =
242 postalCode != null ? Pattern.compile( ".*" + postalCode.toUpperCase() + ".*" ) : null;
243
244 final Pattern cityPattern =
245 city != null ? Pattern.compile( ".*" + city.toUpperCase() + ".*" ) : null;
246
247 for ( int i = records.length - 1; i >= 0 && !task.isCancelled(); i-- )
248 {
249 final String plz = plzFmt.format( records[i].getPostalCode() );
250 task.setProgress( task.getMaximum() - i );
251
252 if ( ( namePattern == null
253 ? true : namePattern.matcher( records[i].getName().toUpperCase() ).matches() )
254 && ( postalPattern == null
255 ? true : postalPattern.matcher( plz ).matches() )
256 && ( cityPattern == null
257 ? true : cityPattern.matcher( records[i].getCity().toUpperCase() ).matches() )
258 && ( headOffices == null
259 ? true : records[i].isHeadOffice() == headOffices.booleanValue() )
260 && ( branchOffices == null
261 ? true : records[i].isHeadOffice() != branchOffices.booleanValue() ) )
262 {
263 col.add( records[i].clone() );
264 }
265 }
266
267 if ( task.isCancelled() )
268 {
269 col.clear();
270 }
271 }
272 catch ( final PatternSyntaxException e )
273 {
274 throw (IllegalArgumentException) new IllegalArgumentException( e.getMessage() ).initCause( e );
275 }
276 finally
277 {
278 if ( task.getMaximum() > this.getMonitoringThreshold() )
279 {
280 this.getTaskMonitor().finish( task );
281 }
282 }
283 }
284
285 return (BankleitzahlInfo[]) col.toArray( new BankleitzahlInfo[ col.size() ] );
286 }
287
288
289
290
291
292
293
294 protected BankleitzahlenDatei getBankfile()
295 {
296 this.assertValidProperties();
297 this.assertInitialized();
298 return this.bankFile;
299 }
300
301
302
303
304
305
306
307
308 private synchronized void assertInitialized()
309 {
310 Task task = null;
311 boolean logExpirationMessage = false;
312
313 try
314 {
315 if ( this.provider == null
316 || System.currentTimeMillis() - this.lastModificationCheck > this.getReloadIntervalMillis() )
317 {
318 this.lastModificationCheck = System.currentTimeMillis();
319 if ( this.provider == null || this.provider.getLastModifiedMillis() != this.lastModifiedMillis )
320 {
321 this.bankFile = null;
322 this.dateOfExpiration = null;
323 this.initialized = false;
324
325 if ( this.provider != null )
326 {
327 this.getLogger().info( this.getReloadInfoMessage(
328 this.getLocale(), new Date( this.lastModifiedMillis ),
329 new Date( this.provider.getLastModifiedMillis() ) ) );
330
331 }
332 }
333 }
334
335 if ( !this.initialized )
336 {
337 final DateFormat dateFormat = new SimpleDateFormat( this.getDateOfExpirationPattern() );
338 this.dateOfExpiration = dateFormat.parse( this.getDateOfExpirationText() );
339 final BankfileProvider bankfileProvider = this.getLatestBankfileProvider();
340
341 if ( bankfileProvider != null && bankfileProvider.getBankfileCount() > 0 )
342 {
343 this.provider = bankfileProvider;
344 this.lastModifiedMillis = bankfileProvider.getLastModifiedMillis();
345 this.dateOfExpiration =
346 bankfileProvider.getDateOfExpiration( bankfileProvider.getBankfileCount() - 1 );
347
348 final URL[] rsrc = new URL[ bankfileProvider.getBankfileCount() ];
349 for ( int i = 0; i < rsrc.length; i++ )
350 {
351 rsrc[i] = bankfileProvider.getBankfile( i );
352 }
353
354 task = new Task();
355 task.setIndeterminate( false );
356 task.setCancelable( false );
357 task.setDescription( new ReadsBankleitzahlenDateiMessage() );
358 task.setMinimum( 0 );
359 task.setProgress( 0 );
360 task.setMaximum( rsrc.length );
361 this.getTaskMonitor().monitor( task );
362
363 int progress = 0;
364 long processedRecords = 0L;
365 task.setProgress( progress++ );
366 this.bankFile = new BankleitzahlenDatei( rsrc[0], bankfileProvider.getFormat( 0 ),
367 bankfileProvider.getDateOfValidity( 0 ),
368 bankfileProvider.getDateOfExpiration( 0 ) );
369
370 processedRecords += this.bankFile.getRecords().length;
371 for ( int i = 1; i < rsrc.length; i++ )
372 {
373 task.setProgress( progress++ );
374 final BankleitzahlenDatei update =
375 new BankleitzahlenDatei( rsrc[i], bankfileProvider.getFormat( i ),
376 bankfileProvider.getDateOfValidity( i ),
377 bankfileProvider.getDateOfExpiration( i ) );
378
379 this.bankFile.update( update );
380 processedRecords += update.getRecords().length;
381 }
382
383
384 if ( this.getLogger().isDebugEnabled() )
385 {
386 for ( int i = 0, l0 = this.bankFile.getDeletedRecords().length; i < l0; i++ )
387 {
388 final BankleitzahlInfo record = this.bankFile.getDeletedRecords()[i];
389
390 if ( record.isHeadOffice() )
391 {
392 this.getLogger().debug( this.getOutdatedInfoMessage(
393 this.getLocale(), record.getBankCode().format( Bankleitzahl.LETTER_FORMAT ) ) );
394
395 }
396 }
397 }
398
399 logExpirationMessage = true;
400 this.initialized = true;
401
402 this.getLogger().info( this.getBankfileInfoMessage(
403 this.getLocale(), new Long( processedRecords ), new Integer( rsrc.length ) ) );
404
405 }
406 else
407 {
408 this.getLogger().warn( this.getNoBankfilesFoundMessage( this.getLocale() ) );
409 }
410 }
411 }
412 catch ( final ParseException e )
413 {
414 throw new RuntimeException( e );
415 }
416 catch ( final IOException e )
417 {
418 throw new RuntimeException( e );
419 }
420 finally
421 {
422 if ( task != null )
423 {
424 this.getTaskMonitor().finish( task );
425 }
426 }
427
428
429 if ( logExpirationMessage )
430 {
431 if ( new Date().after( this.getDateOfExpiration() ) )
432 {
433 this.getApplicationLogger().log( new MessageEvent(
434 this, new Message[]
435 {
436 new OutdatedBankleitzahlenVerzeichnisMessage( this.getDateOfExpiration() )
437 }, MessageEvent.WARNING ) );
438
439 }
440 }
441 }
442
443
444
445
446
447
448 private void assertValidProperties()
449 {
450 if ( this.getReloadIntervalMillis() < 0L )
451 {
452 throw new PropertyException( "reloadIntervalMillis", Long.toString( this.getReloadIntervalMillis() ) );
453 }
454 if ( this.getDateOfExpirationText() == null || this.getDateOfExpirationText().length() == 0 )
455 {
456 throw new PropertyException( "dateOfExpirationText", this.getDateOfExpirationText() );
457 }
458 if ( this.getDateOfExpirationPattern() == null || this.getDateOfExpirationPattern().length() == 0 )
459 {
460 throw new PropertyException( "dateOfExpirationPattern", this.getDateOfExpirationPattern() );
461 }
462
463 try
464 {
465 final DateFormat dateFormat = new SimpleDateFormat( this.getDateOfExpirationPattern() );
466 dateFormat.parse( this.getDateOfExpirationText() );
467 }
468 catch ( final ParseException e )
469 {
470 throw new PropertyException( "dateOfExpirationText", this.getDateOfExpirationText(), e );
471 }
472 }
473
474
475
476
477
478
479
480
481 private BankleitzahlInfo findReplacementBankeitzahlInfo( final BankleitzahlInfo bankInfo )
482 {
483 BankleitzahlInfo replacement = null;
484
485 if ( bankInfo != null && bankInfo.getReplacingBankCode() != null )
486 {
487 replacement = this.bankFile.getHeadOfficeRecord( bankInfo.getReplacingBankCode() );
488
489 if ( replacement == null )
490 {
491 replacement = this.bankFile.getDeletedHeadOfficeRecord( bankInfo.getReplacingBankCode() );
492 }
493
494 final BankleitzahlInfo recurse = this.findReplacementBankeitzahlInfo( replacement );
495
496 if ( recurse != null )
497 {
498 replacement = recurse;
499 }
500 }
501
502 return replacement;
503 }
504
505
506
507
508
509
510
511
512
513
514
515
516 private BankfileProvider getLatestBankfileProvider() throws IOException
517 {
518 final BankfileProvider[] providers = this.getBankfileProvider();
519 BankfileProvider latest = null;
520
521 for ( int i = providers.length - 1; i >= 0; i-- )
522 {
523 if ( providers[i].getBankfileCount() > 0
524 && ( latest == null || latest.getDateOfExpiration( latest.getBankfileCount() - 1 ).
525 before( providers[i].getDateOfExpiration( providers[i].getBankfileCount() - 1 ) ) ) )
526 {
527 latest = providers[i];
528 }
529 }
530
531 return latest;
532 }
533
534
535
536
537
538
539
540 public BankfileBankleitzahlenVerzeichnis()
541 {
542 super();
543 }
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558 private Logger getLogger()
559 {
560 return (Logger) ContainerFactory.getContainer().
561 getDependency( this, "Logger" );
562
563 }
564
565
566
567
568
569
570 private ApplicationLogger getApplicationLogger()
571 {
572 return (ApplicationLogger) ContainerFactory.getContainer().
573 getDependency( this, "ApplicationLogger" );
574
575 }
576
577
578
579
580
581
582 private TaskMonitor getTaskMonitor()
583 {
584 return (TaskMonitor) ContainerFactory.getContainer().
585 getDependency( this, "TaskMonitor" );
586
587 }
588
589
590
591
592
593
594 private BankfileProvider[] getBankfileProvider()
595 {
596 return (BankfileProvider[]) ContainerFactory.getContainer().
597 getDependency( this, "BankfileProvider" );
598
599 }
600
601
602
603
604
605
606 private Locale getLocale()
607 {
608 return (Locale) ContainerFactory.getContainer().
609 getDependency( this, "Locale" );
610
611 }
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626 private java.lang.Long getDefaultReloadIntervalMillis()
627 {
628 return (java.lang.Long) ContainerFactory.getContainer().
629 getProperty( this, "defaultReloadIntervalMillis" );
630
631 }
632
633
634
635
636
637
638 private java.lang.Long getDefaultMonitoringThreshold()
639 {
640 return (java.lang.Long) ContainerFactory.getContainer().
641 getProperty( this, "defaultMonitoringThreshold" );
642
643 }
644
645
646
647
648
649
650 private java.lang.String getDateOfExpirationText()
651 {
652 return (java.lang.String) ContainerFactory.getContainer().
653 getProperty( this, "dateOfExpirationText" );
654
655 }
656
657
658
659
660
661
662 private java.lang.String getDateOfExpirationPattern()
663 {
664 return (java.lang.String) ContainerFactory.getContainer().
665 getProperty( this, "dateOfExpirationPattern" );
666
667 }
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687 private String getOutdatedInfoMessage( final Locale locale,
688 final java.lang.String bankleitzahl )
689 {
690 return ContainerFactory.getContainer().
691 getMessage( this, "outdatedInfo", locale,
692 new Object[]
693 {
694 bankleitzahl
695 });
696
697 }
698
699
700
701
702
703
704
705
706
707
708
709
710 private String getBankfileInfoMessage( final Locale locale,
711 final java.lang.Number entityCount,
712 final java.lang.Number bankfileCount )
713 {
714 return ContainerFactory.getContainer().
715 getMessage( this, "bankfileInfo", locale,
716 new Object[]
717 {
718 entityCount,
719 bankfileCount
720 });
721
722 }
723
724
725
726
727
728
729
730
731
732
733
734
735 private String getReloadInfoMessage( final Locale locale,
736 final java.util.Date lastModification,
737 final java.util.Date lastProviderModification )
738 {
739 return ContainerFactory.getContainer().
740 getMessage( this, "reloadInfo", locale,
741 new Object[]
742 {
743 lastModification,
744 lastProviderModification
745 });
746
747 }
748
749
750
751
752
753
754
755
756
757
758 private String getNoBankfilesFoundMessage( final Locale locale )
759 {
760 return ContainerFactory.getContainer().
761 getMessage( this, "noBankfilesFound", locale, null );
762
763 }
764
765
766
767
768 }