1 /*
2 * Copyright (c) 2014, 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
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.security.AccessController;
34 import java.security.Permission;
35 import java.security.PrivilegedAction;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Objects;
42 import java.util.Optional;
43 import java.util.Set;
44
45 import jdk.internal.module.ModulePath;
46 import jdk.internal.module.SystemModuleFinder;
47 import sun.security.action.GetPropertyAction;
48
49 /**
50 * A finder of modules. A {@code ModuleFinder} is used to find modules during
51 * <a href="Configuration.html#resolution">resolution</a> or
52 * <a href="Configuration.html#servicebinding">service binding</a>.
53 *
54 * <p> A {@code ModuleFinder} can only find one module with a given name. A
55 * {@code ModuleFinder} that finds modules in a sequence of directories, for
56 * example, will locate the first occurrence of a module of a given name and
57 * will ignore other modules of that name that appear in directories later in
58 * the sequence. </p>
59 *
60 * <p> Example usage: </p>
61 *
62 * <pre>{@code
63 * Path dir1, dir2, dir3;
64 *
65 * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
66 *
67 * Optional<ModuleReference> omref = finder.find("jdk.foo");
68 * omref.ifPresent(mref -> ... );
69 *
70 * }</pre>
71 *
72 * <p> The {@link #find(String) find} and {@link #findAll() findAll} methods
73 * defined here can fail for several reasons. These include I/O errors, errors
74 * detected parsing a module descriptor ({@code module-info.class}), or in the
75 * case of {@code ModuleFinder} returned by {@link #of ModuleFinder.of}, that
76 * two or more modules with the same name are found in a directory.
77 * When an error is detected then these methods throw {@link FindException
78 * FindException} with an appropriate {@link Throwable#getCause cause}.
79 * The behavior of a {@code ModuleFinder} after a {@code FindException} is
80 * thrown is undefined. For example, invoking {@code find} after an exception
81 * is thrown may or may not scan the same modules that lead to the exception.
82 * It is recommended that a module finder be discarded after an exception is
83 * thrown. </p>
84 *
85 * <p> A {@code ModuleFinder} is not required to be thread safe. </p>
86 *
87 * @since 9
88 */
89
90 public interface ModuleFinder {
91
92 /**
93 * Finds a reference to a module of a given name.
94 *
95 * <p> A {@code ModuleFinder} provides a consistent view of the
96 * modules that it locates. If {@code find} is invoked several times to
97 * locate the same module (by name) then it will return the same result
98 * each time. If a module is located then it is guaranteed to be a member
99 * of the set of modules returned by the {@link #findAll() findAll}
100 * method. </p>
101 *
102 * @param name
103 * The name of the module to find
104 *
105 * @return A reference to a module with the given name or an empty
106 * {@code Optional} if not found
107 *
108 * @throws FindException
109 * If an error occurs finding the module
110 *
111 * @throws SecurityException
112 * If denied by the security manager
113 */
114 Optional<ModuleReference> find(String name);
115
116 /**
117 * Returns the set of all module references that this finder can locate.
118 *
119 * <p> A {@code ModuleFinder} provides a consistent view of the modules
120 * that it locates. If {@link #findAll() findAll} is invoked several times
121 * then it will return the same (equals) result each time. For each {@code
122 * ModuleReference} element in the returned set then it is guaranteed that
123 * {@link #find find} will locate the {@code ModuleReference} if invoked
124 * to find that module. </p>
125 *
126 * @apiNote This is important to have for methods such as {@link
127 * Configuration#resolveRequiresAndUses resolveRequiresAndUses} that need
128 * to scan the module path to find modules that provide a specific service.
129 *
130 * @return The set of all module references that this finder locates
131 *
132 * @throws FindException
133 * If an error occurs finding all modules
134 *
135 * @throws SecurityException
136 * If denied by the security manager
137 */
138 Set<ModuleReference> findAll();
139
140 /**
141 * Returns a module finder that locates the <em>system modules</em>. The
142 * system modules are the modules in the Java run-time image.
143 * The module finder will always find {@code java.base}.
144 *
145 * <p> If there is a security manager set then its {@link
146 * SecurityManager#checkPermission(Permission) checkPermission} method is
147 * invoked to check that the caller has been granted {@link FilePermission}
148 * to recursively read the directory that is the value of the system
181
182 /**
183 * Returns a module finder that locates modules on the file system by
184 * searching a sequence of directories and/or packaged modules.
185 *
186 * Each element in the given array is one of:
187 * <ol>
188 * <li><p> A path to a directory of modules.</p></li>
189 * <li><p> A path to the <em>top-level</em> directory of an
190 * <em>exploded module</em>. </p></li>
191 * <li><p> A path to a <em>packaged module</em>. </p></li>
192 * </ol>
193 *
194 * The module finder locates modules by searching each directory, exploded
195 * module, or packaged module in array index order. It finds the first
196 * occurrence of a module with a given name and ignores other modules of
197 * that name that appear later in the sequence.
198 *
199 * <p> If an element is a path to a directory of modules then each entry in
200 * the directory is a packaged module or the top-level directory of an
201 * exploded module. The module finder's {@link #find(String) find} or
202 * {@link #findAll() findAll} methods throw {@link FindException} if a
203 * directory containing more than one module with the same name is
204 * encountered. </p>
205 *
206 * <p> If an element in the array is a path to a directory, and that
207 * directory contains a file named {@code module-info.class}, then the
208 * directory is treated as an exploded module rather than a directory of
209 * modules. </p>
210 *
211 * <p> The module finder returned by this method supports modules that are
212 * packaged as JAR files. A JAR file with a {@code module-info.class} in
213 * the top-level directory of the JAR file (or overridden by a versioned
214 * entry in a {@link java.util.jar.JarFile#isMultiRelease() multi-release}
215 * JAR file) is a modular JAR and is an <em>explicit module</em>.
216 * A JAR file that does not have a {@code module-info.class} in the
217 * top-level directory is an {@link ModuleDescriptor#isAutomatic automatic}
218 * module. The {@link ModuleDescriptor} for an automatic module is created as
219 * follows:
220 *
221 * <ul>
222 *
223 * <li><p> The module {@link ModuleDescriptor#name() name}, and {@link
224 * ModuleDescriptor#version() version} if applicable, is derived from
225 * the file name of the JAR file as follows: </p>
226 *
227 * <ul>
228 *
229 * <li><p> The {@code .jar} suffix is removed. </p></li>
230 *
231 * <li><p> If the name matches the regular expression {@code
232 * "-(\\d+(\\.|$))"} then the module name will be derived from the
233 * subsequence preceding the hyphen of the first occurrence. The
234 * subsequence after the hyphen is parsed as a {@link
235 * ModuleDescriptor.Version} and ignored if it cannot be parsed as
236 * a {@code Version}. </p></li>
237 *
238 * <li><p> For the module name, then any trailing digits and dots
239 * are removed, all non-alphanumeric characters ({@code [^A-Za-z0-9]})
240 * are replaced with a dot ({@code "."}), all repeating dots are
241 * replaced with one dot, and all leading and trailing dots are
242 * removed. </p></li>
243 *
244 * <li><p> As an example, a JAR file named {@code foo-bar.jar} will
245 * derive a module name {@code foo.bar} and no version. A JAR file
246 * named {@code foo-1.2.3-SNAPSHOT.jar} will derive a module name
247 * {@code foo} and {@code 1.2.3-SNAPSHOT} as the version. </p></li>
248 *
249 * </ul></li>
250 *
251 * <li><p> It {@link ModuleDescriptor#requires() requires} {@code
252 * java.base}. </p></li>
253 *
254 * <li><p> The set of packages in the module is derived from the names
255 * of non-directory entries in the JAR file. A candidate package name
256 * is derived from an entry using the characters up to, but not
257 * including, the last forward slash. All remaining forward slashes are
258 * replaced with dot ({@code "."}). If the resulting string is a valid
259 * Java identifier then it is assumed to be a package name. For example,
260 * if the JAR file contains an entry "{@code p/q/Foo.class}" then the
261 * package name derived is "{@code p.q}". All packages are {@link
262 * ModuleDescriptor#exports() exported}. </p></li>
263 *
264 * <li><p> The contents of entries starting with {@code
265 * META-INF/services/} are assumed to be service configuration files
266 * (see {@link java.util.ServiceLoader}). If the name of a file
267 * (that follows {@code META-INF/services/}) is a legal Java identifier
268 * then it is assumed to be the fully-qualified binary name of a
269 * service type. The entries in the file are assumed to be the
270 * fully-qualified binary names of provider classes. </p></li>
271 *
272 * <li><p> If the JAR file has a {@code Main-Class} attribute in its
273 * main manifest then its value is the {@link
274 * ModuleDescriptor#mainClass() main class}. </p></li>
275 *
276 * </ul>
277 *
278 * <p> If a {@code ModuleDescriptor} cannot be created (by means of the
279 * {@link ModuleDescriptor.Builder ModuleDescriptor.Builder} API) for an
280 * automatic module then {@code FindException} is thrown. This can arise,
281 * for example, when a legal Java identifier name cannot be derived from
282 * the file name of the JAR file or where the JAR file contains a {@code
283 * .class} in the top-level directory of the JAR file. </p>
284 *
285 * <p> In addition to JAR files, an implementation may also support modules
286 * that are packaged in other implementation specific module formats. When
287 * a file is encountered that is not recognized as a packaged module then
288 * {@code FindException} is thrown. An implementation may choose to ignore
289 * some files, {@link java.nio.file.Files#isHidden hidden} files for
290 * example. Paths to files that do not exist are always ignored. </p>
291 *
292 * <p> As with automatic modules, the contents of a packaged or exploded
293 * module may need to be <em>scanned</em> in order to determine the packages
294 * in the module. If a {@code .class} file (other than {@code
295 * module-info.class}) is found in the top-level directory then it is
296 * assumed to be a class in the unnamed package and so {@code FindException}
297 * is thrown. </p>
298 *
299 * <p> Finders created by this method are lazy and do not eagerly check
300 * that the given file paths are directories or packaged modules.
301 * Consequently, the {@code find} or {@code findAll} methods will only
302 * fail if invoking these methods results in searching a directory or
303 * packaged module and an error is encountered. </p>
304 *
305 * @param entries
306 * A possibly-empty array of paths to directories of modules
307 * or paths to packaged or exploded modules
308 *
309 * @return A {@code ModuleFinder} that locates modules on the file system
310 */
|
1 /*
2 * Copyright (c) 2014, 2017, 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
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.security.AccessController;
34 import java.security.Permission;
35 import java.security.PrivilegedAction;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Objects;
42 import java.util.Optional;
43 import java.util.Set;
44
45 import jdk.internal.module.ModulePath;
46 import jdk.internal.module.SystemModuleFinder;
47 import sun.security.action.GetPropertyAction;
48
49 /**
50 * A finder of modules. A {@code ModuleFinder} is used to find modules during
51 * <a href="package-summary.html#resolution">resolution</a> or
52 * <a href="package-summary.html#servicebinding">service binding</a>.
53 *
54 * <p> A {@code ModuleFinder} can only find one module with a given name. A
55 * {@code ModuleFinder} that finds modules in a sequence of directories, for
56 * example, will locate the first occurrence of a module of a given name and
57 * will ignore other modules of that name that appear in directories later in
58 * the sequence. </p>
59 *
60 * <p> Example usage: </p>
61 *
62 * <pre>{@code
63 * Path dir1, dir2, dir3;
64 *
65 * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
66 *
67 * Optional<ModuleReference> omref = finder.find("jdk.foo");
68 * omref.ifPresent(mref -> ... );
69 *
70 * }</pre>
71 *
72 * <p> The {@link #find(String) find} and {@link #findAll() findAll} methods
73 * defined here can fail for several reasons. These include I/O errors, errors
74 * detected parsing a module descriptor ({@code module-info.class}), or in the
75 * case of {@code ModuleFinder} returned by {@link #of ModuleFinder.of}, that
76 * two or more modules with the same name are found in a directory.
77 * When an error is detected then these methods throw {@link FindException
78 * FindException} with an appropriate {@link Throwable#getCause cause}.
79 * The behavior of a {@code ModuleFinder} after a {@code FindException} is
80 * thrown is undefined. For example, invoking {@code find} after an exception
81 * is thrown may or may not scan the same modules that lead to the exception.
82 * It is recommended that a module finder be discarded after an exception is
83 * thrown. </p>
84 *
85 * <p> A {@code ModuleFinder} is not required to be thread safe. </p>
86 *
87 * @since 9
88 * @spec JPMS
89 */
90
91 public interface ModuleFinder {
92
93 /**
94 * Finds a reference to a module of a given name.
95 *
96 * <p> A {@code ModuleFinder} provides a consistent view of the
97 * modules that it locates. If {@code find} is invoked several times to
98 * locate the same module (by name) then it will return the same result
99 * each time. If a module is located then it is guaranteed to be a member
100 * of the set of modules returned by the {@link #findAll() findAll}
101 * method. </p>
102 *
103 * @param name
104 * The name of the module to find
105 *
106 * @return A reference to a module with the given name or an empty
107 * {@code Optional} if not found
108 *
109 * @throws FindException
110 * If an error occurs finding the module
111 *
112 * @throws SecurityException
113 * If denied by the security manager
114 */
115 Optional<ModuleReference> find(String name);
116
117 /**
118 * Returns the set of all module references that this finder can locate.
119 *
120 * <p> A {@code ModuleFinder} provides a consistent view of the modules
121 * that it locates. If {@link #findAll() findAll} is invoked several times
122 * then it will return the same (equals) result each time. For each {@code
123 * ModuleReference} element in the returned set then it is guaranteed that
124 * {@link #find find} will locate the {@code ModuleReference} if invoked
125 * to find that module. </p>
126 *
127 * @apiNote This is important to have for methods such as {@link
128 * Configuration#resolveAndBind resolveAndBind} that need to scan the
129 * module path to find modules that provide a specific service.
130 *
131 * @return The set of all module references that this finder locates
132 *
133 * @throws FindException
134 * If an error occurs finding all modules
135 *
136 * @throws SecurityException
137 * If denied by the security manager
138 */
139 Set<ModuleReference> findAll();
140
141 /**
142 * Returns a module finder that locates the <em>system modules</em>. The
143 * system modules are the modules in the Java run-time image.
144 * The module finder will always find {@code java.base}.
145 *
146 * <p> If there is a security manager set then its {@link
147 * SecurityManager#checkPermission(Permission) checkPermission} method is
148 * invoked to check that the caller has been granted {@link FilePermission}
149 * to recursively read the directory that is the value of the system
182
183 /**
184 * Returns a module finder that locates modules on the file system by
185 * searching a sequence of directories and/or packaged modules.
186 *
187 * Each element in the given array is one of:
188 * <ol>
189 * <li><p> A path to a directory of modules.</p></li>
190 * <li><p> A path to the <em>top-level</em> directory of an
191 * <em>exploded module</em>. </p></li>
192 * <li><p> A path to a <em>packaged module</em>. </p></li>
193 * </ol>
194 *
195 * The module finder locates modules by searching each directory, exploded
196 * module, or packaged module in array index order. It finds the first
197 * occurrence of a module with a given name and ignores other modules of
198 * that name that appear later in the sequence.
199 *
200 * <p> If an element is a path to a directory of modules then each entry in
201 * the directory is a packaged module or the top-level directory of an
202 * exploded module. It it an error if a directory contains more than one
203 * module with the same name. If an element is a path to a directory, and
204 * that directory contains a file named {@code module-info.class}, then the
205 * directory is treated as an exploded module rather than a directory of
206 * modules. </p>
207 *
208 * <p> The module finder returned by this method supports modules that are
209 * packaged as JAR files. A JAR file with a {@code module-info.class} in
210 * the top-level directory of the JAR file (or overridden by a versioned
211 * entry in a {@link java.util.jar.JarFile#isMultiRelease() multi-release}
212 * JAR file) is a modular JAR and is an <em>explicit module</em>.
213 * A JAR file that does not have a {@code module-info.class} in the
214 * top-level directory is created as an automatic module. The components
215 * for the automatic module are derived as follows:
216 *
217 * <ul>
218 *
219 * <li><p> The module {@link ModuleDescriptor#name() name}, and {@link
220 * ModuleDescriptor#version() version} if applicable, is derived from
221 * the file name of the JAR file as follows: </p>
222 *
223 * <ul>
224 *
225 * <li><p> The {@code .jar} suffix is removed. </p></li>
226 *
227 * <li><p> If the name matches the regular expression {@code
228 * "-(\\d+(\\.|$))"} then the module name will be derived from the
229 * subsequence preceding the hyphen of the first occurrence. The
230 * subsequence after the hyphen is parsed as a {@link
231 * ModuleDescriptor.Version} and ignored if it cannot be parsed as
232 * a {@code Version}. </p></li>
233 *
234 * <li><p> For the module name, then any trailing digits and dots
235 * are removed, all non-alphanumeric characters ({@code [^A-Za-z0-9]})
236 * are replaced with a dot ({@code "."}), all repeating dots are
237 * replaced with one dot, and all leading and trailing dots are
238 * removed. </p></li>
239 *
240 * <li><p> As an example, a JAR file named {@code foo-bar.jar} will
241 * derive a module name {@code foo.bar} and no version. A JAR file
242 * named {@code foo-1.2.3-SNAPSHOT.jar} will derive a module name
243 * {@code foo} and {@code 1.2.3-SNAPSHOT} as the version. </p></li>
244 *
245 * </ul></li>
246 *
247 * <li><p> The set of packages in the module is derived from the
248 * non-directory entries in the JAR file that have names ending in
249 * "{@code .class}". A candidate package name is derived from the name
250 * using the characters up to, but not including, the last forward slash.
251 * All remaining forward slashes are replaced with dot ({@code "."}). If
252 * the resulting string is a legal package name then it is assumed to be
253 * a package name. For example, if the JAR file contains the entry
254 * "{@code p/q/Foo.class}" then the package name derived is
255 * "{@code p.q}".</p></li>
256 *
257 * <li><p> The contents of entries starting with {@code
258 * META-INF/services/} are assumed to be service configuration files
259 * (see {@link java.util.ServiceLoader}). If the name of a file
260 * (that follows {@code META-INF/services/}) is a legal class name
261 * then it is assumed to be the fully-qualified class name of a service
262 * type. The entries in the file are assumed to be the fully-qualified
263 * class names of provider classes. </p></li>
264 *
265 * <li><p> If the JAR file has a {@code Main-Class} attribute in its
266 * main manifest then its value is the module {@link
267 * ModuleDescriptor#mainClass() main class}. </p></li>
268 *
269 * </ul>
270 *
271 * <p> If a {@code ModuleDescriptor} cannot be created (by means of the
272 * {@link ModuleDescriptor.Builder ModuleDescriptor.Builder} API) for an
273 * automatic module then {@code FindException} is thrown. This can arise
274 * when a legal module name cannot be derived from the file name of the JAR
275 * file, where the JAR file contains a {@code .class} in the top-level
276 * directory of the JAR file, where an entry in a service configuration
277 * file is not a legal class name or its package name is not in the set of
278 * packages derived for the module, or where the module main class is not
279 * a legal class name or its package is not in the module. </p>
280 *
281 * <p> In addition to JAR files, an implementation may also support modules
282 * that are packaged in other implementation specific module formats. If
283 * an element in the array specified to this method is a path to a directory
284 * of modules then entries in the directory that not recognized as modules
285 * are ignored. If an element in the array is a path to a packaged module
286 * that is not recognized then a {@code FindException} is thrown when the
287 * file is encountered. Paths to files that do not exist are always ignored.
288 * </p>
289 *
290 * <p> As with automatic modules, the contents of a packaged or exploded
291 * module may need to be <em>scanned</em> in order to determine the packages
292 * in the module. If a {@code .class} file (other than {@code
293 * module-info.class}) is found in the top-level directory then it is
294 * assumed to be a class in the unnamed package and so {@code FindException}
295 * is thrown. </p>
296 *
297 * <p> Finders created by this method are lazy and do not eagerly check
298 * that the given file paths are directories or packaged modules.
299 * Consequently, the {@code find} or {@code findAll} methods will only
300 * fail if invoking these methods results in searching a directory or
301 * packaged module and an error is encountered. </p>
302 *
303 * @param entries
304 * A possibly-empty array of paths to directories of modules
305 * or paths to packaged or exploded modules
306 *
307 * @return A {@code ModuleFinder} that locates modules on the file system
308 */
|