package org.hotswap.agent.plugin.jbossmodules;
import org.hotswap.agent.annotation.OnClassLoadEvent;
import org.hotswap.agent.javassist.CannotCompileException;
import org.hotswap.agent.javassist.ClassPool;
import org.hotswap.agent.javassist.CtClass;
import org.hotswap.agent.javassist.CtField;
import org.hotswap.agent.javassist.CtMethod;
import org.hotswap.agent.javassist.CtNewMethod;
import org.hotswap.agent.javassist.NotFoundException;
import org.hotswap.agent.logging.AgentLogger;
import org.hotswap.agent.util.classloader.HotswapAgentClassLoaderExt;
/**
* ModuleClassLoaderTransformer
*
* @author Vladimir Dvorak
*/
public class ModuleClassLoaderTransformer {
protected static AgentLogger LOGGER = AgentLogger.getLogger(ModuleClassLoaderTransformer.class);
/**
*
* @param ctClass the ct class
* @throws NotFoundException the not found exception
* @throws CannotCompileException the cannot compile exception
*/
@OnClassLoadEvent(classNameRegexp = "org.jboss.modules.ModuleClassLoader")
public static void patchModuleClassLoader(ClassPool classPool, CtClass ctClass) throws CannotCompileException {
try {
CtField pathField = ctClass.getDeclaredField("paths");
CtClass pathsType = pathField.getType();
String pathsGetter = "";
CtClass ctHaClassLoader = classPool.get(HotswapAgentClassLoaderExt.class.getName());
ctClass.addInterface(ctHaClassLoader);
if ("java.util.concurrent.atomic.AtomicReference".equals(pathsType.getName())) {
// version>=1.5
pathsGetter = ".get()";
}
CtClass objectClass = classPool.get(Object.class.getName());
CtField ctField = new CtField(objectClass, "__prepend", ctClass);
ctClass.addField(ctField);
ctClass.addMethod(CtNewMethod.make(
"private void __setupPrepend() {" +
" Class clPaths = Class.forName(\"org.jboss.modules.Paths\", true, this.getClass().getClassLoader());" +
" java.lang.reflect.Method spM = clPaths.getDeclaredMethod(\"__setPrepend\", new Class[] {java.lang.Object.class});" +
" spM.invoke(this.paths" + pathsGetter + ", new java.lang.Object[] { __prepend });"+
"}", ctClass)
);
// Implementation of HotswapAgentClassLoaderExt.setExtraClassPath(...)
ctClass.addMethod(CtNewMethod.make(
"public void setExtraClassPath(java.net.URL[] extraClassPath) {" +
" try {" +
" java.util.List resLoaderList = new java.util.ArrayList();" +
" for (int i=0; i<extraClassPath.length; i++) {" +
" try {" +
" java.net.URL url = extraClassPath[i];" +
" java.io.File root = new java.io.File(url.getPath());" +
" org.jboss.modules.ResourceLoader resourceLoader = org.jboss.modules.ResourceLoaders.createFileResourceLoader(url.getPath(), root);" +
" resLoaderList.add(resourceLoader);" +
" } catch (java.lang.Exception e) {" +
" " + ModuleClassLoaderTransformer.class.getName() + ".logSetExtraClassPathException(e);" +
" }" +
" }" +
" this.__prepend = resLoaderList;" +
" __setupPrepend();" +
" } catch (java.lang.Exception e) {" +
" " + ModuleClassLoaderTransformer.class.getName() + ".logSetExtraClassPathException(e);" +
" }" +
"}", ctClass)
);
CtMethod methRecalculate = ctClass.getDeclaredMethod("recalculate");
methRecalculate.setName("_recalculate");
ctClass.addMethod(CtNewMethod.make(
"boolean recalculate() {" +
" boolean ret = _recalculate();" +
" __setupPrepend();" +
" return ret;" +
"}",
ctClass
));
CtClass ctResLoadClass = classPool.get("org.jboss.modules.ResourceLoaderSpec[]");
CtMethod methResourceLoaders = ctClass.getDeclaredMethod("setResourceLoaders", new CtClass[] { ctResLoadClass });
methResourceLoaders.setBody(
"{" +
" boolean ret = setResourceLoaders((org.jboss.modules.Paths)this.paths" + pathsGetter + ", $1);" +
" __setupPrepend();" +
" return ret;" +
"}"
);
} catch (NotFoundException e) {
LOGGER.warning("Unable to find field \"paths\" in org.jboss.modules.ModuleClassLoader.", e);
}
}
/**
*
* @param classPool the class pool
* @param ctClass the ct class
* @throws NotFoundException the not found exception
* @throws CannotCompileException the cannot compile exception
*/
@OnClassLoadEvent(classNameRegexp = "org.jboss.modules.Paths")
public static void patchModulesPaths(ClassPool classPool, CtClass ctClass) throws NotFoundException, CannotCompileException {
CtClass objectClass = classPool.get(Object.class.getName());
CtField ctField = new CtField(objectClass, "__prepend", ctClass);
ctClass.addField(ctField);
try {
CtMethod methGetAllPaths = ctClass.getDeclaredMethod("getAllPaths");
methGetAllPaths.setBody(
"{" +
" if (this.__prepend != null) {" +
" java.util.Map result = new org.hotswap.agent.plugin.jbossmodules.PrependingMap(this.allPaths, this.__prepend);" +
" return result;" +
" }" +
" return this.allPaths;"+
"}"
);
ctClass.addMethod(CtNewMethod.make(
"public void __setPrepend(java.lang.Object prepend) {" +
" this.__prepend = prepend; " +
"}", ctClass)
);
} catch (NotFoundException e) {
LOGGER.warning("Unable to find method \"getAllPaths()\" in org.jboss.modules.Paths.", e);
}
}
public static void logSetExtraClassPathException(Exception e)
{
LOGGER.warning("patched ModuleClassLoader.setExtraClassPath(URL[]) exception : ", e.getMessage());
}
}