1 /*
   2  * Copyright (c) 2018, 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.File;
  27 import java.util.ArrayList;
  28 import java.util.List;
  29 
  30 public class Options {
  31 
  32     private boolean createImage = false;
  33     private boolean createInstaller = false;
  34     private String installerType = null;
  35     private String jnlp = null;
  36     private String output = null;
  37     private String keep = null;
  38     private boolean help = false;
  39     private boolean verbose = false;
  40     private boolean version = false;
  41     private final List<String> jpackagerOptions = new ArrayList<>();
  42     private boolean isRuntimeImageSet = false;
  43 
  44     private static final String JNLP_OPTION_PREFIX = "--jnlp=";
  45     private static final String OUTPUT_OPTION_PREFIX = "--output=";
  46     private static final String KEEP_OPTION_PREFIX = "--keep=";
  47     private static final String JNLP_OPTION_SHORT_PREFIX = "-j";
  48     private static final String OUTPUT_OPTION_SHORT_PREFIX = "-o";
  49     private static final String KEEP_OPTION_SHORT_PREFIX = "-k";
  50 
  51     private static final String [] INSTALLER_TYPES = {"msi", "rpm", "deb",
  52                                                       "dmg", "pkg", "pkg-app-store"};
  53 
  54     // --output, -o, --input, -i, --files, -f, --main-jar, -j, --class, -c
  55     private static final String [] BLOCKED_JPACKAGER_OPTIONS = {"--output", "-o", "--input", "-i",
  56                                                                 "--files", "-f", "--main-jar",
  57                                                                 "-j", "--class", "-c"};
  58 
  59     private static final String RUNTIME_IMAGE_OPTION = "--runtime-image";
  60 
  61     private static final String ERR_UNKNOWN_OPTION = "Unknown option: ";
  62     private static final String ERR_MISSING_VALUE = "Value is required for option ";
  63     private static final String ERR_MISSING_MODE = "Error: create-image or create-installer mode is required";
  64     private static final String ERR_MISSING_JNLP = "Error: --jnlp is required";
  65     private static final String ERR_MISSING_OUTPUT = "Error: --output is required";
  66     private static final String ERR_OUTPUT_EXISTS = "Error: output folder already exists";
  67     private static final String ERR_KEEP_EXISTS = "Error: folder for --keep argument already exists";
  68     private static final String ERR_INVALID_PROTOCOL_JNLP = "Error: Invalid protocol for JNLP file. Only HTTP, HTTPS and FILE protocols are supported.";
  69 
  70     public boolean createImage() {
  71         return createImage;
  72     }
  73 
  74     public boolean createInstaller() {
  75         return createInstaller;
  76     }
  77 
  78     public String getInstallerType() {
  79         return installerType;
  80     }
  81 
  82     public String getJNLP() {
  83         return jnlp;
  84     }
  85 
  86     public String getOutput() {
  87         return output;
  88     }
  89 
  90     public String keep() {
  91         return keep;
  92     }
  93 
  94     public boolean help() {
  95         return help;
  96     }
  97 
  98     public boolean verbose() {
  99         return verbose;
 100     }
 101 
 102     public boolean version() {
 103         return version;
 104     }
 105 
 106     public List<String> getJPackagerOptions() {
 107         return jpackagerOptions;
 108     }
 109 
 110     public boolean isRuntimeImageSet() {
 111         return isRuntimeImageSet;
 112     }
 113 
 114     // Helper method to dump all options
 115     private void display() {
 116         System.out.println("Options:");
 117         System.out.println("createImage: " + createImage);
 118         System.out.println("createInstaller: " + createInstaller);
 119         System.out.println("installerType: " + installerType);
 120         System.out.println("jnlp: " + jnlp);
 121         System.out.println("output: " + output);
 122         System.out.println("keep: " + keep);
 123         System.out.println("help: " + help);
 124         System.out.println("verbose: " + verbose);
 125         System.out.println("version: " + version);
 126         for (int i = 0; i < jpackagerOptions.size(); i++) {
 127             System.out.println("jpackagerOptions[" + i + "]: " + jpackagerOptions.get(i));
 128         }
 129     }
 130 
 131     private void validate() {
 132         if (help || version) {
 133             return;
 134         }
 135 
 136         if (!createImage && !createInstaller) {
 137             optionError(ERR_MISSING_MODE);
 138         }
 139 
 140         if (jnlp == null) {
 141             optionError(ERR_MISSING_JNLP);
 142         } else {
 143             int index = jnlp.indexOf(":");
 144             if (index == -1 || index == 0) {
 145                 optionError(ERR_INVALID_PROTOCOL_JNLP);
 146             } else {
 147                 String protocol = jnlp.substring(0, index);
 148                 if (!protocol.equalsIgnoreCase("http") &&
 149                     !protocol.equalsIgnoreCase("https") &&
 150                     !protocol.equalsIgnoreCase("file")) {
 151                     optionError(ERR_INVALID_PROTOCOL_JNLP);
 152                 }
 153             }
 154         }
 155 
 156         if (output == null) {
 157             optionError(ERR_MISSING_OUTPUT);
 158         } else {
 159             File file = new File(output);
 160             if (file.exists()) {
 161                 optionErrorNoHelp(ERR_OUTPUT_EXISTS);
 162             }
 163         }
 164 
 165         if (keep != null) {
 166             File file = new File(keep);
 167             if (file.exists()) {
 168                 optionErrorNoHelp(ERR_KEEP_EXISTS);
 169             }
 170         }
 171 
 172         jpackagerOptions.forEach((option) -> {
 173             if (isBlockedOption(option)) {
 174                 Log.error(option + " is not allowed via --jpackager-options, since it will conflict with "
 175                         + "same option generated by JNLPConverter.");
 176             }
 177         });
 178     }
 179 
 180     public boolean isOptionPresent(String option) {
 181         for (String jpackagerOption : jpackagerOptions) {
 182             if (jpackagerOption.equalsIgnoreCase(option)) {
 183                 return true;
 184             }
 185         }
 186 
 187         return false;
 188     }
 189 
 190     private boolean isBlockedOption(String option) {
 191         for (String blockedOption : BLOCKED_JPACKAGER_OPTIONS) {
 192             if (blockedOption.equalsIgnoreCase(option)) {
 193                 return true;
 194             }
 195         }
 196 
 197         return false;
 198     }
 199 
 200     public static void showHelp() {
 201 //      System.out.println("********* Help should not be longer then 80 characters as per JEP-293 *********");
 202         System.out.println("Usage: java -jar JNLPConverter.jar <mode> <options>");
 203         System.out.println("");
 204         System.out.println("where mode is one of:");
 205         System.out.println("  create-image");
 206         System.out.println("          Generates a platform-specific application image.");
 207         System.out.println("  create-installer <type>");
 208         System.out.println("          Generates a platform-specific installer for the application.");
 209         System.out.println("          Valid values for \"type\" are \"msi\", \"rpm\", \"deb\", \"dmg\", \"pkg\",");
 210         System.out.println("          \"pkg-app-store\". If \"type\" is omitted, all supported types of installable");
 211         System.out.println("          packages for current platform will be generated.");
 212         System.out.println("");
 213         System.out.println("Possible options include:");
 214         System.out.println("  -j, --jnlp <path>");
 215         System.out.println("          Full path to JNLP file. Supported protocols are HTTP/HTTPS/FILE.");
 216         System.out.println("  -o, --output <path>");
 217         System.out.println("          Name of the directory where generated output files are placed.");
 218         System.out.println("  -k, --keep <path>");
 219         System.out.println("          Keep JNLP, JARs and command line arguments for jpackager");
 220         System.out.println("          in directory provided.");
 221         System.out.println("      --jpackager-options <options>");
 222         System.out.println("          Specify additional jpackager options or overwrite provided by JNLPConverter.");
 223         System.out.println("          All jpackager options can be specified except: --output -o, --input -i,");
 224         System.out.println("          --files -f, --main-jar -j and --class -c.");
 225         System.out.println("  -h, --help, -?");
 226         System.out.println("          Print this help message");
 227         System.out.println("  -v, --verbose");
 228         System.out.println("          Enable verbose output.");
 229         System.out.println("      --version");
 230         System.out.println("          Version information.");
 231         System.out.println("To specify an argument for a long option, you can use --<name>=<value> or");
 232         System.out.println("--<name> <value>.");
 233         System.out.println("To specify proxy server use standard Java properties http.proxyHost and http.proxyPort.");
 234     }
 235 
 236     private static boolean isInstallerType(String type) {
 237         for (String installerType : INSTALLER_TYPES) {
 238             if (installerType.equals(type)) {
 239                 return true;
 240             }
 241         }
 242 
 243         return false;
 244     }
 245 
 246     public static Options parseArgs(String[] args) {
 247         Options options = new Options();
 248 
 249         int index = 0;
 250         if (args.length >= 1) {
 251             switch (args[0]) {
 252                 case "create-image":
 253                     options.createImage = true;
 254                     index = 1;
 255                     break;
 256                 case "create-installer":
 257                     options.createInstaller = true;
 258                     index = 1;
 259                     if (args.length >= 2) {
 260                         if (isInstallerType(args[1])) {
 261                             options.installerType = args[1];
 262                             index = 2;
 263                         }
 264                     }
 265                     break;
 266                 case "-h":
 267                 case "--help":
 268                 case "-?":
 269                 case "--version":
 270                     break;
 271                 default:
 272                     optionError(Options.ERR_MISSING_MODE);
 273                     break;
 274             }
 275         }
 276 
 277         for (int i = index; i < args.length; i++) {
 278             String arg = args[i];
 279 
 280             if (arg.equals("--jnlp")) {
 281                 if (++i >= args.length) {
 282                     optionError(Options.ERR_MISSING_VALUE, "--jnlp");
 283                 }
 284                 options.jnlp = args[i];
 285             }  else if (arg.startsWith(JNLP_OPTION_PREFIX)) {
 286                 options.jnlp = arg.substring(JNLP_OPTION_PREFIX.length());
 287             } else if (arg.equals("--output")) {
 288                 if (++i >= args.length) {
 289                     optionError(Options.ERR_MISSING_VALUE, "--output");
 290                 }
 291                 options.output = args[i];
 292             } else if (arg.startsWith(OUTPUT_OPTION_PREFIX)) {
 293                 options.output = arg.substring(OUTPUT_OPTION_PREFIX.length());
 294             } else if (arg.equals("--keep")) {
 295                 if (++i >= args.length) {
 296                     optionError(Options.ERR_MISSING_VALUE, "--keep");
 297                 }
 298                 options.keep = args[i];
 299             } else if (arg.startsWith(KEEP_OPTION_PREFIX)) {
 300                 options.keep = arg.substring(KEEP_OPTION_PREFIX.length());
 301             } else if (arg.equals("--help")) {
 302                 options.help = true;
 303             } else if (arg.equals("--verbose")) {
 304                 options.verbose = true;
 305             } else if (arg.equals("--version")) {
 306                 options.version = true;
 307             } else if (arg.equals("-j")) { // short options
 308                 if (++i >= args.length) {
 309                     optionError(Options.ERR_MISSING_VALUE, "-j");
 310                 }
 311                 options.jnlp = args[i];
 312             } else if (arg.startsWith(JNLP_OPTION_SHORT_PREFIX)) {
 313                 options.jnlp = arg.substring(JNLP_OPTION_SHORT_PREFIX.length());
 314             } else if (arg.equals("-o")) {
 315                 if (++i >= args.length) {
 316                     optionError(Options.ERR_MISSING_VALUE, "-o");
 317                 }
 318                 options.output = args[i];
 319             } else if (arg.startsWith(OUTPUT_OPTION_SHORT_PREFIX)) {
 320                 options.output = arg.substring(OUTPUT_OPTION_SHORT_PREFIX.length());
 321             } else if (arg.equals("-k")) {
 322                 if (++i >= args.length) {
 323                     optionError(Options.ERR_MISSING_VALUE, "-k");
 324                 }
 325                 options.keep = args[i];
 326             } else if (arg.startsWith(KEEP_OPTION_SHORT_PREFIX)) {
 327                 options.keep = arg.substring(KEEP_OPTION_SHORT_PREFIX.length());
 328             } else if (arg.equals("-h") || arg.equals("-?")) {
 329                 options.help = true;
 330             } else if (arg.equals("-v")) {
 331                 options.verbose = true;
 332             } else if (arg.equals("--jpackager-options")) {
 333                 for (i = (i + 1); i < args.length; i++) {
 334                     if (!options.isRuntimeImageSet) {
 335                         if (args[i].equals(RUNTIME_IMAGE_OPTION)) {
 336                             options.isRuntimeImageSet = true;
 337                         }
 338                     }
 339                     options.jpackagerOptions.add(args[i]);
 340                 }
 341             } else {
 342                 optionError(ERR_UNKNOWN_OPTION, arg);
 343             }
 344         }
 345 
 346         //options.display(); // For testing only
 347         options.validate();
 348 
 349         return options;
 350     }
 351 
 352     private static void optionErrorNoHelp(String msg) {
 353         System.out.println(msg);
 354         System.exit(1);
 355     }
 356 
 357     private static void optionError(String msg) {
 358         System.out.println(msg);
 359         System.out.println();
 360         showHelp();
 361         System.exit(1);
 362     }
 363 
 364     private static void optionError(String msg, String option) {
 365         System.out.println(msg + option);
 366         System.out.println();
 367         showHelp();
 368         System.exit(1);
 369     }
 370 }