1e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/*******************************************************************************
2398ee59bebad6835dab57b60157eff16d511709eMarc R. Hoffmann * Copyright (c) 2009, 2015 Mountainminds GmbH & Co. KG and Contributors
3e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * All rights reserved. This program and the accompanying materials
4e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * are made available under the terms of the Eclipse Public License v1.0
5e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * which accompanies this distribution, and is available at
6e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * http://www.eclipse.org/legal/epl-v10.html
7e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *
8e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Contributors:
9e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *    Marc R. Hoffmann - initial API and implementation
10e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *
11e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *******************************************************************************/
12e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpackage org.jacoco.core.test;
13e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
14e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.ByteArrayOutputStream;
15e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.IOException;
16e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.InputStream;
179d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmannimport java.util.HashMap;
189d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmannimport java.util.Map;
19e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
20e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/**
21e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Loads a single class from a byte array.
22e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */
23e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpublic class TargetLoader extends ClassLoader {
24e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
259d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann	private final Map<String, byte[]> classes;
26e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
279d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann	public TargetLoader() {
289d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann		super(TargetLoader.class.getClassLoader());
299d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann		this.classes = new HashMap<String, byte[]>();
309d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann	}
31e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
329d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann	public Class<?> add(final String name, final byte[] bytes) {
339d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann		this.classes.put(name, bytes);
349d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann		return load(name);
359d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann	}
36e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
379d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann	public Class<?> add(final Class<?> name, final byte[] bytes) {
389d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann		return add(name.getName(), bytes);
39e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
40e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
419d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann	public Class<?> add(final Class<?> source) throws IOException {
429d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann		return add(source.getName(), getClassDataAsBytes(source));
43e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
44e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
45e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private Class<?> load(final String sourcename) {
46e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		try {
47e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			return loadClass(sourcename);
48e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		} catch (ClassNotFoundException e) {
49e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			// must not happen
50e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throw new RuntimeException(e);
51e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
52e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
53e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
54e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public static InputStream getClassData(Class<?> clazz) {
55e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		final String resource = "/" + clazz.getName().replace('.', '/')
56e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				+ ".class";
57e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return clazz.getResourceAsStream(resource);
58e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
59e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
60e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public static byte[] getClassDataAsBytes(Class<?> clazz) throws IOException {
61e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		InputStream in = getClassData(clazz);
62e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		ByteArrayOutputStream out = new ByteArrayOutputStream();
63e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		byte[] buffer = new byte[0x100];
64e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		int len;
65e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		while ((len = in.read(buffer)) != -1) {
66e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			out.write(buffer, 0, len);
67e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
68e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		in.close();
69e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return out.toByteArray();
70e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
71e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
72e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	@Override
73e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	protected synchronized Class<?> loadClass(String name, boolean resolve)
74e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throws ClassNotFoundException {
759d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann		final byte[] bytes = classes.get(name);
769d79259f33e7117a4bf4ec1db2848e9429455325Marc R. Hoffmann		if (bytes != null) {
77e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			Class<?> c = defineClass(name, bytes, 0, bytes.length);
78e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			if (resolve) {
79e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov				resolveClass(c);
80e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			}
81e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			return c;
82e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
83e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return super.loadClass(name, resolve);
84e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
85e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
86e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov}
87