package water.deploy; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.*; import java.util.*; import water.Boot; import water.util.Log; /** * Creates a node in-process using a separate class loader. */ public class NodeCL extends Thread implements Node { private final URL[] _classpath; private final String[] _args; private final Class _main; private ClassLoader _initialClassLoader, _classLoader; public NodeCL(Class main, String[] args) { super("NodeCL"); _args = args; _main = main; _classpath = getClassPath(); _initialClassLoader = Thread.currentThread().getContextClassLoader(); _classLoader = new URLClassLoader(_classpath, null); } @Override public void inheritIO() { // TODO add -id to PID? // invoke(className, methodName, args) } @Override public void persistIO(String outFile, String errFile) throws IOException { // TODO // invoke(className, methodName, args) } @Override public void kill() { // TODO // invoke(className, methodName, args) } static URL[] getClassPath() { String[] classpath = System.getProperty("java.class.path").split(File.pathSeparator); try { final List<URL> list = new ArrayList<URL>(); if( classpath != null ) { for( final String element : classpath ) { list.addAll(getDirectoryClassPath(element)); list.add(new File(element).toURI().toURL()); } } return list.toArray(new URL[list.size()]); } catch( Exception e ) { throw Log.errRTExcept(e); } } @Override public int waitFor() { try { join(); return 0; } catch( InterruptedException e ) { throw Log.errRTExcept(e); } } @Override public void run() { assert Thread.currentThread().getContextClassLoader() == _initialClassLoader; Thread.currentThread().setContextClassLoader(_classLoader); try { Class<?> c = _classLoader.loadClass(Context.class.getName()); Method method = c.getMethod("run", String.class, String[].class); method.setAccessible(true); method.invoke(null, _main.getName(), _args); } catch( Exception e ) { throw Log.errRTExcept(e); } finally { Thread.currentThread().setContextClassLoader(_initialClassLoader); } } private static List<URL> getDirectoryClassPath(String aDir) { try { final List<URL> list = new LinkedList<URL>(); final File dir = new File(aDir); final URL directoryURL = dir.toURI().toURL(); final String[] children = dir.list(); if( children != null ) { for( final String element : children ) { if( element.endsWith(".jar") ) { final URL url = new URL(directoryURL, URLEncoder.encode(element, "UTF-8")); list.add(url); } } } return list; } catch( Exception e ) { throw Log.errRTExcept(e); } } static class Context { public static void run(String main, String[] args) throws Exception { // Boot takes SystemClassLoader as parent, override with ours Field parent = ClassLoader.class.getDeclaredField("parent"); parent.setAccessible(true); parent.set(Boot._init, Thread.currentThread().getContextClassLoader()); Boot.main(Class.forName(main), args); } } }