28 import java.io.File;
29 import java.io.IOException;
30 import java.io.StringReader;
31 import java.nio.file.Files;
32 import java.nio.file.Path;
33 import java.text.MessageFormat;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.EnumSet;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.Iterator;
40 import java.util.LinkedHashMap;
41 import java.util.LinkedHashSet;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Properties;
45 import java.util.ResourceBundle;
46 import java.util.Set;
47 import java.util.Optional;
48 import java.lang.module.ModuleDescriptor;
49 import java.lang.module.ModuleFinder;
50 import java.lang.module.ModuleReference;
51
52 import jdk.tools.jlink.internal.packager.AppRuntimeImageBuilder;
53
54 final class JLinkBundlerHelper {
55
56 private static final ResourceBundle I18N = ResourceBundle.getBundle(
57 "jdk.jpackage.internal.resources.MainResources");
58 private static final String JRE_MODULES_FILENAME =
59 "jdk/jpackage/internal/resources/jre.list";
60 private static final String SERVER_JRE_MODULES_FILENAME =
61 "jdk/jpackage/internal/resources/jre.module.list";
62
63 private JLinkBundlerHelper() {}
64
65 @SuppressWarnings("unchecked")
66 static final BundlerParamInfo<String> JLINK_BUILDER =
67 new StandardBundlerParam<>(
165
166 if (index > 0) {
167 result = mainModule.substring(0, index);
168 } else {
169 result = mainModule;
170 }
171 }
172
173 return result;
174 }
175
176 static String getJDKVersion(Map<String, ? super Object> params) {
177 String result = "";
178 List<Path> modulePath =
179 StandardBundlerParam.MODULE_PATH.fetchFrom(params);
180 Set<String> limitModules =
181 StandardBundlerParam.LIMIT_MODULES.fetchFrom(params);
182 Path javaBasePath = findPathOfModule(modulePath, "java.base.jmod");
183 Set<String> addModules = getValidModules(modulePath,
184 StandardBundlerParam.ADD_MODULES.fetchFrom(params),
185 limitModules, true);
186
187
188 if (javaBasePath != null && javaBasePath.toFile().exists()) {
189 result = getModuleVersion(javaBasePath.toFile(),
190 modulePath, addModules, limitModules);
191 }
192
193 return result;
194 }
195
196 static Path getJDKHome(Map<String, ? super Object> params) {
197 Path result = null;
198 List<Path> modulePath =
199 StandardBundlerParam.MODULE_PATH.fetchFrom(params);
200 Path javaBasePath = findPathOfModule(modulePath, "java.base.jmod");
201
202 if (javaBasePath != null && javaBasePath.toFile().exists()) {
203 result = javaBasePath.getParent();
204
205 // On a developer build the JDK Home isn't where we expect it
213 final String exe =
214 (Platform.getPlatform() == Platform.WINDOWS) ?
215 ".exe" : "";
216 Path javaExe = bin.resolve("java" + exe);
217
218 if (Files.exists(javaExe)) {
219 found = true;
220 }
221 }
222
223 if (!found) {
224 result = result.resolve(".." + File.separator + "jdk");
225 }
226 }
227 }
228
229 return result;
230 }
231
232 private static Set<String> getValidModules(List<Path> modulePath,
233 Set<String> addModules, Set<String> limitModules,
234 boolean forJRE) {
235 ModuleHelper moduleHelper = new ModuleHelper(
236 modulePath, addModules, limitModules, forJRE);
237 return removeInvalidModules(modulePath, moduleHelper.modules());
238 }
239
240 static void execute(Map<String, ? super Object> params,
241 AbstractAppImageBuilder imageBuilder)
242 throws IOException, Exception {
243 List<Path> modulePath =
244 StandardBundlerParam.MODULE_PATH.fetchFrom(params);
245 Set<String> addModules =
246 StandardBundlerParam.ADD_MODULES.fetchFrom(params);
247 Set<String> limitModules =
248 StandardBundlerParam.LIMIT_MODULES.fetchFrom(params);
249 boolean stripNativeCommands =
250 StandardBundlerParam.STRIP_NATIVE_COMMANDS.fetchFrom(params);
251 Path outputDir = imageBuilder.getRoot();
252 String excludeFileList = imageBuilder.getExcludeFileList();
253 File mainJar = getMainJar(params);
254 ModFile.ModType mainJarType = ModFile.ModType.Unknown;
255
256 if (mainJar != null) {
257 mainJarType = new ModFile(mainJar).getModType();
258 } else if (StandardBundlerParam.MODULE.fetchFrom(params) == null) {
259 // user specified only main class, all jars will be on the classpath
260 mainJarType = ModFile.ModType.UnnamedJar;
261 }
262
263 // Modules
264
265 // The default for an unnamed jar is ALL_DEFAULT with the
266 // non-valid modules removed.
267 if (mainJarType == ModFile.ModType.UnnamedJar) {
268 addModules.add(ModuleHelper.ALL_RUNTIME);
269 } else if (mainJarType == ModFile.ModType.Unknown ||
270 mainJarType == ModFile.ModType.ModularJar) {
271 String mainModule = getMainModule(params);
272 addModules.add(mainModule);
273 }
274 addModules.addAll(getValidModules(
275 modulePath, addModules, limitModules, false));
276
277 Log.verbose(MessageFormat.format(
278 I18N.getString("message.modules"), addModules.toString()));
279
280 AppRuntimeImageBuilder appRuntimeBuilder = new AppRuntimeImageBuilder();
281 appRuntimeBuilder.setOutputDir(outputDir);
282 appRuntimeBuilder.setModulePath(modulePath);
283 appRuntimeBuilder.setAddModules(addModules);
284 appRuntimeBuilder.setLimitModules(limitModules);
285 appRuntimeBuilder.setExcludeFileList(excludeFileList);
286 appRuntimeBuilder.setStripNativeCommands(stripNativeCommands);
287 appRuntimeBuilder.setUserArguments(new HashMap<String,String>());
288
289 appRuntimeBuilder.build();
290 imageBuilder.prepareApplicationFiles();
291 }
292
293 static void generateJre(Map<String, ? super Object> params,
294 AbstractAppImageBuilder imageBuilder)
295 throws IOException, Exception {
296 List<Path> modulePath =
297 StandardBundlerParam.MODULE_PATH.fetchFrom(params);
298 Set<String> addModules =
299 StandardBundlerParam.ADD_MODULES.fetchFrom(params);
300 Set<String> limitModules =
301 StandardBundlerParam.LIMIT_MODULES.fetchFrom(params);
302 boolean stripNativeCommands =
303 StandardBundlerParam.STRIP_NATIVE_COMMANDS.fetchFrom(params);
304 Path outputDir = imageBuilder.getRoot();
305 addModules.add(ModuleHelper.ALL_RUNTIME);
306 Set<String> redistModules = getValidModules(modulePath,
307 addModules, limitModules, true);
308 addModules.addAll(redistModules);
309
310 Log.verbose(MessageFormat.format(
311 I18N.getString("message.modules"), addModules.toString()));
312
313 AppRuntimeImageBuilder appRuntimeBuilder = new AppRuntimeImageBuilder();
314 appRuntimeBuilder.setOutputDir(outputDir);
315 appRuntimeBuilder.setModulePath(modulePath);
316 appRuntimeBuilder.setAddModules(addModules);
317 appRuntimeBuilder.setLimitModules(limitModules);
318 appRuntimeBuilder.setStripNativeCommands(stripNativeCommands);
319 appRuntimeBuilder.setExcludeFileList("");
320 appRuntimeBuilder.setUserArguments(new HashMap<String,String>());
321
322 appRuntimeBuilder.build();
323 imageBuilder.prepareJreFiles();
324 }
325
326 // Returns the path to the JDK modules in the user defined module path.
327 static Path findPathOfModule(
328 List<Path> modulePath, String moduleName) {
329 Path result = null;
330
331 for (Path path : modulePath) {
332 Path moduleNamePath = path.resolve(moduleName);
333
334 if (Files.exists(moduleNamePath)) {
335 result = path;
336 break;
337 }
338 }
339
340 return result;
341 }
342
343 private static Set<String> removeInvalidModules(
344 List<Path> modulePath, Set<String> modules) {
345 Set<String> result = new LinkedHashSet<String>();
346 ModuleManager mm = new ModuleManager(modulePath);
347 List<ModFile> lmodfiles =
348 mm.getModules(EnumSet.of(ModuleManager.SearchType.ModularJar,
349 ModuleManager.SearchType.Jmod,
350 ModuleManager.SearchType.ExplodedModule));
351
352 HashMap<String, ModFile> validModules = new HashMap<>();
353
354 for (ModFile modFile : lmodfiles) {
355 validModules.put(modFile.getModName(), modFile);
356 }
357
358 for (String name : modules) {
359 if (validModules.containsKey(name)) {
360 result.add(name);
361 } else {
362 Log.error(MessageFormat.format(
381 ModuleDescriptor descriptor = mref.get().descriptor();
382
383 if (descriptor != null) {
384 Optional<ModuleDescriptor.Version> version =
385 descriptor.version();
386
387 if (version.isPresent()) {
388 result = version.get().toString();
389 }
390 }
391 }
392
393 return result;
394 }
395
396 private static class ModuleHelper {
397 // The token for "all modules on the module path".
398 private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
399
400 // The token for "all valid runtime modules".
401 static final String ALL_RUNTIME = "ALL-RUNTIME";
402
403 private final Set<String> modules = new HashSet<>();
404 private enum Macros {None, AllModulePath, AllRuntime}
405
406 ModuleHelper(List<Path> paths, Set<String> roots,
407 Set<String> limitMods, boolean forJRE) {
408 Macros macro = Macros.None;
409
410 for (Iterator<String> iterator = roots.iterator();
411 iterator.hasNext();) {
412 String module = iterator.next();
413
414 switch (module) {
415 case ALL_MODULE_PATH:
416 iterator.remove();
417 macro = Macros.AllModulePath;
418 break;
419 case ALL_RUNTIME:
420 iterator.remove();
421 macro = Macros.AllRuntime;
422 break;
423 default:
424 this.modules.add(module);
425 }
426 }
427
428 switch (macro) {
429 case AllModulePath:
430 this.modules.addAll(getModuleNamesFromPath(paths));
431 break;
432 case AllRuntime:
433 Set<Module> runtimeModules =
434 ModuleLayer.boot().modules();
435 for (Module m : runtimeModules) {
436 String name = m.getName();
437 if (forJRE && isModuleExcludedFromJRE(name)) {
438 continue; // JRE does not include this module
439 }
440 this.modules.add(name);
441 }
442 break;
443 }
444 }
445
446 Set<String> modules() {
447 return modules;
448 }
449
450 private boolean isModuleExcludedFromJRE(String name) {
451 return false; // not excluding any modules from JRE at this time
452 }
453
454 private static Set<String> getModuleNamesFromPath(List<Path> Value) {
455 Set<String> result = new LinkedHashSet<String>();
456 ModuleManager mm = new ModuleManager(Value);
457 List<ModFile> modFiles =
458 mm.getModules(
459 EnumSet.of(ModuleManager.SearchType.ModularJar,
460 ModuleManager.SearchType.Jmod,
461 ModuleManager.SearchType.ExplodedModule));
462
463 for (ModFile modFile : modFiles) {
464 result.add(modFile.getModName());
465 }
466
467 return result;
468 }
469 }
470 }
|
28 import java.io.File;
29 import java.io.IOException;
30 import java.io.StringReader;
31 import java.nio.file.Files;
32 import java.nio.file.Path;
33 import java.text.MessageFormat;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.EnumSet;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.Iterator;
40 import java.util.LinkedHashMap;
41 import java.util.LinkedHashSet;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Properties;
45 import java.util.ResourceBundle;
46 import java.util.Set;
47 import java.util.Optional;
48 import java.util.Arrays;
49 import java.util.stream.Collectors;
50 import java.util.stream.Stream;
51 import java.lang.module.Configuration;
52 import java.lang.module.ResolvedModule;
53 import java.lang.module.ModuleDescriptor;
54 import java.lang.module.ModuleFinder;
55 import java.lang.module.ModuleReference;
56
57 import jdk.tools.jlink.internal.packager.AppRuntimeImageBuilder;
58
59 final class JLinkBundlerHelper {
60
61 private static final ResourceBundle I18N = ResourceBundle.getBundle(
62 "jdk.jpackage.internal.resources.MainResources");
63 private static final String JRE_MODULES_FILENAME =
64 "jdk/jpackage/internal/resources/jre.list";
65 private static final String SERVER_JRE_MODULES_FILENAME =
66 "jdk/jpackage/internal/resources/jre.module.list";
67
68 private JLinkBundlerHelper() {}
69
70 @SuppressWarnings("unchecked")
71 static final BundlerParamInfo<String> JLINK_BUILDER =
72 new StandardBundlerParam<>(
170
171 if (index > 0) {
172 result = mainModule.substring(0, index);
173 } else {
174 result = mainModule;
175 }
176 }
177
178 return result;
179 }
180
181 static String getJDKVersion(Map<String, ? super Object> params) {
182 String result = "";
183 List<Path> modulePath =
184 StandardBundlerParam.MODULE_PATH.fetchFrom(params);
185 Set<String> limitModules =
186 StandardBundlerParam.LIMIT_MODULES.fetchFrom(params);
187 Path javaBasePath = findPathOfModule(modulePath, "java.base.jmod");
188 Set<String> addModules = getValidModules(modulePath,
189 StandardBundlerParam.ADD_MODULES.fetchFrom(params),
190 limitModules);
191
192
193 if (javaBasePath != null && javaBasePath.toFile().exists()) {
194 result = getModuleVersion(javaBasePath.toFile(),
195 modulePath, addModules, limitModules);
196 }
197
198 return result;
199 }
200
201 static Path getJDKHome(Map<String, ? super Object> params) {
202 Path result = null;
203 List<Path> modulePath =
204 StandardBundlerParam.MODULE_PATH.fetchFrom(params);
205 Path javaBasePath = findPathOfModule(modulePath, "java.base.jmod");
206
207 if (javaBasePath != null && javaBasePath.toFile().exists()) {
208 result = javaBasePath.getParent();
209
210 // On a developer build the JDK Home isn't where we expect it
218 final String exe =
219 (Platform.getPlatform() == Platform.WINDOWS) ?
220 ".exe" : "";
221 Path javaExe = bin.resolve("java" + exe);
222
223 if (Files.exists(javaExe)) {
224 found = true;
225 }
226 }
227
228 if (!found) {
229 result = result.resolve(".." + File.separator + "jdk");
230 }
231 }
232 }
233
234 return result;
235 }
236
237 private static Set<String> getValidModules(List<Path> modulePath,
238 Set<String> addModules, Set<String> limitModules) {
239 ModuleHelper moduleHelper = new ModuleHelper(
240 modulePath, addModules, limitModules);
241 return removeInvalidModules(modulePath, moduleHelper.modules());
242 }
243
244 static void execute(Map<String, ? super Object> params,
245 AbstractAppImageBuilder imageBuilder)
246 throws IOException, Exception {
247 List<Path> modulePath =
248 StandardBundlerParam.MODULE_PATH.fetchFrom(params);
249 Set<String> addModules =
250 StandardBundlerParam.ADD_MODULES.fetchFrom(params);
251 Set<String> limitModules =
252 StandardBundlerParam.LIMIT_MODULES.fetchFrom(params);
253 boolean stripNativeCommands =
254 StandardBundlerParam.STRIP_NATIVE_COMMANDS.fetchFrom(params);
255 Path outputDir = imageBuilder.getRoot();
256 String excludeFileList = imageBuilder.getExcludeFileList();
257 File mainJar = getMainJar(params);
258 ModFile.ModType mainJarType = ModFile.ModType.Unknown;
259
260 if (mainJar != null) {
261 mainJarType = new ModFile(mainJar).getModType();
262 } else if (StandardBundlerParam.MODULE.fetchFrom(params) == null) {
263 // user specified only main class, all jars will be on the classpath
264 mainJarType = ModFile.ModType.UnnamedJar;
265 }
266
267 // Modules
268
269 if (mainJarType == ModFile.ModType.UnnamedJar) {
270 // The default for an unnamed jar is ALL_DEFAULT
271 addModules.add(ModuleHelper.ALL_DEFAULT);
272 } if (mainJarType == ModFile.ModType.Unknown ||
273 mainJarType == ModFile.ModType.ModularJar) {
274 String mainModule = getMainModule(params);
275 addModules.add(mainModule);
276 }
277 addModules.addAll(getValidModules(
278 modulePath, addModules, limitModules));
279
280 Log.verbose(MessageFormat.format(
281 I18N.getString("message.modules"), addModules.toString()));
282
283 AppRuntimeImageBuilder appRuntimeBuilder = new AppRuntimeImageBuilder();
284 appRuntimeBuilder.setOutputDir(outputDir);
285 appRuntimeBuilder.setModulePath(modulePath);
286 appRuntimeBuilder.setAddModules(addModules);
287 appRuntimeBuilder.setLimitModules(limitModules);
288 appRuntimeBuilder.setExcludeFileList(excludeFileList);
289 appRuntimeBuilder.setStripNativeCommands(stripNativeCommands);
290 appRuntimeBuilder.setUserArguments(new HashMap<String,String>());
291
292 appRuntimeBuilder.build();
293 imageBuilder.prepareApplicationFiles();
294 }
295
296 static void generateJre(Map<String, ? super Object> params,
297 AbstractAppImageBuilder imageBuilder)
298 throws IOException, Exception {
299 List<Path> modulePath =
300 StandardBundlerParam.MODULE_PATH.fetchFrom(params);
301 Set<String> addModules =
302 StandardBundlerParam.ADD_MODULES.fetchFrom(params);
303 Set<String> limitModules =
304 StandardBundlerParam.LIMIT_MODULES.fetchFrom(params);
305 boolean stripNativeCommands =
306 StandardBundlerParam.STRIP_NATIVE_COMMANDS.fetchFrom(params);
307 Path outputDir = imageBuilder.getRoot();
308 addModules.add(ModuleHelper.ALL_MODULE_PATH);
309 Set<String> redistModules = getValidModules(modulePath,
310 addModules, limitModules);
311 addModules.addAll(redistModules);
312
313 Log.verbose(MessageFormat.format(
314 I18N.getString("message.modules"), addModules.toString()));
315
316 AppRuntimeImageBuilder appRuntimeBuilder = new AppRuntimeImageBuilder();
317 appRuntimeBuilder.setOutputDir(outputDir);
318 appRuntimeBuilder.setModulePath(modulePath);
319 appRuntimeBuilder.setAddModules(addModules);
320 appRuntimeBuilder.setLimitModules(limitModules);
321 appRuntimeBuilder.setStripNativeCommands(stripNativeCommands);
322 appRuntimeBuilder.setExcludeFileList("");
323 appRuntimeBuilder.setUserArguments(new HashMap<String,String>());
324
325 appRuntimeBuilder.build();
326 imageBuilder.prepareJreFiles();
327 }
328
329 // Returns the path to the JDK modules in the user defined module path.
330 static Path findPathOfModule(
331 List<Path> modulePath, String moduleName) {
332 Path result = null;
333
334 for (Path path : modulePath) {
335 Path moduleNamePath = path.resolve(moduleName);
336
337 if (Files.exists(moduleNamePath)) {
338 result = path;
339 break;
340 }
341 }
342
343 return result;
344 }
345
346 /*
347 * Returns the set of modules that would be visible by default for
348 * a non-modular-aware application consisting of the given elements.
349 */
350 private static Set<String> getDefaultModules(
351 Path[] paths, String[] addModules) {
352
353 // the modules in the run-time image that export an API
354 Stream<String> systemRoots = ModuleFinder.ofSystem().findAll().stream()
355 .map(ModuleReference::descriptor)
356 .filter(descriptor -> exportsAPI(descriptor))
357 .map(ModuleDescriptor::name);
358
359 Set<String> roots;
360 if (addModules == null || addModules.length == 0) {
361 roots = systemRoots.collect(Collectors.toSet());
362 } else {
363 var extraRoots = Stream.of(addModules);
364 roots = Stream.concat(systemRoots,
365 extraRoots).collect(Collectors.toSet());
366 }
367
368 ModuleFinder finder = ModuleFinder.ofSystem();
369 if (paths != null && paths.length > 0) {
370 finder = ModuleFinder.compose(finder, ModuleFinder.of(paths));
371 }
372 return Configuration.empty()
373 .resolveAndBind(finder, ModuleFinder.of(), roots)
374 .modules()
375 .stream()
376 .map(ResolvedModule::name)
377 .collect(Collectors.toSet());
378 }
379
380 /*
381 * Returns true if the given module exports an API to all module.
382 */
383 private static boolean exportsAPI(ModuleDescriptor descriptor) {
384 return descriptor.exports()
385 .stream()
386 .filter(e -> !e.isQualified())
387 .findAny()
388 .isPresent();
389 }
390
391 private static Set<String> removeInvalidModules(
392 List<Path> modulePath, Set<String> modules) {
393 Set<String> result = new LinkedHashSet<String>();
394 ModuleManager mm = new ModuleManager(modulePath);
395 List<ModFile> lmodfiles =
396 mm.getModules(EnumSet.of(ModuleManager.SearchType.ModularJar,
397 ModuleManager.SearchType.Jmod,
398 ModuleManager.SearchType.ExplodedModule));
399
400 HashMap<String, ModFile> validModules = new HashMap<>();
401
402 for (ModFile modFile : lmodfiles) {
403 validModules.put(modFile.getModName(), modFile);
404 }
405
406 for (String name : modules) {
407 if (validModules.containsKey(name)) {
408 result.add(name);
409 } else {
410 Log.error(MessageFormat.format(
429 ModuleDescriptor descriptor = mref.get().descriptor();
430
431 if (descriptor != null) {
432 Optional<ModuleDescriptor.Version> version =
433 descriptor.version();
434
435 if (version.isPresent()) {
436 result = version.get().toString();
437 }
438 }
439 }
440
441 return result;
442 }
443
444 private static class ModuleHelper {
445 // The token for "all modules on the module path".
446 private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
447
448 // The token for "all valid runtime modules".
449 static final String ALL_DEFAULT = "ALL-DEFAULT";
450
451 private final Set<String> modules = new HashSet<>();
452 private enum Macros {None, AllModulePath, AllRuntime}
453
454 ModuleHelper(List<Path> paths, Set<String> addModules,
455 Set<String> limitModules) {
456 boolean addAllModulePath = false;
457 boolean addDefaultMods = false;
458
459 for (Iterator<String> iterator = addModules.iterator();
460 iterator.hasNext();) {
461 String module = iterator.next();
462
463 switch (module) {
464 case ALL_MODULE_PATH:
465 iterator.remove();
466 addAllModulePath = true;
467 break;
468 case ALL_DEFAULT:
469 iterator.remove();
470 addDefaultMods = true;
471 break;
472 default:
473 this.modules.add(module);
474 }
475 }
476
477 if (addAllModulePath) {
478 this.modules.addAll(getModuleNamesFromPath(paths));
479 } else if (addDefaultMods) {
480 this.modules.addAll(getDefaultModules(
481 paths.toArray(new Path[0]),
482 addModules.toArray(new String[0])));
483 }
484 }
485
486 Set<String> modules() {
487 return modules;
488 }
489
490 private static Set<String> getModuleNamesFromPath(List<Path> Value) {
491 Set<String> result = new LinkedHashSet<String>();
492 ModuleManager mm = new ModuleManager(Value);
493 List<ModFile> modFiles = mm.getModules(
494 EnumSet.of(ModuleManager.SearchType.ModularJar,
495 ModuleManager.SearchType.Jmod,
496 ModuleManager.SearchType.ExplodedModule));
497
498 for (ModFile modFile : modFiles) {
499 result.add(modFile.getModName());
500 }
501 return result;
502 }
503 }
504 }
|