package com.jsonde.instrumentation.classloader; import com.jsonde.instrumentation.ByteCodeTransformException; import com.jsonde.instrumentation.ByteCodeTransformer; import com.jsonde.util.ClassUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; public class JSondeClassLoader extends ClassLoader { @Override protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { Class clazz; try { clazz = findClass(name); } catch (ClassNotFoundException e) { e.printStackTrace(); return super.loadClass(name, resolve); } catch (ClassFormatError e) { e.printStackTrace(); return super.loadClass(name, resolve); } if (null == clazz) { return super.loadClass(name, resolve); } else { if (resolve) { resolveClass(clazz); } return clazz; } } @Override protected Class<?> findClass(final String name) throws ClassNotFoundException { if (name.startsWith("java.")) return null; if ((name.startsWith("com.jsonde")) && (!name.startsWith("com.jsonde.instrumentation.samples"))) return null; ClassLoader parentClassLoader = getParentOrSystemClassLoader(); InputStream byteCodeInputStream = null; byte[] transformedByteArray; try { byteCodeInputStream = parentClassLoader.getResourceAsStream( ClassUtils.convertClassNameToResourceName(name)); transformedByteArray = transform(byteCodeInputStream, true); } catch (ByteCodeTransformException e) { throw new ClassNotFoundException("Error while instrumenting class " + name, e); } finally { if (null != byteCodeInputStream) { try { byteCodeInputStream.close(); } catch (IOException e) { e.printStackTrace(); // todo refactor this line } } } return defineClass(name, transformedByteArray, 0, transformedByteArray.length); } private ClassLoader getParentOrSystemClassLoader() { ClassLoader parentClassLoader = getParent(); if (null == parentClassLoader) { return getSystemClassLoader(); } else { return parentClassLoader; } } public byte[] transform(InputStream inputStream, boolean instrumentClass) throws ByteCodeTransformException { ByteArrayOutputStream originalByteArrayOutputStream = new ByteArrayOutputStream(); try { while (inputStream.available() > 0) { originalByteArrayOutputStream.write(inputStream.read()); } ByteCodeTransformer byteCodeTransformer = new ByteCodeTransformer(); return byteCodeTransformer.transform(originalByteArrayOutputStream.toByteArray(), instrumentClass, this, null); } catch (IOException e) { throw new ByteCodeTransformException(e); } finally { try { originalByteArrayOutputStream.close(); } catch (IOException e) { e.printStackTrace(); // todo refactor this line } } } }