1 /*
   2  * Copyright (c) 2014, 2015, Oracle and/or its affiliates.
   3  * All rights reserved. Use is subject to license terms.
   4  *
   5  * This file is available and licensed under the following license:
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  *
  11  *  - Redistributions of source code must retain the above copyright
  12  *    notice, this list of conditions and the following disclaimer.
  13  *  - Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in
  15  *    the documentation and/or other materials provided with the distribution.
  16  *  - Neither the name of Oracle Corporation nor the names of its
  17  *    contributors may be used to endorse or promote products derived
  18  *    from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 
  33 
  34 #include "Package.h"
  35 #include "Lock.h"
  36 #include "Helpers.h"
  37 #include "JavaUserPreferences.h"
  38 #include "Macros.h"
  39 #include "IniFile.h"
  40 
  41 #include <assert.h>
  42 
  43 
  44 Package::Package(void) {
  45     FInitialized = false;
  46     Initialize();
  47 }
  48 
  49 TPlatformNumber StringToPercentageOfNumber(TString Value, TPlatformNumber Number) {
  50     TPlatformNumber result = 0;
  51     size_t percentage = atoi(PlatformString(Value.c_str()));
  52 
  53     if (percentage > 0 && Number > 0) {
  54         result = Number * percentage / 100;
  55     }
  56 
  57     return result;
  58 }
  59 
  60 void Package::Initialize() {
  61     if (FInitialized == true) {
  62         return;
  63     }
  64 
  65     Platform& platform = Platform::GetInstance();
  66 
  67     FBootFields = new PackageBootFields();
  68     FDebugging = dsNone;
  69 
  70     FBootFields->FPackageRootDirectory = platform.GetPackageRootDirectory();
  71     FBootFields->FPackageAppDirectory = platform.GetPackageAppDirectory();
  72     FBootFields->FPackageLauncherDirectory = platform.GetPackageLauncherDirectory();
  73     FBootFields->FAppDataDirectory = platform.GetAppDataDirectory();
  74 
  75     std::map<TString, TString> keys = platform.GetKeys();
  76 
  77     // Read from configure.cfg/Info.plist
  78     AutoFreePtr<ISectionalPropertyContainer> config = platform.GetConfigFile(platform.GetConfigFileName());
  79 
  80     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_APP_ID_KEY], FBootFields->FAppID);
  81     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[PACKAGER_APP_DATA_DIR], FBootFields->FPackageAppDataDirectory);
  82     FBootFields->FPackageAppDataDirectory = FilePath::FixPathForPlatform(FBootFields->FPackageAppDataDirectory);
  83 
  84     // Main JAR.
  85     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_MAINJAR_KEY], FBootFields->FMainJar);
  86     FBootFields->FMainJar = FilePath::IncludeTrailingSeparater(GetPackageAppDirectory()) +
  87                             FilePath::FixPathForPlatform(FBootFields->FMainJar);
  88 
  89     // Classpath.
  90     // 1. If the provided class path contains main jar then only use provided class path.
  91     // 2. If class path provided by config file is empty then add main jar.
  92     // 3. If main jar is not in provided class path then add it.
  93     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_CLASSPATH_KEY], FBootFields->FClassPath);
  94     FBootFields->FClassPath = FilePath::FixPathSeparatorForPlatform(FBootFields->FClassPath);
  95 
  96     if (FBootFields->FClassPath.empty() == true) {
  97         FBootFields->FClassPath = GetMainJar();
  98     }
  99     else if (FBootFields->FClassPath.find(GetMainJar()) == TString::npos) {
 100         FBootFields->FClassPath = GetMainJar() + FilePath::PathSeparator() + FBootFields->FClassPath;
 101     }
 102 
 103     // Modulepath.
 104     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_MODULEPATH_KEY], FBootFields->FModulePath);
 105     FBootFields->FModulePath = FilePath::FixPathSeparatorForPlatform(FBootFields->FModulePath);
 106 
 107     // Main Class.
 108     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_MAINCLASSNAME_KEY], FBootFields->FMainClassName);
 109 
 110     // Splash Screen.
 111     if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_SPLASH_KEY], FBootFields->FSplashScreenFileName) == true) {
 112         FBootFields->FSplashScreenFileName = FilePath::IncludeTrailingSeparater(GetPackageAppDirectory()) +
 113                                              FilePath::FixPathForPlatform(FBootFields->FSplashScreenFileName);
 114 
 115         if (FilePath::FileExists(FBootFields->FSplashScreenFileName) == false) {
 116             FBootFields->FSplashScreenFileName = _T("");
 117         }
 118     }
 119 
 120     // Runtime.
 121     FBootFields->FIsRuntimeBundled = true;
 122     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[JVM_RUNTIME_KEY], FBootFields->FJVMRuntimeDirectory);
 123 
 124     if (FBootFields->FJVMRuntimeDirectory.empty()) {
 125         FBootFields->FIsRuntimeBundled = false;
 126         FBootFields->FJVMRuntimeDirectory = platform.GetSystemJRE();
 127     }
 128 
 129     // Read jvmargs.
 130     PromoteAppCDSState(config);
 131     ReadJVMArgs(config);
 132 
 133     // Read args if none were passed in.
 134     if (FBootFields->FArgs.size() == 0) {
 135         OrderedMap<TString, TString> args;
 136 
 137         if (config->GetSection(keys[CONFIG_SECTION_ARGOPTIONS], args) == true) {
 138             FBootFields->FArgs = Helpers::MapToNameValueList(args);
 139         }
 140     }
 141 
 142     // Read jvmuserarg defaults.
 143     config->GetSection(keys[CONFIG_SECTION_JVMUSEROPTIONS], FDefaultJVMUserArgs);
 144 
 145     // Load JVM user overrides.
 146     TString jvmUserArgsConfigFileName = GetJVMUserArgsConfigFileName();
 147 
 148     if (FilePath::FileExists(jvmUserArgsConfigFileName) == true) {
 149         // Load new location for user VM overrides.
 150         IniFile userConfig;
 151 
 152         if (userConfig.LoadFromFile(jvmUserArgsConfigFileName) == false) {
 153             // New property file format was not found, attempt to load old property file format.
 154             userConfig.GetSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], FJVMUserArgsOverrides);
 155         }
 156 
 157         userConfig.GetSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], FJVMUserArgsOverrides);
 158     }
 159     else {
 160         // Attemp to load java.util.prefs for legacy JVM user overrides.
 161         AutoFreePtr<JavaUserPreferences> javaPreferences(JavaUserPreferences::CreateInstance());
 162 
 163         if (javaPreferences->Load(GetAppID()) == true) {
 164             FJVMUserArgsOverrides = javaPreferences->GetData();
 165         }
 166     }
 167 
 168     // Auto Memory.
 169     TString autoMemory;
 170 
 171     if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_APP_MEMORY], autoMemory) == true) {
 172         if (autoMemory == _T("auto") || autoMemory == _T("100%")) {
 173             FBootFields->FMemoryState = PackageBootFields::msAuto;
 174             FBootFields->FMemorySize = platform.GetMemorySize();
 175         }
 176         else if (autoMemory.length() == 2 && isdigit(autoMemory[0]) && autoMemory[1] == '%') {
 177             FBootFields->FMemoryState = PackageBootFields::msAuto;
 178             FBootFields->FMemorySize = StringToPercentageOfNumber(autoMemory.substr(0, 1), platform.GetMemorySize());
 179         }
 180         else if (autoMemory.length() == 3 && isdigit(autoMemory[0]) && isdigit(autoMemory[1]) && autoMemory[2] == '%') {
 181             FBootFields->FMemoryState = PackageBootFields::msAuto;
 182             FBootFields->FMemorySize = StringToPercentageOfNumber(autoMemory.substr(0, 2), platform.GetMemorySize());
 183         }
 184         else {
 185             FBootFields->FMemoryState = PackageBootFields::msManual;
 186             FBootFields->FMemorySize = 0;
 187         }
 188     }
 189 
 190     MergeJVMDefaultsWithOverrides();
 191 }
 192 
 193 void Package::Clear() {
 194     FreeBootFields();
 195     FJVMUserArgsOverrides.Clear();
 196     FDefaultJVMUserArgs.Clear();
 197     FJVMUserArgs.Clear();
 198     FInitialized = false;
 199 }
 200 
 201 // This is the only location that the AppCDS state should be modified except
 202 // by command line arguments provided by the user.
 203 //
 204 // The state of AppCDS is as follows:
 205 //
 206 // -> cdsUninitialized
 207 //    -> cdsGenCache If -Xappcds:generatecache
 208 //    -> cdsDisabled If -Xappcds:off
 209 //    -> cdsEnabled If "AppCDSJVMOptions" section is present
 210 //    -> cdsAuto If "AppCDSJVMOptions" section is present and app.appcds.cache=auto
 211 //    -> cdsDisabled Default
 212 //
 213 void Package::PromoteAppCDSState(ISectionalPropertyContainer* Config) {
 214     Platform& platform = Platform::GetInstance();
 215     std::map<TString, TString> keys = platform.GetKeys();
 216 
 217     // The AppCDS state can change at this point.
 218     switch (platform.GetAppCDSState()) {
 219         case cdsEnabled:
 220         case cdsAuto:
 221         case cdsDisabled:
 222         case cdsGenCache: {
 223             // Do nothing.
 224             break;
 225         }
 226 
 227         case cdsUninitialized: {
 228             if (Config->ContainsSection(keys[CONFIG_SECTION_APPCDSJVMOPTIONS]) == true) {
 229                 // If the AppCDS section is present then enable AppCDS.
 230                 TString appCDSCacheValue;
 231 
 232                 // If running with AppCDS enabled, and the configuration has been setup so "auto" is enabled, then
 233                 // the launcher will attempt to generate the cache file automatically and run the application.
 234                 if (Config->GetValue(keys[CONFIG_SECTION_APPLICATION], _T("app.appcds.cache"), appCDSCacheValue) == true &&
 235                     appCDSCacheValue == _T("auto")) {
 236                     platform.SetAppCDSState(cdsAuto);
 237                 }
 238                 else {
 239                     platform.SetAppCDSState(cdsEnabled);
 240                 }
 241             }
 242             else {
 243 
 244                 platform.SetAppCDSState(cdsDisabled);
 245             }
 246         }
 247     }
 248 }
 249 
 250 void Package::ReadJVMArgs(ISectionalPropertyContainer* Config) {
 251     Platform& platform = Platform::GetInstance();
 252     std::map<TString, TString> keys = platform.GetKeys();
 253 
 254     // Evaluate based on the current AppCDS state.
 255     switch (platform.GetAppCDSState()) {
 256         case cdsUninitialized: {
 257             throw Exception(_T("Internal Error"));
 258     }
 259 
 260         case cdsDisabled: {
 261             Config->GetSection(keys[CONFIG_SECTION_JVMOPTIONS], FBootFields->FJVMArgs);
 262             break;
 263         }
 264 
 265         case cdsGenCache: {
 266             Config->GetSection(keys[CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS], FBootFields->FJVMArgs);
 267             break;
 268         }
 269 
 270         case cdsAuto:
 271         case cdsEnabled: {
 272             if (Config->GetValue(keys[CONFIG_SECTION_APPCDSJVMOPTIONS],
 273                                  _T( "-XX:SharedArchiveFile"), FBootFields->FAppCDSCacheFileName) == true) {
 274                 // File names may contain the incorrect path separators. The cache file name must be
 275                 // corrected at this point.
 276                 if (FBootFields->FAppCDSCacheFileName.empty() == false) {
 277                     IniFile* iniConfig = dynamic_cast<IniFile*>(Config);
 278 
 279                     if (iniConfig != NULL) {
 280                         FBootFields->FAppCDSCacheFileName = FilePath::FixPathForPlatform(FBootFields->FAppCDSCacheFileName);
 281                         iniConfig->SetValue(keys[CONFIG_SECTION_APPCDSJVMOPTIONS],
 282                                      _T( "-XX:SharedArchiveFile"), FBootFields->FAppCDSCacheFileName);
 283                     }
 284                 }
 285 
 286                 Config->GetSection(keys[CONFIG_SECTION_APPCDSJVMOPTIONS], FBootFields->FJVMArgs);
 287             }
 288 
 289             break;
 290         }
 291     }
 292 }
 293 
 294 void Package::SetCommandLineArguments(int argc, TCHAR* argv[]) {
 295     if (argc > 0) {
 296         std::list<TString> args;
 297 
 298         // Prepare app arguments. Skip value at index 0 - this is path to executable.
 299         FBootFields->FCommandName = argv[0];
 300 
 301         // Path to executable is at 0 index so start at index 1.
 302         for (int index = 1; index < argc; index++) {
 303             TString arg = argv[index];
 304 
 305 #ifdef DEBUG
 306             if (arg == _T("-debug")) {
 307                 FDebugging = dsNative;
 308             }
 309 
 310             if (arg == _T("-javadebug")) {
 311                 FDebugging = dsJava;
 312             }
 313 #endif //DEBUG
 314 #ifdef MAC
 315             if (arg.find(_T("-psn_"), 0) != TString::npos) {
 316                 Platform& platform = Platform::GetInstance();
 317 
 318                 if (platform.IsMainThread() == true) {
 319 #ifdef DEBUG
 320                     printf("%s\n", arg.c_str());
 321 #endif //DEBUG
 322                     continue;
 323                 }
 324             }
 325 
 326             if (arg == _T("-NSDocumentRevisionsDebugMode")) {
 327                 // Ignore -NSDocumentRevisionsDebugMode and the following YES/NO
 328                 index++;
 329                 continue;
 330             }
 331 #endif //MAC
 332 
 333             args.push_back(arg);
 334         }
 335 
 336         if (args.size() > 0) {
 337             FBootFields->FArgs = args;
 338         }
 339     }
 340 }
 341 
 342 Package& Package::GetInstance() {
 343     static Package instance; // Guaranteed to be destroyed. Instantiated on first use.
 344     return instance;
 345 }
 346 
 347 Package::~Package(void) {
 348     FreeBootFields();
 349 }
 350 
 351 void Package::FreeBootFields() {
 352     if (FBootFields != NULL) {
 353         delete FBootFields;
 354         FBootFields = NULL;
 355     }
 356 }
 357 
 358 OrderedMap<TString, TString> Package::GetJVMArgs() {
 359     return FBootFields->FJVMArgs;
 360 }
 361 
 362 OrderedMap<TString, TString> Package::GetDefaultJVMUserArgs() {
 363     return FDefaultJVMUserArgs;
 364 }
 365 
 366 OrderedMap<TString, TString> Package::GetJVMUserArgOverrides() {
 367     return FJVMUserArgsOverrides;
 368 }
 369 
 370 std::vector<TString> GetKeysThatAreNotDuplicates(OrderedMap<TString, TString> &Defaults,
 371                                                OrderedMap<TString, TString> &Overrides) {
 372     std::vector<TString> result;
 373     std::vector<TString> overrideKeys = Overrides.GetKeys();
 374 
 375     for (size_t index = 0; index < overrideKeys.size(); index++) {
 376         TString overridesKey = overrideKeys[index];
 377         TString overridesValue;
 378         TString defaultValue;
 379 
 380         if ((Defaults.ContainsKey(overridesKey) == false) ||
 381            (Defaults.GetValue(overridesKey, defaultValue) == true &&
 382             Overrides.GetValue(overridesKey, overridesValue) == true &&
 383             defaultValue != overridesValue)) {
 384             result.push_back(overridesKey);
 385         }
 386     }
 387 
 388     return result;
 389 }
 390 
 391 OrderedMap<TString, TString> CreateOrderedMapFromKeyList(OrderedMap<TString, TString> &Map,
 392                                                          std::vector<TString> &Keys) {
 393     OrderedMap<TString, TString> result;
 394 
 395     for (size_t index = 0; index < Keys.size(); index++) {
 396         TString key = Keys[index];
 397         TString value;
 398 
 399         if (Map.GetValue(key, value) == true) {
 400             result.Append(key, value);
 401         }
 402     }
 403 
 404     return result;
 405 }
 406 
 407 void Package::SetJVMUserArgOverrides(OrderedMap<TString, TString> Value) {
 408     OrderedMap<TString, TString> defaults = GetDefaultJVMUserArgs();
 409     OrderedMap<TString, TString> overrides = Value;
 410 
 411     // 1. Remove entries in the overrides that are the same as the defaults.
 412     std::vector<TString> overrideKeys = GetKeysThatAreNotDuplicates(defaults, overrides);
 413 
 414     // 2. Create an ordered map from the overrides that weren't removed.
 415     FJVMUserArgsOverrides = CreateOrderedMapFromKeyList(overrides, overrideKeys);
 416 
 417     // 3. Overwrite JVM user config overrides with provided key/value pair.
 418     SaveJVMUserArgOverrides(FJVMUserArgsOverrides);
 419 
 420     // 4. Merge defaults and overrides to produce FJVMUserArgs.
 421     MergeJVMDefaultsWithOverrides();
 422 }
 423 
 424 void Package::SaveJVMUserArgOverrides(OrderedMap<TString, TString> Data) {
 425     IniFile userConfig;
 426     Platform& platform = Platform::GetInstance();
 427     std::map<TString, TString> keys = platform.GetKeys();
 428     userConfig.AppendSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], Data);
 429     userConfig.SaveToFile(GetJVMUserArgsConfigFileName());
 430 }
 431 
 432 OrderedMap<TString, TString> Package::GetJVMUserArgs() {
 433     return FJVMUserArgs;
 434 }
 435 
 436 std::vector<TString> GetKeysThatAreNotOverridesOfDefaultValues(OrderedMap<TString, TString> &Defaults,
 437                                                                OrderedMap<TString, TString> &Overrides) {
 438     std::vector<TString> result;
 439     std::vector<TString> keys = Overrides.GetKeys();
 440 
 441     for (unsigned int index = 0; index< keys.size(); index++) {
 442         TString key = keys[index];
 443 
 444         if (Defaults.ContainsKey(key) == true) {
 445             try {
 446                 TString value = Overrides[key];
 447                 Defaults[key] = value;
 448             }
 449             catch (std::out_of_range) {
 450             }
 451         }
 452         else {
 453             result.push_back(key);
 454         }
 455     }
 456 
 457     return result;
 458 }
 459 
 460 void Package::MergeJVMDefaultsWithOverrides() {
 461     // Merge jvmuserarg defaults and jvmuserarg overrides to populate FJVMUserArgs.
 462     // 1. If the key is in the config file and not the java.user.preferences the default value is used,
 463     //    the one from the config file.
 464     // 2. If the key is in the java.user.preferences then the value from the java.user.preferences is used and
 465     //    the config file value is ignored.
 466     // 3. If the key is not in the config file but it is in the java.user.preferences then it is added anyway.
 467     //    And if it is removed it won't show back up.
 468     FJVMUserArgs.Clear();
 469     FJVMUserArgs.Append(FDefaultJVMUserArgs);
 470 
 471     OrderedMap<TString, TString> overrides = GetJVMUserArgOverrides();
 472 
 473     // 1. Iterate over all elements in overrides to see if any items
 474     //    override a default value.
 475     std::vector<TString> keys = GetKeysThatAreNotOverridesOfDefaultValues(FJVMUserArgs, overrides);
 476 
 477 
 478     // 2. All remaining items in overrides are appended to the end.
 479     for (unsigned int index = 0; index< keys.size(); index++) {
 480         TString key = keys[index];
 481         TString value;
 482 
 483         if (overrides.GetValue(key, value) == true) {
 484             FJVMUserArgs.Append(key, value);
 485         }
 486     }
 487 }
 488 
 489 std::list<TString> Package::GetArgs() {
 490     assert(FBootFields != NULL);
 491     return FBootFields->FArgs;
 492 }
 493 
 494 TString Package::GetPackageRootDirectory() {
 495     assert(FBootFields != NULL);
 496     return FBootFields->FPackageRootDirectory;
 497 }
 498 
 499 TString Package::GetPackageAppDirectory() {
 500     assert(FBootFields != NULL);
 501     return FBootFields->FPackageAppDirectory;
 502 }
 503 
 504 TString Package::GetPackageLauncherDirectory() {
 505     assert(FBootFields != NULL);
 506     return FBootFields->FPackageLauncherDirectory;
 507 }
 508 
 509 TString Package::GetAppDataDirectory() {
 510     assert(FBootFields != NULL);
 511     return FBootFields->FAppDataDirectory;
 512 }
 513 
 514 TString Package::GetJVMUserArgsConfigFileName() {
 515     if (FJVMUserArgsConfigFileName.empty()) {
 516         Platform& platform = Platform::GetInstance();
 517 
 518         FJVMUserArgsConfigFileName = FilePath::IncludeTrailingSeparater(platform.GetAppDataDirectory()) +
 519                                         FilePath::IncludeTrailingSeparater(GetPackageAppDataDirectory()) +
 520                                         FilePath::IncludeTrailingSeparater(_T("packager")) +
 521                                         _T("jvmuserargs.cfg");
 522     }
 523 
 524     return FJVMUserArgsConfigFileName;
 525 }
 526 
 527 TString Package::GetAppCDSCacheDirectory() {
 528     if (FAppCDSCacheDirectory.empty()) {
 529         Platform& platform = Platform::GetInstance();
 530         FAppCDSCacheDirectory = FilePath::IncludeTrailingSeparater(platform.GetAppDataDirectory()) +
 531                                 FilePath::IncludeTrailingSeparater(GetPackageAppDataDirectory()) +
 532                                 _T("cache");
 533 
 534         Macros& macros = Macros::GetInstance();
 535         FAppCDSCacheDirectory = macros.ExpandMacros(FAppCDSCacheDirectory);
 536         FAppCDSCacheDirectory = FilePath::FixPathForPlatform(FAppCDSCacheDirectory);
 537     }
 538 
 539     return FAppCDSCacheDirectory;
 540 }
 541 
 542 TString Package::GetAppCDSCacheFileName() {
 543     assert(FBootFields != NULL);
 544 
 545     if (FBootFields->FAppCDSCacheFileName.empty() == false) {
 546         Macros& macros = Macros::GetInstance();
 547         FBootFields->FAppCDSCacheFileName = macros.ExpandMacros(FBootFields->FAppCDSCacheFileName);
 548         FBootFields->FAppCDSCacheFileName = FilePath::FixPathForPlatform(FBootFields->FAppCDSCacheFileName);
 549     }
 550 
 551     return FBootFields->FAppCDSCacheFileName;
 552 }
 553 
 554 TString Package::GetAppID() {
 555     assert(FBootFields != NULL);
 556     return FBootFields->FAppID;
 557 }
 558 
 559 TString Package::GetPackageAppDataDirectory() {
 560     assert(FBootFields != NULL);
 561     return FBootFields->FPackageAppDataDirectory;
 562 }
 563 
 564 TString Package::GetClassPath() {
 565     assert(FBootFields != NULL);
 566     return FBootFields->FClassPath;
 567 }
 568 
 569 TString Package::GetModulePath() {
 570     assert(FBootFields != NULL);
 571     return FBootFields->FModulePath;
 572 }
 573 
 574 TString Package::GetMainJar() {
 575     assert(FBootFields != NULL);
 576     return FBootFields->FMainJar;
 577 }
 578 
 579 TString Package::GetMainClassName() {
 580     assert(FBootFields != NULL);
 581     return FBootFields->FMainClassName;
 582 }
 583 
 584 bool Package::IsRuntimeBundled() {
 585     assert(FBootFields != NULL);
 586     return FBootFields->FIsRuntimeBundled;
 587 }
 588 
 589 TString Package::GetJVMLibraryFileName() {
 590     assert(FBootFields != NULL);
 591 
 592     if (FBootFields->FJVMLibraryFileName.empty() == true) {
 593         Platform& platform = Platform::GetInstance();
 594         if (IsRuntimeBundled() == true) {
 595             Macros& macros = Macros::GetInstance();
 596             TString jvmRuntimePath = macros.ExpandMacros(GetJVMRuntimeDirectory());
 597             FBootFields->FJVMLibraryFileName = platform.GetBundledJVMLibraryFileName(jvmRuntimePath);
 598         }
 599         else {
 600             FBootFields->FJVMLibraryFileName = platform.GetSystemJVMLibraryFileName();
 601         }
 602     }
 603 
 604     return FBootFields->FJVMLibraryFileName;
 605 }
 606 
 607 TString Package::GetJVMRuntimeDirectory() {
 608     assert(FBootFields != NULL);
 609     return FBootFields->FJVMRuntimeDirectory;
 610 }
 611 
 612 TString Package::GetSplashScreenFileName() {
 613     assert(FBootFields != NULL);
 614     return FBootFields->FSplashScreenFileName;
 615 }
 616 
 617 bool Package::HasSplashScreen() {
 618     assert(FBootFields != NULL);
 619     return FilePath::FileExists(FBootFields->FSplashScreenFileName);
 620 }
 621 
 622 TString Package::GetCommandName() {
 623     assert(FBootFields != NULL);
 624     return FBootFields->FCommandName;
 625 }
 626 
 627 TPlatformNumber Package::GetMemorySize() {
 628     assert(FBootFields != NULL);
 629     return FBootFields->FMemorySize;
 630 }
 631 
 632 PackageBootFields::MemoryState Package::GetMemoryState() {
 633     assert(FBootFields != NULL);
 634     return FBootFields->FMemoryState;
 635 }
 636 
 637 DebugState Package::Debugging() {
 638     return FDebugging;
 639 }