Showing the changes to java/pkg/sun/misc/JarIndex.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,360 @@ | |||
| 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 | } | ||