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.File;
29 import java.io.FilePermission;
30 import java.nio.file.Files;
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.ModuleBootstrap;
46 import jdk.internal.module.ModulePath;
47 import jdk.internal.module.SystemModuleFinder;
48 import sun.security.action.GetPropertyAction;
49
50 /**
51 * A finder of modules. A {@code ModuleFinder} is used to find modules during
52 * <a href="package-summary.html#resolution">resolution</a> or
53 * <a href="package-summary.html#servicebinding">service binding</a>.
54 *
55 * <p> A {@code ModuleFinder} can only find one module with a given name. A
56 * {@code ModuleFinder} that finds modules in a sequence of directories, for
57 * example, will locate the first occurrence of a module of a given name and
58 * will ignore other modules of that name that appear in directories later in
59 * the sequence. </p>
60 *
61 * <p> Example usage: </p>
62 *
63 * <pre>{@code
64 * Path dir1, dir2, dir3;
65 *
66 * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
67 *
68 * Optional<ModuleReference> omref = finder.find("jdk.foo");
129 * Configuration#resolveAndBind resolveAndBind} that need to scan the
130 * module path to find modules that provide a specific service.
131 *
132 * @return The set of all module references that this finder locates
133 *
134 * @throws FindException
135 * If an error occurs finding all modules
136 *
137 * @throws SecurityException
138 * If denied by the security manager
139 */
140 Set<ModuleReference> findAll();
141
142 /**
143 * Returns a module finder that locates the <em>system modules</em>. The
144 * system modules are the modules in the Java run-time image.
145 * The module finder will always find {@code java.base}.
146 *
147 * <p> If there is a security manager set then its {@link
148 * SecurityManager#checkPermission(Permission) checkPermission} method is
149 * invoked to check that the caller has been granted {@link FilePermission}
150 * to recursively read the directory that is the value of the system
151 * property {@code java.home}. </p>
152 *
153 * @return A {@code ModuleFinder} that locates the system modules
154 *
155 * @throws SecurityException
156 * If denied by the security manager
157 */
158 static ModuleFinder ofSystem() {
159 String home;
160
161 SecurityManager sm = System.getSecurityManager();
162 if (sm != null) {
163 PrivilegedAction<String> pa = new GetPropertyAction("java.home");
164 home = AccessController.doPrivileged(pa);
165 Permission p = new FilePermission(home + File.separator + "-", "read");
166 sm.checkPermission(p);
167 } else {
168 home = System.getProperty("java.home");
169 }
170
171 Path modules = Paths.get(home, "lib", "modules");
172 if (Files.isRegularFile(modules)) {
173 return SystemModuleFinder.getInstance();
174 } else {
175 Path mlib = Paths.get(home, "modules");
176 if (Files.isDirectory(mlib)) {
177 // exploded build may be patched
178 return ModulePath.of(ModuleBootstrap.patcher(), mlib);
179 } else {
180 throw new InternalError("Unable to detect the run-time image");
181 }
182 }
183 }
184
185 /**
186 * Returns a module finder that locates modules on the file system by
187 * searching a sequence of directories and/or packaged modules.
188 *
189 * Each element in the given array is one of:
190 * <ol>
191 * <li><p> A path to a directory of modules.</p></li>
192 * <li><p> A path to the <em>top-level</em> directory of an
193 * <em>exploded module</em>. </p></li>
194 * <li><p> A path to a <em>packaged module</em>. </p></li>
195 * </ol>
196 *
197 * The module finder locates modules by searching each directory, exploded
198 * module, or packaged module in array index order. It finds the first
199 * occurrence of a module with a given name and ignores other modules of
200 * that name that appear later in the sequence.
201 *
202 * <p> If an element is a path to a directory of modules then each entry in
203 * the directory is a packaged module or the top-level directory of an
204 * exploded module. It it an error if a directory contains more than one
205 * module with the same name. If an element is a path to a directory, and
206 * that directory contains a file named {@code module-info.class}, then the
207 * directory is treated as an exploded module rather than a directory of
208 * modules. </p>
209 *
210 * <p> The module finder returned by this method supports modules that are
211 * packaged as JAR files. A JAR file with a {@code module-info.class} in
212 * the top-level directory of the JAR file (or overridden by a versioned
213 * entry in a {@link java.util.jar.JarFile#isMultiRelease() multi-release}
214 * JAR file) is a modular JAR and is an <em>explicit module</em>.
215 * A JAR file that does not have a {@code module-info.class} in the
216 * top-level directory is created as an automatic module. The components
217 * for the automatic module are derived as follows:
218 *
219 * <ul>
220 *
221 * <li><p> The module {@link ModuleDescriptor#name() name}, and {@link
222 * ModuleDescriptor#version() version} if applicable, is derived from
223 * the file name of the JAR file as follows: </p>
224 *
|
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.nio.file.Files;
29 import java.nio.file.Path;
30 import java.nio.file.Paths;
31 import java.security.AccessController;
32 import java.security.Permission;
33 import java.security.PrivilegedAction;
34 import java.util.Collections;
35 import java.util.HashMap;
36 import java.util.HashSet;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Objects;
40 import java.util.Optional;
41 import java.util.Set;
42
43 import jdk.internal.module.ModuleBootstrap;
44 import jdk.internal.module.ModulePatcher;
45 import jdk.internal.module.ModulePath;
46 import jdk.internal.module.SystemModuleFinder;
47
48 /**
49 * A finder of modules. A {@code ModuleFinder} is used to find modules during
50 * <a href="package-summary.html#resolution">resolution</a> or
51 * <a href="package-summary.html#servicebinding">service binding</a>.
52 *
53 * <p> A {@code ModuleFinder} can only find one module with a given name. A
54 * {@code ModuleFinder} that finds modules in a sequence of directories, for
55 * example, will locate the first occurrence of a module of a given name and
56 * will ignore other modules of that name that appear in directories later in
57 * the sequence. </p>
58 *
59 * <p> Example usage: </p>
60 *
61 * <pre>{@code
62 * Path dir1, dir2, dir3;
63 *
64 * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
65 *
66 * Optional<ModuleReference> omref = finder.find("jdk.foo");
127 * Configuration#resolveAndBind resolveAndBind} that need to scan the
128 * 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
148 * {@link RuntimePermission RuntimePermission("accessSystemModules")}
149 * to access the system modules. </p>
150 *
151 * @return A {@code ModuleFinder} that locates the system modules
152 *
153 * @throws SecurityException
154 * If denied by the security manager
155 */
156 static ModuleFinder ofSystem() {
157 SecurityManager sm = System.getSecurityManager();
158 if (sm != null) {
159 sm.checkPermission(new RuntimePermission("accessSystemModules"));
160 PrivilegedAction<ModuleFinder> pa = ModuleFinder::privilegedOfSystem;
161 return AccessController.doPrivileged(pa);
162 } else {
163 return privilegedOfSystem();
164 }
165 }
166
167 /**
168 * Returns a module finder that locates the system modules. This method
169 * assumes it has permissions to access the runtime image.
170 */
171 private static ModuleFinder privilegedOfSystem() {
172 String home = System.getProperty("java.home");
173 Path modules = Paths.get(home, "lib", "modules");
174 if (Files.isRegularFile(modules)) {
175 return SystemModuleFinder.getInstance();
176 } else {
177 Path dir = Paths.get(home, "modules");
178 if (Files.isDirectory(dir)) {
179 return privilegedOf(ModuleBootstrap.patcher(), dir);
180 } else {
181 throw new InternalError("Unable to detect the run-time image");
182 }
183 }
184 }
185
186 /**
187 * Returns a module finder that locates the system modules in an exploded
188 * image. The image may be patched.
189 */
190 private static ModuleFinder privilegedOf(ModulePatcher patcher, Path dir) {
191 ModuleFinder finder = ModulePath.of(patcher, dir);
192 return new ModuleFinder() {
193 @Override
194 public Optional<ModuleReference> find(String name) {
195 PrivilegedAction<Optional<ModuleReference>> pa = () -> finder.find(name);
196 return AccessController.doPrivileged(pa);
197 }
198 @Override
199 public Set<ModuleReference> findAll() {
200 PrivilegedAction<Set<ModuleReference>> pa = finder::findAll;
201 return AccessController.doPrivileged(pa);
202 }
203 };
204 }
205
206 /**
207 * Returns a module finder that locates modules on the file system by
208 * searching a sequence of directories and/or packaged modules.
209 *
210 * Each element in the given array is one of:
211 * <ol>
212 * <li><p> A path to a directory of modules.</p></li>
213 * <li><p> A path to the <em>top-level</em> directory of an
214 * <em>exploded module</em>. </p></li>
215 * <li><p> A path to a <em>packaged module</em>. </p></li>
216 * </ol>
217 *
218 * The module finder locates modules by searching each directory, exploded
219 * module, or packaged module in array index order. It finds the first
220 * occurrence of a module with a given name and ignores other modules of
221 * that name that appear later in the sequence.
222 *
223 * <p> If an element is a path to a directory of modules then each entry in
224 * the directory is a packaged module or the top-level directory of an
225 * exploded module. It is an error if a directory contains more than one
226 * module with the same name. If an element is a path to a directory, and
227 * that directory contains a file named {@code module-info.class}, then the
228 * directory is treated as an exploded module rather than a directory of
229 * modules. </p>
230 *
231 * <p> The module finder returned by this method supports modules that are
232 * packaged as JAR files. A JAR file with a {@code module-info.class} in
233 * the top-level directory of the JAR file (or overridden by a versioned
234 * entry in a {@link java.util.jar.JarFile#isMultiRelease() multi-release}
235 * JAR file) is a modular JAR and is an <em>explicit module</em>.
236 * A JAR file that does not have a {@code module-info.class} in the
237 * top-level directory is created as an automatic module. The components
238 * for the automatic module are derived as follows:
239 *
240 * <ul>
241 *
242 * <li><p> The module {@link ModuleDescriptor#name() name}, and {@link
243 * ModuleDescriptor#version() version} if applicable, is derived from
244 * the file name of the JAR file as follows: </p>
245 *
|