| /* |
| * Copyright (c) 1996, 2015, 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. |
| */ |
| |
| /*****************************************************************************/ |
| /* Copyright (c) IBM Corporation 1998 */ |
| /* */ |
| /* (C) Copyright IBM Corp. 1998 */ |
| /* */ |
| /*****************************************************************************/ |
| |
| package sun.rmi.rmic; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.util.Collection; |
| import java.util.Enumeration; |
| import java.util.Iterator; |
| import java.util.LinkedHashSet; |
| import java.util.StringTokenizer; |
| import java.util.Vector; |
| import java.util.jar.JarFile; |
| import java.util.jar.Manifest; |
| import java.util.jar.Attributes; |
| import sun.tools.java.ClassPath; |
| |
| /** |
| * BatchEnvironment for rmic extends javac's version in four ways: |
| * 1. It overrides errorString() to handle looking for rmic-specific |
| * error messages in rmic's resource bundle |
| * 2. It provides a mechanism for recording intermediate generated |
| * files so that they can be deleted later. |
| * 3. It holds a reference to the Main instance so that generators |
| * can refer to it. |
| * 4. It provides access to the ClassPath passed to the constructor. |
| * |
| * WARNING: The contents of this source file are not part of any |
| * supported API. Code that depends on them does so at its own risk: |
| * they are subject to change or removal without notice. |
| */ |
| |
| @SuppressWarnings("deprecation") |
| public class BatchEnvironment extends sun.tools.javac.BatchEnvironment { |
| |
| /** instance of Main which created this environment */ |
| private Main main; |
| |
| /** |
| * Create a ClassPath object for rmic from a class path string. |
| */ |
| public static ClassPath createClassPath(String classPathString) { |
| ClassPath[] paths = classPaths(null, classPathString, null); |
| return paths[1]; |
| } |
| |
| /** |
| * Create a ClassPath object for rmic from the relevant command line |
| * options for class path and boot class path. |
| */ |
| public static ClassPath createClassPath(String classPathString, |
| String sysClassPathString) |
| { |
| /** |
| * Previously, this method delegated to the |
| * sun.tools.javac.BatchEnvironment.classPaths method in order |
| * to supply default values for paths not specified on the |
| * command line, expand extensions directories into specific |
| * JAR files, and construct the ClassPath object-- but as part |
| * of the fix for 6473331, which adds support for Class-Path |
| * manifest entries in JAR files, those steps are now handled |
| * here directly, with the help of a Path utility class copied |
| * from the new javac implementation (see below). |
| */ |
| Path path = new Path(); |
| |
| if (sysClassPathString == null) { |
| sysClassPathString = System.getProperty("sun.boot.class.path"); |
| } |
| if (sysClassPathString != null) { |
| path.addFiles(sysClassPathString); |
| } |
| |
| /* |
| * Class-Path manifest entries are supported for JAR files |
| * everywhere except in the boot class path. |
| */ |
| path.expandJarClassPaths(true); |
| |
| /* |
| * In the application class path, an empty element means |
| * the current working directory. |
| */ |
| path.emptyPathDefault("."); |
| |
| if (classPathString == null) { |
| // The env.class.path property is the user's CLASSPATH |
| // environment variable, and it set by the wrapper (ie, |
| // javac.exe). |
| classPathString = System.getProperty("env.class.path"); |
| if (classPathString == null) { |
| classPathString = "."; |
| } |
| } |
| path.addFiles(classPathString); |
| |
| return new ClassPath(path.toArray(new String[path.size()])); |
| } |
| |
| /** |
| * Create a BatchEnvironment for rmic with the given class path, |
| * stream for messages and Main. |
| */ |
| public BatchEnvironment(OutputStream out, ClassPath path, Main main) { |
| super(out, new ClassPath(""), path); |
| // use empty "sourcePath" (see 4666958) |
| this.main = main; |
| } |
| |
| /** |
| * Get the instance of Main which created this environment. |
| */ |
| public Main getMain() { |
| return main; |
| } |
| |
| /** |
| * Get the ClassPath. |
| */ |
| public ClassPath getClassPath() { |
| return binaryPath; |
| } |
| |
| /** list of generated source files created in this environment */ |
| private Vector<File> generatedFiles = new Vector<>(); |
| |
| /** |
| * Remember a generated source file generated so that it |
| * can be removed later, if appropriate. |
| */ |
| public void addGeneratedFile(File file) { |
| generatedFiles.addElement(file); |
| } |
| |
| /** |
| * Delete all the generated source files made during the execution |
| * of this environment (those that have been registered with the |
| * "addGeneratedFile" method). |
| */ |
| public void deleteGeneratedFiles() { |
| synchronized(generatedFiles) { |
| Enumeration<File> enumeration = generatedFiles.elements(); |
| while (enumeration.hasMoreElements()) { |
| File file = enumeration.nextElement(); |
| file.delete(); |
| } |
| generatedFiles.removeAllElements(); |
| } |
| } |
| |
| /** |
| * Release resources, if any. |
| */ |
| public void shutdown() { |
| main = null; |
| generatedFiles = null; |
| super.shutdown(); |
| } |
| |
| /** |
| * Return the formatted, localized string for a named error message |
| * and supplied arguments. For rmic error messages, with names that |
| * being with "rmic.", look up the error message in rmic's resource |
| * bundle; otherwise, defer to java's superclass method. |
| */ |
| public String errorString(String err, |
| Object arg0, Object arg1, Object arg2) |
| { |
| if (err.startsWith("rmic.") || err.startsWith("warn.rmic.")) { |
| String result = Main.getText(err, |
| (arg0 != null ? arg0.toString() : null), |
| (arg1 != null ? arg1.toString() : null), |
| (arg2 != null ? arg2.toString() : null)); |
| |
| if (err.startsWith("warn.")) { |
| result = "warning: " + result; |
| } |
| return result; |
| } else { |
| return super.errorString(err, arg0, arg1, arg2); |
| } |
| } |
| public void reset() { |
| } |
| |
| /** |
| * Utility for building paths of directories and JAR files. This |
| * class was copied from com.sun.tools.javac.util.Paths as part of |
| * the fix for 6473331, which adds support for Class-Path manifest |
| * entries in JAR files. Diagnostic code is simply commented out |
| * because rmic silently ignored these conditions historically. |
| */ |
| private static class Path extends LinkedHashSet<String> { |
| private static final long serialVersionUID = 0; |
| private static final boolean warn = false; |
| |
| private static class PathIterator implements Collection<String> { |
| private int pos = 0; |
| private final String path; |
| private final String emptyPathDefault; |
| |
| public PathIterator(String path, String emptyPathDefault) { |
| this.path = path; |
| this.emptyPathDefault = emptyPathDefault; |
| } |
| public PathIterator(String path) { this(path, null); } |
| public Iterator<String> iterator() { |
| return new Iterator<String>() { |
| public boolean hasNext() { |
| return pos <= path.length(); |
| } |
| public String next() { |
| int beg = pos; |
| int end = path.indexOf(File.pathSeparator, beg); |
| if (end == -1) |
| end = path.length(); |
| pos = end + 1; |
| |
| if (beg == end && emptyPathDefault != null) |
| return emptyPathDefault; |
| else |
| return path.substring(beg, end); |
| } |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| } |
| |
| // required for Collection. |
| public int size() { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean isEmpty() { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean contains(Object o) { |
| throw new UnsupportedOperationException(); |
| } |
| public Object[] toArray() { |
| throw new UnsupportedOperationException(); |
| } |
| public <T> T[] toArray(T[] a) { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean add(String o) { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean remove(Object o) { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean containsAll(Collection<?> c) { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean addAll(Collection<? extends String> c) { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean removeAll(Collection<?> c) { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean retainAll(Collection<?> c) { |
| throw new UnsupportedOperationException(); |
| } |
| public void clear() { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean equals(Object o) { |
| throw new UnsupportedOperationException(); |
| } |
| public int hashCode() { |
| throw new UnsupportedOperationException(); |
| } |
| } |
| |
| /** Is this the name of a zip file? */ |
| private static boolean isZip(String name) { |
| return new File(name).isFile(); |
| } |
| |
| private boolean expandJarClassPaths = false; |
| |
| public Path expandJarClassPaths(boolean x) { |
| expandJarClassPaths = x; |
| return this; |
| } |
| |
| /** What to use when path element is the empty string */ |
| private String emptyPathDefault = null; |
| |
| public Path emptyPathDefault(String x) { |
| emptyPathDefault = x; |
| return this; |
| } |
| |
| public Path() { super(); } |
| |
| public Path addDirectories(String dirs, boolean warn) { |
| if (dirs != null) |
| for (String dir : new PathIterator(dirs)) |
| addDirectory(dir, warn); |
| return this; |
| } |
| |
| public Path addDirectories(String dirs) { |
| return addDirectories(dirs, warn); |
| } |
| |
| private void addDirectory(String dir, boolean warn) { |
| if (! new File(dir).isDirectory()) { |
| // if (warn) |
| // log.warning(Position.NOPOS, |
| // "dir.path.element.not.found", dir); |
| return; |
| } |
| |
| for (String direntry : new File(dir).list()) { |
| String canonicalized = direntry.toLowerCase(); |
| if (canonicalized.endsWith(".jar") || |
| canonicalized.endsWith(".zip")) |
| addFile(dir + File.separator + direntry, warn); |
| } |
| } |
| |
| public Path addFiles(String files, boolean warn) { |
| if (files != null) |
| for (String file : new PathIterator(files, emptyPathDefault)) |
| addFile(file, warn); |
| return this; |
| } |
| |
| public Path addFiles(String files) { |
| return addFiles(files, warn); |
| } |
| |
| private void addFile(String file, boolean warn) { |
| if (contains(file)) { |
| /* Discard duplicates and avoid infinite recursion */ |
| return; |
| } |
| |
| File ele = new File(file); |
| if (! ele.exists()) { |
| /* No such file or directory exist */ |
| if (warn) |
| // log.warning(Position.NOPOS, |
| // "path.element.not.found", file); |
| return; |
| } |
| |
| if (ele.isFile()) { |
| /* File is an ordinay file */ |
| String arcname = file.toLowerCase(); |
| if (! (arcname.endsWith(".zip") || |
| arcname.endsWith(".jar"))) { |
| /* File name don't have right extension */ |
| // if (warn) |
| // log.warning(Position.NOPOS, |
| // "invalid.archive.file", file); |
| return; |
| } |
| } |
| |
| /* Now what we have left is either a directory or a file name |
| confirming to archive naming convention */ |
| |
| super.add(file); |
| if (expandJarClassPaths && isZip(file)) |
| addJarClassPath(file, warn); |
| } |
| |
| // Adds referenced classpath elements from a jar's Class-Path |
| // Manifest entry. In some future release, we may want to |
| // update this code to recognize URLs rather than simple |
| // filenames, but if we do, we should redo all path-related code. |
| private void addJarClassPath(String jarFileName, boolean warn) { |
| try { |
| String jarParent = new File(jarFileName).getParent(); |
| JarFile jar = new JarFile(jarFileName); |
| |
| try { |
| Manifest man = jar.getManifest(); |
| if (man == null) return; |
| |
| Attributes attr = man.getMainAttributes(); |
| if (attr == null) return; |
| |
| String path = attr.getValue(Attributes.Name.CLASS_PATH); |
| if (path == null) return; |
| |
| for (StringTokenizer st = new StringTokenizer(path); |
| st.hasMoreTokens();) { |
| String elt = st.nextToken(); |
| if (jarParent != null) |
| elt = new File(jarParent, elt).getCanonicalPath(); |
| addFile(elt, warn); |
| } |
| } finally { |
| jar.close(); |
| } |
| } catch (IOException e) { |
| // log.error(Position.NOPOS, |
| // "error.reading.file", jarFileName, |
| // e.getLocalizedMessage()); |
| } |
| } |
| } |
| } |