This discussion is archived
2 Replies Latest reply: May 29, 2012 11:02 AM by 839063 RSS

Java 7 JWS URLConnection caching

839063 Newbie
Currently Being Moderated
We have a Java Web Start deployed app built against JDK 1.6.0_27 that has had some quirks on users systems running JRE 1.7. One of the issues seems to be related to URLConnection caching.

We have a large resource jar that we manage the downloading and updating of because the JWS APIs to do so proved to be troublesome. We use an HttpURLConnection to check the state of the file and download it, and we track the freshness using a Properties file with some key HTTP headers (HTTP_DATE,HTTP_ETAG,HTTP_CONTENT_LENGTH,HTTP_LAST_MODIFIED). To check if we need to download an update, our code is simply:

boolean hasUpdate() {
boolean hasUpdate = true;
try {
Properties oldProps = loadPropsFromFile();
HttpURLConnection = (HttpURLConnection) jarURL.openConnection();
conn.setDoOutput(true);
if(haveCacheFile()) {
setHeadersFromCache(oldProps,conn);
}
if(conn.getResponseCode() == 304) {
hasUpdate = false;
}
} catch (IOException ex) {
// do stuff
}
return hasUpdate;
}

When an update is to be downloaded we also use the cached HTTP headers to make the request, and with a 200 response we cache the new headers and write the response out to the file. We then load and use the resource jar. If we messed up badly we get a zip file exception.

The loadPropsFromFile simply loads the previously cached headers from the .props file and does a little validation. The setHeadersFromCache takes those properties and sets proper connection request properties based on the cached headers. This has worked very well in Java 6.

In the Java 7 case things seem to go wrong with the initial download. Where the resource jar is 33351185 bytes on the server and in the server logs and in the packet capture and in the file size and cached headers in the Java 6 cases, the Java 7 Web Start (javaws.exe) run will write a file and cache headers with a Content-Length of size 33359617. The web server claims it sent the same bytes to both clients, but they end up different. Windiff shows mostly extra stuff at the end of the zip/jar, stuff that looks like INDEX data but there are a couple minor changes starting from the beginning.

When the program is launched subsequent times with Java 7 JWS (javaws.exe 10.4.0.22-fcs in my test setup) hasUpdate returns true because conn.getResponseCode() returns 200 even though the server sends back 304 (as verified by the server log and packet captures.) If I download the jar files and launch the program with Java 7's java.exe (version 1.7.0_04), conn.getResponseCode() returns 304 as expected.

I setup Netbeans 7.0 running against JDK7 and ran the code in debug and found the same issue. If I ran normal, getResponseCode returns 304 as expected, but if I changed to run under Web Start (local codebase) it would return 200.

I was suspecting that caching had changed in Java 7 but was thrown off by it working everywhere except when run as a web start application until I came across a Stack Overflow post titled "Java Webstart and URLConnection caching API" [0] and the "URLConnection caching API" [1] page it pointed to, specifically this last statement:

There is no default implementation of URLConnection caching in the Java 2 Standard Edition. However, Java Plugin and Java WebStart do provide one out of the box.

So, I put conn.setUseCaches(false) into my hasUpdate and downloading code. Now even in the Java 7 Web Start case (in Netbeans) I download, write and header cache 33351185 bytes and I get the expected 304.

Now, perhaps I should have always been using setUseCaches(false) because I'm attempting to manage caching in my own way. Still it appears something has changed with Java 7's web start that not only returns false responses to the response code, it also changes the bytes written to the disk (at least in this resource jar case). The change doesn't appear to affect my ability to open the jar file, but still, it is a change.

Has anyone else experienced this? Is a list of Java 7 / JWS gotcha's starting to get compiled anywhere?

[0] http://stackoverflow.com/questions/8908826/java-webstart-and-urlconnection-caching-api
[1] http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-cache.html
  • 1. Re: Java 7 JWS URLConnection caching
    817614 Explorer
    Currently Being Moderated
    Sounds like a bug. Could you post the code where you save the specified old header values?
  • 2. Re: Java 7 JWS URLConnection caching
    839063 Newbie
    Currently Being Moderated
    This is in my SwingWorker.doInBackground() to download the file

    if(conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
    Properties props = new Properties();
    props.setProperty("URL", jarURL.toString());
    String value;
    // CACHED_HEADERS is an array of headers we are interested in, mentioned earlier
    for(int i=0; i<CACHED_HEADERS.length; i++) {
    value = conn.getHeaderField(CACHED_HEADERS);
    if(value != null) {
    props.setProperty(CACHED_HEADERS[i], value);
    }
    }
    // in a do/while & try/catch open output streams and write out jar file, cacheFile
    // then write out Properties file
    out = new FileOutputStream(propsFile);
    props.store(out, cacheFile.getName() + " HTTP Headers cache");
    out.close();
    out = null;

    The results look fine when run against javaws on Windows, Mac and Linux computers with Java 6 and not fine with Java 7 on Windows where HTTP_CONTENT_LENGTH appears to be modified, the file content is tweaked and the response codes are not what the server returns, all seemingly due to caching.