jdk/src/java.base/share/classes/sun/misc/ExtensionDependency.java
changeset 31593 7b9e292896d2
parent 31592 43f48e165466
parent 31402 78cd32274693
child 31596 64bfaa6d10a9
equal deleted inserted replaced
31592:43f48e165466 31593:7b9e292896d2
     1 /*
       
     2  * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.misc;
       
    27 
       
    28 import java.io.File;
       
    29 import java.io.FilenameFilter;
       
    30 import java.io.IOException;
       
    31 import java.io.FileNotFoundException;
       
    32 import java.util.StringTokenizer;
       
    33 import java.util.Vector;
       
    34 import java.util.Enumeration;
       
    35 import java.util.jar.JarFile;
       
    36 import java.util.jar.Manifest;
       
    37 import java.util.jar.Attributes;
       
    38 import java.util.jar.Attributes.Name;
       
    39 import java.security.AccessController;
       
    40 import java.security.PrivilegedAction;
       
    41 import java.security.PrivilegedExceptionAction;
       
    42 import java.security.PrivilegedActionException;
       
    43 import java.net.URL;
       
    44 import java.net.MalformedURLException;
       
    45 import sun.net.www.ParseUtil;
       
    46 
       
    47 /**
       
    48  * This class checks dependent extensions a particular jar file may have
       
    49  * declared through its manifest attributes.
       
    50  * <p>
       
    51  * Jar file declared dependent extensions through the extension-list
       
    52  * attribute. The extension-list contains a list of keys used to
       
    53  * fetch the other attributes describing the required extension.
       
    54  * If key is the extension key declared in the extension-list
       
    55  * attribute, the following describing attribute can be found in
       
    56  * the manifest:
       
    57  * <ul>
       
    58  * <li>key-Extension-Name:  (Specification package name)</li>
       
    59  * <li>key-Specification-Version: (Specification-Version)</li>
       
    60  * <li>key-Implementation-Version: (Implementation-Version)</li>
       
    61  * <li>key-Implementation-Vendor-Id: (Imlementation-Vendor-Id)</li>
       
    62  * <li>key-Implementation-Version: (Implementation version)</li>
       
    63  * <li>key-Implementation-URL: (URL to download the requested extension)</li>
       
    64  * </ul>
       
    65  * <p>
       
    66  * This class also maintain versioning consistency of installed
       
    67  * extensions dependencies declared in jar file manifest.
       
    68  *
       
    69  * @deprecated this class will be removed in a future release.
       
    70  * @author  Jerome Dochez
       
    71  */
       
    72 @Deprecated
       
    73 public class ExtensionDependency {
       
    74 
       
    75     /* Callbak interfaces to delegate installation of missing extensions */
       
    76     private static Vector<ExtensionInstallationProvider> providers;
       
    77 
       
    78     /**
       
    79      * Register an ExtensionInstallationProvider. The provider is responsible
       
    80      * for handling the installation (upgrade) of any missing extensions.
       
    81      *
       
    82      * @param eip ExtensionInstallationProvider implementation
       
    83      */
       
    84     public synchronized static void addExtensionInstallationProvider
       
    85         (ExtensionInstallationProvider eip)
       
    86     {
       
    87         if (providers == null) {
       
    88             providers = new Vector<>();
       
    89         }
       
    90         providers.add(eip);
       
    91     }
       
    92 
       
    93     /**
       
    94      * Unregister a previously installed installation provider
       
    95      */
       
    96     public synchronized static void removeExtensionInstallationProvider
       
    97         (ExtensionInstallationProvider eip)
       
    98     {
       
    99         providers.remove(eip);
       
   100     }
       
   101 
       
   102     /**
       
   103      * Checks the dependencies of the jar file on installed extension.
       
   104      *
       
   105      * @param jar containing the attributes declaring the dependencies
       
   106      */
       
   107     public static boolean checkExtensionsDependencies(JarFile jar)
       
   108     {
       
   109         if (providers == null) {
       
   110             // no need to bother, nobody is registered to install missing
       
   111             // extensions
       
   112             return true;
       
   113         }
       
   114 
       
   115         try {
       
   116             ExtensionDependency extDep = new ExtensionDependency();
       
   117             return extDep.checkExtensions(jar);
       
   118         } catch (ExtensionInstallationException e) {
       
   119             debug(e.getMessage());
       
   120         }
       
   121         return false;
       
   122     }
       
   123 
       
   124     /*
       
   125      * Check for all declared required extensions in the jar file
       
   126      * manifest.
       
   127      */
       
   128     protected boolean checkExtensions(JarFile jar)
       
   129         throws ExtensionInstallationException
       
   130     {
       
   131         Manifest man;
       
   132         try {
       
   133             man = jar.getManifest();
       
   134         } catch (IOException e) {
       
   135             return false;
       
   136         }
       
   137 
       
   138         if (man == null) {
       
   139             // The applet does not define a manifest file, so
       
   140             // we just assume all dependencies are satisfied.
       
   141             return true;
       
   142         }
       
   143 
       
   144         boolean result = true;
       
   145         Attributes attr = man.getMainAttributes();
       
   146         if (attr != null) {
       
   147             // Let's get the list of declared dependencies
       
   148             String value = attr.getValue(Name.EXTENSION_LIST);
       
   149             if (value != null) {
       
   150                 StringTokenizer st = new StringTokenizer(value);
       
   151                 // Iterate over all declared dependencies
       
   152                 while (st.hasMoreTokens()) {
       
   153                     String extensionName = st.nextToken();
       
   154                     debug("The file " + jar.getName() +
       
   155                           " appears to depend on " + extensionName);
       
   156                     // Sanity Check
       
   157                     String extName = extensionName + "-" +
       
   158                         Name.EXTENSION_NAME.toString();
       
   159                     if (attr.getValue(extName) == null) {
       
   160                         debug("The jar file " + jar.getName() +
       
   161                               " appers to depend on "
       
   162                               + extensionName + " but does not define the " +
       
   163                               extName + " attribute in its manifest ");
       
   164 
       
   165                     } else {
       
   166                         if (!checkExtension(extensionName, attr)) {
       
   167                             debug("Failed installing " + extensionName);
       
   168                             result = false;
       
   169                         }
       
   170                     }
       
   171                 }
       
   172             } else {
       
   173                 debug("No dependencies for " + jar.getName());
       
   174             }
       
   175         }
       
   176         return result;
       
   177     }
       
   178 
       
   179 
       
   180     /*
       
   181      * Check that a particular dependency on an extension is satisfied.
       
   182      *
       
   183      * @param extensionName is the key used for the attributes in the manifest
       
   184      * @param attr is the attributes of the manifest file
       
   185      *
       
   186      * @return true if the dependency is satisfied by the installed extensions
       
   187      */
       
   188     protected synchronized boolean checkExtension(final String extensionName,
       
   189                                      final Attributes attr)
       
   190         throws ExtensionInstallationException
       
   191     {
       
   192         debug("Checking extension " + extensionName);
       
   193         if (checkExtensionAgainstInstalled(extensionName, attr))
       
   194             return true;
       
   195 
       
   196         debug("Extension not currently installed ");
       
   197         ExtensionInfo reqInfo = new ExtensionInfo(extensionName, attr);
       
   198         return installExtension(reqInfo, null);
       
   199     }
       
   200 
       
   201     /*
       
   202      * Check if a particular extension is part of the currently installed
       
   203      * extensions.
       
   204      *
       
   205      * @param extensionName is the key for the attributes in the manifest
       
   206      * @param attr is the attributes of the manifest
       
   207      *
       
   208      * @return true if the requested extension is already installed
       
   209      */
       
   210     boolean checkExtensionAgainstInstalled(String extensionName,
       
   211                                            Attributes attr)
       
   212         throws ExtensionInstallationException
       
   213     {
       
   214         File fExtension = checkExtensionExists(extensionName);
       
   215 
       
   216         if (fExtension != null) {
       
   217         // Extension already installed, just check against this one
       
   218             try {
       
   219                 if (checkExtensionAgainst(extensionName, attr, fExtension))
       
   220                     return true;
       
   221             } catch (FileNotFoundException e) {
       
   222                 debugException(e);
       
   223             } catch (IOException e) {
       
   224                 debugException(e);
       
   225             }
       
   226             return false;
       
   227 
       
   228         } else {
       
   229         // Not sure if extension is already installed, so check all the
       
   230         // installed extension jar files to see if we get a match
       
   231 
       
   232             File[] installedExts;
       
   233 
       
   234             try {
       
   235             // Get the list of installed extension jar files so we can
       
   236             // compare the installed versus the requested extension
       
   237                 installedExts = getInstalledExtensions();
       
   238             } catch(IOException e) {
       
   239                 debugException(e);
       
   240                 return false;
       
   241             }
       
   242 
       
   243             for (int i=0;i<installedExts.length;i++) {
       
   244                 try {
       
   245                     if (checkExtensionAgainst(extensionName, attr, installedExts[i]))
       
   246                         return true;
       
   247                 } catch (FileNotFoundException e) {
       
   248                     debugException(e);
       
   249                 } catch (IOException e) {
       
   250                     debugException(e);
       
   251                     // let's continue with the next installed extension
       
   252                 }
       
   253             }
       
   254         }
       
   255         return false;
       
   256     }
       
   257 
       
   258     /*
       
   259      * Check if the requested extension described by the attributes
       
   260      * in the manifest under the key extensionName is compatible with
       
   261      * the jar file.
       
   262      *
       
   263      * @param extensionName key in the attribute list
       
   264      * @param attr manifest file attributes
       
   265      * @param file installed extension jar file to compare the requested
       
   266      * extension against.
       
   267      */
       
   268     protected boolean checkExtensionAgainst(String extensionName,
       
   269                                             Attributes attr,
       
   270                                             final File file)
       
   271         throws IOException,
       
   272                FileNotFoundException,
       
   273                ExtensionInstallationException
       
   274     {
       
   275 
       
   276         debug("Checking extension " + extensionName +
       
   277               " against " + file.getName());
       
   278 
       
   279         // Load the jar file ...
       
   280         Manifest man;
       
   281         try {
       
   282             man = AccessController.doPrivileged(
       
   283                 new PrivilegedExceptionAction<Manifest>() {
       
   284                     public Manifest run()
       
   285                             throws IOException, FileNotFoundException {
       
   286                          if (!file.exists())
       
   287                              throw new FileNotFoundException(file.getName());
       
   288                          JarFile jarFile =  new JarFile(file);
       
   289                          return jarFile.getManifest();
       
   290                      }
       
   291                  });
       
   292         } catch(PrivilegedActionException e) {
       
   293             if (e.getException() instanceof FileNotFoundException)
       
   294                 throw (FileNotFoundException) e.getException();
       
   295             throw (IOException) e.getException();
       
   296         }
       
   297 
       
   298         // Construct the extension information object
       
   299         ExtensionInfo reqInfo = new ExtensionInfo(extensionName, attr);
       
   300         debug("Requested Extension : " + reqInfo);
       
   301 
       
   302         int isCompatible = ExtensionInfo.INCOMPATIBLE;
       
   303         ExtensionInfo instInfo = null;
       
   304 
       
   305         if (man != null) {
       
   306             Attributes instAttr = man.getMainAttributes();
       
   307             if (instAttr != null) {
       
   308                 instInfo = new ExtensionInfo(null, instAttr);
       
   309                 debug("Extension Installed " + instInfo);
       
   310                 isCompatible = instInfo.isCompatibleWith(reqInfo);
       
   311                 switch(isCompatible) {
       
   312                 case ExtensionInfo.COMPATIBLE:
       
   313                     debug("Extensions are compatible");
       
   314                     return true;
       
   315 
       
   316                 case ExtensionInfo.INCOMPATIBLE:
       
   317                     debug("Extensions are incompatible");
       
   318                     return false;
       
   319 
       
   320                 default:
       
   321                     // everything else
       
   322                     debug("Extensions require an upgrade or vendor switch");
       
   323                     return installExtension(reqInfo, instInfo);
       
   324 
       
   325                 }
       
   326             }
       
   327         }
       
   328         return false;
       
   329     }
       
   330 
       
   331     /*
       
   332      * An required extension is missing, if an ExtensionInstallationProvider is
       
   333      * registered, delegate the installation of that particular extension to it.
       
   334      *
       
   335      * @param reqInfo Missing extension information
       
   336      * @param instInfo Older installed version information
       
   337      *
       
   338      * @return true if the installation is successful
       
   339      */
       
   340     protected boolean installExtension(ExtensionInfo reqInfo,
       
   341                                        ExtensionInfo instInfo)
       
   342         throws ExtensionInstallationException
       
   343     {
       
   344         Vector<ExtensionInstallationProvider> currentProviders;
       
   345         synchronized(providers) {
       
   346             @SuppressWarnings("unchecked")
       
   347             Vector<ExtensionInstallationProvider> tmp =
       
   348                 (Vector<ExtensionInstallationProvider>) providers.clone();
       
   349             currentProviders = tmp;
       
   350         }
       
   351         for (Enumeration<ExtensionInstallationProvider> e = currentProviders.elements();
       
   352                 e.hasMoreElements();) {
       
   353             ExtensionInstallationProvider eip = e.nextElement();
       
   354 
       
   355             if (eip!=null) {
       
   356                 // delegate the installation to the provider
       
   357                 if (eip.installExtension(reqInfo, instInfo)) {
       
   358                     debug(reqInfo.name + " installation successful");
       
   359                     Launcher.ExtClassLoader cl = (Launcher.ExtClassLoader)
       
   360                         Launcher.getLauncher().getClassLoader().getParent();
       
   361                     addNewExtensionsToClassLoader(cl);
       
   362                     return true;
       
   363                 }
       
   364             }
       
   365         }
       
   366         // We have tried all of our providers, noone could install this
       
   367         // extension, we just return failure at this point
       
   368         debug(reqInfo.name + " installation failed");
       
   369         return false;
       
   370     }
       
   371 
       
   372     /**
       
   373      * Checks if the extension, that is specified in the extension-list in
       
   374      * the applet jar manifest, is already installed (i.e. exists in the
       
   375      * extension directory).
       
   376      *
       
   377      * @param extensionName extension name in the extension-list
       
   378      *
       
   379      * @return the extension if it exists in the extension directory
       
   380      */
       
   381     private File checkExtensionExists(String extensionName) {
       
   382         // Function added to fix bug 4504166
       
   383         final String extName = extensionName;
       
   384         final String[] fileExt = {".jar", ".zip"};
       
   385 
       
   386         return AccessController.doPrivileged(
       
   387             new PrivilegedAction<File>() {
       
   388                 public File run() {
       
   389                     try {
       
   390                         File fExtension;
       
   391                         File[] dirs = getExtDirs();
       
   392 
       
   393                         // Search the extension directories for the extension that is specified
       
   394                         // in the attribute extension-list in the applet jar manifest
       
   395                         for (int i=0;i<dirs.length;i++) {
       
   396                             for (int j=0;j<fileExt.length;j++) {
       
   397                                 if (extName.toLowerCase().endsWith(fileExt[j])) {
       
   398                                     fExtension = new File(dirs[i], extName);
       
   399                                 } else {
       
   400                                     fExtension = new File(dirs[i], extName+fileExt[j]);
       
   401                                 }
       
   402                                 debug("checkExtensionExists:fileName " + fExtension.getName());
       
   403                                 if (fExtension.exists()) {
       
   404                                     return fExtension;
       
   405                                 }
       
   406                             }
       
   407                         }
       
   408                         return null;
       
   409 
       
   410                     } catch(Exception e) {
       
   411                          debugException(e);
       
   412                          return null;
       
   413                     }
       
   414                 }
       
   415             });
       
   416     }
       
   417 
       
   418     /**
       
   419      * @return the java.ext.dirs property as a list of directory
       
   420      */
       
   421     private static File[] getExtDirs() {
       
   422         String s = java.security.AccessController.doPrivileged(
       
   423                 new sun.security.action.GetPropertyAction("java.ext.dirs"));
       
   424 
       
   425         File[] dirs;
       
   426         if (s != null) {
       
   427             StringTokenizer st =
       
   428                 new StringTokenizer(s, File.pathSeparator);
       
   429             int count = st.countTokens();
       
   430             debug("getExtDirs count " + count);
       
   431             dirs = new File[count];
       
   432             for (int i = 0; i < count; i++) {
       
   433                 dirs[i] = new File(st.nextToken());
       
   434                 debug("getExtDirs dirs["+i+"] "+ dirs[i]);
       
   435             }
       
   436         } else {
       
   437             dirs = new File[0];
       
   438             debug("getExtDirs dirs " + dirs);
       
   439         }
       
   440         debug("getExtDirs dirs.length " + dirs.length);
       
   441         return dirs;
       
   442     }
       
   443 
       
   444     /*
       
   445      * Scan the directories and return all files installed in those
       
   446      *
       
   447      * @param dirs list of directories to scan
       
   448      *
       
   449      * @return the list of files installed in all the directories
       
   450      */
       
   451     private static File[] getExtFiles(File[] dirs) throws IOException {
       
   452         Vector<File> urls = new Vector<File>();
       
   453         for (int i = 0; i < dirs.length; i++) {
       
   454             String[] files = dirs[i].list(new JarFilter());
       
   455             if (files != null) {
       
   456                 debug("getExtFiles files.length " + files.length);
       
   457                 for (int j = 0; j < files.length; j++) {
       
   458                     File f = new File(dirs[i], files[j]);
       
   459                     urls.add(f);
       
   460                     debug("getExtFiles f["+j+"] "+ f);
       
   461                 }
       
   462             }
       
   463         }
       
   464         File[] ua = new File[urls.size()];
       
   465         urls.copyInto(ua);
       
   466         debug("getExtFiles ua.length " + ua.length);
       
   467         return ua;
       
   468     }
       
   469 
       
   470     /*
       
   471      * @return the list of installed extensions jar files
       
   472      */
       
   473     private File[] getInstalledExtensions() throws IOException {
       
   474         return AccessController.doPrivileged(
       
   475             new PrivilegedAction<File[]>() {
       
   476                 public File[] run() {
       
   477                      try {
       
   478                          return getExtFiles(getExtDirs());
       
   479                      } catch(IOException e) {
       
   480                          debug("Cannot get list of installed extensions");
       
   481                          debugException(e);
       
   482                         return new File[0];
       
   483                      }
       
   484                  }
       
   485             });
       
   486     }
       
   487 
       
   488     /*
       
   489      * Add the newly installed jar file to the extension class loader.
       
   490      *
       
   491      * @param cl the current installed extension class loader
       
   492      *
       
   493      * @return true if successful
       
   494      */
       
   495     private Boolean addNewExtensionsToClassLoader(Launcher.ExtClassLoader cl) {
       
   496         try {
       
   497             File[] installedExts = getInstalledExtensions();
       
   498             for (int i=0;i<installedExts.length;i++) {
       
   499                 final File instFile = installedExts[i];
       
   500                 URL instURL = AccessController.doPrivileged(
       
   501                     new PrivilegedAction<URL>() {
       
   502                         public URL run() {
       
   503                             try {
       
   504                                 return ParseUtil.fileToEncodedURL(instFile);
       
   505                             } catch (MalformedURLException e) {
       
   506                                 debugException(e);
       
   507                                 return null;
       
   508                             }
       
   509                         }
       
   510                     });
       
   511                 if (instURL != null) {
       
   512                     URL[] urls = cl.getURLs();
       
   513                     boolean found=false;
       
   514                     for (int j = 0; j<urls.length; j++) {
       
   515                         debug("URL["+j+"] is " + urls[j] + " looking for "+
       
   516                                            instURL);
       
   517                         if (urls[j].toString().compareToIgnoreCase(
       
   518                                     instURL.toString())==0) {
       
   519                             found=true;
       
   520                             debug("Found !");
       
   521                         }
       
   522                     }
       
   523                     if (!found) {
       
   524                         debug("Not Found ! adding to the classloader " +
       
   525                               instURL);
       
   526                         cl.addExtURL(instURL);
       
   527                     }
       
   528                 }
       
   529             }
       
   530         } catch (MalformedURLException e) {
       
   531             e.printStackTrace();
       
   532         } catch (IOException e) {
       
   533             e.printStackTrace();
       
   534             // let's continue with the next installed extension
       
   535         }
       
   536         return Boolean.TRUE;
       
   537     }
       
   538 
       
   539     // True to display all debug and trace messages
       
   540     static final boolean DEBUG = false;
       
   541 
       
   542     private static void debug(String s) {
       
   543         if (DEBUG) {
       
   544             System.err.println(s);
       
   545         }
       
   546     }
       
   547 
       
   548     private void debugException(Throwable e) {
       
   549         if (DEBUG) {
       
   550             e.printStackTrace();
       
   551         }
       
   552     }
       
   553 
       
   554 }