patterntesting.runtime.experimental.XrayClassLoader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of patterntesting-rt Show documentation
Show all versions of patterntesting-rt Show documentation
PatternTesting Runtime (patterntesting-rt) is the runtime component for
the PatternTesting framework. It provides the annotations and base classes
for the PatternTesting testing framework (e.g. patterntesting-check,
patterntesting-concurrent or patterntesting-exception) but can be also
used standalone for classpath monitoring or profiling.
It uses AOP and AspectJ to perform this feat.
/*
* $Id: XrayClassLoader.java,v 1.4 2011/07/09 21:43:23 oboehm Exp $
*
* Copyright (c) 2010 by Oliver Boehm
*
* 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 orimplied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* (c)reated 26.12.2010 by oliver ([email protected])
*/
package patterntesting.runtime.experimental;
import java.io.*;
import java.net.URI;
import java.util.*;
import java.util.jar.*;
import org.apache.commons.io.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.*;
import patterntesting.runtime.monitor.ClasspathMonitor;
import patterntesting.runtime.util.Converter;
/**
* If we want to load a class and see what happens if another class (needed by
* the original class) is missing we need a class loader where we can control
* the classpath and other things.
*
* @author oliver
* @since 1.1 (26.12.2010)
*/
public final class XrayClassLoader extends ClassLoader {
private static final ClasspathMonitor classpathMonitor = ClasspathMonitor.getInstance();
private static final Logger log = LoggerFactory.getLogger(XrayClassLoader.class);
private final Map> loadedClassMap = new HashMap>();
/**
* Load class.
*
* @param classname the classname
* @return the class
* @throws ClassNotFoundException the class not found exception
* @see java.lang.ClassLoader#loadClass(java.lang.String)
*/
@Override
public Class> loadClass(final String classname) throws ClassNotFoundException {
Class> loaded = loadedClassMap.get(classname);
if (loaded == null) {
try {
loaded = findClass(classname);
} catch (SecurityException ce) {
log.debug(ce.getLocalizedMessage() + " - using parent to load " + classname);
loaded = super.loadClass(classname);
}
loadedClassMap.put(classname, loaded);
}
return loaded;
}
/**
* Gets the loaded classed of this classloader here.
*
* @return the loaded classed
*/
public Set> getLoadedClasses() {
return new HashSet>(this.loadedClassMap.values());
}
/**
* Find class.
*
* @param classname the classname
* @return the class
* @throws ClassNotFoundException the class not found exception
* @see java.lang.ClassLoader#findClass(java.lang.String)
*/
@Override
protected Class> findClass(final String classname) throws ClassNotFoundException {
URI classUri = classpathMonitor.whichClass(classname);
try {
byte[] data = read(classUri);
return defineClass(classname, data, 0, data.length);
} catch (IOException ioe) {
throw new ClassNotFoundException("can't load class " + classname, ioe);
}
}
private static byte[] read(final URI uri) throws IOException {
log.trace("loading " + uri + "...");
try {
File file = new File(uri);
return FileUtils.readFileToByteArray(file);
} catch (IllegalArgumentException iae) {
String scheme = uri.getScheme();
if ("jar".equals(scheme)) {
return readJar(uri);
} else {
throw new IllegalArgumentException("don't know how to load " + uri);
}
}
}
private static byte[] readJar(final URI uri) throws IOException {
File file = Converter.toFile(StringUtils.substringBefore(uri.toString(), "!"));
String classpath = StringUtils.substringAfterLast(uri.toString(), "!");
JarFile jarFile = new JarFile(file);
JarEntry entry = getEntry(classpath, jarFile);
InputStream istream = jarFile.getInputStream(entry);
try {
return IOUtils.toByteArray(istream);
} finally {
istream.close();
}
}
private static JarEntry getEntry(final String classpath, final JarFile jarFile) {
JarEntry entry = jarFile.getJarEntry(classpath);
if (entry == null) {
entry = jarFile.getJarEntry(classpath.substring(1));
}
return entry;
}
}