ExecutionDataWriter.java revision 37115f4ba4f6126b8c3352ac890c653e428a7dd8
1/******************************************************************************* 2 * Copyright (c) 2009, 2013 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 java.io.ByteArrayOutputStream; 15import java.io.IOException; 16import java.io.OutputStream; 17 18import org.jacoco.core.internal.data.CompactDataOutput; 19 20/** 21 * Serialization of execution data into binary streams. 22 */ 23public class ExecutionDataWriter implements ISessionInfoVisitor, 24 IExecutionDataVisitor { 25 26 /** File format version, will be incremented for each incompatible change. */ 27 public static final char FORMAT_VERSION = 0x1006; 28 29 /** Magic number in header for file format identification. */ 30 public static final char MAGIC_NUMBER = 0xC0C0; 31 32 /** Block identifier for file headers. */ 33 public static final byte BLOCK_HEADER = 0x01; 34 35 /** Block identifier for session information. */ 36 public static final byte BLOCK_SESSIONINFO = 0x10; 37 38 /** Block identifier for execution data of a single class. */ 39 public static final byte BLOCK_EXECUTIONDATA = 0x11; 40 41 /** Underlying data output */ 42 protected final CompactDataOutput out; 43 44 /** 45 * Creates a new writer based on the given output stream. Depending on the 46 * nature of the underlying stream output should be buffered as most data is 47 * written in single bytes. 48 * 49 * @param output 50 * binary stream to write execution data to 51 * @throws IOException 52 * if the header can't be written 53 */ 54 public ExecutionDataWriter(final OutputStream output) throws IOException { 55 this.out = new CompactDataOutput(output); 56 writeHeader(); 57 } 58 59 /** 60 * Writes an file header to identify the stream and its protocol version. 61 * 62 * @throws IOException 63 */ 64 private void writeHeader() throws IOException { 65 out.writeByte(BLOCK_HEADER); 66 out.writeChar(MAGIC_NUMBER); 67 out.writeChar(FORMAT_VERSION); 68 } 69 70 /** 71 * Flushes the underlying stream. 72 * 73 * @throws IOException 74 */ 75 public void flush() throws IOException { 76 out.flush(); 77 } 78 79 public void visitSessionInfo(final SessionInfo info) { 80 try { 81 out.writeByte(BLOCK_SESSIONINFO); 82 out.writeUTF(info.getId()); 83 out.writeLong(info.getStartTimeStamp()); 84 out.writeLong(info.getDumpTimeStamp()); 85 } catch (final IOException e) { 86 throw new RuntimeException(e); 87 } 88 } 89 90 public void visitClassExecution(final ExecutionData data) { 91 try { 92 out.writeByte(BLOCK_EXECUTIONDATA); 93 out.writeLong(data.getId()); 94 out.writeUTF(data.getName()); 95 out.writeBooleanArray(data.getProbes()); 96 } catch (final IOException e) { 97 throw new RuntimeException(e); 98 } 99 } 100 101 /** 102 * Returns the first bytes of a file that represents a valid execution data 103 * file. In any case every execution data file starts with the three bytes 104 * <code>0x01 0xC0 0xC0</code>. 105 * 106 * @return first bytes of a execution data file 107 */ 108 public static final byte[] getFileHeader() { 109 final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 110 try { 111 new ExecutionDataWriter(buffer); 112 } catch (final IOException e) { 113 // Must not happen with ByteArrayOutputStream 114 throw new AssertionError(e); 115 } 116 return buffer.toByteArray(); 117 } 118 119} 120