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;
27
28 import java.io.File;
29 import java.net.URI;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import com.sun.tools.javac.util.Assert;
39
40 /**
41 * The Package class maintains meta information about a package.
42 * For example its sources, dependents,its pubapi and its artifacts.
43 *
44 * It might look odd that we track dependents/pubapi/artifacts on
45 * a package level, but it makes sense since recompiling a full package
46 * takes as long as recompiling a single java file in that package,
47 * if you take into account the startup time of the jvm.
48 *
49 * Also the dependency information will be much smaller (good for the javac_state file size)
50 * and it simplifies tracking artifact generation, you do not always know from which
51 * source a class file was generated, but you always know which package it belongs to.
52 *
53 * It is also educational to see package dependencies triggering recompilation of
54 * other packages. Even though the recompilation was perhaps not necessary,
55 * the visible recompilation of the dependent packages indicates how much circular
56 * dependencies your code has.
57 *
58 * <p><b>This is NOT part of any supported API.
59 * If you write code that depends on this, you do so at your own risk.
60 * This code and its internal interfaces are subject to change or
61 * deletion without notice.</b>
62 */
63 public class Package implements Comparable<Package> {
64 // The module this package belongs to. (There is a legacy module with an empty string name,
65 // used for all legacy sources.)
66 private Module mod;
67 // Name of this package, module:pkg
68 // ex1 jdk.base:java.lang
69 // ex2 :java.lang (when in legacy mode)
70 private String name;
71 // The directory path to the package. If the package belongs to a module,
72 // then that module's file system name is part of the path.
73 private String dirname;
74 // This package depends on these packages.
75 private Set<String> dependencies = new HashSet<>();
76 // This package has the following dependents, that depend on this package.
77 private Set<String> dependents = new HashSet<>();
78 // This is the public api of this package.
79 private List<String> pubapi = new ArrayList<>();
80 // Map from source file name to Source info object.
81 private Map<String,Source> sources = new HashMap<>();
82 // This package generated these artifacts.
83 private Map<String,File> artifacts = new HashMap<>();
84
85 public Package(Module m, String n) {
86 int c = n.indexOf(":");
87 Assert.check(c != -1);
88 String mn = n.substring(0,c);
89 Assert.check(m.name().equals(m.name()));
90 name = n;
91 dirname = n.replace('.', File.separatorChar);
92 if (m.name().length() > 0) {
93 // There is a module here, prefix the module dir name to the path.
94 dirname = m.dirname()+File.separatorChar+dirname;
95 }
96 }
97
98 public Module mod() { return mod; }
99 public String name() { return name; }
100 public String dirname() { return dirname; }
101 public Map<String,Source> sources() { return sources; }
102 public Map<String,File> artifacts() { return artifacts; }
103 public List<String> pubapi() { return pubapi; }
104
105 public Set<String> dependencies() { return dependencies; }
106 public Set<String> dependents() { return dependents; }
107
108 @Override
109 public boolean equals(Object o) {
110 return (o instanceof Package) && name.equals(((Package)o).name);
111 }
112
113 @Override
114 public int hashCode() {
115 return name.hashCode();
116 }
117
118 @Override
119 public int compareTo(Package o) {
120 return name.compareTo(o.name);
121 }
122
123 public void addSource(Source s) {
124 sources.put(s.file().getPath(), s);
125 }
126
127 public void addDependency(String d) {
128 dependencies.add(d);
129 }
130
131 public void addDependent(String d) {
132 dependents.add(d);
133 }
134
135 public void addPubapi(String p) {
136 pubapi.add(p);
137 }
138
139 /**
140 * Check if we have knowledge in the javac state that
141 * describe the results of compiling this package before.
142 */
143 public boolean existsInJavacState() {
144 return artifacts.size() > 0 || pubapi.size() > 0;
145 }
146
147 public static List<String> pubapiToList(String ps)
148 {
149 String[] lines = ps.split("\n");
150 List<String> r = new ArrayList<>();
151 for (String l : lines) {
152 r.add(l);
153 }
154 return r;
155 }
156
157 public boolean hasPubapiChanged(List<String> ps) {
158 Iterator<String> i = ps.iterator();
159 Iterator<String> j = pubapi.iterator();
160 int line = 0;
161 while (i.hasNext() && j.hasNext()) {
162 String is = i.next();
163 String js = j.next();
164 if (!is.equals(js)) {
165 Log.debug("Change in pubapi for package "+name+" line "+line);
166 Log.debug("Old: "+js);
167 Log.debug("New: "+is);
168 return true;
169 }
170 line++;
171 }
172 if ((i.hasNext() && !j.hasNext() ) ||
173 (!i.hasNext() && j.hasNext())) {
174 Log.debug("Change in pubapi for package "+name);
175 if (i.hasNext()) {
176 Log.debug("New has more lines!");
177 } else {
178 Log.debug("Old has more lines!");
179 }
180 return true;
181 }
182 return false;
183 }
184
185 public void setPubapi(List<String> ps) {
186 pubapi = ps;
187 }
188
189 public void setDependencies(Set<String> ds) {
190 dependencies = ds;
191 }
192
193 public void save(StringBuilder b) {
194 b.append("P ").append(name).append("\n");
195 Source.saveSources(sources, b);
196 saveDependencies(b);
197 savePubapi(b);
198 saveArtifacts(b);
199 }
200
201 static public Package load(Module module, String l) {
202 String name = l.substring(2);
203 return new Package(module, name);
204 }
205
206 public void loadDependency(String l) {
207 String n = l.substring(2);
208 addDependency(n);
209 }
210
211 public void loadPubapi(String l) {
212 String pi = l.substring(2);
213 addPubapi(pi);
214 }
215
216 public void saveDependencies(StringBuilder b) {
217 List<String> sorted_dependencies = new ArrayList<>();
218 for (String key : dependencies) {
219 sorted_dependencies.add(key);
220 }
221 Collections.sort(sorted_dependencies);
222 for (String a : sorted_dependencies) {
223 b.append("D "+a+"\n");
224 }
225 }
226
227 public void savePubapi(StringBuilder b) {
228 for (String l : pubapi) {
229 b.append("I "+l+"\n");
230 }
231 }
232
233 public static void savePackages(Map<String,Package> packages, StringBuilder b) {
234 List<String> sorted_packages = new ArrayList<>();
235 for (String key : packages.keySet() ) {
236 sorted_packages.add(key);
237 }
238 Collections.sort(sorted_packages);
239 for (String s : sorted_packages) {
240 Package p = packages.get(s);
241 p.save(b);
242 }
243 }
244
245 public void addArtifact(String a) {
246 artifacts.put(a, new File(a));
247 }
248
249 public void addArtifact(File f) {
250 artifacts.put(f.getPath(), f);
|
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;
27
28 import java.io.File;
29 import java.net.URI;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.TreeMap;
38 import java.util.regex.Matcher;
39 import java.util.regex.Pattern;
40 import java.util.stream.Stream;
41
42 import com.sun.tools.javac.util.Assert;
43 import com.sun.tools.sjavac.pubapi.PubApi;
44
45 /**
46 * The Package class maintains meta information about a package.
47 * For example its sources, dependents,its pubapi and its artifacts.
48 *
49 * It might look odd that we track dependents/pubapi/artifacts on
50 * a package level, but it makes sense since recompiling a full package
51 * takes as long as recompiling a single java file in that package,
52 * if you take into account the startup time of the jvm.
53 *
54 * Also the dependency information will be much smaller (good for the javac_state file size)
55 * and it simplifies tracking artifact generation, you do not always know from which
56 * source a class file was generated, but you always know which package it belongs to.
57 *
58 * It is also educational to see package dependencies triggering recompilation of
59 * other packages. Even though the recompilation was perhaps not necessary,
60 * the visible recompilation of the dependent packages indicates how much circular
61 * dependencies your code has.
62 *
63 * <p><b>This is NOT part of any supported API.
64 * If you write code that depends on this, you do so at your own risk.
65 * This code and its internal interfaces are subject to change or
66 * deletion without notice.</b>
67 */
68 public class Package implements Comparable<Package> {
69 // The module this package belongs to. (There is a legacy module with an empty string name,
70 // used for all legacy sources.)
71 private Module mod;
72 // Name of this package, module:pkg
73 // ex1 jdk.base:java.lang
74 // ex2 :java.lang (when in legacy mode)
75 private String name;
76 // The directory path to the package. If the package belongs to a module,
77 // then that module's file system name is part of the path.
78 private String dirname;
79 // This package has the following dependents, that depend on this package.
80 private Set<String> dependents = new HashSet<>();
81
82 // Fully qualified name of class in this package -> fully qualified name of dependency
83 private Map<String, Set<String>> dependencies = new TreeMap<>();
84 // Fully qualified name of class in this package -> fully qualified name of dependency on class path
85 private Map<String, Set<String>> cpDependencies = new TreeMap<>();
86
87 // This is the public api of this package.
88 private PubApi pubApi = new PubApi();
89 // Map from source file name to Source info object.
90 private Map<String,Source> sources = new HashMap<>();
91 // This package generated these artifacts.
92 private Map<String,File> artifacts = new HashMap<>();
93
94 public Package(Module m, String n) {
95 int c = n.indexOf(":");
96 Assert.check(c != -1);
97 Assert.check(m.name().equals(m.name()));
98 name = n;
99 dirname = n.replace('.', File.separatorChar);
100 if (m.name().length() > 0) {
101 // There is a module here, prefix the module dir name to the path.
102 dirname = m.dirname()+File.separatorChar+dirname;
103 }
104 }
105
106 public Module mod() { return mod; }
107 public String name() { return name; }
108 public String dirname() { return dirname; }
109 public Map<String,Source> sources() { return sources; }
110 public Map<String,File> artifacts() { return artifacts; }
111 public PubApi getPubApi() { return pubApi; }
112
113 public Map<String,Set<String>> typeDependencies() { return dependencies; }
114 public Map<String,Set<String>> typeClasspathDependencies() { return cpDependencies; }
115
116 public Set<String> dependents() { return dependents; }
117
118 @Override
119 public boolean equals(Object o) {
120 return (o instanceof Package) && name.equals(((Package)o).name);
121 }
122
123 @Override
124 public int hashCode() {
125 return name.hashCode();
126 }
127
128 @Override
129 public int compareTo(Package o) {
130 return name.compareTo(o.name);
131 }
132
133 public void addSource(Source s) {
134 sources.put(s.file().getPath(), s);
135 }
136
137 private static Pattern DEP_PATTERN = Pattern.compile("(.*) -> (.*)");
138 public void parseAndAddDependency(String d, boolean cp) {
139 Matcher m = DEP_PATTERN.matcher(d);
140 if (!m.matches())
141 throw new IllegalArgumentException("Bad dependency string: " + d);
142 addDependency(m.group(1), m.group(2), cp);
143 }
144
145 public void addDependency(String fullyQualifiedFrom,
146 String fullyQualifiedTo,
147 boolean cp) {
148 Map<String, Set<String>> map = cp ? cpDependencies : dependencies;
149 if (!map.containsKey(fullyQualifiedFrom))
150 map.put(fullyQualifiedFrom, new HashSet<>());
151 map.get(fullyQualifiedFrom).add(fullyQualifiedTo);
152 }
153
154 public void addDependent(String d) {
155 dependents.add(d);
156 }
157
158 /**
159 * Check if we have knowledge in the javac state that
160 * describe the results of compiling this package before.
161 */
162 public boolean existsInJavacState() {
163 return artifacts.size() > 0 || !pubApi.isEmpty();
164 }
165
166 public boolean hasPubApiChanged(PubApi newPubApi) {
167 return !newPubApi.isBackwardCompatibleWith(pubApi);
168 }
169
170 public void setPubapi(PubApi newPubApi) {
171 pubApi = newPubApi;
172 }
173
174 public void setDependencies(Map<String, Set<String>> ds, boolean cp) {
175 (cp ? cpDependencies : dependencies).clear();
176 for (String fullyQualifiedFrom : ds.keySet())
177 for (String fullyQualifiedTo : ds.get(fullyQualifiedFrom))
178 addDependency(fullyQualifiedFrom, fullyQualifiedTo, cp);
179 }
180
181 public void save(StringBuilder b) {
182 b.append("P ").append(name).append("\n");
183 Source.saveSources(sources, b);
184 saveDependencies(b);
185 savePubapi(b);
186 saveArtifacts(b);
187 }
188
189 static public Package load(Module module, String l) {
190 String name = l.substring(2);
191 return new Package(module, name);
192 }
193
194 public void saveDependencies(StringBuilder b) {
195
196 // Dependencies where *to* is among sources
197 for (String fullyQualifiedFrom : dependencies.keySet()) {
198 for (String fullyQualifiedTo : dependencies.get(fullyQualifiedFrom)) {
199 b.append(String.format("D S %s -> %s%n", fullyQualifiedFrom, fullyQualifiedTo));
200 }
201 }
202
203 // Dependencies where *to* is on class path
204 for (String fullyQualifiedFrom : cpDependencies.keySet()) {
205 for (String fullyQualifiedTo : cpDependencies.get(fullyQualifiedFrom)) {
206 b.append(String.format("D C %s -> %s%n", fullyQualifiedFrom, fullyQualifiedTo));
207 }
208 }
209 }
210
211 public void savePubapi(StringBuilder b) {
212 pubApi.asListOfStrings()
213 .stream()
214 .flatMap(l -> Stream.of("I ", l, "\n"))
215 .forEach(b::append);
216 }
217
218 public static void savePackages(Map<String,Package> packages, StringBuilder b) {
219 List<String> sorted_packages = new ArrayList<>();
220 for (String key : packages.keySet() ) {
221 sorted_packages.add(key);
222 }
223 Collections.sort(sorted_packages);
224 for (String s : sorted_packages) {
225 Package p = packages.get(s);
226 p.save(b);
227 }
228 }
229
230 public void addArtifact(String a) {
231 artifacts.put(a, new File(a));
232 }
233
234 public void addArtifact(File f) {
235 artifacts.put(f.getPath(), f);
|