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