30 import java.io.BufferedReader; |
30 import java.io.BufferedReader; |
31 import java.io.IOException; |
31 import java.io.IOException; |
32 import java.io.InputStream; |
32 import java.io.InputStream; |
33 import java.io.InputStreamReader; |
33 import java.io.InputStreamReader; |
34 import java.io.UncheckedIOException; |
34 import java.io.UncheckedIOException; |
|
35 import java.lang.module.ModuleDescriptor; |
35 import java.util.Collections; |
36 import java.util.Collections; |
36 import java.util.Comparator; |
37 import java.util.Comparator; |
37 import java.util.HashMap; |
38 import java.util.HashMap; |
38 import java.util.HashSet; |
39 import java.util.HashSet; |
39 import java.util.Map; |
40 import java.util.Map; |
40 import java.util.Objects; |
41 import java.util.Objects; |
41 import java.util.Set; |
42 import java.util.Set; |
|
43 import java.util.function.Predicate; |
42 import java.util.stream.Collectors; |
44 import java.util.stream.Collectors; |
43 import java.util.stream.Stream; |
45 import java.util.stream.Stream; |
44 |
46 |
45 /** |
47 /** |
46 * Dependency Analyzer. |
48 * Dependency Analyzer. |
72 protected final Filter filter; |
74 protected final Filter filter; |
73 protected final Map<Archive, Dependences> results = new HashMap<>(); |
75 protected final Map<Archive, Dependences> results = new HashMap<>(); |
74 protected final Map<Location, Archive> locationToArchive = new HashMap<>(); |
76 protected final Map<Location, Archive> locationToArchive = new HashMap<>(); |
75 static final Archive NOT_FOUND |
77 static final Archive NOT_FOUND |
76 = new Archive(JdepsTask.getMessage("artifact.not.found")); |
78 = new Archive(JdepsTask.getMessage("artifact.not.found")); |
|
79 static final Predicate<Archive> ANY = a -> true; |
77 |
80 |
78 /** |
81 /** |
79 * Constructs an Analyzer instance. |
82 * Constructs an Analyzer instance. |
80 * |
83 * |
81 * @param type Type of the dependency analysis |
84 * @param type Type of the dependency analysis |
159 |
162 |
160 /** |
163 /** |
161 * Visit the dependencies of the given source. |
164 * Visit the dependencies of the given source. |
162 * If the requested level is SUMMARY, it will visit the required archives list. |
165 * If the requested level is SUMMARY, it will visit the required archives list. |
163 */ |
166 */ |
164 void visitDependences(Archive source, Visitor v, Type level) { |
167 void visitDependences(Archive source, Visitor v, Type level, Predicate<Archive> targetFilter) { |
165 if (level == Type.SUMMARY) { |
168 if (level == Type.SUMMARY) { |
166 final Dependences result = results.get(source); |
169 final Dependences result = results.get(source); |
167 final Set<Archive> reqs = result.requires(); |
170 final Set<Archive> reqs = result.requires(); |
168 Stream<Archive> stream = reqs.stream(); |
171 Stream<Archive> stream = reqs.stream(); |
169 if (reqs.isEmpty()) { |
172 if (reqs.isEmpty()) { |
182 }); |
185 }); |
183 } else { |
186 } else { |
184 Dependences result = results.get(source); |
187 Dependences result = results.get(source); |
185 if (level != type) { |
188 if (level != type) { |
186 // requesting different level of analysis |
189 // requesting different level of analysis |
187 result = new Dependences(source, level); |
190 result = new Dependences(source, level, targetFilter); |
188 source.visitDependences(result); |
191 source.visitDependences(result); |
189 } |
192 } |
190 result.dependencies().stream() |
193 result.dependencies().stream() |
191 .sorted(Comparator.comparing(Dep::origin) |
194 .sorted(Comparator.comparing(Dep::origin) |
192 .thenComparing(Dep::target)) |
195 .thenComparing(Dep::target)) |
194 d.target(), d.targetArchive())); |
197 d.target(), d.targetArchive())); |
195 } |
198 } |
196 } |
199 } |
197 |
200 |
198 void visitDependences(Archive source, Visitor v) { |
201 void visitDependences(Archive source, Visitor v) { |
199 visitDependences(source, v, type); |
202 visitDependences(source, v, type, ANY); |
|
203 } |
|
204 |
|
205 void visitDependences(Archive source, Visitor v, Type level) { |
|
206 visitDependences(source, v, level, ANY); |
200 } |
207 } |
201 |
208 |
202 /** |
209 /** |
203 * Dependences contains the dependencies for an Archive that can have one or |
210 * Dependences contains the dependencies for an Archive that can have one or |
204 * more classes. |
211 * more classes. |
206 class Dependences implements Archive.Visitor { |
213 class Dependences implements Archive.Visitor { |
207 protected final Archive archive; |
214 protected final Archive archive; |
208 protected final Set<Archive> requires; |
215 protected final Set<Archive> requires; |
209 protected final Set<Dep> deps; |
216 protected final Set<Dep> deps; |
210 protected final Type level; |
217 protected final Type level; |
|
218 protected final Predicate<Archive> targetFilter; |
211 private Profile profile; |
219 private Profile profile; |
212 Dependences(Archive archive, Type level) { |
220 Dependences(Archive archive, Type level) { |
|
221 this(archive, level, ANY); |
|
222 } |
|
223 Dependences(Archive archive, Type level, Predicate<Archive> targetFilter) { |
213 this.archive = archive; |
224 this.archive = archive; |
214 this.deps = new HashSet<>(); |
225 this.deps = new HashSet<>(); |
215 this.requires = new HashSet<>(); |
226 this.requires = new HashSet<>(); |
216 this.level = level; |
227 this.level = level; |
|
228 this.targetFilter = targetFilter; |
217 } |
229 } |
218 |
230 |
219 Set<Dep> dependencies() { |
231 Set<Dep> dependencies() { |
220 return deps; |
232 return deps; |
221 } |
233 } |
264 } |
276 } |
265 |
277 |
266 @Override |
278 @Override |
267 public void visit(Location o, Location t) { |
279 public void visit(Location o, Location t) { |
268 Archive targetArchive = findArchive(t); |
280 Archive targetArchive = findArchive(t); |
269 if (filter.accepts(o, archive, t, targetArchive)) { |
281 if (filter.accepts(o, archive, t, targetArchive) && targetFilter.test(targetArchive)) { |
270 addDep(o, t); |
282 addDep(o, t); |
271 if (archive != targetArchive && !requires.contains(targetArchive)) { |
283 if (archive != targetArchive && !requires.contains(targetArchive)) { |
272 requires.add(targetArchive); |
284 requires.add(targetArchive); |
273 } |
285 } |
274 } |
286 } |
366 origin, originArchive.getName(), |
378 origin, originArchive.getName(), |
367 target, targetArchive.getName()); |
379 target, targetArchive.getName()); |
368 } |
380 } |
369 } |
381 } |
370 |
382 |
|
383 /* |
|
384 * Returns true if the given archive represents not found. |
|
385 */ |
|
386 static boolean notFound(Archive archive) { |
|
387 return archive == NOT_FOUND || archive == REMOVED_JDK_INTERNALS; |
|
388 } |
|
389 |
371 static final Jdk8Internals REMOVED_JDK_INTERNALS = new Jdk8Internals(); |
390 static final Jdk8Internals REMOVED_JDK_INTERNALS = new Jdk8Internals(); |
372 |
391 |
373 static class Jdk8Internals extends Module { |
392 static class Jdk8Internals extends Module { |
374 private final String JDK8_INTERNALS = "/com/sun/tools/jdeps/resources/jdk8_internals.txt"; |
393 private static final String NAME = "JDK removed internal API"; |
|
394 private static final String JDK8_INTERNALS = "/com/sun/tools/jdeps/resources/jdk8_internals.txt"; |
375 private final Set<String> jdk8Internals; |
395 private final Set<String> jdk8Internals; |
376 private Jdk8Internals() { |
396 private Jdk8Internals() { |
377 super("JDK removed internal API"); |
397 super(NAME, ModuleDescriptor.newModule("jdk8internals").build(), true); |
378 try (InputStream in = JdepsTask.class.getResourceAsStream(JDK8_INTERNALS); |
398 try (InputStream in = JdepsTask.class.getResourceAsStream(JDK8_INTERNALS); |
379 BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { |
399 BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { |
380 this.jdk8Internals = reader.lines() |
400 this.jdk8Internals = reader.lines() |
381 .filter(ln -> !ln.startsWith("#")) |
401 .filter(ln -> !ln.startsWith("#")) |
382 .collect(Collectors.toSet()); |
402 .collect(Collectors.toSet()); |