Reading files from an applet

Hello,

I need to make an applet based game, but the problem is the loading. When I put all my images with the class files into one jar file, the file is a little bit over 1,5 MB which might take to long to download for some poeple if I can’t show a progress bar. So my idea was to first download a jar files containing all the class files and a littel bit of pictures to show a loading screen. In the loading screen, I want to download my other jar file, while showing something on screen. But the porblem is that my applet is of course not allowed to download my other jar file from code. How can I do this? I want to create a JarInputStream from a ja file which is located on the same server. I presume I need to download the byte[] from it and create my inputstream from this … but how can I get the byte[] …

Hope someone can help me here (another suggestion on creating a download progress bar is also welcome)

Regards,
Kenzo

Did you considered to make a webstart for your apllet? It will show you progress bar automatically, and it works with jars …

You can force the image jar to be preloaded and have the benefits of the default plug-in progress bar

here is a sample of the expected applet parameters :

Lilian

I know but the problem is that a webstart application doesn’t run “in” a browser, but starts up standalone. Don’t really think they want this … :frowning:

Ahhh… Yes, you’re right.

This works… but I noticed that for big jar’s or slow connections, it looks like the plugin has crashed. People don’t associate this java logo & loading bar with the game datafiles loading but with Java not being able to boot up (we don’t want to have people think Java is slow again ;))

It was possible setting your own background image, which could accompany the progressbar with a loading text… but Sun has mysteriously chosen to drop support for the custom image/progressbar combination since 1.5… only offers a progressbar with the standard Sun loading screen, which will result in the misconception of Java not loading or being very slow.

I outlined an alternative in the JOGL applet post:

[quote]Another way of loading (large) resource files is by downloading the files runtime over an URLConnection with setUseCache enabled. A limitation is that it only caches files with a .jar or .class extension. You can make a zip containing all your images, sound etc and rename it to either .class or .jar. (for jar files you should use URL url = new URL (“jar:” + jarname + “!/”))
Another limitation of this technique is that you can’t monitor progress with caching enabled.

The advantage you have is that you gain more control over what to display as your applet is already up & running without waiting for the JVM archive jars to load…

Now I think of it, it might be possible to overcome the disability to monitor download progress with setUseCache enabled… You can implement your own protocol handler: http://java.sun.com/developer/onlineTraining/protocolhandlers/

What probably happens with setUseCache(true) is the handler streaming the resource to a file upon urlconnection.getInputStream(), it first downloads the whole resource into this file (in the plugincache) and then handles the stream over in one go. Maybe we could override the standard handler and enable reading the progress for the resource->file stream.
[/quote]
So downloading over a urlconnection with setUseCache(true) and the URL (“jar:” + jarname + “!/”)) is enough to download and cache your jar files runtime. You could display a splash screen or whatever you’d like during the download. There might be a hack possible to display your own progressbar (see details in the quote block), but i’ve never tested this. The idea is you can’t monitor the progress with setUseCache enabled is because upon the urlconnection.getinputstream, the protocol handler probably streams the entire conents of the url into a file (for .jar & .class extensions) in the plugin cache. To monitor this caching you could try to subclass the standard protocol handler… it’s worth a shot.

Thijs

Mmm interesting, I’ll also try it in the coming days. It’s always better to have the game displaying something as soos as possible.

Lilian

I’ve looked at the source distribution of Sun, and it seems we should be looking at sun.net.www.protocol.http.HttpURLConnection.java, in the getInputStream() method.

This sourcefile can be found in sun’s private class implementation in the jdk 1.5 source (i’ve downloaded the one with the research license) in the directory j2se/src/share/classes/sun/net/www/protocol/http/

I’ve only looked at it in a rush, but it seems this method first loads an HttpClient.getInputStream and when that one is finished it feeds it to the cachehandler which will eventually put the file into the plugin cache for us. After this is done the inputstream is returned, which is the reason we can’t read progress with urlconnection.getInputstream().read() because this inputstream is available in one sweep after the httpclient.getinputstream, that sun’s implementation of urlconnection uses, is done.

Now we should try to subclass this implementation of HttpURLConnection (if it exists, other JVM’s like the MS JVM obviously won’t use the private sun classes). And extend it a bit with a method like public int getProgress(), which reads the progress of the HttpClient.getInputStream or something.

Thijs

just another thought,

to improve the feedback when downloading the resources with setUseCache(true), we could simply split the big resource jar file into smaller jars (say 10 small jars).

That way, we can provide a progress bar (with an increment step of 10% if splitted in 10 jars) which is much better for the user than wait until a full dowload is complete.

Lilian

Yes, that’s a good solution too.

But it will only work for jars containing a lot of small files, that you can split up. If you’d have fx a 1 mb file in your resource jar, it would still look like it has frozen…

Thx for the help so far. But I am running into a little noob problem here I think. I have the following code:


url = new URL("jar:http://users.pandora.be/kozen/SimpleTest/Kungfu/images.jar!/");
JarURLConnection juc = (JarURLConnection)url.openConnection();
juc.setUseCaches(true);
JarInputStream jis = (JarInputStream)juc.getInputStream();

but this always gives me the following exception:
java.io.IOException: no entry name specified
at sun.net.www.protocol.jar.JarURLConnection.getInputStream(Unknown Source)
at menu.LoadingScreen.run(LoadingScreen.java:197)
at java.lang.Thread.run(Unknown Source)

what can I do about it, and can I directly link to a jar which is on a HTTP server like this from an applet which is online, or do I have to do something special for this?

Regards,
Kenzo

A jar url is the path of the jar, followed by a ! followed by the entry name of the Jar entry you want to load.

This is hiding in the javadocs somwehere…

thx but what if my jar doesn’t contain an entry point and only images … ? Do I have to give the path to all the images then ?

[quote]thx but what if my jar doesn’t contain an entry point and only images … ? Do I have to give the path to all the images then ?
[/quote]
You might want to use juc.getContent()
The JarUrlConnection will return an object which will be a JarFile if you won’t explicitly point at an entry (by closing your jarurl with !/).

Jars by definitiion are made up of Entries.

If you dont have entries, you don’t have a JAR file, your just lying about it in the extension and should not try to use JarURLConnection to get it, just use URLConnection.

    If you want to keep it simple ( ie java 1.1 ) just load in your code in one archive then open up the images jar file as a zipfile and for each zip entry:

   int offset=0;
    int length=(int)zipEntry.getSize();
   
    byte[] imagedata = new byte[length];
	
	try{
		while(length>0)
		{
			int done = inputstream.read(imagedata,offset,length); 
			offset+=done;
			length-=done;
			//update loading bar with amount of bytes done
		}
	}catch(Exception e){}
	
	
	Image image = Toolkit.getDefaultToolkit().createImage(imagedata);

This will work for .gif and .jpg.
The down side of this is that java plugin will not cache the jar file, although MSJVM will.

If you dont mind not being 100% java, you could also load audio this way using sun.audio.