/*
* JBoss, Home of Professional Open Source
* Copyright 2011 Red Hat Inc. and/or its affiliates and other
* contributors as indicated by the @author tags. All rights reserved.
* See the copyright.txt in the distribution for a full listing of
* individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.infinispan.test;
import org.jboss.logging.Logger;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
/**
* A classloader where the classes that are included, excluded or not found can
* individually configured to suit a particular test in a cherry pick fashion.
*
* @author Galder ZamarreƱo
* @since 5.0
*/
public class CherryPickClassLoader extends ClassLoader {
private static final Logger log = Logger.getLogger(CherryPickClassLoader.class);
private String[] includedClasses;
private String[] excludedClasses;
private String[] notFoundClasses;
private Map<String, Class> classes = new HashMap<String, Class>();
public CherryPickClassLoader(String[] includedClasses,
String[] excludedClasses, ClassLoader parent) {
this(includedClasses, excludedClasses, null, parent);
}
public CherryPickClassLoader(String[] includedClasses,
String[] excludedClasses,
String[] notFoundClasses, ClassLoader parent) {
super(parent);
this.includedClasses = includedClasses;
this.excludedClasses = excludedClasses;
this.notFoundClasses = notFoundClasses;
log.debugf("Created %s", this);
}
@Override
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
log.tracef("loadClass(%s,%b)", name, resolve);
if (isIncluded(name) && (isExcluded(name) == false)) {
Class c = findClass(name);
if (resolve)
resolveClass(c);
return c;
} else if (isNotFound(name)) {
throw new ClassNotFoundException(name + " is discarded");
} else {
return super.loadClass(name, resolve);
}
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
log.tracef("findClass(%s)", name);
Class result = classes.get(name);
if (result != null)
return result;
if (isIncluded(name) && (isExcluded(name) == false)) {
result = createClass(name);
} else if (isNotFound(name)) {
throw new ClassNotFoundException(name + " is discarded");
} else {
result = super.findClass(name);
}
classes.put(name, result);
return result;
}
protected Class createClass(String name) throws ClassFormatError, ClassNotFoundException {
log.infof("createClass(%s)", name);
try {
InputStream is = getResourceAsStream(name.replace('.', '/').concat(".class"));
byte[] bytes = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
int read;
while ((read = is.read(bytes)) > -1) {
baos.write(bytes, 0, read);
}
bytes = baos.toByteArray();
return this.defineClass(name, bytes, 0, bytes.length);
} catch (FileNotFoundException e) {
throw new ClassNotFoundException("cannot find " + name, e);
} catch (IOException e) {
throw new ClassNotFoundException("cannot read " + name, e);
}
}
protected boolean isIncluded(String className) {
if (includedClasses != null) {
for (int i = 0; i < includedClasses.length; i++) {
if (className.startsWith(includedClasses[i])) {
return true;
}
}
}
return false;
}
protected boolean isExcluded(String className) {
if (excludedClasses != null) {
for (int i = 0; i < excludedClasses.length; i++) {
if (className.startsWith(excludedClasses[i])) {
return true;
}
}
}
return false;
}
protected boolean isNotFound(String className) {
if (notFoundClasses != null) {
for (int i = 0; i < notFoundClasses.length; i++) {
if (className.startsWith(notFoundClasses[i])) {
return true;
}
}
}
return false;
}
@Override
public String toString() {
String s = getClass().getName();
s += "[includedClasses=";
s += listClasses(includedClasses);
s += ";excludedClasses=";
s += listClasses(excludedClasses);
s += ";notFoundClasses=";
s += listClasses(notFoundClasses);
s += ";parent=";
s += getParent();
s += "]";
return s;
}
private static String listClasses(String[] classes) {
if (classes == null) return null;
String s = "";
for (int i = 0; i < classes.length; i++) {
if (i > 0) s += ",";
s += classes[i];
}
return s;
}
}