AgentOptions.java revision 578947ead80e839a698736693a6c8bf724f5eaab
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}
258