package net.unit8.waitt.feature.coverage; import net.sourceforge.cobertura.util.IOUtil; import java.io.InputStream; import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.Vector; import java.util.logging.Logger; import java.util.regex.Pattern; /** * @author kawasima */ @SuppressWarnings("rawtypes") public class CoberturaClassLoader extends ClassLoader { private static final Logger logger = Logger.getLogger(CoberturaClassLoader.class.getName()); private static CoberturaClassLoader instance; private Set<String> targetPackages; private final Collection<Pattern> ignoreRegexes = new Vector<Pattern>(); private final Set<String> ignoreMethodAnnotations = new HashSet<String>(); private Instrumenter instrumenter = null; private CoberturaClassLoader(ClassLoader parent) { super(parent); initInstrumenter(); } public static synchronized CoberturaClassLoader create(ClassLoader parent) { if (instance == null) { instance = new CoberturaClassLoader(parent); } return instance; } public static CoberturaClassLoader getInstance() { if (instance == null) { throw new IllegalStateException("CoberturaClassLoader hasn't been instantiated yet."); } return instance; } private void initInstrumenter() { instrumenter = new CoberturaInstrumenterWrapper(); instrumenter.setIgnoreRegexes(ignoreRegexes); instrumenter.setIgnoreTrivial(false); instrumenter .setIgnoreMethodAnnotations(ignoreMethodAnnotations); instrumenter.setThreadsafeRigorous(false); instrumenter.setFailOnError(false); } @SuppressWarnings("unchecked") public Class loadClass(final String className, boolean resolve) throws ClassNotFoundException { Class clazz = findLoadedClass(className); if (clazz != null) { return clazz; } Boolean isTargetPackage = false; for (String pkgName : targetPackages) { isTargetPackage |= className.startsWith(pkgName); } if (isTargetPackage) { logger.fine("[loaded] " + className + " from CoberturaClassLoader"); return defineClass(className, resolve); } else { return getParent().loadClass(className); } } private Class defineClass(String className, boolean resolve) throws ClassNotFoundException { Class clazz = null; String path = className.replace('.', '/') + ".class"; InputStream is = getParent().getResourceAsStream(path); byte[] instrumentationResult = null; try { instrumentationResult = instrumenter.instrumentClassByte(is); if (instrumentationResult == null) { return getParent().loadClass(className); } } catch(Throwable t) { throw new ClassNotFoundException(className + " from " + getParent(), t); } finally { IOUtil.closeInputStream(is); } if (is != null) { clazz = defineClass(className, instrumentationResult); if (resolve) { resolveClass(clazz); } } return clazz; } Class defineClass(String className, byte[] bytes) { return defineClass(className, bytes, 0, bytes.length); } public Instrumenter getInstrumenter() { return instrumenter; } public void setTargetPackages(Set<String> targetPackages) { this.targetPackages = targetPackages; } }