1 /* 2 * Copyright (c) 1996, 2012, 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 /*****************************************************************************/ 27 /* Copyright (c) IBM Corporation 1998 */ 28 /* */ 29 /* (C) Copyright IBM Corp. 1998 */ 30 /* */ 31 /*****************************************************************************/ 32 33 package sun.rmi.rmic; 34 35 import java.io.File; 36 import java.io.IOException; 37 import java.io.OutputStream; 38 import java.util.Collection; 39 import java.util.Enumeration; 40 import java.util.Iterator; 41 import java.util.LinkedHashSet; 42 import java.util.StringTokenizer; 43 import java.util.Vector; 44 import java.util.jar.JarFile; 45 import java.util.jar.Manifest; 46 import java.util.jar.Attributes; 47 import sun.tools.java.ClassPath; 48 49 /** 50 * BatchEnvironment for rmic extends javac's version in four ways: 51 * 1. It overrides errorString() to handle looking for rmic-specific 52 * error messages in rmic's resource bundle 53 * 2. It provides a mechanism for recording intermediate generated 54 * files so that they can be deleted later. 55 * 3. It holds a reference to the Main instance so that generators 56 * can refer to it. 57 * 4. It provides access to the ClassPath passed to the constructor. 58 * 59 * WARNING: The contents of this source file are not part of any 60 * supported API. Code that depends on them does so at its own risk: 61 * they are subject to change or removal without notice. 62 */ 63 64 public class BatchEnvironment extends sun.tools.javac.BatchEnvironment { 65 66 /** instance of Main which created this environment */ 67 private Main main; 68 69 /** 70 * Create a ClassPath object for rmic from a class path string. 71 */ createClassPath(String classPathString)72 public static ClassPath createClassPath(String classPathString) { 73 ClassPath[] paths = classPaths(null, classPathString, null, null); 74 return paths[1]; 75 } 76 77 /** 78 * Create a ClassPath object for rmic from the relevant command line 79 * options for class path, boot class path, and extension directories. 80 */ createClassPath(String classPathString, String sysClassPathString, String extDirsString)81 public static ClassPath createClassPath(String classPathString, 82 String sysClassPathString, 83 String extDirsString) 84 { 85 /** 86 * Previously, this method delegated to the 87 * sun.tools.javac.BatchEnvironment.classPaths method in order 88 * to supply default values for paths not specified on the 89 * command line, expand extensions directories into specific 90 * JAR files, and construct the ClassPath object-- but as part 91 * of the fix for 6473331, which adds support for Class-Path 92 * manifest entries in JAR files, those steps are now handled 93 * here directly, with the help of a Path utility class copied 94 * from the new javac implementation (see below). 95 */ 96 Path path = new Path(); 97 98 if (sysClassPathString == null) { 99 sysClassPathString = System.getProperty("sun.boot.class.path"); 100 } 101 if (sysClassPathString != null) { 102 path.addFiles(sysClassPathString); 103 } 104 105 /* 106 * Class-Path manifest entries are supported for JAR files 107 * everywhere except in the boot class path. 108 */ 109 path.expandJarClassPaths(true); 110 111 if (extDirsString == null) { 112 extDirsString = System.getProperty("java.ext.dirs"); 113 } 114 if (extDirsString != null) { 115 path.addDirectories(extDirsString); 116 } 117 118 /* 119 * In the application class path, an empty element means 120 * the current working directory. 121 */ 122 path.emptyPathDefault("."); 123 124 if (classPathString == null) { 125 // The env.class.path property is the user's CLASSPATH 126 // environment variable, and it set by the wrapper (ie, 127 // javac.exe). 128 classPathString = System.getProperty("env.class.path"); 129 if (classPathString == null) { 130 classPathString = "."; 131 } 132 } 133 path.addFiles(classPathString); 134 135 return new ClassPath(path.toArray(new String[path.size()])); 136 } 137 138 /** 139 * Create a BatchEnvironment for rmic with the given class path, 140 * stream for messages and Main. 141 */ BatchEnvironment(OutputStream out, ClassPath path, Main main)142 public BatchEnvironment(OutputStream out, ClassPath path, Main main) { 143 super(out, new ClassPath(""), path); 144 // use empty "sourcePath" (see 4666958) 145 this.main = main; 146 } 147 148 /** 149 * Get the instance of Main which created this environment. 150 */ getMain()151 public Main getMain() { 152 return main; 153 } 154 155 /** 156 * Get the ClassPath. 157 */ getClassPath()158 public ClassPath getClassPath() { 159 return binaryPath; 160 } 161 162 /** list of generated source files created in this environment */ 163 private Vector<File> generatedFiles = new Vector<>(); 164 165 /** 166 * Remember a generated source file generated so that it 167 * can be removed later, if appropriate. 168 */ addGeneratedFile(File file)169 public void addGeneratedFile(File file) { 170 generatedFiles.addElement(file); 171 } 172 173 /** 174 * Delete all the generated source files made during the execution 175 * of this environment (those that have been registered with the 176 * "addGeneratedFile" method). 177 */ deleteGeneratedFiles()178 public void deleteGeneratedFiles() { 179 synchronized(generatedFiles) { 180 Enumeration<File> enumeration = generatedFiles.elements(); 181 while (enumeration.hasMoreElements()) { 182 File file = enumeration.nextElement(); 183 file.delete(); 184 } 185 generatedFiles.removeAllElements(); 186 } 187 } 188 189 /** 190 * Release resources, if any. 191 */ shutdown()192 public void shutdown() { 193 main = null; 194 generatedFiles = null; 195 super.shutdown(); 196 } 197 198 /** 199 * Return the formatted, localized string for a named error message 200 * and supplied arguments. For rmic error messages, with names that 201 * being with "rmic.", look up the error message in rmic's resource 202 * bundle; otherwise, defer to java's superclass method. 203 */ errorString(String err, Object arg0, Object arg1, Object arg2)204 public String errorString(String err, 205 Object arg0, Object arg1, Object arg2) 206 { 207 if (err.startsWith("rmic.") || err.startsWith("warn.rmic.")) { 208 String result = Main.getText(err, 209 (arg0 != null ? arg0.toString() : null), 210 (arg1 != null ? arg1.toString() : null), 211 (arg2 != null ? arg2.toString() : null)); 212 213 if (err.startsWith("warn.")) { 214 result = "warning: " + result; 215 } 216 return result; 217 } else { 218 return super.errorString(err, arg0, arg1, arg2); 219 } 220 } reset()221 public void reset() { 222 } 223 224 /** 225 * Utility for building paths of directories and JAR files. This 226 * class was copied from com.sun.tools.javac.util.Paths as part of 227 * the fix for 6473331, which adds support for Class-Path manifest 228 * entries in JAR files. Diagnostic code is simply commented out 229 * because rmic silently ignored these conditions historically. 230 */ 231 private static class Path extends LinkedHashSet<String> { 232 private static final long serialVersionUID = 0; 233 private static final boolean warn = false; 234 235 private static class PathIterator implements Collection<String> { 236 private int pos = 0; 237 private final String path; 238 private final String emptyPathDefault; 239 PathIterator(String path, String emptyPathDefault)240 public PathIterator(String path, String emptyPathDefault) { 241 this.path = path; 242 this.emptyPathDefault = emptyPathDefault; 243 } PathIterator(String path)244 public PathIterator(String path) { this(path, null); } iterator()245 public Iterator<String> iterator() { 246 return new Iterator<String>() { 247 public boolean hasNext() { 248 return pos <= path.length(); 249 } 250 public String next() { 251 int beg = pos; 252 int end = path.indexOf(File.pathSeparator, beg); 253 if (end == -1) 254 end = path.length(); 255 pos = end + 1; 256 257 if (beg == end && emptyPathDefault != null) 258 return emptyPathDefault; 259 else 260 return path.substring(beg, end); 261 } 262 public void remove() { 263 throw new UnsupportedOperationException(); 264 } 265 }; 266 } 267 268 // required for Collection. size()269 public int size() { 270 throw new UnsupportedOperationException(); 271 } isEmpty()272 public boolean isEmpty() { 273 throw new UnsupportedOperationException(); 274 } contains(Object o)275 public boolean contains(Object o) { 276 throw new UnsupportedOperationException(); 277 } toArray()278 public Object[] toArray() { 279 throw new UnsupportedOperationException(); 280 } toArray(T[] a)281 public <T> T[] toArray(T[] a) { 282 throw new UnsupportedOperationException(); 283 } add(String o)284 public boolean add(String o) { 285 throw new UnsupportedOperationException(); 286 } remove(Object o)287 public boolean remove(Object o) { 288 throw new UnsupportedOperationException(); 289 } containsAll(Collection<?> c)290 public boolean containsAll(Collection<?> c) { 291 throw new UnsupportedOperationException(); 292 } addAll(Collection<? extends String> c)293 public boolean addAll(Collection<? extends String> c) { 294 throw new UnsupportedOperationException(); 295 } removeAll(Collection<?> c)296 public boolean removeAll(Collection<?> c) { 297 throw new UnsupportedOperationException(); 298 } retainAll(Collection<?> c)299 public boolean retainAll(Collection<?> c) { 300 throw new UnsupportedOperationException(); 301 } clear()302 public void clear() { 303 throw new UnsupportedOperationException(); 304 } equals(Object o)305 public boolean equals(Object o) { 306 throw new UnsupportedOperationException(); 307 } hashCode()308 public int hashCode() { 309 throw new UnsupportedOperationException(); 310 } 311 } 312 313 /** Is this the name of a zip file? */ isZip(String name)314 private static boolean isZip(String name) { 315 return new File(name).isFile(); 316 } 317 318 private boolean expandJarClassPaths = false; 319 expandJarClassPaths(boolean x)320 public Path expandJarClassPaths(boolean x) { 321 expandJarClassPaths = x; 322 return this; 323 } 324 325 /** What to use when path element is the empty string */ 326 private String emptyPathDefault = null; 327 emptyPathDefault(String x)328 public Path emptyPathDefault(String x) { 329 emptyPathDefault = x; 330 return this; 331 } 332 Path()333 public Path() { super(); } 334 addDirectories(String dirs, boolean warn)335 public Path addDirectories(String dirs, boolean warn) { 336 if (dirs != null) 337 for (String dir : new PathIterator(dirs)) 338 addDirectory(dir, warn); 339 return this; 340 } 341 addDirectories(String dirs)342 public Path addDirectories(String dirs) { 343 return addDirectories(dirs, warn); 344 } 345 addDirectory(String dir, boolean warn)346 private void addDirectory(String dir, boolean warn) { 347 if (! new File(dir).isDirectory()) { 348 // if (warn) 349 // log.warning(Position.NOPOS, 350 // "dir.path.element.not.found", dir); 351 return; 352 } 353 354 for (String direntry : new File(dir).list()) { 355 String canonicalized = direntry.toLowerCase(); 356 if (canonicalized.endsWith(".jar") || 357 canonicalized.endsWith(".zip")) 358 addFile(dir + File.separator + direntry, warn); 359 } 360 } 361 addFiles(String files, boolean warn)362 public Path addFiles(String files, boolean warn) { 363 if (files != null) 364 for (String file : new PathIterator(files, emptyPathDefault)) 365 addFile(file, warn); 366 return this; 367 } 368 addFiles(String files)369 public Path addFiles(String files) { 370 return addFiles(files, warn); 371 } 372 addFile(String file, boolean warn)373 private void addFile(String file, boolean warn) { 374 if (contains(file)) { 375 /* Discard duplicates and avoid infinite recursion */ 376 return; 377 } 378 379 File ele = new File(file); 380 if (! ele.exists()) { 381 /* No such file or directory exist */ 382 if (warn) 383 // log.warning(Position.NOPOS, 384 // "path.element.not.found", file); 385 return; 386 } 387 388 if (ele.isFile()) { 389 /* File is an ordinay file */ 390 String arcname = file.toLowerCase(); 391 if (! (arcname.endsWith(".zip") || 392 arcname.endsWith(".jar"))) { 393 /* File name don't have right extension */ 394 // if (warn) 395 // log.warning(Position.NOPOS, 396 // "invalid.archive.file", file); 397 return; 398 } 399 } 400 401 /* Now what we have left is either a directory or a file name 402 confirming to archive naming convention */ 403 404 super.add(file); 405 if (expandJarClassPaths && isZip(file)) 406 addJarClassPath(file, warn); 407 } 408 409 // Adds referenced classpath elements from a jar's Class-Path 410 // Manifest entry. In some future release, we may want to 411 // update this code to recognize URLs rather than simple 412 // filenames, but if we do, we should redo all path-related code. addJarClassPath(String jarFileName, boolean warn)413 private void addJarClassPath(String jarFileName, boolean warn) { 414 try { 415 String jarParent = new File(jarFileName).getParent(); 416 JarFile jar = new JarFile(jarFileName); 417 418 try { 419 Manifest man = jar.getManifest(); 420 if (man == null) return; 421 422 Attributes attr = man.getMainAttributes(); 423 if (attr == null) return; 424 425 String path = attr.getValue(Attributes.Name.CLASS_PATH); 426 if (path == null) return; 427 428 for (StringTokenizer st = new StringTokenizer(path); 429 st.hasMoreTokens();) { 430 String elt = st.nextToken(); 431 if (jarParent != null) 432 elt = new File(jarParent, elt).getCanonicalPath(); 433 addFile(elt, warn); 434 } 435 } finally { 436 jar.close(); 437 } 438 } catch (IOException e) { 439 // log.error(Position.NOPOS, 440 // "error.reading.file", jarFileName, 441 // e.getLocalizedMessage()); 442 } 443 } 444 } 445 } 446