Last active
August 29, 2015 13:56
-
-
Save nithril/8926105 to your computer and use it in GitHub Desktop.
Detect new class file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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