Skip to content

Instantly share code, notes, and snippets.

@nithril
Last active August 29, 2015 13:56
Show Gist options
  • Save nithril/8926105 to your computer and use it in GitHub Desktop.
Save nithril/8926105 to your computer and use it in GitHub Desktop.
Detect new class file
package org.springsource.loaded.agent;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.Date;
import java.util.HashSet;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springsource.loaded.ChildClassLoader;
import org.springsource.loaded.ReloadException;
/**
* Created by nigajuan on 10/02/14.
*/
public class MyWatcher implements Runnable {
private static final Logger log = LoggerFactory.getLogger(MyWatcher.class);
private static final long SLEEP = 1000l;
private volatile boolean stop = false;
private Path basePath;
private HashSet<String> loadedFiles = new HashSet<>();
public MyWatcher() throws URISyntaxException {
basePath = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).toPath();
}
public MyWatcher(Path basePath) {
this.basePath = basePath;
}
@Override
public void run() {
try {
Files.walkFileTree(basePath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
loadedFiles.add(file.toString());
return FileVisitResult.CONTINUE;
}
});
while (!stop) {
Thread.sleep(SLEEP);
Files.walkFileTree(basePath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
testClass(file, attrs);
return FileVisitResult.CONTINUE;
}
});
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
private void loadClass(Path file, BasicFileAttributes attrs) throws IOException {
String fullPath = file.toString();
if (fullPath.endsWith(".class")) {
if (!loadedFiles.contains(fullPath)) {
try {
String dotted = basePath.relativize(file).toString().replaceAll("[\\\\/]", ".").replace(".class", "");
//Load class into the classloader
defineClass2(dotted, FileUtils.readFileToByteArray(file.toFile()));
//Force reload to trigger the event
Files.setLastModifiedTime(file, FileTime.fromMillis(new Date().getTime()));
} catch (Exception e) {
log.error(e.getMessage(), e);
}
loadedFiles.add(fullPath);
}
}
}
//From TypeRegistry
private Method findClassMethod = null;
Class<?> defineClass2(String name, byte[] bytes) {
Class<?> clazz;
try {
if (findClassMethod == null) {
findClassMethod = ClassLoader.class.getDeclaredMethod("findClass", new Class[]{String.class});
}
findClassMethod.setAccessible(true);
ClassLoader loaderToUse = getClassLoader();
clazz = (Class<?>) findClassMethod.invoke(loaderToUse, new Object[]{name});
} catch (Exception e) {
throw new ReloadException("Problem defining class " + name, e);
}
return clazz;
}
public ClassLoader getClassLoader() {
return getClass().getClassLoader();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment