1 /* 2 * Copyright (c) 2012, 2017, 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.bundlers; 27 28 import com.oracle.tools.packager.*; 29 import com.sun.javafx.tools.packager.bundlers.Bundler.BundleType; 30 31 import java.io.File; 32 import java.io.IOException; 33 import java.util.*; 34 import java.util.jar.Attributes; 35 import java.util.jar.JarFile; 36 import java.util.jar.Manifest; 37 38 import static com.oracle.tools.packager.StandardBundlerParam.*; 39 40 import jdk.packager.internal.legacy.JLinkBundlerHelper; 41 42 /** 43 * @deprecated use {@link ToolProvider} to locate the {@code "javapackager"} tool instead. 44 */ 45 @Deprecated(since="10", forRemoval=true) 46 public class BundleParams { 47 48 final protected Map<String, ? super Object> params; 49 50 public static final String PARAM_RUNTIME = "runtime"; // RelativeFileSet 51 public static final String PARAM_APP_RESOURCES = "appResources"; // RelativeFileSet 52 public static final String PARAM_TYPE = "type"; // BundlerType 53 public static final String PARAM_BUNDLE_FORMAT = "bundleFormat"; // String 54 public static final String PARAM_ICON = "icon"; // String 55 56 /* Name of bundle file and native launcher */ 57 public static final String PARAM_NAME = "name"; // String 58 59 /* application vendor, used by most of the bundlers */ 60 public static final String PARAM_VENDOR = "vendor"; // String 61 62 /* email name and email, only used for debian */ 63 public static final String PARAM_EMAIL = "email"; // String 64 65 /* Copyright. Used on Mac */ 66 public static final String PARAM_COPYRIGHT = "copyright"; // String 67 68 /* GUID on windows for MSI, CFBundleIdentifier on Mac 69 If not compatible with requirements then bundler either do not bundle 70 or autogenerate */ 71 public static final String PARAM_IDENTIFIER = "identifier"; // String 72 73 /* shortcut preferences */ 74 public static final String PARAM_SHORTCUT = "shortcutHint"; // boolean 75 public static final String PARAM_MENU = "menuHint"; // boolean 76 77 /* Application version. Format may differ for different bundlers */ 78 public static final String PARAM_VERSION = "appVersion"; // String 79 /* Application category. Used at least on Mac/Linux. Value is platform specific */ 80 public static final String PARAM_CATEGORY = "applicationCategory"; // String 81 82 /* Optional short application */ 83 public static final String PARAM_TITLE = "title"; // String 84 85 /* Optional application description. Used by MSI and on Linux */ 86 public static final String PARAM_DESCRIPTION = "description"; // String 87 88 /* License type. Needed on Linux (rpm) */ 89 public static final String PARAM_LICENSE_TYPE = "licenseType"; // String 90 91 /* File(s) with license. Format is OS/bundler specific */ 92 public static final String PARAM_LICENSE_FILE = "licenseFile"; // List<String> 93 94 /* user or system level install. 95 null means "default" */ 96 public static final String PARAM_SYSTEM_WIDE = "systemWide"; // Boolean 97 98 /* service/daemon install. 99 null means "default" */ 100 public static final String PARAM_SERVICE_HINT = "serviceHint"; // Boolean 101 102 103 /* Main application class. Not used directly but used to derive default values */ 104 public static final String PARAM_APPLICATION_CLASS = "applicationClass"; // String 105 106 /* Adds a dialog to let the user choose a directory where the product will be installed. */ 107 public static final String PARAM_INSTALLDIR_CHOOSER = "installdirChooser"; // Boolean 108 109 /* Prevents from launching multiple instances of application. */ 110 public static final String PARAM_SINGLETON = "singleton"; // Boolean 111 112 /** 113 * create a new bundle with all default values 114 */ 115 public BundleParams() { 116 params = new HashMap<>(); 117 } 118 119 /** 120 * Create a bundle params with a copy of the params 121 * @param params map of initial parameters to be copied in. 122 */ 123 public BundleParams(Map<String, ?> params) { 124 this.params = new HashMap<>(params); 125 } 126 127 public void addAllBundleParams(Map<String, ? super Object> p) { 128 params.putAll(p); 129 } 130 131 public <C> C fetchParam(BundlerParamInfo<C> paramInfo) { 132 return paramInfo.fetchFrom(params); 133 } 134 135 @SuppressWarnings("unchecked") 136 public <C> C fetchParamWithDefault(Class<C> klass, C defaultValue, String... keys) { 137 for (String key : keys) { 138 Object o = params.get(key); 139 if (klass.isInstance(o)) { 140 return (C) o; 141 } 142 else if (params.containsKey(keys) && o == null) { 143 return null; 144 } 145 //else if (o != null) { 146 //TODO log an error. 147 //} 148 } 149 return defaultValue; 150 } 151 152 public <C> C fetchParam(Class<C> klass, String... keys) { 153 return fetchParamWithDefault(klass, null, keys); 154 } 155 156 //NOTE: we do not care about application parameters here 157 // as they will be embeded into jar file manifest and 158 // java launcher will take care of them! 159 160 public Map<String, ? super Object> getBundleParamsAsMap() { 161 return new HashMap<>(params); 162 } 163 164 public void setJvmargs(List<String> jvmargs) { 165 putUnlessNullOrEmpty(JVM_OPTIONS.getID(), jvmargs); 166 } 167 168 public void setJvmUserArgs(Map<String, String> userArgs) { 169 170 putUnlessNullOrEmpty(USER_JVM_OPTIONS.getID(), userArgs); 171 } 172 173 public void setJvmProperties(Map<String, String> jvmProperties) { 174 putUnlessNullOrEmpty(JVM_PROPERTIES.getID(), jvmProperties); 175 } 176 177 public void setArguments(List<String> arguments) { 178 putUnlessNullOrEmpty(ARGUMENTS.getID(), arguments); 179 } 180 181 public void setAddModules(String value) { 182 putUnlessNull(StandardBundlerParam.ADD_MODULES.getID(), value); 183 } 184 185 public void setLimitModules(String value) { 186 putUnlessNull(StandardBundlerParam.LIMIT_MODULES.getID(), value); 187 } 188 189 public void setStripNativeCommands(boolean value) { 190 putUnlessNull(StandardBundlerParam.STRIP_NATIVE_COMMANDS.getID(), value); 191 } 192 193 public void setDetectMods(boolean value) { 194 putUnlessNull(JLinkBundlerHelper.DETECT_MODULES.getID(), value); 195 } 196 197 public void setSrcDir(String value) { 198 putUnlessNull(SOURCE_DIR.getID(), value); 199 } 200 201 public void setModulePath(String value) { 202 putUnlessNull(StandardBundlerParam.MODULE_PATH.getID(), value); 203 } 204 205 public void setMainModule(String value) { 206 putUnlessNull(StandardBundlerParam.MODULE.getID(), value); 207 } 208 209 public void setDebug(String value) { 210 putUnlessNull(JLinkBundlerHelper.DEBUG.getID(), value); 211 } 212 213 public String getApplicationID() { 214 return fetchParam(IDENTIFIER); 215 } 216 217 public String getPreferencesID() { 218 return fetchParam(PREFERENCES_ID); 219 } 220 221 public String getTitle() { 222 return fetchParam(TITLE); 223 } 224 225 public void setTitle(String title) { 226 putUnlessNull(PARAM_TITLE, title); 227 } 228 229 public String getApplicationClass() { 230 return fetchParam(MAIN_CLASS); 231 } 232 233 public void setApplicationClass(String applicationClass) { 234 putUnlessNull(PARAM_APPLICATION_CLASS, applicationClass); 235 } 236 237 public void setPrelaoderClass(String preloaderClass) { 238 putUnlessNull(PRELOADER_CLASS.getID(), preloaderClass); 239 } 240 241 public String getAppVersion() { 242 return fetchParam(VERSION); 243 } 244 245 public void setAppVersion(String version) { 246 putUnlessNull(PARAM_VERSION, version); 247 } 248 249 public String getDescription() { 250 return fetchParam(DESCRIPTION); 251 } 252 253 public void setDescription(String s) { 254 putUnlessNull(PARAM_DESCRIPTION, s); 255 } 256 257 public String getLicenseType() { 258 return fetchParam(LICENSE_TYPE); 259 } 260 261 public void setLicenseType(String version) { 262 putUnlessNull(PARAM_LICENSE_TYPE, version); 263 } 264 265 //path is relative to the application root 266 public void addLicenseFile(String path) { 267 List<String> licenseFiles = fetchParam(LICENSE_FILE); 268 if (licenseFiles == null || licenseFiles.isEmpty()) { 269 licenseFiles = new ArrayList<>(); 270 params.put(PARAM_LICENSE_FILE, licenseFiles); 271 } 272 licenseFiles.add(path); 273 } 274 275 public Boolean getSystemWide() { 276 return fetchParam(SYSTEM_WIDE); 277 } 278 279 public void setSystemWide(Boolean b) { 280 putUnlessNull(PARAM_SYSTEM_WIDE, b); 281 } 282 283 public void setServiceHint(Boolean b) { 284 putUnlessNull(PARAM_SERVICE_HINT, b); 285 } 286 287 public void setInstalldirChooser(Boolean b) { 288 putUnlessNull(PARAM_INSTALLDIR_CHOOSER, b); 289 } 290 291 public void setSingleton(Boolean b) { 292 putUnlessNull(PARAM_SINGLETON, b); 293 } 294 295 public void setSignBundle(Boolean b) { putUnlessNull(SIGN_BUNDLE.getID(), b); } 296 297 public boolean isShortcutHint() { 298 return fetchParam(SHORTCUT_HINT); 299 } 300 301 public void setShortcutHint(Boolean v) { 302 putUnlessNull(PARAM_SHORTCUT, v); 303 } 304 305 public boolean isMenuHint() { 306 return fetchParam(MENU_HINT); 307 } 308 309 public void setMenuHint(Boolean v) { 310 putUnlessNull(PARAM_MENU, v); 311 } 312 313 public String getName() { 314 return fetchParam(APP_NAME); 315 } 316 317 public void setName(String name) { 318 putUnlessNull(PARAM_NAME, name); 319 } 320 321 @SuppressWarnings("deprecation") 322 public BundleType getType() { 323 return fetchParam(BundleType.class, PARAM_TYPE); 324 } 325 326 @SuppressWarnings("deprecation") 327 public void setType(BundleType type) { 328 putUnlessNull(PARAM_TYPE, type); 329 } 330 331 public String getBundleFormat() { 332 return fetchParam(String.class, PARAM_BUNDLE_FORMAT); 333 } 334 335 public void setBundleFormat(String t) { 336 putUnlessNull(PARAM_BUNDLE_FORMAT, t); 337 } 338 339 public boolean getVerbose() { 340 return fetchParam(VERBOSE); 341 } 342 343 public void setVerbose(Boolean verbose) { 344 putUnlessNull(VERBOSE.getID(), verbose); 345 } 346 347 public List<String> getLicenseFile() { 348 return fetchParam(LICENSE_FILE); 349 } 350 351 public List<String> getJvmargs() { 352 return JVM_OPTIONS.fetchFrom(params); 353 } 354 355 public List<String> getArguments() { 356 return ARGUMENTS.fetchFrom(params); 357 } 358 359 //Validation approach: 360 // - JRE marker (rt.jar) 361 // - FX marker (jfxrt.jar) 362 // - JDK marker (tools.jar) 363 private static boolean checkJDKRoot(File jdkRoot) { 364 File rtJar = new File(jdkRoot, "jre/lib/rt.jar"); 365 if (!rtJar.exists()) { 366 Log.verbose("rt.jar is not found at " + rtJar.getAbsolutePath()); 367 return false; 368 } 369 370 File jfxJar = new File(jdkRoot, "jre/lib/ext/jfxrt.jar"); 371 if (!jfxJar.exists()) { 372 //Try again with new location 373 jfxJar = new File(jdkRoot, "jre/lib/jfxrt.jar"); 374 if (!jfxJar.exists()) { 375 Log.verbose("jfxrt.jar is not found at " + jfxJar.getAbsolutePath()); 376 return false; 377 } 378 } 379 380 381 File toolsJar = new File(jdkRoot, "lib/tools.jar"); 382 if (!toolsJar.exists()) { 383 Log.verbose("tools.jar is not found at " + toolsJar.getAbsolutePath()); 384 return false; 385 } 386 387 return true; 388 } 389 390 //Depending on platform and user input we may get different "references" 391 //Should support 392 // - java.home 393 // - reference to JDK install folder 394 // - should NOT support JRE dir 395 //Note: input could be null (then we asked to use system JRE) 396 // or it must be valid directory 397 //Returns null on validation failure. Returns jre root if ok. 398 public static File validateRuntimeLocation(File javaHome) { 399 if (javaHome == null) { 400 return null; 401 } 402 403 File jdkRoot; 404 File rtJar = new File(javaHome, "lib/rt.jar"); 405 406 if (rtJar.exists()) { //must be "java.home" case 407 //i.e. we are in JRE folder 408 jdkRoot = javaHome.getParentFile(); 409 } else { //expect it to be root of JDK installation folder 410 //On Mac it could be jdk/ or jdk/Contents/Home 411 //Norm to jdk/Contents/Home for validation 412 if (Platform.getPlatform() == Platform.MAC) { 413 File f = new File(javaHome, "Contents/Home"); 414 if (f.exists() && f.isDirectory()) { 415 javaHome = f; 416 } 417 } 418 jdkRoot = javaHome; 419 } 420 421 if (!checkJDKRoot(jdkRoot)) { 422 throw new RuntimeException( 423 "Can not find JDK artifacts in specified location: " 424 + javaHome.getAbsolutePath()); 425 } 426 427 return new File(jdkRoot, "jre"); 428 } 429 430 //select subset of given runtime using predefined rules 431 public void setRuntime(File baseDir) { 432 baseDir = validateRuntimeLocation(baseDir); 433 434 //mistake or explicit intent to use system runtime 435 if (baseDir == null) { 436 Log.verbose("No Java runtime to embed. Package will need system Java."); 437 params.put(PARAM_RUNTIME, null); 438 return; 439 } 440 doSetRuntime(baseDir); 441 } 442 443 //input dir "jdk/jre" (i.e. jre folder in the jdk) 444 private void doSetRuntime(File baseDir) { 445 params.put(PARAM_RUNTIME, baseDir.toString()); 446 } 447 448 //Currently unused? 449 // 450 //public void setRuntime(RelativeFileSet fs) { 451 // runtime = fs; 452 //} 453 454 public com.oracle.tools.packager.RelativeFileSet getAppResource() { 455 return fetchParam(APP_RESOURCES); 456 } 457 458 public void setAppResource(com.oracle.tools.packager.RelativeFileSet fs) { 459 putUnlessNull(PARAM_APP_RESOURCES, fs); 460 } 461 462 public void setAppResourcesList(List<com.oracle.tools.packager.RelativeFileSet> rfs) { 463 putUnlessNull(APP_RESOURCES_LIST.getID(), rfs); 464 } 465 466 public File getIcon() { 467 return fetchParam(ICON); 468 } 469 470 public void setIcon(File icon) { 471 putUnlessNull(PARAM_ICON, icon); 472 } 473 474 public String getApplicationCategory() { 475 return fetchParam(CATEGORY); 476 } 477 478 public void setApplicationCategory(String category) { 479 putUnlessNull(PARAM_CATEGORY, category); 480 } 481 482 public String getMainClassName() { 483 String applicationClass = getApplicationClass(); 484 485 if (applicationClass == null) { 486 return null; 487 } 488 489 int idx = applicationClass.lastIndexOf("."); 490 if (idx >= 0) { 491 return applicationClass.substring(idx+1); 492 } 493 return applicationClass; 494 } 495 496 public String getCopyright() { 497 return fetchParam(COPYRIGHT); 498 } 499 500 public void setCopyright(String c) { 501 putUnlessNull(PARAM_COPYRIGHT, c); 502 } 503 504 public String getIdentifier() { 505 return fetchParam(IDENTIFIER); 506 } 507 508 public void setIdentifier(String s) { 509 putUnlessNull(PARAM_IDENTIFIER, s); 510 } 511 512 private String mainJar = null; 513 private String mainJarClassPath = null; 514 private boolean useFXPackaging = true; 515 516 //For regular executable Jars we need to take care of classpath 517 //For JavaFX executable jars we do not need to pay attention to ClassPath entry in manifest 518 public String getAppClassPath() { 519 if (mainJar == null) { 520 //this will find out answer 521 getMainApplicationJar(); 522 } 523 if (useFXPackaging || mainJarClassPath == null) { 524 return ""; 525 } 526 return mainJarClassPath; 527 } 528 529 //assuming that application was packaged according to the rules 530 // we must have application jar, i.e. jar where we embed launcher 531 // and have main application class listed as main class! 532 //If there are more than one, or none - it will be treated as deployment error 533 // 534 //Note we look for both JavaFX executable jars and regular executable jars 535 //As long as main "application" entry point is the same it is main class 536 // (i.e. for FX jar we will use JavaFX manifest entry ...) 537 public String getMainApplicationJar() { 538 if (mainJar != null) { 539 return mainJar; 540 } 541 542 com.oracle.tools.packager.RelativeFileSet appResources = getAppResource(); 543 String applicationClass = getApplicationClass(); 544 545 if (appResources == null || applicationClass == null) { 546 return null; 547 } 548 File srcdir = appResources.getBaseDirectory(); 549 for (String fname : appResources.getIncludedFiles()) { 550 JarFile jf; 551 try { 552 jf = new JarFile(new File(srcdir, fname)); 553 Manifest m = jf.getManifest(); 554 Attributes attrs = (m != null) ? m.getMainAttributes() : null; 555 if (attrs != null) { 556 boolean javaMain = applicationClass.equals( 557 attrs.getValue(Attributes.Name.MAIN_CLASS)); 558 boolean fxMain = applicationClass.equals( 559 attrs.getValue(MANIFEST_JAVAFX_MAIN)); 560 if (javaMain || fxMain) { 561 useFXPackaging = fxMain; 562 mainJar = fname; 563 mainJarClassPath = attrs.getValue(Attributes.Name.CLASS_PATH); 564 return mainJar; 565 } 566 } 567 } catch (IOException ignore) { 568 } 569 } 570 return null; 571 } 572 573 public String getVendor() { 574 return fetchParam(VENDOR); 575 } 576 577 public void setVendor(String vendor) { 578 putUnlessNull(PARAM_VENDOR, vendor); 579 } 580 581 public String getEmail() { 582 return fetchParam(String.class, PARAM_EMAIL); 583 } 584 585 public void setEmail(String email) { 586 putUnlessNull(PARAM_EMAIL, email); 587 } 588 589 public void putUnlessNull(String param, Object value) { 590 if (value != null) { 591 params.put(param, value); 592 } 593 } 594 595 public void putUnlessNullOrEmpty(String param, Collection value) { 596 if (value != null && !value.isEmpty()) { 597 params.put(param, value); 598 } 599 } 600 601 public void putUnlessNullOrEmpty(String param, Map value) { 602 if (value != null && !value.isEmpty()) { 603 params.put(param, value); 604 } 605 } 606 607 }