Agent.java revision 2a8b5339c422de268cae3a862a85666a9b0ac176
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.agent.rt.internal; 13 14import java.io.ByteArrayOutputStream; 15import java.io.IOException; 16import java.net.InetAddress; 17import java.net.UnknownHostException; 18 19import org.jacoco.agent.rt.IAgent; 20import org.jacoco.agent.rt.internal.controller.IAgentController; 21import org.jacoco.agent.rt.internal.controller.LocalController; 22import org.jacoco.agent.rt.internal.controller.MBeanController; 23import org.jacoco.agent.rt.internal.controller.TcpClientController; 24import org.jacoco.agent.rt.internal.controller.TcpServerController; 25import org.jacoco.core.JaCoCo; 26import org.jacoco.core.data.ExecutionDataWriter; 27import org.jacoco.core.runtime.AbstractRuntime; 28import org.jacoco.core.runtime.AgentOptions; 29import org.jacoco.core.runtime.AgentOptions.OutputMode; 30import org.jacoco.core.runtime.RuntimeData; 31 32/** 33 * The agent manages the life cycle of JaCoCo runtime. 34 */ 35public class Agent implements IAgent { 36 37 private static Agent singleton; 38 39 /** 40 * Returns a global instance which is already started. If the method is 41 * called the first time the instance is created with the given options. 42 * 43 * @param options 44 * options to configure the instance 45 * @return global instance 46 */ 47 public static synchronized Agent getInstance(final AgentOptions options) { 48 if (singleton == null) { 49 final Agent agent = new Agent(options, IExceptionLogger.SYSTEM_ERR); 50 agent.startup(); 51 Runtime.getRuntime().addShutdownHook(new Thread() { 52 @Override 53 public void run() { 54 agent.shutdown(); 55 } 56 }); 57 singleton = agent; 58 } 59 return singleton; 60 } 61 62 /** 63 * Returns a global instance which is already started. If a agent has not 64 * been initialized before this method will fail. 65 * 66 * @return global instance 67 * @throws IllegalStateException 68 * if no Agent has been started yet 69 */ 70 public static synchronized Agent getInstance() throws IllegalStateException { 71 if (singleton == null) { 72 throw new IllegalStateException("JaCoCo agent not started."); 73 } 74 return singleton; 75 } 76 77 private final AgentOptions options; 78 79 private final IExceptionLogger logger; 80 81 private IAgentController controller; 82 83 private final RuntimeData data; 84 85 /** 86 * Creates a new agent with the given agent options. 87 * 88 * @param options 89 * agent options 90 * @param logger 91 * logger used by this agent 92 */ 93 public Agent(final AgentOptions options, final IExceptionLogger logger) { 94 this.options = options; 95 this.logger = logger; 96 this.data = new RuntimeData(); 97 } 98 99 /** 100 * Returns the runtime data object created by this agent 101 * 102 * @return runtime data for this agent instance 103 */ 104 public RuntimeData getData() { 105 return data; 106 } 107 108 /** 109 * Initializes this agent. 110 * 111 */ 112 public void startup() { 113 try { 114 String sessionId = options.getSessionId(); 115 if (sessionId == null) { 116 sessionId = createSessionId(); 117 } 118 data.setSessionId(sessionId); 119 controller = createAgentController(); 120 controller.startup(options, data); 121 } catch (final Exception e) { 122 logger.logExeption(e); 123 } 124 } 125 126 /** 127 * Shutdown the agent again. 128 */ 129 public void shutdown() { 130 try { 131 if (options.getDumpOnExit()) { 132 controller.writeExecutionData(false); 133 } 134 controller.shutdown(); 135 } catch (final Exception e) { 136 logger.logExeption(e); 137 } 138 } 139 140 /** 141 * Create controller implementation as given by the agent options. 142 * 143 * @return configured controller implementation 144 */ 145 IAgentController createAgentController() { 146 final OutputMode controllerType = options.getOutput(); 147 switch (controllerType) { 148 case file: 149 return new LocalController(); 150 case tcpserver: 151 return new TcpServerController(logger); 152 case tcpclient: 153 return new TcpClientController(logger); 154 case mbean: 155 return new MBeanController(); 156 default: 157 throw new AssertionError(controllerType); 158 } 159 } 160 161 private String createSessionId() { 162 String host; 163 try { 164 host = InetAddress.getLocalHost().getHostName(); 165 } catch (final UnknownHostException e) { 166 host = "unknownhost"; 167 } 168 return host + "-" + AbstractRuntime.createRandomId(); 169 } 170 171 // === IAgent Implementation === 172 173 public String getVersion() { 174 return JaCoCo.VERSION; 175 } 176 177 public String getSessionId() { 178 return data.getSessionId(); 179 } 180 181 public void setSessionId(final String id) { 182 data.setSessionId(id); 183 } 184 185 public void reset() { 186 data.reset(); 187 } 188 189 public byte[] getExecutionData(final boolean reset) { 190 final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 191 try { 192 final ExecutionDataWriter writer = new ExecutionDataWriter(buffer); 193 data.collect(writer, writer, reset); 194 } catch (final IOException e) { 195 // Must not happen with ByteArrayOutputStream 196 throw new AssertionError(e); 197 } 198 return buffer.toByteArray(); 199 } 200 201 public void dump(final boolean reset) throws IOException { 202 controller.writeExecutionData(reset); 203 } 204 205} 206