Peter Jones wrote:
What is not obvious from your above prescription is, in the event that the attempt to retrieve the first URL throws an IOException, whether PreferredClassLoader.isPreferredResource should return false or throw an IOException. If the failure indicates that that referenced JAR file itself definitely does not exist (like because the HTTP server responded with 404), then isPreferredResource should return false, so that class loader delegation can proceed. But if the failure is less definite about the JAR file's existence, then isPreferredResource should throw an IOException, because perhaps it was the deployer's intention that the class or resource be preferred and thus it would be wrong for class loader delegation to succeed just because of a transient communication failure.
Thank Peter, I agree with the current conclusions made by the code in PreferredClassLoader so I don't want to change that behavior. What I would like to add (and not replace) is some logic that would try first to get a definite answer about the existence of a PREFERRED.LIST that doesn't by-pass a JAR file cache (i.e. use the "jar:" protocol). If that succeeds we are happy (see below), if it doesn't succeed we fall back to the current logic. Succeeding is defined as JarURLConnection.getManifest() for the URL jar:http://host/download.jar!/ *not* throwing an IOException, result can either be a Manifest object or null. When JarURLConnection.getJarEntry() for the URL jar:http://host/download.jar!/META-INF/PREFERRED.LIST throws a FileNotFoundException we know for sure that there is no PREFERRED.LIST (the first call succeeding that means the JAR file is locally available as result of the caching behavior, that means that a FileNotFoundException indicates the entry is missing). I don't have any problem if this added logic is only activated through the use of some system/security property, because in my environment (Seven) I know the exact behavior of the "jar:" protocol handler as well as behavior of the cache.
I don't recall the details offhand (is Laird subscribed to this list?), but I believe that the general problem was that information necessary to make this decision was not exposed when using a "jar:" URL, at least for the JDK implementations of the time (early 1.4).
I just looked at my "jar:" protocol implementation and that one also throws FileNotFoundException in both cases, i.e. when the JAR file can't be found, or when the JAR file can be found but the entry is missing. I believe this behavior is demanded by the semantics for JarURLConnection as you are only allowed to return null for getJarEntry in case the JAR URL points to a JAR file itself and not an entry. So it is safe to assume that nothing happened since that day. -- Mark
