AgentOptions.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.core.runtime;
   14
   15import static java.lang.String.format;
   16
   17import java.io.File;
   18import java.util.Arrays;
   19import java.util.Collection;
   20import java.util.HashMap;
   21import java.util.Map;
   22
   23/**
   24 * Utility to create and parse options for the runtime agent. Options are
   25 * represented as a string in the following format:
   26 * 
   27 * <pre>
   28 *   key1=value1,key2=value2,key3=value3
   29 * </pre>
   30 * 
   31 * @author Marc R. Hoffmann
   32 * @version $Revision: $
   33 */
   34public class AgentOptions {
   35
   36    /**
   37     * Specifies the output file for execution data. Default is
   38     * <code>jacoco.exec</code> in the working directory.
   39     */
   40    public static final String DESTFILE = "destfile";
   41
   42    /**
   43     * Specifies whether execution data should be appended to the output file.
   44     * Default is <code>true</code>.
   45     */
   46    public static final String APPEND = "append";
   47
   48    /**
   49     * Wildcard expression for class names that should be included for code
   50     * coverage. Default is <code>*</code> (all classes included).
   51     * 
   52     * @see WildcardMatcher
   53     */
   54    public static final String INCLUDES = "includes";
   55
   56    /**
   57     * Wildcard expression for class names that should be excluded from code
   58     * coverage. Default is the empty string (no exclusions).
   59     * 
   60     * @see WildcardMatcher
   61     */
   62    public static final String EXCLUDES = "excludes";
   63
   64    /**
   65     * Wildcard expression for class loaders names for classes that should be
   66     * excluded from code coverage. This means all classes loaded by a class
   67     * loader which full qualified name matches this expression will be ignored
   68     * for code coverage regardless of all other filtering settings. Default is
   69     * <code>sun.reflect.DelegatingClassLoader</code>.
   70     * 
   71     * @see WildcardMatcher
   72     */
   73    public static final String EXCLCLASSLOADER = "exclclassloader";
   74
   75    private static final Collection<String> VALID_OPTIONS = Arrays.asList(
   76            DESTFILE, APPEND, INCLUDES, EXCLUDES, EXCLCLASSLOADER);
   77
   78    private final Map<String, String> options;
   79
   80    /**
   81     * New instance with all values set to default.
   82     */
   83    public AgentOptions() {
   84        this.options = new HashMap<String, String>();
   85    }
   86
   87    /**
   88     * New instance parsed from the given option string.
   89     * 
   90     * @param optionstr
   91     *            string to parse or <code>null</code>
   92     */
   93    public AgentOptions(final String optionstr) {
   94        this();
   95        if (optionstr != null && optionstr.length() > 0) {
   96            for (final String entry : optionstr.split(",")) {
   97                final int pos = entry.indexOf('=');
   98                if (pos == -1) {
   99                    throw new IllegalArgumentException(format(
  100                            "Invalid agent option syntax \"%s\".", optionstr));
  101                }
  102                final String key = entry.substring(0, pos);
  103                if (!VALID_OPTIONS.contains(key)) {
  104                    throw new IllegalArgumentException(format(
  105                            "Unknown agent option \"%s\".", key));
  106                }
  107                options.put(key, entry.substring(pos + 1));
  108            }
  109        }
  110    }
  111
  112    /**
  113     * Returns the output file location.
  114     * 
  115     * @return output file location
  116     */
  117    public String getDestfile() {
  118        final String destfile = options.get(DESTFILE);
  119        return destfile == null ? "jacoco.exec" : destfile;
  120    }
  121
  122    /**
  123     * Sets the output file location.
  124     * 
  125     * @param destfile
  126     *            output file location
  127     */
  128    public void setDestfile(final String destfile) {
  129        setOption(DESTFILE, destfile);
  130    }
  131
  132    /**
  133     * Returns whether the output should be appended to an existing file.
  134     * 
  135     * @return <code>true</code>, when the output should be appended
  136     */
  137    public boolean getAppend() {
  138        final String value = options.get(APPEND);
  139        return value == null ? true : Boolean.parseBoolean(value);
  140    }
  141
  142    /**
  143     * Sets whether the output should be appended to an existing file.
  144     * 
  145     * @param append
  146     *            <code>true</code>, when the output should be appended
  147     */
  148    public void setAppend(final boolean append) {
  149        setOption(APPEND, String.valueOf(append));
  150    }
  151
  152    /**
  153     * Returns the wildcard expression for classes to include.
  154     * 
  155     * @return wildcard expression for classes to include
  156     * @see WildcardMatcher
  157     */
  158    public String getIncludes() {
  159        final String value = options.get(INCLUDES);
  160        return value == null ? "*" : value;
  161    }
  162
  163    /**
  164     * Sets the wildcard expression for classes to include.
  165     * 
  166     * @param includes
  167     *            wildcard expression for classes to include
  168     * @see WildcardMatcher
  169     */
  170    public void setIncludes(final String includes) {
  171        setOption(INCLUDES, includes);
  172    }
  173
  174    /**
  175     * Returns the wildcard expression for classes to exclude.
  176     * 
  177     * @return wildcard expression for classes to exclude
  178     * @see WildcardMatcher
  179     */
  180    public String getExcludes() {
  181        final String value = options.get(EXCLUDES);
  182        return value == null ? "" : value;
  183    }
  184
  185    /**
  186     * Sets the wildcard expression for classes to exclude.
  187     * 
  188     * @param excludes
  189     *            wildcard expression for classes to exclude
  190     * @see WildcardMatcher
  191     */
  192    public void setExcludes(final String excludes) {
  193        setOption(EXCLUDES, excludes);
  194    }
  195
  196    /**
  197     * Returns the wildcard expression for excluded class loaders.
  198     * 
  199     * @return expression for excluded class loaders
  200     * @see WildcardMatcher
  201     */
  202    public String getExclClassloader() {
  203        final String value = options.get(EXCLCLASSLOADER);
  204        return value == null ? "sun.reflect.DelegatingClassLoader" : value;
  205    }
  206
  207    /**
  208     * Sets the wildcard expression for excluded class loaders.
  209     * 
  210     * @param expression
  211     *            expression for excluded class loaders
  212     * @see WildcardMatcher
  213     */
  214    public void setExclClassloader(final String expression) {
  215        setOption(EXCLCLASSLOADER, expression);
  216    }
  217
  218    private void setOption(final String key, final String value) {
  219        if (value.contains(",")) {
  220            throw new IllegalArgumentException(format(
  221                    "Invalid character in option argument \"%s\"", value));
  222        }
  223        options.put(key, value);
  224    }
  225
  226    /**
  227     * Generate required JVM argument string based on current configuration and
  228     * supplied agent jar location
  229     * 
  230     * @param agentJarFile
  231     *            location of the JaCoCo Agent Jar
  232     * @return Argument to pass to create new VM with coverage enabled
  233     */
  234    public String getVMArgument(final File agentJarFile) {
  235        return format("-javaagent:%s=%s", agentJarFile, this);
  236    }
  237
  238    /**
  239     * Creates a string representation that can be passed to the agent via the
  240     * command line. Might be the empty string, if no options are set.
  241     */
  242    @Override
  243    public String toString() {
  244        final StringBuilder sb = new StringBuilder();
  245        for (final String key : VALID_OPTIONS) {
  246            final String value = options.get(key);
  247            if (value != null) {
  248                if (sb.length() > 0) {
  249                    sb.append(',');
  250                }
  251                sb.append(key).append('=').append(value);
  252            }
  253        }
  254        return sb.toString();
  255    }
  256
  257}