Created
November 7, 2012 20:55
-
-
Save pierre/4034381 to your computer and use it in GitHub Desktop.
Classloader isolation in Kb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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