1 /* 2 * Copyright (c) 2012, 2014, 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 com.sun.tools.sjavac.comp; 27 28 import java.io.IOException; 29 import java.io.PrintWriter; 30 import java.net.URI; 31 import java.util.HashMap; 32 import java.util.HashSet; 33 import java.util.Map; 34 import java.util.Set; 35 36 import javax.tools.*; 37 import javax.tools.JavaFileObject.Kind; 38 39 import com.sun.tools.javac.file.JavacFileManager; 40 import com.sun.tools.javac.util.DefinedBy; 41 import com.sun.tools.javac.util.DefinedBy.Api; 42 import com.sun.tools.javac.util.ListBuffer; 43 44 /** 45 * Intercepts reads and writes to the file system to gather 46 * information about what artifacts are generated. 47 * 48 * Traps writes to certain files, if the content written is identical 49 * to the existing file. 50 * 51 * Can also blind out the filemanager from seeing certain files in the file system. 52 * Necessary to prevent javac from seeing some sources where the source path points. 53 * 54 * <p><b>This is NOT part of any supported API. 55 * If you write code that depends on this, you do so at your own risk. 56 * This code and its internal interfaces are subject to change or 57 * deletion without notice.</b> 58 */ 59 @com.sun.tools.javac.api.ClientCodeWrapper.Trusted 60 public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager> { 61 62 // Set of sources that can be seen by javac. 63 Set<URI> visibleSources = new HashSet<>(); 64 // Map from modulename:packagename to artifacts. 65 Map<String,Set<URI>> packageArtifacts = new HashMap<>(); 66 // Where to print informational messages. 67 PrintWriter stdout; 68 69 public SmartFileManager(JavaFileManager fileManager) { 70 super(fileManager); 71 } 72 73 public void setVisibleSources(Set<URI> s) { 74 visibleSources = s; 75 } 76 77 public void cleanArtifacts() { 78 packageArtifacts = new HashMap<>(); 79 } 80 81 public void setLog(PrintWriter pw) { 82 stdout = pw; 83 } 84 85 /** 86 * Set whether or not to use ct.sym as an alternate to rt.jar. 87 */ 88 public void setSymbolFileEnabled(boolean b) { 89 if (!(fileManager instanceof JavacFileManager)) 90 throw new IllegalStateException(); 91 ((JavacFileManager) fileManager).setSymbolFileEnabled(b); 92 } 93 94 public Map<String,Set<URI>> getPackageArtifacts() { 95 return packageArtifacts; 96 } 97 98 @Override @DefinedBy(Api.COMPILER) 99 public Iterable<JavaFileObject> list(Location location, 100 String packageName, 101 Set<Kind> kinds, 102 boolean recurse) throws IOException { 103 // Acquire the list of files. 104 Iterable<JavaFileObject> files = super.list(location, packageName, kinds, recurse); 105 if (visibleSources.isEmpty()) { 106 return files; 107 } 108 // Now filter! 109 ListBuffer<JavaFileObject> filteredFiles = new ListBuffer<>(); 110 for (JavaFileObject f : files) { 111 URI uri = f.toUri(); 112 String t = uri.toString(); 113 if (t.startsWith("jar:") 114 || t.endsWith(".class") 115 || visibleSources.contains(uri)) { 116 filteredFiles.add(f); 117 } 118 } 119 return filteredFiles; 120 } 121 122 @Override @DefinedBy(Api.COMPILER) 123 public boolean hasLocation(Location location) { 124 return super.hasLocation(location); 125 } 126 127 @Override @DefinedBy(Api.COMPILER) 128 public JavaFileObject getJavaFileForInput(Location location, 129 String className, 130 Kind kind) throws IOException { 131 JavaFileObject file = super.getJavaFileForInput(location, className, kind); 132 if (file == null || visibleSources.isEmpty()) { 133 return file; 134 } 135 136 if (visibleSources.contains(file.toUri())) { 137 return file; 138 } 139 return null; 140 } 141 142 @Override @DefinedBy(Api.COMPILER) 143 public JavaFileObject getJavaFileForOutput(Location location, 144 String className, 145 Kind kind, 146 FileObject sibling) throws IOException { 147 JavaFileObject file = super.getJavaFileForOutput(location, className, kind, sibling); 148 if (file == null) return file; 149 int dp = className.lastIndexOf('.'); 150 String pkg_name = ""; 151 if (dp != -1) { 152 pkg_name = className.substring(0, dp); 153 } 154 // When modules are in use, then the mod_name might be something like "jdk_base" 155 String mod_name = ""; 156 addArtifact(mod_name+":"+pkg_name, file.toUri()); 157 return file; 158 } 159 160 @Override @DefinedBy(Api.COMPILER) 161 public FileObject getFileForInput(Location location, 162 String packageName, 163 String relativeName) throws IOException { 164 FileObject file = super.getFileForInput(location, packageName, relativeName); 165 if (file == null || visibleSources.isEmpty()) { 166 return file; 167 } 168 169 if (visibleSources.contains(file.toUri())) { 170 return file; 171 } 172 return null; 173 } 174 175 @Override @DefinedBy(Api.COMPILER) 176 public FileObject getFileForOutput(Location location, 177 String packageName, 178 String relativeName, 179 FileObject sibling) throws IOException { 180 FileObject file = super.getFileForOutput(location, packageName, relativeName, sibling); 181 if (file == null) return file; 182 if (location.equals(StandardLocation.NATIVE_HEADER_OUTPUT) && 183 file instanceof JavaFileObject) { 184 file = new SmartFileObject((JavaFileObject)file, stdout); 185 packageName = ":" + packageNameFromFileName(relativeName); 186 } 187 if (packageName.equals("")) { 188 packageName = ":"; 189 } 190 addArtifact(packageName, file.toUri()); 191 return file; 192 } 193 194 private String packageNameFromFileName(String fn) { 195 StringBuilder sb = new StringBuilder(); 196 int p = fn.indexOf('_'), pp = 0; 197 while (p != -1) { 198 if (sb.length() > 0) sb.append('.'); 199 sb.append(fn.substring(pp,p)); 200 if (p == fn.length()-1) break; 201 pp = p+1; 202 p = fn.indexOf('_',pp); 203 } 204 return sb.toString(); 205 } 206 207 @Override @DefinedBy(Api.COMPILER) 208 public void flush() throws IOException { 209 super.flush(); 210 } 211 212 @Override @DefinedBy(Api.COMPILER) 213 public void close() throws IOException { 214 super.close(); 215 } 216 217 void addArtifact(String pkgName, URI art) { 218 Set<URI> s = packageArtifacts.get(pkgName); 219 if (s == null) { 220 s = new HashSet<>(); 221 packageArtifacts.put(pkgName, s); 222 } 223 s.add(art); 224 } 225 }