Home | History | Annotate | Download | only in test
      1 /*******************************************************************************
      2  * Copyright (c) 2009, 2018 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  *    Evgeny Mandrikov - initial API and implementation
     10  *
     11  *******************************************************************************/
     12 package org.jacoco.core.test;
     13 
     14 import java.io.IOException;
     15 
     16 import org.jacoco.core.data.ExecutionDataStore;
     17 import org.jacoco.core.data.SessionInfoStore;
     18 import org.jacoco.core.instr.Instrumenter;
     19 import org.jacoco.core.runtime.IRuntime;
     20 import org.jacoco.core.runtime.RuntimeData;
     21 import org.jacoco.core.runtime.SystemPropertiesRuntime;
     22 
     23 /**
     24  * Class loader which loads classes from another class loader and instruments
     25  * them.
     26  */
     27 public final class InstrumentingLoader extends ClassLoader {
     28 
     29 	private final IRuntime runtime;
     30 	private final String scope;
     31 	private final ClassLoader delegate;
     32 
     33 	private final RuntimeData data;
     34 	private final Instrumenter instrumenter;
     35 
     36 	public InstrumentingLoader(IRuntime runtime, String scope,
     37 			ClassLoader delegate) throws Exception {
     38 		this.runtime = runtime;
     39 		this.scope = scope;
     40 		this.delegate = delegate;
     41 		this.data = new RuntimeData();
     42 		runtime.startup(data);
     43 		this.instrumenter = new Instrumenter(runtime);
     44 	}
     45 
     46 	public InstrumentingLoader(Class<?> target) throws Exception {
     47 		this(new SystemPropertiesRuntime(), target.getPackage().getName(),
     48 				target.getClassLoader());
     49 	}
     50 
     51 	@Override
     52 	protected synchronized Class<?> loadClass(String name, boolean resolve)
     53 			throws ClassNotFoundException {
     54 		if (name.startsWith(scope)) {
     55 			final byte[] bytes;
     56 			try {
     57 				bytes = TargetLoader.getClassDataAsBytes(delegate, name);
     58 			} catch (IOException e) {
     59 				throw new ClassNotFoundException("Unable to load", e);
     60 			}
     61 			final byte[] instrumented;
     62 			try {
     63 				instrumented = instrumenter.instrument(bytes, name);
     64 			} catch (IOException e) {
     65 				throw new ClassNotFoundException("Unable to instrument", e);
     66 			}
     67 			final Class<?> c = defineClass(name, instrumented, 0,
     68 					instrumented.length);
     69 			if (resolve) {
     70 				resolveClass(c);
     71 			}
     72 			return c;
     73 		}
     74 		return super.loadClass(name, resolve);
     75 	}
     76 
     77 	public ExecutionDataStore collect() {
     78 		final ExecutionDataStore store = new ExecutionDataStore();
     79 		data.collect(store, new SessionInfoStore(), false);
     80 		runtime.shutdown();
     81 		return store;
     82 	}
     83 
     84 }
     85