view netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.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/runtime/JNLPClassLoader.java@8dc304404e01
children
line wrap: on
line source


// 
// 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.runtime;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeSet;
import java.util.Vector;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import net.sourceforge.jnlp.ExtensionDesc;
import net.sourceforge.jnlp.JARDesc;
import net.sourceforge.jnlp.JNLPFile;
import net.sourceforge.jnlp.LaunchException;
import net.sourceforge.jnlp.ParseException;
import net.sourceforge.jnlp.PluginBridge;
import net.sourceforge.jnlp.ResourcesDesc;
import net.sourceforge.jnlp.SecurityDesc;
import net.sourceforge.jnlp.cache.CacheUtil;
import net.sourceforge.jnlp.cache.ResourceTracker;
import net.sourceforge.jnlp.cache.UpdatePolicy;
import net.sourceforge.jnlp.security.SecurityWarningDialog;
import net.sourceforge.jnlp.tools.JarSigner;
import sun.misc.JarIndex;

/**
 * Classloader that takes it's resources from a JNLP file.  If the
 * JNLP file defines extensions, separate classloaders for these
 * will be created automatically.  Classes are loaded with the
 * security context when the classloader was created.
 *
 * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
 * @version $Revision: 1.20 $ 
 */
public class JNLPClassLoader extends URLClassLoader {

    // todo: initializePermissions should get the permissions from
    // extension classes too so that main file classes can load
    // resources in an extension.

    /** shortcut for resources */
    private static String R(String key) { return JNLPRuntime.getMessage(key); }

    /** map from JNLPFile url to shared classloader */
    private static Map urlToLoader = new HashMap(); // never garbage collected!

    /** number of times a classloader with native code is created */
    private static int nativeCounter = 0;

    /** the directory for native code */
    private File nativeDir = null; // if set, some native code exists

    /** security context */
    private AccessControlContext acc = AccessController.getContext();

    /** the permissions for the cached jar files */
    private List resourcePermissions;

    /** the app */
    private ApplicationInstance app = null; // here for faster lookup in security manager

    /** list of this, local and global loaders this loader uses */
    private JNLPClassLoader loaders[] = null; // ..[0]==this

    /** whether to strictly adhere to the spec or not */
    private boolean strict = true;

    /** loads the resources */
    private ResourceTracker tracker = new ResourceTracker(true); // prefetch

    /** the update policy for resources */
    private UpdatePolicy updatePolicy;

    /** the JNLP file */
    private JNLPFile file;

    /** the resources section */
    private ResourcesDesc resources;

    /** the security section */
    private SecurityDesc security;
    
    /** Permissions granted by the user during runtime. */
    private ArrayList<Permission> runtimePermissions = new ArrayList<Permission>();

    /** all jars not yet part of classloader or active */
    private List available = new ArrayList();

	/** all of the jar files that were verified */
	private ArrayList<String> verifiedJars = null;

	/** all of the jar files that were not verified */
	private ArrayList<String> unverifiedJars = null;

	/** the jarsigner tool to verify our jars */
	private JarSigner js = null;

	private boolean signing = false;
	
	/** ArrayList containing jar indexes for various jars available to this classloader */
	private ArrayList<JarIndex> jarIndexes = new ArrayList<JarIndex>();
	
	/** File entries in the jar files available to this classloader */
	private TreeSet jarEntries = new TreeSet();

    /**
     * Create a new JNLPClassLoader from the specified file.
     *
     * @param file the JNLP file
     */
    protected JNLPClassLoader(JNLPFile file, UpdatePolicy policy) throws LaunchException {
        super(new URL[0], JNLPClassLoader.class.getClassLoader());

        if (JNLPRuntime.isDebug())
            System.out.println("New classloader: "+file.getFileLocation());

        this.file = file;
        this.updatePolicy = policy;
        this.resources = file.getResources();

        // initialize extensions
        initializeExtensions();

        // initialize permissions
        initializePermissions();

        initializeResources();

        setSecurity();

    }

    private void setSecurity() {
		/**
		 * When we're trying to load an applet, file.getSecurity() will return
		 * null since there is no jnlp file to specify permissions. We
		 * determine security settings here, after trying to verify jars.
		 */
		if (file instanceof PluginBridge) {
			if (signing == true) {
				this.security = new SecurityDesc(file, 
					SecurityDesc.ALL_PERMISSIONS,
					file.getCodeBase().getHost());
			} else {
				this.security = new SecurityDesc(file, 
					SecurityDesc.SANDBOX_PERMISSIONS, 
					file.getCodeBase().getHost());
			}
		} else { //regular jnlp file
			
			/**
			 * If the application is signed, then we set the SecurityDesc to the
			 * <security> tag in the jnlp file. Note that if an application is
			 * signed, but there is no <security> tag in the jnlp file, the
			 * application will get sandbox permissions.
			 * If the application is unsigned, we ignore the <security> tag and 
			 * use a sandbox instead. 
			 */
			if (signing == true) {
				this.security = file.getSecurity();
			} else {
				this.security = new SecurityDesc(file, 
						SecurityDesc.SANDBOX_PERMISSIONS, 
						file.getCodeBase().getHost());
			}
		}
    }
    
    /**
     * Returns a JNLP classloader for the specified JNLP file.
     *
     * @param file the file to load classes for
     * @param policy the update policy to use when downloading resources
     */
    public static JNLPClassLoader getInstance(JNLPFile file, UpdatePolicy policy) throws LaunchException {
        JNLPClassLoader loader = null;
        URL location = file.getFileLocation();

        if (location != null)
            loader = (JNLPClassLoader) urlToLoader.get(location);

		try {
        	if (loader == null)
            	loader = new JNLPClassLoader(file, policy);
		} catch (LaunchException e) {
			throw e;
		}

        if (file.getInformation().isSharingAllowed())
            urlToLoader.put(location, loader);

        return loader;
    }

    /**
     * Returns a JNLP classloader for the JNLP file at the specified
     * location. 
     *
     * @param location the file's location
     * @param policy the update policy to use when downloading resources
     */
    public static JNLPClassLoader getInstance(URL location, String cookieStr, UpdatePolicy policy) throws IOException, ParseException, LaunchException {
        JNLPClassLoader loader = (JNLPClassLoader) urlToLoader.get(location);

        if (loader == null)
            loader = getInstance(new JNLPFile(location, cookieStr, false, policy), policy);

        return loader;
    }

    /**
     * Load the extensions specified in the JNLP file.
     */
    void initializeExtensions() {
        ExtensionDesc[] ext = resources.getExtensions();

        List loaderList = new ArrayList();

        loaderList.add(this);

		//if (ext != null) {
        	for (int i=0; i < ext.length; i++) {
            	try {
               		JNLPClassLoader loader = getInstance(ext[i].getLocation(), ext[i].getCookieStr(), updatePolicy);
                	loaderList.add(loader);
            	}
            	catch (Exception ex) {
                	ex.printStackTrace();
            	}
        	}
		//}

        loaders = (JNLPClassLoader[]) loaderList.toArray(new JNLPClassLoader[ loaderList.size()]);
    }

    /**
     * Make permission objects for the classpath.
     */
    void initializePermissions() {
        resourcePermissions = new ArrayList();

        JARDesc jars[] = resources.getJARs();
        for (int i=0; i < jars.length; i++) {
            Permission p = CacheUtil.getReadPermission(jars[i].getLocation(),
                                                       jars[i].getVersion());

            if (JNLPRuntime.isDebug()) {
            	if (p == null)
            		System.out.println("Unable to add permission for " + jars[i].getLocation());
            	else
            		System.out.println("Permission added: " + p.toString());
            }
            if (p != null)
                resourcePermissions.add(p);
        }
    }

    /**
     * Load all of the JARs used in this JNLP file into the
     * ResourceTracker for downloading.
     */
    void initializeResources() throws LaunchException {
        JARDesc jars[] = resources.getJARs();
		if (jars == null || jars.length == 0)
			return;
		/*
		if (jars == null || jars.length == 0) {
			throw new LaunchException(null, null, R("LSFatal"),
			                    R("LCInit"), R("LFatalVerification"), "No jars!");
		}
		*/
        List initialJars = new ArrayList();

        for (int i=0; i < jars.length; i++) {

            available.add(jars[i]);

            if (jars[i].isEager())
                initialJars.add(jars[i]); // regardless of part

            tracker.addResource(jars[i].getLocation(),
                                file.getCookieStr(),
                                jars[i].getVersion(), 
                                jars[i].isCacheable() ? JNLPRuntime.getDefaultUpdatePolicy() : UpdatePolicy.FORCE
                               );
        }

        if (strict)
            fillInPartJars(initialJars); // add in each initial part's lazy jars

		if (JNLPRuntime.isVerifying()) {

			JarSigner js;
			waitForJars(initialJars); //download the jars first.

			try {
				js = verifyJars(initialJars);
			} catch (Exception e) {
				//we caught an Exception from the JarSigner class.
				//Note: one of these exceptions could be from not being able
				//to read the cacerts or trusted.certs files.
				e.printStackTrace();
				throw new LaunchException(null, null, R("LSFatal"),
					R("LCInit"), R("LFatalVerification"), R("LFatalVerificationInfo"));
			}

			//Case when at least one jar has some signing
			if (js.anyJarsSigned()){
				signing = true;

				//user does not trust this publisher
				if (!js.getAlreadyTrustPublisher()) {
				    checkTrustWithUser(js);
				} else {
					/**
					 * If the user trusts this publisher (i.e. the publisher's certificate
					 * is in the user's trusted.certs file), we do not show any dialogs.
					 */
				}
			} else {

				signing = false;
				//otherwise this jar is simply unsigned -- make sure to ask
				//for permission on certain actions
			}
		}

        activateJars(initialJars);
    }

    private void checkTrustWithUser(JarSigner js) throws LaunchException {
        if (!js.getRootInCacerts()) { //root cert is not in cacerts
            boolean b = SecurityWarningDialog.showCertWarningDialog(
                SecurityWarningDialog.AccessType.UNVERIFIED, file, js);
            if (!b)
                throw new LaunchException(null, null, R("LSFatal"), 
                    R("LCLaunching"), R("LNotVerified"), "");
        } else if (js.getRootInCacerts()) { //root cert is in cacerts
            boolean b = false;
            if (js.noSigningIssues())
                b = SecurityWarningDialog.showCertWarningDialog(
                        SecurityWarningDialog.AccessType.VERIFIED, file, js);
            else if (!js.noSigningIssues())
                b = SecurityWarningDialog.showCertWarningDialog(
                        SecurityWarningDialog.AccessType.SIGNING_ERROR, file, js);
            if (!b)
                throw new LaunchException(null, null, R("LSFatal"),
                    R("LCLaunching"), R("LCancelOnUserRequest"), "");
        }
    }

    /**
     * Add applet's codebase URL.  This allows compatibility with
     * applets that load resources from their codebase instead of
     * through JARs, but can slow down resource loading.  Resources
     * loaded from the codebase are not cached.
     */
    public void enableCodeBase() {
        addURL( file.getCodeBase() ); // nothing happens if called more that once?
    }

    /**
     * Sets the JNLP app this group is for; can only be called once.
     */
    public void setApplication(ApplicationInstance app) {
        if (this.app != null) {
            if (JNLPRuntime.isDebug()) {
                Exception ex = new IllegalStateException("Application can only be set once");
                ex.printStackTrace();
            }
            return;
        }

        this.app = app;
    }

    /**
     * Returns the JNLP app for this classloader
     */
    public ApplicationInstance getApplication() {
        return app;
    }

    /**
     * Returns the JNLP file the classloader was created from.
     */
    public JNLPFile getJNLPFile() {
        return file;
    }

    /**
     * Returns the permissions for the CodeSource.
     */
    protected PermissionCollection getPermissions(CodeSource cs) {
        Permissions result = new Permissions();

        // should check for extensions or boot, automatically give all
        // access w/o security dialog once we actually check certificates.

        // copy security permissions from SecurityDesc element
		if (security != null) {
        	Enumeration e = security.getPermissions().elements();
        	while (e.hasMoreElements())
            	result.add((Permission) e.nextElement());
		}

        // add in permission to read the cached JAR files
        for (int i=0; i < resourcePermissions.size(); i++)
            result.add((Permission) resourcePermissions.get(i));

        // add in the permissions that the user granted.
        for (int i=0; i < runtimePermissions.size(); i++)
        	result.add(runtimePermissions.get(i));

        return result;
    }

    protected void addPermission(Permission p) {
    	runtimePermissions.add(p);
    }
    
    /**
     * Adds to the specified list of JARS any other JARs that need
     * to be loaded at the same time as the JARs specified (ie, are
     * in the same part).
     */
    protected void fillInPartJars(List jars) {
        for (int i=0; i < jars.size(); i++) {
            String part = ((JARDesc) jars.get(i)).getPart();

            for (int a=0; a < available.size(); a++) {
                JARDesc jar = (JARDesc) available.get(a);

                if (part != null && part.equals(jar.getPart()))
                    if (!jars.contains(jar))
                        jars.add(jar);
            }
        }
    }

    /**
     * Ensures that the list of jars have all been transferred, and
     * makes them available to the classloader.  If a jar contains
     * native code, the libraries will be extracted and placed in
     * the path.
     *
     * @param jars the list of jars to load
     */
    protected void activateJars(final List jars) {
        PrivilegedAction activate = new PrivilegedAction() {

            public Object run() {
                // transfer the Jars
                waitForJars(jars);

                for (int i=0; i < jars.size(); i++) {
                    JARDesc jar = (JARDesc) jars.get(i);

                    available.remove(jar);

                    // add jar
                    File localFile = tracker.getCacheFile(jar.getLocation());
                    try {
                        URL location = jar.getLocation(); // non-cacheable, use source location
                        if (localFile != null) {
                            location = localFile.toURL(); // cached file
                            
                            // This is really not the best way.. but we need some way for 
                            // PluginAppletViewer::getCachedImageRef() to check if the image 
                            // is available locally, and it cannot use getResources() because 
                            // that prefetches the resource, which confuses MediaTracker.waitForAll() 
                            // which does a wait(), waiting for notification (presumably 
                            // thrown after a resource is fetched). This bug manifests itself
                            // particularly when using The FileManager applet from Webmin.
                            
                            JarFile jarFile = new JarFile(localFile);
                            Enumeration e = jarFile.entries();
                            while (e.hasMoreElements()) {
                                
                                JarEntry je = (JarEntry) e.nextElement();
                                
                                // another jar in my jar? it is more likely than you think  
                                if (je.getName().endsWith(".jar")) {
                                    // We need to extract that jar so that it can be loaded 
                                    // (inline loading with "jar:..!/..." path will not work 
                                    // with standard classloader methods)

                                    String extractedJarLocation = localFile.getParent() + "/" + je.getName();
                                    FileOutputStream extractedJar = new FileOutputStream(extractedJarLocation);
                                    InputStream is = jarFile.getInputStream(je);

                                    byte[] bytes = new byte[1024];
                                    int read = is.read(bytes);
                                    while (read > 0) {
                                        extractedJar.write(bytes, 0, read);
                                        read = is.read(bytes);
                                    }

                                    is.close();
                                    extractedJar.close();

                                    JarSigner signer = new JarSigner();
                                    signer.verifyJar(extractedJarLocation);

                                    if (signer.anyJarsSigned() && !signer.getAlreadyTrustPublisher()) {
                                        checkTrustWithUser(signer);
                                    }

                                    try {
                                        addURL(new URL("file://" + extractedJarLocation));
                                    } catch (MalformedURLException mfue) {
                                        if (JNLPRuntime.isDebug())
                                            System.err.println("Unable to add extracted nested jar to classpath");

                                        mfue.printStackTrace();
                                    }
                                }

                                jarEntries.add(je.getName());
                            }

                        }

                        addURL(location);

                        // there is currently no mechanism to cache files per 
                        // instance.. so only index cached files
                        if (localFile != null) {
                            JarIndex index = JarIndex.getJarIndex(new JarFile(localFile.getAbsolutePath()), null);

                            if (index != null)
                                jarIndexes.add(index);
                        }

                        if (JNLPRuntime.isDebug())
                            System.err.println("Activate jar: "+location);
                    }
                    catch (Exception ex) {
                        if (JNLPRuntime.isDebug())
                            ex.printStackTrace();
                    }

                    if (jar.isNative())
                        activateNative(jar);
                }

                return null;
            }
        };

        AccessController.doPrivileged(activate, acc);
    }

    /**
     * Enable the native code contained in a JAR by copying the
     * native files into the filesystem.  Called in the security
     * context of the classloader.
     */
    protected void activateNative(JARDesc jar) {
        if (JNLPRuntime.isDebug())
            System.out.println("Activate native: "+jar.getLocation());

        File localFile = tracker.getCacheFile(jar.getLocation());
        if (localFile == null)
            return;

        if (nativeDir == null)
            nativeDir = getNativeDir();

        try {
            JarFile jarFile = new JarFile(localFile, false);
            Enumeration entries = jarFile.entries();

            while (entries.hasMoreElements()) {
                JarEntry e = (JarEntry) entries.nextElement();

                if (e.isDirectory() || e.getName().indexOf('/') != -1)
                    continue;

                File outFile = new File(nativeDir, e.getName());

                CacheUtil.streamCopy(jarFile.getInputStream(e),
                                     new FileOutputStream(outFile));
            }
        }
        catch (IOException ex) {
            if (JNLPRuntime.isDebug())
                ex.printStackTrace();
        }
    }

    /**
     * Return the base directory to store native code files in.
     * This method does not need to return the same directory across
     * calls.
     */
    protected File getNativeDir() {
        nativeDir = new File(System.getProperty("java.io.tmpdir") 
                             + File.separator + "netx-native-" 
                             + (new Random().nextInt() & 0xFFFF));

        if (!nativeDir.mkdirs()) 
            return null;
        else
            return nativeDir;
    }

    /**
     * Return the absolute path to the native library.
     */
    protected String findLibrary(String lib) {
        if (nativeDir == null)
            return null;

        String syslib = System.mapLibraryName(lib);

        File target = new File(nativeDir, syslib);
        if (target.exists())
            return target.toString();
        else {
            String result = super.findLibrary(lib);
            if (result != null)
                return result;

            return findLibraryExt(lib);
        }
    }

    /**
     * Try to find the library path from another peer classloader.
     */
    protected String findLibraryExt(String lib) {
        for (int i=0; i < loaders.length; i++) {
            String result = null;

            if (loaders[i] != this)
                result = loaders[i].findLibrary(lib);

            if (result != null)
                return result;
        }

        return null;
    }

    /**
     * Wait for a group of JARs, and send download events if there
     * is a download listener or display a progress window otherwise.
     *
     * @param jars the jars
     */
    private void waitForJars(List jars) {
        URL urls[] = new URL[jars.size()];

        for (int i=0; i < jars.size(); i++) {
            JARDesc jar = (JARDesc) jars.get(i);

            urls[i] = jar.getLocation();
        }

        CacheUtil.waitForResources(app, tracker, urls, file.getTitle());
    }

    /**
	 * Verifies code signing of jars to be used.
	 *
	 * @param jars the jars to be verified.
	 */
	private JarSigner verifyJars(List<JARDesc> jars) throws Exception {
	
		js = new JarSigner();
		js.verifyJars(jars, tracker);
		return js;
	}

    /**
     * Find the loaded class in this loader or any of its extension loaders.
     */
    protected Class findLoadedClassAll(String name) {
        for (int i=0; i < loaders.length; i++) {
            Class result = null;

            if (loaders[i] == this)
                result = super.findLoadedClass(name);
            else
                result = loaders[i].findLoadedClassAll(name);

            if (result != null)
                return result;
        }

        return null;
    }

    /**
     * Find a JAR in the shared 'extension' classloaders, this
     * classloader, or one of the classloaders for the JNLP file's
     * extensions.
     */
    public Class loadClass(String name) throws ClassNotFoundException {

        Class result = findLoadedClassAll(name);

        // try parent classloader
        if (result == null) {
            try {
                ClassLoader parent = getParent();
                if (parent == null)
                    parent = ClassLoader.getSystemClassLoader();

                return parent.loadClass(name);
            }
            catch (ClassNotFoundException ex) { }
        }

        // filter out 'bad' package names like java, javax
        // validPackage(name);

        // search this and the extension loaders
        if (result == null)
            try {
                result = loadClassExt(name);
            } catch (ClassNotFoundException cnfe) {

                // Not found in external loader either. As a last resort, look in any available indexes

                // Currently this loads jars directly from the site. We cannot cache it because this 
                // call is initiated from within the applet, which does not have disk read/write permissions
                for (JarIndex index: jarIndexes) {
                    LinkedList<String> jarList = index.get(name.replace('.', '/'));

                    if (jarList != null) {
                        for (String jarName: jarList) {
                            JARDesc desc;
                            try {
                                desc = new JARDesc(new URL(file.getCodeBase(), jarName),
                                        null, null, false, true, false, true);
                            } catch (MalformedURLException mfe) {
                                throw new ClassNotFoundException(name);
                            }

                            available.add(desc);

                            tracker.addResource(desc.getLocation(), 
                                    file.getCookieStr(),
                                    desc.getVersion(), 
                                    JNLPRuntime.getDefaultUpdatePolicy()
                            );

                            URL remoteURL;
                            try {
                                remoteURL = new URL(file.getCodeBase() + jarName);
                            } catch (MalformedURLException mfe) {
                                throw new ClassNotFoundException(name);
                            }

                            URL u;

                            try {
                                u = tracker.getCacheURL(remoteURL);
                            } catch (Exception e) {
                                throw new ClassNotFoundException(name);
                            }

                            if (u != null)
                                addURL(u);

                        }

                        // If it still fails, let it error out                        
                        result = loadClassExt(name);
                    }
                }
            }

        return result;
    }

    /**
     * Find the class in this loader or any of its extension loaders.
     */
    protected Class findClass(String name) throws ClassNotFoundException {
        for (int i=0; i < loaders.length; i++) {
            try {
                if (loaders[i] == this)
                    return super.findClass(name);
                else
                    return loaders[i].findClass(name);
            }
            catch(ClassNotFoundException ex) { }
            catch(ClassFormatError cfe) {}
        }

        throw new ClassNotFoundException(name);
    }

    /**
     * Search for the class by incrementally adding resources to the
     * classloader and its extension classloaders until the resource
     * is found.
     */
    private Class loadClassExt(String name) throws ClassNotFoundException {
        // make recursive
        addAvailable();

        // find it
        try {
            return findClass(name);
        }
        catch(ClassNotFoundException ex) {
        }

        // add resources until found
        while (true) {
            JNLPClassLoader addedTo = addNextResource();

            if (addedTo == null)
                throw new ClassNotFoundException(name);

            try {
                return addedTo.findClass(name);
            }
            catch(ClassNotFoundException ex) {
            }
        }
    }

    /**
     * Finds the resource in this, the parent, or the extension
     * class loaders.
     */
    public URL getResource(String name) {
        URL result = super.getResource(name);

        for (int i=1; i < loaders.length; i++)
            if (result == null)
                result = loaders[i].getResource(name);

        return result;
    }

    /**
     * Finds the resource in this, the parent, or the extension
     * class loaders.
     */
    public Enumeration findResources(String name) throws IOException {
        Vector resources = new Vector();

        for (int i=0; i < loaders.length; i++) {
            Enumeration e;

            if (loaders[i] == this)
                e = super.findResources(name);
            else 
                e = loaders[i].findResources(name);

            while (e.hasMoreElements())
                resources.add(e.nextElement());
        }

        return resources.elements();
    }
    
    /**
     * Returns if the specified resource is available locally from a cached jar
     * 
     * @param s The name of the resource
     * @return Whether or not the resource is available locally
     */
    public boolean resourceAvailableLocally(String s) {
        return jarEntries.contains(s);
    }

    /**
     * Adds whatever resources have already been downloaded in the
     * background.
     */
    protected void addAvailable() {
        // go through available, check tracker for it and all of its
        // part brothers being available immediately, add them.

        for (int i=1; i < loaders.length; i++) {
            loaders[i].addAvailable();
        }
    }

    /**
     * Adds the next unused resource to the classloader.  That
     * resource and all those in the same part will be downloaded
     * and added to the classloader before returning.  If there are
     * no more resources to add, the method returns immediately.
     *
     * @return the classloader that resources were added to, or null
     */
    protected JNLPClassLoader addNextResource() {
        if (available.size() == 0) {
            for (int i=1; i < loaders.length; i++) {
                JNLPClassLoader result = loaders[i].addNextResource();

                if (result != null)
                    return result;
            }
            return null;
        }

        // add jar
        List jars = new ArrayList();
        jars.add(available.get(0));

        fillInPartJars(jars);

		
		activateJars(jars);

        return this;
    }

    // this part compatibility with previous classloader
    /**
     * @deprecated
     */
    public String getExtensionName() {
        String result = file.getInformation().getTitle();

        if (result == null)
            result = file.getInformation().getDescription();
        if (result == null && file.getFileLocation() != null)
            result = file.getFileLocation().toString();
        if (result == null && file.getCodeBase() != null)
            result = file.getCodeBase().toString();

        return result;
    }

    /**
     * @deprecated
     */
    public String getExtensionHREF() {
        return file.getFileLocation().toString();
    }

	public boolean getSigning() {
		return signing;
	}

	protected SecurityDesc getSecurity() {
		return security;
	}
}