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