view netx/net/sourceforge/jnlp/cache/CacheUtil.java @ 1842:31b0ba36a6b7

Completely restructure the building and inclusion of netx and plugin code. We were relying on the binary plugs process (and thus importing unneeded SNMP classes). We now use the same method as jaxws, jaxp, langtools and corba, and the binary plugs process is turned off (the default, we were turning it on by setting ALT_BINARY_PLUGS_PATH). 2009-05-27 Andrew John Hughes <ahughes@redhat.com> * overlays/openjdk/jdk/src/share/classes/javax/jnlp/BasicService.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/ClipboardService.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/DownloadService.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/DownloadServiceListener.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/ExtensionInstallerService.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/FileContents.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/FileOpenService.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/FileSaveService.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/JNLPRandomAccessFile.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/PersistenceService.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/PrintService.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/ServiceManager.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/ServiceManagerStub.java, * overlays/openjdk/jdk/src/share/classes/javax/jnlp/UnavailableServiceException.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/AppletDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/ApplicationDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/ComponentDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/DefaultLaunchHandler.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/ExtensionDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/IconDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/InformationDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/InstallerDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/JARDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/JNLPFile.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/JNLPSplashScreen.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/JREDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/LaunchException.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/LaunchHandler.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/Launcher.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/NetxPanel.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/Node.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/PackageDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/ParseException.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/Parser.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/PluginBridge.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/PropertyDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/ResourcesDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/SecurityDesc.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/Version.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/cache/CacheEntry.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/cache/CacheUtil.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/cache/DefaultDownloadIndicator.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/cache/DownloadIndicator.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/cache/Resource.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/cache/ResourceTracker.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/cache/UpdatePolicy.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/cache/package.html, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/event/ApplicationEvent.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/event/ApplicationListener.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/event/DownloadEvent.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/event/DownloadListener.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/event/package.html, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/package.html, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/resources/Manifest.mf, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/resources/Messages.properties, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/resources/about.jnlp, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/resources/default.jnlp, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/AppThreadGroup.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/AppletAudioClip.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/AppletEnvironment.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/AppletInstance.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/ApplicationInstance.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/Boot.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/Boot13.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/JNLPClassLoader.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/JNLPPolicy.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/JNLPRuntime.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/runtime/package.html, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/AccessWarningPane.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/AppletWarningPane.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/CertVerifier.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/CertWarningPane.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/CertsInfoPane.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/HttpsCertVerifier.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/MoreInfoPane.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/SecurityDialogUI.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/SecurityUtil.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/SecurityWarningDialog.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/SingleCertInfoPane.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/VariableX509TrustManager.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/viewer/CertificatePane.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/security/viewer/CertificateViewer.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/ServiceUtil.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/XBasicService.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/XClipboardService.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/XDownloadService.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/XExtensionInstallerService.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/XFileContents.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/XFileOpenService.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/XFileSaveService.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/XJNLPRandomAccessFile.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/XPersistenceService.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/XPrintService.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/XServiceManagerStub.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/services/package.html, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/tools/CharacterEncoder.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/tools/HexDumpEncoder.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/tools/JarRunner.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/tools/JarSigner.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/tools/JarSignerResources.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/tools/KeyStoreUtil.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/tools/KeyTool.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/util/PropertiesFile.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/util/Reflect.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/util/WeakList.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/nanoxml/XMLElement.java, * overlays/openjdk/jdk/src/share/classes/net/sourceforge/nanoxml/XMLParseException.java: Moved to... * Makefile.am: Remove use of ALT_BINARY_PLUGS_PATH (and thus turn off the binary plugs build), add a INITIAL_BOOTSTRAP_LINK_STAMP target which allows us to depend on $(ICEDTEA_BOOT_DIR) for both types of build, output to lib/tools.jar not jre/lib/tools.jar, add targets for building netx and liveconnect classes and make icedtea targets dependent on this. * netx/javax/jnlp/BasicService.java, * netx/javax/jnlp/ClipboardService.java, * netx/javax/jnlp/DownloadService.java, * netx/javax/jnlp/DownloadServiceListener.java, * netx/javax/jnlp/ExtensionInstallerService.java, * netx/javax/jnlp/FileContents.java, * netx/javax/jnlp/FileOpenService.java, * netx/javax/jnlp/FileSaveService.java, * netx/javax/jnlp/JNLPRandomAccessFile.java, * netx/javax/jnlp/PersistenceService.java, * netx/javax/jnlp/PrintService.java, * netx/javax/jnlp/ServiceManager.java, * netx/javax/jnlp/ServiceManagerStub.java, * netx/javax/jnlp/UnavailableServiceException.java, * netx/net/sourceforge/jnlp/AppletDesc.java, * netx/net/sourceforge/jnlp/ApplicationDesc.java, * netx/net/sourceforge/jnlp/ComponentDesc.java, * netx/net/sourceforge/jnlp/DefaultLaunchHandler.java, * netx/net/sourceforge/jnlp/ExtensionDesc.java, * netx/net/sourceforge/jnlp/IconDesc.java, * netx/net/sourceforge/jnlp/InformationDesc.java, * netx/net/sourceforge/jnlp/InstallerDesc.java, * netx/net/sourceforge/jnlp/JARDesc.java, * netx/net/sourceforge/jnlp/JNLPFile.java, * netx/net/sourceforge/jnlp/JNLPSplashScreen.java, * netx/net/sourceforge/jnlp/JREDesc.java, * netx/net/sourceforge/jnlp/LaunchException.java, * netx/net/sourceforge/jnlp/LaunchHandler.java, * netx/net/sourceforge/jnlp/Launcher.java, * netx/net/sourceforge/jnlp/NetxPanel.java, * netx/net/sourceforge/jnlp/Node.java, * netx/net/sourceforge/jnlp/PackageDesc.java, * netx/net/sourceforge/jnlp/ParseException.java, * netx/net/sourceforge/jnlp/Parser.java, * netx/net/sourceforge/jnlp/PluginBridge.java, * netx/net/sourceforge/jnlp/PropertyDesc.java, * netx/net/sourceforge/jnlp/ResourcesDesc.java, * netx/net/sourceforge/jnlp/SecurityDesc.java, * netx/net/sourceforge/jnlp/Version.java, * netx/net/sourceforge/jnlp/cache/CacheEntry.java, * netx/net/sourceforge/jnlp/cache/CacheUtil.java, * netx/net/sourceforge/jnlp/cache/DefaultDownloadIndicator.java, * netx/net/sourceforge/jnlp/cache/DownloadIndicator.java, * netx/net/sourceforge/jnlp/cache/Resource.java, * netx/net/sourceforge/jnlp/cache/ResourceTracker.java, * netx/net/sourceforge/jnlp/cache/UpdatePolicy.java, * netx/net/sourceforge/jnlp/cache/package.html, * netx/net/sourceforge/jnlp/event/ApplicationEvent.java, * netx/net/sourceforge/jnlp/event/ApplicationListener.java, * netx/net/sourceforge/jnlp/event/DownloadEvent.java, * netx/net/sourceforge/jnlp/event/DownloadListener.java, * netx/net/sourceforge/jnlp/event/package.html, * netx/net/sourceforge/jnlp/package.html, * netx/net/sourceforge/jnlp/resources/Manifest.mf, * netx/net/sourceforge/jnlp/resources/Messages.properties, * netx/net/sourceforge/jnlp/resources/about.jnlp, * netx/net/sourceforge/jnlp/resources/default.jnlp, * netx/net/sourceforge/jnlp/runtime/AppThreadGroup.java, * netx/net/sourceforge/jnlp/runtime/AppletAudioClip.java, * netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java, * netx/net/sourceforge/jnlp/runtime/AppletInstance.java, * netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java, * netx/net/sourceforge/jnlp/runtime/Boot.java, * netx/net/sourceforge/jnlp/runtime/Boot13.java, * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java, * netx/net/sourceforge/jnlp/runtime/JNLPPolicy.java, * netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java, * netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java, * netx/net/sourceforge/jnlp/runtime/package.html, * netx/net/sourceforge/jnlp/security/AccessWarningPane.java, * netx/net/sourceforge/jnlp/security/AppletWarningPane.java, * netx/net/sourceforge/jnlp/security/CertVerifier.java, * netx/net/sourceforge/jnlp/security/CertWarningPane.java, * netx/net/sourceforge/jnlp/security/CertsInfoPane.java, * netx/net/sourceforge/jnlp/security/HttpsCertVerifier.java, * netx/net/sourceforge/jnlp/security/MoreInfoPane.java, * netx/net/sourceforge/jnlp/security/SecurityDialogUI.java, * netx/net/sourceforge/jnlp/security/SecurityUtil.java, * netx/net/sourceforge/jnlp/security/SecurityWarningDialog.java, * netx/net/sourceforge/jnlp/security/SingleCertInfoPane.java, * netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java, * netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java, * netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java, * netx/net/sourceforge/jnlp/services/ServiceUtil.java, * netx/net/sourceforge/jnlp/services/XBasicService.java, * netx/net/sourceforge/jnlp/services/XClipboardService.java, * netx/net/sourceforge/jnlp/services/XDownloadService.java, * netx/net/sourceforge/jnlp/services/XExtensionInstallerService.java, * netx/net/sourceforge/jnlp/services/XFileContents.java, * netx/net/sourceforge/jnlp/services/XFileOpenService.java, * netx/net/sourceforge/jnlp/services/XFileSaveService.java, * netx/net/sourceforge/jnlp/services/XJNLPRandomAccessFile.java, * netx/net/sourceforge/jnlp/services/XPersistenceService.java, * netx/net/sourceforge/jnlp/services/XPrintService.java, * netx/net/sourceforge/jnlp/services/XServiceManagerStub.java, * netx/net/sourceforge/jnlp/services/package.html, * netx/net/sourceforge/jnlp/tools/CharacterEncoder.java, * netx/net/sourceforge/jnlp/tools/HexDumpEncoder.java, * netx/net/sourceforge/jnlp/tools/JarRunner.java, * netx/net/sourceforge/jnlp/tools/JarSigner.java, * netx/net/sourceforge/jnlp/tools/JarSignerResources.java, * netx/net/sourceforge/jnlp/tools/KeyStoreUtil.java, * netx/net/sourceforge/jnlp/tools/KeyTool.java, * netx/net/sourceforge/jnlp/util/PropertiesFile.java, * netx/net/sourceforge/jnlp/util/Reflect.java, * netx/net/sourceforge/jnlp/util/WeakList.java, * netx/net/sourceforge/nanoxml/XMLElement.java, * netx/net/sourceforge/nanoxml/XMLParseException.java: to here. * patches/ecj/icedtea.patch: Recreated. * patches/icedtea-ant.patch: Remove hack to jaxws which uses plugs directory (now undefined). * patches/icedtea-javac-debuginfo.patch: Recreated. * patches/icedtea-netx.patch: Include netx and netscape classes via the same import mechanism as jaxws, jaxp, corba and langtools (extracting a classes.zip).
author Andrew John Hughes <ahughes@redhat.com>
date Thu, 28 May 2009 10:18:19 +0100
parents overlays/openjdk/jdk/src/share/classes/net/sourceforge/jnlp/cache/CacheUtil.java@9f7d3e786d0a
children
line wrap: on
line source

// Copyright (C) 2001-2003 Jon A. Maxwell (JAM)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


package net.sourceforge.jnlp.cache;

import java.io.*;
import java.net.*;
import java.util.*;
import java.lang.reflect.*;
import java.security.*;
import javax.jnlp.*;

import net.sourceforge.jnlp.*;
import net.sourceforge.jnlp.runtime.*;

/**
 * Provides static methods to interact with the cache, download
 * indicator, and other utility methods.<p>
 *
 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
 * @version $Revision: 1.17 $
 */
public class CacheUtil {

    private static String R(String key, Object param) { 
        return JNLPRuntime.getMessage(key, new Object[] {param}); 
    }

    /**
     * Compares a URL using string compare of its protocol, host,
     * port, path, query, and anchor.  This method avoids the host
     * name lookup that URL.equals does for http: protocol URLs.
     * It may not return the same value as the URL.equals method
     * (different hostnames that resolve to the same IP address,
     * ie sourceforge.net and www.sourceforge.net).
     */
    public static boolean urlEquals(URL u1, URL u2) {
        if (u1==u2)
            return true;
        if (u1==null || u2==null)
            return false;

        if (!compare(u1.getProtocol(), u2.getProtocol(), true) ||
            !compare(u1.getHost(), u2.getHost(), true) ||
            //u1.getDefaultPort() != u2.getDefaultPort() || // only in 1.4
            !compare(u1.getPath(), u2.getPath(), false) ||
            !compare(u1.getQuery(), u2.getQuery(), false) ||
            !compare(u1.getRef(), u2.getRef(), false))
            return false;
        else
            return true;
    }

    /**
     * Caches a resource and returns a URL for it in the cache;
     * blocks until resource is cached.  If the resource location is
     * not cacheable (points to a local file, etc) then the original
     * URL is returned.<p>
     *
     * @param location location of the resource
     * @param version the version, or null
     * @return either the location in the cache or the original location
     */
    public static URL getCachedResource(URL location, String cookieStr, Version version, UpdatePolicy policy) {
        ResourceTracker rt = new ResourceTracker();
        rt.addResource(location, cookieStr, version, policy);
        try {
            File f = rt.getCacheFile(location);
            return f.toURL();
        }
        catch (MalformedURLException ex) {
            return location;
        }
    }

    /**
     * Compare strings that can be null.
     */
    private static boolean compare(String s1, String s2, boolean ignore) {
        if (s1==s2)
            return true;
        if (s1==null || s2==null)
            return false;

        if (ignore)
            return s1.equalsIgnoreCase(s2);
        else
            return s1.equals(s2);
    }

    /**
     * Returns the Permission object necessary to access the
     * resource, or null if no permission is needed.
     */
    public static Permission getReadPermission(URL location, Version version) {
        if (CacheUtil.isCacheable(location, version)) {
            File file = CacheUtil.getCacheFile(location, version);

            return new FilePermission(file.getPath(), "read");
        }
        else {
            try {
                // this is what URLClassLoader does
                return location.openConnection().getPermission();
            }
            catch (java.io.IOException ioe) {
                // should try to figure out the permission
            	if (JNLPRuntime.isDebug())
            		ioe.printStackTrace();
            }
        }

        return null;
    }

    /**
     * Returns whether there is a version of the URL contents in the
     * cache and it is up to date.  This method may not return
     * immediately.
     *
     * @param source the source URL
     * @param version the versions to check for
     * @param connection a connection to the URL, or null
     * @return whether the cache contains the version
     * @throws IllegalArgumentException if the source is not cacheable
     */
    public static boolean isCurrent(URL source, Version version, URLConnection connection) {

        if (!isCacheable(source, version))
            throw new IllegalArgumentException(R("CNotCacheable", source));

        try {
            if (connection == null)
                connection = source.openConnection();

            connection.connect();

            CacheEntry entry = new CacheEntry(source, version); // could pool this
            boolean result = entry.isCurrent(connection);

            if (JNLPRuntime.isDebug())
                System.out.println("isCurrent: "+source+" = "+result);

            return result;
        }
        catch (Exception ex) {
            if (JNLPRuntime.isDebug())
                ex.printStackTrace();

            return isCached(source, version); // if can't connect return whether already in cache
        }
    }

    /**
     * Returns true if the cache has a local copy of the contents of
     * the URL matching the specified version string.
     *
     * @param source the source URL
     * @param version the versions to check for
     * @return true if the source is in the cache
     * @throws IllegalArgumentException if the source is not cacheable
     */
    public static boolean isCached(URL source, Version version) {
        if (!isCacheable(source, version))
            throw new IllegalArgumentException(R("CNotCacheable", source));

        CacheEntry entry = new CacheEntry(source, version); // could pool this
        boolean result = entry.isCached();

        if (JNLPRuntime.isDebug())
            System.out.println("isCached: "+source+" = "+result);

        return result;
    }

    /**
     * Returns whether the resource can be cached as a local file;
     * if not, then URLConnection.openStream can be used to obtain
     * the contents.
     */
    public static boolean isCacheable(URL source, Version version) {
        if (source == null)
            return false;

        if (source.getProtocol().equals("file"))
            return false;

        if (source.getProtocol().equals("jar"))
            return false;

        return true;
    }

    /**
     * Returns the file for the locally cached contents of the
     * source.  This method returns the file location only and does
     * not download the resource.  The latest version of the
     * resource that matches the specified version will be returned.
     *
     * @param source the source URL
     * @param version the version id of the local file
     * @return the file location in the cache, or null if no versions cached
     * @throws IllegalArgumentException if the source is not cacheable
     */
    public static File getCacheFile(URL source, Version version) {
        // ensure that version is an version id not version string

        if (!isCacheable(source, version))
            throw new IllegalArgumentException(R("CNotCacheable", source));

        try {
            File localFile = urlToPath(source, "cache");
            localFile.getParentFile().mkdirs();

            return localFile;
        }
        catch (Exception ex) {
            if (JNLPRuntime.isDebug())
                ex.printStackTrace();

            return null;
        }
    }

    /**
     * Returns a buffered output stream open for writing to the
     * cache file.
     *
     * @param source the remote location
     * @param version the file version to write to
     */
    public static OutputStream getOutputStream(URL source, Version version) throws IOException {
        File localFile = getCacheFile(source, version);
        OutputStream out = new FileOutputStream(localFile);

        return new BufferedOutputStream(out);
    }

    /**
     * Copies from an input stream to an output stream.  On
     * completion, both streams will be closed.  Streams are
     * buffered automatically.
     */
    public static void streamCopy(InputStream is, OutputStream os) throws IOException {
        if (!(is instanceof BufferedInputStream))
            is = new BufferedInputStream(is);

        if (!(os instanceof BufferedOutputStream))
            os = new BufferedOutputStream(os);

        try {
            byte b[] = new byte[4096];
            while (true) {
                int c = is.read(b, 0, b.length);
                if (c == -1)
                    break;

                os.write(b, 0, c);
            }
        }
        finally {
            is.close();
            os.close();
        }
    }

    /**
     * Converts a URL into a local path string within the runtime's
     * base directory.
     *
     * @param location the url
     * @param subdir subdirectory under the base directory
     * @return the file
     */
    public static File urlToPath(URL location, String subdir) {
        StringBuffer path = new StringBuffer();

        if (subdir != null) {
            path.append(subdir);
            path.append(File.separatorChar);
        }

        path.append(location.getProtocol());
        path.append(File.separatorChar);
        path.append(location.getHost());
        path.append(File.separatorChar);
        path.append(location.getPath().replace('/', File.separatorChar));

        return new File(JNLPRuntime.getBaseDir(), fixPath(path.toString()));
    }

    /**
     * Clean up a string by removing characters that can't appear in
     * a local file name.
     */
    private static String fixPath(String path) {
        char badChars[] = { '\\', '/', ':', '*', '?', '"', '<', '>', '|' };

        for (int i=0; i < badChars.length; i++)
            if (badChars[i] != File.separatorChar)
                if (-1 != path.indexOf(badChars[i]))
                    path = path.replace(badChars[i], 'X');

        return path;
    }

    /**
     * Waits until the resources are downloaded, while showing a
     * progress indicator.
     *
     * @param tracker the resource tracker
     * @param resources the resources to wait for
     * @param title name of the download
     */
    public static void waitForResources(ApplicationInstance app, ResourceTracker tracker, URL resources[], String title) {
        DownloadIndicator indicator = JNLPRuntime.getDefaultDownloadIndicator();
        DownloadServiceListener listener = null;

        try {
            if (indicator == null) {
                tracker.waitForResources(resources, 0);
                return;
            }

            // see if resources can be downloaded very quickly; avoids
            // overhead of creating display components for the resources
            if (tracker.waitForResources(resources, indicator.getInitialDelay())) 
                return;

            // only resources not starting out downloaded are displayed
            List urlList = new ArrayList();
            for (int i=0; i < resources.length; i++) {
                if (!tracker.checkResource(resources[i]))
                    urlList.add(resources[i]);
            }
            URL undownloaded[] = (URL[]) urlList.toArray( new URL[urlList.size()] );

            listener = indicator.getListener(app, title, undownloaded);

            do {
                long read = 0;
                long total = 0;

                for (int i=0; i < undownloaded.length; i++) {
                    // add in any -1's; they're insignificant
                    total += tracker.getTotalSize(undownloaded[i]);
                    read += tracker.getAmountRead(undownloaded[i]);
                }

                int percent = (int)( (100*read)/Math.max(1,total) );

                for (int i=0; i < undownloaded.length; i++)
                    listener.progress(undownloaded[i], "version",
                                      tracker.getAmountRead(undownloaded[i]),
                                      tracker.getTotalSize(undownloaded[i]),
                                      percent);
            }
            while (!tracker.waitForResources(resources, indicator.getUpdateRate()));

            // make sure they read 100% until indicator closes
            for (int i=0; i < undownloaded.length; i++)
                listener.progress(undownloaded[i], "version",
                                  tracker.getTotalSize(undownloaded[i]),
                                  tracker.getTotalSize(undownloaded[i]),
                                  100);

        }
        catch (InterruptedException ex) {
            if (JNLPRuntime.isDebug())
                ex.printStackTrace();
        }
        finally {
            if (listener != null)
                indicator.disposeListener(listener);
        }
    }

}