FileLocator.java revision 762:425ca13f66db
1/* 2 * Copyright (c) 1999, 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 * Licensed Materials - Property of IBM 27 * 5639-D57 (C) COPYRIGHT International Business Machines Corp. 1997,1998 28 * RMI-IIOP v1.0 29 * 30 */ 31 32package com.sun.tools.corba.se.idl.som.cff; 33 34import java.lang.Exception; 35import java.lang.String; 36import java.lang.System; 37import java.io.BufferedInputStream; 38import java.io.DataInputStream; 39import java.io.File; 40import java.io.FileInputStream; 41import java.io.FileNotFoundException; 42import java.io.InputStream; 43import java.io.IOException; 44import java.util.Locale; 45import java.util.NoSuchElementException; 46import java.util.Properties; 47import java.util.StringTokenizer; 48import java.util.zip.*; 49 50/** 51 * FileLocator is an abstract class (one that cannot be instantiated) that 52 * provides class methods for finding files in the directories or zip 53 * archives that make up the CLASSPATH. 54 * 55 * @author Larry K. Raper 56 */ 57public abstract class FileLocator extends Object { 58 59 /* Class variables */ 60 61 62 static final Properties pp = System.getProperties (); 63 static final String classPath = pp.getProperty ("java.class.path", "."); 64 static final String pathSeparator = pp.getProperty ("path.separator", ";"); 65 66 /* Instance variables */ 67 68 /* [None, no instances of this class are ever instantiated.] */ 69 70 /** 71 * locateClassFile returns a DataInputStream with mark/reset 72 * capability that can be used to read the requested class file. The 73 * CLASSPATH is used to locate the class. 74 * 75 * @param classFileName The name of the class to locate. The class name 76 * should be given in fully-qualified form, for example: 77 * <pre> 78 * java.lang.Object 79 * java.io.DataInputStream 80 * </pre> 81 * 82 * @exception java.io.FileNotFoundException The requested class file 83 * could not be found. 84 * @exception java.io.IOException The requested class file 85 * could not be opened. 86 */ 87 public static DataInputStream locateClassFile (String classFileName) 88 throws FileNotFoundException, IOException { 89 90 boolean notFound = true; 91 StringTokenizer st; 92 String path = ""; 93 String pathNameForm; 94 File cf = null; 95 NamedDataInputStream result; 96 97 st = new StringTokenizer (classPath, pathSeparator, false); 98 pathNameForm = classFileName.replace ('.', File.separatorChar) + 99 ".class"; 100 101 while (st.hasMoreTokens () && notFound) { 102 103 try {path = st.nextToken ();} 104 catch (NoSuchElementException nse) {break;} 105 int pLen = path.length (); 106 String pathLast4 = pLen > 3 ? path.substring (pLen - 4) : ""; 107 if (pathLast4.equalsIgnoreCase (".zip") || 108 pathLast4.equalsIgnoreCase (".jar")) { 109 110 try { 111 112 result = locateInZipFile (path, classFileName, true, true); 113 if (result == null) 114 continue; 115 return (DataInputStream) result; 116 117 } catch (ZipException zfe) { 118 continue; 119 } catch (IOException ioe) { 120 continue; 121 } 122 123 } else { 124 try {cf = new File (path + File.separator + pathNameForm); 125 } catch (NullPointerException npe) { continue; } 126 if ((cf != null) && cf.exists ()) 127 notFound = false; 128 } 129 } 130 131 if (notFound) { 132 133 /* Make one last attempt to find the file in the current 134 * directory 135 */ 136 137 int lastdot = classFileName.lastIndexOf ('.'); 138 String simpleName = 139 (lastdot >= 0) ? classFileName.substring (lastdot+1) : 140 classFileName; 141 142 result = new NamedDataInputStream (new BufferedInputStream ( 143 new FileInputStream (simpleName + ".class")), 144 simpleName + ".class", false); 145 return (DataInputStream) result; 146 } 147 148 result = new NamedDataInputStream (new BufferedInputStream ( 149 new FileInputStream (cf)), path + File.separator + pathNameForm, 150 false); 151 return (DataInputStream) result; 152 153 } 154 155 /** 156 * locateLocaleSpecificFileInClassPath returns a DataInputStream that 157 * can be used to read the requested file, but the name of the file is 158 * determined using information from the current locale and the supplied 159 * file name (which is treated as a "base" name, and is supplemented with 160 * country and language related suffixes, obtained from the current 161 * locale). The CLASSPATH is used to locate the file. 162 * 163 * @param fileName The name of the file to locate. The file name 164 * may be qualified with a partial path name, using '/' as the separator 165 * character or using separator characters appropriate for the host file 166 * system, in which case each directory or zip file in the CLASSPATH will 167 * be used as a base for finding the fully-qualified file. 168 * Here is an example of how the supplied fileName is used as a base 169 * for locating a locale-specific file: 170 * 171 * <pre> 172 * Supplied fileName: a/b/c/x.y, current locale: US English 173 * 174 * Look first for: a/b/c/x_en_US.y 175 * (if that fails) Look next for: a/b/c/x_en.y 176 * (if that fails) Look last for: a/b/c/x.y 177 * 178 * All elements of the class path are searched for each name, 179 * before the next possible name is tried. 180 * </pre> 181 * 182 * @exception java.io.FileNotFoundException The requested class file 183 * could not be found. 184 * @exception java.io.IOException The requested class file 185 * could not be opened. 186 */ 187 public static DataInputStream locateLocaleSpecificFileInClassPath ( 188 String fileName) throws FileNotFoundException, IOException { 189 190 String localeSuffix = "_" + Locale.getDefault ().toString (); 191 int lastSlash = fileName.lastIndexOf ('/'); 192 int lastDot = fileName.lastIndexOf ('.'); 193 String fnFront, fnEnd; 194 DataInputStream result = null; 195 boolean lastAttempt = false; 196 197 if ((lastDot > 0) && (lastDot > lastSlash)) { 198 fnFront = fileName.substring (0, lastDot); 199 fnEnd = fileName.substring (lastDot); 200 } else { 201 fnFront = fileName; 202 fnEnd = ""; 203 } 204 205 while (true) { 206 if (lastAttempt) 207 result = locateFileInClassPath (fileName); 208 else try { 209 result = locateFileInClassPath (fnFront + localeSuffix + fnEnd); 210 } catch (Exception e) { /* ignore */ } 211 if ((result != null) || lastAttempt) 212 break; 213 int lastUnderbar = localeSuffix.lastIndexOf ('_'); 214 if (lastUnderbar > 0) 215 localeSuffix = localeSuffix.substring (0, lastUnderbar); 216 else 217 lastAttempt = true; 218 } 219 return result; 220 221 } 222 223 /** 224 * locateFileInClassPath returns a DataInputStream that can be used 225 * to read the requested file. The resource is located in the java.corba 226 * module or if not found, then the CLASSPATH is searched. 227 * 228 * @param fileName The name of the file to locate. The file name 229 * may be qualified with a partial path name, using '/' as the separator 230 * character or using separator characters appropriate for the host file 231 * system, in which case each directory or zip file in the CLASSPATH will 232 * be used as a base for finding the fully-qualified file. 233 * 234 * @exception java.io.FileNotFoundException The requested class file 235 * could not be found. 236 * @exception java.io.IOException The requested class file 237 * could not be opened. 238 */ 239 public static DataInputStream locateFileInClassPath (String fileName) 240 throws FileNotFoundException, IOException { 241 242 // The resource should be in the java.corba module 243 InputStream in = FileLocator.class.getResourceAsStream("/" + fileName); 244 if (in != null) { 245 return new DataInputStream(in); 246 } 247 248 boolean notFound = true; 249 StringTokenizer st; 250 String path = ""; 251 File cf = null; 252 NamedDataInputStream result; 253 254 String zipEntryName = File.separatorChar == '/' ? fileName : 255 fileName.replace (File.separatorChar, '/'); 256 257 String localFileName = File.separatorChar == '/' ? fileName : 258 fileName.replace ('/', File.separatorChar); 259 260 st = new StringTokenizer (classPath, pathSeparator, false); 261 262 while (st.hasMoreTokens () && notFound) { 263 264 try {path = st.nextToken ();} 265 catch (NoSuchElementException nse) {break;} 266 int pLen = path.length (); 267 String pathLast4 = pLen > 3 ? path.substring (pLen - 4) : ""; 268 if (pathLast4.equalsIgnoreCase (".zip") || 269 pathLast4.equalsIgnoreCase (".jar")) { 270 271 try { 272 273 result = locateInZipFile (path, zipEntryName, false, false); 274 if (result == null) 275 continue; 276 return (DataInputStream) result; 277 278 } catch (ZipException zfe) { 279 continue; 280 } catch (IOException ioe) { 281 continue; 282 } 283 284 } else { 285 try {cf = new File (path + File.separator + localFileName); 286 } catch (NullPointerException npe) { continue; } 287 if ((cf != null) && cf.exists ()) 288 notFound = false; 289 } 290 } 291 292 if (notFound) { 293 294 /* Make one last attempt to find the file in the current 295 * directory 296 */ 297 298 int lastpart = localFileName.lastIndexOf (File.separator); 299 String simpleName = 300 (lastpart >= 0) ? localFileName.substring (lastpart+1) : 301 localFileName; 302 303 result = new NamedDataInputStream (new BufferedInputStream ( 304 new FileInputStream (simpleName)), simpleName, false); 305 return (DataInputStream) result; 306 } 307 308 result = new NamedDataInputStream (new BufferedInputStream ( 309 new FileInputStream (cf)), path + File.separator + localFileName, 310 false); 311 return (DataInputStream) result; 312 313 } 314 315 /** 316 * Returns the fully qualified file name associated with the passed 317 * DataInputStream <i>if the DataInputStream was created using one 318 * of the static locate methods supplied with this class</i>, otherwise 319 * returns a zero length string. 320 */ 321 public static String getFileNameFromStream (DataInputStream ds) { 322 323 if (ds instanceof NamedDataInputStream) 324 return ((NamedDataInputStream) ds).fullyQualifiedFileName; 325 return ""; 326 327 } 328 329 /** 330 * Returns an indication of whether the passed DataInputStream is 331 * associated with a member of a zip file <i>if the DataInputStream was 332 * created using one of the static locate methods supplied with this 333 * class</i>, otherwise returns false. 334 */ 335 public static boolean isZipFileAssociatedWithStream (DataInputStream ds) { 336 337 if (ds instanceof NamedDataInputStream) 338 return ((NamedDataInputStream) ds).inZipFile; 339 return false; 340 341 } 342 343 private static NamedDataInputStream locateInZipFile (String zipFileName, 344 String fileName, boolean wantClass, boolean buffered) 345 throws ZipException, IOException { 346 347 ZipFile zf; 348 ZipEntry ze; 349 zf = new ZipFile (zipFileName); 350 351 if (zf == null) 352 return null; 353 String zeName = wantClass ? 354 fileName.replace ('.', '/') + ".class" : 355 fileName; 356 357 // This code works with JDK 1.0 level SUN zip classes 358 // 359 360 // ze = zf.get (zeName); 361 // if (ze == null) 362 // return null; 363 // return new NamedDataInputStream ( 364 // new BufferedInputStream (new ZipInputStream (ze)), 365 // zipFileName + '(' +zeName + ')', true); 366 367 // This code works with JDK 1.0.2 and JDK 1.1 level SUN zip classes 368 // 369 370 ze = zf.getEntry (zeName); 371 if (ze == null) { 372 zf.close(); // D55355, D56419 373 zf = null; 374 return null; 375 } 376 InputStream istream = zf.getInputStream(ze); 377 if (buffered) 378 istream = new BufferedInputStream(istream); 379 return new NamedDataInputStream (istream, 380 zipFileName + '(' + zeName + ')', true); 381 382 } 383 384} 385 386/** 387 * This class is used to associate a filename with a DataInputStream 388 * The host platform's file naming conventions are assumed for the filename. 389 * 390 * @author Larry K. Raper 391 * 392 */ 393/* default access */ class NamedDataInputStream extends DataInputStream { 394 395 /* Instance variables */ 396 397 /** 398 * The name of the file associated with the DataInputStream. 399 */ 400 public String fullyQualifiedFileName; 401 402 /** 403 * Indicates whether or not the file is contained in a .zip file. 404 */ 405 public boolean inZipFile; 406 407 /* Constructors */ 408 409 protected NamedDataInputStream (InputStream in, String fullyQualifiedName, 410 boolean inZipFile) { 411 412 super (in); 413 this.fullyQualifiedFileName = fullyQualifiedName; 414 this.inZipFile = inZipFile; 415 416 } 417 418} 419