SmartFileManager.java revision 2593:035b01d356ee
1107571Sgrehan/*
2107571Sgrehan * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
3107571Sgrehan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4107571Sgrehan *
5107571Sgrehan * This code is free software; you can redistribute it and/or modify it
6107571Sgrehan * under the terms of the GNU General Public License version 2 only, as
7107571Sgrehan * published by the Free Software Foundation.  Oracle designates this
8107571Sgrehan * particular file as subject to the "Classpath" exception as provided
9107571Sgrehan * by Oracle in the LICENSE file that accompanied this code.
10107571Sgrehan *
11107571Sgrehan * This code is distributed in the hope that it will be useful, but WITHOUT
12107571Sgrehan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13107571Sgrehan * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14107571Sgrehan * version 2 for more details (a copy is included in the LICENSE file that
15107571Sgrehan * accompanied this code).
16107571Sgrehan *
17107571Sgrehan * You should have received a copy of the GNU General Public License version
18107571Sgrehan * 2 along with this work; if not, write to the Free Software Foundation,
19107571Sgrehan * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20107571Sgrehan *
21107571Sgrehan * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22107571Sgrehan * or visit www.oracle.com if you need additional information or have any
23107571Sgrehan * questions.
24107571Sgrehan */
25107571Sgrehan
26107571Sgrehanpackage com.sun.tools.sjavac.comp;
27107571Sgrehan
28107571Sgrehanimport java.io.IOException;
29107571Sgrehanimport java.io.PrintWriter;
30107571Sgrehanimport java.net.URI;
31107571Sgrehanimport java.util.HashMap;
32107571Sgrehanimport java.util.HashSet;
33107571Sgrehanimport java.util.Map;
34107571Sgrehanimport java.util.Set;
35107571Sgrehan
36107571Sgrehanimport javax.tools.*;
37107571Sgrehanimport javax.tools.JavaFileObject.Kind;
38107571Sgrehan
39107571Sgrehanimport com.sun.tools.javac.file.JavacFileManager;
40107571Sgrehanimport com.sun.tools.javac.util.ListBuffer;
41107571Sgrehan
42107571Sgrehan/**
43107571Sgrehan * Intercepts reads and writes to the file system to gather
44107571Sgrehan * information about what artifacts are generated.
45107571Sgrehan *
46107571Sgrehan * Traps writes to certain files, if the content written is identical
47107571Sgrehan * to the existing file.
48107571Sgrehan *
49107571Sgrehan * Can also blind out the filemanager from seeing certain files in the file system.
50107571Sgrehan * Necessary to prevent javac from seeing some sources where the source path points.
51107571Sgrehan *
52107571Sgrehan *  <p><b>This is NOT part of any supported API.
53107571Sgrehan *  If you write code that depends on this, you do so at your own risk.
54107571Sgrehan *  This code and its internal interfaces are subject to change or
55107571Sgrehan *  deletion without notice.</b>
56107571Sgrehan */
57107571Sgrehanpublic class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager> {
58107571Sgrehan
59107571Sgrehan    // Set of sources that can be seen by javac.
60107571Sgrehan    Set<URI> visibleSources = new HashSet<>();
61107571Sgrehan    // Map from modulename:packagename to artifacts.
62107571Sgrehan    Map<String,Set<URI>> packageArtifacts = new HashMap<>();
63107571Sgrehan    // Where to print informational messages.
64107571Sgrehan    PrintWriter stdout;
65107571Sgrehan
66107571Sgrehan    public SmartFileManager(JavaFileManager fileManager) {
67107571Sgrehan        super(fileManager);
68107571Sgrehan    }
69107571Sgrehan
70107571Sgrehan    public void setVisibleSources(Set<URI> s) {
71107571Sgrehan        visibleSources = s;
72107571Sgrehan    }
73107571Sgrehan
74    public void cleanArtifacts() {
75        packageArtifacts = new HashMap<>();
76    }
77
78    public void setLog(PrintWriter pw) {
79        stdout = pw;
80    }
81
82    /**
83     * Set whether or not to use ct.sym as an alternate to rt.jar.
84     */
85    public void setSymbolFileEnabled(boolean b) {
86        if (!(fileManager instanceof JavacFileManager))
87            throw new IllegalStateException();
88        ((JavacFileManager) fileManager).setSymbolFileEnabled(b);
89    }
90
91    public Map<String,Set<URI>> getPackageArtifacts() {
92        return packageArtifacts;
93    }
94
95    @Override
96    public Iterable<JavaFileObject> list(Location location,
97                                         String packageName,
98                                         Set<Kind> kinds,
99                                         boolean recurse) throws IOException {
100        // Acquire the list of files.
101        Iterable<JavaFileObject> files = super.list(location, packageName, kinds, recurse);
102        if (visibleSources.isEmpty()) {
103            return files;
104        }
105        // Now filter!
106        ListBuffer<JavaFileObject> filteredFiles = new ListBuffer<>();
107        for (JavaFileObject f : files) {
108            URI uri = f.toUri();
109            String t = uri.toString();
110            if (t.startsWith("jar:")
111                || t.endsWith(".class")
112                || visibleSources.contains(uri)) {
113                filteredFiles.add(f);
114            }
115        }
116        return filteredFiles;
117    }
118
119    @Override
120    public boolean hasLocation(Location location) {
121        return super.hasLocation(location);
122    }
123
124    @Override
125    public JavaFileObject getJavaFileForInput(Location location,
126                                              String className,
127                                              Kind kind) throws IOException {
128        JavaFileObject file = super.getJavaFileForInput(location, className, kind);
129        if (file == null || visibleSources.isEmpty()) {
130            return file;
131        }
132
133        if (visibleSources.contains(file.toUri())) {
134            return file;
135        }
136        return null;
137    }
138
139    @Override
140    public JavaFileObject getJavaFileForOutput(Location location,
141                                               String className,
142                                               Kind kind,
143                                               FileObject sibling) throws IOException {
144        JavaFileObject file = super.getJavaFileForOutput(location, className, kind, sibling);
145        if (file == null) return file;
146        int dp = className.lastIndexOf('.');
147        String pkg_name = "";
148        if (dp != -1) {
149            pkg_name = className.substring(0, dp);
150        }
151        // When modules are in use, then the mod_name might be something like "jdk_base"
152        String mod_name = "";
153        addArtifact(mod_name+":"+pkg_name, file.toUri());
154        return file;
155    }
156
157    @Override
158    public FileObject getFileForInput(Location location,
159                                      String packageName,
160                                      String relativeName) throws IOException {
161        FileObject file =  super.getFileForInput(location, packageName, relativeName);
162        if (file == null || visibleSources.isEmpty()) {
163            return file;
164        }
165
166        if (visibleSources.contains(file.toUri())) {
167            return file;
168        }
169        return null;
170    }
171
172    @Override
173    public FileObject getFileForOutput(Location location,
174                                       String packageName,
175                                       String relativeName,
176                                       FileObject sibling) throws IOException {
177        FileObject file = super.getFileForOutput(location, packageName, relativeName, sibling);
178        if (file == null) return file;
179        if (location.equals(StandardLocation.NATIVE_HEADER_OUTPUT) &&
180                file instanceof JavaFileObject) {
181           file = new SmartFileObject((JavaFileObject)file, stdout);
182           packageName = ":" + packageNameFromFileName(relativeName);
183        }
184        if (packageName.equals("")) {
185            packageName = ":";
186        }
187        addArtifact(packageName, file.toUri());
188        return file;
189    }
190
191    private String packageNameFromFileName(String fn) {
192        StringBuilder sb = new StringBuilder();
193        int p = fn.indexOf('_'), pp = 0;
194        while (p != -1) {
195            if (sb.length() > 0) sb.append('.');
196            sb.append(fn.substring(pp,p));
197            if (p == fn.length()-1) break;
198            pp = p+1;
199            p = fn.indexOf('_',pp);
200        }
201        return sb.toString();
202    }
203
204    @Override
205    public void flush() throws IOException {
206        super.flush();
207    }
208
209    @Override
210    public void close() throws IOException {
211        super.close();
212    }
213
214    void addArtifact(String pkgName, URI art) {
215        Set<URI> s = packageArtifacts.get(pkgName);
216        if (s == null) {
217            s = new HashSet<>();
218            packageArtifacts.put(pkgName, s);
219        }
220        s.add(art);
221    }
222}
223