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/ModuleReferences.java
41159 views
1
/*
2
* Copyright (c) 2015, 2021, 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.IOError;
30
import java.io.IOException;
31
import java.io.InputStream;
32
import java.io.UncheckedIOException;
33
import java.lang.module.ModuleReader;
34
import java.lang.module.ModuleReference;
35
import java.net.URI;
36
import java.nio.ByteBuffer;
37
import java.nio.file.Files;
38
import java.nio.file.Path;
39
import java.util.List;
40
import java.util.Objects;
41
import java.util.Optional;
42
import java.util.concurrent.locks.Lock;
43
import java.util.concurrent.locks.ReadWriteLock;
44
import java.util.concurrent.locks.ReentrantReadWriteLock;
45
import java.util.function.Supplier;
46
import java.util.jar.JarEntry;
47
import java.util.jar.JarFile;
48
import java.util.stream.Stream;
49
import java.util.zip.ZipFile;
50
51
import jdk.internal.jmod.JmodFile;
52
import jdk.internal.module.ModuleHashes.HashSupplier;
53
import sun.net.www.ParseUtil;
54
55
56
/**
57
* A factory for creating ModuleReference implementations where the modules are
58
* packaged as modular JAR file, JMOD files or where the modules are exploded
59
* on the file system.
60
*/
61
62
class ModuleReferences {
63
private ModuleReferences() { }
64
65
/**
66
* Creates a ModuleReference to a possibly-patched module
67
*/
68
private static ModuleReference newModule(ModuleInfo.Attributes attrs,
69
URI uri,
70
Supplier<ModuleReader> supplier,
71
ModulePatcher patcher,
72
HashSupplier hasher) {
73
ModuleReference mref = new ModuleReferenceImpl(attrs.descriptor(),
74
uri,
75
supplier,
76
null,
77
attrs.target(),
78
attrs.recordedHashes(),
79
hasher,
80
attrs.moduleResolution());
81
if (patcher != null)
82
mref = patcher.patchIfNeeded(mref);
83
84
return mref;
85
}
86
87
/**
88
* Creates a ModuleReference to a possibly-patched module in a modular JAR.
89
*/
90
static ModuleReference newJarModule(ModuleInfo.Attributes attrs,
91
ModulePatcher patcher,
92
Path file) {
93
URI uri = file.toUri();
94
Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
95
HashSupplier hasher = (a) -> ModuleHashes.computeHash(supplier, a);
96
return newModule(attrs, uri, supplier, patcher, hasher);
97
}
98
99
/**
100
* Creates a ModuleReference to a module in a JMOD file.
101
*/
102
static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) {
103
URI uri = file.toUri();
104
Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
105
HashSupplier hasher = (a) -> ModuleHashes.computeHash(supplier, a);
106
return newModule(attrs, uri, supplier, null, hasher);
107
}
108
109
/**
110
* Creates a ModuleReference to a possibly-patched exploded module.
111
*/
112
static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs,
113
ModulePatcher patcher,
114
Path dir) {
115
Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
116
return newModule(attrs, dir.toUri(), supplier, patcher, null);
117
}
118
119
120
/**
121
* A base module reader that encapsulates machinery required to close the
122
* module reader safely.
123
*/
124
static abstract class SafeCloseModuleReader implements ModuleReader {
125
126
// RW lock to support safe close
127
private final ReadWriteLock lock = new ReentrantReadWriteLock();
128
private final Lock readLock = lock.readLock();
129
private final Lock writeLock = lock.writeLock();
130
private boolean closed;
131
132
SafeCloseModuleReader() { }
133
134
/**
135
* Returns a URL to resource. This method is invoked by the find
136
* method to do the actual work of finding the resource.
137
*/
138
abstract Optional<URI> implFind(String name) throws IOException;
139
140
/**
141
* Returns an input stream for reading a resource. This method is
142
* invoked by the open method to do the actual work of opening
143
* an input stream to the resource.
144
*/
145
abstract Optional<InputStream> implOpen(String name) throws IOException;
146
147
/**
148
* Returns a stream of the names of resources in the module. This
149
* method is invoked by the list method to do the actual work of
150
* creating the stream.
151
*/
152
abstract Stream<String> implList() throws IOException;
153
154
/**
155
* Closes the module reader. This method is invoked by close to do the
156
* actual work of closing the module reader.
157
*/
158
abstract void implClose() throws IOException;
159
160
@Override
161
public final Optional<URI> find(String name) throws IOException {
162
readLock.lock();
163
try {
164
if (!closed) {
165
return implFind(name);
166
} else {
167
throw new IOException("ModuleReader is closed");
168
}
169
} finally {
170
readLock.unlock();
171
}
172
}
173
174
175
@Override
176
public final Optional<InputStream> open(String name) throws IOException {
177
readLock.lock();
178
try {
179
if (!closed) {
180
return implOpen(name);
181
} else {
182
throw new IOException("ModuleReader is closed");
183
}
184
} finally {
185
readLock.unlock();
186
}
187
}
188
189
@Override
190
public final Stream<String> list() throws IOException {
191
readLock.lock();
192
try {
193
if (!closed) {
194
return implList();
195
} else {
196
throw new IOException("ModuleReader is closed");
197
}
198
} finally {
199
readLock.unlock();
200
}
201
}
202
203
@Override
204
public final void close() throws IOException {
205
writeLock.lock();
206
try {
207
if (!closed) {
208
closed = true;
209
implClose();
210
}
211
} finally {
212
writeLock.unlock();
213
}
214
}
215
}
216
217
218
/**
219
* A ModuleReader for a modular JAR file.
220
*/
221
static class JarModuleReader extends SafeCloseModuleReader {
222
private final JarFile jf;
223
private final URI uri;
224
225
static JarFile newJarFile(Path path) {
226
try {
227
return new JarFile(new File(path.toString()),
228
true, // verify
229
ZipFile.OPEN_READ,
230
JarFile.runtimeVersion());
231
} catch (IOException ioe) {
232
throw new UncheckedIOException(ioe);
233
}
234
}
235
236
JarModuleReader(Path path, URI uri) {
237
this.jf = newJarFile(path);
238
this.uri = uri;
239
}
240
241
private JarEntry getEntry(String name) {
242
return jf.getJarEntry(Objects.requireNonNull(name));
243
}
244
245
@Override
246
Optional<URI> implFind(String name) throws IOException {
247
JarEntry je = getEntry(name);
248
if (je != null) {
249
if (jf.isMultiRelease())
250
name = je.getRealName();
251
if (je.isDirectory() && !name.endsWith("/"))
252
name += "/";
253
String encodedPath = ParseUtil.encodePath(name, false);
254
String uris = "jar:" + uri + "!/" + encodedPath;
255
return Optional.of(URI.create(uris));
256
} else {
257
return Optional.empty();
258
}
259
}
260
261
@Override
262
Optional<InputStream> implOpen(String name) throws IOException {
263
JarEntry je = getEntry(name);
264
if (je != null) {
265
return Optional.of(jf.getInputStream(je));
266
} else {
267
return Optional.empty();
268
}
269
}
270
271
@Override
272
Stream<String> implList() throws IOException {
273
// take snapshot to avoid async close
274
List<String> names = jf.versionedStream()
275
.map(JarEntry::getName)
276
.toList();
277
return names.stream();
278
}
279
280
@Override
281
void implClose() throws IOException {
282
jf.close();
283
}
284
}
285
286
287
/**
288
* A ModuleReader for a JMOD file.
289
*/
290
static class JModModuleReader extends SafeCloseModuleReader {
291
private final JmodFile jf;
292
private final URI uri;
293
294
static JmodFile newJmodFile(Path path) {
295
try {
296
return new JmodFile(path);
297
} catch (IOException ioe) {
298
throw new UncheckedIOException(ioe);
299
}
300
}
301
302
JModModuleReader(Path path, URI uri) {
303
this.jf = newJmodFile(path);
304
this.uri = uri;
305
}
306
307
private JmodFile.Entry getEntry(String name) {
308
Objects.requireNonNull(name);
309
return jf.getEntry(JmodFile.Section.CLASSES, name);
310
}
311
312
@Override
313
Optional<URI> implFind(String name) {
314
JmodFile.Entry je = getEntry(name);
315
if (je != null) {
316
if (je.isDirectory() && !name.endsWith("/"))
317
name += "/";
318
String encodedPath = ParseUtil.encodePath(name, false);
319
String uris = "jmod:" + uri + "!/" + encodedPath;
320
return Optional.of(URI.create(uris));
321
} else {
322
return Optional.empty();
323
}
324
}
325
326
@Override
327
Optional<InputStream> implOpen(String name) throws IOException {
328
JmodFile.Entry je = getEntry(name);
329
if (je != null) {
330
return Optional.of(jf.getInputStream(je));
331
} else {
332
return Optional.empty();
333
}
334
}
335
336
@Override
337
Stream<String> implList() throws IOException {
338
// take snapshot to avoid async close
339
List<String> names = jf.stream()
340
.filter(e -> e.section() == JmodFile.Section.CLASSES)
341
.map(JmodFile.Entry::name)
342
.toList();
343
return names.stream();
344
}
345
346
@Override
347
void implClose() throws IOException {
348
jf.close();
349
}
350
}
351
352
353
/**
354
* A ModuleReader for an exploded module.
355
*/
356
static class ExplodedModuleReader implements ModuleReader {
357
private final Path dir;
358
private volatile boolean closed;
359
360
ExplodedModuleReader(Path dir) {
361
this.dir = dir;
362
363
// when running with a security manager then check that the caller
364
// has access to the directory.
365
@SuppressWarnings("removal")
366
SecurityManager sm = System.getSecurityManager();
367
if (sm != null) {
368
boolean unused = Files.isDirectory(dir);
369
}
370
}
371
372
/**
373
* Throws IOException if the module reader is closed;
374
*/
375
private void ensureOpen() throws IOException {
376
if (closed) throw new IOException("ModuleReader is closed");
377
}
378
379
@Override
380
public Optional<URI> find(String name) throws IOException {
381
ensureOpen();
382
Path path = Resources.toFilePath(dir, name);
383
if (path != null) {
384
try {
385
return Optional.of(path.toUri());
386
} catch (IOError e) {
387
throw (IOException) e.getCause();
388
}
389
} else {
390
return Optional.empty();
391
}
392
}
393
394
@Override
395
public Optional<InputStream> open(String name) throws IOException {
396
ensureOpen();
397
Path path = Resources.toFilePath(dir, name);
398
if (path != null) {
399
return Optional.of(Files.newInputStream(path));
400
} else {
401
return Optional.empty();
402
}
403
}
404
405
@Override
406
public Optional<ByteBuffer> read(String name) throws IOException {
407
ensureOpen();
408
Path path = Resources.toFilePath(dir, name);
409
if (path != null) {
410
return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
411
} else {
412
return Optional.empty();
413
}
414
}
415
416
@Override
417
public Stream<String> list() throws IOException {
418
ensureOpen();
419
return Files.walk(dir, Integer.MAX_VALUE)
420
.map(f -> Resources.toResourceName(dir, f))
421
.filter(s -> s.length() > 0);
422
}
423
424
@Override
425
public void close() {
426
closed = true;
427
}
428
}
429
430
}
431
432