Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/src/share/classes/com/sun/tools/jdeps/Analyzer.java
38899 views
1
/*
2
* Copyright (c) 2013, 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
package com.sun.tools.jdeps;
26
27
import java.util.HashMap;
28
import java.util.HashSet;
29
import java.util.List;
30
import java.util.Map;
31
import java.util.Objects;
32
import java.util.Set;
33
import java.util.SortedMap;
34
import java.util.SortedSet;
35
import java.util.TreeMap;
36
import java.util.TreeSet;
37
38
import com.sun.tools.classfile.Dependency.Location;
39
import com.sun.tools.jdeps.PlatformClassPath.JDKArchive;
40
41
/**
42
* Dependency Analyzer.
43
*/
44
public class Analyzer {
45
/**
46
* Type of the dependency analysis. Appropriate level of data
47
* will be stored.
48
*/
49
public enum Type {
50
SUMMARY,
51
PACKAGE,
52
CLASS,
53
VERBOSE
54
};
55
56
/**
57
* Filter to be applied when analyzing the dependencies from the given archives.
58
* Only the accepted dependencies are recorded.
59
*/
60
interface Filter {
61
boolean accepts(Location origin, Archive originArchive, Location target, Archive targetArchive);
62
}
63
64
private final Type type;
65
private final Filter filter;
66
private final Map<Archive, ArchiveDeps> results = new HashMap<>();
67
private final Map<Location, Archive> map = new HashMap<>();
68
private final Archive NOT_FOUND
69
= new Archive(JdepsTask.getMessage("artifact.not.found"));
70
71
/**
72
* Constructs an Analyzer instance.
73
*
74
* @param type Type of the dependency analysis
75
* @param filter
76
*/
77
public Analyzer(Type type, Filter filter) {
78
this.type = type;
79
this.filter = filter;
80
}
81
82
/**
83
* Performs the dependency analysis on the given archives.
84
*/
85
public void run(List<Archive> archives) {
86
// build a map from Location to Archive
87
buildLocationArchiveMap(archives);
88
89
// traverse and analyze all dependencies
90
for (Archive archive : archives) {
91
ArchiveDeps deps = new ArchiveDeps(archive, type);
92
archive.visitDependences(deps);
93
results.put(archive, deps);
94
}
95
}
96
97
private void buildLocationArchiveMap(List<Archive> archives) {
98
// build a map from Location to Archive
99
for (Archive archive: archives) {
100
for (Location l: archive.getClasses()) {
101
if (!map.containsKey(l)) {
102
map.put(l, archive);
103
} else {
104
// duplicated class warning?
105
}
106
}
107
}
108
}
109
110
public boolean hasDependences(Archive archive) {
111
if (results.containsKey(archive)) {
112
return results.get(archive).dependencies().size() > 0;
113
}
114
return false;
115
}
116
117
public Set<String> dependences(Archive source) {
118
ArchiveDeps result = results.get(source);
119
return result.targetDependences();
120
}
121
122
public interface Visitor {
123
/**
124
* Visits a recorded dependency from origin to target which can be
125
* a fully-qualified classname, a package name, a module or
126
* archive name depending on the Analyzer's type.
127
*/
128
public void visitDependence(String origin, Archive originArchive,
129
String target, Archive targetArchive);
130
}
131
132
/**
133
* Visit the dependencies of the given source.
134
* If the requested level is SUMMARY, it will visit the required archives list.
135
*/
136
public void visitDependences(Archive source, Visitor v, Type level) {
137
if (level == Type.SUMMARY) {
138
final ArchiveDeps result = results.get(source);
139
SortedMap<String, Archive> sorted = new TreeMap<>();
140
for (Archive a : result.requires()) {
141
sorted.put(a.getName(), a);
142
}
143
for (Archive archive : sorted.values()) {
144
Profile profile = result.getTargetProfile(archive);
145
v.visitDependence(source.getName(), source,
146
profile != null ? profile.profileName() : archive.getName(), archive);
147
}
148
} else {
149
ArchiveDeps result = results.get(source);
150
if (level != type) {
151
// requesting different level of analysis
152
result = new ArchiveDeps(source, level);
153
source.visitDependences(result);
154
}
155
SortedSet<Dep> sorted = new TreeSet<>(result.dependencies());
156
for (Dep d : sorted) {
157
v.visitDependence(d.origin(), d.originArchive(), d.target(), d.targetArchive());
158
}
159
}
160
}
161
162
public void visitDependences(Archive source, Visitor v) {
163
visitDependences(source, v, type);
164
}
165
166
/**
167
* ArchiveDeps contains the dependencies for an Archive that can have one or
168
* more classes.
169
*/
170
class ArchiveDeps implements Archive.Visitor {
171
protected final Archive archive;
172
protected final Set<Archive> requires;
173
protected final Set<Dep> deps;
174
protected final Type level;
175
private Profile profile;
176
ArchiveDeps(Archive archive, Type level) {
177
this.archive = archive;
178
this.deps = new HashSet<>();
179
this.requires = new HashSet<>();
180
this.level = level;
181
}
182
183
Set<Dep> dependencies() {
184
return deps;
185
}
186
187
Set<String> targetDependences() {
188
Set<String> targets = new HashSet<>();
189
for (Dep d : deps) {
190
targets.add(d.target());
191
}
192
return targets;
193
}
194
195
Set<Archive> requires() {
196
return requires;
197
}
198
199
Profile getTargetProfile(Archive target) {
200
return JDKArchive.isProfileArchive(target) ? profile : null;
201
}
202
203
Archive findArchive(Location t) {
204
Archive target = archive.getClasses().contains(t) ? archive : map.get(t);
205
if (target == null) {
206
map.put(t, target = NOT_FOUND);
207
}
208
return target;
209
}
210
211
// return classname or package name depedning on the level
212
private String getLocationName(Location o) {
213
if (level == Type.CLASS || level == Type.VERBOSE) {
214
return o.getClassName();
215
} else {
216
String pkg = o.getPackageName();
217
return pkg.isEmpty() ? "<unnamed>" : pkg;
218
}
219
}
220
221
@Override
222
public void visit(Location o, Location t) {
223
Archive targetArchive = findArchive(t);
224
if (filter.accepts(o, archive, t, targetArchive)) {
225
addDep(o, t);
226
if (archive != targetArchive && !requires.contains(targetArchive)) {
227
requires.add(targetArchive);
228
}
229
}
230
if (targetArchive instanceof JDKArchive) {
231
Profile p = Profile.getProfile(t.getPackageName());
232
if (profile == null || (p != null && p.compareTo(profile) > 0)) {
233
profile = p;
234
}
235
}
236
}
237
238
private Dep curDep;
239
protected Dep addDep(Location o, Location t) {
240
String origin = getLocationName(o);
241
String target = getLocationName(t);
242
Archive targetArchive = findArchive(t);
243
if (curDep != null &&
244
curDep.origin().equals(origin) &&
245
curDep.originArchive() == archive &&
246
curDep.target().equals(target) &&
247
curDep.targetArchive() == targetArchive) {
248
return curDep;
249
}
250
251
Dep e = new Dep(origin, archive, target, targetArchive);
252
if (deps.contains(e)) {
253
for (Dep e1 : deps) {
254
if (e.equals(e1)) {
255
curDep = e1;
256
}
257
}
258
} else {
259
deps.add(e);
260
curDep = e;
261
}
262
return curDep;
263
}
264
}
265
266
/*
267
* Class-level or package-level dependency
268
*/
269
class Dep implements Comparable<Dep> {
270
final String origin;
271
final Archive originArchive;
272
final String target;
273
final Archive targetArchive;
274
275
Dep(String origin, Archive originArchive, String target, Archive targetArchive) {
276
this.origin = origin;
277
this.originArchive = originArchive;
278
this.target = target;
279
this.targetArchive = targetArchive;
280
}
281
282
String origin() {
283
return origin;
284
}
285
286
Archive originArchive() {
287
return originArchive;
288
}
289
290
String target() {
291
return target;
292
}
293
294
Archive targetArchive() {
295
return targetArchive;
296
}
297
298
@Override
299
@SuppressWarnings("unchecked")
300
public boolean equals(Object o) {
301
if (o instanceof Dep) {
302
Dep d = (Dep) o;
303
return this.origin.equals(d.origin) &&
304
this.originArchive == d.originArchive &&
305
this.target.equals(d.target) &&
306
this.targetArchive == d.targetArchive;
307
}
308
return false;
309
}
310
311
@Override
312
public int hashCode() {
313
int hash = 7;
314
hash = 67*hash + Objects.hashCode(this.origin)
315
+ Objects.hashCode(this.originArchive)
316
+ Objects.hashCode(this.target)
317
+ Objects.hashCode(this.targetArchive);
318
return hash;
319
}
320
321
@Override
322
public int compareTo(Dep o) {
323
if (this.origin.equals(o.origin)) {
324
if (this.target.equals(o.target)) {
325
if (this.originArchive == o.originArchive &&
326
this.targetArchive == o.targetArchive) {
327
return 0;
328
} else if (this.originArchive == o.originArchive) {
329
return this.targetArchive.getPathName().compareTo(o.targetArchive.getPathName());
330
} else {
331
return this.originArchive.getPathName().compareTo(o.originArchive.getPathName());
332
}
333
} else {
334
return this.target.compareTo(o.target);
335
}
336
}
337
return this.origin.compareTo(o.origin);
338
}
339
}
340
}
341
342