wps/src/main/java/org/gcube/data/analysis/wps/repository/AlgorithmUpdater.java

130 lines
3.3 KiB
Java

package org.gcube.data.analysis.wps.repository;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class AlgorithmUpdater {
private static final Logger log = LoggerFactory.getLogger(AlgorithmUpdater.class);
private String algorithmDirectory;
private boolean mustUpdate = false;
private WatcherThread watcherThread = null;
public AlgorithmUpdater(String algorithmDirectory) {
super();
this.algorithmDirectory = algorithmDirectory;
}
protected synchronized boolean mustUpdate(){
return mustUpdate;
}
protected synchronized void reset(){
mustUpdate = false;
}
public boolean isStarted(){
return watcherThread!=null;
}
protected void startWhatcher(){
watcherThread = new WatcherThread(Thread.currentThread().getContextClassLoader(), algorithmDirectory);
watcherThread.start();
}
private class WatcherThread extends Thread {
private WatchService watcher;
private ClassLoader loader;
private Path dir;
public WatcherThread(ClassLoader loader, String algorithmDirectory) {
super();
try {
watcher = FileSystems.getDefault().newWatchService();
this.loader = loader;
//TODO: change with something from configuration
dir = Paths.get(algorithmDirectory);
dir.register(watcher, ENTRY_CREATE);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public void run(){
for (;;) {
// wait for key to be signaled
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException x) {
return;
}
for (WatchEvent<?> event: key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
// This key is registered only
// for ENTRY_CREATE events,
// but an OVERFLOW event can
// occur regardless if events
// are lost or discarded.
if (kind == OVERFLOW) {
continue;
}
// The filename is the
// context of the event.
WatchEvent<Path> ev = (WatchEvent<Path>)event;
Path filename = ev.context();
if (filename.toString().endsWith(".jar")){
try{
final Class<URLClassLoader> sysclass = URLClassLoader.class;
// TODO some kind of a hack. Need to invent better solution.
final Method method = sysclass.getDeclaredMethod("addURL", new Class[] { URL.class });
method.setAccessible(true);
method.invoke(loader, new URL[] { dir.resolve(filename).toFile().toURI().toURL() });
log.info("filename added is {} in loader {}",filename, loader.getClass().getName());
mustUpdate = true;
}catch(Exception e){
log.error("filename {} cannot be added to classpath",e,filename);
}
} else log.info("filename {} is not a jar",filename);
}
boolean valid = key.reset();
if (!valid) {
break;
}
}
}
}
protected void shutdown(){
if (isStarted()){
//TODO : kill the watcherThread
watcherThread = null;
}
}
}