SystemPropertiesRuntime.java revision 402370f12bbe40b6438e06b788c6a4273c6294fd
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 java.util.Arrays;
16import java.util.Collections;
17import java.util.HashMap;
18import java.util.Map;
19
20import org.jacoco.core.data.IExecutionDataVisitor;
21import org.jacoco.core.instr.GeneratorConstants;
22import org.objectweb.asm.Opcodes;
23import org.objectweb.asm.commons.GeneratorAdapter;
24
25/**
26 * This {@link IRuntime} implementation places the coverage data in the
27 * {@link System#getProperties()} hash table. The advantage is, that the
28 * instrumented classes do not get dependencies to other classes than the JRE
29 * library itself.
30 *
31 * This runtime may cause problems in environments with security restrictions,
32 * in applications that replace the system properties or in applications that
33 * fail if non-String values are placed in the system properties.
34 *
35 *
36 * @author Marc R. Hoffmann
37 * @version $Revision: $
38 */
39public class SystemPropertiesRuntime implements IRuntime {
40
41	private static final String KEYPREFIX = "jacoco-";
42
43	private final String key;
44
45	/**
46	 * Creates a new runtime.
47	 */
48	public SystemPropertiesRuntime() {
49		this.key = KEYPREFIX + hashCode();
50	}
51
52	// TODO: lokale Variable vermeiden (swap!)
53	public void generateRegistration(final long classId,
54			final GeneratorAdapter gen) {
55
56		// boolean[][] data = pop()
57		final int data = gen.newLocal(GeneratorConstants.DATAFIELD_TYPE);
58		gen.storeLocal(data);
59
60		// stack := System.getProperties()
61		gen.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System",
62				"getProperties", "()Ljava/util/Properties;");
63
64		// stack := stack.get(key)
65		gen.push(key);
66		gen.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/Properties",
67				"get", "(Ljava/lang/Object;)Ljava/lang/Object;");
68		gen.visitTypeInsn(Opcodes.CHECKCAST, "java/util/Map");
69
70		// stack.put(classId, data)
71		gen.push(classId);
72		gen.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf",
73				"(J)Ljava/lang/Long;");
74
75		gen.loadLocal(data);
76		gen.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Map", "put",
77				"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
78		gen.pop();
79	}
80
81	public void startup() {
82		final Map<Long, boolean[][]> dataMap = Collections
83				.synchronizedMap(new HashMap<Long, boolean[][]>());
84		System.getProperties().put(key, dataMap);
85	}
86
87	@SuppressWarnings("unchecked")
88	private Map<Long, boolean[][]> getDataMap() {
89		final Object object = System.getProperties().get(key);
90		if (object == null) {
91			throw new IllegalStateException("Runtime not started.");
92		}
93		return (Map<Long, boolean[][]>) object;
94	}
95
96	public void collect(final IExecutionDataVisitor visitor, final boolean reset) {
97		final Map<Long, boolean[][]> dataMap = getDataMap();
98		synchronized (dataMap) {
99			for (final Map.Entry<Long, boolean[][]> entry : dataMap.entrySet()) {
100				final long classId = entry.getKey().longValue();
101				final boolean[][] blockData = entry.getValue();
102				visitor.visitClassExecution(classId, blockData);
103			}
104			if (reset) {
105				reset();
106			}
107		}
108	}
109
110	public void reset() {
111		final Map<Long, boolean[][]> dataMap = getDataMap();
112		synchronized (dataMap) {
113			for (final boolean[][] data : dataMap.values()) {
114				for (final boolean[] arr : data) {
115					Arrays.fill(arr, false);
116				}
117			}
118		}
119	}
120
121	public void shutdown() {
122		System.getProperties().remove(key);
123	}
124
125}
126