jdk/src/java.base/share/classes/sun/misc/ExtensionDependency.java
changeset 31402 78cd32274693
parent 31401 1514c0a798d2
parent 31238 a66084451ee2
child 31412 32477ea959ee
child 31593 7b9e292896d2
child 31594 1b71ba1c8c35
child 31597 f63dde8cc8f7
child 31599 f1b42743d3ee
child 31604 5d0a8a6d6570
equal deleted inserted replaced
31401:1514c0a798d2 31402:78cd32274693
     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 }