package org.hotswap.agent.plugin.seam; import java.lang.reflect.Method; import java.util.Collections; import java.util.Set; import java.util.WeakHashMap; import org.hotswap.agent.annotation.Init; import org.hotswap.agent.annotation.LoadEvent; import org.hotswap.agent.annotation.OnClassLoadEvent; import org.hotswap.agent.annotation.Plugin; import org.hotswap.agent.command.Command; import org.hotswap.agent.command.Scheduler; import org.hotswap.agent.javassist.CannotCompileException; import org.hotswap.agent.javassist.CtClass; import org.hotswap.agent.javassist.CtConstructor; import org.hotswap.agent.javassist.CtMethod; import org.hotswap.agent.javassist.NotFoundException; import org.hotswap.agent.logging.AgentLogger; import org.hotswap.agent.util.PluginManagerInvoker; @Plugin(name = "Seam", description = "Seam framework (http://seamframework.org/). Clears java.beans.Introspector cache and org.jboss.el.util.ReferenceCache on any class redefinition.", testedVersions = {"2.3.1"}, expectedVersions = {"2.2", "2.3"}) public class SeamPlugin { private static AgentLogger LOGGER = AgentLogger.getLogger(SeamPlugin.class); @Init Scheduler scheduler; @Init ClassLoader appClassLoader; Set<Object> registeredJbossReferenceCaches = Collections.newSetFromMap(new WeakHashMap<Object, Boolean>()); @OnClassLoadEvent(classNameRegexp = "org.jboss.seam.init.Initialization") public static void seamServletCallInitialized(CtClass ctClass) throws NotFoundException, CannotCompileException { CtMethod init = ctClass.getDeclaredMethod("init"); init.insertBefore( "{" + PluginManagerInvoker.buildInitializePlugin(SeamPlugin.class) + "}" ); LOGGER.debug("org.jboss.seam.init.Initialization enhanced with plugin initialization."); } public void registerJbossReferenceCache(Object referenceCache) { registeredJbossReferenceCaches.add(referenceCache); LOGGER.debug("SeamPlugin - registerJbossReferenceCache : " + referenceCache.getClass().getName()); } @OnClassLoadEvent(classNameRegexp = "org.jboss.el.util.ReferenceCache") public static void referenceCacheRegisterVariable(CtClass ctClass) throws CannotCompileException { String registerThis = PluginManagerInvoker.buildCallPluginMethod(SeamPlugin.class, "registerJbossReferenceCache", "this", "java.lang.Object"); for (CtConstructor constructor : ctClass.getDeclaredConstructors()) { constructor.insertAfter(registerThis); } } @OnClassLoadEvent(classNameRegexp = ".*", events = LoadEvent.REDEFINE) public void invalidateClassCache() throws Exception { scheduler.scheduleCommand(clearJbossReferenceCache); } private Command clearJbossReferenceCache = new Command() { public void executeCommand() { LOGGER.debug("Refreshing Jboss reference caches."); try { Method clearCacheMethod = resolveClass("org.jboss.el.util.ReferenceCache").getDeclaredMethod("clear"); for (Object referenceCache : registeredJbossReferenceCaches) { clearCacheMethod.invoke(referenceCache); } } catch (Exception e) { LOGGER.error("Error clear in jboss ReferenceCache .", e); } } }; private Class<?> resolveClass(String name) throws ClassNotFoundException { return Class.forName(name, true, appClassLoader); } }