CoverageTransformer.java

    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.agent.rt;
   14
   15import static java.lang.String.format;
   16
   17import java.lang.instrument.ClassFileTransformer;
   18import java.lang.instrument.IllegalClassFormatException;
   19import java.security.ProtectionDomain;
   20
   21import org.jacoco.core.instr.CRC64;
   22import org.jacoco.core.instr.Instrumenter;
   23import org.jacoco.core.runtime.AgentOptions;
   24import org.jacoco.core.runtime.IRuntime;
   25import org.jacoco.core.runtime.WildcardMatcher;
   26
   27/**
   28 * Class file transformer to instrument classes for code coverage analysis.
   29 * 
   30 * @author Marc R. Hoffmann
   31 * @version $Revision: $
   32 */
   33public class CoverageTransformer implements ClassFileTransformer {
   34
   35    private static final String AGENT_PREFIX;
   36
   37    static {
   38        final String name = CoverageTransformer.class.getName();
   39        AGENT_PREFIX = toVMName(name.substring(0, name.lastIndexOf('.')));
   40    }
   41
   42    private final Instrumenter instrumenter;
   43
   44    private final WildcardMatcher includes;
   45
   46    private final WildcardMatcher excludes;
   47
   48    private final WildcardMatcher exclClassloader;
   49
   50    public CoverageTransformer(IRuntime runtime, AgentOptions options) {
   51        this.instrumenter = new Instrumenter(runtime);
   52        // Class names will be reported in VM notation:
   53        includes = new WildcardMatcher(toVMName(options.getIncludes()));
   54        excludes = new WildcardMatcher(toVMName(options.getExcludes()));
   55        exclClassloader = new WildcardMatcher(options.getExclClassloader());
   56    }
   57
   58    public byte[] transform(ClassLoader loader, String classname,
   59            Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
   60            byte[] classfileBuffer) throws IllegalClassFormatException {
   61
   62        if (!filter(loader, classname)) {
   63            return null;
   64        }
   65
   66        try {
   67            return instrumenter.instrument(classfileBuffer);
   68        } catch (Throwable t) {
   69            final Long id = Long.valueOf(CRC64.checksum(classfileBuffer));
   70            final String msg = "Error while instrumenting class %s (id=0x%x).";
   71            final IllegalClassFormatException ex = new IllegalClassFormatException(
   72                    format(msg, classname, id));
   73            ex.initCause(t);
   74            // Force some output, as the exception is ignored by the JVM:
   75            ex.printStackTrace();
   76            throw ex;
   77        }
   78    }
   79
   80    /**
   81     * Checks whether this class should be instrumented.
   82     * 
   83     * @param loader
   84     *            loader for the class
   85     * @return <code>true</code> if the class should be instrumented
   86     */
   87    protected boolean filter(ClassLoader loader, String classname) {
   88        // Don't instrument classes of the bootstrap loader:
   89        return loader != null &&
   90
   91        !classname.startsWith(AGENT_PREFIX) &&
   92
   93        !exclClassloader.matches(loader.getClass().getName()) &&
   94
   95        includes.matches(classname) &&
   96
   97        !excludes.matches(classname);
   98    }
   99
  100    private static String toVMName(String srcName) {
  101        return srcName.replace('.', '/');
  102    }
  103
  104}