testful.runner.RemoteClassLoader.java Source code

Java tutorial

Introduction

Here is the source code for testful.runner.RemoteClassLoader.java

Source

/*
 * TestFul - http://code.google.com/p/testful/
 * Copyright (C) 2010  Matteo Miraz
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package testful.runner;

import java.rmi.RemoteException;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import testful.utils.ElementWithKey;

/**
 * Remote class loader.
 * @author matteo
 */
public class RemoteClassLoader extends ClassLoader implements ElementWithKey<String> {

    private static Logger logger = Logger.getLogger("testful.executor");

    private static final ClassLoader superClassLoader = RemoteClassLoader.class.getClassLoader();

    /** for these classes, use always the system class loader */
    private static final String[] SYSTEM_CLASSES = { "testful.coverage.TrackerDatum",
            "testful.model.IClassRegistry", };

    /** for these classes force the use of the remote class loader */
    private static final String[] REMOTE_CLASSES = {
            // Trackers
            "testful.coverage.Tracker", "testful.coverage.behavior.BehaviorTracker",
            "testful.coverage.fault.FaultTracker", "testful.coverage.stopper.Stopper",
            "testful.coverage.stopper.Stopper$1", "testful.coverage.whiteBox.TrackerWhiteBox",

            // Execution Managers
            "testful.runner.Executor", "testful.mutation.MutationTestExecutor",
            "testful.model.executor.TestExecutor", "testful.coverage.CoverageTestExecutor",
            "testful.model.OperationResultTestExecutor", "testful.regression.TestfulTestCase$FaultTestExecutor",

            // Test Executor
            "testful.model.executor.ReflectionExecutor",

            // Utilities
            "testful.model.ClassRegistry", "testful.model.ClassRegistry$1", // Fix for the sun compiler
            "testful.runner.Executor", "testful.runner.ObjectRegistry", };

    /** for these packages, use always the system class loader */
    private static final String[] SYSTEM_PACKAGES = { "testful.model.OperationResult", // this class and its inner classes
    };

    /** for these packages force to use the remote class loader */
    private static final String[] REMOTE_PACKAGES = { "testful.coverage.behavior.Abstractor", // common prefix to all Abstractors
            "org.apache.commons.jexl", };

    public static boolean canUseSystemClassLoader(String name) {
        for (String allow : SYSTEM_CLASSES)
            if (name.equals(allow))
                return true;

        for (String forbid : REMOTE_CLASSES)
            if (name.equals(forbid))
                return false;

        for (String allow : SYSTEM_PACKAGES)
            if (name.startsWith(allow))
                return true;

        for (String forbid : REMOTE_PACKAGES)
            if (name.startsWith(forbid))
                return false;

        return true;
    }

    private static long idGenerator = 0;

    private final long id;
    private final DataFinder finder;
    private final Set<String> loaded;
    private final String key;

    public RemoteClassLoader(DataFinder finder) throws RemoteException {
        super(superClassLoader);

        id = idGenerator++;
        loaded = new HashSet<String>();

        this.finder = finder;
        key = finder.getKey();
    }

    public RemoteClassLoader getNew() throws RemoteException {
        return new RemoteClassLoader(finder);
    }

    public DataFinder getFinder() {
        return finder;
    }

    @Override
    protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {

        if (canUseSystemClassLoader(name) || loaded.contains(name))
            return super.loadClass(name, resolve);

        return findClass(name);
    }

    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {

        final byte[] b;
        try {

            synchronized (finder) {

                final long start = System.currentTimeMillis();
                b = finder.getData(ClassType.NAME, name);
                final long end = System.currentTimeMillis();

                time += (end - start);
            }

        } catch (RemoteException e) {
            final ClassNotFoundException exc = new ClassNotFoundException("Cannot retrieve the class " + name, e);
            logger.log(Level.WARNING, exc.getMessage(), exc);
            throw exc;
        }

        if (b == null)
            throw new ClassNotFoundException("Cannot find class " + name);

        Class<?> c = defineClass(name, b, 0, b.length);
        loaded.add(name);
        return c;

    }

    /** Total time used by method findClass */
    private long time;

    /**
     * Returns the amount of time spent to load classes (and reset the counter)
     * @return the amount of time (ms) spent to load classes
     */
    public long getLoadingTime() {

        final long ret;
        synchronized (finder) {
            ret = time;
            time = 0;
        }

        return ret;
    }

    @Override
    public String getKey() {
        return key;
    }

    @Override
    public String toString() {
        return this.getClass().getSimpleName() + ":" + id;
    }

    @Override
    public RemoteClassLoader clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Clone not supported in RemoteClassLoader");
    }
}