Use LWJGL in a web app

Started by nuvolanotturna, December 15, 2010, 10:41:43

Previous topic - Next topic

nuvolanotturna

Hi, i'm trying to do something I'm not sure I can do :P

I would like to use LWJGL libraries in a server side application deployed on Tomcat Application Server. It kind of works, but when I reload the application I get this error:

java.lang.UnsatisfiedLinkError: Native Library /Applications/NetBeans/apache-tomcat-6.0.26/bin/liblwjgl.jnilib already loaded in another classloader


I'm aware of the problem: the jvm allows to load the same natives only once in the same jvm and so the class that calls System.loadLibrary(String) should be loaded by a classloader that is not affected by reloading the web application itself (http://wiki.apache.org/tomcat/HowTo#I.27m_encountering_classloader_problems_when_using_JNI_under_Tomcat).

Do you think there is any workaround for this problem?

Thanks for any help
Eve

Matthias

One work around would be to put lwjgl.jar in the classpath of the app container itself instead of including it in your application.

While LWJGL's GLxx classes are thread safe and can be used from several threads - it is optimized for single threaded use.
But classes like Display, Mouse and Keyboard are single instances - so you can't use Display.create() from different threads to create 2 displays.

There may also be issues running LWJGL in a headless environment (eg as a service in a *nix system).

Matzon

Kappa has a "fix" for unloading natives - its a hack, beware :)

/**
	 * Unload natives loaded by a different classloader.
	 *
	 * Due to limitations of the jvm, native files can only
	 * be loaded once and only be used by the classloader
	 * they were loaded from.
	 *
	 * Due to the way applets on plugin1 work, one jvm must
	 * be used for all applets. We need to use multiple
	 * classloaders in the same jvm due to LWJGL's static
	 * nature. I order to solve this we simply remove the
	 * natives from a previous classloader allowing a new
	 * classloader to use those natives in the same jvm.
	 *
	 * This method will only attempt to unload natives from a
	 * previous classloader if it detects that the natives have
	 * been loaded in the same jvm.
	 *
	 * @param nativePath directory where natives are stored
	 */
	private void unloadNatives(String nativePath) {

		// check whether natives have been loaded into this jvm
		if (!natives_loaded) {
			return;
		}

		try {
			Field field = ClassLoader.class.getDeclaredField("loadedLibraryNames");
			field.setAccessible(true);
			Vector libs = (Vector) field.get(getClass().getClassLoader());

			String path = new File(nativePath).getCanonicalPath();

			for (int i = 0; i < libs.size(); i++) {
				String s = (String) libs.get(i);

				// if a native from the nativePath directory is loaded, unload it
				if (s.startsWith(path)) {
					libs.remove(i);
					i--;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

http://java-game-lib.svn.sourceforge.net/viewvc/java-game-lib/trunk/LWJGL/src/java/org/lwjgl/util/applet/AppletLoader.java?revision=3435&content-type=text%2Fplain

nuvolanotturna

It works! :) I should have thought of that! :P
Thanks :)

Btw I'm aware of the issues I can run into with this application. Actually the goal is just to render offscreen some 3d model and show images on a web page. I'm not sure I'll be able to do that but I'm trying :)



Thanks for the hack also! :)