ExecutionDataReader.java revision e69ba4dbb015949c5d84ba7bbb0b53efac28bb23
1/******************************************************************************* 2 * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * Marc R. Hoffmann - initial API and implementation 10 * 11 *******************************************************************************/ 12package org.jacoco.core.data; 13 14import static java.lang.String.format; 15 16import java.io.EOFException; 17import java.io.IOException; 18import java.io.InputStream; 19 20import org.jacoco.core.internal.data.CompactDataInput; 21 22/** 23 * Deserialization of execution data from binary streams. 24 */ 25public class ExecutionDataReader { 26 27 /** Underlying data input */ 28 protected final CompactDataInput in; 29 30 private ISessionInfoVisitor sessionInfoVisitor = null; 31 32 private IExecutionDataVisitor executionDataVisitor = null; 33 34 private boolean firstBlock = true; 35 36 /** 37 * Creates a new reader based on the given input stream input. Depending on 38 * the nature of the underlying stream input should be buffered as most data 39 * is read in single bytes. 40 * 41 * @param input 42 * input stream to read execution data from 43 */ 44 public ExecutionDataReader(final InputStream input) { 45 this.in = new CompactDataInput(input); 46 } 47 48 /** 49 * Sets an listener for session information. 50 * 51 * @param visitor 52 */ 53 public void setSessionInfoVisitor(final ISessionInfoVisitor visitor) { 54 this.sessionInfoVisitor = visitor; 55 } 56 57 /** 58 * Sets an listener for execution data. 59 * 60 * @param visitor 61 */ 62 public void setExecutionDataVisitor(final IExecutionDataVisitor visitor) { 63 this.executionDataVisitor = visitor; 64 } 65 66 /** 67 * Reads all data and reports it to the corresponding visitors. The stream 68 * is read until its end or a command confirmation has been sent. 69 * 70 * @return <code>true</code> if additional data can be expected after a 71 * command has been executed. <code>false</code> if the end of the 72 * stream has been reached. 73 * @throws IOException 74 * might be thrown by the underlying input stream 75 */ 76 public boolean read() throws IOException { 77 try { 78 byte type; 79 do { 80 type = in.readByte(); 81 if (firstBlock && type != ExecutionDataWriter.BLOCK_HEADER) { 82 throw new IOException("Invalid execution data file."); 83 } 84 firstBlock = false; 85 } while (readBlock(type)); 86 return true; 87 } catch (final EOFException e) { 88 return false; 89 } 90 } 91 92 /** 93 * Reads a block of data identified by the given id. Subclasses may 94 * overwrite this method to support additional block types. 95 * 96 * @param blocktype 97 * block type 98 * @return <code>true</code> if there are more blocks to read 99 * @throws IOException 100 * might be thrown by the underlying input stream 101 */ 102 protected boolean readBlock(final byte blocktype) throws IOException { 103 switch (blocktype) { 104 case ExecutionDataWriter.BLOCK_HEADER: 105 readHeader(); 106 return true; 107 case ExecutionDataWriter.BLOCK_SESSIONINFO: 108 readSessionInfo(); 109 return true; 110 case ExecutionDataWriter.BLOCK_EXECUTIONDATA: 111 readExecutionData(); 112 return true; 113 default: 114 throw new IOException(format("Unknown block type %x.", 115 Byte.valueOf(blocktype))); 116 } 117 } 118 119 private void readHeader() throws IOException { 120 if (in.readChar() != ExecutionDataWriter.MAGIC_NUMBER) { 121 throw new IOException("Invalid execution data file."); 122 } 123 final char version = in.readChar(); 124 if (version != ExecutionDataWriter.FORMAT_VERSION) { 125 throw new IOException(format("Incompatible version %x.", 126 Integer.valueOf(version))); 127 } 128 } 129 130 private void readSessionInfo() throws IOException { 131 if (sessionInfoVisitor == null) { 132 throw new IOException("No session info visitor."); 133 } 134 final String id = in.readUTF(); 135 final long start = in.readLong(); 136 final long dump = in.readLong(); 137 sessionInfoVisitor.visitSessionInfo(new SessionInfo(id, start, dump)); 138 } 139 140 private void readExecutionData() throws IOException { 141 if (executionDataVisitor == null) { 142 throw new IOException("No execution data visitor."); 143 } 144 final long id = in.readLong(); 145 final String name = in.readUTF(); 146 final boolean[] data = in.readBooleanArray(); 147 executionDataVisitor.visitClassExecution(new ExecutionData(id, name, 148 data)); 149 } 150 151} 152