0N/A/*
2362N/A * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.misc;
0N/A
0N/Aimport java.io.File;
0N/Aimport java.io.FilenameFilter;
0N/Aimport java.io.IOException;
0N/Aimport java.io.FileNotFoundException;
0N/Aimport java.util.StringTokenizer;
0N/Aimport java.util.Vector;
0N/Aimport java.util.Enumeration;
0N/Aimport java.util.jar.JarFile;
0N/Aimport java.util.jar.Manifest;
0N/Aimport java.util.jar.Attributes;
0N/Aimport java.util.jar.Attributes.Name;
0N/Aimport java.security.AccessController;
0N/Aimport java.security.PrivilegedAction;
0N/Aimport java.security.PrivilegedExceptionAction;
0N/Aimport java.security.PrivilegedActionException;
0N/Aimport java.net.URL;
0N/Aimport java.net.MalformedURLException;
0N/Aimport sun.net.www.ParseUtil;
0N/A
0N/A/**
0N/A * <p>
0N/A * This class checks dependent extensions a particular jar file may have
0N/A * declared through its manifest attributes.
0N/A * </p>
0N/A * Jar file declared dependent extensions through the extension-list
0N/A * attribute. The extension-list contains a list of keys used to
0N/A * fetch the other attributes describing the required extension.
0N/A * If key is the extension key declared in the extension-list
0N/A * attribute, the following describing attribute can be found in
0N/A * the manifest :
0N/A * key-Extension-Name: (Specification package name)
0N/A * key-Specification-Version: (Specification-Version)
0N/A * key-Implementation-Version: (Implementation-Version)
0N/A * key-Implementation-Vendor-Id: (Imlementation-Vendor-Id)
0N/A * key-Implementation-Version: (Implementation version)
0N/A * key-Implementation-URL: (URL to download the requested extension)
0N/A * <p>
0N/A * This class also maintain versioning consistency of installed
0N/A * extensions dependencies declared in jar file manifest.
0N/A * </p>
0N/A * @author Jerome Dochez
0N/A */
0N/Apublic class ExtensionDependency {
0N/A
0N/A /* Callbak interfaces to delegate installation of missing extensions */
0N/A private static Vector providers;
0N/A
0N/A /**
0N/A * <p>
0N/A * Register an ExtensionInstallationProvider. The provider is responsible
0N/A * for handling the installation (upgrade) of any missing extensions.
0N/A * </p>
0N/A * @param eip ExtensionInstallationProvider implementation
0N/A */
0N/A public synchronized static void addExtensionInstallationProvider
0N/A (ExtensionInstallationProvider eip)
0N/A {
0N/A if (providers == null) {
0N/A providers = new Vector();
0N/A }
0N/A providers.add(eip);
0N/A }
0N/A
0N/A /**
0N/A * <p>
0N/A * Unregister a previously installed installation provider
0N/A * </p>
0N/A */
0N/A public synchronized static void removeExtensionInstallationProvider
0N/A (ExtensionInstallationProvider eip)
0N/A {
0N/A providers.remove(eip);
0N/A }
0N/A
0N/A /**
0N/A * <p>
0N/A * Checks the dependencies of the jar file on installed extension.
0N/A * </p>
0N/A * @param jarFile containing the attriutes declaring the dependencies
0N/A */
0N/A public static boolean checkExtensionsDependencies(JarFile jar)
0N/A {
0N/A if (providers == null) {
0N/A // no need to bother, nobody is registered to install missing
0N/A // extensions
0N/A return true;
0N/A }
0N/A
0N/A try {
0N/A ExtensionDependency extDep = new ExtensionDependency();
0N/A return extDep.checkExtensions(jar);
0N/A } catch (ExtensionInstallationException e) {
0N/A debug(e.getMessage());
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /*
0N/A * Check for all declared required extensions in the jar file
0N/A * manifest.
0N/A */
0N/A protected boolean checkExtensions(JarFile jar)
0N/A throws ExtensionInstallationException
0N/A {
0N/A Manifest man;
0N/A try {
0N/A man = jar.getManifest();
0N/A } catch (IOException e) {
0N/A return false;
0N/A }
0N/A
0N/A if (man == null) {
0N/A // The applet does not define a manifest file, so
0N/A // we just assume all dependencies are satisfied.
0N/A return true;
0N/A }
0N/A
0N/A boolean result = true;
0N/A Attributes attr = man.getMainAttributes();
0N/A if (attr != null) {
0N/A // Let's get the list of declared dependencies
0N/A String value = attr.getValue(Name.EXTENSION_LIST);
0N/A if (value != null) {
0N/A StringTokenizer st = new StringTokenizer(value);
0N/A // Iterate over all declared dependencies
0N/A while (st.hasMoreTokens()) {
0N/A String extensionName = st.nextToken();
0N/A debug("The file " + jar.getName() +
0N/A " appears to depend on " + extensionName);
0N/A // Sanity Check
0N/A String extName = extensionName + "-" +
0N/A Name.EXTENSION_NAME.toString();
0N/A if (attr.getValue(extName) == null) {
0N/A debug("The jar file " + jar.getName() +
0N/A " appers to depend on "
0N/A + extensionName + " but does not define the " +
0N/A extName + " attribute in its manifest ");
0N/A
0N/A } else {
0N/A if (!checkExtension(extensionName, attr)) {
0N/A debug("Failed installing " + extensionName);
0N/A result = false;
0N/A }
0N/A }
0N/A }
0N/A } else {
0N/A debug("No dependencies for " + jar.getName());
0N/A }
0N/A }
0N/A return result;
0N/A }
0N/A
0N/A
0N/A /*
0N/A * <p>
0N/A * Check that a particular dependency on an extension is satisfied.
0N/A * </p>
0N/A * @param extensionName is the key used for the attributes in the manifest
0N/A * @param attr is the attributes of the manifest file
0N/A *
0N/A * @return true if the dependency is satisfied by the installed extensions
0N/A */
0N/A protected synchronized boolean checkExtension(final String extensionName,
0N/A final Attributes attr)
0N/A throws ExtensionInstallationException
0N/A {
0N/A debug("Checking extension " + extensionName);
0N/A if (checkExtensionAgainstInstalled(extensionName, attr))
0N/A return true;
0N/A
0N/A debug("Extension not currently installed ");
0N/A ExtensionInfo reqInfo = new ExtensionInfo(extensionName, attr);
0N/A return installExtension(reqInfo, null);
0N/A }
0N/A
0N/A /*
0N/A * <p>
0N/A * Check if a particular extension is part of the currently installed
0N/A * extensions.
0N/A * </p>
0N/A * @param extensionName is the key for the attributes in the manifest
0N/A * @param attr is the attributes of the manifest
0N/A *
0N/A * @return true if the requested extension is already installed
0N/A */
0N/A boolean checkExtensionAgainstInstalled(String extensionName,
0N/A Attributes attr)
0N/A throws ExtensionInstallationException
0N/A {
0N/A File fExtension = checkExtensionExists(extensionName);
0N/A
0N/A if (fExtension != null) {
0N/A // Extension already installed, just check against this one
0N/A try {
0N/A if (checkExtensionAgainst(extensionName, attr, fExtension))
0N/A return true;
0N/A } catch (FileNotFoundException e) {
0N/A debugException(e);
0N/A } catch (IOException e) {
0N/A debugException(e);
0N/A }
0N/A return false;
0N/A
0N/A } else {
0N/A // Not sure if extension is already installed, so check all the
0N/A // installed extension jar files to see if we get a match
0N/A
0N/A File[] installedExts;
0N/A
0N/A try {
0N/A // Get the list of installed extension jar files so we can
0N/A // compare the installed versus the requested extension
0N/A installedExts = getInstalledExtensions();
0N/A } catch(IOException e) {
0N/A debugException(e);
0N/A return false;
0N/A }
0N/A
0N/A for (int i=0;i<installedExts.length;i++) {
0N/A try {
0N/A if (checkExtensionAgainst(extensionName, attr, installedExts[i]))
0N/A return true;
0N/A } catch (FileNotFoundException e) {
0N/A debugException(e);
0N/A } catch (IOException e) {
0N/A debugException(e);
0N/A // let's continue with the next installed extension
0N/A }
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /*
0N/A * <p>
0N/A * Check if the requested extension described by the attributes
0N/A * in the manifest under the key extensionName is compatible with
0N/A * the jar file.
0N/A * </p>
0N/A *
0N/A * @param extensionName key in the attibute list
0N/A * @param attr manifest file attributes
0N/A * @param file installed extension jar file to compare the requested
0N/A * extension against.
0N/A */
0N/A protected boolean checkExtensionAgainst(String extensionName,
0N/A Attributes attr,
0N/A final File file)
0N/A throws IOException,
0N/A FileNotFoundException,
0N/A ExtensionInstallationException
0N/A {
0N/A
0N/A debug("Checking extension " + extensionName +
0N/A " against " + file.getName());
0N/A
0N/A // Load the jar file ...
0N/A Manifest man;
0N/A try {
28N/A man = AccessController.doPrivileged(
28N/A new PrivilegedExceptionAction<Manifest>() {
28N/A public Manifest run()
0N/A throws IOException, FileNotFoundException {
0N/A if (!file.exists())
0N/A throw new FileNotFoundException(file.getName());
0N/A JarFile jarFile = new JarFile(file);
0N/A return jarFile.getManifest();
0N/A }
0N/A });
0N/A } catch(PrivilegedActionException e) {
0N/A if (e.getException() instanceof FileNotFoundException)
0N/A throw (FileNotFoundException) e.getException();
0N/A throw (IOException) e.getException();
0N/A }
0N/A
0N/A // Construct the extension information object
0N/A ExtensionInfo reqInfo = new ExtensionInfo(extensionName, attr);
0N/A debug("Requested Extension : " + reqInfo);
0N/A
0N/A int isCompatible = ExtensionInfo.INCOMPATIBLE;
0N/A ExtensionInfo instInfo = null;
0N/A
0N/A if (man != null) {
0N/A Attributes instAttr = man.getMainAttributes();
0N/A if (instAttr != null) {
0N/A instInfo = new ExtensionInfo(null, instAttr);
0N/A debug("Extension Installed " + instInfo);
0N/A isCompatible = instInfo.isCompatibleWith(reqInfo);
0N/A switch(isCompatible) {
0N/A case ExtensionInfo.COMPATIBLE:
0N/A debug("Extensions are compatible");
0N/A return true;
0N/A
0N/A case ExtensionInfo.INCOMPATIBLE:
0N/A debug("Extensions are incompatible");
0N/A return false;
0N/A
0N/A default:
0N/A // everything else
0N/A debug("Extensions require an upgrade or vendor switch");
0N/A return installExtension(reqInfo, instInfo);
0N/A
0N/A }
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /*
0N/A * <p>
0N/A * An required extension is missing, if an ExtensionInstallationProvider is
0N/A * registered, delegate the installation of that particular extension to it.
0N/A * </p>
0N/A *
0N/A * @param reqInfo Missing extension information
0N/A * @param instInfo Older installed version information
0N/A *
0N/A * @return true if the installation is successful
0N/A */
0N/A protected boolean installExtension(ExtensionInfo reqInfo,
0N/A ExtensionInfo instInfo)
0N/A throws ExtensionInstallationException
0N/A {
0N/A
0N/A Vector currentProviders;
0N/A synchronized(providers) {
0N/A currentProviders = (Vector) providers.clone();
0N/A }
0N/A for (Enumeration e=currentProviders.elements();e.hasMoreElements();) {
0N/A ExtensionInstallationProvider eip =
0N/A (ExtensionInstallationProvider) e.nextElement();
0N/A
0N/A if (eip!=null) {
0N/A // delegate the installation to the provider
0N/A if (eip.installExtension(reqInfo, instInfo)) {
0N/A debug(reqInfo.name + " installation successful");
0N/A Launcher.ExtClassLoader cl = (Launcher.ExtClassLoader)
0N/A Launcher.getLauncher().getClassLoader().getParent();
0N/A addNewExtensionsToClassLoader(cl);
0N/A return true;
0N/A }
0N/A }
0N/A }
0N/A // We have tried all of our providers, noone could install this
0N/A // extension, we just return failure at this point
0N/A debug(reqInfo.name + " installation failed");
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * <p>
0N/A * Checks if the extension, that is specified in the extension-list in
0N/A * the applet jar manifest, is already installed (i.e. exists in the
0N/A * extension directory).
0N/A * </p>
0N/A *
0N/A * @param extensionName extension name in the extension-list
0N/A *
0N/A * @return the extension if it exists in the extension directory
0N/A */
0N/A private File checkExtensionExists(String extensionName) {
0N/A // Function added to fix bug 4504166
0N/A final String extName = extensionName;
0N/A final String[] fileExt = {".jar", ".zip"};
0N/A
28N/A return AccessController.doPrivileged(
28N/A new PrivilegedAction<File>() {
28N/A public File run() {
0N/A try {
0N/A File fExtension;
0N/A File[] dirs = getExtDirs();
0N/A
0N/A // Search the extension directories for the extension that is specified
0N/A // in the attribute extension-list in the applet jar manifest
0N/A for (int i=0;i<dirs.length;i++) {
0N/A for (int j=0;j<fileExt.length;j++) {
0N/A if (extName.toLowerCase().endsWith(fileExt[j])) {
0N/A fExtension = new File(dirs[i], extName);
0N/A } else {
0N/A fExtension = new File(dirs[i], extName+fileExt[j]);
0N/A }
0N/A debug("checkExtensionExists:fileName " + fExtension.getName());
0N/A if (fExtension.exists()) {
0N/A return fExtension;
0N/A }
0N/A }
0N/A }
0N/A return null;
0N/A
0N/A } catch(Exception e) {
0N/A debugException(e);
0N/A return null;
0N/A }
0N/A }
0N/A });
0N/A }
0N/A
0N/A /**
0N/A * <p>
0N/A * @return the java.ext.dirs property as a list of directory
0N/A * </p>
0N/A */
0N/A private static File[] getExtDirs() {
0N/A String s = java.security.AccessController.doPrivileged(
0N/A new sun.security.action.GetPropertyAction("java.ext.dirs"));
0N/A
0N/A File[] dirs;
0N/A if (s != null) {
0N/A StringTokenizer st =
0N/A new StringTokenizer(s, File.pathSeparator);
0N/A int count = st.countTokens();
0N/A debug("getExtDirs count " + count);
0N/A dirs = new File[count];
0N/A for (int i = 0; i < count; i++) {
0N/A dirs[i] = new File(st.nextToken());
0N/A debug("getExtDirs dirs["+i+"] "+ dirs[i]);
0N/A }
0N/A } else {
0N/A dirs = new File[0];
0N/A debug("getExtDirs dirs " + dirs);
0N/A }
0N/A debug("getExtDirs dirs.length " + dirs.length);
0N/A return dirs;
0N/A }
0N/A
0N/A /*
0N/A * <p>
0N/A * Scan the directories and return all files installed in those
0N/A * </p>
0N/A * @param dirs list of directories to scan
0N/A *
0N/A * @return the list of files installed in all the directories
0N/A */
0N/A private static File[] getExtFiles(File[] dirs) throws IOException {
28N/A Vector<File> urls = new Vector<File>();
0N/A for (int i = 0; i < dirs.length; i++) {
0N/A String[] files = dirs[i].list(new JarFilter());
0N/A if (files != null) {
0N/A debug("getExtFiles files.length " + files.length);
0N/A for (int j = 0; j < files.length; j++) {
0N/A File f = new File(dirs[i], files[j]);
0N/A urls.add(f);
0N/A debug("getExtFiles f["+j+"] "+ f);
0N/A }
0N/A }
0N/A }
0N/A File[] ua = new File[urls.size()];
0N/A urls.copyInto(ua);
0N/A debug("getExtFiles ua.length " + ua.length);
0N/A return ua;
0N/A }
0N/A
0N/A /*
0N/A * <p>
0N/A * @return the list of installed extensions jar files
0N/A * </p>
0N/A */
0N/A private File[] getInstalledExtensions() throws IOException {
28N/A return AccessController.doPrivileged(
28N/A new PrivilegedAction<File[]>() {
28N/A public File[] run() {
0N/A try {
0N/A return getExtFiles(getExtDirs());
0N/A } catch(IOException e) {
0N/A debug("Cannot get list of installed extensions");
0N/A debugException(e);
28N/A return new File[0];
0N/A }
0N/A }
0N/A });
0N/A }
0N/A
0N/A /*
0N/A * <p>
0N/A * Add the newly installed jar file to the extension class loader.
0N/A * </p>
0N/A *
0N/A * @param cl the current installed extension class loader
0N/A *
0N/A * @return true if successful
0N/A */
0N/A private Boolean addNewExtensionsToClassLoader(Launcher.ExtClassLoader cl) {
0N/A try {
0N/A File[] installedExts = getInstalledExtensions();
0N/A for (int i=0;i<installedExts.length;i++) {
0N/A final File instFile = installedExts[i];
0N/A URL instURL = AccessController.doPrivileged(
0N/A new PrivilegedAction<URL>() {
0N/A public URL run() {
0N/A try {
0N/A return ParseUtil.fileToEncodedURL(instFile);
0N/A } catch (MalformedURLException e) {
0N/A debugException(e);
0N/A return null;
0N/A }
0N/A }
0N/A });
0N/A if (instURL != null) {
0N/A URL[] urls = cl.getURLs();
0N/A boolean found=false;
0N/A for (int j = 0; j<urls.length; j++) {
0N/A debug("URL["+j+"] is " + urls[j] + " looking for "+
0N/A instURL);
0N/A if (urls[j].toString().compareToIgnoreCase(
0N/A instURL.toString())==0) {
0N/A found=true;
0N/A debug("Found !");
0N/A }
0N/A }
0N/A if (!found) {
0N/A debug("Not Found ! adding to the classloader " +
0N/A instURL);
0N/A cl.addExtURL(instURL);
0N/A }
0N/A }
0N/A }
0N/A } catch (MalformedURLException e) {
0N/A e.printStackTrace();
0N/A } catch (IOException e) {
0N/A e.printStackTrace();
0N/A // let's continue with the next installed extension
0N/A }
0N/A return Boolean.TRUE;
0N/A }
0N/A
0N/A // True to display all debug and trace messages
0N/A static final boolean DEBUG = false;
0N/A
0N/A private static void debug(String s) {
0N/A if (DEBUG) {
0N/A System.err.println(s);
0N/A }
0N/A }
0N/A
0N/A private void debugException(Throwable e) {
0N/A if (DEBUG) {
0N/A e.printStackTrace();
0N/A }
0N/A }
0N/A
0N/A}