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.nio.file.Paths;
40 import java.util.List;
41 import java.util.Objects;
42 import java.util.Optional;
43 import java.util.concurrent.locks.Lock;
44 import java.util.concurrent.locks.ReadWriteLock;
45 import java.util.concurrent.locks.ReentrantReadWriteLock;
46 import java.util.function.Supplier;
47 import java.util.jar.JarEntry;
48 import java.util.jar.JarFile;
49 import java.util.stream.Collectors;
50 import java.util.stream.Stream;
51 import java.util.zip.ZipFile;
52
53 import jdk.internal.jmod.JmodFile;
54 import jdk.internal.misc.JavaLangAccess;
55 import jdk.internal.misc.SharedSecrets;
56 import jdk.internal.module.ModuleHashes.HashSupplier;
57 import jdk.internal.util.jar.VersionedStream;
58 import sun.net.www.ParseUtil;
59
60
61 /**
62 * A factory for creating ModuleReference implementations where the modules are
63 * packaged as modular JAR file, JMOD files or where the modules are exploded
64 * on the file system.
65 */
66
67 class ModuleReferences {
68
69 private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
70
71 private ModuleReferences() { }
72
73 /**
226 private final JarFile jf;
227 private final URI uri;
228
229 static JarFile newJarFile(Path path) {
230 try {
231 return new JarFile(path.toFile(),
232 true, // verify
233 ZipFile.OPEN_READ,
234 JarFile.runtimeVersion());
235 } catch (IOException ioe) {
236 throw new UncheckedIOException(ioe);
237 }
238 }
239
240 JarModuleReader(Path path, URI uri) {
241 this.jf = newJarFile(path);
242 this.uri = uri;
243 }
244
245 private JarEntry getEntry(String name) {
246 return jf.getJarEntry(Objects.requireNonNull(name));
247 }
248
249 @Override
250 Optional<URI> implFind(String name) throws IOException {
251 JarEntry je = getEntry(name);
252 if (je != null) {
253 if (jf.isMultiRelease())
254 name = SharedSecrets.javaUtilJarAccess().getRealName(jf, je);
255 String encodedPath = ParseUtil.encodePath(name, false);
256 String uris = "jar:" + uri + "!/" + encodedPath;
257 return Optional.of(URI.create(uris));
258 } else {
259 return Optional.empty();
260 }
261 }
262
263 @Override
264 Optional<InputStream> implOpen(String name) throws IOException {
265 JarEntry je = getEntry(name);
266 if (je != null) {
353
354 /**
355 * A ModuleReader for an exploded module.
356 */
357 static class ExplodedModuleReader implements ModuleReader {
358 private final Path dir;
359 private volatile boolean closed;
360
361 ExplodedModuleReader(Path dir) {
362 this.dir = dir;
363
364 // when running with a security manager then check that the caller
365 // has access to the directory.
366 SecurityManager sm = System.getSecurityManager();
367 if (sm != null) {
368 boolean unused = Files.isDirectory(dir);
369 }
370 }
371
372 /**
373 * Returns a Path to access to the given resource.
374 */
375 private Path toPath(String name) {
376 Path path = Paths.get(name.replace('/', File.separatorChar));
377 if (path.getRoot() == null) {
378 return dir.resolve(path);
379 } else {
380 // drop the root component so that the resource is
381 // located relative to the module directory
382 int n = path.getNameCount();
383 return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
384 }
385 }
386
387 /**
388 * Throws IOException if the module reader is closed;
389 */
390 private void ensureOpen() throws IOException {
391 if (closed) throw new IOException("ModuleReader is closed");
392 }
393
394 @Override
395 public Optional<URI> find(String name) throws IOException {
396 ensureOpen();
397 Path path = toPath(name);
398 if (path != null && Files.isRegularFile(path)) {
399 try {
400 return Optional.of(path.toUri());
401 } catch (IOError e) {
402 throw (IOException) e.getCause();
403 }
404 } else {
405 return Optional.empty();
406 }
407 }
408
409 @Override
410 public Optional<InputStream> open(String name) throws IOException {
411 ensureOpen();
412 Path path = toPath(name);
413 if (path != null && Files.isRegularFile(path)) {
414 return Optional.of(Files.newInputStream(path));
415 } else {
416 return Optional.empty();
417 }
418 }
419
420 @Override
421 public Optional<ByteBuffer> read(String name) throws IOException {
422 ensureOpen();
423 Path path = toPath(name);
424 if (path != null && Files.isRegularFile(path)) {
425 return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
426 } else {
427 return Optional.empty();
428 }
429 }
430
431 @Override
432 public Stream<String> list() throws IOException {
433 ensureOpen();
434 // sym links not followed
435 return Files.find(dir, Integer.MAX_VALUE,
436 (path, attrs) -> attrs.isRegularFile())
437 .map(f -> dir.relativize(f)
438 .toString()
439 .replace(File.separatorChar, '/'));
440 }
441
442 @Override
443 public void close() {
444 closed = true;
|
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.nio.file.Paths;
40 import java.util.List;
41 import java.util.Objects;
42 import java.util.Optional;
43 import java.util.concurrent.locks.Lock;
44 import java.util.concurrent.locks.ReadWriteLock;
45 import java.util.concurrent.locks.ReentrantReadWriteLock;
46 import java.util.function.Supplier;
47 import java.util.jar.JarEntry;
48 import java.util.jar.JarFile;
49 import java.util.stream.Collectors;
50 import java.util.stream.Stream;
51 import java.util.zip.ZipFile;
52
53 import jdk.internal.jmod.JmodFile;
54 import jdk.internal.loader.ResourceHelper;
55 import jdk.internal.misc.JavaLangAccess;
56 import jdk.internal.misc.SharedSecrets;
57 import jdk.internal.module.ModuleHashes.HashSupplier;
58 import jdk.internal.util.jar.VersionedStream;
59 import sun.net.www.ParseUtil;
60
61
62 /**
63 * A factory for creating ModuleReference implementations where the modules are
64 * packaged as modular JAR file, JMOD files or where the modules are exploded
65 * on the file system.
66 */
67
68 class ModuleReferences {
69
70 private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
71
72 private ModuleReferences() { }
73
74 /**
227 private final JarFile jf;
228 private final URI uri;
229
230 static JarFile newJarFile(Path path) {
231 try {
232 return new JarFile(path.toFile(),
233 true, // verify
234 ZipFile.OPEN_READ,
235 JarFile.runtimeVersion());
236 } catch (IOException ioe) {
237 throw new UncheckedIOException(ioe);
238 }
239 }
240
241 JarModuleReader(Path path, URI uri) {
242 this.jf = newJarFile(path);
243 this.uri = uri;
244 }
245
246 private JarEntry getEntry(String name) {
247 JarEntry entry = jf.getJarEntry(Objects.requireNonNull(name));
248 return (entry == null || entry.isDirectory()) ? null : entry;
249 }
250
251 @Override
252 Optional<URI> implFind(String name) throws IOException {
253 JarEntry je = getEntry(name);
254 if (je != null) {
255 if (jf.isMultiRelease())
256 name = SharedSecrets.javaUtilJarAccess().getRealName(jf, je);
257 String encodedPath = ParseUtil.encodePath(name, false);
258 String uris = "jar:" + uri + "!/" + encodedPath;
259 return Optional.of(URI.create(uris));
260 } else {
261 return Optional.empty();
262 }
263 }
264
265 @Override
266 Optional<InputStream> implOpen(String name) throws IOException {
267 JarEntry je = getEntry(name);
268 if (je != null) {
355
356 /**
357 * A ModuleReader for an exploded module.
358 */
359 static class ExplodedModuleReader implements ModuleReader {
360 private final Path dir;
361 private volatile boolean closed;
362
363 ExplodedModuleReader(Path dir) {
364 this.dir = dir;
365
366 // when running with a security manager then check that the caller
367 // has access to the directory.
368 SecurityManager sm = System.getSecurityManager();
369 if (sm != null) {
370 boolean unused = Files.isDirectory(dir);
371 }
372 }
373
374 /**
375 * Throws IOException if the module reader is closed;
376 */
377 private void ensureOpen() throws IOException {
378 if (closed) throw new IOException("ModuleReader is closed");
379 }
380
381 /**
382 * Returns a Path to access the given resource. Returns null if the
383 * resource name does not convert to a file path that locates a regular
384 * file in the module.
385 */
386 private Path toFilePath(String name) {
387 Path path = ResourceHelper.toFilePath(name);
388 if (path != null) {
389 Path file = dir.resolve(path);
390 if (Files.isRegularFile(file)) {
391 return file;
392 }
393 }
394 return null;
395 }
396
397 @Override
398 public Optional<URI> find(String name) throws IOException {
399 ensureOpen();
400 Path path = toFilePath(name);
401 if (path != null) {
402 try {
403 return Optional.of(path.toUri());
404 } catch (IOError e) {
405 throw (IOException) e.getCause();
406 }
407 } else {
408 return Optional.empty();
409 }
410 }
411
412 @Override
413 public Optional<InputStream> open(String name) throws IOException {
414 ensureOpen();
415 Path path = toFilePath(name);
416 if (path != null) {
417 return Optional.of(Files.newInputStream(path));
418 } else {
419 return Optional.empty();
420 }
421 }
422
423 @Override
424 public Optional<ByteBuffer> read(String name) throws IOException {
425 ensureOpen();
426 Path path = toFilePath(name);
427 if (path != null) {
428 return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
429 } else {
430 return Optional.empty();
431 }
432 }
433
434 @Override
435 public Stream<String> list() throws IOException {
436 ensureOpen();
437 // sym links not followed
438 return Files.find(dir, Integer.MAX_VALUE,
439 (path, attrs) -> attrs.isRegularFile())
440 .map(f -> dir.relativize(f)
441 .toString()
442 .replace(File.separatorChar, '/'));
443 }
444
445 @Override
446 public void close() {
447 closed = true;
|