package org.hotswap.agent.plugin.deltaspike; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; 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.Scheduler; import org.hotswap.agent.javassist.CtClass; import org.hotswap.agent.logging.AgentLogger; import org.hotswap.agent.plugin.deltaspike.jsf.ViewConfigReloadCommand; import org.hotswap.agent.plugin.deltaspike.proxy.PartialBeanClassRefreshCommand; import org.hotswap.agent.util.AnnotationHelper; /** * Apache DeltaSpike * @author Vladimir Dvorak */ @Plugin(name = "Deltaspike", description = "Apache DeltaSpike (http://deltaspike.apache.org/), support repository reloading", testedVersions = {"1.5.2, 1.7.2"}, expectedVersions = {"1.5-1.7"}, supportClass = {DeltaSpikeTransformers.class}) public class DeltaSpikePlugin { private static AgentLogger LOGGER = AgentLogger.getLogger(DeltaSpikePlugin.class); private static final String REPOSITORY_ANNOTATION = "org.apache.deltaspike.data.api.Repository"; private static final int WAIT_ON_REDEFINE = 1000; @Init ClassLoader appClassLoader; @Init Scheduler scheduler; Map<Object, String> registeredRepoComponents = new WeakHashMap<Object, String>(); Map<Object, String> registeredPartialBeans = new WeakHashMap<Object, String>(); Map<Object, List<String>> registeredViewConfExtRootClasses = new WeakHashMap<Object, List<String>>(); public void registerRepoComponent(Object repoComponent, Class<?> repositoryClass) { if (!registeredRepoComponents.containsKey(repoComponent)) { LOGGER.debug("DeltaspikePlugin - Repository Component registered : {}", repositoryClass.getName()); } registeredRepoComponents.put(repoComponent, repositoryClass.getName()); } public void registerPartialBean(Object bean, Class<?> partialBeanClass) { synchronized(registeredPartialBeans) { registeredPartialBeans.put(bean, partialBeanClass.getName()); } LOGGER.debug("Registering partial bean : {}", partialBeanClass.getName()); } @OnClassLoadEvent(classNameRegexp = ".*", events = LoadEvent.REDEFINE) public void classReload(CtClass clazz, Class original) { checkRefreshPartialBean(clazz, original); checkRefreshViewConfigExtension(clazz, original); } private void checkRefreshPartialBean(CtClass clazz, Class original) { Object partialBean = getObjectByName(registeredPartialBeans, clazz.getName()); if (partialBean != null) { PartialBeanClassRefreshCommand cmd = new PartialBeanClassRefreshCommand(appClassLoader, partialBean, clazz.getName()); if (AnnotationHelper.hasAnnotation(clazz, REPOSITORY_ANNOTATION)) { Object repositoryComponent = getObjectByName(registeredRepoComponents, clazz.getName()); if (repositoryComponent != null) { cmd.setRepositoryComponent(repositoryComponent); } } scheduler.scheduleCommand(cmd, WAIT_ON_REDEFINE); } } private Object getObjectByName(Map<Object, String> registeredComponents, String className) { for (Entry<Object, String> entry : registeredComponents.entrySet()) { if (className.equals(entry.getValue())) { return entry.getKey(); } } return null; } private void checkRefreshViewConfigExtension(CtClass clazz, Class original) { String className = original.getName(); int index = className.indexOf("$"); String rootClassName = (index!=-1) ? className.substring(0, index) : className; for (Entry<Object, List<String>> entry: registeredViewConfExtRootClasses.entrySet()) { List<String> rootClassNameList = entry.getValue(); for (String viewConfigClassName: rootClassNameList) { if (viewConfigClassName.equals(rootClassName)) { scheduler.scheduleCommand(new ViewConfigReloadCommand(appClassLoader, entry.getKey(), entry.getValue()), WAIT_ON_REDEFINE); return; } } } } public void registerViewConfigRootClasses(Object viewConfigExtension, List rootClassList) { if (rootClassList != null ) { List<String> rootClassNameList = new ArrayList<String>(); for (Object viewConfigClassObj : rootClassList) { Class<?> viewConfigClass = (Class<?>) viewConfigClassObj; LOGGER.debug("Registering ViewConfigRoot class : {}", viewConfigClass.getName()); rootClassNameList.add(viewConfigClass.getName()); } registeredViewConfExtRootClasses.put(viewConfigExtension, rootClassNameList); } } }