| /* |
| * Copyright (c) 2015, 2016, 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> |
| * |
| * <p> A {@code ModuleReader} implementation may require permissions to access |
| * resources in the module. Consequently the {@link #find find}, {@link #open |
| * open}, {@link #read read}, and {@link #list list} methods may throw {@code |
| * SecurityException} if access is denied by the security manager. </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 |
| * @spec JPMS |
| */ |
| |
| 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 |
| * @throws SecurityException |
| * If denied by the security manager |
| * |
| * @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 |
| * @throws SecurityException |
| * If denied by the security manager |
| */ |
| 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 SecurityException |
| * If denied by the security manager |
| * @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(); |
| } |
| } |
| |
| /** |
| * Release 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. {@code SecurityException} may also be thrown |
| * when using the stream to list the module contents and access is denied |
| * by the security manager. </p> |
| * |
| * <p> The behavior of the stream when used after the module reader is |
| * closed is implementation specific and therefore not specified. </p> |
| * |
| * @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 |
| * @throws SecurityException |
| * If denied by the security manager |
| */ |
| 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; |
| |
| } |