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 an abstract 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}. A module reader may treat 52 * directories in the module content as resources (whether it does or not is 53 * module reader specific). Where the module content contains a directory 54 * that can be located as a resource then its name ends with a slash ('/'). The 55 * directory can also be located with a name that drops the trailing slash. </p> 56 * 57 * <p> A {@code ModuleReader} is {@linkplain ModuleReference#open open} upon 58 * creation and is closed by invoking the {@link #close close} method. Failure 59 * to close a module reader may result in a resource leak. The {@code 60 * try-with-resources} statement provides a useful construct to ensure that 61 * module readers are closed. </p> 62 * 63 * <p> A {@code ModuleReader} implementation may require permissions to access 64 * resources in the module. Consequently the {@link #find find}, {@link #open 65 * open}, {@link #read read}, and {@link #list list} methods may throw {@code 66 * SecurityException} if access is denied by the security manager. </p> 67 * 68 * @implSpec Implementations of {@code ModuleReader} should take great care 69 * when translating an abstract resource name to the location of a resource in 70 * a packaged module or on the file system. Implementations are advised to 71 * treat resource names with elements such as '{@code .}, '{@code ..}', 72 * elements containing file separators, or empty elements as "not found". More 73 * generally, if the resource name is not in the stream of elements that the 74 * {@code list} method returns then the resource should be treated as "not 75 * found" to avoid inconsistencies. 76 * 77 * @see ModuleReference 78 * @since 9 79 * @spec JPMS 80 */ 81 82 public interface ModuleReader extends Closeable { 83 84 /** 85 * Finds a resource, returning a URI to the resource in the module. 86 * 87 * <p> If the module reader can determine that the name locates a directory 88 * then the resulting URI will end with a slash ('/'). </p> 89 * 90 * @param name 91 * The name of the resource to open for reading 92 * 93 * @return A URI to the resource; an empty {@code Optional} if the resource 94 * is not found or a URI cannot be constructed to locate the 95 * resource 96 * 97 * @throws IOException 98 * If an I/O error occurs or the module reader is closed 99 * @throws SecurityException 100 * If denied by the security manager 101 * 102 * @see ClassLoader#getResource(String) 103 */ 104 Optional<URI> find(String name) throws IOException; 105 106 /** 107 * Opens a resource, returning an input stream to read the resource in 108 * the module. 109 * 110 * <p> The behavior of the input stream when used after the module reader 111 * is closed is implementation specific and therefore not specified. </p> 112 * 113 * @implSpec The default implementation invokes the {@link #find(String) 114 * find} method to get a URI to the resource. If found, then it attempts 115 * to construct a {@link java.net.URL URL} and open a connection to the 116 * resource. 117 * 118 * @param name 119 * The name of the resource to open for reading 120 * 121 * @return An input stream to read the resource or an empty 122 * {@code Optional} if not found 123 * 124 * @throws IOException 125 * If an I/O error occurs or the module reader is closed 126 * @throws SecurityException 127 * If denied by the security manager 128 */ 129 default Optional<InputStream> open(String name) throws IOException { 130 Optional<URI> ouri = find(name); 131 if (ouri.isPresent()) { 132 return Optional.of(ouri.get().toURL().openStream()); 133 } else { 134 return Optional.empty(); 135 } 136 } 137 138 /** 139 * Reads a resource, returning a byte buffer with the contents of the 140 * resource. 141 * 142 * The element at the returned buffer's position is the first byte of the 143 * resource, the element at the buffer's limit is the last byte of the 144 * resource. Once consumed, the {@link #release(ByteBuffer) release} method 145 * must be invoked. Failure to invoke the {@code release} method may result 146 * in a resource leak. 147 * 148 * @apiNote This method is intended for high-performance class loading. It 149 * is not capable (or intended) to read arbitrary large resources that 150 * could potentially be 2GB or larger. The rationale for using this method 151 * in conjunction with the {@code release} method is to allow module reader 152 * implementations manage buffers in an efficient manner. 153 * 154 * @implSpec The default implementation invokes the {@link #open(String) 155 * open} method and reads all bytes from the input stream into a byte 156 * buffer. 157 * 158 * @param name 159 * The name of the resource to read 160 * 161 * @return A byte buffer containing the contents of the resource or an 162 * empty {@code Optional} if not found 163 * 164 * @throws IOException 165 * If an I/O error occurs or the module reader is closed 166 * @throws SecurityException 167 * If denied by the security manager 168 * @throws OutOfMemoryError 169 * If the resource is larger than {@code Integer.MAX_VALUE}, 170 * the maximum capacity of a byte buffer 171 * 172 * @see ClassLoader#defineClass(String, ByteBuffer, java.security.ProtectionDomain) 173 */ 174 default Optional<ByteBuffer> read(String name) throws IOException { 175 Optional<InputStream> oin = open(name); 176 if (oin.isPresent()) { 177 try (InputStream in = oin.get()) { 178 return Optional.of(ByteBuffer.wrap(in.readAllBytes())); 179 } 180 } else { 181 return Optional.empty(); 182 } 183 } 184 185 /** 186 * Release a byte buffer. This method should be invoked after consuming 187 * the contents of the buffer returned by the {@code read} method. 188 * The behavior of this method when invoked to release a buffer that has 189 * already been released, or the behavior when invoked to release a buffer 190 * after a {@code ModuleReader} is closed is implementation specific and 191 * therefore not specified. 192 * 193 * @param bb 194 * The byte buffer to release 195 * 196 * @implSpec The default implementation doesn't do anything except check 197 * if the byte buffer is null. 198 */ 199 default void release(ByteBuffer bb) { 200 Objects.requireNonNull(bb); 201 } 202 203 /** 204 * Lists the contents of the module, returning a stream of elements that 205 * are the names of all resources in the module. Whether the stream of 206 * elements includes names corresponding to directories in the module is 207 * module reader specific. 208 * 209 * <p> In lazy implementations then an {@code IOException} may be thrown 210 * when using the stream to list the module contents. If this occurs then 211 * the {@code IOException} will be wrapped in an {@link 212 * java.io.UncheckedIOException} and thrown from the method that caused the 213 * access to be attempted. {@code SecurityException} may also be thrown 214 * when using the stream to list the module contents and access is denied 215 * by the security manager. </p> 216 * 217 * <p> The behavior of the stream when used after the module reader is 218 * closed is implementation specific and therefore not specified. </p> 219 * 220 * @return A stream of elements that are the names of all resources 221 * in the module 222 * 223 * @throws IOException 224 * If an I/O error occurs or the module reader is closed 225 * @throws SecurityException 226 * If denied by the security manager 227 */ 228 Stream<String> list() throws IOException; 229 230 /** 231 * Closes the module reader. Once closed then subsequent calls to locate or 232 * read a resource will fail by throwing {@code IOException}. 233 * 234 * <p> A module reader is not required to be asynchronously closeable. If a 235 * thread is reading a resource and another thread invokes the close method, 236 * then the second thread may block until the read operation is complete. </p> 237 */ 238 @Override 239 void close() throws IOException; 240 241 }