1 /*
   2  * Copyright (c) 2011, 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
  23  * questions.
  24  */
  25 
  26 package com.sun.javafx.tools.packager;
  27 
  28 import com.oracle.tools.packager.*;
  29 import com.oracle.tools.packager.RelativeFileSet;
  30 import com.oracle.tools.packager.jnlp.JNLPBundler;
  31 import com.sun.javafx.tools.packager.bundlers.*;
  32 import com.sun.javafx.tools.packager.bundlers.Bundler.BundleType;
  33 import java.io.File;
  34 import java.util.ArrayList;
  35 import java.util.Arrays;
  36 import java.util.Collection;
  37 import java.util.LinkedHashMap;
  38 import java.util.LinkedHashSet;
  39 import java.util.LinkedList;
  40 import java.util.List;
  41 import java.util.Map;
  42 import java.util.Set;
  43 import java.util.TreeMap;
  44 import java.util.TreeSet;
  45 
  46 import jdk.packager.internal.JLinkBundlerHelper;
  47 
  48 import static com.oracle.tools.packager.jnlp.JNLPBundler.*;
  49 
  50 public class DeployParams extends CommonParams {
  51     public enum RunMode {
  52         WEBSTART, EMBEDDED, STANDALONE, ALL
  53     }
  54 
  55     final List<RelativeFileSet> resources = new ArrayList<>();
  56 
  57     String id;
  58     String title;
  59     String vendor;
  60     String email;
  61     String description;
  62     String category;
  63     String licenseType;
  64     String copyright;
  65     String version;
  66     Boolean systemWide;
  67     Boolean serviceHint;
  68     Boolean signBundle;
  69     Boolean installdirChooser;
  70 
  71     String applicationClass;
  72     String preloader;
  73 
  74     List<Param> params;
  75     List<HtmlParam> htmlParams;
  76     List<String> arguments; //unnamed arguments
  77 
  78     // Java 9 modules support
  79     Set<String> addModules = null;
  80     Set<String> limitModules = null;
  81     Boolean stripNativeCommands = null;
  82     Boolean detectmods = null;
  83     String modulePath = null;
  84     String module = null;
  85     String debugPort = null;
  86     String srcdir;
  87 
  88     int width;
  89     int height;
  90     String embeddedWidth = null;
  91     String embeddedHeight = null;
  92 
  93     String appName;
  94     String codebase;
  95 
  96     boolean embedJNLP = true;
  97     @Deprecated final boolean embedCertificates = false;
  98     boolean allPermissions = false;
  99     String updateMode = "background";
 100     boolean isExtension = false;
 101     boolean isSwingApp = false;
 102 
 103     Boolean needShortcut = null;
 104     Boolean needMenu = null;
 105     Boolean needInstall = null;
 106 
 107     String outfile;
 108     //if true then we cobundle js and image files needed
 109     // for web deployment with the application
 110     boolean includeDT;
 111 
 112     String placeholder = "'javafx-app-placeholder'";
 113     String appId = null;
 114 
 115     // didn't have a setter...
 116     boolean offlineAllowed = true;
 117 
 118     List<JSCallback> callbacks = null;
 119 
 120     //list of HTML templates to process
 121     List<Template> templates = new LinkedList<>();
 122 
 123     String jrePlatform = "1.8+";
 124     String fxPlatform = PackagerLib.JAVAFX_VERSION+"+";
 125     File javaRuntimeToUse = null;
 126     boolean javaRuntimeWasSet = false;
 127 
 128     //list of jvm args (in theory string can contain spaces and need to be escaped
 129     List<String> jvmargs = new LinkedList<>();
 130     Map<String, String> jvmUserArgs = new LinkedHashMap<>();
 131 
 132     //list of jvm properties (can also be passed as VM args
 133     // but keeping them separate make it a bit more convinient for JNLP generation)
 134     Map<String, String> properties = new LinkedHashMap<>();
 135 
 136     // raw arguments to the bundler
 137     Map<String, ? super Object> bundlerArguments = new LinkedHashMap<>();
 138 
 139     String fallbackApp = null;
 140 
 141     public void setJavaRuntimeSource(File src) {
 142         javaRuntimeToUse = src;
 143         javaRuntimeWasSet = true;
 144     }
 145 
 146     public void setCodebase(String codebase) {
 147         this.codebase = codebase;
 148     }
 149 
 150     public void setId(String id) {
 151         this.id = id;
 152     }
 153 
 154     public void setCategory(String category) {
 155         this.category = category;
 156     }
 157 
 158     public void setLicenseType(String licenseType) {
 159         this.licenseType = licenseType;
 160     }
 161 
 162     public void setCopyright(String copyright) {
 163         this.copyright = copyright;
 164     }
 165 
 166     public void setVersion(String version) {
 167         this.version = version;
 168     }
 169 
 170     public void setSystemWide(Boolean systemWide) {
 171         this.systemWide = systemWide;
 172     }
 173 
 174     public void setServiceHint(Boolean serviceHint) {
 175         this.serviceHint = serviceHint;
 176     }
 177 
 178     public void setInstalldirChooser(Boolean installdirChooser) {
 179         this.installdirChooser = installdirChooser;
 180     }
 181 
 182     public void setSignBundle(Boolean signBundle) {
 183         this.signBundle = signBundle;
 184     }
 185 
 186     public void setJRE(String v) {
 187         jrePlatform = v;
 188     }
 189 
 190     public void setSwingAppWithEmbeddedJavaFX(boolean v) {
 191         isSwingApp = v;
 192     }
 193 
 194     public void setNeedInstall(boolean b) {
 195         needInstall = b;
 196     }
 197 
 198     public void setOfflineAllowed(boolean b) {
 199         offlineAllowed = b;
 200     }
 201 
 202     public void setNeedShortcut(Boolean b) {
 203         needShortcut = b;
 204     }
 205 
 206     public void setNeedMenu(Boolean b) {
 207         needMenu = b;
 208     }
 209 
 210     public void setEmbeddedDimensions(String w, String h) {
 211         embeddedWidth = w;
 212         embeddedHeight = h;
 213     }
 214 
 215     public void setFallback(String v) {
 216         if (v == null) {
 217             return;
 218         }
 219 
 220         if ("none".equals(v) || "null".equals(v)) {
 221             fallbackApp = null;
 222         } else {
 223             fallbackApp = v;
 224         }
 225     }
 226 
 227     public void setJavafx(String v) {
 228         fxPlatform = v;
 229     }
 230 
 231     public void addJvmArg(String v) {
 232         jvmargs.add(v);
 233     }
 234 
 235     public void addJvmUserArg(String n, String v) {
 236         jvmUserArgs.put(n, v);
 237     }
 238 
 239     public void addJvmProperty(String n, String v) {
 240         properties.put(n, v);
 241     }
 242 
 243     public void setAllPermissions(boolean allPermissions) {
 244         this.allPermissions = allPermissions;
 245     }
 246 
 247     public void setAppName(String appName) {
 248         this.appName = appName;
 249     }
 250 
 251     public void setArguments(List<String> args) {
 252         this.arguments = args;
 253     }
 254 
 255     public void addAddModule(String module) {
 256         if (addModules == null) {
 257             addModules = new LinkedHashSet<>();
 258         }
 259 
 260         addModules.add(module);
 261     }
 262 
 263     public void addLimitModule(String module) {
 264         if (limitModules == null) {
 265             limitModules = new LinkedHashSet<>();
 266         }
 267 
 268         limitModules.add(module);
 269     }
 270 
 271     public void setModulePath(String value) {
 272         this.modulePath = value;
 273     }
 274 
 275     public void setModule(String value) {
 276         this.module = value;
 277     }
 278 
 279     public void setDebug(String value) {
 280         this.debugPort = value;
 281     }
 282 
 283     public void setStripNativeCommands(boolean value) {
 284         this.stripNativeCommands = value;
 285     }
 286 
 287     public void setDetectModules(boolean value) {
 288         this.detectmods = value;
 289     }
 290 
 291     public void setDescription(String description) {
 292         this.description = description;
 293     }
 294 
 295     public void setEmbedJNLP(boolean embedJNLP) {
 296         this.embedJNLP = embedJNLP;
 297     }
 298 
 299     @Deprecated
 300     public void setEmbedCertifcates(boolean v) {
 301         if (v) {
 302             System.out.println("JavaFX Packager no longer supports embedding certificates in JNLP files.  Setting will be ignored.");
 303         }
 304     }
 305 
 306     public void setPlaceholder(String p) {
 307         placeholder = p;
 308     }
 309 
 310     public void setAppId(String id) {
 311         appId = id;
 312     }
 313 
 314     public void setHeight(int height) {
 315         this.height = height;
 316     }
 317 
 318     public void setHtmlParams(List<HtmlParam> htmlParams) {
 319         this.htmlParams = htmlParams;
 320     }
 321 
 322     public void setOutfile(String outfile) {
 323         this.outfile = outfile;
 324     }
 325 
 326     public void setParams(List<Param> params) {
 327         this.params = params;
 328     }
 329 
 330     public void setPreloader(String preloader) {
 331         this.preloader = preloader;
 332     }
 333 
 334     public void setTitle(String title) {
 335         this.title = title;
 336     }
 337 
 338     public void setUpdateMode(String updateMode) {
 339         this.updateMode = updateMode;
 340     }
 341 
 342     public void setVendor(String vendor) {
 343         this.vendor = vendor;
 344     }
 345 
 346     public void setEmail(String email) {
 347         this.email = email;
 348     }
 349 
 350     public void setWidth(int width) {
 351         this.width = width;
 352     }
 353 
 354     public void setExtension(boolean isExtension) {
 355         this.isExtension = isExtension;
 356     }
 357 
 358     public void setApplicationClass(String applicationClass) {
 359         this.applicationClass = applicationClass;
 360     }
 361 
 362     public void setIncludeDT(boolean doEmbed) {
 363         includeDT = doEmbed;
 364     }
 365 
 366     public void setJSCallbacks(List<JSCallback> list) {
 367         callbacks = list;
 368     }
 369 
 370     public void addCallback(String name, String cmd) {
 371         if (callbacks == null) {
 372             callbacks = new ArrayList<>();
 373         }
 374 
 375         callbacks.add(new JSCallback(name, cmd));
 376     }
 377 
 378     static class Template {
 379         File in;
 380         File out;
 381 
 382         Template(File in, File out) {
 383             this.in = in;
 384             this.out = out;
 385         }
 386     }
 387 
 388     public void addTemplate(File in, File out) {
 389         templates.add(new Template(in, out));
 390     }
 391 
 392     //we need to expand as in some cases
 393     // (most notably javapackager)
 394     //we may get "." as filename and assumption is we include
 395     // everything in the given folder
 396     // (IOUtils.copyfiles() have recursive behavior)
 397     List<File> expandFileset(File root) {
 398         List<File> files = new LinkedList<>();
 399         if (com.oracle.tools.packager.IOUtils.isNotSymbolicLink(root)) {
 400             if (root.isDirectory()) {
 401                 File[] children = root.listFiles();
 402                 if (children != null) {
 403                     for (File f : children) {
 404                         files.addAll(expandFileset(f));
 405                     }
 406                 }
 407             } else {
 408                 files.add(root);
 409             }
 410         }
 411         return files;
 412     }
 413 
 414     @Override
 415     public void addResource(File baseDir, String path) {
 416         File file = new File(baseDir, path);
 417         //normalize top level dir
 418         // to strip things like "." in the path
 419         // or it can confuse symlink detection logic
 420         file = file.getAbsoluteFile();
 421 
 422         if (baseDir == null) {
 423             baseDir = file.getParentFile();
 424         }
 425         resources.add(new RelativeFileSet(baseDir, new LinkedHashSet<>(expandFileset(file))));
 426     }
 427 
 428     @Override
 429     public void addResource(File baseDir, File file) {
 430         //normalize initial file
 431         // to strip things like "." in the path
 432         // or it can confuse symlink detection logic
 433         file = file.getAbsoluteFile();
 434 
 435         if (baseDir == null) {
 436             baseDir = file.getParentFile();
 437         }
 438         resources.add(new RelativeFileSet(baseDir, new LinkedHashSet<>(expandFileset(file))));
 439     }
 440 
 441     public void addResource(File baseDir, String path, String type) {
 442         addResource(baseDir, createFile(baseDir, path), type);
 443     }
 444 
 445     public void addResource(File baseDir, File file, String type) {
 446         addResource(baseDir, file, "eager", type, null, null);
 447     }
 448 
 449     public void addResource(File baseDir, File file, String mode, String type, String os, String arch) {
 450         Set<File> singleFile = new LinkedHashSet<>();
 451         singleFile.add(file);
 452         if (baseDir == null) {
 453             baseDir = file.getParentFile();
 454         }
 455         RelativeFileSet rfs = new RelativeFileSet(baseDir, singleFile);
 456         rfs.setArch(arch);
 457         rfs.setMode(mode);
 458         rfs.setOs(os);
 459         rfs.setType(parseTypeFromString(type, file));
 460         resources.add(rfs);
 461     }
 462 
 463     private RelativeFileSet.Type parseTypeFromString(String type, File file) {
 464         if (type == null) {
 465             if (file.getName().endsWith(".jar")) {
 466                 return RelativeFileSet.Type.jar;
 467             } else if (file.getName().endsWith(".jnlp")) {
 468                 return RelativeFileSet.Type.jnlp;
 469             } else {
 470                 return RelativeFileSet.Type.UNKNOWN;
 471             }
 472         } else {
 473             return RelativeFileSet.Type.valueOf(type);
 474         }
 475     }
 476 
 477     private static File createFile(final File baseDir, final String path) {
 478         final File testFile = new File(path);
 479         return testFile.isAbsolute()
 480                 ? testFile
 481                 : new File(baseDir == null
 482                     ? null
 483                     : baseDir.getAbsolutePath(),
 484                       path);
 485     }
 486 
 487 
 488     @Override
 489     public void validate() throws PackagerException {
 490         if (outdir == null) {
 491             throw new PackagerException("ERR_MissingArgument", "-outdir");
 492         }
 493         if (outfile == null) {
 494             throw new PackagerException("ERR_MissingArgument", "-outfile");
 495         }
 496 
 497         if (module == null) {
 498             if (resources.isEmpty()) {
 499                 throw new PackagerException("ERR_MissingAppResources");
 500             }
 501             if (applicationClass == null) {
 502                 throw new PackagerException("ERR_MissingArgument", "-appclass");
 503             }
 504         }
 505     }
 506 
 507     public boolean validateForJNLP() {
 508         boolean result = false;
 509 
 510         // Success
 511         if (applicationClass != null && !applicationClass.isEmpty() &&
 512             (getBundleType() == BundleType.JNLP || getBundleType() == BundleType.ALL)) {
 513             result = true;
 514         }
 515 
 516         // Failed
 517         if ((module != null && !module.isEmpty()) ||
 518             (addModules != null && !addModules.isEmpty()) ||
 519             (limitModules != null && !limitModules.isEmpty()) |
 520             (modulePath != null && !modulePath.isEmpty()) ||
 521             getBundleType() == BundleType.INSTALLER ||
 522             getBundleType() == BundleType.NATIVE ||
 523             getBundleType() == BundleType.IMAGE) {
 524 
 525             result = false;
 526         }
 527 
 528         return result;
 529     }
 530 
 531     public boolean validateForBundle() {
 532         boolean result = false;
 533 
 534         // Success
 535         if (((applicationClass != null && !applicationClass.isEmpty()) ||
 536             !module.isEmpty())) {
 537             result = true;
 538         }
 539 
 540         return result;
 541     }
 542 
 543     //could be icon or splash
 544     static class Icon {
 545         final static int UNDEFINED = -1;
 546 
 547         String href;
 548         String kind;
 549         int width = UNDEFINED;
 550         int height = UNDEFINED;
 551         int depth = UNDEFINED;
 552         RunMode mode = RunMode.WEBSTART;
 553 
 554         Icon(String href, String kind, int w, int h, int d, RunMode m) {
 555             mode = m;
 556             this.href = href;
 557             this.kind = kind;
 558             if (w > 0) {
 559                 width = w;
 560             }
 561             if (h > 0) {
 562                 height = h;
 563             }
 564             if (d > 0) {
 565                 depth = d;
 566             }
 567         }
 568     }
 569 
 570     List<Icon> icons = new LinkedList<>();
 571 
 572     public void addIcon(String href, String kind, int w, int h, int d, RunMode m) {
 573         icons.add(new Icon(href, kind, w, h, d, m));
 574     }
 575 
 576     BundleType bundleType = BundleType.NONE;
 577     String targetFormat = null; //means any
 578 
 579     public void setBundleType(BundleType type) {
 580         bundleType = type;
 581     }
 582 
 583     public BundleType getBundleType() {
 584         return bundleType;
 585     }
 586 
 587     public void setTargetFormat(String t) {
 588         targetFormat = t;
 589     }
 590 
 591     public String getTargetFormat() {
 592         return targetFormat;
 593     }
 594 
 595     private String getArch() {
 596         String arch = System.getProperty("os.arch").toLowerCase();
 597 
 598         if ("x86".equals(arch) || "i386".equals(arch) || "i486".equals(arch)
 599                 || "i586".equals(arch) || "i686".equals(arch)) {
 600             arch = "x86";
 601         } else if ("x86_64".equals(arch) || "amd64".equals("arch")) {
 602             arch = "x86_64";
 603         }
 604 
 605         return arch;
 606     }
 607 
 608     static final Set<String> multi_args = new TreeSet<>(Arrays.asList(
 609             StandardBundlerParam.JVM_PROPERTIES.getID(),
 610             StandardBundlerParam.JVM_OPTIONS.getID(),
 611             StandardBundlerParam.USER_JVM_OPTIONS.getID(),
 612             StandardBundlerParam.ARGUMENTS.getID(),
 613             JLinkBundlerHelper.MODULE_PATH.getID(),
 614             JLinkBundlerHelper.ADD_MODULES.getID(),
 615             JLinkBundlerHelper.LIMIT_MODULES.getID(),
 616             JLinkBundlerHelper.STRIP_NATIVE_COMMANDS.getID(),
 617             JLinkBundlerHelper.DETECT_MODULES.getID()
 618     ));
 619 
 620     @SuppressWarnings("unchecked")
 621     public void addBundleArgument(String key, Object value) {
 622         // special hack for multi-line arguments
 623         if (multi_args.contains(key) && value instanceof String) {
 624             Object existingValue = bundlerArguments.get(key);
 625             if (existingValue instanceof String) {
 626                 bundlerArguments.put(key, existingValue + "\n\n" + value);
 627             } else if (existingValue instanceof List) {
 628                 ((List)existingValue).add(value);
 629             } else if (existingValue instanceof Map && ((String)value).contains("=")) {
 630                 String[] mapValues = ((String)value).split("=", 2);
 631                 ((Map)existingValue).put(mapValues[0], mapValues[1]);
 632             } else {
 633                 bundlerArguments.put(key, value);
 634             }
 635         } else {
 636             bundlerArguments.put(key, value);
 637         }
 638     }
 639 
 640     public BundleParams getBundleParams() {
 641         BundleParams bundleParams = new BundleParams();
 642 
 643         //construct app resources
 644         //  relative to output folder!
 645         String currentOS = System.getProperty("os.name").toLowerCase();
 646         String currentArch = getArch();
 647 
 648         for (RelativeFileSet rfs : resources) {
 649             String os = rfs.getOs();
 650             String arch = rfs.getArch();
 651             //skip resources for other OS
 652             // and nativelib jars (we are including raw libraries)
 653             if ((os == null || currentOS.contains(os.toLowerCase())) &&
 654                     (arch == null || currentArch.startsWith(arch.toLowerCase()))
 655                     && rfs.getType() != RelativeFileSet.Type.nativelib) {
 656                 if (rfs.getType() == RelativeFileSet.Type.license) {
 657                     for (String s : rfs.getIncludedFiles()) {
 658                         bundleParams.addLicenseFile(s);
 659                     }
 660                 }
 661             }
 662         }
 663 
 664         bundleParams.setAppResourcesList(resources);
 665 
 666         bundleParams.setIdentifier(id);
 667 
 668         if (javaRuntimeWasSet) {
 669             bundleParams.setRuntime(javaRuntimeToUse);
 670         }
 671         bundleParams.setApplicationClass(applicationClass);
 672         bundleParams.setPrelaoderClass(preloader);
 673         bundleParams.setName(this.appName);
 674         bundleParams.setAppVersion(version);
 675         bundleParams.setType(bundleType);
 676         bundleParams.setBundleFormat(targetFormat);
 677         bundleParams.setVendor(vendor);
 678         bundleParams.setEmail(email);
 679         bundleParams.setShortcutHint(needShortcut);
 680         bundleParams.setMenuHint(needMenu);
 681         putUnlessNull(INSTALL_HINT.getID(), needInstall);
 682         bundleParams.setSystemWide(systemWide);
 683         bundleParams.setServiceHint(serviceHint);
 684         bundleParams.setInstalldirChooser(installdirChooser);
 685         bundleParams.setSignBundle(signBundle);
 686         bundleParams.setCopyright(copyright);
 687         bundleParams.setApplicationCategory(category);
 688         bundleParams.setLicenseType(licenseType);
 689         bundleParams.setDescription(description);
 690         bundleParams.setTitle(title);
 691         if (verbose) bundleParams.setVerbose(true);
 692 
 693         bundleParams.setJvmProperties(properties);
 694         bundleParams.setJvmargs(jvmargs);
 695         bundleParams.setJvmUserArgs(jvmUserArgs);
 696         bundleParams.setArguments(arguments);
 697 
 698         if (addModules != null && !addModules.isEmpty()) {
 699             bundleParams.setAddModules(addModules);
 700         }
 701 
 702         if (limitModules != null && !limitModules.isEmpty()) {
 703             bundleParams.setLimitModules(limitModules);
 704         }
 705 
 706         if (stripNativeCommands != null) {
 707             bundleParams.setStripNativeCommands(stripNativeCommands);
 708         }
 709 
 710         bundleParams.setSrcDir(srcdir);
 711 
 712         if (modulePath != null && !modulePath.isEmpty()) {
 713             bundleParams.setModulePath(modulePath);
 714         }
 715 
 716         if (module != null && !module.isEmpty()) {
 717             bundleParams.setMainModule(module);
 718         }
 719 
 720         if (debugPort != null && !debugPort.isEmpty()) {
 721             bundleParams.setDebug(debugPort);
 722         }
 723 
 724         if (detectmods != null) {
 725             bundleParams.setDetectMods(detectmods);
 726         }
 727 
 728         File appIcon = null;
 729         List<Map<String, ? super Object>> bundlerIcons = new ArrayList<>();
 730         for (Icon ic: icons) {
 731             //NB: in theory we should be paying attention to RunMode but
 732             // currently everything is marked as webstart internally and runmode
 733             // is not publicly documented property
 734             if (/* (ic.mode == RunMode.ALL || ic.mode == RunMode.STANDALONE) && */
 735                 (ic.kind == null || ic.kind.equals("default")))
 736             {
 737                 //could be full path or something relative to the output folder
 738                 appIcon = new File(ic.href);
 739                 if (!appIcon.exists()) {
 740                     com.oracle.tools.packager.Log.debug("Icon [" + ic.href + "] is not valid absolute path. " +
 741                             "Assume it is relative to the output dir.");
 742                     appIcon = new File(outdir, ic.href);
 743                 }
 744             }
 745 
 746             Map<String, ? super Object> iconInfo = new TreeMap<>();
 747             if (ic.href != null) iconInfo.put(ICONS_HREF.getID(), ic.href);
 748             if (ic.kind != null) iconInfo.put(ICONS_KIND.getID(), ic.kind);
 749             if (ic.width > 0)    iconInfo.put(ICONS_WIDTH.getID(), Integer.toString(ic.width));
 750             if (ic.height > 0)   iconInfo.put(ICONS_HEIGHT.getID(), Integer.toString(ic.height));
 751             if (ic.depth > 0)    iconInfo.put(ICONS_DEPTH.getID(), Integer.toString(ic.depth));
 752 
 753             if (!iconInfo.isEmpty()) bundlerIcons.add(iconInfo);
 754         }
 755         putUnlessNullOrEmpty(ICONS.getID(), bundlerIcons);
 756 
 757         bundleParams.setIcon(appIcon);
 758 
 759         Map<String, String> paramsMap = new TreeMap<>();
 760         if (params != null) {
 761             for (Param p : params) {
 762                 paramsMap.put(p.name, p.value);
 763             }
 764         }
 765         putUnlessNullOrEmpty(JNLPBundler.APP_PARAMS.getID(), paramsMap);
 766 
 767         Map<String, String> unescapedHtmlParams = new TreeMap<>();
 768         Map<String, String> escapedHtmlParams = new TreeMap<>();
 769         if (htmlParams != null) {
 770             for (HtmlParam hp : htmlParams) {
 771                 if (hp.needEscape) {
 772                     escapedHtmlParams.put(hp.name, hp.value);
 773                 } else {
 774                     unescapedHtmlParams.put(hp.name, hp.value);
 775                 }
 776             }
 777         }
 778         putUnlessNullOrEmpty(JNLPBundler.APPLET_PARAMS.getID(), unescapedHtmlParams);
 779         putUnlessNullOrEmpty(ESCAPED_APPLET_PARAMS.getID(), escapedHtmlParams);
 780 
 781 
 782         putUnlessNull(WIDTH.getID(), width);
 783         putUnlessNull(HEIGHT.getID(), height);
 784         putUnlessNull(EMBEDDED_WIDTH.getID(), embeddedWidth);
 785         putUnlessNull(EMBEDDED_HEIGHT.getID(), embeddedHeight);
 786 
 787         putUnlessNull(CODEBASE.getID(), codebase);
 788         putUnlessNull(EMBED_JNLP.getID(), embedJNLP);
 789         // embedCertificates
 790         putUnlessNull(ALL_PERMISSIONS.getID(), allPermissions);
 791         putUnlessNull(UPDATE_MODE.getID(), updateMode);
 792         putUnlessNull(EXTENSION.getID(), isExtension);
 793         putUnlessNull(SWING_APP.getID(), isSwingApp);
 794 
 795         putUnlessNull(OUT_FILE.getID(), outfile);
 796         putUnlessNull(INCLUDE_DT.getID(), includeDT);
 797         putUnlessNull(PLACEHOLDER.getID(), placeholder);
 798         putUnlessNull(OFFLINE_ALLOWED.getID(), offlineAllowed);
 799 
 800         Map<String, String> callbacksMap = new TreeMap<>();
 801         if (callbacks != null) {
 802             for (JSCallback callback : callbacks) {
 803                 callbacksMap.put(callback.getName(), callback.getCmd());
 804             }
 805         }
 806         putUnlessNull(JS_CALLBACKS.getID(), callbacksMap);
 807 
 808         Map<File, File> templatesMap = new TreeMap<>();
 809         if (templates != null) {
 810             for (Template template : templates) {
 811                 templatesMap.put(template.in, template.out);
 812             }
 813         }
 814         putUnlessNull(TEMPLATES.getID(), templatesMap);
 815 
 816         putUnlessNull(FX_PLATFORM.getID(), fxPlatform);
 817         putUnlessNull(JRE_PLATFORM.getID(), jrePlatform);
 818 
 819         putUnlessNull(FALLBACK_APP.getID(), fallbackApp);
 820 
 821         // check for collisions
 822         TreeSet<String> keys = new TreeSet<>(bundlerArguments.keySet());
 823         keys.retainAll(bundleParams.getBundleParamsAsMap().keySet());
 824 
 825         if (!keys.isEmpty()) {
 826             throw new RuntimeException("Deploy Params and Bundler Arguments overlap in the following values:" + keys.toString());
 827         }
 828 
 829         bundleParams.addAllBundleParams(bundlerArguments);
 830 
 831         return bundleParams;
 832     }
 833 
 834     public void putUnlessNull(String param, Object value) {
 835         if (value != null) {
 836             bundlerArguments.put(param, value);
 837         }
 838     }
 839 
 840     public void putUnlessNullOrEmpty(String param, Map<?, ?> value) {
 841         if (value != null && !value.isEmpty()) {
 842             bundlerArguments.put(param, value);
 843         }
 844     }
 845 
 846     public void putUnlessNullOrEmpty(String param, Collection<?> value) {
 847         if (value != null && !value.isEmpty()) {
 848             bundlerArguments.put(param, value);
 849         }
 850     }
 851 }