1 /***
2 *
3 * Copyright 2004 Hiram Chirino
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 **/
18 package org.codehaus.activemq.journal.impl;
19
20 import java.io.DataInput;
21 import java.io.DataOutput;
22 import java.io.IOException;
23 import java.nio.ByteBuffer;
24 import java.util.zip.CRC32;
25
26 /***
27 * Serializes/Deserializes record header information.
28 *
29 * @version $Revision: 1.1 $
30 */
31 public class RecordFooter {
32
33 static final public int SELECTED_CHECKSUM_ALGORITHIM;
34 static final public int NO_CHECKSUM_ALGORITHIM=0;
35 static final public int HASH_CHECKSUM_ALGORITHIM=1;
36 static final public int CRC32_CHECKSUM_ALGORITHIM=2;
37
38 static {
39 String type = System.getProperty("org.codehaus.activemq.journal.impl.SELECTED_CHECKSUM_ALGORITHIM", "hash");
40 if( "none".equals(type) ) {
41 SELECTED_CHECKSUM_ALGORITHIM = NO_CHECKSUM_ALGORITHIM;
42 } else if( "crc32".equals(type) ) {
43 SELECTED_CHECKSUM_ALGORITHIM = CRC32_CHECKSUM_ALGORITHIM;
44 } else if( "hash".equals(type) ) {
45 SELECTED_CHECKSUM_ALGORITHIM = HASH_CHECKSUM_ALGORITHIM;
46 } else {
47 System.err.println("System property 'org.codehaus.activemq.journal.impl.SELECTED_CHECKSUM_ALGORITHIM' not set properly. Valid values are: 'none', 'hash', or 'crc32'");
48 SELECTED_CHECKSUM_ALGORITHIM = NO_CHECKSUM_ALGORITHIM;
49 }
50 }
51
52 static final public int RECORD_FOOTER_SIZE=19;
53 static final public byte[] END_OF_RECORD = new byte[] { 'E', 'o', 'R' };
54
55 public long checksum;
56 public long sequenceId;
57
58 /***
59 * @return
60 */
61 public ByteBuffer toByteBuffer() {
62 ByteBuffer buff = ByteBuffer.allocate(RECORD_FOOTER_SIZE);
63 buff.putLong(checksum)
64 .putLong(sequenceId)
65 .put(END_OF_RECORD)
66 .flip();
67 return buff;
68 }
69
70 void writeRecordFooter( DataOutput out ) throws IOException {
71 out.writeLong(checksum);
72 out.writeLong(sequenceId);
73 out.write(END_OF_RECORD);
74 }
75
76 void readRecordFooter( DataInput in ) throws IOException {
77 checksum = in.readLong();
78 sequenceId = in.readLong();
79 for (int i = 0; i < END_OF_RECORD.length; i++) {
80 byte checkByte = END_OF_RECORD[i];
81 if( in.readByte()!= checkByte ) {
82 throw new IOException("Not a valid record header.");
83 }
84 }
85 }
86
87 /***
88 *
89 */
90 public void invalidate() {
91 checksum=-1;
92 sequenceId=-1;
93 }
94
95 public boolean matches(RecordHeader header) {
96 return header.sequenceId==sequenceId;
97 }
98
99 static public boolean isChecksumingEnabled() {
100 return SELECTED_CHECKSUM_ALGORITHIM!=NO_CHECKSUM_ALGORITHIM;
101 }
102
103 public boolean matches(byte data[]) {
104 return buildChecksum(data)==checksum;
105 }
106
107 static public long buildChecksum(byte[] data) {
108 if( SELECTED_CHECKSUM_ALGORITHIM==HASH_CHECKSUM_ALGORITHIM ) {
109 byte rc[] = new byte[8];
110 for (int i = 0; i < data.length; i++) {
111 rc[i%8] ^= data[i];
112 }
113 return (rc[0])|(rc[1]<<1)|(rc[2]<<2)|(rc[3]<<3)|(rc[4]<<4)|(rc[5]<<5)|(rc[6]<<6)|(rc[7]<<7) ;
114 } else if( SELECTED_CHECKSUM_ALGORITHIM==CRC32_CHECKSUM_ALGORITHIM ) {
115 CRC32 crc32 = new CRC32();
116 crc32.update(data);
117 return crc32.getValue();
118 } else {
119 return 0L;
120 }
121 }
122
123 /***
124 * @param header
125 * @param data
126 */
127 public void bulkSet(RecordHeader header, byte[] data) {
128 this.sequenceId = header.sequenceId;
129 this.checksum = buildChecksum(data);
130 }
131
132 }