Problem with JNLP and JInput

I want to apply webstart functionality for my JInput based application (the JInputTester you may know) and cannot get around the problem with the native plugins.

When not using JInput as an extension the file structure has to be this way (I think that because I have tested it. Any documentation on that?)

appDir:
application.jar
jinput.jar
jutils.jar
controller [containing platform dependant files]

This assumes to have jinput.jar and jutils.jar in the classpath (specified by the jar’s manifest and/or the JNLP file).

When webstart downloads everything and my application launches there’re no problems but it cannot find any devices because of missing plugin libraries.

Is there any solution to this?

Have you tried bundling the controller folder into a JAR and including that in the Web Start resources?

Check the jutils source to see how plugins are loaded and it might help.

Bundling the folder and including it as a nativelibrary in the resources sections doesn’t work because JNLP specification says the files have to be in the root of the jar. I checked webstart’s cache folders and nothing was extracted.

I had the idea to set the property jinput.controllerPluginPath to “.” and put the plugin files at the root of the jar. This doesn’t help as I found out that the property user.dir which is used by DefaultControllerEnvironment is set to everything but not the real path webstart is using for its file caching.

Maybe I have to admit that webstart generates a subfolder for jar files which should contain native libs. This makes things even worse because other JNLP clients may not do it this way. So special workarounds for webstart are not a good idea …

Well, now I have better insight on how JInput scans for plugins but I can say that I am not very happy with that. Why ‘user.dir’ ?

Problems may also arise when no webstart is in use:
One might start a downloaded application (which contains the application jar, jinput.jar/jutils.jar and a controller subfolder) from a different location than the application folder and will not find any input devices because jinput did not find its plugins.

Isn’t there any other method to load the plugins that uses the existing classpath?

I think the solution is to use WebStart to launch an extension installer that installs the jinput stuff directly into the JRE extensions folder. I think the “controller” folder can go in the JRE lib folder right?

But, I agree it would also be nice if it could be worked around so the JRE folders don’t need to be touched and it can still work with Web Start.

This looks very bad: I have tried some tricks and hacks to get it working with webstart (mainly trying to get the absolute path of the folder where webstart saves the native libs) but it doesn’t work because any jar that is inside the containing the native library is not added to the classpath …

Even when the plugin is already installed on my machine webstart applications are not allowed to do the loadLibrary call. This exception proves that:

Caused by: java.security.AccessControlException: access denied (java.lang.RuntimePermission loadLibrary.dxinput)
at java.security.AccessControlContext.checkPermission(Unknown Source)

  at java.security.AccessController.checkPermission(Unknown Source)

Edited after having seen swpalmers recent post:
An extension installer may have the problem I stated above, too. Or am I wrong?

The installer itself must be signed so it can write to the JRE folders. But after that the Web Start apps that need jinput should just work, and they should never need to download and install Web Start again unless there is an update. I think the jinput classes will be trusted once they are in the JRE folder So loading the plugin DLLs shouldn’t be a problem.

The exception in my last post was done when the plugin was already installed in ${jdk.home}/lib/controller. Maybe this is a bug in webstart because I cannot find any information in the JNLP specs that is saying that it is not allowed to load native libraries when ‘all-permissions’ are granted.

A WebStart app definitely IS allowed to load native DLLs when all-permissions are granted. Of course for that to work that JAR must be signed too.

You may try this:
http://page.inf.fu-berlin.de/~rschuste/java/jinputtesterFU.jnlp

(the link has to be put into the address line of webstart. don’t know why it doesn’t start the application properly. the admins say the server has registered the MIME type …)

I tried it and there was no error in the console window but it obviously didn’t work because it shows no devices.

P.S. Make the application exit when the window is closed. It is really annoying to have to go killing processes as it is now.

Oh, I assumed to test it with installed plugins. Please install the plugins for the JRE that runs webstarted applications and have a look at the strange exception JInputTester then throws.

Regarding the exit-Feature: When everything works well JInputTester ends all threads so the VM shuts itself down. I wonder what the official recommendation is explicitly or implicitly shutdown the VM?

Ok, I ran it from the command line in my home folder where the “controller” folder is. It seems that the plugin JAR does not have permission to run native code.

Java Web Start 1.2 Console, started Wed Sep 24 11:53:35 EDT 2003
Java 2 Runtime Environment: Version 1.4.1_01 by Apple Computer, Inc.
Logging to file: /Users/scottpalmer/webstart.log
Scanning jar: HIDWrapper.jar
Examining file : META-INF/
Examining file : META-INF/MANIFEST.MF
Examining file : net/
Examining file : net/java/
Examining file : net/java/games/
Examining file : net/java/games/input/
Examining file : net/java/games/input/InputController.class
Examining file : net/java/games/input/InputControllerElement.class
Examining file : net/java/games/input/OSXEnvironmentPlugin.class
Found candidate class: net/java/games/input/OSXEnvironmentPlugin.class
Adding class to plugins:net.java.games.input.OSXEnvironmentPlugin
Examining file : net/java/games/input/OSXGamepad.class
Examining file : net/java/games/input/OSXJoystick.class
Examining file : net/java/games/input/OSXKeyboard.class
Examining file : net/java/games/input/OSXMouse$BallAxis.class
Examining file : net/java/games/input/OSXMouse$BallImpl.class
Examining file : net/java/games/input/OSXMouse$ButtonImpl.class
Examining file : net/java/games/input/OSXMouse$ButtonsImpl.class
Examining file : net/java/games/input/OSXMouse.class

Then:

java.lang.ExceptionInInitializerError
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:274)
at java.lang.Class.newInstance0(Class.java:306)
at java.lang.Class.newInstance(Class.java:259)
at net.java.games.input.DefaultControllerEnvironment.scanControllersAt(DefaultControllerEnvironment.java:183)
at net.java.games.input.DefaultControllerEnvironment.scanControllers(DefaultControllerEnvironment.java:164)
at net.java.games.input.DefaultControllerEnvironment.access$000(DefaultControllerEnvironment.java:57)
at net.java.games.input.DefaultControllerEnvironment$1.run(DefaultControllerEnvironment.java:108)
at java.security.AccessController.doPrivileged(Native Method)
at net.java.games.input.DefaultControllerEnvironment.getControllers(DefaultControllerEnvironment.java:106)
at robs.jinput.JInputTester.(JInputTester.java:24)
at robs.jinput.JInputTester.main(JInputTester.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at com.sun.javaws.Launcher.executeApplication(Launcher.java:785)
at com.sun.javaws.Launcher.executeMainClass(Launcher.java:747)
at com.sun.javaws.Launcher.continueLaunch(Launcher.java:632)
at com.sun.javaws.Launcher.handleApplicationDesc(Launcher.java:359)
at com.sun.javaws.Launcher.handleLaunchFile(Launcher.java:177)
at com.sun.javaws.Launcher.run(Launcher.java:145)
at java.lang.Thread.run(Thread.java:554)
Caused by: java.security.AccessControlException: access denied (java.lang.RuntimePermission loadLibrary.jinput)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:270)
at java.security.AccessController.checkPermission(AccessController.java:401)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:542)
at java.lang.SecurityManager.checkLink(SecurityManager.java:834)
at java.lang.Runtime.loadLibrary0(Runtime.java:782)
at java.lang.System.loadLibrary(System.java:832)
at net.java.games.input.OSXEnvironmentPlugin.(OSXEnvironmentPlugin.java:298)
… 25 more

What I’m not sure is if this is a bug in Web Start, or a feature that we aren’t using properly… e.g. The classloader that Web Start uses to access the apps Jars probably has permission to load and run native code, and if the plugin is in the JRE folders it might get permission to load native code, but as it is the plugin Jar is in a “unknown” location in terms of what Web Start grant permissions to… well that’s my theory so far…

Where are the jinput installation instructions? I’ve got to take a closer look and try putting the plugins in other places.

The installation instructions are in the APIDOC for ControllerEnvironment. The name ‘controller’ for the plugin library can be overriden by setting the property jinput.controllerPluginPath. The last one isn’t documented anywhere. I found it in the sources of DefaultControllerEnvironment.

— EDIT:

I have found an easy way to come around the problems but it cannot considered to be a solution because I modified the DefaultControllerEnvironment.
It looks for the value of the property ‘jinput.plugin.class’ and instantiates one if set. I implemented this as an alternative: When the property is not set the usual behaviour comes into play.

I really don’t like modifying the library to my needs but currently this is the only way to get things working with webstart. Finally there would be a problem when someone has jinput.jar installed as an extension …

Okay,

I’m still trying to fully understand the issue here.

Hardwiring the plugin class, even in a property, is definitely NOT the right answer as it violates the spirit and design of the plug-ins. (That being that the user code should not need to be aware of what the underlying plugins are.)

I can easily see a permissions issue is as JWS should NOT allow arbitrary jars to run arbitrary downloaded native code-- this would be a bad security hole the size of a medium sized cement truck.

The solution to the perimissions issue is either:
(A) Sign your code so users have some confidence in granting you the access you request
(B) As others have said, use a signed installer to install JInput into the JRE itself where it can run with bootclasspath permissions.

I’m kind of curious. Don’t you have this same issue with JOGL as well? If not, why not?

I have no problems with JOGL because it conforms cleanly to what can be done with webstart. I sign all the jars I want the JNLP client to process and thats it. Or simply said: JOGL doesn’t use the plugin mechanism.

For JInput the problems are: Access to the plugin is not possible because the two possible configurations for this do not work:
(I take the win32 plugin as an example)

  1. Config: dxinput.jar dxinput.dll bundled in jinput-plugin-win32.jar (signed as well) and specified in the JNLP as nativelib.
    Problem: How to tell DefaultControllerEnvironment to search in a directory called:
    “E:\Dokumente und Einstellungen\RoB1\Anwendungsdaten\Sun\Java\Deployment\javaws\c
    ache\http\Dpage.inf.fu-berlin.de\P80\DM~rschuste\DMjava\RNjinput-plugin-win32.jar” - this is specific to my system and to the JNLP client implementation. Theres no way to set “user.dir” at runtime to this.

2.) dxinput.jar and dxinput.dll pre-installed (by hand) in jre/lib/controller - the only directory that can be found by DefaultControllerEnvironment safely (optionally signed).
Doing things this way causes the exception swpalmer and me have seen.

I really did not want to modifiy the DefaultControllerEnvironment but after endless hours of trying & testing the hack was my last hope.

The only thing I say: Please test the application and have a look yourself.
If you want to see the code before starting webstart it is available here:
http://page.inf.fu-berlin.de/~rschuste/java/jinputtester.jar

(There is an obsolete class inside that was targeted to find out the path)

[quote]I’m still trying to fully understand the issue here.
[/quote]
The Plugin support of JUtils doesn’t work with Web Start for some reason. Even if the plugin & native code is already downloaded and installed, an app that is started with Web Start can’t load them if they try to load native code.

I’ve filed an issue with JUtils.

[quote]I can easily see a permissions issue is as JWS should NOT allow arbitrary jars to run arbitrary downloaded native code-- this would be a bad security hole the size of a medium sized cement truck.
[/quote]
That’s not it. Even with a signed jar, or having the plugins already installed in the JRE lib and ext folder the native code will not load.

[quote]The solution to the perimissions issue is either:
(A) Sign your code so users have some confidence in granting you the access you request
(B) As others have said, use a signed installer to install JInput into the JRE itself where it can run with bootclasspath permissions.

I’m kind of curious. Don’t you have this same issue with JOGL as well? If not, why not?
[/quote]
A & B don’t work.

As TheBohemian said above JOGL doesn’t use the plugin stuff from JUtils.

Hm. The Jutil plugin stuff itself has no native code.

Can you email me the precise error? or better yet point me at a small test case? I’l ltry to promote this to the top of my list.

Thanks

JK

[quote]Well, now I have better insight on how JInput scans for plugins but I can say that I am not very happy with that. Why ‘user.dir’ ?
[/quote]
Because we wanted to have a way to load them relative to the game execution directory and that seemed the logical way.

I’d be happy to change this, lets get a consensus on what we want instead.

One solution would be to take the “user.dir” out of the code and instead define an escape sequence that means “working dir” or whatever is equivalent.

This seems a bit kludgy to me though. is there a cleaner way to do this that will make JWS happy?

JK

When I made this complain I thought that using the plugin would be possible if only WS has a way to find them. Then came the exception …

JUtil uses really no native code but for JInput the initialization of the plugin classes causes the call to System.loadLibrary(). And that is the exact location of the exception.

Win32:
Caused by: java.security.AccessControlException: access denied (java.lang.RuntimePermission loadLibrary.dxinput)

MacOS:
Caused by: java.security.AccessControlException: access denied (java.lang.RuntimePermission loadLibrary.jinput)

Hi
Have you tried setting the property controllerPath (i think thats it, i’m not at home so I can’t check) to the directory you wish to load jinput from?

Cheers

Endolf