content: /*******************************************************************************
   * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *    Evgeny Mandrikov - initial API and implementation
   *
   *******************************************************************************/
  package org.jacoco.core.test;
  
  import java.io.IOException;
  
  import org.jacoco.core.data.ExecutionDataStore;
  import org.jacoco.core.data.SessionInfoStore;
  import org.jacoco.core.instr.Instrumenter;
  import org.jacoco.core.runtime.IRuntime;
  import org.jacoco.core.runtime.RuntimeData;
  import org.jacoco.core.runtime.SystemPropertiesRuntime;
  
  /**
   * Class loader which loads classes from another class loader and instruments
   * them.
   */
  public final class InstrumentingLoader extends ClassLoader {
  
  	private final IRuntime runtime;
  	private final String scope;
  	private final ClassLoader delegate;
  
  	private final RuntimeData data;
  	private final Instrumenter instrumenter;
  
  	public InstrumentingLoader(IRuntime runtime, String scope,
  			ClassLoader delegate) throws Exception {
  		this.runtime = runtime;
  		this.scope = scope;
  		this.delegate = delegate;
  		this.data = new RuntimeData();
  		runtime.startup(data);
  		this.instrumenter = new Instrumenter(runtime);
  	}
  
  	public InstrumentingLoader(Class<?> target) throws Exception {
  		this(new SystemPropertiesRuntime(), target.getPackage().getName(),
  				target.getClassLoader());
  	}
  
  	@Override
  	protected synchronized Class<?> loadClass(String name, boolean resolve)
  			throws ClassNotFoundException {
  		if (name.startsWith(scope)) {
  			final byte[] bytes;
  			try {
  				bytes = TargetLoader.getClassDataAsBytes(delegate, name);
  			} catch (IOException e) {
  				throw new ClassNotFoundException("Unable to load", e);
  			}
  			final byte[] instrumented;
  			try {
  				instrumented = instrumenter.instrument(bytes, name);
  			} catch (IOException e) {
  				throw new ClassNotFoundException("Unable to instrument", e);
  			}
  			final Class<?> c = defineClass(name, instrumented, 0,
  					instrumented.length);
  			if (resolve) {
  				resolveClass(c);
  			}
  			return c;
  		}
  		return super.loadClass(name, resolve);
  	}
  
  	public ExecutionDataStore collect() {
  		final ExecutionDataStore store = new ExecutionDataStore();
  		data.collect(store, new SessionInfoStore(), false);
  		runtime.shutdown();
  		return store;
  	}
  
  }
  