Preparations..

This is Tomcat not Apache, so no .htaccess. Tomcat is only really used for Servlet development. I have attached a zip of my test code. Note that I have provided a .jar file for the applet because otherwise the webserver complains. However it is an empty file, so if the applet loads, it must have been the pack200 file that was served.

The attached Zip goes in the WebApps directory under TomCat. I had to rename it to .jar as .zips are not allowed attachments. It should still open Ok in winzip or 7-zip.

Incidentally, the documentation for the JNLPdownloadservlet is at:
http://download.oracle.com/javase/1.5.0/docs/guide/javaws/developersguide/downloadservletguide.html

Incidentally, if you want to use Apache, this guy has pretty much caught the nub of the problem:

http://www.thrysoee.dk/pack200/

[quote]Can you guys maybe try some old app in my compile-and-shrink app, to see whether my pack200 test htmlpage works reliably on a wide range of browsers?
[/quote]
Riven,

Your Compile-And-Shrink service is absolutely brilliant. We all owe you a debt of gratitude for providing it.

I created some simple applets to test it out. If I post the binaries that it produces onto my web server, I can download and run the pack200 applets without a problem on a PC. However, the Compile-And-Shrink test HTML pages never worked for me.

That said, please do not modify Compile-And-Shrink or at least provide a link to a mirror if you intend to take it down for enhancements. I can live without a working HTML test page. :slight_smile:

Hmmm… some results seem a bit too small;

S.normal.7z.pack.gz => 2825 bytes => test
S.progrd.7z.pack.gz => 348 bytes => test
S.normal.kz.pack.gz => 2694 bytes => test
S.progrd.kz.pack.gz => 332 bytes => test
S.normal.bj.pack.gz => 2717 bytes => test
S.progrd.bj.pack.gz => 328 bytes => test

And all the likely looking tests I tried threw ‘class not found’ - something not quite right? (FF & XP).

Interesting, zeroone. Operating system, browser vendor, browser version, JRE version please?

Alan_W,

Your HTML page contains this applet tag:

<APPLET archive="falcon4k.jar" code="F.class" width=600 height=400></APPLET>

My test HTML pages are slightly different. Below, I took the fields from your applet tag and introduced them into mine to illustrate the difference:

<APPLET archive="falcon4k" code="F.class" width=600 height=400><param name="java_arguments" value="-Djnlp.packEnabled=true" /></applet>

I leave the file extension of the archive off, which in my case is actually falcon4k.pack.gz (as produced by Riven’s Compile-And-Shrink service). Also, I had to introduce the packEnabled parameter.

Maybe your HTML difference is the secret. Then again…

[quote]Note that I have provided a .jar file for the applet because otherwise the webserver complains. However it is an empty file, so if the applet loads, it must have been the pack200 file that was served.
[/quote]
Can you explain the purpose of the empty jar file? So, you have the pack200 file and a jar file? How does the web server know what to deploy and when?

This is outrageous! I can confirm it stopped working. I haven’t touched it since last year, and it worked perfectly fine.

The packenabled flag was introduced in Java 1.6 (was it at u10 - I can’t remember.

The way to work with Java 1.5 is that you write the html to request the plain jar. The server then inspects the http headers, realises that java is can decode pack200 and serves the .gz file instread

[quote]Interesting, zeroone. Operating system, browser vendor, browser version, JRE version please?
[/quote]
Riven,

I am running 64-bit Windows 7 Home Premium with Internet Explorer 8. My JRE is version 6 update 20 (1.6.0_20-b02).

See my prior post. A slight tweak to the HTML may help. In fact, I actually insert a version number after the archive name (still with no file extension):

<APPLET archive="falcon4k?version=123" code="F.class" width=600 height=400><param name="java_arguments" value="-Djnlp.packEnabled=true" /></applet>

If you change the version number, it forces the Java Plugin to re-download the archive file. Otherwise, it tends to launch a cached version.

[quote]This is outrageous! I can confirm it stopped working. I haven’t touched it since last year, and it worked perfectly fine.
[/quote]
Can you document how it works? Can we setup a mirror service?

[quote]The way to work with Java 1.5 is that you write the html to request the plain jar. The server then inspects the http headers, realises that java is can decode pack200 and serves the .gz file instread
[/quote]
Alan_W,

Wow! That’s pretty amazing. I didn’t realize that the HTTP request header contains enough information to enable the server to make that decision. I guess the web browser presents the applet tag to the Java Plugin and the plugin makes the request for the jar on the browser’s behalf, passing in information about the plugin (and possibly the browser also) in the request header. Then, the plugin must recognize that it receives a gz file instead of jar and it carries out the appropriate decompression actions.

How have things changed with Java 6?

I fixed it. It was entirely my fault. Due to some realtime gzip feature I added to my http server, “Content-Encoding” was cleared if I turned off the gzip-ing. Silly me, what was I thinking!

Can everybody try again?

http://indiespot.net/app/java-four-kay-test?task=html&resource=49c5cf2a366148c8eb4d229fbeb0a81b.6&className=W

For some reason, the plugin requests the archive 3 times, but it works.

In a nutshell

  1. Browser asks webserver for Falcon4k.jar and sets the following http headers:
    Accept-Encoding = “pack200-gzip, gzip”
  2. Web server has special add on code and looks for “pack200-gzip” in the header Accept-Encoding
  3. Server then sends back the .gz file instead of the .jar file with:
    Content-Encoding = “pack200-gzip”

Note that these http headers are case sensitive.

You can make this more complex and serve up gzip files as well if you are keen

If you try to do this in .htaccess you need one of the following Apache mod add-ons
mod_negotiation
mod_rewrite

I think there is also some facility for multi file type associations that might have some mileage.
Edit: It was Multiview - I found the article I vaguely remembered - It’s a bit of a kludge though
http://sixlegs.com/blog/java/pack200-apache.html

Of course this can be done in PHP

Alan_W,

Thanks for the info. I am hosting my web page on an Apache server and I know little about how to configure it. I copied-and-pasted some stuff to my .htaccess to make it work, but I really don’t understand what any of it means:

AddType application/x-java-jnlp-file .jnlp

# Return the right mime type for JARs
AddType application/x-java-archive .jar
# Enable type maps
AddHandler application/x-type-map .var
Options +MultiViews
# Tweak MultiViews - this line is for
# APACHE 2.0 ONLY!
MultiViewsMatch Any

<Files *.pack.gz>
  # Enable the Content-Encoding header for .jar.pack.gz files
  AddEncoding pack200-gzip .jar
  # Stop mod_gzip from messing with the Content-Encoding
  # response for these files
  RemoveEncoding .gz
</Files>

What do those mod add-ons do? How do I get them? I am not hosting stuff locally; so, I may not be able to install them. Also, I don’t know PHP. Is there some PHP trick that can solve these deployment problems?

[quote]I fixed it. It was entirely my fault. Due to some realtime gzip feature I added to my http server, “Content-Encoding” was cleared if I turned off the gzip-ing. Silly me, what was I thinking!

Can everybody try again?
[/quote]
Riven,

I just tested it. It works perfectly. Thanks for fixing it.

Surely you can port this to PHP:


         File file;

         String acceptEncoding1 = request.getHeader("Accept-Encoding");
         String acceptEncoding2 = request.getHeader("accept-encoding");
         String acceptEncoding = acceptEncoding1 == null ? acceptEncoding2 : acceptEncoding1;

         if (acceptEncoding != null && acceptEncoding.contains("pack200-gzip"))
         {
            response.setHeader("Content-Encoding", "pack200-gzip");

            file = new File(JavaFourKayShrinkService.GENERATED_FILE_BASE, resourceName + ".pack.gz");
         }
         else
         {
            file = new File(JavaFourKayShrinkService.GENERATED_FILE_BASE, resourceName + ".jar");
         }

         System.out.println("serving: " + file.getAbsolutePath() + " [exists: " + file.exists() + "]");

         if (file.exists())
         {
            response.setStatusCode(StatusCode.OK);
            response.setKeepAlive(true);
            response.setTransferEncodingChunked(true);
            response.setContentType("application/x-java-archive");
            response.stream(new FileInputStream(file), file.length());
         }
         else
         {
            response.setStatusCode(StatusCode.NOT_FOUND);
            response.setKeepAlive(true);
            response.setTransferEncodingChunked(true);
            response.setContentType("text/plain");
            response.setContent("file not found: " + file.getName());
         }

I’m not great on Apache myself. The Multiviews feature attempts to guess a suitable file extension based on the requested encoding, when there isn’t a direct match to the requested file extension. See the link I added to me previous post. The trick appears to rename the .jar to something else, as otherwise Multiviews never comes into play. Thats all from me for the moment, as I think the writers in the links know what they are doing far better than me. Personally, I liked the Mod-Rewrite solution (see link a few posts back)

Riven,

If I understand your servlet code correctly, it checks the request header to determine if the plugin running in the browser accepts pack200. Then, it delivers a .pack.gz if it does. Otherwise, it delivers a .jar file. Is the .jar file a normal, non-pack200 jar? Meaning, you have to maintain a pack200 version and a normal version on the server?

On a side note, I’ll research PHP. I can’t run servlets on my web server unfortunately. Thanks for the snippet.

Yes. See here for the worst spec ever.

Riven,

Thanks for the link. I think I found that before and it scared the hell out of me. :slight_smile:

By the way, does your animated image on this forum change based on the name of the user who logged in? How did you do that?