org.wisdom.test.shared.InVivoClassLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.wisdom.test.shared.InVivoClassLoader.java

Source

/*
 * #%L
 * Wisdom-Framework
 * %%
 * Copyright (C) 2013 - 2014 Wisdom Framework
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package org.wisdom.test.shared;

import org.apache.commons.io.IOUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;

import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * A classloader responsible for loading the test classes and finding classes from the application bundles.
 */
public class InVivoClassLoader extends ClassLoader {
    private final BundleContext context;
    private final String testClass;

    /**
     * Creates the classloader.
     *
     * @param clazz   the test class
     * @param context the bundle context
     */
    public InVivoClassLoader(String clazz, BundleContext context) {
        this.context = context;
        this.testClass = clazz;
    }

    /**
     * Loads the byte code of the given class. The byte code is loaded form the resource contained in the bundle.
     *
     * @param classname the class name
     * @return the loaded byte array containing the byte code
     * @throws IOException if the class cannot be loaded.
     */
    private byte[] loadBytecode(String classname) throws IOException {
        URL resource = context.getBundle().getResource(classname.replace(".", "/") + ".class");
        if (resource == null) {
            throw new IOException("Cannot load the bytecode of " + classname);
        }
        return IOUtils.toByteArray(resource);
    }

    /**
     * Attempts to load the class with the given name. If this class is the test class (or one of its inner class),
     * it defines it, otherwise it loads the class using the bundle class loader.
     *
     * @param name the class name
     * @return the loaded class
     * @throws ClassNotFoundException if the class cannot be loaded (not found)
     */
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        if (name.equals(testClass) || name.startsWith(testClass + "$")) {
            try {
                final byte[] bytes = loadBytecode(name);
                return defineClass(name, bytes, 0, bytes.length);
            } catch (IOException e) {
                throw new RuntimeException("Cannot define class " + name + " - did not find the .class file", e);
            }
        }

        try {
            return context.getBundle().loadClass(name);
        } catch (ClassNotFoundException e) { //NOSONAR
            // Next.
        }

        List<Bundle> bundles = Arrays.asList(context.getBundles());
        Collections.reverse(bundles);
        for (Bundle bundle : bundles) {
            try {
                return bundle.loadClass(name);
            } catch (ClassNotFoundException e) { //NOSONAR
                // Next.
            }
        }

        return super.loadClass(name);

    }
}