1 /* 2 * Copyright (c) 2014, 2015, 2016 Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 */ 5 package com.oracle.appbundlers.utils; 6 7 import static com.oracle.appbundlers.utils.Config.CONFIG_INSTANCE; 8 import static java.lang.String.format; 9 import static java.nio.file.Files.newDirectoryStream; 10 import static java.util.stream.Collectors.joining; 11 import static java.util.stream.Collectors.toList; 12 13 import java.io.ByteArrayOutputStream; 14 import java.io.File; 15 import java.io.IOException; 16 import java.nio.file.DirectoryStream; 17 import java.nio.file.FileVisitResult; 18 import java.nio.file.Files; 19 import java.nio.file.Path; 20 import java.nio.file.Paths; 21 import java.nio.file.SimpleFileVisitor; 22 import java.nio.file.attribute.BasicFileAttributes; 23 import java.util.ArrayList; 24 import java.util.Arrays; 25 import java.util.Collections; 26 import java.util.HashSet; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.Map.Entry; 30 import java.util.Set; 31 import java.util.concurrent.ExecutionException; 32 import java.util.jar.Attributes; 33 import java.util.jar.JarEntry; 34 import java.util.jar.JarFile; 35 import java.util.jar.JarOutputStream; 36 import java.util.jar.Manifest; 37 import java.util.logging.Level; 38 import java.util.logging.Logger; 39 import java.util.stream.Collectors; 40 import java.util.stream.Stream; 41 import java.util.zip.ZipEntry; 42 43 import javax.tools.JavaCompiler; 44 import javax.tools.ToolProvider; 45 46 import javafx.util.Pair; 47 48 /** 49 * @author Dmitry Ginzburg <dmitry.x.ginzburg@oracle.com> 50 */ 51 public class AppWrapper implements Constants { 52 53 private static final Logger LOG = Logger 54 .getLogger(AppWrapper.class.getName()); 55 56 private Path workDir; 57 private final List<Source> sources; 58 private final String mainJar; 59 private final String mainClass; 60 61 private String paramsForJarsCompilation; 62 63 public AppWrapper(Path workDir, String mainClass, Source... source) { 64 this.workDir = workDir; 65 this.sources = Arrays.asList(source); 66 this.mainClass = mainClass; 67 List<String> jars = sources.stream() 68 .filter(src -> src.getFullName().equals(mainClass)) 69 .map(Source::getJarName).collect(toList()); 70 if (jars.size() != 1) { 71 throw new IllegalArgumentException( 72 format("Can not determine main jar : " + jars)); 73 } 74 mainJar = jars.get(0); 75 } 76 77 public AppWrapper(Path workDir, String mainClass, 78 String paramsForCompilation, Source... source) { 79 this(workDir, mainClass, source); 80 this.paramsForJarsCompilation = paramsForCompilation; 81 } 82 83 /** 84 * copy the old AppWrapper, but change the work dir 85 */ 86 public AppWrapper(AppWrapper copied, Path workDir) { 87 this.workDir = workDir; 88 sources = new ArrayList<>(copied.sources); 89 mainJar = copied.mainJar; 90 mainClass = copied.mainClass; 91 } 92 93 public String getAppName() { 94 return mainClass.substring(mainClass.lastIndexOf('.') + 1); 95 } 96 97 public void preinstallApp(ExtensionType extension) throws IOException { 98 createSrcBundleAndBinDirs(); 99 100 if (!getJarTempSources().isEmpty()) { 101 Utils.createDir(getJarDir()); 102 } 103 104 if (!getModuleTempSources().isEmpty()) { 105 Utils.createDir( 106 Paths.get(getModulePathBasedOnExtension(extension))); 107 } 108 } 109 110 private void createSrcBundleAndBinDirs() throws IOException { 111 Utils.createDir(getSrcDir()); 112 Utils.createDir(getBundlesDir()); 113 Utils.createDir(getBinDir()); 114 } 115 116 public void preinstallApp(ExtensionType[] extensionArray) throws IOException { 117 createSrcBundleAndBinDirs(); 118 119 for (ExtensionType extension : extensionArray) { 120 Utils.createDir(Paths.get(getModulePathBasedOnExtension(extension))); 121 } 122 } 123 124 private List<Source> getJarTempSources() { 125 return sources.stream().filter((source) -> !source.isModule()) 126 .collect(Collectors.toList()); 127 } 128 129 public Path getWorkDir() { 130 return workDir; 131 } 132 133 public void setWorkDir(Path workDir) { 134 this.workDir = workDir; 135 } 136 137 public List<Source> getSources() { 138 return sources; 139 } 140 141 public String getMainClass() { 142 return this.mainClass; 143 } 144 145 public Path getBundlesDir() { 146 return getWorkDir().resolve(BUNDLES); 147 } 148 149 private Path getSrcDir() { 150 return getWorkDir().resolve(SOURCE); 151 } 152 153 public Path getJarDir() { 154 return getWorkDir().resolve(JARS); 155 } 156 157 private Path getBinDir() { 158 return getWorkDir().resolve(BIN); 159 } 160 161 public Path getMainJarFile() { 162 return getJarDir().resolve(mainJar + ".jar"); 163 } 164 165 public void writeSourcesToAppDirectory() throws IOException { 166 Path appDir = getSrcDir(); 167 for (Source source : getModuleTempSources()) { 168 source.generateSourceForModule(appDir); 169 } 170 171 for (Source source : getJarTempSources()) { 172 source.generateSourceForJar(appDir); 173 } 174 } 175 176 public int compileApp(ExtensionType extension, Path... classpath) 177 throws IOException { 178 return compileApp(new String[0], extension, classpath); 179 } 180 181 private int compileApp(String[] javacOptions, ExtensionType extension, 182 Path... classpath) throws IOException { 183 int resultForModule = compileAppForModules(javacOptions, extension, 184 classpath); 185 int resultForJar = compileAppForJars(javacOptions, extension, 186 classpath); 187 int result = 0; 188 if (resultForJar < 0 || resultForModule < 0) { 189 result = -1; 190 } 191 return result; 192 } 193 194 public int compileApp(Path... classpath) throws IOException { 195 return compileApp(new String[0], classpath); 196 } 197 198 public int compileApp(String[] javacOptions, Path... classpath) 199 throws IOException { 200 return compileApp(javacOptions, null, classpath); 201 } 202 203 public int compileAndCreateJavaExtensionProduct(ExtensionType extension, Path... classpath) throws IOException, ExecutionException { 204 int resultForModule = compileAppForModules(new String[0], extension, classpath); 205 jarApp(extension); 206 compileAppForJars(new String[0], extension, classpath); 207 jarApp(ExtensionType.NormalJar); 208 return resultForModule; 209 } 210 211 private int compileAppForJars(String[] javacOptions, 212 ExtensionType extension, Path[] classpath) throws IOException { 213 if (getJarTempSources().isEmpty()) { 214 return 0; 215 } 216 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 217 final List<String> argsList = new ArrayList<>(); 218 219 if (javacOptions != null && javacOptions.length > 0) { 220 for (int i = 0; i < javacOptions.length; i++) { 221 String javacOption = javacOptions[i]; 222 argsList.add(javacOption); 223 } 224 } 225 226 argsList.add("-d"); 227 argsList.add(getBinDir().toString()); 228 229 int result = 0; 230 for (Source tempSource : getJarTempSources()) { 231 List<String> newArgs = new ArrayList<String>(); 232 newArgs.addAll(argsList); 233 234 newArgs.add("-classpath"); 235 if (classpath.length != 0) { 236 newArgs.add(Stream.of(classpath) 237 .map(eachPath -> eachPath.toAbsolutePath().toString()) 238 .collect(joining(File.pathSeparator))); 239 } else { 240 newArgs.add(getBinDir().toString()); 241 } 242 243 if (paramsForJarsCompilation != null) { 244 newArgs.add(this.paramsForJarsCompilation); 245 } 246 247 if (extension != null) { 248 newArgs.add("-mp"); 249 newArgs.add(String.join(File.pathSeparator, getModulePathBasedOnExtension(extension), JMODS_PATH_IN_JDK)); 250 } 251 252 String string = getSrcDir() + File.separator 253 + tempSource.getPackageName().replace(".", File.separator); 254 Path path = Paths.get(string); 255 Files.walkFileTree(path, new SimpleFileVisitor<Path>() { 256 @Override 257 public FileVisitResult visitFile(Path file, 258 BasicFileAttributes attr) { 259 260 if (file.toString().endsWith(".java")) { 261 newArgs.add(file.toString()); 262 } 263 return FileVisitResult.CONTINUE; 264 } 265 }); 266 267 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 268 LOG.log(Level.INFO, 269 "====================COMPILATION STARTS FOR NORMAL JAR==========================="); 270 LOG.log(Level.INFO,"compilation command for jars is " + newArgs); 271 result = compiler.run(System.in, outputStream, System.err, 272 newArgs.toArray(new String[newArgs.size()])); 273 LOG.log(Level.INFO, 274 "====================COMPILATION ENDS FOR NORMAL JAR============================="); 275 } 276 return result; 277 } 278 279 private int compileAppForModules(String[] javacOptions, 280 ExtensionType extension, Path... classpath) throws IOException { 281 if (getModuleTempSources().isEmpty()) { 282 return 0; 283 } 284 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 285 int result = 0; 286 for (Source source : getModuleTempSources()) { 287 final List<String> argsList = new ArrayList<>(); 288 289 if (javacOptions != null && javacOptions.length > 0) { 290 for (int i = 0; i < javacOptions.length; i++) { 291 String javacOption = javacOptions[i]; 292 argsList.add(javacOption); 293 } 294 } 295 296 argsList.add("-mp"); 297 argsList.add(String.join(File.pathSeparator, getBinDir().toString(), JMODS_PATH_IN_JDK)); 298 argsList.add("-d"); 299 argsList.add(String.join(File.separator, getBinDir().toString(), 300 source.getModuleName())); 301 Files.walkFileTree( 302 Paths.get(String.join(File.separator, 303 getSrcDir().toString(), source.getModuleName())), 304 new SimpleFileVisitor<Path>() { 305 public FileVisitResult visitFile(Path file, 306 BasicFileAttributes attr) { 307 if (file.toString().endsWith(".java")) { 308 argsList.add(file.toString()); 309 } 310 return FileVisitResult.CONTINUE; 311 } 312 }); 313 if (classpath.length != 0) { 314 argsList.add("-classpath"); 315 argsList.add(Stream.of(classpath) 316 .map(path -> path.toAbsolutePath().toString()) 317 .collect(joining(File.pathSeparator))); 318 } 319 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 320 if(extension != null) { 321 LOG.log(Level.INFO, 322 "====================COMPILATION STARTS FOR "+extension+" ==========================="); 323 LOG.log(Level.INFO, "compilation command for "+extension+" is "+argsList); 324 } else { 325 LOG.log(Level.INFO, 326 "compilation command for modules is " + argsList); 327 } 328 329 int tempResult = compiler.run(System.in, outputStream, System.err, 330 argsList.toArray(new String[argsList.size()])); 331 if (tempResult != 0) { 332 result = tempResult; 333 } 334 String out = outputStream.toString(); 335 if (!out.trim().isEmpty()) { 336 LOG.log(Level.INFO, out); 337 } 338 if(extension != null) { 339 LOG.log(Level.INFO, 340 "===================COMPILATION ENDS FOR "+extension+ " =============================="); 341 } else { 342 LOG.log(Level.INFO, "===================COMPILATION ENDS==================="); 343 } 344 LOG.log(Level.INFO, "\n"); 345 } 346 return result; 347 } 348 349 public List<Path> getJarFilesList() throws IOException { 350 try (DirectoryStream<Path> jarsStream = Files 351 .newDirectoryStream(getJarDir(), "*.jar")) { 352 List<Path> jars = new ArrayList<>(); 353 jarsStream.forEach(jars::add); 354 return jars; 355 } 356 } 357 358 private void createSimpleJar(List<Pair<String, String>> services, 359 boolean crossClassPath) throws IOException { 360 361 if (getJarTempSources().isEmpty()) { 362 return; 363 } 364 Map<String, List<Source>> jars = getJarTempSources().stream() 365 .collect(Collectors.groupingBy(Source::getJarName)); 366 367 for (Entry<String, List<Source>> entry : jars.entrySet()) { 368 String jarFileName = entry.getKey(); 369 Path jarFile = getJarDir().resolve(jarFileName + ".jar"); 370 Manifest manifest = new Manifest(); 371 manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, 372 "1.0"); 373 if (crossClassPath) 374 manifest.getMainAttributes().put(Attributes.Name.CLASS_PATH, 375 jars.keySet().stream() 376 .filter(str -> !str.equals(jarFileName)) 377 .map(str -> str + ".jar") 378 .collect(joining(File.pathSeparator))); 379 if (mainJar.equals(jarFileName)) { 380 manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, 381 mainClass); 382 } 383 384 try (JarOutputStream jarOutputStream = new JarOutputStream( 385 Files.newOutputStream(jarFile), manifest)) { 386 add(jarOutputStream, new HashSet<>(entry.getValue())); 387 for (Pair<String, String> service : services) { 388 if (!entry.getValue().stream().anyMatch(source -> source 389 .getFullName().equals(service.getValue()))) { 390 continue; 391 } 392 jarOutputStream.putNextEntry(new JarEntry( 393 "META-INF/services/" + service.getKey())); 394 jarOutputStream.write(service.getValue().getBytes()); 395 jarOutputStream.closeEntry(); 396 } 397 } 398 } 399 } 400 401 private void add(JarOutputStream jarStream, Set<Source> sources) 402 throws IOException { 403 Path classesDir = getBinDir(); 404 for (Source src : sources) { 405 Path packageDir = classesDir 406 .resolve(src.getPackageName().replace('.', '/')); 407 // we need to process inner classes like App1$1 408 DirectoryStream<Path> classFiles = newDirectoryStream(packageDir, 409 src.getSimpleName() + "*.class"); 410 for (Path classFile : classFiles) { 411 ZipEntry entry = new JarEntry( 412 src.getPackageName().replace('.', '/') + "/" 413 + classFile.getFileName().toString()); 414 jarStream.putNextEntry(entry); 415 jarStream.write(Files.readAllBytes(classFile)); 416 jarStream.closeEntry(); 417 } 418 } 419 } 420 421 public List<Source> getModuleTempSources() { 422 return sources.stream().filter((source) -> source.isModule()) 423 .collect(Collectors.toList()); 424 } 425 426 public Path getExplodedModsDir() { 427 return getBinDir(); 428 } 429 430 public Path getJmodsDir() { 431 return getWorkDir().resolve(JMODS_DIR); 432 } 433 434 public Path getModularJarsDir() { 435 return getWorkDir().resolve(MODULAR_JARS_DIR); 436 } 437 438 public List<Path> getModularJarFileList() throws IOException { 439 try (DirectoryStream<Path> jarsStream = Files 440 .newDirectoryStream(getModularJarsDir(), "*.jar")) { 441 List<Path> jars = new ArrayList<>(); 442 jarsStream.forEach(jars::add); 443 return jars; 444 } 445 } 446 447 public List<Path> getJmodFileList() throws IOException { 448 try (DirectoryStream<Path> jarsStream = Files 449 .newDirectoryStream(getJmodsDir(), "*.jmod")) { 450 List<Path> jmods = new ArrayList<>(); 451 jarsStream.forEach(jmods::add); 452 return jmods; 453 } 454 } 455 456 /* 457 * list mod directory 458 */ 459 460 public List<Path> getExplodedModFileList() throws IOException { 461 try (DirectoryStream<Path> jarsStream = Files 462 .newDirectoryStream(getExplodedModsDir(), "*")) { 463 List<Path> modFiles = new ArrayList<>(); 464 jarsStream.forEach(modFiles::add); 465 return modFiles; 466 } 467 } 468 469 public void jarApp(ExtensionType extension) 470 throws IOException, ExecutionException { 471 switch (extension) { 472 case NormalJar: 473 createSimpleJar(Collections.emptyList(), false); 474 break; 475 case ModularJar: 476 createModularJar(Collections.emptyList(), false); 477 break; 478 case ExplodedModules: /****************************************** 479 * bin directory itself is exploded modules 480 * directory 481 ******************************************/ 482 break; 483 case Jmods: 484 createJmod(); 485 break; 486 } 487 } 488 489 public void jarApp(List<Pair<String, String>> services, 490 boolean crossClassPath) throws IOException, ExecutionException { 491 createSimpleJar(services, crossClassPath); 492 createModularJar(services, crossClassPath); 493 } 494 495 private void createJmod() throws IOException, ExecutionException { 496 for (Source source : getModuleTempSources()) { 497 List<String> command = new ArrayList<String>(); 498 command.add("jmod"); 499 command.add("create"); 500 command.add("--class-path"); 501 command.add(getBinDir().toString() + File.separator 502 + source.getModuleName()); 503 command.add("--main-class"); 504 command.add(source.getFullName()); 505 command.add(getJmodsDir() + File.separator + source.getModuleName() 506 + ".jmod"); 507 System.out.println( 508 "=========================JMOD CREATION STARTS========================="); 509 Utils.runCommand(command, CONFIG_INSTANCE.getInstallTimeout()); 510 System.out.println( 511 "=========================JMOD CREATION ENDS==========================="); 512 System.out.println(); 513 } 514 } 515 516 private void createModularJar(List<Pair<String, String>> services, 517 boolean crossClassPath) throws IOException, ExecutionException { 518 519 if (getModuleTempSources().isEmpty()) { 520 return; 521 } 522 /* 523 * @TODO check whether services are required in modular jar Need to 524 * change below code Implementation pending. complete this 525 * implementation. 526 */ 527 if (!services.isEmpty()) { 528 Map<String, List<Source>> jars = sources.stream() 529 .collect(Collectors.groupingBy(Source::getJarName)); 530 531 // for (Map.Entry<String, List<TempSource>> entry : jars.entrySet()) 532 // { 533 // String jarFileName = entry.getKey(); 534 //// Path jarFile = getJarDir().resolve(jarFileName + ".jar"); 535 // Manifest manifest = new Manifest(); 536 // manifest.getMainAttributes() 537 // .put(Attributes.Name.MANIFEST_VERSION, "1.0"); 538 // if (crossClassPath) { 539 // manifest.getMainAttributes() 540 // .put(Attributes.Name.CLASS_PATH, 541 // jars.keySet().stream() 542 // .filter(str -> !str 543 // .equals(jarFileName)) 544 // .map(str -> str + ".jar") 545 // .collect(joining(File.pathSeparator))); 546 // } 547 // if (mainJar != null && jarFileName != null && 548 // mainJar.equals(jarFileName)) { 549 // manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, 550 // mainClass); 551 // } 552 // } 553 /* 554 * Dummy code 555 * 556 * @TODO complete implementation. 557 */ 558 559 for (Source tempSource : getModuleTempSources()) { 560 Manifest manifest = new Manifest(); 561 String jarFileName = tempSource.getJarName(); 562 manifest.getMainAttributes() 563 .put(Attributes.Name.MANIFEST_VERSION, "1.0"); 564 if (crossClassPath) { 565 manifest.getMainAttributes() 566 .put(Attributes.Name.CLASS_PATH, 567 jars.keySet().stream() 568 .filter(str -> !str 569 .equals(jarFileName)) 570 .map(str -> str + ".jar") 571 .collect(joining(File.pathSeparator))); 572 } 573 if (mainJar != null && jarFileName != null 574 && mainJar.equals(jarFileName)) { 575 manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, 576 mainClass); 577 } 578 579 // try (JarOutputStream jarOutputStream = new JarOutputStream( 580 // Files.newOutputStream(Paths.get(jarFileName)), manifest)) { 581 // Stream<Path> walk = 582 // Files.walk(Paths.get(getModularJarsDir().toString() + 583 // File.separatorChar + tempSource.getModuleName()), 584 // Integer.MAX_VALUE); 585 // String join = String.join(File.separator, 586 // getModularJarsDir().toString(), tempSource.getModuleName(), 587 // tempSource.getModuleName().replace('.', File.separatorChar)); 588 // Path moduleInfoPath = 589 // getModularJarsDir().resolve(tempSource.getModuleName().replace('.', 590 // '/')).resolve("module-info.class"); 591 // ZipEntry zipEntry = new JarEntry( 592 // moduleInfoPath.getFileName().toString()); 593 // jarOutputStream.putNextEntry(zipEntry); 594 // jarOutputStream.write(Files.readAllBytes(moduleInfoPath)); 595 // jarOutputStream.closeEntry(); 596 // 597 // String packageName = 598 // getModularJarsDir().toString().replace('.', '/'); 599 // DirectoryStream<Path> classFiles = newDirectoryStream( 600 // getModularJarsDir().resolve(packageName), "*.class"); 601 // for (Path eachClassFile : classFiles) { 602 // ZipEntry jarEntry = new JarEntry("com/greetings" + "/" 603 // + eachClassFile.getFileName().toString()); 604 // jarOutputStream.putNextEntry(jarEntry); 605 // jarOutputStream.write(Files.readAllBytes(eachClassFile)); 606 // jarOutputStream.closeEntry(); 607 // } 608 // } 609 610 // Files.walkFileTree(Paths.get(getModsDir().toString() + 611 // File.separatorChar + tempSource.getModuleName()), new 612 // SimpleFileVisitor<Path>() { 613 // @Override 614 // public FileVisitResult visitFile(Path file, 615 // BasicFileAttributes attr) { 616 // 617 // if ("module-info.java".equals(file.toString())) { 618 // ZipEntry zipEntry = new JarEntry( 619 // moduleInfoPath.getFileName().toString()); 620 // jarOutputStream.putNextEntry(zipEntry); 621 // jarOutputStream.write(Files.readAllBytes(moduleInfoPath)); 622 // jarOutputStream.closeEntry(); 623 // } 624 // return FileVisitResult.CONTINUE; 625 // } 626 // }); 627 628 } 629 630 } else { 631 /* 632 * JDK 9 jar creation procedure. $ jar --create 633 * --file=mlib/org.astro@1.0.jar --module-version=1.0 -C 634 * mods/org.astro . 635 */ 636 for (Source source : getModuleTempSources()) { 637 List<String> command = new ArrayList<String>(); 638 command.add("jar"); 639 command.add("--create"); 640 command.add("--file=" + getModularJarsDir() + File.separator 641 + source.getJarName() + ".jar"); 642 command.add("--module-version=1.0"); 643 if (source.getFullName() != null && this.mainClass != null 644 && source.getFullName().equals(this.mainClass)) { 645 command.add("--main-class=" + this.mainClass); 646 } 647 command.add("-C"); 648 String moduleAbsouleDirectoryPath = String.join(File.separator, 649 getBinDir().toString(), source.getModuleName()); 650 command.add(moduleAbsouleDirectoryPath); 651 command.add("."); 652 System.out.println( 653 "====================MODULAR JAR CREATION STARTS=================="); 654 Utils.runCommand(command, CONFIG_INSTANCE.getInstallTimeout()); 655 System.out.println( 656 "====================MODULAR JAR CREATION ENDS===================="); 657 System.out.println(); 658 } 659 } 660 } 661 662 public String getIdentifier() { 663 try (JarFile mainJar = new JarFile(getMainJarFile().toFile());) { 664 Manifest manifest = mainJar.getManifest(); 665 for (Map.Entry<Object, Object> entry : manifest.getMainAttributes() 666 .entrySet()) { 667 if (entry.getKey().toString().equals("Main-Class")) { 668 return entry.getValue().toString(); 669 } 670 } 671 } catch (IOException ex) { 672 throw new RuntimeException(ex); 673 } 674 return ""; 675 } 676 677 public String getAllModuleNamesSeparatedByPathSeparator() { 678 return getModuleTempSources().stream().map(Source::getModuleName) 679 .collect(Collectors.joining(File.pathSeparator)); 680 } 681 682 public String getAllModuleNamesSeparatedByComma() { 683 return getModuleTempSources().stream().map(Source::getModuleName) 684 .collect(Collectors.joining(",")); 685 } 686 687 public List<String> getAllModuleNamesAsList() { 688 return getModuleTempSources().stream().map(Source::getModuleName) 689 .collect(Collectors.toList()); 690 } 691 692 public String getMainModuleName() { 693 List<Source> collect = sources.stream() 694 .filter((source) -> source.isMainModule()) 695 .collect(Collectors.toList()); 696 return !collect.isEmpty() ? collect.get(0).getModuleName() : null; 697 } 698 699 public boolean isAppContainsModules() { 700 return !getModuleTempSources().isEmpty(); 701 } 702 703 private String getModulePathBasedOnExtension(ExtensionType extension) { 704 if (extension == null) { 705 throw new NullPointerException("Extension cannot be null"); 706 } 707 switch (extension) { 708 case ModularJar: 709 return getModularJarsDir().toString(); 710 case ExplodedModules: 711 return getExplodedModsDir().toString(); 712 case Jmods: 713 return getJmodsDir().toString(); 714 default: 715 return getJarDir().toString(); 716 } 717 } 718 }