In order to run a JVM app using compact profile 1, 2 or 3 JRE the Java 
bootstrap code under runjava cannot depend on java.beans.* that is not part of 
any of the compact profiles. More specifically runjava depends on cglib and asm 
java libraries that manipulate bytecode and rely on java.beans*.

Therefore the changes that are part of this commit essentially allow to 
bootstrap a JVM app in one of two modes:
      - old one which provides classloader and JUL log manager isolation 
between potential multiple apps and runjava code and apps that possibly targets 
multi-apps on single JVM in OSv and requires full JRE
      - new one which does NOT provide any classloader and JUL log manager 
isolation and targets single main method apps on JVM in OSv and allows using 
compact profile 1, 2 or 3

    Following changes are part of this commit:

    * Added io.osv.isolated and io.osv.nonisolated packages under java/runjava 
and refactored ContextIsolator to create Jvm, NonIsolatedJvm, 
RunNonIsolatedJvmApp, IsolatedJvm, RunIsolatedJvmApp classes

    * Changed java.cc and makefile to support producing two executable - old 
java.so that can run multiple JVM apps in isolated fashion (class loader, log 
manager, etc) and new java_non_isolated.so that can run single JVM app without 
any isolation of the former one

    * Changed java/jvm/java.cc to print which java class it uses to bootstrap - 
isolated or nonisolated one; fixed Makefile to properly handle building of 
java_non_isolated.so

    * Added java_non_isolated.so to modules/java-tests/usr.manifest

    * Added java_non_isolated test to test.py; modified testing.py to detect 
failure to start *.so

    * Added unit tests to test running non-isolated JVM app to tests-isolates

Fixes #497

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
---
 Makefile                                           |   7 +-
 java/jvm/java.cc                                   |  13 +-
 ... AppThreadTerminatedWithUncaughtException.java} |   6 +-
 .../java/io/osv/{ContextIsolator.java => Jvm.java} | 183 +++------------------
 java/runjava/src/main/java/io/osv/RunJava.java     |  48 ------
 .../src/main/java/io/osv/RunJvmAppHelper.java      |  44 +++++
 .../main/java/io/osv/{ => isolated}/Context.java   |   2 +-
 .../osv/{ => isolated}/ContextFailedException.java |   6 +-
 .../src/main/java/io/osv/isolated/IsolatedJvm.java | 160 ++++++++++++++++++
 .../java/io/osv/{ => isolated}/MultiJarLoader.java |   4 +-
 .../osv/{ => isolated}/OsvSystemClassLoader.java   |   4 +-
 .../java/io/osv/isolated/RunIsolatedJvmApp.java    |  33 ++++
 .../main/java/io/osv/jul/IsolatingLogManager.java  |   6 +-
 .../main/java/io/osv/jul/LogManagerWrapper.java    |   2 +-
 .../java/io/osv/nonisolated/NonIsolatedJvm.java    |  86 ++++++++++
 .../io/osv/nonisolated/RunNonIsolatedJvmApp.java   |  33 ++++
 .../src/main/java/tests/LoggingProcess.java        |   4 +-
 ...Process.java => NonIsolatedLoggingProcess.java} |  10 +-
 .../src/main/java/tests/PropertyReader.java        |   4 +-
 .../src/main/java/tests/PropertySetter.java        |   4 +-
 .../src/main/java/tests/StaticFieldSetter.java     |   4 +-
 ...Tests.java => AllTestsThatTestIsolatedApp.java} |   2 +-
 ...ts.java => AllTestsThatTestNonIsolatedApp.java} |   9 +-
 .../main/java/io/osv/ClassLoaderIsolationTest.java |   5 +-
 .../io/osv/ClassLoaderWithoutIsolationTest.java    |  89 ++++++++++
 .../src/main/java/io/osv/LoggingIsolationTest.java |   4 +-
 .../java/io/osv/LoggingWithoutIsolationTest.java   |  54 ++++++
 .../main/java/io/osv/PropertyIsolationTest.java    |   4 +-
 ...estIsolateLaunching.java => TestLaunching.java} |  23 ++-
 modules/java-tests/usr.manifest                    |   9 +
 scripts/test.py                                    |   6 +-
 scripts/tests/testing.py                           |   1 +
 32 files changed, 615 insertions(+), 254 deletions(-)
 copy java/runjava/src/main/java/io/osv/{ContextFailedException.java => 
AppThreadTerminatedWithUncaughtException.java} (52%)
 rename java/runjava/src/main/java/io/osv/{ContextIsolator.java => Jvm.java} 
(51%)
 delete mode 100644 java/runjava/src/main/java/io/osv/RunJava.java
 create mode 100644 java/runjava/src/main/java/io/osv/RunJvmAppHelper.java
 rename java/runjava/src/main/java/io/osv/{ => isolated}/Context.java (98%)
 rename java/runjava/src/main/java/io/osv/{ => 
isolated}/ContextFailedException.java (62%)
 create mode 100644 java/runjava/src/main/java/io/osv/isolated/IsolatedJvm.java
 rename java/runjava/src/main/java/io/osv/{ => isolated}/MultiJarLoader.java 
(97%)
 rename java/runjava/src/main/java/io/osv/{ => 
isolated}/OsvSystemClassLoader.java (98%)
 create mode 100644 
java/runjava/src/main/java/io/osv/isolated/RunIsolatedJvmApp.java
 create mode 100644 
java/runjava/src/main/java/io/osv/nonisolated/NonIsolatedJvm.java
 create mode 100644 
java/runjava/src/main/java/io/osv/nonisolated/RunNonIsolatedJvmApp.java
 copy java/tests-isolates/src/main/java/tests/{LoggingProcess.java => 
NonIsolatedLoggingProcess.java} (80%)
 copy java/tests/src/main/java/io/osv/{AllTests.java => 
AllTestsThatTestIsolatedApp.java} (91%)
 rename java/tests/src/main/java/io/osv/{AllTests.java => 
AllTestsThatTestNonIsolatedApp.java} (67%)
 create mode 100644 
java/tests/src/main/java/io/osv/ClassLoaderWithoutIsolationTest.java
 create mode 100644 
java/tests/src/main/java/io/osv/LoggingWithoutIsolationTest.java
 rename java/tests/src/main/java/io/osv/{TestIsolateLaunching.java => 
TestLaunching.java} (53%)
 create mode 100644 modules/java-tests/usr.manifest

diff --git a/Makefile b/Makefile
index 650f667..e294a03 100644
--- a/Makefile
+++ b/Makefile
@@ -136,7 +136,8 @@ very-quiet = $(if $V, $1, @$1)
 ifeq ($(arch),aarch64)
 java-targets :=
 else
-java-targets := $(out)/java/jvm/java.so $(out)/java/jni/balloon.so 
$(out)/java/jni/elf-loader.so $(out)/java/jni/networking.so \
+java-targets := $(out)/java/jvm/java.so $(out)/java/jvm/java_non_isolated.so \
+       $(out)/java/jni/balloon.so $(out)/java/jni/elf-loader.so 
$(out)/java/jni/networking.so \
         $(out)/java/jni/stty.so $(out)/java/jni/tracepoint.so 
$(out)/java/jni/power.so $(out)/java/jni/monitor.so
 endif
 
@@ -376,6 +377,10 @@ $(out)/%.o: %.c | generated-headers
        $(makedir)
        $(call quiet, $(CC) $(CFLAGS) -c -o $@ $<, CC $*.c)
 
+$(out)/java/jvm/java_non_isolated.o: java/jvm/java.cc | generated-headers
+       $(makedir)
+       $(call quiet, $(CXX) $(CXXFLAGS) -DRUN_JAVA_NON_ISOLATED -o $@ -c 
java/jvm/java.cc, CXX $<)
+
 $(out)/%.o: %.S
        $(makedir)
        $(call quiet, $(CXX) $(CXXFLAGS) $(ASFLAGS) -c -o $@ $<, AS $*.s)
diff --git a/java/jvm/java.cc b/java/jvm/java.cc
index 8c14462..b00d937 100644
--- a/java/jvm/java.cc
+++ b/java/jvm/java.cc
@@ -30,7 +30,11 @@ extern size_t jvm_heap_size;
 // parameters.
 
 #define JVM_PATH        "/usr/lib/jvm/jre/lib/amd64/server/libjvm.so"
-#define RUNJAVA         "io/osv/RunJava"    // separated by slashes, not dots
+#if defined(RUN_JAVA_NON_ISOLATED)
+#define RUNJAVA         "io/osv/nonisolated/RunNonIsolatedJvmApp"    // 
separated by slashes, not dots
+#else
+#define RUNJAVA         "io/osv/isolated/RunIsolatedJvmApp"    // separated by 
slashes, not dots
+#endif
 
 JavaVMOption mkoption(const char* s)
 {
@@ -96,6 +100,8 @@ static void on_vm_stop(JNIEnv *env, jclass clz) {
 
 static int java_main(int argc, char **argv)
 {
+    std::cout << "java.so: Starting JVM app using: " << RUNJAVA << "\n";
+
     auto prog = elf::get_program();
     // The JVM library remains loaded as long as jvm_so is in scope.
     auto jvm_so = prog->get_library(JVM_PATH);
@@ -108,8 +114,11 @@ static int java_main(int argc, char **argv)
 
     std::vector<JavaVMOption> options;
     options.push_back(mkoption("-Djava.class.path=/dev/null"));
-    
options.push_back(mkoption("-Djava.system.class.loader=io.osv.OsvSystemClassLoader"));
+#if !defined(RUN_JAVA_NON_ISOLATED)
+    std::cout << "java.so: Setting Java system classloader and logging manager 
to the isolated ones" << "\n";
+    
options.push_back(mkoption("-Djava.system.class.loader=io.osv.isolated.OsvSystemClassLoader"));
     
options.push_back(mkoption("-Djava.util.logging.manager=io.osv.jul.IsolatingLogManager"));
+#endif
     options.push_back(mkoption("-Dosv.version=" + osv::version()));
 
     {
diff --git a/java/runjava/src/main/java/io/osv/ContextFailedException.java 
b/java/runjava/src/main/java/io/osv/AppThreadTerminatedWithUncaughtException.java
similarity index 52%
copy from java/runjava/src/main/java/io/osv/ContextFailedException.java
copy to 
java/runjava/src/main/java/io/osv/AppThreadTerminatedWithUncaughtException.java
index 541115e..c4ec729 100644
--- a/java/runjava/src/main/java/io/osv/ContextFailedException.java
+++ 
b/java/runjava/src/main/java/io/osv/AppThreadTerminatedWithUncaughtException.java
@@ -1,13 +1,13 @@
 package io.osv;
 
 /*
- * Copyright (C) 2014 Cloudius Systems, Ltd.
+ * Copyright (C) 2016 Waldemar Kozaczuk
  *
  * This work is open source software, licensed under the terms of the
  * BSD license as described in the LICENSE file in the top-level directory.
  */
-public class ContextFailedException extends Exception {
-    public ContextFailedException(Throwable cause) {
+public class AppThreadTerminatedWithUncaughtException extends Exception {
+    public AppThreadTerminatedWithUncaughtException(Throwable cause) {
         super(cause);
     }
 }
diff --git a/java/runjava/src/main/java/io/osv/ContextIsolator.java 
b/java/runjava/src/main/java/io/osv/Jvm.java
similarity index 51%
rename from java/runjava/src/main/java/io/osv/ContextIsolator.java
rename to java/runjava/src/main/java/io/osv/Jvm.java
index bf4d443..8008174 100644
--- a/java/runjava/src/main/java/io/osv/ContextIsolator.java
+++ b/java/runjava/src/main/java/io/osv/Jvm.java
@@ -1,13 +1,8 @@
 package io.osv;
 
-import io.osv.jul.IsolatingLogManager;
-import net.sf.cglib.proxy.Dispatcher;
-import net.sf.cglib.proxy.Enhancer;
-
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FilePermission;
-import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
@@ -20,138 +15,19 @@ import java.util.List;
 import java.util.Properties;
 import java.util.jar.JarFile;
 import java.util.jar.Manifest;
-import java.util.logging.LogManager;
 import java.util.zip.ZipException;
 
 /*
+ * Copyright (C) 2016 Waldemar Kozaczuk
  * Copyright (C) 2014 Cloudius Systems, Ltd.
  *
  * This work is open source software, licensed under the terms of the
  * BSD license as described in the LICENSE file in the top-level directory.
  */
-public class ContextIsolator {
-    private static final ContextIsolator instance = new ContextIsolator();
-
-    static {
-        verifyLogManagerIsInstalled();
-    }
-
-    private final Context masterContext;
-    private final Properties commonSystemProperties;
-
-    private static void verifyLogManagerIsInstalled() {
-        LogManager manager = LogManager.getLogManager();
-        if (!(manager instanceof IsolatingLogManager)) {
-            throw new AssertionError("For isolation to work logging manager 
must be "
-                    + IsolatingLogManager.class.getName() + " but is: " + 
manager.getClass().getName());
-        }
-    }
-
-    private final InheritableThreadLocal<Context> currentContext = new 
InheritableThreadLocal<Context>() {
-        @Override
-        protected Context initialValue() {
-            return masterContext;
-        }
-    };
-
-    private final ClassLoader parentClassLoaderForIsolates;
-
-    public static ContextIsolator getInstance() {
-        return instance;
-    }
-
-    public ContextIsolator() {
-        ClassLoader originalSystemClassLoader = 
getOsvClassLoader().getParent();
-        commonSystemProperties = copyOf(System.getProperties());
-        masterContext = new Context(originalSystemClassLoader, 
copyOf(commonSystemProperties));
-
-        parentClassLoaderForIsolates = originalSystemClassLoader;
-
-        installSystemPropertiesProxy();
-    }
-
-    private Properties copyOf(Properties properties) {
-        Properties result = new Properties();
-        result.putAll(properties);
-        return result;
-    }
-
-    private static void installSystemPropertiesProxy() {
-        Enhancer enhancer = new Enhancer();
-        enhancer.setSuperclass(Properties.class);
-        enhancer.setCallback(new Dispatcher() {
-            @Override
-            public Object loadObject() throws Exception {
-                return instance.getContext().getProperties();
-            }
-        });
-        Properties contextAwareProperties = (Properties) enhancer.create();
-
-        try {
-            Field props = System.class.getDeclaredField("props");
-            props.setAccessible(true);
-            props.set(System.class, contextAwareProperties);
-        } catch (NoSuchFieldException | IllegalAccessException e) {
-            throw new AssertionError("Unable to override System.props", e);
-        }
-    }
-
-    public Context getContext() {
-        return currentContext.get();
-    }
-
-    private Context run(ClassLoader classLoader, final String classpath, final 
String mainClass,
-                        final String[] args, final Properties properties) {
-        Properties contextProperties = new Properties();
-        contextProperties.putAll(commonSystemProperties);
-        contextProperties.putAll(properties);
-
-        final Context context = new Context(classLoader, contextProperties);
+public abstract class Jvm<T> {
+    public abstract void runSync(String... args) throws Throwable;
 
-        Thread thread = new Thread() {
-            @Override
-            public void run() {
-                currentContext.set(context);
-                context.setProperty("java.class.path", classpath);
-
-                try {
-                    runMain(loadClass(mainClass), args);
-                } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
-                } catch (MainClassNotFoundException e) {
-                    context.setException(e);
-                } catch (Throwable e) {
-                    getUncaughtExceptionHandler().uncaughtException(this, e);
-                }
-            }
-        };
-
-        context.setMainThread(thread);
-        thread.setUncaughtExceptionHandler(new 
Thread.UncaughtExceptionHandler() {
-            @Override
-            public void uncaughtException(Thread t, Throwable e) {
-                context.setException(e);
-            }
-        });
-        thread.setContextClassLoader(classLoader);
-        thread.start();
-        return context;
-    }
-
-    public void runSync(String... args) throws Throwable {
-        Context context = run(args);
-
-        while (true) {
-            try {
-                context.join();
-                return;
-            } catch (InterruptedException e) {
-                context.interrupt();
-            }
-        }
-    }
-
-    public Context run(String... args) throws Throwable {
+    public T run(String... args) throws Throwable {
         Properties properties = new Properties();
 
         ArrayList<String> classpath = new ArrayList<>();
@@ -189,7 +65,7 @@ public class ContextIsolator {
         throw new IllegalArgumentException("No jar or class specified to 
run.");
     }
 
-    private Context runJar(String jarName, String[] args, ArrayList<String> 
classpath, Properties properties) throws Throwable {
+    private T runJar(String jarName, String[] args, ArrayList<String> 
classpath, Properties properties) throws Throwable {
         File jarFile = new File(jarName);
         try {
             JarFile jar = new JarFile(jarFile);
@@ -208,18 +84,23 @@ public class ContextIsolator {
         }
     }
 
-    private Context runClass(String mainClass, String[] args, Iterable<String> 
classpath, Properties properties) throws MalformedURLException {
-        ClassLoader appClassLoader = getClassLoader(classpath, 
parentClassLoaderForIsolates);
+    private T runClass(String mainClass, String[] args, Iterable<String> 
classpath, Properties properties) throws MalformedURLException {
+        ClassLoader appClassLoader = createAppClassLoader(classpath, 
getParentClassLoader());
         return run(appClassLoader, joinClassPath(classpath), mainClass, args, 
properties);
     }
 
-    private static ClassLoader getClassLoader(Iterable<String> classpath, 
ClassLoader parent) throws MalformedURLException {
+    protected abstract T run(ClassLoader classLoader, final String classpath, 
final String mainClass,
+                final String[] args, final Properties properties);
+
+    protected abstract ClassLoader getParentClassLoader();
+
+    private ClassLoader createAppClassLoader(Iterable<String> classpath, 
ClassLoader parent) throws MalformedURLException {
         List<URL> urls = toUrls(classpath);
         URL[] urlArray = urls.toArray(new URL[urls.size()]);
         return new AppClassLoader(urlArray, parent);
     }
 
-    private static List<URL> toUrls(Iterable<String> classpath) throws 
MalformedURLException {
+    private List<URL> toUrls(Iterable<String> classpath) throws 
MalformedURLException {
         ArrayList<URL> urls = new ArrayList<>();
         for (String path : classpath) {
             urls.add(toUrl(path));
@@ -227,7 +108,7 @@ public class ContextIsolator {
         return urls;
     }
 
-    private static void runMain(Class<?> klass, String[] args) throws 
Throwable {
+    protected void runMain(Class<?> klass, String[] args) throws Throwable {
         Method main = klass.getMethod("main", String[].class);
         try {
             main.invoke(null, new Object[]{args});
@@ -236,18 +117,15 @@ public class ContextIsolator {
         }
     }
 
-    private static OsvSystemClassLoader getOsvClassLoader() {
-        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
-        if (!(systemClassLoader instanceof OsvSystemClassLoader)) {
-            throw new AssertionError("System class loader should be an 
instance of "
-                    + OsvSystemClassLoader.class.getName() + " but is "
-                    + systemClassLoader.getClass().getName());
+    protected Class<?> loadClass(String name) throws 
MainClassNotFoundException {
+        try {
+            return 
Thread.currentThread().getContextClassLoader().loadClass(name);
+        } catch (ClassNotFoundException ex) {
+            throw new MainClassNotFoundException(name);
         }
-
-        return (OsvSystemClassLoader) systemClassLoader;
     }
 
-    private static String joinClassPath(Iterable<String> classpath) {
+    private String joinClassPath(Iterable<String> classpath) {
         StringBuilder sb = new StringBuilder();
         boolean first = true;
         for (String path : classpath) {
@@ -260,29 +138,21 @@ public class ContextIsolator {
         return sb.toString();
     }
 
-    private static URL toUrl(String path) throws MalformedURLException {
+    private URL toUrl(String path) throws MalformedURLException {
         return new URL("file:///" + path + (isDirectory(path) ? "/" : ""));
     }
 
-    private static boolean isDirectory(String path) {
+    private boolean isDirectory(String path) {
         return new File(path).isDirectory();
     }
 
-    private static Class<?> loadClass(String name) throws 
MainClassNotFoundException {
-        try {
-            return 
Thread.currentThread().getContextClassLoader().loadClass(name);
-        } catch (ClassNotFoundException ex) {
-            throw new MainClassNotFoundException(name);
-        }
-    }
-
     // Expand classpath, as given in the "-classpath" option, to a list of
     // jars or directories. As in the traditional "java" command-line
     // launcher, components of the class path are separated by ":", and
     // we also support the traditional (but awkward) Java wildcard syntax,
     // where "dir/*" adds to the classpath all jar files in the given
     // directory.
-    private static Iterable<String> expandClassPath(String classpath) {
+    private Iterable<String> expandClassPath(String classpath) {
         ArrayList<String> ret = new ArrayList<>();
         for (String component : classpath.split(":")) {
             if (component.endsWith("/*")) {
@@ -307,10 +177,6 @@ public class ContextIsolator {
         return ret;
     }
 
-    public Object receive() throws InterruptedException {
-        return getContext().takeMessage();
-    }
-
     private static class AppClassLoader extends URLClassLoader {
         public AppClassLoader(URL[] urlArray, ClassLoader parent) {
             super(urlArray, parent);
@@ -324,5 +190,4 @@ public class ContextIsolator {
             return permissions;
         }
     }
-
 }
diff --git a/java/runjava/src/main/java/io/osv/RunJava.java 
b/java/runjava/src/main/java/io/osv/RunJava.java
deleted file mode 100644
index f7b8302..0000000
--- a/java/runjava/src/main/java/io/osv/RunJava.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package io.osv;
-
-/*
- * Copyright (C) 2013-2014 Cloudius Systems, Ltd.
- *
- * This work is open source software, licensed under the terms of the
- * BSD license as described in the LICENSE file in the top-level directory.
- */
-
-public class RunJava {
-       private static native void onVMStop();
-
-       static {
-               Runtime.getRuntime().addShutdownHook(new Thread() {
-                       public void run() {
-                               onVMStop();
-                       }
-               });
-       }
-
-    public static void main(String[] args) {
-        if (args.length > 0 && args[0].equals("-version")) {
-            System.err.println("java version \"" +
-                    System.getProperty("java.version") + "\"");
-            System.err.println(System.getProperty("java.runtime.name") +
-                    " (" + System.getProperty("java.runtime.version") +
-                    ")");
-            System.err.println(System.getProperty("java.vm.name") +
-                    " (build " + System.getProperty("java.vm.version") +
-                    ", " + System.getProperty("java.vm.info") + ")");
-            return;
-        }
-
-        try {
-            ContextIsolator.getInstance().runSync(args);
-        } catch (IllegalArgumentException ex) {
-            System.err.println("RunJava: " + ex.getMessage());
-        } catch (ContextFailedException ex) {
-            if (ex.getCause() instanceof MainClassNotFoundException) {
-                System.err.println("Error: Could not find or load main class " 
+ ((MainClassNotFoundException) ex.getCause()).getClassName());
-            } else {
-                ex.printStackTrace();
-            }
-        } catch (Throwable ex) {
-            ex.printStackTrace();
-        }
-    }
-}
diff --git a/java/runjava/src/main/java/io/osv/RunJvmAppHelper.java 
b/java/runjava/src/main/java/io/osv/RunJvmAppHelper.java
new file mode 100644
index 0000000..6300999
--- /dev/null
+++ b/java/runjava/src/main/java/io/osv/RunJvmAppHelper.java
@@ -0,0 +1,44 @@
+package io.osv;
+
+/*
+ * Copyright (C) 2016 Waldemar Kozaczuk
+ * Copyright (C) 2013-2016 Cloudius Systems, Ltd.
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+public class RunJvmAppHelper {
+
+   public interface JvmFactory {
+       Jvm getJvm();
+   }
+
+   static public void runSync(JvmFactory jvmFactory, String[] args) {
+
+       if (args.length > 0 && args[0].equals("-version")) {
+           System.err.println("java version \"" +
+                   System.getProperty("java.version") + "\"");
+           System.err.println(System.getProperty("java.runtime.name") +
+                   " (" + System.getProperty("java.runtime.version") +
+                   ")");
+           System.err.println(System.getProperty("java.vm.name") +
+                   " (build " + System.getProperty("java.vm.version") +
+                   ", " + System.getProperty("java.vm.info") + ")");
+           return;
+       }
+
+       try {
+           jvmFactory.getJvm().runSync(args);
+       } catch (IllegalArgumentException ex) {
+           System.err.println("RunJava: " + ex.getMessage());
+       } catch (AppThreadTerminatedWithUncaughtException ex) {
+           if (ex.getCause() instanceof MainClassNotFoundException) {
+               System.err.println("Error: Could not find or load main class " 
+ ((MainClassNotFoundException) ex.getCause()).getClassName());
+           } else {
+               ex.printStackTrace();
+           }
+       } catch (Throwable ex) {
+           ex.printStackTrace();
+       }
+   }
+}
diff --git a/java/runjava/src/main/java/io/osv/Context.java 
b/java/runjava/src/main/java/io/osv/isolated/Context.java
similarity index 98%
rename from java/runjava/src/main/java/io/osv/Context.java
rename to java/runjava/src/main/java/io/osv/isolated/Context.java
index ad70504..73f86fd 100644
--- a/java/runjava/src/main/java/io/osv/Context.java
+++ b/java/runjava/src/main/java/io/osv/isolated/Context.java
@@ -1,4 +1,4 @@
-package io.osv;
+package io.osv.isolated;
 
 import io.osv.jul.LogManagerWrapper;
 import io.osv.util.LazilyInitialized;
diff --git a/java/runjava/src/main/java/io/osv/ContextFailedException.java 
b/java/runjava/src/main/java/io/osv/isolated/ContextFailedException.java
similarity index 62%
rename from java/runjava/src/main/java/io/osv/ContextFailedException.java
rename to java/runjava/src/main/java/io/osv/isolated/ContextFailedException.java
index 541115e..6623f59 100644
--- a/java/runjava/src/main/java/io/osv/ContextFailedException.java
+++ b/java/runjava/src/main/java/io/osv/isolated/ContextFailedException.java
@@ -1,4 +1,6 @@
-package io.osv;
+package io.osv.isolated;
+
+import io.osv.AppThreadTerminatedWithUncaughtException;
 
 /*
  * Copyright (C) 2014 Cloudius Systems, Ltd.
@@ -6,7 +8,7 @@ package io.osv;
  * This work is open source software, licensed under the terms of the
  * BSD license as described in the LICENSE file in the top-level directory.
  */
-public class ContextFailedException extends Exception {
+public class ContextFailedException extends 
AppThreadTerminatedWithUncaughtException {
     public ContextFailedException(Throwable cause) {
         super(cause);
     }
diff --git a/java/runjava/src/main/java/io/osv/isolated/IsolatedJvm.java 
b/java/runjava/src/main/java/io/osv/isolated/IsolatedJvm.java
new file mode 100644
index 0000000..6bc3768
--- /dev/null
+++ b/java/runjava/src/main/java/io/osv/isolated/IsolatedJvm.java
@@ -0,0 +1,160 @@
+package io.osv.isolated;
+
+import io.osv.MainClassNotFoundException;
+import io.osv.Jvm;
+import io.osv.jul.IsolatingLogManager;
+import net.sf.cglib.proxy.Dispatcher;
+import net.sf.cglib.proxy.Enhancer;
+
+import java.lang.reflect.Field;
+import java.util.Properties;
+import java.util.logging.LogManager;
+
+/*
+ * Copyright (C) 2016 Waldemar Kozaczuk
+ * Copyright (C) 2014 Cloudius Systems, Ltd.
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+public class IsolatedJvm extends Jvm<Context> {
+    private static final IsolatedJvm instance = new IsolatedJvm();
+
+    static {
+        verifyLogManagerIsInstalled();
+    }
+
+    private final Context masterContext;
+    private final Properties commonSystemProperties;
+
+    private static void verifyLogManagerIsInstalled() {
+        LogManager manager = LogManager.getLogManager();
+        if (!(manager instanceof IsolatingLogManager)) {
+            throw new AssertionError("For isolation to work logging manager 
must be "
+                    + IsolatingLogManager.class.getName() + " but is: " + 
manager.getClass().getName());
+        }
+    }
+
+    private final InheritableThreadLocal<Context> currentContext = new 
InheritableThreadLocal<Context>() {
+        @Override
+        protected Context initialValue() {
+            return masterContext;
+        }
+    };
+
+    private final ClassLoader parentClassLoaderForIsolates;
+
+    public static IsolatedJvm getInstance() {
+        return instance;
+    }
+
+    private IsolatedJvm() {
+        ClassLoader originalSystemClassLoader = 
getOsvClassLoader().getParent();
+        commonSystemProperties = copyOf(System.getProperties());
+        masterContext = new Context(originalSystemClassLoader, 
copyOf(commonSystemProperties));
+
+        parentClassLoaderForIsolates = originalSystemClassLoader;
+
+        installSystemPropertiesProxy();
+    }
+
+    private Properties copyOf(Properties properties) {
+        Properties result = new Properties();
+        result.putAll(properties);
+        return result;
+    }
+
+    private void installSystemPropertiesProxy() {
+        Enhancer enhancer = new Enhancer();
+        enhancer.setSuperclass(Properties.class);
+        enhancer.setCallback(new Dispatcher() {
+            @Override
+            public Object loadObject() throws Exception {
+                return instance.getContext().getProperties();
+            }
+        });
+        Properties contextAwareProperties = (Properties) enhancer.create();
+
+        try {
+            Field props = System.class.getDeclaredField("props");
+            props.setAccessible(true);
+            props.set(System.class, contextAwareProperties);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new AssertionError("Unable to override System.props", e);
+        }
+    }
+
+    public Context getContext() {
+        return currentContext.get();
+    }
+
+    protected Context run(ClassLoader classLoader, final String classpath, 
final String mainClass,
+                        final String[] args, final Properties properties) {
+        Properties contextProperties = new Properties();
+        contextProperties.putAll(commonSystemProperties);
+        contextProperties.putAll(properties);
+
+        final Context context = new Context(classLoader, contextProperties);
+
+        Thread thread = new Thread() {
+            @Override
+            public void run() {
+                currentContext.set(context);
+                context.setProperty("java.class.path", classpath);
+
+                try {
+                    runMain(loadClass(mainClass), args);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                } catch (MainClassNotFoundException e) {
+                    context.setException(e);
+                } catch (Throwable e) {
+                    getUncaughtExceptionHandler().uncaughtException(this, e);
+                }
+            }
+        };
+
+        context.setMainThread(thread);
+        thread.setUncaughtExceptionHandler(new 
Thread.UncaughtExceptionHandler() {
+            @Override
+            public void uncaughtException(Thread t, Throwable e) {
+                context.setException(e);
+            }
+        });
+        thread.setContextClassLoader(classLoader);
+        thread.start();
+        return context;
+    }
+
+    protected ClassLoader getParentClassLoader() {
+        return parentClassLoaderForIsolates;
+    }
+
+    public void runSync(String... args) throws Throwable {
+        Context context = run(args);
+
+        while (true) {
+            try {
+                context.join();
+                return;
+            } catch (InterruptedException e) {
+                context.interrupt();
+            }
+        }
+    }
+
+    private OsvSystemClassLoader getOsvClassLoader() {
+        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+        if (!(systemClassLoader instanceof OsvSystemClassLoader)) {
+            throw new AssertionError("System class loader should be an 
instance of "
+                    + OsvSystemClassLoader.class.getName() + " but is "
+                    + systemClassLoader.getClass().getName());
+        }
+
+        return (OsvSystemClassLoader) systemClassLoader;
+    }
+
+    public Object receive() throws InterruptedException {
+        return getContext().takeMessage();
+    }
+}
diff --git a/java/runjava/src/main/java/io/osv/MultiJarLoader.java 
b/java/runjava/src/main/java/io/osv/isolated/MultiJarLoader.java
similarity index 97%
rename from java/runjava/src/main/java/io/osv/MultiJarLoader.java
rename to java/runjava/src/main/java/io/osv/isolated/MultiJarLoader.java
index daf19ef..8902a89 100644
--- a/java/runjava/src/main/java/io/osv/MultiJarLoader.java
+++ b/java/runjava/src/main/java/io/osv/isolated/MultiJarLoader.java
@@ -1,4 +1,4 @@
-package io.osv;
+package io.osv.isolated;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -110,7 +110,7 @@ public class MultiJarLoader {
         @Override
         public void run() {
             try {
-                ContextIsolator.getInstance().runSync(args.split("\\s+"));
+                IsolatedJvm.getInstance().runSync(args.split("\\s+"));
             } catch (Throwable e) {
                 System.err.println("Exception was caught while running " + args
                         + " exception: " + e);
diff --git a/java/runjava/src/main/java/io/osv/OsvSystemClassLoader.java 
b/java/runjava/src/main/java/io/osv/isolated/OsvSystemClassLoader.java
similarity index 98%
rename from java/runjava/src/main/java/io/osv/OsvSystemClassLoader.java
rename to java/runjava/src/main/java/io/osv/isolated/OsvSystemClassLoader.java
index dfa5b00..fee72cf 100644
--- a/java/runjava/src/main/java/io/osv/OsvSystemClassLoader.java
+++ b/java/runjava/src/main/java/io/osv/isolated/OsvSystemClassLoader.java
@@ -1,4 +1,4 @@
-package io.osv;
+package io.osv.isolated;
 
 /*
  * Copyright (C) 2013 Cloudius Systems, Ltd.
@@ -54,7 +54,7 @@ public class OsvSystemClassLoader extends ClassLoader {
     }
 
     private Context getContext() {
-        return ContextIsolator.getInstance().getContext();
+        return IsolatedJvm.getInstance().getContext();
     }
 
     private ClassLoader getDelegate() {
diff --git a/java/runjava/src/main/java/io/osv/isolated/RunIsolatedJvmApp.java 
b/java/runjava/src/main/java/io/osv/isolated/RunIsolatedJvmApp.java
new file mode 100644
index 0000000..29e3ccc
--- /dev/null
+++ b/java/runjava/src/main/java/io/osv/isolated/RunIsolatedJvmApp.java
@@ -0,0 +1,33 @@
+package io.osv.isolated;
+
+/*
+ * Copyright (C) 2016 Waldemar Kozaczuk
+ * Copyright (C) 2013-2014 Cloudius Systems, Ltd.
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+import io.osv.Jvm;
+
+import static io.osv.RunJvmAppHelper.runSync;
+import static io.osv.RunJvmAppHelper.JvmFactory;
+
+public class RunIsolatedJvmApp {
+       private static native void onVMStop();
+
+       static {
+               Runtime.getRuntime().addShutdownHook(new Thread() {
+                       public void run() {
+                               onVMStop();
+                       }
+               });
+       }
+
+    public static void main(String[] args) {
+        runSync(new JvmFactory() {
+            public Jvm getJvm() {
+                return IsolatedJvm.getInstance();
+            }
+        },args);
+    }
+}
diff --git a/java/runjava/src/main/java/io/osv/jul/IsolatingLogManager.java 
b/java/runjava/src/main/java/io/osv/jul/IsolatingLogManager.java
index 843bfc2..18b7d64 100644
--- a/java/runjava/src/main/java/io/osv/jul/IsolatingLogManager.java
+++ b/java/runjava/src/main/java/io/osv/jul/IsolatingLogManager.java
@@ -1,7 +1,7 @@
 package io.osv.jul;
 
-import io.osv.Context;
-import io.osv.ContextIsolator;
+import io.osv.isolated.Context;
+import io.osv.isolated.IsolatedJvm;
 
 import java.beans.PropertyChangeListener;
 import java.io.IOException;
@@ -19,7 +19,7 @@ import java.util.logging.Logger;
 @SuppressWarnings("UnusedDeclaration")
 public class IsolatingLogManager extends LogManager {
     private LogManager getDelegate() {
-        Context context = ContextIsolator.getInstance().getContext();
+        Context context = IsolatedJvm.getInstance().getContext();
         return context.getLogManagerWrapper().getManager();
     }
 
diff --git a/java/runjava/src/main/java/io/osv/jul/LogManagerWrapper.java 
b/java/runjava/src/main/java/io/osv/jul/LogManagerWrapper.java
index e4d48d2..d00f014 100644
--- a/java/runjava/src/main/java/io/osv/jul/LogManagerWrapper.java
+++ b/java/runjava/src/main/java/io/osv/jul/LogManagerWrapper.java
@@ -1,6 +1,6 @@
 package io.osv.jul;
 
-import io.osv.Context;
+import io.osv.isolated.Context;
 import io.osv.util.LazilyInitialized;
 import net.sf.cglib.proxy.Enhancer;
 import net.sf.cglib.proxy.MethodInterceptor;
diff --git a/java/runjava/src/main/java/io/osv/nonisolated/NonIsolatedJvm.java 
b/java/runjava/src/main/java/io/osv/nonisolated/NonIsolatedJvm.java
new file mode 100644
index 0000000..5d19b77
--- /dev/null
+++ b/java/runjava/src/main/java/io/osv/nonisolated/NonIsolatedJvm.java
@@ -0,0 +1,86 @@
+package io.osv.nonisolated;
+
+import io.osv.AppThreadTerminatedWithUncaughtException;
+import io.osv.Jvm;
+import io.osv.MainClassNotFoundException;
+
+import java.util.Properties;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+/*
+ * Copyright (C) 2016 Waldemar Kozaczuk
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+public class NonIsolatedJvm extends Jvm<Thread> {
+
+    private static final NonIsolatedJvm instance = new NonIsolatedJvm();
+
+    private AtomicReference<Throwable> thrownException = new 
AtomicReference<>();
+
+    public static NonIsolatedJvm getInstance() {
+        return instance;
+    }
+
+    private NonIsolatedJvm() {}
+
+    @Override
+    protected Thread run(ClassLoader classLoader, final String classpath, 
final String mainClass, final String[] args, final Properties properties) {
+        thrownException.set(null);
+        Thread thread = new Thread() {
+            @Override
+            public void run() {
+            System.setProperty("java.class.path", classpath);
+
+            for(Map.Entry<?,?> property : properties.entrySet())
+                
System.setProperty(property.getKey().toString(),property.getValue().toString());
 //TODO Check for null
+
+            try {
+                runMain(loadClass(mainClass), args);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+            } catch (MainClassNotFoundException e) {
+                thrownException.set(e);
+            } catch (Throwable e) {
+                getUncaughtExceptionHandler().uncaughtException(this, e);
+            }
+            }
+        };
+
+        thread.setUncaughtExceptionHandler(new 
Thread.UncaughtExceptionHandler() {
+            @Override
+            public void uncaughtException(Thread t, Throwable e) {
+                thrownException.set(e);
+            }
+        });
+        thread.setContextClassLoader(classLoader);
+        thread.start();
+        return thread;
+    }
+
+    public void runSync(String... args) throws Throwable {
+        Thread thread = run(args);
+
+        while (true) {
+            try {
+                thread.join();
+                final Throwable exception = thrownException.get();
+                if (null != exception) {
+                    throw new 
AppThreadTerminatedWithUncaughtException(exception);
+                }
+                return;
+            } catch (InterruptedException e) {
+                thread.interrupt();
+            }
+        }
+    }
+
+    @Override
+    protected ClassLoader getParentClassLoader() {
+        return Thread.currentThread().getContextClassLoader();
+    }
+
+    public Throwable getThrownExceptionIfAny() { return thrownException.get(); 
}
+}
diff --git 
a/java/runjava/src/main/java/io/osv/nonisolated/RunNonIsolatedJvmApp.java 
b/java/runjava/src/main/java/io/osv/nonisolated/RunNonIsolatedJvmApp.java
new file mode 100644
index 0000000..12f8800
--- /dev/null
+++ b/java/runjava/src/main/java/io/osv/nonisolated/RunNonIsolatedJvmApp.java
@@ -0,0 +1,33 @@
+package io.osv.nonisolated;
+
+/*
+ * Copyright (C) 2016 Waldemar Kozaczuk
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+import io.osv.Jvm;
+
+import static io.osv.RunJvmAppHelper.runSync;
+import static io.osv.RunJvmAppHelper.JvmFactory;
+
+public class RunNonIsolatedJvmApp {
+       private static native void onVMStop();
+
+       static {
+               Runtime.getRuntime().addShutdownHook(new Thread() {
+                       public void run() {
+                               onVMStop();
+                       }
+               });
+       }
+
+    public static void main(String[] args) {
+        runSync(new JvmFactory() {
+            public Jvm getJvm() {
+                return NonIsolatedJvm.getInstance();
+            }
+        },args);
+    }
+}
diff --git a/java/tests-isolates/src/main/java/tests/LoggingProcess.java 
b/java/tests-isolates/src/main/java/tests/LoggingProcess.java
index 161d4f6..c1d8385 100644
--- a/java/tests-isolates/src/main/java/tests/LoggingProcess.java
+++ b/java/tests-isolates/src/main/java/tests/LoggingProcess.java
@@ -1,6 +1,6 @@
 package tests;
 
-import io.osv.ContextIsolator;
+import io.osv.isolated.IsolatedJvm;
 
 import java.util.concurrent.CyclicBarrier;
 import java.util.logging.FileHandler;
@@ -16,7 +16,7 @@ import java.util.logging.SimpleFormatter;
  */
 public class LoggingProcess {
     public static void main(String[] args) throws Throwable {
-        CyclicBarrier barrier = (CyclicBarrier) 
ContextIsolator.getInstance().receive();
+        CyclicBarrier barrier = (CyclicBarrier) 
IsolatedJvm.getInstance().receive();
 
         String logFileName = args[0];
         String loggerName = args[1];
diff --git a/java/tests-isolates/src/main/java/tests/LoggingProcess.java 
b/java/tests-isolates/src/main/java/tests/NonIsolatedLoggingProcess.java
similarity index 80%
copy from java/tests-isolates/src/main/java/tests/LoggingProcess.java
copy to java/tests-isolates/src/main/java/tests/NonIsolatedLoggingProcess.java
index 161d4f6..e0755d3 100644
--- a/java/tests-isolates/src/main/java/tests/LoggingProcess.java
+++ b/java/tests-isolates/src/main/java/tests/NonIsolatedLoggingProcess.java
@@ -1,23 +1,19 @@
 package tests;
 
-import io.osv.ContextIsolator;
-
-import java.util.concurrent.CyclicBarrier;
 import java.util.logging.FileHandler;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.SimpleFormatter;
 
 /*
+ * Copyright (C) 2016 Waldemar Kozaczuk
  * Copyright (C) 2014 Cloudius Systems, Ltd.
  *
  * This work is open source software, licensed under the terms of the
  * BSD license as described in the LICENSE file in the top-level directory.
  */
-public class LoggingProcess {
+public class NonIsolatedLoggingProcess {
     public static void main(String[] args) throws Throwable {
-        CyclicBarrier barrier = (CyclicBarrier) 
ContextIsolator.getInstance().receive();
-
         String logFileName = args[0];
         String loggerName = args[1];
         Level level = Level.parse(args[2]);
@@ -30,8 +26,6 @@ public class LoggingProcess {
 
         logger.setLevel(level);
 
-        barrier.await();
-
         logger.info(message);
         logger.warning(message);
     }
diff --git a/java/tests-isolates/src/main/java/tests/PropertyReader.java 
b/java/tests-isolates/src/main/java/tests/PropertyReader.java
index ae63402..5e51ade 100644
--- a/java/tests-isolates/src/main/java/tests/PropertyReader.java
+++ b/java/tests-isolates/src/main/java/tests/PropertyReader.java
@@ -1,6 +1,6 @@
 package tests;
 
-import io.osv.ContextIsolator;
+import io.osv.isolated.IsolatedJvm;
 
 import java.util.concurrent.CyclicBarrier;
 
@@ -17,7 +17,7 @@ public class PropertyReader {
         String property = args[0];
         String expectedValue = args[1];
 
-        CyclicBarrier barrier = (CyclicBarrier) 
ContextIsolator.getInstance().receive();
+        CyclicBarrier barrier = (CyclicBarrier) 
IsolatedJvm.getInstance().receive();
         barrier.await();
 
         assertEquals(expectedValue, System.getProperty(property));
diff --git a/java/tests-isolates/src/main/java/tests/PropertySetter.java 
b/java/tests-isolates/src/main/java/tests/PropertySetter.java
index 9ea83fa..8b4d72e 100644
--- a/java/tests-isolates/src/main/java/tests/PropertySetter.java
+++ b/java/tests-isolates/src/main/java/tests/PropertySetter.java
@@ -1,6 +1,6 @@
 package tests;
 
-import io.osv.ContextIsolator;
+import io.osv.isolated.IsolatedJvm;
 
 import java.util.concurrent.CyclicBarrier;
 
@@ -14,7 +14,7 @@ import static org.junit.Assert.assertEquals;
  */
 public class PropertySetter {
     public static void main(String[] args) throws Exception {
-        CyclicBarrier barrier = (CyclicBarrier) 
ContextIsolator.getInstance().receive();
+        CyclicBarrier barrier = (CyclicBarrier) 
IsolatedJvm.getInstance().receive();
         String property = args[0];
         String value = args[1];
 
diff --git a/java/tests-isolates/src/main/java/tests/StaticFieldSetter.java 
b/java/tests-isolates/src/main/java/tests/StaticFieldSetter.java
index 6ef94e9..0103afc 100644
--- a/java/tests-isolates/src/main/java/tests/StaticFieldSetter.java
+++ b/java/tests-isolates/src/main/java/tests/StaticFieldSetter.java
@@ -1,6 +1,6 @@
 package tests;
 
-import io.osv.ContextIsolator;
+import io.osv.isolated.IsolatedJvm;
 
 import java.util.concurrent.BrokenBarrierException;
 import java.util.concurrent.CyclicBarrier;
@@ -26,7 +26,7 @@ public class StaticFieldSetter {
 
     public static class Party {
         public static void main(String[] args) throws InterruptedException, 
BrokenBarrierException {
-            CyclicBarrier barrier = (CyclicBarrier) 
ContextIsolator.getInstance().receive();
+            CyclicBarrier barrier = (CyclicBarrier) 
IsolatedJvm.getInstance().receive();
 
             String value = args[0];
             staticField = value;
diff --git a/java/tests/src/main/java/io/osv/AllTests.java 
b/java/tests/src/main/java/io/osv/AllTestsThatTestIsolatedApp.java
similarity index 91%
copy from java/tests/src/main/java/io/osv/AllTests.java
copy to java/tests/src/main/java/io/osv/AllTestsThatTestIsolatedApp.java
index 4eca806..5cdb498 100644
--- a/java/tests/src/main/java/io/osv/AllTests.java
+++ b/java/tests/src/main/java/io/osv/AllTestsThatTestIsolatedApp.java
@@ -17,5 +17,5 @@ import org.junit.runners.Suite;
         PropertyIsolationTest.class,
         OsvApiTest.class
 })
-public class AllTests {
+public class AllTestsThatTestIsolatedApp {
 }
diff --git a/java/tests/src/main/java/io/osv/AllTests.java 
b/java/tests/src/main/java/io/osv/AllTestsThatTestNonIsolatedApp.java
similarity index 67%
rename from java/tests/src/main/java/io/osv/AllTests.java
rename to java/tests/src/main/java/io/osv/AllTestsThatTestNonIsolatedApp.java
index 4eca806..cfb78b5 100644
--- a/java/tests/src/main/java/io/osv/AllTests.java
+++ b/java/tests/src/main/java/io/osv/AllTestsThatTestNonIsolatedApp.java
@@ -1,21 +1,20 @@
 package io.osv;
 
 /*
+ * Copyright (C) 2016 Waldemar Kozaczuk
  * Copyright (C) 2014 Cloudius Systems, Ltd.
  *
  * This work is open source software, licensed under the terms of the
  * BSD license as described in the LICENSE file in the top-level directory.
  */
-
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-        LoggingIsolationTest.class,
-        ClassLoaderIsolationTest.class,
-        PropertyIsolationTest.class,
+        LoggingWithoutIsolationTest.class,
+        ClassLoaderWithoutIsolationTest.class,
         OsvApiTest.class
 })
-public class AllTests {
+public class AllTestsThatTestNonIsolatedApp {
 }
diff --git a/java/tests/src/main/java/io/osv/ClassLoaderIsolationTest.java 
b/java/tests/src/main/java/io/osv/ClassLoaderIsolationTest.java
index f140e1b..5e920a9 100644
--- a/java/tests/src/main/java/io/osv/ClassLoaderIsolationTest.java
+++ b/java/tests/src/main/java/io/osv/ClassLoaderIsolationTest.java
@@ -5,7 +5,10 @@ import tests.*;
 
 import java.util.concurrent.CyclicBarrier;
 
-import static io.osv.TestIsolateLaunching.runIsolate;
+import io.osv.isolated.Context;
+import io.osv.isolated.ContextFailedException;
+
+import static io.osv.TestLaunching.runIsolate;
 import static org.junit.Assert.*;
 
 /*
diff --git 
a/java/tests/src/main/java/io/osv/ClassLoaderWithoutIsolationTest.java 
b/java/tests/src/main/java/io/osv/ClassLoaderWithoutIsolationTest.java
new file mode 100644
index 0000000..ec20cf2
--- /dev/null
+++ b/java/tests/src/main/java/io/osv/ClassLoaderWithoutIsolationTest.java
@@ -0,0 +1,89 @@
+package io.osv;
+
+import io.osv.nonisolated.NonIsolatedJvm;
+import org.junit.Test;
+import tests.*;
+
+import static io.osv.TestLaunching.runWithoutIsolation;
+import static org.junit.Assert.*;
+
+/*
+ * Copyright (C) 2016 Waldemar Kozaczuk
+ * Copyright (C) 2014 Cloudius Systems, Ltd.
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+public class ClassLoaderWithoutIsolationTest {
+    private static final Class<?> THIS_CLASS = 
ClassLoaderWithoutIsolationTest.class;
+
+    @Test
+    public void testParentContextSeesModificationsOfStaticFields() throws 
Throwable {
+        Thread thread = runWithoutIsolation(StaticFieldSetter.class); // This 
is where the class is loaded and available to child one
+        thread.join();
+
+        //
+        // Rethrow any exception that may have been raised and led to the 
thread terminating
+        final Throwable exception = 
NonIsolatedJvm.getInstance().getThrownExceptionIfAny();
+        if( null != exception)
+            throw exception;
+        //
+        // There is one class instance of StaticFieldSetter loaded as there is 
no isolation
+        // between the parent app classloader (at the tests runner level) and 
the child app
+        // classloader level which is created when runWithoutIsolation is 
called
+        assertEquals(StaticFieldSetter.NEW_VALUE, 
StaticFieldSetter.staticField);
+    }
+
+    @Test
+    public void testChildSeesSameVersionOfAClassDefinedInParentContext() 
throws Throwable {
+        String fieldName = "field_existing_only_in_isolate_context";
+
+        try {
+            ClassPresentInBothContexts.class.getDeclaredField(fieldName);
+            throw new AssertionError("The field should be absent in parent 
context");
+        } catch (NoSuchFieldException e) {
+            // expected
+        }
+
+        Thread thread = runWithoutIsolation(FieldTester.class, 
ClassPresentInBothContexts.class.getName(), fieldName);
+        thread.join();
+        //
+        // Rethrow any exception that may have been raised and led to the 
thread terminating
+        final Throwable exception = 
NonIsolatedJvm.getInstance().getThrownExceptionIfAny();
+        if( null != exception && exception instanceof NoSuchFieldException) {
+            // It is what is expected as there is no isolation between child 
and parent classloader the class loaded
+            // by parent classloader from tests.jar which is a first jar in 
the classpath
+        }
+        else if( null != exception) {
+            throw exception;
+        }
+        else {
+            throw new AssertionError("The field should be also absent in child 
context");
+        }
+    }
+
+    @Test
+    public void testClassesDefinedInParentContextAreVisibleToChild() throws 
Throwable {
+        Thread thread = runWithoutIsolation(ClassFinder.class, 
ClassPresentOnlyInParentContext.class.getName());
+        thread.join();
+        //
+        // Rethrow any exception that may have been raised and led to the 
thread terminating
+        final Throwable exception = 
NonIsolatedJvm.getInstance().getThrownExceptionIfAny();
+        if( null != exception)
+            throw exception;
+        //
+        // As there is no isolation between child and parent classloader the 
class loaded
+        // by parent classloader ClassPresentOnlyInParentContext from 
tests.jar will
+        // actually be visible in the children
+    }
+
+    @Test
+    public void testClassesFromExtensionDirectoryCanBeLoaded() throws 
Exception {
+        assertNotNull(SomeExtensionClass.class);
+    }
+
+    @Test
+    public void 
testClassPutInRootDirectoryIsNotPickedUpByDefaultSystemClassLoader() throws 
Exception {
+        assertSame(ClassPutInRoot.class.getClassLoader(), 
THIS_CLASS.getClassLoader());
+    }
+}
\ No newline at end of file
diff --git a/java/tests/src/main/java/io/osv/LoggingIsolationTest.java 
b/java/tests/src/main/java/io/osv/LoggingIsolationTest.java
index bb4637f..8154960 100644
--- a/java/tests/src/main/java/io/osv/LoggingIsolationTest.java
+++ b/java/tests/src/main/java/io/osv/LoggingIsolationTest.java
@@ -7,7 +7,9 @@ import java.io.File;
 import java.io.IOException;
 import java.util.concurrent.CyclicBarrier;
 
-import static io.osv.TestIsolateLaunching.runIsolate;
+import io.osv.isolated.Context;
+
+import static io.osv.TestLaunching.runIsolate;
 import static org.apache.commons.io.FileUtils.forceDeleteOnExit;
 import static org.apache.commons.io.FileUtils.readLines;
 import static org.fest.assertions.Assertions.assertThat;
diff --git a/java/tests/src/main/java/io/osv/LoggingWithoutIsolationTest.java 
b/java/tests/src/main/java/io/osv/LoggingWithoutIsolationTest.java
new file mode 100644
index 0000000..5f5a188
--- /dev/null
+++ b/java/tests/src/main/java/io/osv/LoggingWithoutIsolationTest.java
@@ -0,0 +1,54 @@
+package io.osv;
+
+import io.osv.nonisolated.NonIsolatedJvm;
+import org.junit.Test;
+import tests.NonIsolatedLoggingProcess;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import static io.osv.TestLaunching.runWithoutIsolation;
+import static org.apache.commons.io.FileUtils.forceDeleteOnExit;
+import static org.apache.commons.io.FileUtils.readLines;
+import static org.fest.assertions.Assertions.assertThat;
+
+/*
+ * Copyright (C) 2016 Waldemar Kozaczuk
+ * Copyright (C) 2014 Cloudius Systems, Ltd.
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+public class LoggingWithoutIsolationTest {
+    private static final String LOGGER_NAME = "test-logger";
+
+    @Test
+    public void testLogger() throws Throwable {
+        File log = newTemporaryFile();
+
+        Thread thread = runWithoutIsolation(NonIsolatedLoggingProcess.class, 
log.getAbsolutePath(), LOGGER_NAME, "INFO", "ctx");
+        thread.join();
+
+        //
+        // Rethrow any exception that may have been raised and led to the 
thread terminating
+        final Throwable exception = 
NonIsolatedJvm.getInstance().getThrownExceptionIfAny();
+        if( null != exception)
+            throw exception;
+
+        final List<String> logLines = readLines(log);
+        for( String line : logLines)
+            System.out.println(line);
+
+        assertThat(logLines)
+                .hasSize(4)
+                .contains("INFO: ctx")
+                .contains("WARNING: ctx");
+    }
+
+    private File newTemporaryFile() throws IOException {
+        File file = File.createTempFile("test", null);
+        forceDeleteOnExit(file);
+        return file;
+    }
+}
diff --git a/java/tests/src/main/java/io/osv/PropertyIsolationTest.java 
b/java/tests/src/main/java/io/osv/PropertyIsolationTest.java
index 073d857..ad822ad 100644
--- a/java/tests/src/main/java/io/osv/PropertyIsolationTest.java
+++ b/java/tests/src/main/java/io/osv/PropertyIsolationTest.java
@@ -6,7 +6,9 @@ import tests.PropertySetter;
 
 import java.util.concurrent.CyclicBarrier;
 
-import static io.osv.TestIsolateLaunching.runIsolate;
+import io.osv.isolated.Context;
+
+import static io.osv.TestLaunching.runIsolate;
 import static java.util.Arrays.asList;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
diff --git a/java/tests/src/main/java/io/osv/TestIsolateLaunching.java 
b/java/tests/src/main/java/io/osv/TestLaunching.java
similarity index 53%
rename from java/tests/src/main/java/io/osv/TestIsolateLaunching.java
rename to java/tests/src/main/java/io/osv/TestLaunching.java
index c7e95f7..c8955c7 100644
--- a/java/tests/src/main/java/io/osv/TestIsolateLaunching.java
+++ b/java/tests/src/main/java/io/osv/TestLaunching.java
@@ -5,6 +5,10 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import io.osv.isolated.Context;
+import io.osv.isolated.IsolatedJvm;
+import io.osv.nonisolated.NonIsolatedJvm;
+
 import static java.util.Arrays.asList;
 import static org.fest.assertions.Assertions.assertThat;
 
@@ -14,13 +18,27 @@ import static org.fest.assertions.Assertions.assertThat;
  * This work is open source software, licensed under the terms of the
  * BSD license as described in the LICENSE file in the top-level directory.
  */
-public class TestIsolateLaunching {
+public class TestLaunching {
 
     public static Context runIsolate(Class<?> clazz, String... programArgs) 
throws Throwable {
         return runIsolate(clazz, Collections.<String>emptyList(), programArgs);
     }
 
     public static Context runIsolate(Class<?> clazz, List<String> args, 
String... programArgs) throws Throwable {
+        List<String> allArgs = testJarAndPrepareArgs(clazz, args, programArgs);
+        return IsolatedJvm.getInstance().run(allArgs.toArray(new 
String[allArgs.size()]));
+    }
+
+    public static Thread runWithoutIsolation(Class<?> clazz, String... 
programArgs) throws Throwable {
+        return runWithoutIsolation(clazz, Collections.<String>emptyList(), 
programArgs);
+    }
+
+    public static Thread runWithoutIsolation(Class<?> clazz, List<String> 
args, String... programArgs) throws Throwable {
+        List<String> allArgs = testJarAndPrepareArgs(clazz, args, programArgs);
+        return NonIsolatedJvm.getInstance().run(allArgs.toArray(new 
String[allArgs.size()]));
+    }
+
+    private static List<String> testJarAndPrepareArgs(Class<?> clazz, 
List<String> args, String... programArgs) {
         String jarPath = System.getProperty("isolates.jar");
         assertThat(jarPath).isNotEmpty();
         assertThat(new File(jarPath)).exists();
@@ -32,7 +50,6 @@ public class TestIsolateLaunching {
         allArgs.add(clazz.getName());
         allArgs.addAll(asList(programArgs));
 
-        return ContextIsolator.getInstance().run(allArgs.toArray(new 
String[allArgs.size()]));
+        return allArgs;
     }
-
 }
diff --git a/modules/java-tests/usr.manifest b/modules/java-tests/usr.manifest
new file mode 100644
index 0000000..0dca54e
--- /dev/null
+++ b/modules/java-tests/usr.manifest
@@ -0,0 +1,9 @@
+#
+# Copyright (C) 2013-2014 Cloudius Systems, Ltd.
+#
+# This work is open source software, licensed under the terms of the
+# BSD license as described in the LICENSE file in the top-level directory.
+#
+
+[manifest]
+/java_non_isolated.so: java/jvm/java_non_isolated.so
diff --git a/scripts/test.py b/scripts/test.py
index 5441149..605cb1a 100755
--- a/scripts/test.py
+++ b/scripts/test.py
@@ -22,8 +22,10 @@ blacklist= [
 ]
 
 add_tests([
-    SingleCommandTest('java', '/java.so -cp 
/tests/java/tests.jar:/tests/java/isolates.jar \
-        -Disolates.jar=/tests/java/isolates.jar org.junit.runner.JUnitCore 
io.osv.AllTests'),
+    SingleCommandTest('java_isolated', '/java.so -cp 
/tests/java/tests.jar:/tests/java/isolates.jar \
+        -Disolates.jar=/tests/java/isolates.jar org.junit.runner.JUnitCore 
io.osv.AllTestsThatTestIsolatedApp'),
+    SingleCommandTest('java_non_isolated', '/java_non_isolated.so -cp 
/tests/java/tests.jar:/tests/java/isolates.jar \
+        -Disolates.jar=/tests/java/isolates.jar org.junit.runner.JUnitCore 
io.osv.AllTestsThatTestNonIsolatedApp'),
     SingleCommandTest('java-perms', '/java.so -cp /tests/java/tests.jar 
io.osv.TestDomainPermissions'),
 ])
 
diff --git a/scripts/tests/testing.py b/scripts/tests/testing.py
index 89c8224..f71156d 100644
--- a/scripts/tests/testing.py
+++ b/scripts/tests/testing.py
@@ -73,6 +73,7 @@ def scan_errors(s):
         "at org.junit.runner.JUnitCore.main",
         "ContextFailedException",
        "\[backtrace\]",
+        "Failed to load object",
     ]
     for pattern in patterns:
         if re.findall(pattern, s):
-- 
1.9.1

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to