| /* | |
| * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package java.lang.module; | |
| import java.io.Closeable; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.net.URI; | |
| import java.nio.ByteBuffer; | |
| import java.util.Objects; | |
| import java.util.Optional; | |
| import java.util.stream.Stream; | |
| /** | |
| * Provides access to the content of a module. | |
| * | |
| * <p> A module reader is intended for cases where access to the resources in a | |
| * module is required, regardless of whether the module has been loaded. | |
| * A framework that scans a collection of packaged modules on the file system, | |
| * for example, may use a module reader to access a specific resource in each | |
| * module. A module reader is also intended to be used by {@code ClassLoader} | |
| * implementations that load classes and resources from modules. </p> | |
| * | |
| * <p> A resource in a module is identified by an abstract name that is a | |
| * '{@code /}'-separated path string. For example, module {@code java.base} may | |
| * have a resource "{@code java/lang/Object.class}" that, by convention, is the | |
| * class file for {@code java.lang.Object}. A module reader may treat | |
| * directories in the module content as resources (whether it does or not is | |
| * module reader specific). Where the module content contains a directory | |
| * that can be located as a resource then its name ends with a slash ('/'). The | |
| * directory can also be located with a name that drops the trailing slash. </p> | |
| * | |
| * <p> A {@code ModuleReader} is {@linkplain ModuleReference#open open} upon | |
| * creation and is closed by invoking the {@link #close close} method. Failure | |
| * to close a module reader may result in a resource leak. The {@code | |
| * try-with-resources} statement provides a useful construct to ensure that | |
| * module readers are closed. </p> | |
| * | |
| * @implSpec Implementations of {@code ModuleReader} should take great care | |
| * when translating an abstract resource name to the location of a resource in | |
| * a packaged module or on the file system. Implementations are advised to | |
| * treat resource names with elements such as '{@code .}, '{@code ..}', | |
| * elements containing file separators, or empty elements as "not found". More | |
| * generally, if the resource name is not in the stream of elements that the | |
| * {@code list} method returns then the resource should be treated as "not | |
| * found" to avoid inconsistencies. | |
| * | |
| * @see ModuleReference | |
| * @since 9 | |
| */ | |
| public interface ModuleReader extends Closeable { | |
| /** | |
| * Finds a resource, returning a URI to the resource in the module. | |
| * | |
| * <p> If the module reader can determine that the name locates a directory | |
| * then the resulting URI will end with a slash ('/'). </p> | |
| * | |
| * @param name | |
| * The name of the resource to open for reading | |
| * | |
| * @return A URI to the resource; an empty {@code Optional} if the resource | |
| * is not found or a URI cannot be constructed to locate the | |
| * resource | |
| * | |
| * @throws IOException | |
| * If an I/O error occurs or the module reader is closed | |
| * | |
| * @see ClassLoader#getResource(String) | |
| */ | |
| Optional<URI> find(String name) throws IOException; | |
| /** | |
| * Opens a resource, returning an input stream to read the resource in | |
| * the module. | |
| * | |
| * <p> The behavior of the input stream when used after the module reader | |
| * is closed is implementation specific and therefore not specified. </p> | |
| * | |
| * @implSpec The default implementation invokes the {@link #find(String) | |
| * find} method to get a URI to the resource. If found, then it attempts | |
| * to construct a {@link java.net.URL URL} and open a connection to the | |
| * resource. | |
| * | |
| * @param name | |
| * The name of the resource to open for reading | |
| * | |
| * @return An input stream to read the resource or an empty | |
| * {@code Optional} if not found | |
| * | |
| * @throws IOException | |
| * If an I/O error occurs or the module reader is closed | |
| */ | |
| default Optional<InputStream> open(String name) throws IOException { | |
| Optional<URI> ouri = find(name); | |
| if (ouri.isPresent()) { | |
| return Optional.of(ouri.get().toURL().openStream()); | |
| } else { | |
| return Optional.empty(); | |
| } | |
| } | |
| /** | |
| * Reads a resource, returning a byte buffer with the contents of the | |
| * resource. | |
| * | |
| * The element at the returned buffer's position is the first byte of the | |
| * resource, the element at the buffer's limit is the last byte of the | |
| * resource. Once consumed, the {@link #release(ByteBuffer) release} method | |
| * must be invoked. Failure to invoke the {@code release} method may result | |
| * in a resource leak. | |
| * | |
| * @apiNote This method is intended for high-performance class loading. It | |
| * is not capable (or intended) to read arbitrary large resources that | |
| * could potentially be 2GB or larger. The rationale for using this method | |
| * in conjunction with the {@code release} method is to allow module reader | |
| * implementations manage buffers in an efficient manner. | |
| * | |
| * @implSpec The default implementation invokes the {@link #open(String) | |
| * open} method and reads all bytes from the input stream into a byte | |
| * buffer. | |
| * | |
| * @param name | |
| * The name of the resource to read | |
| * | |
| * @return A byte buffer containing the contents of the resource or an | |
| * empty {@code Optional} if not found | |
| * | |
| * @throws IOException | |
| * If an I/O error occurs or the module reader is closed | |
| * @throws OutOfMemoryError | |
| * If the resource is larger than {@code Integer.MAX_VALUE}, | |
| * the maximum capacity of a byte buffer | |
| * | |
| * @see ClassLoader#defineClass(String, ByteBuffer, java.security.ProtectionDomain) | |
| */ | |
| default Optional<ByteBuffer> read(String name) throws IOException { | |
| Optional<InputStream> oin = open(name); | |
| if (oin.isPresent()) { | |
| try (InputStream in = oin.get()) { | |
| return Optional.of(ByteBuffer.wrap(in.readAllBytes())); | |
| } | |
| } else { | |
| return Optional.empty(); | |
| } | |
| } | |
| /** | |
| * Releases a byte buffer. This method should be invoked after consuming | |
| * the contents of the buffer returned by the {@code read} method. | |
| * The behavior of this method when invoked to release a buffer that has | |
| * already been released, or the behavior when invoked to release a buffer | |
| * after a {@code ModuleReader} is closed is implementation specific and | |
| * therefore not specified. | |
| * | |
| * @param bb | |
| * The byte buffer to release | |
| * | |
| * @implSpec The default implementation doesn't do anything except check | |
| * if the byte buffer is null. | |
| */ | |
| default void release(ByteBuffer bb) { | |
| Objects.requireNonNull(bb); | |
| } | |
| /** | |
| * Lists the contents of the module, returning a stream of elements that | |
| * are the names of all resources in the module. Whether the stream of | |
| * elements includes names corresponding to directories in the module is | |
| * module reader specific. | |
| * | |
| * <p> In lazy implementations then an {@code IOException} may be thrown | |
| * when using the stream to list the module contents. If this occurs then | |
| * the {@code IOException} will be wrapped in an {@link | |
| * java.io.UncheckedIOException} and thrown from the method that caused the | |
| * access to be attempted. | |
| * | |
| * <p> The returned stream may contain references to one or more open directories | |
| * in the module. The directories are closed by closing the stream. </p> | |
| * | |
| * <p> The behavior of the stream when used after the module reader is | |
| * closed is implementation specific and therefore not specified. </p> | |
| * | |
| * @apiNote | |
| * This method should be used within a try-with-resources statement or similar | |
| * control structure to ensure that any open directories referenced by the | |
| * stream are closed promptly after the stream's operations have completed. | |
| * | |
| * @return A stream of elements that are the names of all resources | |
| * in the module | |
| * | |
| * @throws IOException | |
| * If an I/O error occurs or the module reader is closed | |
| */ | |
| Stream<String> list() throws IOException; | |
| /** | |
| * Closes the module reader. Once closed then subsequent calls to locate or | |
| * read a resource will fail by throwing {@code IOException}. | |
| * | |
| * <p> A module reader is not required to be asynchronously closeable. If a | |
| * thread is reading a resource and another thread invokes the close method, | |
| * then the second thread may block until the read operation is complete. </p> | |
| */ | |
| @Override | |
| void close() throws IOException; | |
| } |