Problem with JNLP and JInput

I am totally conused.

Are you saying the problem is that JWS prevents the scan for plug-in fiels from finding plugins? Or that JWS permissions are preventing the native part of the plugin from being loaded? (The excpetion you quoted sounds lke the latter-- that a plug-in IS in fact being found but that JWS is not allowing the link of the native JNI library portion.)

The latter should be no different for JInput then for JOGL. If there is a diference, we need to get clear on what it is and why JWS doesnt like it.

Yes its the latter one. The exception is generated when the plugin class is loaded into the jvm and the static initializer attempts to load the native library. I am a newbie in Java’s security management but I can cleanly see a difference between the loading mechnisms of JInput and JOGL:

A program is started via webstart. The JNLP file specifies jogl.jar as jar-ressource and its native library in the native section. With this information Webstart can permit its security managers loading of the native code.

Now for JInput: Due to the plugin design the plugin-jar and its native counterpart are not in the classpath of the runtime environment. They were added by jutils which belongs to the application.
I think that webstart considers the application untrusted even if it was signed and the user confirmed his/her trust for it.

This is only speculation but it makes sense for me. I will try to setup some configurations on my machine to see if I can get around this security restriction. I’ll tell you if I am successful …

— EDIT
The Security Exception occurs only when the plugin and the jinput/jutil stuff is installed as extension. Regardless whether they are available through JNLP, too.

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());

Ah. I see. The issue here is that the plugin stuff specifically requires the plug-in’s DLL to be in the same folder as the Plug-in’s JAR. This is to prevent name clashes in DLL names between different plug-ins written by different people at different times.

I’m not sure how to change this in a way that preserves the intent and works for JWS. Really, its a limitation in JWs thats the issue.

I’ll try to get the JWS guys involved and see what we can come up with.

BTW guys, I’m going to be off in Wisconsin from Oct 3 through Oct 13 for my little brother’s wedding. I’ll try to stay connected to you guys but my posting may be a bit spotty and my resources limited til I get back.

JK

Okay, I talked to the JNI guys.

I can add a property that you can set that will turn off the "getLibrary’ override in the class loader for plug-ins. This should let JWS go where it wants to for the library.

HOWEVER realize that this creates a potential problem for using independantly develoepd plug-ins together.

The reason why “getLibrary” currrently points to the same directory as the one in which the plug-in jar is found is in order to make it possible to use plug-ins with conflicting names. If you turn that off, then if two plug-in writers both named their DLLs something stupid like “input.dll” you will be unable to use both plug-ins at the same time.

Or in the more general case, any app that uses the plug in library which turns off this feature will not be able to use DLLs with name conflicts together. (This is less likely a proiblem for JInput as it might be for somethign like an image mainpulation package or other “framework” type app that might have a great many plug-ins.)

That clear?

JK

Well? is everyone happy with this solution? If so I’ll implement it.

Works for me.

I regret it doesn’t work. Special property was set. Plugin was delivered by JNLP as nativelib. The following code was tried:


print(System.getProperty("net.java.games.util.plugins.nolocalnative"));
true

bsh % loader = new PluginLoader(new File("unused"));
bsh % print(loader.findLibrary("dxinput"));
null

bsh % contextLoader = Thread.currentThread().getContextClassLoader();
bsh % print(contextLoader.findLibrary("dxinput"));
E:\Dokumente und Einstellungen\RoB1\Anwendungsdaten\Sun\Java\Deployment\javaws\cache\http\DtheBohemian.dyndns.org\P80\DMjaws\RNjinput-plugin-win32.jar\dxinput.dll

The last command shows that finding the native library with the context classloader works. It seems that the current implementation isn’t using its parent (which IS the context classloader) properly.

When plugin is already installed in lib/controller everything works fine as stated in my last post.

Found out the following:
PluginLoader is using super.findLibrary() to retrieve the library’s path when the special property is set. That’s nice but none of PluginLoader’s superclasses is delegating findLibrary to its parent.
To make things even worse the only implementation of this method exists in ClassLoader itself and it simply returns ‘null’. Weird: It is impossible to call parent.findLibrary because it is ‘protected’.

[In my previous post this was done by BeanShell using Reflection and disabled access restrictions.]

Hmm.

Well, if the proper parent routine returns null then the logicc inside of the classloader must be “if getLibrary returns null, then look in the default places.”

I’m not entirely sure thats what we want. though, as I suspect doing so would defeat JWS’s security restrictions.

Is it really not working if you put the lib file in the native declarations in the JNLP? Thatw as my itnent, to make it work like all other JNLP apps with native code, which are required to do that.