/* * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.misc; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.FileNotFoundException; import java.util.StringTokenizer; import java.util.Vector; import java.util.Enumeration; import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.jar.Attributes; import java.util.jar.Attributes.Name; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; import java.net.URL; import java.net.MalformedURLException; import sun.net.www.ParseUtil; /** *
* This class checks dependent extensions a particular jar file may have * declared through its manifest attributes. *
* Jar file declared dependent extensions through the extension-list * attribute. The extension-list contains a list of keys used to * fetch the other attributes describing the required extension. * If key is the extension key declared in the extension-list * attribute, the following describing attribute can be found in * the manifest : * key-Extension-Name: (Specification package name) * key-Specification-Version: (Specification-Version) * key-Implementation-Version: (Implementation-Version) * key-Implementation-Vendor-Id: (Imlementation-Vendor-Id) * key-Implementation-Version: (Implementation version) * key-Implementation-URL: (URL to download the requested extension) ** This class also maintain versioning consistency of installed * extensions dependencies declared in jar file manifest. *
* @author Jerome Dochez */ public class ExtensionDependency { /* Callbak interfaces to delegate installation of missing extensions */ private static Vector providers; /** ** Register an ExtensionInstallationProvider. The provider is responsible * for handling the installation (upgrade) of any missing extensions. *
* @param eip ExtensionInstallationProvider implementation */ public synchronized static void addExtensionInstallationProvider (ExtensionInstallationProvider eip) { if (providers == null) { providers = new Vector(); } providers.add(eip); } /** ** Unregister a previously installed installation provider *
*/ public synchronized static void removeExtensionInstallationProvider (ExtensionInstallationProvider eip) { providers.remove(eip); } /** ** Checks the dependencies of the jar file on installed extension. *
* @param jarFile containing the attriutes declaring the dependencies */ public static boolean checkExtensionsDependencies(JarFile jar) { if (providers == null) { // no need to bother, nobody is registered to install missing // extensions return true; } try { ExtensionDependency extDep = new ExtensionDependency(); return extDep.checkExtensions(jar); } catch (ExtensionInstallationException e) { debug(e.getMessage()); } return false; } /* * Check for all declared required extensions in the jar file * manifest. */ protected boolean checkExtensions(JarFile jar) throws ExtensionInstallationException { Manifest man; try { man = jar.getManifest(); } catch (IOException e) { return false; } if (man == null) { // The applet does not define a manifest file, so // we just assume all dependencies are satisfied. return true; } boolean result = true; Attributes attr = man.getMainAttributes(); if (attr != null) { // Let's get the list of declared dependencies String value = attr.getValue(Name.EXTENSION_LIST); if (value != null) { StringTokenizer st = new StringTokenizer(value); // Iterate over all declared dependencies while (st.hasMoreTokens()) { String extensionName = st.nextToken(); debug("The file " + jar.getName() + " appears to depend on " + extensionName); // Sanity Check String extName = extensionName + "-" + Name.EXTENSION_NAME.toString(); if (attr.getValue(extName) == null) { debug("The jar file " + jar.getName() + " appers to depend on " + extensionName + " but does not define the " + extName + " attribute in its manifest "); } else { if (!checkExtension(extensionName, attr)) { debug("Failed installing " + extensionName); result = false; } } } } else { debug("No dependencies for " + jar.getName()); } } return result; } /* ** Check that a particular dependency on an extension is satisfied. *
* @param extensionName is the key used for the attributes in the manifest * @param attr is the attributes of the manifest file * * @return true if the dependency is satisfied by the installed extensions */ protected synchronized boolean checkExtension(final String extensionName, final Attributes attr) throws ExtensionInstallationException { debug("Checking extension " + extensionName); if (checkExtensionAgainstInstalled(extensionName, attr)) return true; debug("Extension not currently installed "); ExtensionInfo reqInfo = new ExtensionInfo(extensionName, attr); return installExtension(reqInfo, null); } /* ** Check if a particular extension is part of the currently installed * extensions. *
* @param extensionName is the key for the attributes in the manifest * @param attr is the attributes of the manifest * * @return true if the requested extension is already installed */ boolean checkExtensionAgainstInstalled(String extensionName, Attributes attr) throws ExtensionInstallationException { File fExtension = checkExtensionExists(extensionName); if (fExtension != null) { // Extension already installed, just check against this one try { if (checkExtensionAgainst(extensionName, attr, fExtension)) return true; } catch (FileNotFoundException e) { debugException(e); } catch (IOException e) { debugException(e); } return false; } else { // Not sure if extension is already installed, so check all the // installed extension jar files to see if we get a match File[] installedExts; try { // Get the list of installed extension jar files so we can // compare the installed versus the requested extension installedExts = getInstalledExtensions(); } catch(IOException e) { debugException(e); return false; } for (int i=0;i* An required extension is missing, if an ExtensionInstallationProvider is * registered, delegate the installation of that particular extension to it. *
* * @param reqInfo Missing extension information * @param instInfo Older installed version information * * @return true if the installation is successful */ protected boolean installExtension(ExtensionInfo reqInfo, ExtensionInfo instInfo) throws ExtensionInstallationException { Vector currentProviders; synchronized(providers) { currentProviders = (Vector) providers.clone(); } for (Enumeration e=currentProviders.elements();e.hasMoreElements();) { ExtensionInstallationProvider eip = (ExtensionInstallationProvider) e.nextElement(); if (eip!=null) { // delegate the installation to the provider if (eip.installExtension(reqInfo, instInfo)) { debug(reqInfo.name + " installation successful"); Launcher.ExtClassLoader cl = (Launcher.ExtClassLoader) Launcher.getLauncher().getClassLoader().getParent(); addNewExtensionsToClassLoader(cl); return true; } } } // We have tried all of our providers, noone could install this // extension, we just return failure at this point debug(reqInfo.name + " installation failed"); return false; } /** ** Checks if the extension, that is specified in the extension-list in * the applet jar manifest, is already installed (i.e. exists in the * extension directory). *
* * @param extensionName extension name in the extension-list * * @return the extension if it exists in the extension directory */ private File checkExtensionExists(String extensionName) { // Function added to fix bug 4504166 final String extName = extensionName; final String[] fileExt = {".jar", ".zip"}; return AccessController.doPrivileged( new PrivilegedAction* Scan the directories and return all files installed in those *
* @param dirs list of directories to scan * * @return the list of files installed in all the directories */ private static File[] getExtFiles(File[] dirs) throws IOException { Vector* @return the list of installed extensions jar files *
*/ private File[] getInstalledExtensions() throws IOException { return AccessController.doPrivileged( new PrivilegedAction* Add the newly installed jar file to the extension class loader. *
* * @param cl the current installed extension class loader * * @return true if successful */ private Boolean addNewExtensionsToClassLoader(Launcher.ExtClassLoader cl) { try { File[] installedExts = getInstalledExtensions(); for (int i=0;i