I used BeanShell for ‘live’ poking around with webstart and jinput and that helped a lot. For further explanations I have to define two terms:
I consider a library installed when it is available in the ext folder of the running JVM.
A library is deployed when it is made available through the JNLP tag ‘jar’ or ‘nativelib’. Because of the Java class loading mechanism one should know that having the same class available via extension and JNLP the class is always loaded from the file in the ext folder (short: installation overrides deploying).
All explanations assume to have the jinput plugin installed in ${java.home}/lib/controller (deploying is currently impossible!).
With the jinputtester and webstart it goes like this:
a) jinput.jar and jutils.jar are installed:
All classes are taken from the installed version of jinput because Java’s classloaders have to ask their parent class loaders first to find a class data. Because of the things I explained in the last post a security exception is thrown.
b) jinput.jar and jutils.jar are deployed:
Jinput finds (for example) dxplugin.jar in ${java.home}/lib/controller and lets jutils searching for suitable classes in this jar. When jutils finds a matching class file (“DirectInputEnvironmentPlugin.class”) it generates a special class loader (PluginLoader) that can access all the files in dxinput.jar without explicitly specifying a parent class loader. This causes the usage of the SystemClassLoader. Anyway when defineClass() is called for DirectInputEnvironmentPlugin it fails (ClassNotFoundException) because it is unable to locate its parent class: ControllerEnvironment.
[This kind of exception wasn’t mentioned before because I thought I did something wrong with the JNLP file.]
Java expects ControllerEnvironment to be accessable from the same classloader that tries to define DirectInputEnvironmentPlugin. This does not work because PluginLoader can only load classes that are inside the dxinput.jar and that are available to the SystemClassLoader.
The only real problem is that PluginLoader is created without a parent that is able to find the class ControllerEnvironment. I think it would be pretty easy to fix the problems we have at the moment:
PluginLoader should be given the context class loader as parent!
modifying jutils
recompiling
signing
I can happily admit: This works! It fixes all problems!
For those who don’t know but try to follow this explanation: The context class loader is to be found via Thread.currentThread().getContextClassLoader() and specifies the class loader that generated the thread. For applications that were started from the commandline this is the same as the SystemClassLoader but for applications that were launched from webstart it is a special classloader.
The usage of the context classloader even fixes the security exception I got when having jinput/jutils installed.
After this long post I hope everyone who was involved understood the problem and how it was solved. If not I will try to explain further.
Finally here is my RFE: Please replace the creation of the PluginLoader in net.java.games.input.Plugins with this:
PluginLoader loader = new PluginLoader(f, Thread.currentThread().getContextClassLoader());