1 /*
   2  * Copyright (c) 2011, 2014, 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.sun.javafx.tools.ant.Callback;
  29 import com.sun.javafx.tools.packager.bundlers.*;
  30 import com.sun.javafx.tools.resource.DeployResource;
  31 import java.io.File;
  32 import java.io.IOException;
  33 import java.util.ArrayList;
  34 import java.util.HashMap;
  35 import java.util.HashSet;
  36 import java.util.LinkedList;
  37 import java.util.List;
  38 import java.util.Map;
  39 import java.util.Set;
  40 import java.util.TreeSet;
  41 
  42 public class DeployParams extends CommonParams {
  43     public enum RunMode {
  44         WEBSTART, EMBEDDED, STANDALONE, ALL
  45     }
  46 
  47     final List<DeployResource> resources = new ArrayList<>();
  48 
  49     String id;
  50     String title;
  51     String vendor;
  52     String email;
  53     String description;
  54     String category;
  55     String licenseType;
  56     String copyright;
  57     String version;
  58     Boolean systemWide;
  59 
  60     String applicationClass;
  61     String preloader;
  62 
  63     List<Param> params;
  64     List<HtmlParam> htmlParams;
  65     List<String> arguments; //unnamed arguments
  66 
  67     int width;
  68     int height;
  69     String embeddedWidth = null;
  70     String embeddedHeight = null;
  71 
  72     String appName;
  73     String codebase;
  74 
  75     boolean embedJNLP = true;
  76     boolean embedCertificates = false;
  77     boolean allPermissions = false;
  78     String updateMode = "background";
  79     boolean isExtension = false;
  80     boolean isSwingApp = false;
  81 
  82     boolean needShortcut = false;
  83     boolean needMenu = false;
  84     boolean needInstall = false;
  85 
  86     String outfile;
  87     //if true then we cobundle js and image files needed
  88     // for web deployment with the application
  89     boolean includeDT;
  90 
  91     String placeholder = null;
  92     String appId = null;
  93 
  94     // didn't have a setter...
  95     boolean offlineAllowed = true;
  96 
  97     List<JSCallback> callbacks;
  98 
  99     //list of HTML templates to process
 100     List<Template> templates = new LinkedList<>();
 101 
 102     String jrePlatform = "1.6+";
 103     String fxPlatform = PackagerLib.JAVAFX_VERSION+"+";
 104     File javaRuntimeToUse = null;
 105     boolean javaRuntimeWasSet = false;
 106 
 107     //list of jvm args (in theory string can contain spaces and need to be escaped
 108     List<String> jvmargs = new LinkedList<>();
 109     Map<String, String> jvmUserArgs = new HashMap<>();
 110 
 111     //list of jvm properties (can also be passed as VM args
 112     // but keeping them separate make it a bit more convinient for JNLP generation)
 113     Map<String, String> properties = new HashMap<>();
 114     
 115     // raw arguments to the bundler
 116     Map<String, ? super Object> bundlerArguments = new HashMap<>();
 117 
 118     String fallbackApp = "com.javafx.main.NoJavaFXFallback";
 119 
 120     public void setJavaRuntimeSource(File src) {
 121         javaRuntimeToUse = src;
 122         javaRuntimeWasSet = true;
 123     }
 124 
 125     public void setCodebase(String codebase) {
 126         this.codebase = codebase;
 127     }
 128 
 129     public void setId(String id) {
 130         this.id = id;
 131     }
 132 
 133     public void setCategory(String category) {
 134         this.category = category;
 135     }
 136 
 137     public void setLicenseType(String licenseType) {
 138         this.licenseType = licenseType;
 139     }
 140 
 141     public void setCopyright(String copyright) {
 142         this.copyright = copyright;
 143     }
 144 
 145     public void setVersion(String version) {
 146         this.version = version;
 147     }
 148 
 149     public void setSystemWide(Boolean systemWide) {
 150         this.systemWide = systemWide;
 151     }
 152 
 153     public void setJRE(String v) {
 154         jrePlatform = v;
 155     }
 156 
 157     public void setSwingAppWithEmbeddedJavaFX(boolean v) {
 158         isSwingApp = v;
 159     }
 160 
 161     public void setNeedInstall(boolean b) {
 162         needInstall = b;
 163     }
 164 
 165     public void setOfflineAllowed(boolean b) {
 166         offlineAllowed = b;
 167     }
 168 
 169     public void setNeedShortcut(boolean b) {
 170         needShortcut = b;
 171     }
 172 
 173     public void setNeedMenu(boolean b) {
 174         needMenu = b;
 175     }
 176 
 177     public void setEmbeddedDimensions(String w, String h) {
 178         embeddedWidth = w;
 179         embeddedHeight = h;
 180     }
 181 
 182     public void setFallback(String v) {
 183         if (v == null) {
 184             return;
 185         }
 186 
 187         if ("none".equals(v) || "null".equals(v)) {
 188             fallbackApp = null;
 189         } else {
 190             fallbackApp = v;
 191         }
 192     }
 193 
 194     public void setJavafx(String v) {
 195         fxPlatform = v;
 196     }
 197 
 198     public void addJvmArg(String v) {
 199         jvmargs.add(v);
 200     }
 201 
 202     public void addJvmUserArg(String n, String v) {
 203         jvmUserArgs.put(n, v);
 204     }
 205 
 206     public void addJvmProperty(String n, String v) {
 207         properties.put(n, v);
 208     }
 209 
 210     public void setAllPermissions(boolean allPermissions) {
 211         this.allPermissions = allPermissions;
 212     }
 213 
 214     public void setAppName(String appName) {
 215         this.appName = appName;
 216     }
 217 
 218     public void setArguments(List<String> args) {
 219         this.arguments = args;
 220     }
 221 
 222     public void setDescription(String description) {
 223         this.description = description;
 224     }
 225 
 226     public void setEmbedJNLP(boolean embedJNLP) {
 227         this.embedJNLP = embedJNLP;
 228     }
 229 
 230     public void setEmbedCertifcates(boolean v) {
 231         embedCertificates = v;
 232     }
 233 
 234     public void setPlaceholder(String p) {
 235         placeholder = p;
 236     }
 237 
 238     public void setAppId(String id) {
 239         appId = id;
 240     }
 241 
 242     public void setHeight(int height) {
 243         this.height = height;
 244     }
 245 
 246     public void setHtmlParams(List<HtmlParam> htmlParams) {
 247         this.htmlParams = htmlParams;
 248     }
 249 
 250     public void setOutfile(String outfile) {
 251         this.outfile = outfile;
 252     }
 253 
 254     public void setParams(List<Param> params) {
 255         this.params = params;
 256     }
 257 
 258     public void setPreloader(String preloader) {
 259         this.preloader = preloader;
 260     }
 261 
 262     public void setTitle(String title) {
 263         this.title = title;
 264     }
 265 
 266     public void setUpdateMode(String updateMode) {
 267         this.updateMode = updateMode;
 268     }
 269 
 270     public void setVendor(String vendor) {
 271         this.vendor = vendor;
 272     }
 273 
 274     public void setEmail(String email) {
 275         this.email = email;
 276     }
 277 
 278     public void setWidth(int width) {
 279         this.width = width;
 280     }
 281 
 282     public void setExtension(boolean isExtension) {
 283         this.isExtension = isExtension;
 284     }
 285 
 286     public void setApplicationClass(String applicationClass) {
 287         this.applicationClass = applicationClass;
 288     }
 289 
 290     public void setIncludeDT(boolean doEmbed) {
 291         includeDT = doEmbed;
 292     }
 293 
 294     public void setJSCallbacks(List<JSCallback> list) {
 295         callbacks = list;
 296     }
 297 
 298     public void setCallbacks(List<Callback> list) {
 299         List<JSCallback> jslist = new ArrayList<>(list.size());
 300         for (Callback cb: list) {
 301             jslist.add(new JSCallback(cb.getName(), cb.getCmd()));
 302         }
 303         callbacks = jslist;
 304     }
 305 
 306     static class Template {
 307         File in;
 308         File out;
 309 
 310         Template(File in, File out) {
 311             this.in = in;
 312             this.out = out;
 313         }
 314     }
 315 
 316     public void addTemplate(File in, File out) {
 317         templates.add(new Template(in, out));
 318     }
 319 
 320     //we need to expand as in some cases
 321     // (most notably javafxpackager)
 322     //we may get "." as filename and assumption is we include
 323     // everything in the given folder
 324     // (IOUtils.copyfiles() have recursive behavior)
 325     List<File> expandFileset(File root) {
 326         List<File> files = new LinkedList<>();
 327         if (IOUtils.isNotSymbolicLink(root)) {
 328            if (root.isDirectory()) {
 329                File[] children = root.listFiles();
 330                if (children != null) {
 331                    for (File f : children) {
 332                        files.addAll(expandFileset(f));
 333                    }
 334                }
 335            } else {
 336                files.add(root);
 337            }
 338         }
 339         return files;
 340     }
 341 
 342     @Override
 343     public void addResource(File baseDir, String path) {
 344         File file = new File(baseDir, path);
 345         try {
 346             //normalize top level dir
 347             // to strip things like "." in the path
 348             // or it can confuse symlink detection logic
 349             file = file.getCanonicalFile();
 350         } catch (IOException ignored) {}
 351         for (File f: expandFileset(file)) {
 352            resources.add(new DeployResource(baseDir, f));
 353         }
 354     }
 355 
 356     @Override
 357     public void addResource(File baseDir, File file) {
 358         try {
 359             //normalize initial file
 360             // to strip things like "." in the path
 361             // or it can confuse symlink detection logic
 362             file = file.getCanonicalFile();
 363         } catch (IOException ignored) {}
 364         for (File f: expandFileset(file)) {
 365            resources.add(new DeployResource(baseDir, f));
 366         }
 367     }
 368 
 369     public void addResource(File baseDir, String path, String type) {
 370         resources.add(new DeployResource(baseDir, path, type));
 371     }
 372 
 373     public void addResource(File baseDir, File file, String type) {
 374         resources.add(new DeployResource(baseDir, file, type));
 375     }
 376 
 377     public void addResource(File baseDir, File file, String mode, String type, String os, String arch) {
 378         resources.add(new DeployResource(baseDir, file, mode, type, os, arch));
 379     }
 380 
 381     @Override
 382     public void validate() throws PackagerException {
 383         if (outdir == null) {
 384             throw new PackagerException("ERR_MissingArgument", "-outdir");
 385         }
 386         if (outfile == null) {
 387             throw new PackagerException("ERR_MissingArgument", "-outfile");
 388         }
 389         if (resources.isEmpty()) {
 390             throw new PackagerException("ERR_MissingAppResources");
 391         }
 392         if (applicationClass == null) {
 393             throw new PackagerException("ERR_MissingArgument", "-appclass");
 394         }
 395     }
 396 
 397     //could be icon or splash
 398     static class Icon {
 399         final static int UNDEFINED = -1;
 400 
 401         String href;
 402         String kind;
 403         int width = UNDEFINED;
 404         int height = UNDEFINED;
 405         int depth = UNDEFINED;
 406         RunMode mode = RunMode.WEBSTART;
 407 
 408         Icon(String href, String kind, int w, int h, int d, RunMode m) {
 409             mode = m;
 410             this.href = href;
 411             this.kind = kind;
 412             if (w > 0) {
 413                 width = w;
 414             }
 415             if (h > 0) {
 416                 height = h;
 417             }
 418             if (d > 0) {
 419                 depth = d;
 420             }
 421         }
 422     }
 423 
 424     List<Icon> icons = new LinkedList<>();
 425 
 426     public void addIcon(String href, String kind, int w, int h, int d, RunMode m) {
 427         icons.add(new Icon(href, kind, w, h, d, m));
 428     }
 429 
 430     BundleType bundleType = BundleType.NONE;
 431     String targetFormat = null; //means any
 432 
 433     public void setBundleType(BundleType type) {
 434         bundleType = type;
 435     }
 436     
 437     public BundleType getBundleType() {
 438         return bundleType;
 439     }
 440 
 441     public void setTargetFormat(String t) {
 442         targetFormat = t;
 443     }
 444 
 445     public String getTargetFormat() {
 446         return targetFormat;
 447     }
 448 
 449     private String getArch() {
 450         String arch = System.getProperty("os.arch").toLowerCase();
 451 
 452         if ("x86".equals(arch) || "i386".equals(arch) || "i486".equals(arch)
 453                 || "i586".equals(arch) || "i686".equals(arch)) {
 454             arch = "x86";
 455         } else if ("x86_64".equals(arch) || "amd64".equals("arch")) {
 456             arch = "x86_64";
 457         }
 458 
 459         return arch;
 460     }
 461     
 462     public void addBundleArgument(String key, String value) {
 463         bundlerArguments.put(key, value);
 464     }
 465 
 466     public BundleParams getBundleParams() {
 467         if (bundleType != BundleType.NONE) {
 468             BundleParams bundleParams = new BundleParams();
 469 
 470             //construct app resources
 471             //  relative to output folder!
 472             Set<File> files = new HashSet<>();
 473             String currentOS = System.getProperty("os.name").toLowerCase();
 474             String currentArch = getArch();
 475 
 476             for (DeployResource r: resources) {
 477                 String os = r.getOs();
 478                 String arch = r.getArch();
 479                 //skip resources for other OS
 480                 // and nativelib jars (we are including raw libraries)
 481                 if ((os == null || currentOS.contains(os.toLowerCase())) &&
 482                         (arch == null || currentArch.startsWith(arch.toLowerCase()))
 483                         && r.getType() != DeployResource.Type.nativelib) {
 484                     files.add(new File(outdir, r.getRelativePath()));
 485                     if (r.getType() == DeployResource.Type.license) {
 486                         bundleParams.addLicenseFile(r.getRelativePath());
 487                     }
 488                 }
 489             }
 490             RelativeFileSet appResources = new RelativeFileSet(outdir, files);
 491 
 492             bundleParams.setIdentifier(id);
 493             bundleParams.setAppResource(appResources);
 494 
 495             if (javaRuntimeWasSet) {
 496                 bundleParams.setRuntime(javaRuntimeToUse);
 497             } else {
 498                 bundleParams.setDefaultRuntime();
 499             }
 500             bundleParams.setApplicationClass(applicationClass);
 501             bundleParams.setName(this.appName);
 502             bundleParams.setAppVersion(version);
 503             bundleParams.setType(bundleType);
 504             bundleParams.setBundleFormat(targetFormat);
 505             bundleParams.setVendor(vendor);
 506             bundleParams.setEmail(email);
 507             bundleParams.setShortcutHint(needShortcut);
 508             bundleParams.setMenuHint(needMenu);
 509             bundleParams.setSystemWide(systemWide);
 510             bundleParams.setCopyright(copyright);
 511             bundleParams.setApplicationCategory(category);
 512             bundleParams.setLicenseType(licenseType);
 513             bundleParams.setDescription(description);
 514             bundleParams.setTitle(title);
 515 
 516             bundleParams.setJvmProperties(properties);
 517             bundleParams.setJvmargs(jvmargs);
 518             bundleParams.setJvmUserArgs(jvmUserArgs);
 519 
 520             File appIcon = null;
 521             for (Icon ic: icons) {
 522                 //NB: in theory we should be paying attention to RunMode but
 523                 // currently everything is marked as webstart internally and runmode
 524                 // is not publicly documented property
 525                 if (/* (ic.mode == RunMode.ALL || ic.mode == RunMode.STANDALONE) && */
 526                     (ic.kind == null || ic.kind.equals("default"))) {
 527                     //could be full path or something relative to the output folder
 528                     appIcon = new File(ic.href);
 529                     if (!appIcon.exists()) {
 530                         Log.debug("Icon ["+ic.href+"] is not valid absolute path. "+
 531                                 "Assume it is relative to the output dir.");
 532                         appIcon = new File(outdir, ic.href);
 533                     }
 534                 }
 535             }
 536 
 537             bundleParams.setIcon(appIcon);
 538 
 539             // check for collisions
 540             TreeSet<String> keys = new TreeSet<>(bundlerArguments.keySet());
 541             keys.retainAll(bundleParams.getBundleParamsAsMap().keySet());
 542 
 543             if (!keys.isEmpty()) {
 544                 throw new RuntimeException("Deploy Params and Bundler Arguments overlap in the following values:" + keys.toString());
 545             }
 546             
 547             bundleParams.addAllBundleParams(bundlerArguments);
 548             
 549             return bundleParams;
 550         } else {
 551             return null;
 552         }
 553     }
 554 }