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