Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/jdk/internal/module/ModulePathValidator.java
41159 views
1
/*
2
* Copyright (c) 2018, 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 jdk.internal.module;
27
28
import java.io.File;
29
import java.io.IOException;
30
import java.io.PrintStream;
31
import java.lang.module.FindException;
32
import java.lang.module.ModuleDescriptor;
33
import java.lang.module.ModuleFinder;
34
import java.lang.module.ModuleReference;
35
import java.net.URI;
36
import java.nio.file.DirectoryStream;
37
import java.nio.file.Files;
38
import java.nio.file.NoSuchFileException;
39
import java.nio.file.Path;
40
import java.nio.file.attribute.BasicFileAttributes;
41
import java.util.Comparator;
42
import java.util.HashMap;
43
import java.util.Map;
44
import java.util.Optional;
45
import java.util.stream.Stream;
46
47
/**
48
* A validator to check for errors and conflicts between modules.
49
*/
50
51
class ModulePathValidator {
52
private static final String MODULE_INFO = "module-info.class";
53
private static final String INDENT = " ";
54
55
private final Map<String, ModuleReference> nameToModule;
56
private final Map<String, ModuleReference> packageToModule;
57
private final PrintStream out;
58
59
private int errorCount;
60
61
private ModulePathValidator(PrintStream out) {
62
this.nameToModule = new HashMap<>();
63
this.packageToModule = new HashMap<>();
64
this.out = out;
65
}
66
67
/**
68
* Scans and the validates all modules on the module path. The module path
69
* comprises the upgrade module path, system modules, and the application
70
* module path.
71
*
72
* @param out the print stream for output messages
73
* @return the number of errors found
74
*/
75
static int scanAllModules(PrintStream out) {
76
ModulePathValidator validator = new ModulePathValidator(out);
77
78
// upgrade module path
79
String value = System.getProperty("jdk.module.upgrade.path");
80
if (value != null) {
81
Stream.of(value.split(File.pathSeparator))
82
.map(Path::of)
83
.forEach(validator::scan);
84
}
85
86
// system modules
87
ModuleFinder.ofSystem().findAll().stream()
88
.sorted(Comparator.comparing(ModuleReference::descriptor))
89
.forEach(validator::process);
90
91
// application module path
92
value = System.getProperty("jdk.module.path");
93
if (value != null) {
94
Stream.of(value.split(File.pathSeparator))
95
.map(Path::of)
96
.forEach(validator::scan);
97
}
98
99
return validator.errorCount;
100
}
101
102
/**
103
* Prints the module location and name.
104
*/
105
private void printModule(ModuleReference mref) {
106
mref.location()
107
.filter(uri -> !isJrt(uri))
108
.ifPresent(uri -> out.print(uri + " "));
109
ModuleDescriptor descriptor = mref.descriptor();
110
out.print(descriptor.name());
111
if (descriptor.isAutomatic())
112
out.print(" automatic");
113
out.println();
114
}
115
116
/**
117
* Prints the module location and name, checks if the module is
118
* shadowed by a previously seen module, and finally checks for
119
* package conflicts with previously seen modules.
120
*/
121
private void process(ModuleReference mref) {
122
String name = mref.descriptor().name();
123
ModuleReference previous = nameToModule.putIfAbsent(name, mref);
124
if (previous != null) {
125
printModule(mref);
126
out.print(INDENT + "shadowed by ");
127
printModule(previous);
128
} else {
129
boolean first = true;
130
131
// check for package conflicts when not shadowed
132
for (String pkg : mref.descriptor().packages()) {
133
previous = packageToModule.putIfAbsent(pkg, mref);
134
if (previous != null) {
135
if (first) {
136
printModule(mref);
137
first = false;
138
errorCount++;
139
}
140
String mn = previous.descriptor().name();
141
out.println(INDENT + "contains " + pkg
142
+ " conflicts with module " + mn);
143
}
144
}
145
}
146
}
147
148
/**
149
* Scan an element on a module path. The element is a directory
150
* of modules, an exploded module, or a JAR file.
151
*/
152
private void scan(Path entry) {
153
BasicFileAttributes attrs;
154
try {
155
attrs = Files.readAttributes(entry, BasicFileAttributes.class);
156
} catch (NoSuchFileException ignore) {
157
return;
158
} catch (IOException ioe) {
159
out.println(entry + " " + ioe);
160
errorCount++;
161
return;
162
}
163
164
String fn = entry.getFileName().toString();
165
if (attrs.isRegularFile() && fn.endsWith(".jar")) {
166
// JAR file, explicit or automatic module
167
scanModule(entry).ifPresent(this::process);
168
} else if (attrs.isDirectory()) {
169
Path mi = entry.resolve(MODULE_INFO);
170
if (Files.exists(mi)) {
171
// exploded module
172
scanModule(entry).ifPresent(this::process);
173
} else {
174
// directory of modules
175
scanDirectory(entry);
176
}
177
}
178
}
179
180
/**
181
* Scan the JAR files and exploded modules in a directory.
182
*/
183
private void scanDirectory(Path dir) {
184
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
185
Map<String, Path> moduleToEntry = new HashMap<>();
186
187
for (Path entry : stream) {
188
BasicFileAttributes attrs;
189
try {
190
attrs = Files.readAttributes(entry, BasicFileAttributes.class);
191
} catch (IOException ioe) {
192
out.println(entry + " " + ioe);
193
errorCount++;
194
continue;
195
}
196
197
ModuleReference mref = null;
198
199
String fn = entry.getFileName().toString();
200
if (attrs.isRegularFile() && fn.endsWith(".jar")) {
201
mref = scanModule(entry).orElse(null);
202
} else if (attrs.isDirectory()) {
203
Path mi = entry.resolve(MODULE_INFO);
204
if (Files.exists(mi)) {
205
mref = scanModule(entry).orElse(null);
206
}
207
}
208
209
if (mref != null) {
210
String name = mref.descriptor().name();
211
Path previous = moduleToEntry.putIfAbsent(name, entry);
212
if (previous != null) {
213
// same name as other module in the directory
214
printModule(mref);
215
out.println(INDENT + "contains same module as "
216
+ previous.getFileName());
217
errorCount++;
218
} else {
219
process(mref);
220
}
221
}
222
}
223
} catch (IOException ioe) {
224
out.println(dir + " " + ioe);
225
errorCount++;
226
}
227
}
228
229
/**
230
* Scan a JAR file or exploded module.
231
*/
232
private Optional<ModuleReference> scanModule(Path entry) {
233
ModuleFinder finder = ModuleFinder.of(entry);
234
try {
235
return finder.findAll().stream().findFirst();
236
} catch (FindException e) {
237
out.println(entry);
238
out.println(INDENT + e.getMessage());
239
Throwable cause = e.getCause();
240
if (cause != null) {
241
out.println(INDENT + cause);
242
}
243
errorCount++;
244
return Optional.empty();
245
}
246
}
247
248
/**
249
* Returns true if the given URI is a jrt URI
250
*/
251
private static boolean isJrt(URI uri) {
252
return (uri != null && uri.getScheme().equalsIgnoreCase("jrt"));
253
}
254
}
255
256