package org.hotswap.agent.plugin.owb.command;
import java.util.HashMap;
import java.util.Map;
import org.apache.webbeans.proxy.AbstractProxyFactory;
import org.hotswap.agent.config.PluginManager;
import org.hotswap.agent.logging.AgentLogger;
import org.hotswap.agent.util.ReflectionHelper;
/**
* The OWB proxyFactory has its class loading tasks delegated to this class, which can then have some magic applied
* to make OWB think that the class has not been loaded yet.
*
* @author Vladimir Dvorak
*/
public class ProxyClassLoadingDelegate {
private static AgentLogger LOGGER = AgentLogger.getLogger(ProxyClassLoadingDelegate.class);
private static final ThreadLocal<Boolean> MAGIC_IN_PROGRESS = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return false;
}
};
public static final void beginProxyRegeneration() {
MAGIC_IN_PROGRESS.set(true);
}
public static final void endProxyRegeneration() {
MAGIC_IN_PROGRESS.remove();
}
public static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException {
if (MAGIC_IN_PROGRESS.get()) {
throw new ClassNotFoundException("HotswapAgent");
}
return Class.forName(name, initialize, loader);
}
public static Class defineAndLoadClass(AbstractProxyFactory proxyFactory, ClassLoader classLoader, String proxyName, byte[] proxyBytes) {
if (MAGIC_IN_PROGRESS.get()) {
try {
final Class<?> originalProxyClass = classLoader.loadClass(proxyName);
try {
Map<Class<?>, byte[]> reloadMap = new HashMap<Class<?>, byte[]>();
reloadMap.put(originalProxyClass, proxyBytes);
// TODO : is this standard way how to reload class?
PluginManager.getInstance().hotswap(reloadMap);
return originalProxyClass;
} catch (Exception e) {
throw new RuntimeException(e);
}
} catch (ClassNotFoundException e) {
//it has not actually been loaded yet
}
}
try {
return (Class<?>) ReflectionHelper.invoke(proxyFactory, AbstractProxyFactory.class, "defineAndLoadClass",
new Class[]{ClassLoader.class, String.class, byte[].class},
classLoader, proxyName, proxyBytes);
} catch (Exception e) {
LOGGER.error("defineAndLoadClass() exception {}", e.getMessage());
}
return null;
}
}