Skip to content
Snippets Groups Projects
Commit 211bb7fb authored by Tomasz Grabiec's avatar Tomasz Grabiec
Browse files

java: do not pollute isolate classpath with isolator dependencies

We don't want cglib classes needed by io.osv.* classes to be
accessible from application classes. This could cause problems
if application would want to use its own version of cglib. In this
case the application provided cglib would be masked by the one
inside OSv.

To solve this problem we do not set the current class loader
as application class loader parent, but instead we link it with
a proxy which combines bootstrap class loader and the original
system class loader allowing only classes from io.osv.* package
to be loaded from the system class loader.

Class loader diagram:

 +-----------+
 | Bootstrap |<---------------+
 +-----------+                |
      ^                       |
      |                       |
      |                       |
 +----+------+  io.osv.*  +-----------+
 | System    |<-----------| Filtering |
 +-----------+            +-----------+
                              ^
                              |
                              |
            +-----------+     |
            | App 1     |-----+
            +-----------+     |
                              |
            +-----------+     |
            | App 2     |-----+
            +-----------+

This way the application may still use OSv java APIs, but does
not see classes from our dependencies and may load its own version
of these classes.
parent b174b89c
No related branches found
No related tags found
No related merge requests found
......@@ -42,13 +42,19 @@ public class ContextIsolator {
}
private final InheritableThreadLocal<Context> currentContext = new InheritableThreadLocal<>();
private final ClassLoader parentClassLoaderForIsolates;
public static ContextIsolator getInstance() {
return instance;
}
public ContextIsolator() {
currentContext.set(new Context(ClassLoader.getSystemClassLoader(), System.getProperties()));
ClassLoader originalSystemClassLoader = getOsvClassLoader().getParent();
currentContext.set(new Context(originalSystemClassLoader, System.getProperties()));
parentClassLoaderForIsolates = new TeeClassLoader(
new FilteringClassLoader(originalSystemClassLoader, "io.osv."));
installSystemPropertiesProxy();
}
......@@ -180,20 +186,12 @@ public class ContextIsolator {
}
private Context runClass(String mainClass, String[] args, Iterable<String> classpath, Properties properties) throws MalformedURLException {
OsvSystemClassLoader osvClassLoader = getOsvClassLoader();
ClassLoader appClassLoader = getClassLoader(classpath, osvClassLoader.getParent());
ClassLoader appClassLoader = getClassLoader(classpath, parentClassLoaderForIsolates);
return run(appClassLoader, joinClassPath(classpath), mainClass, args, properties);
}
private static ClassLoader getClassLoader(Iterable<String> classpath, ClassLoader parent) throws MalformedURLException {
List<URL> urls = toUrls(classpath);
// If no classpath was specified, don't touch the classloader at
// all, so we just inherit the one used to run us.
if (urls.isEmpty()) {
return parent;
}
URL[] urlArray = urls.toArray(new URL[urls.size()]);
return new URLClassLoader(urlArray, parent);
}
......
package io.osv;
class FilteringClassLoader extends ClassLoader {
private final String allowedPrefix;
public FilteringClassLoader(ClassLoader parent, String allowedPrefix) {
super(parent);
this.allowedPrefix = allowedPrefix;
}
private boolean isClassAllowed(String name) {
return name.startsWith(allowedPrefix);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (!isClassAllowed(name)) {
throw new ClassNotFoundException(name);
}
return super.loadClass(name, resolve);
}
}
package io.osv;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
class TeeClassLoader extends ClassLoader {
private ClassLoader delegate;
public TeeClassLoader(ClassLoader delegate) {
super(null);
this.delegate = delegate;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
return delegate.loadClass(name);
}
@Override
protected URL findResource(String name) {
return delegate.getResource(name);
}
@Override
protected Enumeration<URL> findResources(String name) throws IOException {
return delegate.getResources(name);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment