Save This Page
Home » openjdk-7 » sun » misc » [javadoc | source]
    1   /*
    2    * Copyright (c) 1999, 2011, 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;
   29   import java.util;
   30   import java.util.jar;
   31   import java.util.zip;
   32   
   33   /**
   34    * This class is used to maintain mappings from packages, classes
   35    * and resources to their enclosing JAR files. Mappings are kept
   36    * at the package level except for class or resource files that
   37    * are located at the root directory. URLClassLoader uses the mapping
   38    * information to determine where to fetch an extension class or
   39    * resource from.
   40    *
   41    * @author  Zhenghua Li
   42    * @since   1.3
   43    */
   44   
   45   public class JarIndex {
   46   
   47       /**
   48        * The hash map that maintains mappings from
   49        * package/classe/resource to jar file list(s)
   50        */
   51       private HashMap indexMap;
   52   
   53       /**
   54        * The hash map that maintains mappings from
   55        * jar file to package/class/resource lists
   56        */
   57       private HashMap jarMap;
   58   
   59       /*
   60        * An ordered list of jar file names.
   61        */
   62       private String[] jarFiles;
   63   
   64       /**
   65        * The index file name.
   66        */
   67       public static final String INDEX_NAME = "META-INF/INDEX.LIST";
   68   
   69       /**
   70        * true if, and only if, sun.misc.JarIndex.metaInfFilenames is set to true.
   71        * If true, the names of the files in META-INF, and its subdirectories, will
   72        * be added to the index. Otherwise, just the directory names are added.
   73        */
   74       private static final boolean metaInfFilenames =
   75           "true".equals(System.getProperty("sun.misc.JarIndex.metaInfFilenames"));
   76   
   77       /**
   78        * Constructs a new, empty jar index.
   79        */
   80       public JarIndex() {
   81           indexMap = new HashMap();
   82           jarMap = new HashMap();
   83       }
   84   
   85       /**
   86        * Constructs a new index from the specified input stream.
   87        *
   88        * @param is the input stream containing the index data
   89        */
   90       public JarIndex(InputStream is) throws IOException {
   91           this();
   92           read(is);
   93       }
   94   
   95       /**
   96        * Constructs a new index for the specified list of jar files.
   97        *
   98        * @param files the list of jar files to construct the index from.
   99        */
  100       public JarIndex(String[] files) throws IOException {
  101           this();
  102           this.jarFiles = files;
  103           parseJars(files);
  104       }
  105   
  106       /**
  107        * Returns the jar index, or <code>null</code> if none.
  108        *
  109        * This single parameter version of the method is retained
  110        * for binary compatibility with earlier releases.
  111        *
  112        * @param jar the JAR file to get the index from.
  113        * @exception IOException if an I/O error has occurred.
  114        */
  115       public static JarIndex getJarIndex(JarFile jar) throws IOException {
  116           return getJarIndex(jar, null);
  117       }
  118   
  119       /**
  120        * Returns the jar index, or <code>null</code> if none.
  121        *
  122        * @param jar the JAR file to get the index from.
  123        * @exception IOException if an I/O error has occurred.
  124        */
  125       public static JarIndex getJarIndex(JarFile jar, MetaIndex metaIndex) throws IOException {
  126           JarIndex index = null;
  127           /* If metaIndex is not null, check the meta index to see
  128              if META-INF/INDEX.LIST is contained in jar file or not.
  129           */
  130           if (metaIndex != null &&
  131               !metaIndex.mayContain(INDEX_NAME)) {
  132               return null;
  133           }
  134           JarEntry e = jar.getJarEntry(INDEX_NAME);
  135           // if found, then load the index
  136           if (e != null) {
  137               index = new JarIndex(jar.getInputStream(e));
  138           }
  139           return index;
  140       }
  141   
  142       /**
  143        * Returns the jar files that are defined in this index.
  144        */
  145       public String[] getJarFiles() {
  146           return jarFiles;
  147       }
  148   
  149       /*
  150        * Add the key, value pair to the hashmap, the value will
  151        * be put in a linked list which is created if necessary.
  152        */
  153       private void addToList(String key, String value, HashMap t) {
  154           LinkedList list = (LinkedList)t.get(key);
  155           if (list == null) {
  156               list = new LinkedList();
  157               list.add(value);
  158               t.put(key, list);
  159           } else if (!list.contains(value)) {
  160               list.add(value);
  161           }
  162       }
  163   
  164       /**
  165        * Returns the list of jar files that are mapped to the file.
  166        *
  167        * @param fileName the key of the mapping
  168        */
  169       public LinkedList get(String fileName) {
  170           LinkedList jarFiles = null;
  171           if ((jarFiles = (LinkedList)indexMap.get(fileName)) == null) {
  172               /* try the package name again */
  173               int pos;
  174               if((pos = fileName.lastIndexOf("/")) != -1) {
  175                   jarFiles = (LinkedList)indexMap.get(fileName.substring(0, pos));
  176               }
  177           }
  178           return jarFiles;
  179       }
  180   
  181       /**
  182        * Add the mapping from the specified file to the specified
  183        * jar file. If there were no mapping for the package of the
  184        * specified file before, a new linked list will be created,
  185        * the jar file is added to the list and a new mapping from
  186        * the package to the jar file list is added to the hashmap.
  187        * Otherwise, the jar file will be added to the end of the
  188        * existing list.
  189        *
  190        * @param fileName the file name
  191        * @param jarName the jar file that the file is mapped to
  192        *
  193        */
  194       public void add(String fileName, String jarName) {
  195           String packageName;
  196           int pos;
  197           if((pos = fileName.lastIndexOf("/")) != -1) {
  198               packageName = fileName.substring(0, pos);
  199           } else {
  200               packageName = fileName;
  201           }
  202   
  203           // add the mapping to indexMap
  204           addToList(packageName, jarName, indexMap);
  205   
  206           // add the mapping to jarMap
  207           addToList(jarName, packageName, jarMap);
  208       }
  209   
  210       /**
  211        * Same as add(String,String) except that it doesn't strip off from the
  212        * last index of '/'. It just adds the filename.
  213        */
  214       private void addExplicit(String fileName, String jarName) {
  215           // add the mapping to indexMap
  216           addToList(fileName, jarName, indexMap);
  217   
  218           // add the mapping to jarMap
  219           addToList(jarName, fileName, jarMap);
  220        }
  221   
  222       /**
  223        * Go through all the jar files and construct the
  224        * index table.
  225        */
  226       private void parseJars(String[] files) throws IOException {
  227           if (files == null) {
  228               return;
  229           }
  230   
  231           String currentJar = null;
  232   
  233           for (int i = 0; i < files.length; i++) {
  234               currentJar = files[i];
  235               ZipFile zrf = new ZipFile(currentJar.replace
  236                                         ('/', File.separatorChar));
  237   
  238               Enumeration entries = zrf.entries();
  239               while(entries.hasMoreElements()) {
  240                   ZipEntry entry = (ZipEntry) entries.nextElement();
  241                   String fileName = entry.getName();
  242   
  243                   // Skip the META-INF directory, the index, and manifest.
  244                   // Any files in META-INF/ will be indexed explicitly
  245                   if (fileName.equals("META-INF/") ||
  246                       fileName.equals(INDEX_NAME) ||
  247                       fileName.equals(JarFile.MANIFEST_NAME))
  248                       continue;
  249   
  250                   if (!metaInfFilenames) {
  251                       add(fileName, currentJar);
  252                   } else {
  253                       if (!fileName.startsWith("META-INF/")) {
  254                           add(fileName, currentJar);
  255                       } else if (!entry.isDirectory()) {
  256                           // Add files under META-INF explicitly so that certain
  257                           // services, like ServiceLoader, etc, can be located
  258                           // with greater accuracy. Directories can be skipped
  259                           // since each file will be added explicitly.
  260                           addExplicit(fileName, currentJar);
  261                       }
  262                   }
  263               }
  264   
  265               zrf.close();
  266           }
  267       }
  268   
  269       /**
  270        * Writes the index to the specified OutputStream
  271        *
  272        * @param out the output stream
  273        * @exception IOException if an I/O error has occurred
  274        */
  275       public void write(OutputStream out) throws IOException {
  276           BufferedWriter bw = new BufferedWriter
  277               (new OutputStreamWriter(out, "UTF8"));
  278           bw.write("JarIndex-Version: 1.0\n\n");
  279   
  280           if (jarFiles != null) {
  281               for (int i = 0; i < jarFiles.length; i++) {
  282                   /* print out the jar file name */
  283                   String jar = jarFiles[i];
  284                   bw.write(jar + "\n");
  285                   LinkedList jarlist = (LinkedList)jarMap.get(jar);
  286                   if (jarlist != null) {
  287                       Iterator listitr = jarlist.iterator();
  288                       while(listitr.hasNext()) {
  289                           bw.write((String)(listitr.next()) + "\n");
  290                       }
  291                   }
  292                   bw.write("\n");
  293               }
  294               bw.flush();
  295           }
  296       }
  297   
  298   
  299       /**
  300        * Reads the index from the specified InputStream.
  301        *
  302        * @param is the input stream
  303        * @exception IOException if an I/O error has occurred
  304        */
  305       public void read(InputStream is) throws IOException {
  306           BufferedReader br = new BufferedReader
  307               (new InputStreamReader(is, "UTF8"));
  308           String line = null;
  309           String currentJar = null;
  310   
  311           /* an ordered list of jar file names */
  312           Vector jars = new Vector();
  313   
  314           /* read until we see a .jar line */
  315           while((line = br.readLine()) != null && !line.endsWith(".jar"));
  316   
  317           for(;line != null; line = br.readLine()) {
  318               if (line.length() == 0)
  319                   continue;
  320   
  321               if (line.endsWith(".jar")) {
  322                   currentJar = line;
  323                   jars.add(currentJar);
  324               } else {
  325                   String name = line;
  326                   addToList(name, currentJar, indexMap);
  327                   addToList(currentJar, name, jarMap);
  328               }
  329           }
  330   
  331           jarFiles = (String[])jars.toArray(new String[jars.size()]);
  332       }
  333   
  334       /**
  335        * Merges the current index into another index, taking into account
  336        * the relative path of the current index.
  337        *
  338        * @param toIndex The destination index which the current index will
  339        *                merge into.
  340        * @param path    The relative path of the this index to the destination
  341        *                index.
  342        *
  343        */
  344       public void merge(JarIndex toIndex, String path) {
  345           Iterator itr = indexMap.entrySet().iterator();
  346           while(itr.hasNext()) {
  347               Map.Entry e = (Map.Entry)itr.next();
  348               String packageName = (String)e.getKey();
  349               LinkedList from_list = (LinkedList)e.getValue();
  350               Iterator listItr = from_list.iterator();
  351               while(listItr.hasNext()) {
  352                   String jarName = (String)listItr.next();
  353                   if (path != null) {
  354                       jarName = path.concat(jarName);
  355                   }
  356                   toIndex.add(packageName, jarName);
  357               }
  358           }
  359       }
  360   }

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