Java web start and resources in Jars.

Started by Eternity, June 01, 2011, 23:28:16

Previous topic - Next topic

Eternity

Hi.

I've got my game to read all resource files from jars. This works fine in eclipse where i added the jar that contains the resources to the build path of my project.

I cant however get it to read the resources from the Jar in java web start. Im guessing there might be something wrong in my JNLP file? (ive never done any of this before btw) Please take a look :D and if its not the JNLP file what else could it possibly be? seeing as it reads frim the Jar just fine when i run it localy.

the source for lwjgl is also compiled into SpheresOfMadness.jar.

<!-- test jnlp file -->
<jnlp
  spec="1.0+"
  codebase="http://www.distantmelody.net/temp/">
  <information>
    <title>Spheres of Madness</title>
    <vendor>DMStudio</vendor>
    <homepage href="http://www.distantmelody.net/"/>
    <description>Spheres of Madness</description>
    <description kind="short">Spheres of Madness</description>
    <icon kind="splash" href="logo.png" />
  </information>
  <security>
    <all-permissions/>
  </security>
  <resources>
    <j2se version="1.6+"/>
    <jar href="SpheresOfMadness.jar" main="true"/>
    <jar href="data.jar"/>
  </resources>
  <resources os="Windows">
    <j2se version="1.6+"/>
    <nativelib href="native-windows.jar"/>
  </resources>
  <application-desc main-class="spheres_of_madness.SpheresOfMadness">
    </application-desc>
</jnlp>


Endolf

What code are you using to get the resources?, webstart fiddles with the classloader, so you will probably want to do
Thread.currentThread().getContextClassLoader().getResourceAsStream(resource)
or something like that depending on if you want the stream or url.

HTH

Endolf

Matthias

From my experience it's best not to use the context class loader at all.

Put the resources in the same (or a sub folder) of one of your classes. Or make a Resources class where your resources are.
Resources.class.getResource("gfx/logo.png");


This works for all cases where you would be able to load/use class too, which makes it very easy to use and low maintenance.

NOTE: Class.getResource() works with relative paths, it can only reliable access resources in the same JAR as the class file.
NOTE: Some tools related to signing / verification have issues with data only JARs, so the above approach also works these issues.

Eternity

Thnx! il try that solution when i get home from work today.

Endolf

Quote from: Matthias on June 02, 2011, 06:51:56
From my experience it's best not to use the context class loader at all.

Ok, so now the poor chap has 2 conflicting views :), do you use webstart?

for further reference, google the context class loader v.s. the current class loader (or something along those lines). See http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html for someone elses view :)

Endolf


Matthias

Quote from: Endolf on June 02, 2011, 07:28:57
...
Ok, so now the poor chap has 2 conflicting views :), do you use webstart?
...
Endolf
Yes - I use Webstart and both signed and unsigned applets (with LWJGL Appletloader). And my approach above has always worked perfectly in all environments.
And I nearly always use getResource() over getResourceAsStream() because this allows me to reference other resources using relative paths.

Endolf

Quote from: Matthias on June 02, 2011, 07:49:31
Yes - I use Webstart and both signed and unsigned applets (with LWJGL Appletloader). And my approach above has always worked perfectly in all environments.
I had troubles waaaay back when I first started with resources, I've used the context classloader ever since, it works perfectly in webstart and when running in eclipse. It's also necessary when doing webapps in JEE land, but that's a different environment :)

Quote
And I nearly always use getResource() over getResourceAsStream() because this allows me to reference other resources using relative paths.

Me too, I just happened to have that example to hand and didn't want to post something that didn't compile (couldn't remember that capitalisation and CBA to look at the javadoc :))

Endolf

Eternity

OK. i placed everything in one jar file and i used Thread.currentThread().getContextClassLoader(). The result is my java web start application runs fine on some pc's but on others it stops finding resources as soon as it creates more than one thread. (the first resource that it loads is a little config file for the engine at wich time no threads apart from the main thread has been created so that still works)

I tried using the main thread to get the contextclassloader regardled of wich thread tries to load something but that didint work either. I unfortenetley have 2 threads that might need to load resources. my main thread that loads small config files and scripts and my resource loader thread that that loads model/sounds/textures etc.

As for the other suggestion. I realy need to be able to work from the root... Else it would just make my life miserable. so adding a blank class to some random package wont do as the path would then become relative to that package. (real pity we cant import from the root anymore!!)

Matthias

You could also try this:
Resources.class.getClassLoader().getResource("path/to/logo.png");

But never use a leading slash ('/') with a class loader.

Endolf

Quote from: Eternity on June 02, 2011, 19:52:13
OK. i placed everything in one jar file and i used Thread.currentThread().getContextClassLoader(). The result is my java web start application runs fine on some pc's but on others it stops finding resources as soon as it creates more than one thread.

That is very strange, I use threads in my application and it loads fine. What jdk, os and architecture are they running on when it fails?, there must be a common factor in where it fails and where it doesn't.

Endolf

Endolf

Also, if you are the one creating the new threads you could always check what the context class loader is on the new threads and compare it to the context class loader on the main thread.

Endolf

broumbroum

open Java configuration panel ->advanced tab, and enable all console tracing. you should see when the classloader is not finding the resources properly.
also you can try <jar download="eager" ...> which will force downloading the jar file on resource loading.

Eternity

It started working on the pc it didint run after wiping the cache and restarting it. seems that somehow it kept on using outdated jars.

Both the Resources.class.getClassLoader() and then Thread.currentThread().getContextClassLoader() solutions work fine.

Thnx for the help! :D