use of org.fakereplace.replacement.AddedClass in project fakereplace by fakereplace.
the class WildflyAutoUpdate method runUpdate.
public static synchronized Result runUpdate(ModuleClassLoader classLoader) {
String moduleName = classLoader.getModule().getIdentifier().getName();
if (moduleName.startsWith(DEPLOYMENT)) {
moduleName = moduleName.substring(DEPLOYMENT.length());
}
String sourcePaths = System.getProperty(FAKEREPLACE_SOURCE_PATHS + moduleName);
if (sourcePaths == null) {
return Result.NO_CHANGE;
}
List<Path> paths = Arrays.stream(sourcePaths.split(",")).map((s) -> Paths.get(s)).collect(Collectors.toList());
try {
for (Path base : paths) {
final Map<String, Long> timestamps = new HashMap<>();
scan(base, base, timestamps);
List<String> toUpdate = new ArrayList<>();
List<String> added = new ArrayList<>();
List<String> replace = new ArrayList<>();
for (Map.Entry<String, Long> entry : timestamps.entrySet()) {
String name = entry.getKey();
if (name.endsWith(".java")) {
String baseName = name.substring(0, name.length() - 5);
Long last = replacedTimestamps.get(baseName);
if (last != null) {
if (last < entry.getValue()) {
toUpdate.add(baseName);
replacedTimestamps.put(baseName, entry.getValue());
replace.add(baseName);
}
} else {
URL res = classLoader.getResource(baseName + ".class");
if (res != null) {
URLConnection con = res.openConnection();
long lm = con.getLastModified();
if (lm < entry.getValue()) {
toUpdate.add(baseName);
replacedTimestamps.put(baseName, entry.getValue());
replace.add(baseName);
}
} else {
toUpdate.add(baseName);
replacedTimestamps.put(baseName, entry.getValue());
added.add(baseName);
}
}
}
}
if (!toUpdate.isEmpty()) {
System.out.println("Fakereplace detected the following source files have been changed: " + toUpdate);
ClassLoaderCompiler compiler = new ClassLoaderCompiler(classLoader, base, toUpdate);
compiler.compile();
Map<String, byte[]> byteMap = REPLACED_CLASSES.computeIfAbsent(classLoader, k -> new HashMap<>());
AddedClass[] addedClass = new AddedClass[added.size()];
for (int i = 0; i < added.size(); ++i) {
String className = added.get(i);
addedClass[i] = new AddedClass(className, compiler.getOutput().get(className).toByteArray(), classLoader);
byteMap.put(className, compiler.getOutput().get(className).toByteArray());
}
ClassDefinition[] classDefinition = new ClassDefinition[replace.size()];
for (int i = 0; i < replace.size(); ++i) {
String className = replace.get(i);
classDefinition[i] = new ClassDefinition(classLoader.loadClass(className.replace("/", ".")), compiler.getOutput().get(className).toByteArray());
byteMap.put(className, compiler.getOutput().get(className).toByteArray());
}
try {
Fakereplace.redefine(classDefinition, addedClass);
} catch (Exception e) {
System.err.println("Hot replace failed, redeploy required" + e.getMessage());
return Result.REDEPLOY_REQUIRED;
}
return Result.RELOAD;
}
}
return Result.NO_CHANGE;
} catch (Exception e) {
System.err.println("Check for updated classes failed");
e.printStackTrace();
} finally {
// something in the compiler clears the TCCL, fix it up
Thread.currentThread().setContextClassLoader(classLoader);
}
return Result.NO_CHANGE;
}
use of org.fakereplace.replacement.AddedClass in project fakereplace by fakereplace.
the class ClassReplacer method replaceQueuedClasses.
public void replaceQueuedClasses(boolean useFakereplace) {
try {
ClassDefinition[] definitions = new ClassDefinition[queuedClassReplacements.size()];
AddedClass[] newClasses = new AddedClass[addedClasses.size()];
for (Class<?> o : queuedClassReplacements.keySet()) {
Class<?> n = queuedClassReplacements.get(o);
String newName = o.getName();
String oldName = n.getName();
nameReplacements.put(oldName, newName);
}
for (Entry<Class<?>, String> o : addedClasses.entrySet()) {
nameReplacements.put(o.getKey().getName(), o.getValue());
}
int count = 0;
for (Class<?> o : queuedClassReplacements.keySet()) {
Class<?> n = queuedClassReplacements.get(o);
CtClass nc = pool.get(n.getName());
if (nc.isFrozen()) {
nc.defrost();
}
for (String oldName : nameReplacements.keySet()) {
String newName = nameReplacements.get(oldName);
nc.replaceClassName(oldName, newName);
}
nc.setName(o.getName());
ClassDefinition cd = new ClassDefinition(o, nc.toBytecode());
definitions[count++] = cd;
}
count = 0;
for (Entry<Class<?>, String> o : addedClasses.entrySet()) {
CtClass nc = pool.get(o.getKey().getName());
if (nc.isFrozen()) {
nc.defrost();
}
for (String newName : nameReplacements.keySet()) {
String oldName = nameReplacements.get(newName);
nc.replaceClassName(newName, oldName);
}
AddedClass ncd = new AddedClass(o.getValue(), nc.toBytecode(), o.getKey().getClassLoader());
newClasses[count++] = ncd;
}
if (useFakereplace) {
Fakereplace.redefine(definitions, newClasses);
} else {
Fakereplace.getInstrumentation().redefineClasses(definitions);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
use of org.fakereplace.replacement.AddedClass in project fakereplace by fakereplace.
the class FakeReplaceServlet method doPost.
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
ObjectInputStream in = new ObjectInputStream(req.getInputStream());
String deployment = in.readUTF();
ServiceController<DeploymentUnit> deploymentService = deploymentService(deployment);
Module module = deploymentService.getValue().getAttachment(Attachments.MODULE);
int size = in.readInt();
ClassDefinition[] definitions = new ClassDefinition[size];
for (int i = 0; i < size; ++i) {
String className = in.readUTF();
byte[] data = (byte[]) in.readObject();
Class clazz = module.getClassLoader().loadClass(className);
ClassDefinition d = new ClassDefinition(clazz, data);
definitions[i] = d;
}
size = in.readInt();
AddedClass[] added = new AddedClass[size];
for (int i = 0; i < size; ++i) {
String className = in.readUTF();
byte[] data = (byte[]) in.readObject();
added[i] = new AddedClass(className, data, module.getClassLoader());
}
size = in.readInt();
Map<String, byte[]> resources = new HashMap<>();
for (int i = 0; i < size; ++i) {
String resourceName = in.readUTF();
byte[] data = (byte[]) in.readObject();
resources.put(resourceName, data);
}
updateResource(resources, deploymentService);
Fakereplace.redefine(definitions, added);
} catch (ClassNotFoundException e) {
throw new ServletException(e);
}
}
use of org.fakereplace.replacement.AddedClass in project fakereplace by fakereplace.
the class Fakereplace method redefine.
public static void redefine(ClassDefinition[] classes, AddedClass[] addedData, boolean wait) {
try {
for (AddedClass i : addedData) {
ClassFile cf = new ClassFile(new DataInputStream(new ByteArrayInputStream(i.getData())));
mainTransformer.addNewClass(new NewClassData(i.getClassName(), i.getLoader(), cf));
}
for (ClassDefinition i : classes) {
ClassDataStore.instance().markClassReplaced(i.getDefinitionClass());
BaseClassData baseClassData = ClassDataStore.instance().getBaseClassData(i.getDefinitionClass().getClassLoader(), i.getDefinitionClass().getName());
if (baseClassData != null) {
ClassDataStore.instance().saveClassData(i.getDefinitionClass().getClassLoader(), i.getDefinitionClass().getName(), new ClassDataBuilder(baseClassData));
}
}
for (AddedClass c : addedData) {
ClassLookupManager.addClassInfo(c.getClassName(), c.getLoader(), c.getData());
}
inst.redefineClasses(classes);
clearJvmCaches();
if (wait) {
mainTransformer.waitForTasks();
}
} catch (Throwable e) {
try {
// dump the classes to /tmp so we can look at them
for (ClassDefinition d : classes) {
try {
ByteArrayInputStream bin = new ByteArrayInputStream(d.getDefinitionClassFile());
DataInputStream dis = new DataInputStream(bin);
final ClassFile file = new ClassFile(dis);
Transformer.getManipulator().transformClass(file, d.getDefinitionClass().getClassLoader(), true, new HashSet<>());
String dumpDir = AgentOptions.getOption(AgentOption.DUMP_DIR);
if (dumpDir != null) {
FileOutputStream s = new FileOutputStream(dumpDir + '/' + d.getDefinitionClass().getName() + "1.class");
DataOutputStream dos = new DataOutputStream(s);
file.write(dos);
dos.flush();
dos.close();
// s.write(d.getDefinitionClassFile());
s.close();
}
} catch (IOException a) {
a.printStackTrace();
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
throw (new RuntimeException(e));
}
}
use of org.fakereplace.replacement.AddedClass in project fakereplace by fakereplace.
the class ClassReplacer method replaceQueuedClasses.
public void replaceQueuedClasses(boolean useFakereplace) {
try {
ClassDefinition[] definitions = new ClassDefinition[queuedClassReplacements.size()];
AddedClass[] newClasses = new AddedClass[addedClasses.size()];
for (Class<?> o : queuedClassReplacements.keySet()) {
Class<?> n = queuedClassReplacements.get(o);
String newName = o.getName();
String oldName = n.getName();
nameReplacements.put(oldName, newName);
}
for (Entry<Class<?>, String> o : addedClasses.entrySet()) {
nameReplacements.put(o.getKey().getName(), o.getValue());
}
int count = 0;
for (Class<?> o : queuedClassReplacements.keySet()) {
Class<?> n = queuedClassReplacements.get(o);
CtClass nc = pool.get(n.getName());
if (nc.isFrozen()) {
nc.defrost();
}
for (String oldName : nameReplacements.keySet()) {
String newName = nameReplacements.get(oldName);
nc.replaceClassName(oldName, newName);
}
nc.setName(o.getName());
ClassDefinition cd = new ClassDefinition(o, nc.toBytecode());
definitions[count++] = cd;
}
count = 0;
for (Entry<Class<?>, String> o : addedClasses.entrySet()) {
CtClass nc = pool.get(o.getKey().getName());
if (nc.isFrozen()) {
nc.defrost();
}
for (String newName : nameReplacements.keySet()) {
String oldName = nameReplacements.get(newName);
nc.replaceClassName(newName, oldName);
}
AddedClass ncd = new AddedClass(o.getValue(), nc.toBytecode(), o.getKey().getClassLoader());
newClasses[count++] = ncd;
}
if (useFakereplace) {
Fakereplace.redefine(definitions, newClasses);
} else {
Fakereplace.getInstrumentation().redefineClasses(definitions);
}
queuedClassReplacements.clear();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Aggregations