git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-analysis/wps@153272 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
parent
df5b27a4b7
commit
27a8136cdd
|
@ -84,6 +84,15 @@
|
||||||
</context-param>
|
</context-param>
|
||||||
|
|
||||||
<filter>
|
<filter>
|
||||||
|
<filter-name>ClassLoaderFilter</filter-name>
|
||||||
|
<filter-class>org.gcube.data.analysis.wps.filter.ClassLoaderFilter</filter-class>
|
||||||
|
</filter>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
|
||||||
<filter-name>CORS</filter-name>
|
<filter-name>CORS</filter-name>
|
||||||
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
|
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
|
||||||
<init-param>
|
<init-param>
|
||||||
|
@ -112,6 +121,11 @@
|
||||||
<url-pattern>/*</url-pattern>
|
<url-pattern>/*</url-pattern>
|
||||||
</filter-mapping>
|
</filter-mapping>
|
||||||
|
|
||||||
|
<filter-mapping>
|
||||||
|
<filter-name>ClassLoaderFilter</filter-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</filter-mapping>
|
||||||
|
|
||||||
<!-- <filter> <filter-name>authn</filter-name> -->
|
<!-- <filter> <filter-name>authn</filter-name> -->
|
||||||
<!-- display-name>Authentication Chain Filter</display-name -->
|
<!-- display-name>Authentication Chain Filter</display-name -->
|
||||||
<!-- description> Delegates calls to AuthenticationChainFilter that is defined
|
<!-- description> Delegates calls to AuthenticationChainFilter that is defined
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -3,7 +3,7 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.gcube.data-analysis</groupId>
|
<groupId>org.gcube.data-analysis</groupId>
|
||||||
<artifactId>wps</artifactId>
|
<artifactId>wps</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
<name>WPS</name>
|
<name>WPS</name>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.gcube.data.analysis.wps;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -112,7 +113,10 @@ public class GetCapabilitiesBuilder {
|
||||||
LOGGER.debug("Found {} algorithms in scope {} ",algorithmsInScope.size() ,ScopeProvider.instance.get());
|
LOGGER.debug("Found {} algorithms in scope {} ",algorithmsInScope.size() ,ScopeProvider.instance.get());
|
||||||
StringBuffer capabilities = new StringBuffer();
|
StringBuffer capabilities = new StringBuffer();
|
||||||
|
|
||||||
for (String algorithmInScope : algorithmsInScope) {
|
//TO eliminate duplicate coming from IS
|
||||||
|
Set<String> algorithmsSet = new HashSet<String>(algorithmsInScope);
|
||||||
|
|
||||||
|
for (String algorithmInScope : algorithmsSet ) {
|
||||||
String classAlgorithm = allalgorithms.get(algorithmInScope);
|
String classAlgorithm = allalgorithms.get(algorithmInScope);
|
||||||
if (classAlgorithm != null) {
|
if (classAlgorithm != null) {
|
||||||
LOGGER.debug("Approving " + classAlgorithm + " to capabilities ");
|
LOGGER.debug("Approving " + classAlgorithm + " to capabilities ");
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package org.gcube.data.analysis.wps.filter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import org.gcube.data.analysis.wps.repository.GcubeAlgorithmRepository;
|
||||||
|
|
||||||
|
public class ClassLoaderFilter implements Filter{
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response,
|
||||||
|
FilterChain chain) throws IOException, ServletException {
|
||||||
|
Thread.currentThread().setContextClassLoader(GcubeAlgorithmRepository.getUpdater().getLoader());
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,19 +1,23 @@
|
||||||
package org.gcube.data.analysis.wps.repository;
|
package org.gcube.data.analysis.wps.repository;
|
||||||
|
|
||||||
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
|
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
|
||||||
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
|
|
||||||
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
|
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
|
import java.nio.file.DirectoryIteratorException;
|
||||||
|
import java.nio.file.DirectoryStream;
|
||||||
import java.nio.file.FileSystems;
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.WatchEvent;
|
import java.nio.file.WatchEvent;
|
||||||
import java.nio.file.WatchKey;
|
import java.nio.file.WatchKey;
|
||||||
import java.nio.file.WatchService;
|
import java.nio.file.WatchService;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -45,34 +49,53 @@ public final class AlgorithmUpdater {
|
||||||
return watcherThread!=null;
|
return watcherThread!=null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void startWhatcher(){
|
protected void init(){
|
||||||
watcherThread = new WatcherThread(Thread.currentThread().getContextClassLoader(), algorithmDirectory);
|
watcherThread = new WatcherThread(Thread.currentThread().getContextClassLoader(), algorithmDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void startWhatcher(){
|
||||||
watcherThread.start();
|
watcherThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void init(){
|
|
||||||
|
|
||||||
|
public ClassLoader getLoader() {
|
||||||
|
return this.watcherThread.getLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class WatcherThread extends Thread {
|
private class WatcherThread extends Thread {
|
||||||
|
|
||||||
|
/*private Map<String, Long> justCreated = new WeakHashMap<String, Long>();
|
||||||
|
private static final long ENTRY_MAX_TIME = 300000;*/
|
||||||
private WatchService watcher;
|
private WatchService watcher;
|
||||||
private ClassLoader loader;
|
private ClassLoader loader;
|
||||||
|
private ClassLoader parentLoader;
|
||||||
private Path dir;
|
private Path dir;
|
||||||
|
private List<String> installedURLS;
|
||||||
|
|
||||||
public WatcherThread(ClassLoader loader, String algorithmDirectory) {
|
public WatcherThread(ClassLoader parentLoader, String algorithmDirectory) {
|
||||||
super();
|
super();
|
||||||
try {
|
try {
|
||||||
|
log.debug("Watcher Thread created");
|
||||||
watcher = FileSystems.getDefault().newWatchService();
|
watcher = FileSystems.getDefault().newWatchService();
|
||||||
this.loader = loader;
|
this.parentLoader = parentLoader;
|
||||||
//TODO: change with something from configuration
|
log.debug("parent class loader is {}", parentLoader.getClass().getSimpleName());
|
||||||
dir = Paths.get(algorithmDirectory);
|
dir = Paths.get(algorithmDirectory);
|
||||||
dir.register(watcher, ENTRY_CREATE, ENTRY_MODIFY);
|
installedURLS = updateClassLoader();
|
||||||
|
dir.register(watcher, ENTRY_CREATE);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected ClassLoader getLoader() {
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void run(){
|
public void run(){
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -88,7 +111,7 @@ public final class AlgorithmUpdater {
|
||||||
|
|
||||||
for (WatchEvent<?> event: key.pollEvents()) {
|
for (WatchEvent<?> event: key.pollEvents()) {
|
||||||
WatchEvent.Kind<?> kind = event.kind();
|
WatchEvent.Kind<?> kind = event.kind();
|
||||||
log.trace("new event thrown for directory watcher");
|
|
||||||
// This key is registered only
|
// This key is registered only
|
||||||
// for ENTRY_CREATE events,
|
// for ENTRY_CREATE events,
|
||||||
// but an OVERFLOW event can
|
// but an OVERFLOW event can
|
||||||
|
@ -103,20 +126,40 @@ public final class AlgorithmUpdater {
|
||||||
WatchEvent<Path> ev = (WatchEvent<Path>)event;
|
WatchEvent<Path> ev = (WatchEvent<Path>)event;
|
||||||
Path filename = ev.context();
|
Path filename = ev.context();
|
||||||
|
|
||||||
if (filename.toString().endsWith(".jar")){
|
log.trace("new event thrown for directory watcher with filename {} and kind {}", filename, kind);
|
||||||
log.debug("found filename {} ",filename.toString());
|
|
||||||
|
if (filename.toString().endsWith("_interface.jar") ){
|
||||||
try{
|
try{
|
||||||
|
if (installedURLS.contains(filename.getFileName().toString())){
|
||||||
|
log.debug("modifying an already installed algorithm");
|
||||||
|
installedURLS = updateClassLoader();
|
||||||
|
} else {
|
||||||
|
log.debug("installing new algorithm");
|
||||||
final Class<URLClassLoader> sysclass = URLClassLoader.class;
|
final Class<URLClassLoader> sysclass = URLClassLoader.class;
|
||||||
// TODO some kind of a hack. Need to invent better solution.
|
// TODO some kind of a hack. Need to invent better solution.
|
||||||
final Method method = sysclass.getDeclaredMethod("addURL", new Class[] { URL.class });
|
final Method method = sysclass.getDeclaredMethod("addURL", new Class[] { URL.class });
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
method.invoke(loader, new URL[] { dir.resolve(filename).toFile().toURI().toURL() });
|
URL realjarURL = null;
|
||||||
log.info("filename added is {} in loader {}",filename, loader.getClass().getName());
|
URL[] jarURLS ;
|
||||||
|
try{
|
||||||
|
realjarURL = dir.resolve(filename.toString().replaceFirst("_interface", "")).getFileName().toUri().toURL();
|
||||||
|
jarURLS = new URL[] {realjarURL,
|
||||||
|
dir.resolve(filename).toFile().toURI().toURL() };
|
||||||
|
log.debug("found {} ",realjarURL);
|
||||||
|
}catch(Exception ipe){
|
||||||
|
jarURLS = new URL[] {dir.resolve(filename).toFile().toURI().toURL() };
|
||||||
|
log.warn("only {} have been found",filename);
|
||||||
|
}
|
||||||
|
method.invoke(loader, jarURLS );
|
||||||
|
log.info("filename added in loader {}",filename, loader.getClass().getName());
|
||||||
|
installedURLS.add(filename.getFileName().toString());
|
||||||
|
}
|
||||||
mustUpdate = true;
|
mustUpdate = true;
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
log.error("filename {} cannot be added to classpath",e,filename);
|
log.error("filename {} cannot be added to classpath",e,filename);
|
||||||
}
|
}
|
||||||
} else log.info("filename {} is not a jar",filename);
|
|
||||||
|
} else log.info("filename {} is not an algorithm interface",filename);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +169,34 @@ public final class AlgorithmUpdater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> updateClassLoader(){
|
||||||
|
log.debug("getting the stream from directoy {}",dir.getFileName());
|
||||||
|
List<URL> urls = new ArrayList<URL>();
|
||||||
|
List<String> toReturn = new ArrayList<String>(urls.size());
|
||||||
|
|
||||||
|
DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
|
||||||
|
public boolean accept(Path file) throws IOException {
|
||||||
|
return (file.getFileName().toString().endsWith(".jar"));
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter )){
|
||||||
|
for (Path file: stream) {
|
||||||
|
log.debug("loading url {}",file.getFileName());
|
||||||
|
urls.add(file.toUri().toURL());
|
||||||
|
toReturn.add(file.getFileName().toString());
|
||||||
|
}
|
||||||
|
} catch (IOException | DirectoryIteratorException x) {
|
||||||
|
log.error("error reading config dir",x);
|
||||||
|
}
|
||||||
|
this.loader = new URLClassLoader(urls.toArray(new URL[urls.size()]), parentLoader);
|
||||||
|
log.debug("loader object is {}", loader);
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected void shutdown(){
|
protected void shutdown(){
|
||||||
if (isStarted()){
|
if (isStarted()){
|
||||||
|
|
|
@ -29,6 +29,7 @@ public class GcubeAlgorithmRepository implements IAlgorithmRepository {
|
||||||
public GcubeAlgorithmRepository(){
|
public GcubeAlgorithmRepository(){
|
||||||
log.info("gcube algorithm repository started");
|
log.info("gcube algorithm repository started");
|
||||||
if (updater==null) throw new RuntimeException("GcubeAlgorithmRepository cannot be initialized: updater is null");
|
if (updater==null) throw new RuntimeException("GcubeAlgorithmRepository cannot be initialized: updater is null");
|
||||||
|
updater.init();
|
||||||
updateRepository();
|
updateRepository();
|
||||||
updater.startWhatcher();
|
updater.startWhatcher();
|
||||||
}
|
}
|
||||||
|
@ -85,11 +86,12 @@ public class GcubeAlgorithmRepository implements IAlgorithmRepository {
|
||||||
|
|
||||||
private static synchronized void updateRepository(){
|
private static synchronized void updateRepository(){
|
||||||
if (reflection==null || updater.mustUpdate()){
|
if (reflection==null || updater.mustUpdate()){
|
||||||
|
Thread.currentThread().setContextClassLoader(updater.getLoader());
|
||||||
log.info("updating repository ({}) ",updater.mustUpdate());
|
log.info("updating repository ({}) ",updater.mustUpdate());
|
||||||
updater.reset();
|
updater.reset();
|
||||||
ConfigurationBuilder confBuilder = new ConfigurationBuilder()
|
ConfigurationBuilder confBuilder = new ConfigurationBuilder()
|
||||||
.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(PACKAGE_TO_FIND)))
|
.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(PACKAGE_TO_FIND)))
|
||||||
.setUrls(((URLClassLoader)Thread.currentThread().getContextClassLoader()).getURLs());
|
.setUrls(((URLClassLoader)updater.getLoader()).getURLs());
|
||||||
reflection = new Reflections(confBuilder);
|
reflection = new Reflections(confBuilder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,4 +119,7 @@ public class GcubeAlgorithmRepository implements IAlgorithmRepository {
|
||||||
} else return false;
|
} else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AlgorithmUpdater getUpdater(){
|
||||||
|
return updater;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ no. 654119), SoBigData (grant no. 654024);
|
||||||
Version
|
Version
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|
||||||
1.0.0-SNAPSHOT (${maven.build.timestamp})
|
1.0.0-SNAPSHOT (2017-09-19)
|
||||||
|
|
||||||
Please see the file named "changelog.xml" in this directory for the release notes.
|
Please see the file named "changelog.xml" in this directory for the release notes.
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,15 @@
|
||||||
</context-param>
|
</context-param>
|
||||||
|
|
||||||
<filter>
|
<filter>
|
||||||
|
<filter-name>ClassLoaderFilter</filter-name>
|
||||||
|
<filter-class>org.gcube.data.analysis.wps.filter.ClassLoaderFilter</filter-class>
|
||||||
|
</filter>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
|
||||||
<filter-name>CORS</filter-name>
|
<filter-name>CORS</filter-name>
|
||||||
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
|
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
|
||||||
<init-param>
|
<init-param>
|
||||||
|
@ -112,6 +121,11 @@
|
||||||
<url-pattern>/*</url-pattern>
|
<url-pattern>/*</url-pattern>
|
||||||
</filter-mapping>
|
</filter-mapping>
|
||||||
|
|
||||||
|
<filter-mapping>
|
||||||
|
<filter-name>ClassLoaderFilter</filter-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</filter-mapping>
|
||||||
|
|
||||||
<!-- <filter> <filter-name>authn</filter-name> -->
|
<!-- <filter> <filter-name>authn</filter-name> -->
|
||||||
<!-- display-name>Authentication Chain Filter</display-name -->
|
<!-- display-name>Authentication Chain Filter</display-name -->
|
||||||
<!-- description> Delegates calls to AuthenticationChainFilter that is defined
|
<!-- description> Delegates calls to AuthenticationChainFilter that is defined
|
||||||
|
|
Loading…
Reference in New Issue