package org.hotswap.agent.plugin.deltaspike;
import org.hotswap.agent.annotation.OnClassLoadEvent;
import org.hotswap.agent.config.PluginManager;
import org.hotswap.agent.javassist.CannotCompileException;
import org.hotswap.agent.javassist.ClassPool;
import org.hotswap.agent.javassist.CtClass;
import org.hotswap.agent.javassist.CtConstructor;
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.javassist.expr.ExprEditor;
import org.hotswap.agent.javassist.expr.MethodCall;
import org.hotswap.agent.javassist.expr.NewExpr;
import org.hotswap.agent.logging.AgentLogger;
import org.hotswap.agent.util.PluginManagerInvoker;
/**
* Hook PartialBeanBindingExtension to register DeltaSpikePlugin
* Hook into DeltaSpikeProxyFactory generator to register proxy factory into DeltaSpikePlugin.
*
* @author Vladimir Dvorak
*/
public class DeltaSpikeTransformers {
private static final String VIEW_CONFIG_RESOLVER_PROXY_FLD_NAME = "__viewConfigResolverProxy";
private static AgentLogger LOGGER = AgentLogger.getLogger(DeltaSpikeTransformers.class);
/**
* Patch partial bean binding extension.
*
* @param ctClass the ct class
* @throws NotFoundException the not found exception
* @throws CannotCompileException the cannot compile exception
*/
@OnClassLoadEvent(classNameRegexp = "org.apache.deltaspike.partialbean.impl.PartialBeanBindingExtension")
public static void patchPartialBeanBindingExtension(CtClass ctClass) throws NotFoundException, CannotCompileException {
CtMethod init = ctClass.getDeclaredMethod("init");
init.insertAfter(PluginManagerInvoker.buildInitializePlugin(DeltaSpikePlugin.class));
LOGGER.debug("org.apache.deltaspike.partialbean.impl.PartialBeanBindingExtension enhanced with plugin initialization.");
CtMethod createPartialBeanMethod = ctClass.getDeclaredMethod("createPartialBean");
createPartialBeanMethod.insertAfter(
"if (" + PluginManager.class.getName() + ".getInstance().isPluginInitialized(\"" + DeltaSpikePlugin.class.getName() + "\", beanClass.getClassLoader())) {" +
PluginManagerInvoker.buildCallPluginMethod(DeltaSpikePlugin.class, "registerPartialBean",
"$_", "java.lang.Object",
"beanClass", "java.lang.Class"
) +
"}" +
"return $_;"
);
}
/**
* Delegates ClassUtils.tryToLoadClassForName to org.hotswap.agent.plugin.deltaspike.proxy.ProxyClassLoadingDelegate::tryToLoadClassForName
*
* @param ctClass the ct class
* @throws NotFoundException the not found exception
* @throws CannotCompileException the cannot compile exception
*/
@OnClassLoadEvent(classNameRegexp = "org.apache.deltaspike.proxy.api.DeltaSpikeProxyFactory")
public static void patchDeltaSpikeProxyFactory(CtClass ctClass) throws NotFoundException, CannotCompileException {
// Deltaspike 1.5
instrumentTryToLoadClassForName(ctClass, "getProxyClass");
instrumentTryToLoadClassForName(ctClass, "createProxyClass");
// Deltaspike 1.7
instrumentTryToLoadClassForName(ctClass, "resolveAlreadyDefinedProxyClass");
}
private static void instrumentTryToLoadClassForName(CtClass ctClass, String methodName) throws CannotCompileException {
try {
CtMethod getProxyClassMethod = ctClass.getDeclaredMethod(methodName);
getProxyClassMethod.instrument(
new ExprEditor() {
public void edit(MethodCall m) throws CannotCompileException {
if (m.getClassName().equals("org.apache.deltaspike.core.util.ClassUtils") && m.getMethodName().equals("tryToLoadClassForName"))
m.replace("{ $_ = org.hotswap.agent.plugin.deltaspike.proxy.ProxyClassLoadingDelegate.tryToLoadClassForName($$); }");
}
});
} catch (NotFoundException e) {
LOGGER.debug("Method {} not found in {}.", methodName, ctClass.getName());
}
}
/**
* Delegates loadClass to org.hotswap.agent.plugin.deltaspike.proxy.ProxyClassLoadingDelegate::loadClass
*
* @param ctClass the ct class
* @throws NotFoundException the not found exception
* @throws CannotCompileException the cannot compile exception
*/
@OnClassLoadEvent(classNameRegexp = "org.apache.deltaspike.proxy.impl.AsmProxyClassGenerator")
public static void patchAsmProxyClassGenerator(CtClass ctClass) throws NotFoundException, CannotCompileException {
CtMethod generateProxyClassMethod = ctClass.getDeclaredMethod("generateProxyClass");
generateProxyClassMethod.instrument(
new ExprEditor() {
public void edit(MethodCall m) throws CannotCompileException {
if (m.getClassName().equals("org.apache.deltaspike.proxy.impl.AsmProxyClassGenerator") && m.getMethodName().equals("loadClass"))
m.replace("{ $_ = org.hotswap.agent.plugin.deltaspike.proxy.ProxyClassLoadingDelegate.loadClass($$); }");
}
});
}
@OnClassLoadEvent(classNameRegexp = "org.apache.deltaspike.data.impl.meta.RepositoryComponent")
public static void patchRepositoryComponent(CtClass ctClass) throws CannotCompileException {
StringBuilder src = new StringBuilder("{");
src.append(PluginManagerInvoker.buildInitializePlugin(DeltaSpikePlugin.class));
src.append(PluginManagerInvoker.buildCallPluginMethod(DeltaSpikePlugin.class, "registerRepoComponent",
"this", "java.lang.Object",
"this.repoClass", "java.lang.Class"));
src.append("}");
for (CtConstructor constructor : ctClass.getDeclaredConstructors()) {
constructor.insertAfter(src.toString());
}
ctClass.addMethod(CtNewMethod.make("public void __reinitialize() {" +
" this.methods.clear(); " +
" initialize();" +
"}", ctClass));
LOGGER.debug("org.apache.deltaspike.data.impl.meta.RepositoryComponent - added registering hook + method __reinitialize().");
}
@OnClassLoadEvent(classNameRegexp = "org.apache.deltaspike.jsf.impl.config.view.ViewConfigExtension")
public static void patchViewConfigExtension(CtClass ctClass, ClassPool classPool) throws CannotCompileException, NotFoundException {
CtMethod init = ctClass.getDeclaredMethod("init");
StringBuilder src = new StringBuilder("{");
src.append(" if (this.isActivated) {");
src.append( PluginManagerInvoker.buildInitializePlugin(DeltaSpikePlugin.class));
src.append(" }");
src.append("}");
init.insertAfter(src.toString());
LOGGER.debug("org.apache.deltaspike.jsf.impl.config.view.ViewConfigExtension enhanced with plugin initialization.");
CtClass viewConfigResProxyClass = classPool.get("org.hotswap.agent.plugin.deltaspike.jsf.ViewConfigResolverProxy");
CtField viewConfigResProxyField = new CtField(viewConfigResProxyClass, VIEW_CONFIG_RESOLVER_PROXY_FLD_NAME, ctClass);
ctClass.addField(viewConfigResProxyField);
CtMethod generateProxyClassMethod = ctClass.getDeclaredMethod("transformMetaDataTree");
generateProxyClassMethod.instrument(
new ExprEditor() {
public void edit(NewExpr e) throws CannotCompileException {
if (e.getClassName().equals("org.apache.deltaspike.jsf.impl.config.view.DefaultViewConfigResolver"))
e.replace("{ " +
" java.lang.Object _resolver = new org.apache.deltaspike.jsf.impl.config.view.DefaultViewConfigResolver($$); " +
" if (this." + VIEW_CONFIG_RESOLVER_PROXY_FLD_NAME + "==null) {" +
" this." + VIEW_CONFIG_RESOLVER_PROXY_FLD_NAME + "=new org.hotswap.agent.plugin.deltaspike.jsf.ViewConfigResolverProxy();" +
" }" +
" this." + VIEW_CONFIG_RESOLVER_PROXY_FLD_NAME + ".setViewConfigResolver(_resolver);" +
" java.util.List _list = org.hotswap.agent.plugin.deltaspike.jsf.ViewConfigResolverUtils.findViewConfigRootClasses(this.rootViewConfigNode);" +
PluginManagerInvoker.buildCallPluginMethod(DeltaSpikePlugin.class, "registerViewConfigRootClasses",
"this", "java.lang.Object", "_list", "java.util.List") +
" $_ = this." + VIEW_CONFIG_RESOLVER_PROXY_FLD_NAME + ";" +
"}");
}
});
}
}