JacocoAgent.java

    1/*******************************************************************************
    2 * Copyright (c) 2009 Mountainminds GmbH & Co. KG and others
    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.agent.rt;
   14
   15import java.io.BufferedOutputStream;
   16import java.io.File;
   17import java.io.FileOutputStream;
   18import java.io.IOException;
   19import java.io.OutputStream;
   20import java.lang.instrument.Instrumentation;
   21
   22import org.jacoco.core.data.ExecutionDataWriter;
   23import org.jacoco.core.runtime.AgentOptions;
   24import org.jacoco.core.runtime.IRuntime;
   25import org.jacoco.core.runtime.ModifiedSystemClassRuntime;
   26
   27/**
   28 * The agent which is referred as the <code>Premain-Class</code>.
   29 * 
   30 * @author Marc R. Hoffmann
   31 * @version $Revision: $
   32 */
   33public class JacocoAgent {
   34
   35    private final AgentOptions options;
   36
   37    private IRuntime runtime;
   38
   39    /**
   40     * Creates a new agent with the given agent options.
   41     * 
   42     * @param options
   43     *            agent options
   44     */
   45    public JacocoAgent(AgentOptions options) {
   46        this.options = options;
   47    }
   48
   49    /**
   50     * Creates a new agent with the given agent options string.
   51     * 
   52     * @param agentArgs
   53     *            agent options as text string
   54     */
   55    public JacocoAgent(String options) {
   56        this(new AgentOptions(options));
   57    }
   58
   59    /**
   60     * Initializes this agent.
   61     * 
   62     * @param inst
   63     *            instrumentation services
   64     * @throws Exception
   65     *             internal startup problem
   66     */
   67    public void init(final Instrumentation inst) throws Exception {
   68        runtime = createRuntime(inst);
   69        runtime.startup();
   70        inst.addTransformer(new CoverageTransformer(runtime, options));
   71    }
   72
   73    /**
   74     * Creates the specific coverage runtime implementation.
   75     * 
   76     * @param inst
   77     *            instrumentation services
   78     * @return coverage runtime instance
   79     * @throws Exception
   80     *             creation problem
   81     */
   82    protected IRuntime createRuntime(final Instrumentation inst)
   83            throws Exception {
   84        return ModifiedSystemClassRuntime.createFor(inst, "java/sql/Types");
   85    }
   86
   87    /**
   88     * Shutdown the agent again.
   89     */
   90    public void shutdown() {
   91        writeExecutionData();
   92    }
   93
   94    /**
   95     * Writes the collected execution data to the specified file.
   96     * 
   97     * @param runtime
   98     *            runtime containing the execution data
   99     */
  100    protected void writeExecutionData() {
  101        try {
  102            File execFile = new File(options.getDestfile()).getAbsoluteFile();
  103            File folder = execFile.getParentFile();
  104            if (folder != null) {
  105                folder.mkdirs();
  106            }
  107            OutputStream output = new BufferedOutputStream(
  108                    new FileOutputStream(execFile, options.getAppend()));
  109            ExecutionDataWriter writer = new ExecutionDataWriter(output);
  110            writer.writeHeader();
  111            runtime.collect(writer, false);
  112            output.close();
  113        } catch (IOException e) {
  114            e.printStackTrace();
  115        }
  116    }
  117
  118    /**
  119     * This method is called by the JVM to initialize Java agents.
  120     * 
  121     * @param options
  122     *            agent options
  123     * @param inst
  124     *            intrumentation callback provided by the JVM
  125     */
  126    public static void premain(final String options, final Instrumentation inst)
  127            throws Exception {
  128        final JacocoAgent agent = new JacocoAgent(options);
  129        agent.init(inst);
  130
  131        Runtime.getRuntime().addShutdownHook(new Thread() {
  132            @Override
  133            public void run() {
  134                agent.shutdown();
  135            }
  136        });
  137    }
  138
  139}