1/*******************************************************************************
2 * Copyright (c) 2009, 2015 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 *    Marc R. Hoffmann - initial API and implementation
10 *
11 *******************************************************************************/
12package org.jacoco.core.test;
13
14import java.io.ByteArrayOutputStream;
15import java.io.IOException;
16import java.io.InputStream;
17import java.util.HashMap;
18import java.util.Map;
19
20/**
21 * Loads a single class from a byte array.
22 */
23public class TargetLoader extends ClassLoader {
24
25	private final Map<String, byte[]> classes;
26
27	public TargetLoader() {
28		super(TargetLoader.class.getClassLoader());
29		this.classes = new HashMap<String, byte[]>();
30	}
31
32	public Class<?> add(final String name, final byte[] bytes) {
33		this.classes.put(name, bytes);
34		return load(name);
35	}
36
37	public Class<?> add(final Class<?> name, final byte[] bytes) {
38		return add(name.getName(), bytes);
39	}
40
41	public Class<?> add(final Class<?> source) throws IOException {
42		return add(source.getName(), getClassDataAsBytes(source));
43	}
44
45	private Class<?> load(final String sourcename) {
46		try {
47			return loadClass(sourcename);
48		} catch (ClassNotFoundException e) {
49			// must not happen
50			throw new RuntimeException(e);
51		}
52	}
53
54	public static InputStream getClassData(Class<?> clazz) {
55		final String resource = "/" + clazz.getName().replace('.', '/')
56				+ ".class";
57		return clazz.getResourceAsStream(resource);
58	}
59
60	public static byte[] getClassDataAsBytes(Class<?> clazz) throws IOException {
61		InputStream in = getClassData(clazz);
62		ByteArrayOutputStream out = new ByteArrayOutputStream();
63		byte[] buffer = new byte[0x100];
64		int len;
65		while ((len = in.read(buffer)) != -1) {
66			out.write(buffer, 0, len);
67		}
68		in.close();
69		return out.toByteArray();
70	}
71
72	@Override
73	protected synchronized Class<?> loadClass(String name, boolean resolve)
74			throws ClassNotFoundException {
75		final byte[] bytes = classes.get(name);
76		if (bytes != null) {
77			Class<?> c = defineClass(name, bytes, 0, bytes.length);
78			if (resolve) {
79				resolveClass(c);
80			}
81			return c;
82		}
83		return super.loadClass(name, resolve);
84	}
85
86}
87