org.hotswap.agent.plugin.proxy.ReloadJavaProxyCommand Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hotswap-agent-proxy-plugin Show documentation
Show all versions of hotswap-agent-proxy-plugin Show documentation
Java unlimited runtime class and resource redefinition.
/*
* Copyright 2013-2024 the HotswapAgent authors.
*
* This file is part of HotswapAgent.
*
* HotswapAgent is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* HotswapAgent is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with HotswapAgent. If not, see http://www.gnu.org/licenses/.
*/
package org.hotswap.agent.plugin.proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hotswap.agent.command.Command;
import org.hotswap.agent.command.MergeableCommand;
import org.hotswap.agent.config.PluginManager;
import org.hotswap.agent.logging.AgentLogger;
import org.hotswap.agent.plugin.proxy.java.ProxyGenerator;
/**
* Joins subsequent proxy redefinition commands together and guarantee execution order
*/
public class ReloadJavaProxyCommand extends MergeableCommand {
private static AgentLogger LOGGER = AgentLogger.getLogger(ReloadJavaProxyCommand.class);
private ClassLoader classLoader;
private String className;
private Map signatureMapOrig;
public ReloadJavaProxyCommand(ClassLoader classLoader, String className, Map signatureMapOrig) {
this.classLoader = classLoader;
this.className = className;
this.signatureMapOrig = signatureMapOrig;
}
@Override
public void executeCommand() {
try {
executeSingleCommand();
List commands = new ArrayList<>(getMergedCommands());
for (Command command: commands) {
((ReloadJavaProxyCommand) command).executeSingleCommand();
}
} finally {
ProxyPlugin.reloadFlag = false;
}
}
public void executeSingleCommand() {
try {
Class> clazz = classLoader.loadClass(className);
Map signatureMap = ProxyClassSignatureHelper.getNonSyntheticSignatureMap(clazz);
LOGGER.debug("executeSingleCommand class:{}, signature equals:{}", className, signatureMap.equals(signatureMapOrig));
if (!signatureMap.equals(signatureMapOrig) || !isImplementInterface(signatureMap, clazz)) {
byte[] generateProxyClass = ProxyGenerator.generateProxyClass(className, clazz.getInterfaces());
Map, byte[]> reloadMap = new HashMap<>();
reloadMap.put(clazz, generateProxyClass);
PluginManager.getInstance().hotswap(reloadMap);
LOGGER.reload("Class '{}' has been reloaded.", className);
}
} catch (ClassNotFoundException e) {
LOGGER.error("Error redefining java proxy {}", e, className);
}
}
// Whether all methods of the interface are implemented
private boolean isImplementInterface(Map signatureMap, Class> clazz) {
String clazzSignature = "";
try {
clazzSignature = ProxyClassSignatureHelper.getJavaClassSignature(clazz).replaceAll("final ", "");
LOGGER.debug("clazzSignature: {}", clazzSignature);
} catch (Exception e) {
LOGGER.error("Error getJavaClassSignature {}", clazz, e);
return true;
}
for (Map.Entry entry : signatureMap.entrySet()) {
if(clazzSignature.contains(entry.getKey()) && entry.getValue().contains("public abstract")) {
LOGGER.debug("{} Signature: {}", entry.getKey(), entry.getValue());
String[] methodSignatures = entry.getValue().replaceAll("abstract ", "").split(";");
for (String methodSignature : methodSignatures) {
if(!clazzSignature.contains(methodSignature)) {
return false;
}
}
}
}
return true;
}
public boolean shiftScheduleTime() {
return false;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ReloadJavaProxyCommand that = (ReloadJavaProxyCommand) o;
if (!classLoader.equals(that.classLoader)) return false;
return true;
}
@Override
public int hashCode() {
int result = classLoader.hashCode();
return result;
}
@Override
public String toString() {
return "ReloadJavaProxyCommand{" + "classLoader=" + classLoader + '}';
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy