Clover coverage report - ActiveIO - 1.0
Coverage timestamp: Fri Apr 22 2005 14:27:22 PDT
file stats: LOC: 310   Methods: 22
NCLOC: 208   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
Record.java 22.7% 43.4% 59.1% 40.2%
coverage coverage
 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.activeio.journal.active;
 19   
 
 20   
 import java.io.DataInput;
 21   
 import java.io.DataInputStream;
 22   
 import java.io.DataOutput;
 23   
 import java.io.DataOutputStream;
 24   
 import java.io.IOException;
 25   
 import java.util.zip.CRC32;
 26   
 
 27   
 import org.activeio.Disposable;
 28   
 import org.activeio.Packet;
 29   
 import org.activeio.adapter.PacketInputStream;
 30   
 import org.activeio.adapter.PacketOutputStream;
 31   
 import org.activeio.packet.ByteArrayPacket;
 32   
 
 33   
 
 34   
 /**
 35   
  * Serializes/Deserializes data records. 
 36   
  * 
 37   
  * @version $Revision: 1.1 $
 38   
  */
 39   
 final public class Record implements Disposable {
 40   
     
 41   
     static final public int RECORD_HEADER_SIZE=8+Location.SERIALIZED_SIZE;
 42   
     static final public int RECORD_FOOTER_SIZE=12+Location.SERIALIZED_SIZE;
 43   
     static final public int RECORD_BASE_SIZE=RECORD_HEADER_SIZE+RECORD_FOOTER_SIZE;
 44   
     
 45   
     static final public byte[] START_OF_RECORD     = new byte[] { 'S', 'o', 'R' }; 
 46   
     static final public byte[] END_OF_RECORD     = new byte[] { 'E', 'o', 'R', '.' }; 
 47   
         
 48   
     static final public int SELECTED_CHECKSUM_ALGORITHIM;
 49   
     static final public int NO_CHECKSUM_ALGORITHIM=0;
 50   
     static final public int HASH_CHECKSUM_ALGORITHIM=1;
 51   
     static final public int CRC32_CHECKSUM_ALGORITHIM=2;
 52   
     
 53   
     static {
 54  4
         String type = System.getProperty("org.activeio.journal.active.SELECTED_CHECKSUM_ALGORITHIM", "none");
 55  4
         if( "none".equals(type) ) {
 56  4
             SELECTED_CHECKSUM_ALGORITHIM = NO_CHECKSUM_ALGORITHIM;            
 57  0
         } else if( "crc32".equals(type) ) {
 58  0
             SELECTED_CHECKSUM_ALGORITHIM = CRC32_CHECKSUM_ALGORITHIM;            
 59  0
         } else if( "hash".equals(type) ) {
 60  0
             SELECTED_CHECKSUM_ALGORITHIM = HASH_CHECKSUM_ALGORITHIM;            
 61   
         } else {
 62  0
             System.err.println("System property 'org.activeio.journal.active.SELECTED_CHECKSUM_ALGORITHIM' not set properly.  Valid values are: 'none', 'hash', or 'crc32'");
 63  0
             SELECTED_CHECKSUM_ALGORITHIM = NO_CHECKSUM_ALGORITHIM;            
 64   
         }
 65   
     }
 66   
     
 67  22
     static public boolean isChecksumingEnabled() {
 68  22
         return SELECTED_CHECKSUM_ALGORITHIM!=NO_CHECKSUM_ALGORITHIM;
 69   
     }
 70   
             
 71   
     private final ByteArrayPacket headerFooterPacket = new ByteArrayPacket(new byte[RECORD_BASE_SIZE]);
 72   
     private final DataOutputStream headerFooterData = new DataOutputStream(new PacketOutputStream(headerFooterPacket));
 73   
 
 74   
     private int payloadLength;
 75   
     private Location location;
 76   
     private byte recordType;        
 77   
     private long checksum;    
 78   
     private Location mark;
 79   
     private Packet payload;
 80   
          
 81  40
     public Record() {        
 82   
     }
 83   
 
 84  22
     public Record(byte recordType, Packet payload, Location mark) throws IOException {
 85  22
         this(null, recordType, payload, mark);
 86   
     }
 87   
     
 88  22
     public Record(Location location, byte recordType, Packet payload, Location mark) throws IOException {
 89  22
         this.location = location;
 90  22
         this.recordType = recordType;
 91  22
         this.mark = mark;
 92  22
         this.payload = payload.slice();
 93  22
         this.payloadLength = payload.remaining();
 94  22
         if( isChecksumingEnabled() ) {
 95  0
             checksum(new DataInputStream(new PacketInputStream(this.payload)));
 96   
         }
 97   
 
 98  22
         writeHeader(headerFooterData);
 99  22
         writeFooter(headerFooterData);
 100   
     }    
 101   
     
 102  22
     public void setLocation(Location location) throws IOException {
 103  22
         this.location = location;
 104  22
         headerFooterPacket.clear();
 105  22
         headerFooterPacket.position(8);
 106  22
         location.writeToDataOutput(headerFooterData);
 107  22
         headerFooterPacket.position(RECORD_HEADER_SIZE+8);
 108  22
         location.writeToDataOutput(headerFooterData);
 109  22
         payload.clear();
 110  22
         headerFooterPacket.position(0);
 111  22
         headerFooterPacket.limit(RECORD_HEADER_SIZE);
 112   
     }
 113   
     
 114  22
     private void writeHeader( DataOutput out ) throws IOException {
 115  22
         out.write(START_OF_RECORD);
 116  22
         out.writeByte(recordType);
 117  22
         out.writeInt(payloadLength);
 118  22
         if( location!=null )
 119  0
             location.writeToDataOutput(out);
 120   
         else
 121  22
             out.writeLong(0);
 122   
     }    
 123   
     
 124  40
     public void readHeader( DataInput in ) throws IOException {
 125  40
         readAndCheckConstant(in, START_OF_RECORD, "Invalid record header: start of record constant missing.");
 126  30
         recordType = in.readByte();
 127  30
         payloadLength = in.readInt();
 128  30
         if( payloadLength < 0 )
 129  0
             throw new IOException("Invalid record header: record length cannot be less than zero.");
 130  30
         location = Location.readFromDataInput(in);
 131   
     }
 132   
     
 133  22
     private void writeFooter( DataOutput out ) throws IOException {
 134  22
         out.writeLong(checksum);
 135  22
         if( location!=null )
 136  0
             location.writeToDataOutput(out);
 137   
         else
 138  22
             out.writeLong(0);
 139  22
         out.write(END_OF_RECORD);
 140   
     }
 141   
     
 142  0
     public void readFooter( DataInput in ) throws IOException {
 143  0
         long l = in.readLong();        
 144  0
         if( isChecksumingEnabled() ) {
 145  0
             if( l!=checksum )            
 146  0
                 throw new IOException("Invalid record footer: checksum does not match.");
 147   
         } else {
 148  0
             checksum = l;            
 149   
         }
 150   
         
 151  0
         Location loc = Location.readFromDataInput(in);
 152  0
         if( !loc.equals(location) )
 153  0
             throw new IOException("Invalid record footer: location id does not match.");
 154   
         
 155  0
         readAndCheckConstant(in, END_OF_RECORD, "Invalid record header: end of record constant missing.");
 156   
     }
 157   
     
 158   
     /**
 159   
      * @param randomAccessFile
 160   
      * @throws IOException
 161   
      */
 162  0
     public void checksum(DataInput in) throws IOException {
 163  0
         if( SELECTED_CHECKSUM_ALGORITHIM==HASH_CHECKSUM_ALGORITHIM ) {
 164   
 
 165  0
             byte  buffer[] = new byte[1024];
 166  0
             byte rc[] = new byte[8];
 167  0
             for (int i = 0; i < payloadLength;) {
 168  0
                 int l = Math.min(buffer.length, payloadLength-i);
 169  0
                 in.readFully(buffer,0,l);
 170  0
                 for (int j = 0; j < l; j++) {
 171  0
                     rc[j%8] ^= buffer[j];            
 172   
                 }
 173  0
                 i+=l;
 174   
             }            
 175  0
             checksum = (rc[0])|(rc[1]<<1)|(rc[2]<<2)|(rc[3]<<3)|(rc[4]<<4)|(rc[5]<<5)|(rc[6]<<6)|(rc[7]<<7) ;
 176   
             
 177  0
         } else if( SELECTED_CHECKSUM_ALGORITHIM==CRC32_CHECKSUM_ALGORITHIM ) {
 178  0
             byte  buffer[] = new byte[1024];
 179  0
             CRC32 crc32 = new CRC32();
 180  0
             for (int i = 0; i < payloadLength;) {
 181  0
                 int l = Math.min(buffer.length, payloadLength-i);
 182  0
                 in.readFully(buffer,0,l);
 183  0
                 crc32.update(buffer,0,l);
 184  0
                 i+=l;
 185   
             }            
 186  0
             checksum = crc32.getValue();
 187   
         } else {
 188  0
             checksum = 0L;
 189   
         }
 190   
     }
 191   
 
 192   
     
 193   
     /**
 194   
      */
 195  40
     private void readAndCheckConstant(DataInput in, byte[] byteConstant, String errorMessage ) throws IOException {
 196  40
         for (int i = 0; i < byteConstant.length; i++) {
 197  100
             byte checkByte = byteConstant[i];
 198  100
             if( in.readByte()!= checkByte ) {
 199  10
                 throw new IOException(errorMessage);
 200   
             }
 201   
         }
 202   
     }    
 203   
     
 204  0
     public boolean readFromPacket(Packet packet) throws IOException {
 205  0
         Packet dup = packet.duplicate();
 206   
 
 207  0
         if( dup.remaining() < RECORD_HEADER_SIZE )
 208  0
             return false;
 209  0
         DataInputStream is = new DataInputStream(new PacketInputStream(dup));
 210  0
         readHeader( is );
 211  0
         if( dup.remaining() < payloadLength+RECORD_FOOTER_SIZE ) {
 212  0
             return false;
 213   
         }
 214   
         
 215   
         // Set limit to create a slice of the payload.
 216  0
         dup.limit(dup.position()+payloadLength);
 217  0
         this.payload = dup.slice();        
 218  0
         if( isChecksumingEnabled() ) {
 219  0
             checksum(new DataInputStream(new PacketInputStream(payload)));
 220   
         }
 221   
         
 222   
         // restore the limit and seek to the footer.
 223  0
         dup.limit(packet.limit());
 224  0
         dup.position(dup.position()+payloadLength);
 225  0
         readFooter(is);
 226   
         
 227   
         // If every thing went well.. advance the position of the orignal packet.
 228  0
         packet.position(dup.position());
 229  0
         dup.dispose();
 230  0
         return true;        
 231   
     }
 232   
     
 233   
     /**
 234   
      * @return Returns the checksum.
 235   
      */
 236  0
     public long getChecksum() {
 237  0
         return checksum;
 238   
     }
 239   
 
 240   
     /**
 241   
      * @return Returns the length.
 242   
      */
 243  22
     public int getPayloadLength() {
 244  22
         return payloadLength;
 245   
     }
 246   
 
 247   
     /**
 248   
      * @return Returns the length of the record .
 249   
      */
 250  0
     public int getRecordLength() {
 251  0
         return payloadLength+Record.RECORD_BASE_SIZE;
 252   
     }
 253   
 
 254   
     /**
 255   
      * @return Returns the location.
 256   
      */
 257  0
     public Location getLocation() {
 258  0
         return location;
 259   
     }
 260   
     
 261   
     /**
 262   
      * @return Returns the mark.
 263   
      */
 264  0
     public Location getMark() {
 265  0
         return mark;
 266   
     }
 267   
 
 268   
     /**
 269   
      * @return Returns the payload.
 270   
      */
 271  0
     public Packet getPayload() {
 272  0
         return payload;
 273   
     }
 274   
 
 275   
     /**
 276   
      * @return Returns the recordType.
 277   
      */
 278  8
     public byte getRecordType() {
 279  8
         return recordType;
 280   
     }
 281   
 
 282  36
     public boolean hasRemaining() {
 283  36
         return headerFooterPacket.position()!=RECORD_BASE_SIZE;
 284   
     }
 285   
 
 286  22
     public void read(Packet packet) {
 287   
         
 288   
         // push the header
 289  22
         headerFooterPacket.read(packet);
 290   
         // push the payload.
 291  22
         payload.read(packet);
 292   
         
 293   
         // Can we switch to the footer now?
 294  22
         if( !payload.hasRemaining() && headerFooterPacket.position()==RECORD_HEADER_SIZE ) {
 295  22
             headerFooterPacket.position(RECORD_HEADER_SIZE);
 296  22
              headerFooterPacket.limit(RECORD_BASE_SIZE);
 297  22
             headerFooterPacket.read(packet);            
 298   
         }
 299   
         
 300   
     }
 301   
 
 302  0
     public void dispose() {
 303  0
         if( payload!=null ) {
 304  0
             payload.dispose();
 305  0
             payload=null;
 306   
         }
 307   
     }
 308   
 
 309   
 }
 310