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

Save This Page
Home » openjdk-7 » sun » misc » [javadoc | source]