/* * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.misc; import java.io.BufferedReader; import java.io.FileReader; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /* * MetaIndex is intended to decrease startup time (in particular cold * start, when files are not yet in the disk cache) by providing a * quick reject mechanism for probes into jar files. The on-disk * representation of the meta-index is a flat text file with per-jar * entries indicating (generally speaking) prefixes of package names * contained in the jar. As an example, here is an edited excerpt of * the meta-index generated for jre/lib in the current build: *
% VERSION 1
# charsets.jar
sun/
# jce.jar
javax/
! jsse.jar
sun/
com/sun/net/
javax/
com/sun/security/
@ resources.jar
com/sun/xml/
com/sun/rowset/
com/sun/org/
sun/
com/sun/imageio/
javax/
com/sun/java/swing/
META-INF/services/
com/sun/java/util/jar/pack/
com/sun/corba/
com/sun/jndi/
! rt.jar
org/w3c/
com/sun/imageio/
javax/
java/
sun/
...
*

A few notes about the design of the meta-index: * *

* *

To avoid changing the behavior of the current application * loader and other loaders, the current MetaIndex implementation in * the JDK requires that the directory containing the meta-index be * registered with the MetaIndex class before construction of the * associated URLClassPath. This prevents the need for automatic * searching for the meta-index in the URLClassPath code and potential * changes in behavior for non-core ClassLoaders. * * This class depends on make/tools/MetaIndex/BuildMetaIndex.java and * is used principally by sun.misc.URLClassPath. */ public class MetaIndex { // Maps jar file names in registered directories to meta-indices private static volatile Map jarMap; // List of contents of this meta-index private String[] contents; // Indicate whether the coresponding jar file is a pure class jar file or not private boolean isClassOnlyJar; //---------------------------------------------------------------------- // Registration of directories (which can cause parsing of the // meta-index file if it is present), and fetching of parsed // meta-indices // jarMap is not strictly thread-safe when the meta index mechanism // is extended for user-provided jar files in future. public static MetaIndex forJar(File jar) { return getJarMap().get(jar); } // 'synchronized' is added to protect the jarMap from being modified // by multiple threads. public static synchronized void registerDirectory(File dir) { // Note that this does not currently check to see whether the // directory has previously been registered, since the meta-index // in a particular directory creates multiple entries in the // jarMap. If this mechanism is extended beyond the boot and // extension class paths (for example, automatically searching for // meta-index files in directories containing jars which have been // explicitly opened) then this code should be generalized. // // This method must be called from a privileged context. File indexFile = new File(dir, "meta-index"); if (indexFile.exists()) { try { BufferedReader reader = new BufferedReader(new FileReader(indexFile)); String line = null; String curJarName = null; boolean isCurJarContainClassOnly = false; List contents = new ArrayList(); Map map = getJarMap(); /* Convert dir into canonical form. */ dir = dir.getCanonicalFile(); /* Note: The first line should contain the version of * the meta-index file. We have to match the right version * before trying to parse this file. */ line = reader.readLine(); if (line == null || !line.equals("% VERSION 2")) { reader.close(); return; } while ((line = reader.readLine()) != null) { switch (line.charAt(0)) { case '!': case '#': case '@': { // Store away current contents, if any if ((curJarName != null) && (contents.size() > 0)) { map.put(new File(dir, curJarName), new MetaIndex(contents, isCurJarContainClassOnly)); contents.clear(); } // Fetch new current jar file name curJarName = line.substring(2); if (line.charAt(0) == '!') { isCurJarContainClassOnly = true; } else if (isCurJarContainClassOnly) { isCurJarContainClassOnly = false; } break; } case '%': break; default: { contents.add(line); } } } // Store away current contents, if any if ((curJarName != null) && (contents.size() > 0)) { map.put(new File(dir, curJarName), new MetaIndex(contents, isCurJarContainClassOnly)); } reader.close(); } catch (IOException e) { // Silently fail for now (similar behavior to elsewhere in // extension and core loaders) } } } //---------------------------------------------------------------------- // Public APIs // public boolean mayContain(String entry) { // Ask non-class file from class only jar returns false // This check is important to avoid some class only jar // files such as rt.jar are opened for resource request. if (isClassOnlyJar && !entry.endsWith(".class")){ return false; } String[] conts = contents; for (int i = 0; i < conts.length; i++) { if (entry.startsWith(conts[i])) { return true; } } return false; } //---------------------------------------------------------------------- // Implementation only below this point // @IllegalArgumentException if entries is null. private MetaIndex(List entries, boolean isClassOnlyJar) throws IllegalArgumentException { if (entries == null) { throw new IllegalArgumentException(); } contents = entries.toArray(new String[0]); this.isClassOnlyJar = isClassOnlyJar; } private static Map getJarMap() { if (jarMap == null) { synchronized (MetaIndex.class) { if (jarMap == null) { jarMap = new HashMap(); } } } assert jarMap != null; return jarMap; } }