ModuleReader.java revision 16909:085c764a3e5b
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
26package java.lang.module;
27
28import java.io.Closeable;
29import java.io.IOException;
30import java.io.InputStream;
31import java.net.URI;
32import java.nio.ByteBuffer;
33import java.util.Objects;
34import java.util.Optional;
35import 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
82public 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}
242