Skip to content

Instantly share code, notes, and snippets.

@pierre
Created November 7, 2012 20:55
Show Gist options
  • Save pierre/4034381 to your computer and use it in GitHub Desktop.
Save pierre/4034381 to your computer and use it in GitHub Desktop.
Classloader isolation in Kb
// Killbill object interface
package com.ning.billing.beatrix.util;
import java.util.List;
public interface MyKBI {
List getList();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Killbill object implementation
package com.ning.billing.beatrix.util;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import com.ning.billing.beatrix.util.MyList;
public class MyKBImpl implements MyKBI {
@Override
public List<?> getList() {
return new MyList();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Killbill specific MyList implementation
package com.ning.billing.beatrix.util;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class MyList implements List<Integer> {
@Override
public int size() {
return 1;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(final Object o) {
return false;
}
@Override
public Iterator<Integer> iterator() {
return null;
}
@Override
public Object[] toArray() {
return new Object[0];
}
@Override
public <T> T[] toArray(final T[] a) {
return null;
}
@Override
public boolean add(final Integer integer) {
return false;
}
@Override
public boolean remove(final Object o) {
return false;
}
@Override
public boolean containsAll(final Collection<?> c) {
return false;
}
@Override
public boolean addAll(final Collection<? extends Integer> c) {
return false;
}
@Override
public boolean addAll(final int index, final Collection<? extends Integer> c) {
return false;
}
@Override
public boolean removeAll(final Collection<?> c) {
return false;
}
@Override
public boolean retainAll(final Collection<?> c) {
return false;
}
@Override
public void clear() {
}
@Override
public Integer get(final int index) {
return null;
}
@Override
public Integer set(final int index, final Integer element) {
return null;
}
@Override
public void add(final int index, final Integer element) {
}
@Override
public Integer remove(final int index) {
return null;
}
@Override
public int indexOf(final Object o) {
return 0;
}
@Override
public int lastIndexOf(final Object o) {
return 0;
}
@Override
public ListIterator<Integer> listIterator() {
return null;
}
@Override
public ListIterator<Integer> listIterator(final int index) {
return null;
}
@Override
public List<Integer> subList(final int fromIndex, final int toIndex) {
return null;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Killbill plugin interface
package com.ning.billing.beatrix.util;
public interface MyPluginI {
public void doSomething(MyKBI kbObject);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Killbill plugin implementation
package com.ning.billing.beatrix.util;
import java.util.List;
import com.ning.billing.beatrix.util.MyPluginI;
import com.ning.billing.beatrix.util.MyList;
public class MyPlugin implements MyPluginI {
public void doSomething(MyKBI bleh) {
System.out.println(this.getClass().getClassLoader().toString());
System.out.println(bleh.getList().size());
System.out.println(bleh.getList().getClass().toString());
System.out.println(bleh.getList().getClass().getClassLoader().toString());
final List myList = new MyList();
System.out.println(myList.size());
System.out.println(myList.getClass().toString());
System.out.println(myList.getClass().getClassLoader().toString());
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Plugin specific MyList implementation
package com.ning.billing.beatrix.util;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class MyList implements List<Integer> {
@Override
public int size() {
return -1;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(final Object o) {
return false;
}
@Override
public Iterator<Integer> iterator() {
return null;
}
@Override
public Object[] toArray() {
return new Object[0];
}
@Override
public <T> T[] toArray(final T[] a) {
return null;
}
@Override
public boolean add(final Integer integer) {
return false;
}
@Override
public boolean remove(final Object o) {
return false;
}
@Override
public boolean containsAll(final Collection<?> c) {
return false;
}
@Override
public boolean addAll(final Collection<? extends Integer> c) {
return false;
}
@Override
public boolean addAll(final int index, final Collection<? extends Integer> c) {
return false;
}
@Override
public boolean removeAll(final Collection<?> c) {
return false;
}
@Override
public boolean retainAll(final Collection<?> c) {
return false;
}
@Override
public void clear() {
}
@Override
public Integer get(final int index) {
return null;
}
@Override
public Integer set(final int index, final Integer element) {
return null;
}
@Override
public void add(final int index, final Integer element) {
}
@Override
public Integer remove(final int index) {
return null;
}
@Override
public int indexOf(final Object o) {
return 0;
}
@Override
public int lastIndexOf(final Object o) {
return 0;
}
@Override
public ListIterator<Integer> listIterator() {
return null;
}
@Override
public ListIterator<Integer> listIterator(final int index) {
return null;
}
@Override
public List<Integer> subList(final int fromIndex, final int toIndex) {
return null;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class Kb {
static class KbCoreClassLoader extends URLClassLoader {
public KbCoreClassLoader(URL[] urls) {
super(urls);
}
}
static class PluginClassLoader extends URLClassLoader {
public PluginClassLoader(URL[] urls) {
super(urls);
}
}
public static void main(final String[] args) throws Exception {
// Killbill specific classloader
final ClassLoader kbCoreClassLoader = new KbCoreClassLoader(new URL[]{new URL("file:///tmp/kb/")});
final MyKBI kbObject = (MyKBI) kbCoreClassLoader.loadClass("com.ning.billing.beatrix.util.MyKBImpl").newInstance();
// Plugin specific classloader
final ClassLoader kbPluginClassLoader = new PluginClassLoader(new URL[]{new URL("file:///tmp/plugin/")});
final MyPluginI kbPluginInstance = (MyPluginI) kbPluginClassLoader.loadClass("com.ning.billing.beatrix.util.MyPlugin").newInstance();
kbPluginInstance.doSomething(kbObject);
// com.ning.billing.beatrix.util.Kb$PluginClassLoader@3dac2f9c
// 1
// class com.ning.billing.beatrix.util.MyList
// com.ning.billing.beatrix.util.Kb$KbCoreClassLoader@457471e0
// -1
// class com.ning.billing.beatrix.util.MyList
// com.ning.billing.beatrix.util.Kb$PluginClassLoader@3dac2f9c
}
static class CoreRunnable implements Runnable {
MyPluginI pluginI;
CoreRunnable(final MyPluginI pluginI) {
this.pluginI = pluginI;
}
@Override
public void run() {
try {
final MyKBI bleh = (MyKBI) Thread.currentThread().getContextClassLoader().loadClass("com.ning.billing.beatrix.util.MyKBImpl").newInstance();
System.out.println("Kb calling plugin");
pluginI.doSomething(bleh);
while (true) {
Thread.sleep(100000);
}
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (ClassNotFoundException e) {
} catch (InterruptedException e) {
}
}
}
static class PluginRunnable implements Runnable {
MyPluginI pluginI;
@Override
public void run() {
try {
pluginI = (MyPluginI) Thread.currentThread().getContextClassLoader().loadClass("com.ning.billing.beatrix.util.MyPlugin").newInstance();
System.out.println("Plugin started");
while (true) {
Thread.sleep(100000);
}
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (ClassNotFoundException e) {
} catch (InterruptedException e) {
}
}
public MyPluginI getPluginI() {
return pluginI;
}
}
public static void mainWithThreads(String[] args) throws MalformedURLException, ClassNotFoundException, IllegalAccessException, InstantiationException, InterruptedException {
final PluginRunnable pluginRunnable = new PluginRunnable();
final Thread pluginThread = new Thread(pluginRunnable);
pluginThread.setContextClassLoader(new PluginClassLoader(new URL[]{new URL("file:///tmp/plugin/")}));
pluginThread.start();
Thread.sleep(1000);
final Runnable coreRunnable = new CoreRunnable(pluginRunnable.getPluginI());
final Thread kbCoreThread = new Thread(coreRunnable);
kbCoreThread.setContextClassLoader(new KbCoreClassLoader(new URL[]{new URL("file:///tmp/kb/")}));
kbCoreThread.start();
Thread.currentThread().join();
}
public static void mainBroken(String[] args) throws MalformedURLException, ClassNotFoundException, IllegalAccessException, InstantiationException, InterruptedException {
final ClassLoader commonClassLoader = new KbCoreClassLoader(new URL[]{new URL("file:///tmp/kb/"), new URL("file:///tmp/plugin/")});
final MyKBI kbObject = (MyKBI) commonClassLoader.loadClass("com.ning.billing.beatrix.util.MyKBImpl").newInstance();
final MyPluginI kbPluginInstance = (MyPluginI) commonClassLoader.loadClass("com.ning.billing.beatrix.util.MyPlugin").newInstance();
kbPluginInstance.doSomething(kbObject);
// Note! Doesn't work here because the parent is searched first
//
// com.ning.billing.beatrix.util.Kb$KbCoreClassLoader@721cdeff
// 1
// class com.ning.billing.beatrix.util.MyList
// com.ning.billing.beatrix.util.Kb$KbCoreClassLoader@721cdeff
// 1
// class com.ning.billing.beatrix.util.MyList
// com.ning.billing.beatrix.util.Kb$KbCoreClassLoader@721cdeff
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment