1 /* 2 * Copyright (c) 2018, 2019, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jnlp.converter; 25 26 import java.io.BufferedWriter; 27 import java.io.File; 28 import java.io.FileNotFoundException; 29 import java.io.FileOutputStream; 30 import java.io.FileWriter; 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.io.PrintWriter; 34 import java.net.HttpURLConnection; 35 import java.net.URI; 36 import java.net.URL; 37 import java.nio.file.Files; 38 import java.nio.file.Path; 39 import java.util.ArrayList; 40 import java.util.Enumeration; 41 import java.util.List; 42 import java.util.jar.JarEntry; 43 import java.util.jar.JarFile; 44 import jnlp.converter.parser.JNLPDesc; 45 import jnlp.converter.parser.JNLPDesc.AssociationDesc; 46 import jnlp.converter.parser.JNLPDesc.IconDesc; 47 import jnlp.converter.parser.ResourcesDesc.JARDesc; 48 import jnlp.converter.parser.XMLFormat; 49 50 public class JNLPConverter { 51 52 private final Options options; 53 private JNLPDesc jnlpd = null; 54 private final List<String> launchArgs = new ArrayList<>(); 55 56 private String downloadFolder = null; 57 private String jnlpDownloadFolder = null; 58 private static String jnlpDownloadFolderStatic; 59 private String jarDownloadFolder = null; 60 private String iconDownloadFolder = null; 61 private String propDownloadFolder = null; 62 63 private static String jpackagePath = null; 64 65 private static boolean markFileToDelete = false; 66 67 private static final String FA_EXTENSIONS = "extension"; 68 private static final String FA_CONTENT_TYPE = "mime-type"; 69 private static final String FA_DESCRIPTION = "description"; 70 private static final String FA_ICON = "icon"; 71 72 public JNLPConverter(Options options) { 73 this.options = options; 74 jnlpDownloadFolderStatic = getJnlpDownloadFolder(); 75 markFileToDelete = (options.keep() == null); 76 } 77 78 public String [] getLaunchArgs() { 79 return launchArgs.toArray(new String[0]); 80 } 81 82 public void convert() { 83 try { 84 loadJNLPDesc(); 85 downloadResources(); 86 validate(); 87 buildLaunchArgs(); 88 saveLaunchArgs(); 89 runJPackage(); 90 } catch (Exception ex) { 91 Log.error(ex.getMessage()); 92 } 93 } 94 95 private JNLPDesc getJNLPD(String jnlp) throws Exception { 96 URL codebase = getCodeBase(jnlp); 97 byte[] bits = HTTPHelper.getJNLPBits(jnlp, jnlp); 98 return XMLFormat.parse(bits, codebase, jnlp); 99 } 100 101 private void loadJNLPDesc() throws Exception { 102 String jnlp = options.getJNLP(); 103 jnlpd = getJNLPD(jnlp); 104 105 // Check for required options in case of FX 106 if (jnlpd.isFXApp()) { 107 if (!options.isRuntimeImageSet()) { 108 throw new Exception("This is a JavaFX Web-Start application which requires a runtime image capable of running JavaFX applications, which can be specified by the jpackage option --runtime-image (using --jpackage-options)."); 109 } 110 } 111 112 // Check href. It can be same as URL we provided or new one 113 // if JNLP has different href or codebase. We assume that 114 // XMLFormat.parse() will handle any errors in href and codebase 115 // correctly. 116 String href = jnlpd.getHref(); 117 if (href != null && !href.equalsIgnoreCase(jnlp)) { 118 if (href.startsWith("file:")) { 119 URI hrefURI = new URI(href); 120 URI jnlpURI = new URI(jnlp); 121 122 String hrefPath = hrefURI.getPath(); 123 String jnlpPath = jnlpURI.getPath(); 124 125 if (!hrefPath.equalsIgnoreCase(jnlpPath)) { 126 jnlp = href; 127 jnlpd = getJNLPD(jnlp); 128 } 129 } else { 130 jnlp = href; 131 jnlpd = getJNLPD(jnlp); 132 } 133 } 134 135 if (jnlpd.getName() == null) { 136 jnlpd.setName(getNameFromURL(jnlp)); 137 } 138 } 139 140 private static String getNameFromURL(String url) throws IOException { 141 int index; 142 int index1 = url.lastIndexOf('/'); 143 int index2 = url.lastIndexOf('\\'); 144 145 if (index1 >= index2) { 146 index = index1; 147 } else { 148 index = index2; 149 } 150 151 if (index != -1) { 152 String name = url.substring(index + 1, url.length()); 153 if (name.endsWith(".jnlp")) { 154 return name.substring(0, name.length() - 5); 155 } 156 } 157 158 return null; 159 } 160 161 private URL getCodeBase(String jnlp) throws Exception { 162 int index = jnlp.lastIndexOf('/'); 163 if (index != -1) { 164 if (HTTPHelper.isHTTPUrl(jnlp)) { 165 return new URL(jnlp.substring(0, index + 1)); 166 } else { 167 String codeBasePath = jnlp.substring(0, index); 168 if (!codeBasePath.endsWith("/")) { 169 codeBasePath += "/"; 170 } 171 return new URI(codeBasePath).toURL(); 172 } 173 } 174 175 return null; 176 } 177 178 public static void markFileToDelete(String file) { 179 if (file == null || file.isEmpty()) { 180 return; 181 } 182 183 if (markFileToDelete) { 184 try { 185 File f = new File(file); 186 f.deleteOnExit(); 187 } catch (Exception e) { 188 // Print exception, but do not fail conversion. 189 Log.warning(e.getLocalizedMessage()); 190 } 191 } 192 } 193 194 public static void deleteFile(String file) { 195 try { 196 File f = new File(file); 197 f.delete(); 198 } catch (Exception e) { 199 Log.warning(e.getLocalizedMessage()); 200 } 201 } 202 203 private void downloadResources() throws Exception { 204 List<JARDesc> jars = jnlpd.getResources(); 205 for (JARDesc jar : jars) { 206 if (jar.getVersion() != null) { 207 if (!jnlpd.isVersionEnabled()) { 208 throw new Exception("Error: Version based download protocol is not supported without -Djnlp.versionEnabled=true."); 209 } 210 } 211 212 String destFile = null; 213 if (HTTPHelper.isHTTPUrl(jar.getLocation().toString())) { 214 if (jar.getVersion() != null) { 215 try { 216 destFile = HTTPHelper.downloadFile(jar.getVersionLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); 217 } catch (HTTPHelperException ex) { 218 if (ex.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) { 219 System.out.println("Error downloading versioned JAR from " + jar.getVersionLocation()); 220 System.out.println(ex.getMessage()); 221 System.out.println("Downloading " + jar.getLocation() + " instead."); 222 destFile = HTTPHelper.downloadFile(jar.getLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); 223 } else { 224 throw ex; 225 } 226 } 227 } else { 228 destFile = HTTPHelper.downloadFile(jar.getLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); 229 } 230 markFileToDelete(destFile); 231 } else { 232 if (jar.getVersion() != null) { 233 try { 234 destFile = HTTPHelper.copyFile(jar.getVersionLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); 235 } catch (FileNotFoundException ex) { 236 System.out.println("Error copying versioned JAR from " + jar.getVersionLocation()); 237 System.out.println(ex.getMessage()); 238 System.out.println("Copying " + jar.getLocation() + " instead."); 239 destFile = HTTPHelper.copyFile(jar.getLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); 240 } 241 } else { 242 destFile = HTTPHelper.copyFile(jar.getLocation().toString(), getJarDownloadFolder(), HTTPHelper.getFileNameFromURL(jar.getLocation().toString())); 243 } 244 markFileToDelete(destFile); 245 } 246 247 if (jar.isNativeLib()) { 248 unpackNativeLib(destFile); 249 deleteFile(destFile); 250 } else { 251 jnlpd.addFile(jar.getName()); 252 } 253 } 254 255 IconDesc icon = jnlpd.getIcon(); 256 if (icon != null) { 257 String destFile; 258 259 if (HTTPHelper.isHTTPUrl(icon.getLocation())) { 260 destFile = HTTPHelper.downloadFile(icon.getLocation(), getIconDownloadFolder(), HTTPHelper.getFileNameFromURL(icon.getLocation())); 261 } else { 262 destFile = HTTPHelper.copyFile(icon.getLocation(), getIconDownloadFolder(), HTTPHelper.getFileNameFromURL(icon.getLocation())); 263 } 264 265 markFileToDelete(destFile); 266 icon.setLocalLocation(destFile); 267 } 268 269 AssociationDesc [] associations = jnlpd.getAssociations(); 270 if (associations != null) { 271 for (AssociationDesc association : associations) { 272 if (association.getIconUrl() != null) { 273 String destFile; 274 if (HTTPHelper.isHTTPUrl(association.getIconUrl())) { 275 destFile = HTTPHelper.downloadFile(association.getIconUrl(), getIconDownloadFolder(), HTTPHelper.getFileNameFromURL(association.getIconUrl())); 276 } else { 277 destFile = HTTPHelper.copyFile(association.getIconUrl(), getIconDownloadFolder(), HTTPHelper.getFileNameFromURL(association.getIconUrl())); 278 } 279 280 markFileToDelete(destFile); 281 association.setIconLocalLocation(destFile); 282 } 283 } 284 } 285 } 286 287 public void unpackNativeLib(String file) throws IOException { 288 try (JarFile jarFile = new JarFile(file)) { 289 Enumeration entries = jarFile.entries(); 290 291 while (entries.hasMoreElements()) { 292 JarEntry entry = (JarEntry) entries.nextElement(); 293 294 // Skip directories 295 if (entry.isDirectory()) { 296 continue; 297 } 298 299 String entryName = entry.getName(); 300 // Skip anything in sub-directories 301 if (entryName.contains("\\") || entryName.contains("/")) { 302 continue; 303 } 304 305 // Skip anything not ending with .dll, .dylib or .so 306 if (!entryName.endsWith(".dll") && !entryName.endsWith(".dylib") && !entryName.endsWith(".so")) { 307 continue; 308 } 309 310 File destFile = new File(getJarDownloadFolder(), entryName); 311 if (destFile.exists()) { 312 Log.warning(destFile.getAbsolutePath() + " already exist and will not be overwriten by native library from " + file + "."); 313 continue; 314 } 315 316 InputStream inputStream = jarFile.getInputStream(entry); 317 FileOutputStream outputStream = new FileOutputStream(destFile); 318 319 byte[] buffer = new byte[HTTPHelper.BUFFER_SIZE]; 320 int length; 321 do { 322 length = inputStream.read(buffer); 323 if (length > 0) { 324 outputStream.write(buffer, 0, length); 325 } 326 } while (length > 0); 327 328 jnlpd.addFile(entryName); 329 } 330 } 331 } 332 333 private void validate() { 334 if (jnlpd.getMainJar() == null) { 335 Log.error("Cannot find main jar"); 336 } 337 338 if (jnlpd.getMainClass() == null) { 339 Log.error("Cannot find main class"); 340 } 341 } 342 343 private void addLaunchArg(String arg, List<String> launchArgs) { 344 if (arg != null && !arg.isEmpty()) { 345 if (!options.isOptionPresent(arg)){ 346 launchArgs.add(arg); 347 } else { 348 Log.info(arg + " generated by JNLPConverter is dropped, since it is overwriten via --jpackage-options"); 349 } 350 } 351 } 352 353 private void addLaunchArg(String arg, String value, List<String> launchArgs) { 354 if (arg != null && !arg.isEmpty() && value != null && !value.isEmpty()) { 355 if (!options.isOptionPresent(arg)){ 356 launchArgs.add(arg); 357 launchArgs.add(value); 358 } else { 359 Log.info(arg + "=" + value +" generated by JNLPConverter is dropped, since it is overwriten via --jpackage-options"); 360 } 361 } 362 } 363 364 private void displayLaunchArgs() { 365 if (Log.isVerbose()) { 366 System.out.println(); 367 System.out.println("jpackage launch arguments (each argument starts on new line):"); 368 launchArgs.forEach((arg) -> { 369 System.out.println(arg); 370 }); 371 } 372 } 373 374 private static int fileAssociationsCount = 0; 375 private String getFileAssociationsFile() { 376 String file = getPropDownloadFolder(); 377 file += File.separator; 378 file += "fileAssociation"; 379 file += String.valueOf(fileAssociationsCount); 380 file += ".properties"; 381 382 fileAssociationsCount++; 383 384 return file; 385 } 386 387 private void buildLaunchArgs() { 388 if (options.createAppImage()) { 389 addLaunchArg("create-app-image", launchArgs); 390 } else if (options.createInstaller()) { 391 if (options.getInstallerType() == null) { 392 addLaunchArg("create-installer", launchArgs); 393 } else { 394 addLaunchArg("create-installer", launchArgs); 395 if (options.getInstallerType() != null) { 396 addLaunchArg("--installer-type", options.getInstallerType(), launchArgs); 397 } 398 } 399 } 400 401 // Set verbose for jpackage if it is set for us. 402 if (options.verbose()) { 403 addLaunchArg("--verbose", launchArgs); 404 } 405 406 addLaunchArg("--input", getJarDownloadFolder(), launchArgs); 407 addLaunchArg("--output", options.getOutput(), launchArgs); 408 addLaunchArg("--name", jnlpd.getName(), launchArgs); 409 addLaunchArg("--app-version", jnlpd.getVersion(), launchArgs); 410 addLaunchArg("--vendor", jnlpd.getVendor(), launchArgs); 411 addLaunchArg("--description", jnlpd.getDescription(), launchArgs); 412 addLaunchArg("--icon", jnlpd.getIconLocation(), launchArgs); 413 addLaunchArg("--main-jar", jnlpd.getMainJar(), launchArgs); 414 addLaunchArg("--main-class", jnlpd.getMainClass(), launchArgs); 415 416 addArguments(launchArgs); 417 addJVMArgs(launchArgs); 418 419 if (options.createInstaller()) { 420 if (jnlpd.isDesktopHint()) { 421 if (Platform.isWindows()) { 422 addLaunchArg("--win-shortcut", launchArgs); 423 } else { 424 Log.warning("Ignoring shortcut hint, since it is not supported on current platform."); 425 } 426 } 427 428 if (jnlpd.isMenuHint()) { 429 if (Platform.isWindows()) { 430 addLaunchArg("--win-menu", launchArgs); 431 addLaunchArg("--win-menu-group", jnlpd.getSubMenu(), launchArgs); 432 } else { 433 Log.warning("Ignoring menu hint, since it is not supported on current platform."); 434 } 435 } 436 437 AssociationDesc[] associations = jnlpd.getAssociations(); 438 if (associations != null) { 439 for (AssociationDesc association : associations) { 440 String file = getFileAssociationsFile(); 441 markFileToDelete(file); 442 443 try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)))) { 444 if (association.getExtensions() != null && association.getMimeType() != null) { 445 out.println(FA_EXTENSIONS + "=" + quote(association.getExtensions())); 446 out.println(FA_CONTENT_TYPE + "=" + quote(association.getMimeType())); 447 448 if (association.getMimeDescription() != null) { 449 out.println(FA_DESCRIPTION + "=" + association.getMimeDescription()); 450 } 451 452 if (association.getIconLocalLocation() != null) { 453 out.println(FA_ICON + "=" + quote(association.getIconLocalLocation())); 454 } 455 456 addLaunchArg("--file-associations", file, launchArgs); 457 } 458 } catch (Exception ex) { 459 Log.warning(ex.toString()); 460 if (association.getExtensions() != null) { 461 Log.warning("File assoication for " + association.getExtensions() + " will be ignored due to exception above."); 462 } 463 } 464 } 465 } 466 } 467 468 // Add options from --jpackage-options 469 List<String> jpackageOptions = options.getJPackageOptions(); 470 jpackageOptions.forEach((option) -> { 471 launchArgs.add(option); 472 }); 473 474 displayLaunchArgs(); 475 } 476 477 private String getCommandFileName() { 478 Platform platform = Platform.getPlatform(); 479 switch (platform) { 480 case WINDOWS: 481 return "run_jpackage.bat"; 482 case LINUX: 483 return "run_jpackage.sh"; 484 case MAC: 485 return "run_jpackage.sh"; 486 default: 487 Log.error("Cannot determine platform type."); 488 return ""; 489 } 490 } 491 492 private void saveLaunchArgs() { 493 if (options.keep() != null) { 494 File keepFolder = new File(options.keep()); 495 String cmdFile = keepFolder.getAbsolutePath() + File.separator + getCommandFileName(); 496 try (PrintWriter out = new PrintWriter(cmdFile)) { 497 out.print(getJPackagePath()); 498 launchArgs.forEach((arg) -> { 499 out.print(" "); 500 501 if (arg.contains(" ")) { 502 int len = arg.length(); 503 if (len >= 1) { 504 if (arg.charAt(0) != '"' && arg.charAt(len - 1) != '"') { 505 out.print("\"" + arg + "\""); 506 } else { 507 if (Platform.isWindows()) { 508 out.print(arg); 509 } else { 510 arg = escapeQuote(arg); 511 out.print("\"" + arg + "\""); 512 } 513 } 514 } 515 } else { 516 out.print(arg); 517 } 518 }); 519 } catch (FileNotFoundException ex) { 520 Log.error("Cannot save file with command line: " + ex.getLocalizedMessage()); 521 } 522 } 523 } 524 525 private void runJPackage() { 526 List<String> command = new ArrayList<>(); 527 command.add(getJPackagePath()); 528 command.addAll(launchArgs); 529 530 ProcessBuilder builder = new ProcessBuilder(); 531 builder.inheritIO(); 532 builder.command(command); 533 534 try { 535 Process process = builder.start(); 536 int exitCode = process.waitFor(); 537 if (exitCode != 0) { 538 Log.warning("jpackage retrun non zero code: " + exitCode); 539 } 540 } catch (IOException | InterruptedException ex) { 541 Log.error(ex.getMessage()); 542 } 543 } 544 545 private void addArguments(List<String> launchArgs) { 546 List<String> arguments = jnlpd.getArguments(); 547 if (arguments.isEmpty()) { 548 return; 549 } 550 551 String argsStr = ""; 552 for (int i = 0; i < arguments.size(); i++) { 553 String arg = arguments.get(i); 554 argsStr += quote(arg); 555 if ((i + 1) != arguments.size()) { 556 argsStr += " "; 557 } 558 } 559 560 launchArgs.add("--arguments"); 561 if (Platform.isWindows()) { 562 if (argsStr.contains(" ")) { 563 if (argsStr.contains("\"")) { 564 argsStr = escapeQuote(argsStr); 565 } 566 argsStr = "\"" + argsStr + "\""; 567 } 568 } 569 launchArgs.add(argsStr); 570 } 571 572 private void addJVMArgs(List<String> launchArgs) { 573 List<String> jvmArgs = jnlpd.getVMArgs(); 574 if (jvmArgs.isEmpty()) { 575 return; 576 } 577 578 String jvmArgsStr = ""; 579 for (int i = 0; i < jvmArgs.size(); i++) { 580 String arg = jvmArgs.get(i); 581 jvmArgsStr += quote(arg); 582 if ((i + 1) != jvmArgs.size()) { 583 jvmArgsStr += " "; 584 } 585 } 586 587 launchArgs.add("--java-options"); 588 if (Platform.isWindows()) { 589 if (jvmArgsStr.contains(" ")) { 590 if (jvmArgsStr.contains("\"")) { 591 jvmArgsStr = escapeQuote(jvmArgsStr); 592 } 593 jvmArgsStr = "\"" + jvmArgsStr + "\""; 594 } 595 } 596 launchArgs.add(jvmArgsStr); 597 } 598 599 private String quote(String in) { 600 if (in == null) { 601 return null; 602 } 603 604 if (in.isEmpty()) { 605 return ""; 606 } 607 608 if (!in.contains("=")) { 609 // Not a property 610 if (in.contains(" ")) { 611 in = escapeQuote(in); 612 return "\"" + in + "\""; 613 } 614 return in; 615 } 616 617 if (!in.contains(" ")) { 618 return in; // No need to quote 619 } 620 621 int paramIndex = in.indexOf("="); 622 if (paramIndex <= 0) { 623 return in; // Something wrong, just skip quoting 624 } 625 626 String param = in.substring(0, paramIndex); 627 String value = in.substring(paramIndex + 1); 628 629 if (value.length() == 0) { 630 return in; // No need to quote 631 } 632 633 value = escapeQuote(value); 634 635 return param + "=" + "\"" + value + "\""; 636 } 637 638 private String escapeQuote(String in) { 639 if (in == null) { 640 return null; 641 } 642 643 if (in.isEmpty()) { 644 return ""; 645 } 646 647 if (in.contains("\"")) { 648 // Use code points to preserve non-ASCII chars 649 StringBuilder sb = new StringBuilder(); 650 int codeLen = in.codePointCount(0, in.length()); 651 for (int i = 0; i < codeLen; i++) { 652 int code = in.codePointAt(i); 653 // Note: No need to escape '\' on Linux or OS X. 654 // jpackage expects us to pass arguments and properties with quotes and spaces as a map 655 // with quotes being escaped with additional \ for internal quotes. 656 // So if we want two properties below: 657 // -Djnlp.Prop1=Some "Value" 1 658 // -Djnlp.Prop2=Some Value 2 659 // jpackage will need: 660 // "-Djnlp.Prop1=\"Some \\"Value\\" 1\" -Djnlp.Prop2=\"Some Value 2\"" 661 // but since we using ProcessBuilder to run jpackage we will need to escape 662 // our escape symbols as well, so we will need to pass string below to ProcessBuilder: 663 // "-Djnlp.Prop1=\\\"Some \\\\\\\"Value\\\\\\\" 1\\\" -Djnlp.Prop2=\\\"Some Value 2\\\"" 664 switch (code) { 665 case '"': 666 // " -> \" -> \\\" 667 if (i == 0 || in.codePointAt(i - 1) != '\\') { 668 sb.appendCodePoint('\\'); 669 sb.appendCodePoint(code); 670 } 671 break; 672 case '\\': 673 // We need to escape already escaped symbols as well 674 if ((i + 1) < codeLen) { 675 int nextCode = in.codePointAt(i + 1); 676 if (nextCode == '"') { 677 // \" -> \\\" 678 sb.appendCodePoint('\\'); 679 sb.appendCodePoint('\\'); 680 sb.appendCodePoint('\\'); 681 sb.appendCodePoint(nextCode); 682 } else { 683 sb.appendCodePoint('\\'); 684 sb.appendCodePoint(code); 685 } 686 } else { 687 sb.appendCodePoint(code); 688 } 689 break; 690 default: 691 sb.appendCodePoint(code); 692 break; 693 } 694 } 695 return sb.toString(); 696 } 697 698 return in; 699 } 700 701 public synchronized String getDownloadFolder() { 702 if (downloadFolder == null) { 703 try { 704 File file; 705 if (options.keep() == null) { 706 Path path = Files.createTempDirectory("JNLPConverter"); 707 file = path.toFile(); 708 file.deleteOnExit(); 709 } else { 710 file = new File(options.keep()); 711 if (!file.exists()) { 712 file.mkdir(); 713 } 714 } 715 716 downloadFolder = file.getAbsolutePath(); 717 } catch (IOException e) { 718 Log.error(e.getMessage()); 719 } 720 } 721 722 return downloadFolder; 723 } 724 725 public final synchronized String getJnlpDownloadFolder() { 726 if (jnlpDownloadFolder == null) { 727 File file = new File(getDownloadFolder() + File.separator + "jnlp"); 728 file.mkdir(); 729 markFileToDelete(getDownloadFolder() + File.separator + "jnlp"); 730 jnlpDownloadFolder = file.getAbsolutePath(); 731 } 732 733 return jnlpDownloadFolder; 734 } 735 736 public static String getJnlpDownloadFolderStatic() { 737 return jnlpDownloadFolderStatic; 738 } 739 740 public synchronized String getJarDownloadFolder() { 741 if (jarDownloadFolder == null) { 742 File file = new File(getDownloadFolder() + File.separator + "jar"); 743 file.mkdir(); 744 markFileToDelete(getDownloadFolder() + File.separator + "jar"); 745 jarDownloadFolder = file.getAbsolutePath(); 746 } 747 748 return jarDownloadFolder; 749 } 750 751 public synchronized String getIconDownloadFolder() { 752 if (iconDownloadFolder == null) { 753 File file = new File(getDownloadFolder() + File.separator + "icon"); 754 file.mkdir(); 755 markFileToDelete(getDownloadFolder() + File.separator + "icon"); 756 iconDownloadFolder = file.getAbsolutePath(); 757 } 758 759 return iconDownloadFolder; 760 } 761 762 public synchronized String getPropDownloadFolder() { 763 if (propDownloadFolder == null) { 764 File file = new File(getDownloadFolder() + File.separator + "prop"); 765 file.mkdir(); 766 markFileToDelete(getDownloadFolder() + File.separator + "prop"); 767 propDownloadFolder = file.getAbsolutePath(); 768 } 769 770 return propDownloadFolder; 771 } 772 773 public synchronized static String getJPackagePath() { 774 if (jpackagePath == null) { 775 jpackagePath = System.getProperty("java.home"); 776 jpackagePath += File.separator; 777 jpackagePath += "bin"; 778 jpackagePath += File.separator; 779 780 Platform platform = Platform.getPlatform(); 781 switch (platform) { 782 case WINDOWS: 783 jpackagePath += "jpackage.exe"; 784 break; 785 case LINUX: 786 jpackagePath += "jpackage"; 787 break; 788 case MAC: 789 jpackagePath += "jpackage"; 790 break; 791 default: 792 Log.error("Cannot determine platform type."); 793 break; 794 } 795 796 Log.verbose("jpackage: " + jpackagePath); 797 } 798 799 return jpackagePath; 800 } 801 802 public static String getIconFormat(String icon) { 803 // GIF, JPEG, ICO, or PNG 804 if (icon.toLowerCase().endsWith(".gif")) { 805 return "GIF"; 806 } else if (icon.toLowerCase().endsWith(".jpg")) { 807 return "JPEG"; 808 } else if (icon.toLowerCase().endsWith(".ico")) { 809 return "ICO"; 810 } else if (icon.toLowerCase().endsWith(".png")) { 811 return "PNG"; 812 } 813 814 return "UNKNOWN"; 815 } 816 817 public static boolean isIconSupported(String icon) { 818 Platform platform = Platform.getPlatform(); 819 switch (platform) { 820 case WINDOWS: 821 if (icon.endsWith(".ico")) { 822 return true; 823 } else { 824 Log.warning("Icon file format (" + getIconFormat(icon) + ") is not supported on Windows for file " + icon + "."); 825 return false; 826 } 827 case LINUX: 828 if (icon.endsWith(".png")) { 829 return true; 830 } else { 831 Log.warning("Icon file format (" + getIconFormat(icon) + ") is not supported on Linux for file " + icon + "."); 832 return false; 833 } 834 case MAC: 835 Log.warning("Icon file format (" + getIconFormat(icon) + ") is not supported on OS X for file " + icon + "."); 836 return false; 837 } 838 839 return false; 840 } 841 }