1 /*
   2  * Copyright (c) 2015, 2016, 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 java.lang.module;
  27 
  28 import java.io.Closeable;
  29 import java.io.IOException;
  30 import java.io.InputStream;
  31 import java.net.URI;
  32 import java.nio.ByteBuffer;
  33 import java.util.Objects;
  34 import java.util.Optional;
  35 import java.util.stream.Stream;
  36 
  37 
  38 /**
  39  * Provides access to the content of a module.
  40  *
  41  * <p> A module reader is intended for cases where access to the resources in a
  42  * module is required, regardless of whether the module has been loaded.
  43  * A framework that scans a collection of packaged modules on the file system,
  44  * for example, may use a module reader to access a specific resource in each
  45  * module. A module reader is also intended to be used by {@code ClassLoader}
  46  * implementations that load classes and resources from modules. </p>
  47  *
  48  * <p> A resource in a module is identified by a name that is a
  49  * '{@code /}'-separated path string. For example, module {@code java.base} may
  50  * have a resource "{@code java/lang/Object.class}" that, by convention, is the
  51  * class file for {@code java.lang.Object}. </p>
  52  *
  53  * <p> A {@code ModuleReader} is {@linkplain ModuleReference#open open} upon
  54  * creation and is closed by invoking the {@link #close close} method.  Failure
  55  * to close a module reader may result in a resource leak.  The {@code
  56  * try-with-resources} statement provides a useful construct to ensure that
  57  * module readers are closed. </p>
  58  *
  59  * <p> A {@code ModuleReader} implementation may require permissions to access
  60  * resources in the module. Consequently the {@link #find find}, {@link #open
  61  * open}, {@link #read read}, and {@link #list list} methods may throw {@code
  62  * SecurityException} if access is denied by the security manager. </p>
  63  *
  64  * @see ModuleReference
  65  * @since 9
  66  */
  67 
  68 public interface ModuleReader extends Closeable {
  69 
  70     /**
  71      * Finds a resource, returning a URI to the resource in the module.
  72      *
  73      * @param  name
  74      *         The name of the resource to open for reading
  75      *
  76      * @return A URI to the resource; an empty {@code Optional} if the resource
  77      *         is not found or a URI cannot be constructed to locate the
  78      *         resource
  79      *
  80      * @throws IOException
  81      *         If an I/O error occurs or the module reader is closed
  82      * @throws SecurityException
  83      *         If denied by the security manager
  84      *
  85      * @see ClassLoader#getResource(String)
  86      */
  87     Optional<URI> find(String name) throws IOException;
  88 
  89     /**
  90      * Opens a resource, returning an input stream to read the resource in
  91      * the module.
  92      *
  93      * <p> The behavior of the input stream when used after the module reader
  94      * is closed is implementation specific and therefore not specified. </p>
  95      *
  96      * @implSpec The default implementation invokes the {@link #find(String)
  97      * find} method to get a URI to the resource. If found, then it attempts
  98      * to construct a {@link java.net.URL URL} and open a connection to the
  99      * resource.
 100      *
 101      * @param  name
 102      *         The name of the resource to open for reading
 103      *
 104      * @return An input stream to read the resource or an empty
 105      *         {@code Optional} if not found
 106      *
 107      * @throws IOException
 108      *         If an I/O error occurs or the module reader is closed
 109      * @throws SecurityException
 110      *         If denied by the security manager
 111      */
 112     default Optional<InputStream> open(String name) throws IOException {
 113         Optional<URI> ouri = find(name);
 114         if (ouri.isPresent()) {
 115             return Optional.of(ouri.get().toURL().openStream());
 116         } else {
 117             return Optional.empty();
 118         }
 119     }
 120 
 121     /**
 122      * Reads a resource, returning a byte buffer with the contents of the
 123      * resource.
 124      *
 125      * The element at the returned buffer's position is the first byte of the
 126      * resource, the element at the buffer's limit is the last byte of the
 127      * resource. Once consumed, the {@link #release(ByteBuffer) release} method
 128      * must be invoked. Failure to invoke the {@code release} method may result
 129      * in a resource leak.
 130      *
 131      * @apiNote This method is intended for high-performance class loading. It
 132      * is not capable (or intended) to read arbitrary large resources that
 133      * could potentially be 2GB or larger. The rational for using this method
 134      * in conjunction with the {@code release} method is to allow module reader
 135      * implementations manage buffers in an efficient manner.
 136      *
 137      * @implSpec The default implementation invokes the {@link #open(String)
 138      * open} method and reads all bytes from the input stream into a byte
 139      * buffer.
 140      *
 141      * @param  name
 142      *         The name of the resource to read
 143      *
 144      * @return A byte buffer containing the contents of the resource or an
 145      *         empty {@code Optional} if not found
 146      *
 147      * @throws IOException
 148      *         If an I/O error occurs or the module reader is closed
 149      * @throws SecurityException
 150      *         If denied by the security manager
 151      *
 152      * @see ClassLoader#defineClass(String, ByteBuffer, java.security.ProtectionDomain)
 153      */
 154     default Optional<ByteBuffer> read(String name) throws IOException {
 155         Optional<InputStream> oin = open(name);
 156         if (oin.isPresent()) {
 157             try (InputStream in = oin.get()) {
 158                 return Optional.of(ByteBuffer.wrap(in.readAllBytes()));
 159             }
 160         } else {
 161             return Optional.empty();
 162         }
 163     }
 164 
 165     /**
 166      * Release a byte buffer. This method should be invoked after consuming
 167      * the contents of the buffer returned by the {@code read} method.
 168      * The behavior of this method when invoked to release a buffer that has
 169      * already been released, or the behavior when invoked to release a buffer
 170      * after a {@code ModuleReader} is closed is implementation specific and
 171      * therefore not specified.
 172      *
 173      * @param  bb
 174      *         The byte buffer to release
 175      *
 176      * @implSpec The default implementation doesn't do anything except check
 177      * if the byte buffer is null.
 178      */
 179     default void release(ByteBuffer bb) {
 180         Objects.requireNonNull(bb);
 181     }
 182 
 183     /**
 184      * Lists the contents of the module, returning a stream of elements that
 185      * are the names of all resources in the module.
 186      *
 187      * <p> In lazy implementations then an {@code IOException} may be thrown
 188      * when using the stream to list the module contents. If this occurs then
 189      * the {@code IOException} will be wrapped in an {@link
 190      * java.io.UncheckedIOException} and thrown from the method that caused the
 191      * access to be attempted. {@code SecurityException} may also be thrown
 192      * when using the stream to list the module contents and access is denied
 193      * by the security manager. </p>
 194      *
 195      * <p> The behavior of the stream when used after the module reader is
 196      * closed is implementation specific and therefore not specified. </p>
 197      *
 198      * @return A stream of elements that are the names of all resources
 199      *         in the module
 200      *
 201      * @throws IOException
 202      *         If an I/O error occurs or the module reader is closed
 203      * @throws SecurityException
 204      *         If denied by the security manager
 205      */
 206     Stream<String> list() throws IOException;
 207 
 208     /**
 209      * Closes the module reader. Once closed then subsequent calls to locate or
 210      * read a resource will fail by throwing {@code IOException}.
 211      *
 212      * <p> A module reader is not required to be asynchronously closeable. If a
 213      * thread is reading a resource and another thread invokes the close method,
 214      * then the second thread may block until the read operation is complete. </p>
 215      */
 216     @Override
 217     void close() throws IOException;
 218 
 219 }