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.dtaus.ri.zka;
22
23 import java.io.IOException;
24 import java.text.ParseException;
25 import java.util.Arrays;
26 import java.util.Calendar;
27 import java.util.Date;
28 import java.util.EventListener;
29 import java.util.Locale;
30 import javax.swing.event.EventListenerList;
31 import org.jdtaus.banking.AlphaNumericText27;
32 import org.jdtaus.banking.TextschluesselVerzeichnis;
33 import org.jdtaus.banking.dtaus.Checksum;
34 import org.jdtaus.banking.dtaus.CorruptedException;
35 import org.jdtaus.banking.dtaus.Header;
36 import org.jdtaus.banking.dtaus.LogicalFile;
37 import org.jdtaus.banking.dtaus.Transaction;
38 import org.jdtaus.banking.dtaus.spi.CurrencyCounter;
39 import org.jdtaus.banking.dtaus.spi.Fields;
40 import org.jdtaus.banking.dtaus.spi.HeaderValidator;
41 import org.jdtaus.banking.dtaus.spi.IllegalHeaderException;
42 import org.jdtaus.banking.dtaus.spi.IllegalTransactionException;
43 import org.jdtaus.banking.dtaus.spi.TransactionValidator;
44 import org.jdtaus.banking.messages.ChecksumErrorMessage;
45 import org.jdtaus.banking.messages.ChecksumsFileMessage;
46 import org.jdtaus.banking.messages.IllegalDataMessage;
47 import org.jdtaus.banking.spi.CurrencyMapper;
48 import org.jdtaus.core.container.ContainerFactory;
49 import org.jdtaus.core.container.Implementation;
50 import org.jdtaus.core.io.FileOperations;
51 import org.jdtaus.core.io.util.FlushableFileOperations;
52 import org.jdtaus.core.lang.spi.MemoryManager;
53 import org.jdtaus.core.logging.spi.Logger;
54 import org.jdtaus.core.messages.DeletesBlocksMessage;
55 import org.jdtaus.core.messages.InsertsBlocksMessage;
56 import org.jdtaus.core.monitor.spi.Task;
57 import org.jdtaus.core.monitor.spi.TaskMonitor;
58 import org.jdtaus.core.nio.util.Charsets;
59 import org.jdtaus.core.text.Message;
60 import org.jdtaus.core.text.spi.ApplicationLogger;
61
62
63
64
65
66
67
68
69
70
71 public abstract class AbstractLogicalFile implements LogicalFile
72 {
73
74 public interface Listener extends EventListener
75 {
76
77
78
79
80
81
82
83
84
85
86 void bytesInserted( long position, long bytes ) throws IOException;
87
88
89
90
91
92
93
94
95
96
97 void bytesDeleted( long position, long bytes ) throws IOException;
98
99 }
100
101
102 protected static final int ENCODING_ASCII = 1;
103
104
105 protected static final int ENCODING_EBCDI = 2;
106
107
108 protected static final long NO_NUMBER = Long.MIN_VALUE;
109
110
111 protected static final int MAX_SCHEDULEDAYS = 15;
112
113
114 private static final int MAX_TRANSACTIONS = 9999999;
115
116
117 private static final long VALID_DATES_START_MILLIS = 315529200000L;
118
119
120 private static final long VALID_DATES_END_MILLIS = 3471289199999L;
121
122
123 private static final int FORMAT_MAX_DIGITS = 17;
124
125
126 private static final int FORMAT_MAX_CHARS = 105;
127
128
129
130
131
132 protected static final long[] EXP10 = new long[ FORMAT_MAX_DIGITS + 1 ];
133
134
135
136
137
138 private static final byte[] DIGITS_TO_ASCII =
139 {
140 48, 49, 50, 51, 52, 53, 54, 55, 56, 57
141 };
142
143
144
145
146
147 private static final byte[] ASCII_TO_DIGITS = new byte[ 60 ];
148
149
150
151
152
153 private static final byte[] DIGITS_TO_EBCDI =
154 {
155 (byte) 0xF0, (byte) 0xF1, (byte) 0xF2, (byte) 0xF3, (byte) 0xF4, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7,
156 (byte) 0xF8, (byte) 0xF9
157 };
158
159
160
161
162
163 private static final byte[] EBCDI_TO_DIGITS = new byte[ 0xFA ];
164
165
166 private static final String DIN66003 = "ISO646-DE";
167
168
169 private static final String IBM273 = "IBM273";
170
171
172 private static final byte ASCII_SPACE = (byte) 32;
173
174
175 private static final byte EBCDI_SPACE = (byte) 0x40;
176
177
178 private FileOperations fileOperations;
179
180
181 private long headerPosition;
182
183
184 private long checksumPosition;
185
186
187
188
189
190 private long[] index;
191
192
193 private Header cachedHeader = null;
194
195
196 private Checksum cachedChecksum = null;
197
198
199 private final Calendar calendar = Calendar.getInstance( Locale.GERMANY );
200
201
202 private final byte[] buffer = new byte[ FORMAT_MAX_CHARS + 1 ];
203
204
205 private final StringBuffer shortDateBuffer = new StringBuffer( 6 );
206
207
208 private final StringBuffer longDateBuffer = new StringBuffer( 8 );
209
210
211 private CurrencyCounter counter;
212
213
214 private Configuration configuration;
215
216
217 private Integer monitoringThreshold;
218
219
220 private final EventListenerList listeners = new EventListenerList();
221
222
223 private byte[] defaultBuffer;
224
225
226
227
228
229 private Long maximumExtensionCount;
230
231
232 static
233 {
234 for ( int i = 0; i <= FORMAT_MAX_DIGITS; i++ )
235 {
236 EXP10[i] = (long) Math.floor( Math.pow( 10.00D, i ) );
237 }
238
239 Arrays.fill( ASCII_TO_DIGITS, (byte) -1 );
240 Arrays.fill( EBCDI_TO_DIGITS, (byte) -1 );
241 ASCII_TO_DIGITS[48] = 0;
242 ASCII_TO_DIGITS[49] = 1;
243 ASCII_TO_DIGITS[50] = 2;
244 ASCII_TO_DIGITS[51] = 3;
245 ASCII_TO_DIGITS[52] = 4;
246 ASCII_TO_DIGITS[53] = 5;
247 ASCII_TO_DIGITS[54] = 6;
248 ASCII_TO_DIGITS[55] = 7;
249 ASCII_TO_DIGITS[56] = 8;
250 ASCII_TO_DIGITS[57] = 9;
251 EBCDI_TO_DIGITS[0xF0] = 0;
252 EBCDI_TO_DIGITS[0xF1] = 1;
253 EBCDI_TO_DIGITS[0xF2] = 2;
254 EBCDI_TO_DIGITS[0xF3] = 3;
255 EBCDI_TO_DIGITS[0xF4] = 4;
256 EBCDI_TO_DIGITS[0xF5] = 5;
257 EBCDI_TO_DIGITS[0xF6] = 6;
258 EBCDI_TO_DIGITS[0xF7] = 7;
259 EBCDI_TO_DIGITS[0xF8] = 8;
260 EBCDI_TO_DIGITS[0xF9] = 9;
261 }
262
263
264
265
266
267
268
269
270
271 protected AbstractLogicalFile()
272 {
273 this.calendar.setLenient( false );
274 Arrays.fill( this.buffer, (byte) -1 );
275 }
276
277
278
279
280
281
282 protected Configuration getConfiguration()
283 {
284 if ( this.configuration == null )
285 {
286 this.configuration = new Configuration();
287 }
288
289 return this.configuration;
290 }
291
292
293
294
295
296
297 protected void setConfiguration( final Configuration configuration )
298 {
299 this.configuration = configuration;
300 }
301
302
303
304
305
306
307 protected long getHeaderPosition()
308 {
309 return this.headerPosition;
310 }
311
312
313
314
315
316
317
318
319
320 protected void setHeaderPosition( final long headerPosition ) throws IOException
321 {
322 if ( headerPosition < 0L )
323 {
324 throw new IllegalArgumentException( Long.toString( headerPosition ) );
325 }
326
327 this.headerPosition = headerPosition;
328 }
329
330
331
332
333
334
335 protected long getChecksumPosition()
336 {
337 return this.checksumPosition;
338 }
339
340
341
342
343
344
345
346
347
348 protected void setChecksumPosition( final long checksumPosition ) throws IOException
349 {
350 if ( checksumPosition <= this.getHeaderPosition() )
351 {
352 throw new IllegalArgumentException( Long.toString( checksumPosition ) );
353 }
354
355 this.checksumPosition = checksumPosition;
356 }
357
358
359
360
361
362
363 protected FileOperations getFileOperations()
364 {
365 return this.fileOperations;
366 }
367
368
369
370
371
372
373
374
375
376 protected void setFileOperations( final FileOperations fileOperations ) throws IOException
377 {
378 if ( fileOperations == null )
379 {
380 throw new NullPointerException( "fileOperations" );
381 }
382
383 if ( this.fileOperations != null && this.fileOperations instanceof FlushableFileOperations )
384 {
385 ( (FlushableFileOperations) this.fileOperations ).flush();
386 }
387
388 this.fileOperations = fileOperations;
389 this.cachedHeader = null;
390 this.cachedChecksum = null;
391 this.index = null;
392 Arrays.fill( this.buffer, (byte) -1 );
393 }
394
395
396
397
398
399
400 public int getMonitoringThreshold()
401 {
402 if ( this.monitoringThreshold == null )
403 {
404 this.monitoringThreshold = this.getDefaultMonitoringThreshold();
405 }
406
407 return this.monitoringThreshold.intValue();
408 }
409
410
411
412
413
414
415 public void setMonitoringThreshold( final int value )
416 {
417 this.monitoringThreshold = new Integer( value );
418 }
419
420
421
422
423
424
425
426
427 public long getMaximumExtensionCount()
428 {
429 if ( this.maximumExtensionCount == null )
430 {
431 this.maximumExtensionCount = this.getDefaultMaximumExtensionCount();
432 }
433
434 return this.maximumExtensionCount.longValue();
435 }
436
437
438
439
440
441
442
443
444 public void setMaximumExtensionCount( final Long value )
445 {
446 this.maximumExtensionCount = value;
447 }
448
449
450
451
452
453
454
455
456 public void addListener( final Listener listener )
457 {
458 this.listeners.add( Listener.class, listener );
459 }
460
461
462
463
464
465
466
467
468 public void removeFileOperationsListener( final Listener listener )
469 {
470 this.listeners.remove( Listener.class, listener );
471 }
472
473
474
475
476
477
478 public Listener[] getListeners()
479 {
480 return (Listener[]) this.listeners.getListeners( Listener.class );
481 }
482
483
484
485
486
487
488
489
490
491 protected void fireBytesInserted( final long position, final long bytes ) throws IOException
492 {
493 final Object[] list = this.listeners.getListenerList();
494 for ( int i = list.length - 2; i >= 0; i -= 2 )
495 {
496 if ( list[i] == Listener.class )
497 {
498 ( (Listener) list[i + 1] ).bytesInserted( position, bytes );
499 }
500 }
501 }
502
503
504
505
506
507
508
509
510
511 protected void fireBytesDeleted( final long position, final long bytes ) throws IOException
512 {
513 final Object[] list = this.listeners.getListenerList();
514 for ( int i = list.length - 2; i >= 0; i -= 2 )
515 {
516 if ( list[i] == Listener.class )
517 {
518 ( (Listener) list[i + 1] ).bytesDeleted( position, bytes );
519 }
520 }
521 }
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545 protected Long readNumber( final int field, final long position, final int len, final int encoding )
546 throws IOException
547 {
548 return this.readNumber(
549 field, position, len, encoding, this.getConfiguration().isSpaceCharacterAllowed( field ) );
550
551 }
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580 protected Long readNumber( final int field, final long position, final int len, final int encoding,
581 final boolean allowSpaces ) throws IOException
582 {
583 long ret = 0L;
584 final byte space;
585 final byte[] table;
586 final byte[] revTable;
587 final String cset;
588 String logViolation = null;
589
590 if ( encoding == ENCODING_ASCII )
591 {
592 table = DIGITS_TO_ASCII;
593 revTable = ASCII_TO_DIGITS;
594 space = ASCII_SPACE;
595 cset = DIN66003;
596 }
597 else if ( encoding == ENCODING_EBCDI )
598 {
599 table = DIGITS_TO_EBCDI;
600 revTable = EBCDI_TO_DIGITS;
601 space = EBCDI_SPACE;
602 cset = IBM273;
603 }
604 else
605 {
606 throw new IllegalArgumentException( Integer.toString( encoding ) );
607 }
608
609 this.fileOperations.setFilePointer( position );
610 this.fileOperations.read( this.buffer, 0, len );
611
612 for ( int read = 0; read < len; read++ )
613 {
614 if ( allowSpaces && this.buffer[read] == space )
615 {
616 if ( logViolation == null )
617 {
618 logViolation = Charsets.decode( this.buffer, 0, len, cset );
619 }
620
621 this.buffer[read] = table[0];
622 }
623
624 if ( !( this.buffer[read] >= table[0] && this.buffer[read] <= table[9] ) )
625 {
626 if ( ThreadLocalMessages.isErrorsEnabled() )
627 {
628 throw new CorruptedException( this.getImplementation(), position );
629 }
630 else
631 {
632 final Message msg = new IllegalDataMessage(
633 field, IllegalDataMessage.TYPE_NUMERIC, position,
634 Charsets.decode( this.buffer, 0, len, cset ) );
635
636 ThreadLocalMessages.getMessages().addMessage( msg );
637 }
638
639 ret = NO_NUMBER;
640 logViolation = null;
641 break;
642 }
643 else
644 {
645 ret += revTable[this.buffer[read] & 0xFF] * EXP10[len - read - 1];
646 }
647 }
648
649 if ( logViolation != null )
650 {
651 if ( this.getLogger().isInfoEnabled() )
652 {
653 this.getLogger().info( this.getReadNumberIllegalFileInfoMessage(
654 this.getLocale(), logViolation, new Long( ret ) ) );
655
656 }
657 }
658
659 return new Long( ret );
660 }
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679 protected void writeNumber( final int field, final long position, final int len, long number, final int encoding )
680 throws IOException
681 {
682 int i;
683 int pos;
684 final long maxValue = EXP10[len] - 1L;
685 int digit;
686 final byte[] table;
687
688 if ( number < 0L || number > maxValue )
689 {
690 throw new IllegalArgumentException( Long.toString( number ) );
691 }
692
693 if ( encoding == ENCODING_ASCII )
694 {
695 table = DIGITS_TO_ASCII;
696 }
697 else if ( encoding == ENCODING_EBCDI )
698 {
699 table = DIGITS_TO_EBCDI;
700 }
701 else
702 {
703 throw new IllegalArgumentException( Integer.toString( encoding ) );
704 }
705
706 for ( i = len - 1, pos = 0; i >= 0; i--, pos++ )
707 {
708 digit = (int) Math.floor( number / EXP10[i] );
709 number -= ( digit * EXP10[i] );
710 this.buffer[pos] = table[digit];
711 }
712
713 this.fileOperations.setFilePointer( position );
714 this.fileOperations.write( this.buffer, 0, len );
715 }
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738 protected AlphaNumericText27 readAlphaNumeric( final int field, final long position, final int len,
739 final int encoding ) throws IOException
740 {
741 final String cset;
742 final String str;
743 AlphaNumericText27 txt = null;
744
745 if ( encoding == ENCODING_ASCII )
746 {
747 cset = DIN66003;
748 }
749 else if ( encoding == ENCODING_EBCDI )
750 {
751 cset = IBM273;
752 }
753 else
754 {
755 throw new IllegalArgumentException( Integer.toString( encoding ) );
756 }
757
758 this.fileOperations.setFilePointer( position );
759 this.fileOperations.read( this.buffer, 0, len );
760 str = Charsets.decode( this.buffer, 0, len, cset );
761
762 try
763 {
764 txt = AlphaNumericText27.parse( str );
765 }
766 catch ( ParseException e )
767 {
768 if ( this.getLogger().isDebugEnabled() )
769 {
770 this.getLogger().debug( e.toString() );
771 }
772
773 txt = null;
774 if ( ThreadLocalMessages.isErrorsEnabled() )
775 {
776 throw new CorruptedException( this.getImplementation(), position );
777 }
778 else
779 {
780 final Message msg =
781 new IllegalDataMessage( field, IllegalDataMessage.TYPE_ALPHA_NUMERIC, position, str );
782
783 ThreadLocalMessages.getMessages().addMessage( msg );
784 }
785 }
786
787 return txt;
788 }
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809 protected void writeAlphaNumeric( final int field, final long position, final int len, final String str,
810 final int encoding ) throws IOException
811 {
812 final int length;
813 final int delta;
814 final char[] c;
815 final byte[] buf;
816 final byte space;
817 final String cset;
818
819 if ( str == null )
820 {
821 throw new NullPointerException( "str" );
822 }
823 if ( ( length = str.length() ) > len )
824 {
825 throw new IllegalArgumentException( str );
826 }
827
828 if ( encoding == ENCODING_ASCII )
829 {
830 space = ASCII_SPACE;
831 cset = DIN66003;
832 }
833 else if ( encoding == ENCODING_EBCDI )
834 {
835 space = EBCDI_SPACE;
836 cset = IBM273;
837 }
838 else
839 {
840 throw new IllegalArgumentException( Integer.toString( encoding ) );
841 }
842
843 c = str.toCharArray();
844 for ( int i = c.length - 1; i >= 0; i-- )
845 {
846 if ( !AlphaNumericText27.checkAlphaNumeric( c[i] ) )
847 {
848 throw new IllegalArgumentException( Character.toString( c[i] ) );
849 }
850 }
851
852 buf = Charsets.encode( str, cset );
853 if ( length < len )
854 {
855 delta = len - length;
856 System.arraycopy( buf, 0, this.buffer, 0, buf.length );
857 Arrays.fill( this.buffer, buf.length, buf.length + delta, space );
858 }
859 else
860 {
861 System.arraycopy( buf, 0, this.buffer, 0, buf.length );
862 }
863
864 this.fileOperations.setFilePointer( position );
865 this.fileOperations.write( this.buffer, 0, len );
866 }
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890 protected Date readShortDate( final int field, final long position, final int encoding ) throws IOException
891 {
892 final int len;
893 final String cset;
894
895 Date ret = null;
896 String str = null;
897 boolean legal = false;
898 Message msg;
899
900 if ( encoding == ENCODING_ASCII )
901 {
902 cset = DIN66003;
903 }
904 else if ( encoding == ENCODING_EBCDI )
905 {
906 cset = IBM273;
907 }
908 else
909 {
910 throw new IllegalArgumentException( Integer.toString( encoding ) );
911 }
912
913 try
914 {
915 this.fileOperations.setFilePointer( position );
916 this.fileOperations.read( this.buffer, 0, 6 );
917 str = Charsets.decode( this.buffer, 0, 6, cset );
918 len = str.trim().length();
919
920 if ( len == 6 )
921 {
922 this.calendar.clear();
923
924 this.calendar.set( Calendar.DAY_OF_MONTH, Integer.valueOf( str.substring( 0, 2 ) ).intValue() );
925
926
927 this.calendar.set( Calendar.MONTH, Integer.valueOf( str.substring( 2, 4 ) ).intValue() - 1 );
928
929
930 int year = Integer.valueOf( str.substring( 4, 6 ) ).intValue();
931 year = year <= 79 ? 2000 + year : 1900 + year;
932
933 this.calendar.set( Calendar.YEAR, year );
934 ret = this.calendar.getTime();
935
936 if ( !this.checkDate( ret ) )
937 {
938 if ( ThreadLocalMessages.isErrorsEnabled() )
939 {
940 throw new CorruptedException( this.getImplementation(), position );
941 }
942 else
943 {
944 msg = new IllegalDataMessage( field, IllegalDataMessage.TYPE_SHORTDATE, position, str );
945 ThreadLocalMessages.getMessages().addMessage( msg );
946 }
947
948 ret = null;
949 }
950 }
951
952 if ( len == 0 || len == 6 )
953 {
954 legal = true;
955 }
956
957 }
958 catch ( NumberFormatException e )
959 {
960 if ( this.getLogger().isDebugEnabled() )
961 {
962 this.getLogger().debug( e.toString() );
963 }
964
965 ret = null;
966 legal = false;
967 }
968
969 if ( !legal )
970 {
971 if ( ThreadLocalMessages.isErrorsEnabled() )
972 {
973 throw new CorruptedException( this.getImplementation(), position );
974 }
975 else
976 {
977 msg = new IllegalDataMessage( field, IllegalDataMessage.TYPE_SHORTDATE, position, str );
978 ThreadLocalMessages.getMessages().addMessage( msg );
979 }
980 }
981
982 return ret;
983 }
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002 protected void writeShortDate( final int field, final long position, final Date date, final int encoding )
1003 throws IOException
1004 {
1005 int i;
1006 final byte[] buf;
1007 final String cset;
1008
1009 if ( encoding == ENCODING_ASCII )
1010 {
1011 cset = DIN66003;
1012 }
1013 else if ( encoding == ENCODING_EBCDI )
1014 {
1015 cset = IBM273;
1016 }
1017 else
1018 {
1019 throw new IllegalArgumentException( Integer.toString( encoding ) );
1020 }
1021
1022 if ( date != null )
1023 {
1024 if ( !this.checkDate( date ) )
1025 {
1026 throw new IllegalArgumentException( date.toString() );
1027 }
1028
1029 this.shortDateBuffer.setLength( 0 );
1030 this.calendar.clear();
1031 this.calendar.setTime( date );
1032
1033 i = this.calendar.get( Calendar.DAY_OF_MONTH );
1034 if ( i < 10 )
1035 {
1036 this.shortDateBuffer.append( '0' );
1037 }
1038 this.shortDateBuffer.append( i );
1039
1040 i = this.calendar.get( Calendar.MONTH ) + 1;
1041 if ( i < 10 )
1042 {
1043 this.shortDateBuffer.append( '0' );
1044 }
1045 this.shortDateBuffer.append( i );
1046
1047 i = this.calendar.get( Calendar.YEAR );
1048 this.shortDateBuffer.append( i >= 2000 && i <= 2009 ? "0" : "" );
1049 this.shortDateBuffer.append( i >= 1980 && i < 2000 ? i - 1900 : i - 2000 );
1050
1051 buf = Charsets.encode( this.shortDateBuffer.toString(), cset );
1052 }
1053 else
1054 {
1055 buf = Charsets.encode( " ", cset );
1056 }
1057
1058 this.fileOperations.setFilePointer( position );
1059 this.fileOperations.write( buf, 0, 6 );
1060 }
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080 protected Date readLongDate( final int field, final long position, final int encoding ) throws IOException
1081 {
1082 final int len;
1083 final String cset;
1084
1085 boolean legal = false;
1086 Date ret = null;
1087 String str = null;
1088 Message msg;
1089
1090 if ( encoding == ENCODING_ASCII )
1091 {
1092 cset = DIN66003;
1093 }
1094 else if ( encoding == ENCODING_EBCDI )
1095 {
1096 cset = IBM273;
1097 }
1098 else
1099 {
1100 throw new IllegalArgumentException( Integer.toString( encoding ) );
1101 }
1102
1103 try
1104 {
1105 this.fileOperations.setFilePointer( position );
1106 this.fileOperations.read( this.buffer, 0, 8 );
1107 str = Charsets.decode( this.buffer, 0, 8, cset );
1108 len = str.trim().length();
1109 if ( len == 8 )
1110 {
1111 this.calendar.clear();
1112
1113 this.calendar.set( Calendar.DAY_OF_MONTH, Integer.valueOf( str.substring( 0, 2 ) ).intValue() );
1114
1115
1116 this.calendar.set( Calendar.MONTH, Integer.valueOf( str.substring( 2, 4 ) ).intValue() - 1 );
1117
1118
1119 this.calendar.set( Calendar.YEAR, Integer.valueOf( str.substring( 4, 8 ) ).intValue() );
1120
1121 ret = this.calendar.getTime();
1122 if ( !this.checkDate( ret ) )
1123 {
1124 if ( ThreadLocalMessages.isErrorsEnabled() )
1125 {
1126 throw new CorruptedException( this.getImplementation(), position );
1127 }
1128 else
1129 {
1130 msg = new IllegalDataMessage( field, IllegalDataMessage.TYPE_LONGDATE, position, str );
1131 ThreadLocalMessages.getMessages().addMessage( msg );
1132 }
1133
1134 ret = null;
1135 }
1136
1137 }
1138
1139 if ( len == 0 || len == 8 )
1140 {
1141 legal = true;
1142 }
1143
1144 }
1145 catch ( NumberFormatException e )
1146 {
1147 if ( this.getLogger().isDebugEnabled() )
1148 {
1149 this.getLogger().debug( e.toString() );
1150 }
1151
1152 legal = false;
1153 ret = null;
1154 }
1155
1156 if ( !legal )
1157 {
1158 if ( ThreadLocalMessages.isErrorsEnabled() )
1159 {
1160 throw new CorruptedException( this.getImplementation(), position );
1161 }
1162 else
1163 {
1164 msg = new IllegalDataMessage( field, IllegalDataMessage.TYPE_LONGDATE, position, str );
1165 ThreadLocalMessages.getMessages().addMessage( msg );
1166 }
1167 }
1168
1169 return ret;
1170 }
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189 protected void writeLongDate( final int field, final long position, final Date date, final int encoding )
1190 throws IOException
1191 {
1192 int i;
1193 final byte[] buf;
1194 final String cset;
1195
1196 if ( encoding == ENCODING_ASCII )
1197 {
1198 cset = DIN66003;
1199 }
1200 else if ( encoding == ENCODING_EBCDI )
1201 {
1202 cset = IBM273;
1203 }
1204 else
1205 {
1206 throw new IllegalArgumentException( Integer.toString( encoding ) );
1207 }
1208
1209 if ( date != null )
1210 {
1211 if ( !this.checkDate( date ) )
1212 {
1213 throw new IllegalArgumentException( date.toString() );
1214 }
1215
1216 this.longDateBuffer.setLength( 0 );
1217 this.calendar.clear();
1218 this.calendar.setTime( date );
1219
1220 i = this.calendar.get( Calendar.DAY_OF_MONTH );
1221 if ( i < 10 )
1222 {
1223 this.longDateBuffer.append( '0' );
1224 }
1225 this.longDateBuffer.append( i );
1226
1227 i = this.calendar.get( Calendar.MONTH ) + 1;
1228 if ( i < 10 )
1229 {
1230 this.longDateBuffer.append( '0' );
1231 }
1232 this.longDateBuffer.append( i );
1233
1234 i = this.calendar.get( Calendar.YEAR );
1235 this.longDateBuffer.append( i );
1236 buf = Charsets.encode( this.longDateBuffer.toString(), cset );
1237 }
1238 else
1239 {
1240 buf = Charsets.encode( " ", cset );
1241 }
1242
1243 this.fileOperations.setFilePointer( position );
1244 this.fileOperations.write( buf, 0, 8 );
1245 }
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267 protected long readNumberPackedPositive( final int field, final long position, final int len, final boolean sign )
1268 throws IOException
1269 {
1270 long ret = 0L;
1271 final int nibbles = 2 * len;
1272 int exp = nibbles - ( sign ? 2 : 1 );
1273 boolean highNibble = true;
1274 int read = 0;
1275 Message msg;
1276
1277 this.fileOperations.setFilePointer( position );
1278 this.fileOperations.read( this.buffer, 0, len );
1279
1280 for ( int nibble = 0; nibble < nibbles; nibble++, exp-- )
1281 {
1282 final int digit = highNibble ? ( ( this.buffer[read] & 0xF0 ) >> 4 ) : ( this.buffer[read++] & 0xF );
1283
1284 highNibble = !highNibble;
1285
1286
1287 if ( sign && exp < 0 )
1288 {
1289 if ( digit != 0xC )
1290 {
1291 if ( ThreadLocalMessages.isErrorsEnabled() )
1292 {
1293 throw new CorruptedException( this.getImplementation(), position );
1294 }
1295 else
1296 {
1297 msg = new IllegalDataMessage(
1298 field, IllegalDataMessage.TYPE_PACKET_POSITIVE, position, Integer.toString( digit ) );
1299
1300 ThreadLocalMessages.getMessages().addMessage( msg );
1301 }
1302
1303 ret = NO_NUMBER;
1304 break;
1305 }
1306 }
1307 else
1308 {
1309 if ( digit < 0 || digit > 9 )
1310 {
1311 if ( !ThreadLocalMessages.isErrorsEnabled() )
1312 {
1313 throw new CorruptedException( this.getImplementation(), position );
1314 }
1315 else
1316 {
1317 msg = new IllegalDataMessage(
1318 field, IllegalDataMessage.TYPE_PACKET_POSITIVE, position, Integer.toString( digit ) );
1319
1320 ThreadLocalMessages.getMessages().addMessage( msg );
1321 }
1322
1323 ret = NO_NUMBER;
1324 break;
1325 }
1326
1327 ret += ( digit * EXP10[exp] );
1328 }
1329 }
1330
1331 return ret;
1332 }
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350 protected void writeNumberPackedPositive( final int field, final long position, final int len, long number,
1351 final boolean sign ) throws IOException
1352 {
1353 int i;
1354 int pos = 0;
1355 final int nibbles = len * 2;
1356 final int digits = nibbles - ( sign ? 1 : 0 );
1357 int exp = digits - 1;
1358 final long maxValue = EXP10[digits] - 1L;
1359 byte b = 0;
1360 boolean highNibble = true;
1361
1362 if ( number < 0L || number > maxValue )
1363 {
1364 throw new IllegalArgumentException( Long.toString( number ) );
1365 }
1366
1367 for ( i = 0; i < nibbles; i++, exp-- )
1368 {
1369 final int digit;
1370
1371 if ( sign && exp < 0 )
1372 {
1373 digit = 0xC;
1374 }
1375 else
1376 {
1377 digit = (int) Math.floor( number / EXP10[exp] );
1378 number -= ( digit * EXP10[exp] );
1379 }
1380 if ( highNibble )
1381 {
1382 b = (byte) ( ( digit << 4 ) & 0xF0 );
1383 }
1384 else
1385 {
1386 this.buffer[pos++] = (byte) ( b | digit );
1387 }
1388
1389 highNibble = !highNibble;
1390 }
1391
1392 this.fileOperations.setFilePointer( position );
1393 this.fileOperations.write( this.buffer, 0, len );
1394 }
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410 protected long readNumberBinary( final int field, final long position, final int len ) throws IOException
1411 {
1412 if ( len <= 0 || len > 8 )
1413 {
1414 throw new IllegalArgumentException( Integer.toString( len ) );
1415 }
1416
1417 long ret = 0L;
1418 int shift = ( len - 1 ) * 8;
1419
1420 this.fileOperations.setFilePointer( position );
1421 this.fileOperations.read( this.buffer, 0, len );
1422
1423 for ( int i = 0; i < len; i++, shift -= 8 )
1424 {
1425 ret |= ( ( this.buffer[i] & 0xFF ) << shift );
1426 }
1427
1428 return ret;
1429 }
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444 protected void writeNumberBinary( final int field, final long position, final int len, final long number )
1445 throws IOException
1446 {
1447 if ( len <= 0 || len > 8 )
1448 {
1449 throw new IllegalArgumentException( Integer.toString( len ) );
1450 }
1451
1452 int shift = ( len - 1 ) * 8;
1453 int i;
1454
1455 for ( i = 0; i < len; i++, shift -= 8 )
1456 {
1457 this.buffer[i] = (byte) ( ( number >> shift ) & 0xFFL );
1458 }
1459
1460 this.fileOperations.setFilePointer( position );
1461 this.fileOperations.write( this.buffer, 0, len );
1462 }
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472 protected boolean checkTransactionId( final int id, final Checksum checksum )
1473 {
1474 if ( checksum == null )
1475 {
1476 throw new NullPointerException( "checksum" );
1477 }
1478
1479 final int count = checksum.getTransactionCount();
1480 return count > 0 && id >= 0 && id < count;
1481 }
1482
1483
1484
1485
1486
1487
1488 protected boolean checkTransactionCount( final int transactionCount )
1489 {
1490 return transactionCount >= 0 && transactionCount <= MAX_TRANSACTIONS;
1491 }
1492
1493
1494
1495
1496
1497
1498
1499
1500 protected boolean checkDate( final Date date )
1501 {
1502 boolean valid = false;
1503
1504 if ( date != null )
1505 {
1506 final long millis = date.getTime();
1507 valid = millis >= VALID_DATES_START_MILLIS && millis <= VALID_DATES_END_MILLIS;
1508 }
1509
1510 return valid;
1511 }
1512
1513
1514
1515
1516
1517
1518
1519 protected void resizeIndex( final int index, final Checksum checksum )
1520 {
1521 if ( this.index == null )
1522 {
1523 this.index = this.getMemoryManager().allocateLongs( checksum.getTransactionCount() + 1 );
1524 Arrays.fill( this.index, -1L );
1525 }
1526
1527 while ( this.index.length < index + 1 )
1528 {
1529 int newLength = this.index.length * 2;
1530 if ( newLength <= index )
1531 {
1532 newLength = index + 1;
1533 }
1534 else if ( newLength > MAX_TRANSACTIONS )
1535 {
1536 newLength = MAX_TRANSACTIONS;
1537 }
1538
1539 final long[] newIndex = this.getMemoryManager().allocateLongs( newLength );
1540 System.arraycopy( this.index, 0, newIndex, 0, this.index.length );
1541 Arrays.fill( newIndex, this.index.length, newIndex.length, -1L );
1542 this.index = newIndex;
1543 }
1544 }
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554 protected void insertBytes( final long position, final long bytes ) throws IOException
1555 {
1556 final Task task = new Task();
1557 long toMoveByte = this.getFileOperations().getLength() - position;
1558 long progress = 0L;
1559 long progressDivisor = 1L;
1560 long maxProgress = toMoveByte;
1561
1562 if ( toMoveByte <= 0L )
1563 {
1564 this.getFileOperations().setLength( this.getFileOperations().getLength() + bytes );
1565 this.fireBytesInserted( position, bytes );
1566 return;
1567 }
1568
1569 final byte[] buf = this.getBuffer( toMoveByte > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) toMoveByte );
1570 while ( maxProgress > Integer.MAX_VALUE )
1571 {
1572 maxProgress /= 2L;
1573 progressDivisor *= 2L;
1574 }
1575
1576 task.setIndeterminate( false );
1577 task.setCancelable( false );
1578 task.setMinimum( 0 );
1579 task.setMaximum( (int) maxProgress );
1580 task.setProgress( (int) progress );
1581 task.setDescription( new InsertsBlocksMessage() );
1582
1583 final boolean monitoring = toMoveByte > this.getMonitoringThreshold();
1584 if ( monitoring )
1585 {
1586 this.getTaskMonitor().monitor( task );
1587 }
1588
1589 try
1590 {
1591 long readPos = this.getFileOperations().getLength();
1592 while ( toMoveByte > 0L )
1593 {
1594 final int moveLen = buf.length >= toMoveByte ? (int) toMoveByte : buf.length;
1595 readPos -= moveLen;
1596 final long writePos = readPos + bytes;
1597
1598 this.getFileOperations().setFilePointer( readPos );
1599 int read = 0;
1600 int total = 0;
1601
1602 do
1603 {
1604 read = this.getFileOperations().read( buf, total, moveLen - total );
1605 assert read != FileOperations.EOF : "Unexpected end of file.";
1606 total += read;
1607 }
1608 while ( total < moveLen );
1609
1610 this.getFileOperations().setFilePointer( writePos );
1611 this.getFileOperations().write( buf, 0, moveLen );
1612
1613 toMoveByte -= moveLen;
1614 progress += moveLen;
1615 task.setProgress( (int) ( progress / progressDivisor ) );
1616 }
1617 }
1618 finally
1619 {
1620 if ( monitoring )
1621 {
1622 this.getTaskMonitor().finish( task );
1623 }
1624 }
1625
1626 this.fireBytesInserted( position, bytes );
1627 }
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637 protected void removeBytes( final long position, final long bytes ) throws IOException
1638 {
1639 final Task task = new Task();
1640 long toMoveByte = this.getFileOperations().getLength() - position - bytes;
1641 long progress = 0L;
1642 long progressDivisor = 1L;
1643 long maxProgress = toMoveByte;
1644
1645
1646 if ( toMoveByte == 0L )
1647 {
1648 this.getFileOperations().setLength( this.getFileOperations().getLength() - bytes );
1649 this.fireBytesDeleted( position, bytes );
1650 return;
1651 }
1652
1653 final byte[] buf = this.getBuffer( toMoveByte > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) toMoveByte );
1654 while ( maxProgress > Integer.MAX_VALUE )
1655 {
1656 maxProgress /= 2L;
1657 progressDivisor *= 2L;
1658 }
1659
1660 task.setIndeterminate( false );
1661 task.setCancelable( false );
1662 task.setMinimum( 0 );
1663 task.setMaximum( (int) maxProgress );
1664 task.setProgress( (int) progress );
1665 task.setDescription( new DeletesBlocksMessage() );
1666
1667 final boolean monitoring = toMoveByte > this.getMonitoringThreshold();
1668 if ( monitoring )
1669 {
1670 this.getTaskMonitor().monitor( task );
1671 }
1672
1673 try
1674 {
1675 long readPos = position + bytes;
1676 while ( toMoveByte > 0L )
1677 {
1678 final int len = toMoveByte <= buf.length ? (int) toMoveByte : buf.length;
1679 final long writePos = readPos - bytes;
1680
1681 this.getFileOperations().setFilePointer( readPos );
1682
1683 int read = 0;
1684 int total = 0;
1685 do
1686 {
1687 read = this.getFileOperations().read( buf, total, len - total );
1688 assert read != FileOperations.EOF : "Unexpected end of file.";
1689 total += read;
1690
1691 }
1692 while ( total < len );
1693
1694
1695 this.getFileOperations().setFilePointer( writePos );
1696 this.getFileOperations().write( buf, 0, len );
1697
1698 toMoveByte -= len;
1699 readPos += len;
1700 progress += len;
1701 task.setProgress( (int) ( progress / progressDivisor ) );
1702 }
1703
1704 this.getFileOperations().setLength( this.getFileOperations().getLength() - bytes );
1705 }
1706 finally
1707 {
1708 if ( monitoring )
1709 {
1710 this.getTaskMonitor().finish( task );
1711 }
1712 }
1713
1714 this.fireBytesDeleted( position, bytes );
1715 }
1716
1717 private byte[] getBuffer( final int requested ) throws IOException
1718 {
1719 final long length = this.getFileOperations().getLength();
1720
1721 if ( requested <= 0 || requested > length )
1722 {
1723 throw new IllegalArgumentException( Integer.toString( requested ) );
1724 }
1725
1726 if ( this.defaultBuffer == null )
1727 {
1728 this.defaultBuffer = this.getMemoryManager().allocateBytes( this.getDefaultBufferSize() );
1729 }
1730
1731 return requested <= this.defaultBuffer.length || this.getMemoryManager().getAvailableBytes() < requested
1732 ? this.defaultBuffer : this.getMemoryManager().allocateBytes( requested );
1733
1734 }
1735
1736
1737
1738
1739
1740
1741 protected abstract int getBlockSize();
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752 protected abstract char getBlockType( long position ) throws IOException;
1753
1754
1755
1756
1757
1758
1759
1760
1761 protected abstract int byteCount( Transaction transaction );
1762
1763
1764
1765
1766
1767
1768 protected abstract Implementation getImplementation();
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780 protected abstract Header readHeader() throws IOException;
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792 protected abstract void writeHeader( Header header ) throws IOException;
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804 protected abstract Checksum readChecksum() throws IOException;
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816 protected abstract void writeChecksum( Checksum checksum ) throws IOException;
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829 protected abstract Transaction readTransaction( long position, Transaction transaction ) throws IOException;
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840 protected abstract void writeTransaction( long position, Transaction transaction ) throws IOException;
1841
1842 public Header getHeader() throws IOException
1843 {
1844 if ( this.cachedHeader == null )
1845 {
1846 this.cachedHeader = this.readHeader();
1847 }
1848
1849 return (Header) this.cachedHeader.clone();
1850 }
1851
1852 public Header setHeader( final Header header ) throws IOException
1853 {
1854 IllegalHeaderException result = null;
1855 final Header old = this.getHeader();
1856 final HeaderValidator[] validators = this.getHeaderValidator();
1857
1858 for ( int i = validators.length - 1; i >= 0; i-- )
1859 {
1860 result = validators[i].assertValidHeader( this, header, this.counter, result );
1861 }
1862
1863 if ( result != null && result.getMessages().length > 0 )
1864 {
1865 throw result;
1866 }
1867
1868 this.writeHeader( header );
1869 this.cachedHeader = (Header) header.clone();
1870 return old;
1871 }
1872
1873 public Checksum getChecksum() throws IOException
1874 {
1875 if ( this.cachedChecksum == null )
1876 {
1877 this.cachedChecksum = this.readChecksum();
1878 }
1879
1880 return (Checksum) this.cachedChecksum.clone();
1881 }
1882
1883 protected void setChecksum( final Checksum checksum ) throws IOException
1884 {
1885 this.writeChecksum( checksum );
1886 this.cachedChecksum = (Checksum) checksum.clone();
1887 }
1888
1889 protected void checksum() throws IOException
1890 {
1891 final Checksum c = new Checksum();
1892 Transaction t = new Transaction();
1893 final Task task = new Task();
1894 task.setIndeterminate( true );
1895 task.setCancelable( false );
1896 task.setDescription( new ChecksumsFileMessage() );
1897
1898 try
1899 {
1900 this.getTaskMonitor().monitor( task );
1901
1902 final long fileLength = this.fileOperations.getLength();
1903 long position = this.getHeaderPosition();
1904 char type = this.getBlockType( position );
1905 this.setChecksumPosition( position + this.getBlockSize() );
1906 this.counter = new CurrencyCounter();
1907
1908 if ( type == 'A' )
1909 {
1910 this.getHeader();
1911
1912 position += this.getBlockSize();
1913 int transactionIndex = 0;
1914
1915 while ( position < fileLength && ( type = this.getBlockType( position ) ) == 'C' )
1916 {
1917 this.resizeIndex( transactionIndex, c );
1918 this.index[transactionIndex] = position - this.getHeaderPosition();
1919 t = this.readTransaction( this.getHeaderPosition() + this.index[transactionIndex++], t );
1920 final int len = this.byteCount( t );
1921
1922 if ( t.getCurrency() != null )
1923 {
1924 this.counter.add( t.getCurrency() );
1925 }
1926 if ( t.getAmount() != null && t.getTargetAccount() != null && t.getTargetBank() != null )
1927 {
1928 c.add( t );
1929 }
1930
1931 position += len;
1932 this.setChecksumPosition( position );
1933 c.setTransactionCount( transactionIndex );
1934 }
1935
1936 this.setChecksumPosition( position );
1937 if ( type == 'E' )
1938 {
1939 final Checksum stored = this.getChecksum();
1940 if ( !stored.equals( c ) )
1941 {
1942 if ( ThreadLocalMessages.isErrorsEnabled() )
1943 {
1944 throw new CorruptedException( this.getImplementation(), position );
1945 }
1946 else
1947 {
1948 final Message msg = new ChecksumErrorMessage( stored, c, this.getHeaderPosition() );
1949 ThreadLocalMessages.getMessages().addMessage( msg );
1950 }
1951 }
1952 }
1953 else
1954 {
1955 if ( ThreadLocalMessages.isErrorsEnabled() )
1956 {
1957 throw new CorruptedException(
1958 this.getImplementation(), position + DTAUSDisk.ERECORD_OFFSETS[1] );
1959
1960 }
1961 else
1962 {
1963 final Message msg = new IllegalDataMessage(
1964 Fields.FIELD_E2, IllegalDataMessage.TYPE_CONSTANT, position + DTAUSDisk.ERECORD_OFFSETS[1],
1965 Character.toString( type ) );
1966
1967 ThreadLocalMessages.getMessages().addMessage( msg );
1968 }
1969 }
1970 }
1971 else
1972 {
1973 if ( ThreadLocalMessages.isErrorsEnabled() )
1974 {
1975 throw new CorruptedException( this.getImplementation(), position + DTAUSDisk.ARECORD_OFFSETS[1] );
1976 }
1977 else
1978 {
1979 final Message msg = new IllegalDataMessage(
1980 Fields.FIELD_A2, IllegalDataMessage.TYPE_CONSTANT, position + DTAUSDisk.ARECORD_OFFSETS[1],
1981 Character.toString( type ) );
1982
1983 ThreadLocalMessages.getMessages().addMessage( msg );
1984 }
1985 }
1986 }
1987 finally
1988 {
1989 this.getTaskMonitor().finish( task );
1990 }
1991 }
1992
1993 public final void createTransaction( final Transaction transaction ) throws IOException
1994 {
1995 this.addTransaction( transaction );
1996 }
1997
1998 public int addTransaction( final Transaction transaction ) throws IOException
1999 {
2000 final Checksum checksum = this.getChecksum();
2001 final int newCount = checksum.getTransactionCount() + 1;
2002
2003 if ( !this.checkTransactionCount( newCount ) )
2004 {
2005 throw new ArrayIndexOutOfBoundsException( newCount );
2006 }
2007
2008 IllegalTransactionException result = null;
2009 final TransactionValidator[] validators = this.getTransactionValidator();
2010
2011 for ( int i = validators.length - 1; i >= 0; i-- )
2012 {
2013 result = validators[i].assertValidTransaction( this, transaction, result );
2014 }
2015
2016 if ( result != null && result.getMessages().length > 0 )
2017 {
2018 throw result;
2019 }
2020
2021 this.counter.add( transaction.getCurrency() );
2022 checksum.setTransactionCount( newCount );
2023 checksum.add( transaction );
2024
2025 final int transactionIndex = checksum.getTransactionCount() - 1;
2026 final int len = this.byteCount( transaction );
2027 this.insertBytes( this.getChecksumPosition(), len );
2028 this.setChecksumPosition( this.getChecksumPosition() + len );
2029 this.resizeIndex( transactionIndex, checksum );
2030 this.index[transactionIndex] = this.getChecksumPosition() - len - this.getHeaderPosition();
2031 this.writeTransaction( this.getHeaderPosition() + this.index[transactionIndex], transaction );
2032 this.writeChecksum( checksum );
2033 this.cachedChecksum = checksum;
2034 return transactionIndex;
2035 }
2036
2037 public Transaction getTransaction( final int index ) throws IOException
2038 {
2039 final Checksum checksum = this.getChecksum();
2040 if ( !this.checkTransactionId( index, checksum ) )
2041 {
2042 throw new ArrayIndexOutOfBoundsException( index );
2043 }
2044
2045 return this.readTransaction( this.index[index] + this.getHeaderPosition(), new Transaction() );
2046 }
2047
2048 public Transaction setTransaction( final int index, final Transaction transaction ) throws IOException
2049 {
2050 final Checksum checksum = this.getChecksum();
2051 if ( !this.checkTransactionId( index, checksum ) )
2052 {
2053 throw new ArrayIndexOutOfBoundsException( index );
2054 }
2055
2056 IllegalTransactionException result = null;
2057 final TransactionValidator[] validators = this.getTransactionValidator();
2058
2059 for ( int i = validators.length - 1; i >= 0; i-- )
2060 {
2061 result = validators[i].assertValidTransaction( this, transaction, result );
2062 }
2063
2064 if ( result != null && result.getMessages().length > 0 )
2065 {
2066 throw result;
2067 }
2068
2069 final Transaction old = this.getTransaction( index );
2070
2071 if ( !old.getCurrency().getCurrencyCode().equals( transaction.getCurrency().getCurrencyCode() ) )
2072 {
2073 this.counter.substract( old.getCurrency() );
2074 this.counter.add( transaction.getCurrency() );
2075 }
2076
2077 int i;
2078 checksum.subtract( old );
2079 checksum.add( transaction );
2080 final int oldLen = this.byteCount( old );
2081 final int newLen = this.byteCount( transaction );
2082 if ( oldLen < newLen )
2083 {
2084 final int delta = newLen - oldLen;
2085 this.insertBytes( this.getHeaderPosition() + this.index[index], delta );
2086
2087 for ( i = index + 1; i < this.index.length; i++ )
2088 {
2089 if ( this.index[i] != -1L )
2090 {
2091 this.index[i] += delta;
2092 }
2093 }
2094
2095 this.setChecksumPosition( this.getChecksumPosition() + delta );
2096 }
2097 else if ( oldLen > newLen )
2098 {
2099 final int delta = oldLen - newLen;
2100 this.removeBytes( this.getHeaderPosition() + this.index[index], delta );
2101
2102 for ( i = index + 1; i < this.index.length; i++ )
2103 {
2104 if ( this.index[i] != -1L )
2105 {
2106 this.index[i] -= delta;
2107 }
2108 }
2109
2110 this.setChecksumPosition( this.getChecksumPosition() - delta );
2111 }
2112
2113 this.writeTransaction( this.getHeaderPosition() + this.index[index], transaction );
2114 this.writeChecksum( checksum );
2115 this.cachedChecksum = checksum;
2116 return old;
2117 }
2118
2119 public Transaction removeTransaction( final int index ) throws IOException
2120 {
2121 final Checksum checksum = this.getChecksum();
2122 if ( !this.checkTransactionId( index, checksum ) )
2123 {
2124 throw new ArrayIndexOutOfBoundsException( index );
2125 }
2126
2127 final Transaction removed = this.getTransaction( index );
2128 checksum.setTransactionCount( checksum.getTransactionCount() - 1 );
2129 checksum.subtract( removed );
2130 this.counter.substract( removed.getCurrency() );
2131
2132 final int len = this.byteCount( removed );
2133 this.removeBytes( this.getHeaderPosition() + this.index[index], len );
2134 this.setChecksumPosition( this.getChecksumPosition() - len );
2135 for ( int i = index + 1; i < this.index.length; i++ )
2136 {
2137 if ( this.index[i] != -1L )
2138 {
2139 this.index[i] -= len;
2140 }
2141
2142 this.index[i - 1] = this.index[i];
2143 }
2144
2145 this.writeChecksum( checksum );
2146 this.cachedChecksum = checksum;
2147 return removed;
2148 }
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160 protected Logger getLogger()
2161 {
2162 return (Logger) ContainerFactory.getContainer().
2163 getDependency( this, "Logger" );
2164
2165 }
2166
2167
2168
2169
2170
2171
2172 protected MemoryManager getMemoryManager()
2173 {
2174 return (MemoryManager) ContainerFactory.getContainer().
2175 getDependency( this, "MemoryManager" );
2176
2177 }
2178
2179
2180
2181
2182
2183
2184 protected ApplicationLogger getApplicationLogger()
2185 {
2186 return (ApplicationLogger) ContainerFactory.getContainer().
2187 getDependency( this, "ApplicationLogger" );
2188
2189 }
2190
2191
2192
2193
2194
2195
2196 protected TaskMonitor getTaskMonitor()
2197 {
2198 return (TaskMonitor) ContainerFactory.getContainer().
2199 getDependency( this, "TaskMonitor" );
2200
2201 }
2202
2203
2204
2205
2206
2207
2208 protected TextschluesselVerzeichnis getTextschluesselVerzeichnis()
2209 {
2210 return (TextschluesselVerzeichnis) ContainerFactory.getContainer().
2211 getDependency( this, "TextschluesselVerzeichnis" );
2212
2213 }
2214
2215
2216
2217
2218
2219
2220 protected CurrencyMapper getCurrencyMapper()
2221 {
2222 return (CurrencyMapper) ContainerFactory.getContainer().
2223 getDependency( this, "CurrencyMapper" );
2224
2225 }
2226
2227
2228
2229
2230
2231
2232 protected HeaderValidator[] getHeaderValidator()
2233 {
2234 return (HeaderValidator[]) ContainerFactory.getContainer().
2235 getDependency( this, "HeaderValidator" );
2236
2237 }
2238
2239
2240
2241
2242
2243
2244 protected TransactionValidator[] getTransactionValidator()
2245 {
2246 return (TransactionValidator[]) ContainerFactory.getContainer().
2247 getDependency( this, "TransactionValidator" );
2248
2249 }
2250
2251
2252
2253
2254
2255
2256 protected Locale getLocale()
2257 {
2258 return (Locale) ContainerFactory.getContainer().
2259 getDependency( this, "Locale" );
2260
2261 }
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276 protected java.lang.Integer getDefaultMonitoringThreshold()
2277 {
2278 return (java.lang.Integer) ContainerFactory.getContainer().
2279 getProperty( this, "defaultMonitoringThreshold" );
2280
2281 }
2282
2283
2284
2285
2286
2287
2288 protected java.lang.Long getDefaultMaximumExtensionCount()
2289 {
2290 return (java.lang.Long) ContainerFactory.getContainer().
2291 getProperty( this, "defaultMaximumExtensionCount" );
2292
2293 }
2294
2295
2296
2297
2298
2299
2300 protected int getDefaultBufferSize()
2301 {
2302 return ( (java.lang.Integer) ContainerFactory.getContainer().
2303 getProperty( this, "defaultBufferSize" ) ).intValue();
2304
2305 }
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326 protected String getReadNumberIllegalFileInfoMessage( final Locale locale,
2327 final java.lang.String readString,
2328 final java.lang.Number convertedNumber )
2329 {
2330 return ContainerFactory.getContainer().
2331 getMessage( this, "readNumberIllegalFileInfo", locale,
2332 new Object[]
2333 {
2334 readString,
2335 convertedNumber
2336 });
2337
2338 }
2339
2340
2341
2342
2343 }