1 /*
   2  * Copyright (c) 2014, 2016, 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     // Main Module.
  90     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_MAINMODULE_KEY], FBootFields->FMainModule);
  91 
  92     // Classpath.
  93     // 1. If the provided class path contains main jar then only use provided class path.
  94     // 2. If class path provided by config file is empty then add main jar.
  95     // 3. If main jar is not in provided class path then add it.
  96     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_CLASSPATH_KEY], FBootFields->FClassPath);
  97     FBootFields->FClassPath = FilePath::FixPathSeparatorForPlatform(FBootFields->FClassPath);
  98 
  99     if (FBootFields->FClassPath.empty() == true) {
 100         FBootFields->FClassPath = GetMainJar();
 101     }
 102     else if (FBootFields->FClassPath.find(GetMainJar()) == TString::npos) {
 103         FBootFields->FClassPath = GetMainJar() + FilePath::PathSeparator() + FBootFields->FClassPath;
 104     }
 105 
 106     // Modulepath.
 107     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_MODULEPATH_KEY], FBootFields->FModulePath);
 108     FBootFields->FModulePath = FilePath::FixPathSeparatorForPlatform(FBootFields->FModulePath);
 109 
 110     // Main Class.
 111     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_MAINCLASSNAME_KEY], FBootFields->FMainClassName);
 112 
 113     // Splash Screen.
 114     if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_SPLASH_KEY], FBootFields->FSplashScreenFileName) == true) {
 115         FBootFields->FSplashScreenFileName = FilePath::IncludeTrailingSeparater(GetPackageAppDirectory()) +
 116                                              FilePath::FixPathForPlatform(FBootFields->FSplashScreenFileName);
 117 
 118         if (FilePath::FileExists(FBootFields->FSplashScreenFileName) == false) {
 119             FBootFields->FSplashScreenFileName = _T("");
 120         }
 121     }
 122 
 123     // Runtime.
 124     FBootFields->FIsRuntimeBundled = true;
 125     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[JVM_RUNTIME_KEY], FBootFields->FJVMRuntimeDirectory);
 126 
 127     if (FBootFields->FJVMRuntimeDirectory.empty()) {
 128         FBootFields->FIsRuntimeBundled = false;
 129         FBootFields->FJVMRuntimeDirectory = platform.GetSystemJRE();
 130     }
 131 
 132     // Read jvmargs.
 133     PromoteAppCDSState(config);
 134     ReadJVMArgs(config);
 135 
 136     // Read args if none were passed in.
 137     if (FBootFields->FArgs.size() == 0) {
 138         OrderedMap<TString, TString> args;
 139 
 140         if (config->GetSection(keys[CONFIG_SECTION_ARGOPTIONS], args) == true) {
 141             FBootFields->FArgs = Helpers::MapToNameValueList(args);
 142         }
 143     }
 144 
 145     // Read jvmuserarg defaults.
 146     config->GetSection(keys[CONFIG_SECTION_JVMUSEROPTIONS], FDefaultJVMUserArgs);
 147 
 148     // Load JVM user overrides.
 149     TString jvmUserArgsConfigFileName = GetJVMUserArgsConfigFileName();
 150 
 151     if (FilePath::FileExists(jvmUserArgsConfigFileName) == true) {
 152         // Load new location for user VM overrides.
 153         IniFile userConfig;
 154 
 155         if (userConfig.LoadFromFile(jvmUserArgsConfigFileName) == false) {
 156             // New property file format was not found, attempt to load old property file format.
 157             userConfig.GetSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], FJVMUserArgsOverrides);
 158         }
 159 
 160         userConfig.GetSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], FJVMUserArgsOverrides);
 161     }
 162     else {
 163         // Attemp to load java.util.prefs for legacy JVM user overrides.
 164         AutoFreePtr<JavaUserPreferences> javaPreferences(JavaUserPreferences::CreateInstance());
 165 
 166         if (javaPreferences->Load(GetAppID()) == true) {
 167             FJVMUserArgsOverrides = javaPreferences->GetData();
 168         }
 169     }
 170 
 171     // Auto Memory.
 172     TString autoMemory;
 173 
 174     if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_APP_MEMORY], autoMemory) == true) {
 175         if (autoMemory == _T("auto") || autoMemory == _T("100%")) {
 176             FBootFields->FMemoryState = PackageBootFields::msAuto;
 177             FBootFields->FMemorySize = platform.GetMemorySize();
 178         }
 179         else if (autoMemory.length() == 2 && isdigit(autoMemory[0]) && autoMemory[1] == '%') {
 180             FBootFields->FMemoryState = PackageBootFields::msAuto;
 181             FBootFields->FMemorySize = StringToPercentageOfNumber(autoMemory.substr(0, 1), platform.GetMemorySize());
 182         }
 183         else if (autoMemory.length() == 3 && isdigit(autoMemory[0]) && isdigit(autoMemory[1]) && autoMemory[2] == '%') {
 184             FBootFields->FMemoryState = PackageBootFields::msAuto;
 185             FBootFields->FMemorySize = StringToPercentageOfNumber(autoMemory.substr(0, 2), platform.GetMemorySize());
 186         }
 187         else {
 188             FBootFields->FMemoryState = PackageBootFields::msManual;
 189             FBootFields->FMemorySize = 0;
 190         }
 191     }
 192 
 193     // Debug
 194     TString debug;
 195     if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_APP_DEBUG], debug) == true) {
 196         FBootFields->FArgs.push_back(debug);
 197     }
 198 
 199     MergeJVMDefaultsWithOverrides();
 200 }
 201 
 202 void Package::Clear() {
 203     FreeBootFields();
 204     FJVMUserArgsOverrides.Clear();
 205     FDefaultJVMUserArgs.Clear();
 206     FJVMUserArgs.Clear();
 207     FInitialized = false;
 208 }
 209 
 210 // This is the only location that the AppCDS state should be modified except
 211 // by command line arguments provided by the user.
 212 //
 213 // The state of AppCDS is as follows:
 214 //
 215 // -> cdsUninitialized
 216 //    -> cdsGenCache If -Xappcds:generatecache
 217 //    -> cdsDisabled If -Xappcds:off
 218 //    -> cdsEnabled If "AppCDSJVMOptions" section is present
 219 //    -> cdsAuto If "AppCDSJVMOptions" section is present and app.appcds.cache=auto
 220 //    -> cdsDisabled Default
 221 //
 222 void Package::PromoteAppCDSState(ISectionalPropertyContainer* Config) {
 223     Platform& platform = Platform::GetInstance();
 224     std::map<TString, TString> keys = platform.GetKeys();
 225 
 226     // The AppCDS state can change at this point.
 227     switch (platform.GetAppCDSState()) {
 228         case cdsEnabled:
 229         case cdsAuto:
 230         case cdsDisabled:
 231         case cdsGenCache: {
 232             // Do nothing.
 233             break;
 234         }
 235 
 236         case cdsUninitialized: {
 237             if (Config->ContainsSection(keys[CONFIG_SECTION_APPCDSJVMOPTIONS]) == true) {
 238                 // If the AppCDS section is present then enable AppCDS.
 239                 TString appCDSCacheValue;
 240 
 241                 // If running with AppCDS enabled, and the configuration has been setup so "auto" is enabled, then
 242                 // the launcher will attempt to generate the cache file automatically and run the application.
 243                 if (Config->GetValue(keys[CONFIG_SECTION_APPLICATION], _T("app.appcds.cache"), appCDSCacheValue) == true &&
 244                     appCDSCacheValue == _T("auto")) {
 245                     platform.SetAppCDSState(cdsAuto);
 246                 }
 247                 else {
 248                     platform.SetAppCDSState(cdsEnabled);
 249                 }
 250             }
 251             else {
 252 
 253                 platform.SetAppCDSState(cdsDisabled);
 254             }
 255         }
 256     }
 257 }
 258 
 259 void Package::ReadJVMArgs(ISectionalPropertyContainer* Config) {
 260     Platform& platform = Platform::GetInstance();
 261     std::map<TString, TString> keys = platform.GetKeys();
 262 
 263     // Evaluate based on the current AppCDS state.
 264     switch (platform.GetAppCDSState()) {
 265         case cdsUninitialized: {
 266             throw Exception(_T("Internal Error"));
 267     }
 268 
 269         case cdsDisabled: {
 270             Config->GetSection(keys[CONFIG_SECTION_JVMOPTIONS], FBootFields->FJVMArgs);
 271             break;
 272         }
 273 
 274         case cdsGenCache: {
 275             Config->GetSection(keys[CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS], FBootFields->FJVMArgs);
 276             break;
 277         }
 278 
 279         case cdsAuto:
 280         case cdsEnabled: {
 281             if (Config->GetValue(keys[CONFIG_SECTION_APPCDSJVMOPTIONS],
 282                                  _T( "-XX:SharedArchiveFile"), FBootFields->FAppCDSCacheFileName) == true) {
 283                 // File names may contain the incorrect path separators. The cache file name must be
 284                 // corrected at this point.
 285                 if (FBootFields->FAppCDSCacheFileName.empty() == false) {
 286                     IniFile* iniConfig = dynamic_cast<IniFile*>(Config);
 287 
 288                     if (iniConfig != NULL) {
 289                         FBootFields->FAppCDSCacheFileName = FilePath::FixPathForPlatform(FBootFields->FAppCDSCacheFileName);
 290                         iniConfig->SetValue(keys[CONFIG_SECTION_APPCDSJVMOPTIONS],
 291                                      _T( "-XX:SharedArchiveFile"), FBootFields->FAppCDSCacheFileName);
 292                     }
 293                 }
 294 
 295                 Config->GetSection(keys[CONFIG_SECTION_APPCDSJVMOPTIONS], FBootFields->FJVMArgs);
 296             }
 297 
 298             break;
 299         }
 300     }
 301 }
 302 
 303 void Package::SetCommandLineArguments(int argc, TCHAR* argv[]) {
 304     if (argc > 0) {
 305         std::list<TString> args;
 306 
 307         // Prepare app arguments. Skip value at index 0 - this is path to executable.
 308         FBootFields->FCommandName = argv[0];
 309 
 310         // Path to executable is at 0 index so start at index 1.
 311         for (int index = 1; index < argc; index++) {
 312             TString arg = argv[index];
 313 
 314 #ifdef DEBUG
 315             if (arg == _T("-debug")) {
 316                 FDebugging = dsNative;
 317             }
 318 
 319             if (arg == _T("-javadebug")) {
 320                 FDebugging = dsJava;
 321             }
 322 #endif //DEBUG
 323 #ifdef MAC
 324             if (arg.find(_T("-psn_"), 0) != TString::npos) {
 325                 Platform& platform = Platform::GetInstance();
 326 
 327                 if (platform.IsMainThread() == true) {
 328 #ifdef DEBUG
 329                     printf("%s\n", arg.c_str());
 330 #endif //DEBUG
 331                     continue;
 332                 }
 333             }
 334 
 335             if (arg == _T("-NSDocumentRevisionsDebugMode")) {
 336                 // Ignore -NSDocumentRevisionsDebugMode and the following YES/NO
 337                 index++;
 338                 continue;
 339             }
 340 #endif //MAC
 341 
 342             args.push_back(arg);
 343         }
 344 
 345         if (args.size() > 0) {
 346             FBootFields->FArgs = args;
 347         }
 348     }
 349 }
 350 
 351 Package& Package::GetInstance() {
 352     static Package instance; // Guaranteed to be destroyed. Instantiated on first use.
 353     return instance;
 354 }
 355 
 356 Package::~Package(void) {
 357     FreeBootFields();
 358 }
 359 
 360 void Package::FreeBootFields() {
 361     if (FBootFields != NULL) {
 362         delete FBootFields;
 363         FBootFields = NULL;
 364     }
 365 }
 366 
 367 OrderedMap<TString, TString> Package::GetJVMArgs() {
 368     return FBootFields->FJVMArgs;
 369 }
 370 
 371 OrderedMap<TString, TString> Package::GetDefaultJVMUserArgs() {
 372     return FDefaultJVMUserArgs;
 373 }
 374 
 375 OrderedMap<TString, TString> Package::GetJVMUserArgOverrides() {
 376     return FJVMUserArgsOverrides;
 377 }
 378 
 379 std::vector<TString> GetKeysThatAreNotDuplicates(OrderedMap<TString, TString> &Defaults,
 380                                                OrderedMap<TString, TString> &Overrides) {
 381     std::vector<TString> result;
 382     std::vector<TString> overrideKeys = Overrides.GetKeys();
 383 
 384     for (size_t index = 0; index < overrideKeys.size(); index++) {
 385         TString overridesKey = overrideKeys[index];
 386         TString overridesValue;
 387         TString defaultValue;
 388 
 389         if ((Defaults.ContainsKey(overridesKey) == false) ||
 390            (Defaults.GetValue(overridesKey, defaultValue) == true &&
 391             Overrides.GetValue(overridesKey, overridesValue) == true &&
 392             defaultValue != overridesValue)) {
 393             result.push_back(overridesKey);
 394         }
 395     }
 396 
 397     return result;
 398 }
 399 
 400 OrderedMap<TString, TString> CreateOrderedMapFromKeyList(OrderedMap<TString, TString> &Map,
 401                                                          std::vector<TString> &Keys) {
 402     OrderedMap<TString, TString> result;
 403 
 404     for (size_t index = 0; index < Keys.size(); index++) {
 405         TString key = Keys[index];
 406         TString value;
 407 
 408         if (Map.GetValue(key, value) == true) {
 409             result.Append(key, value);
 410         }
 411     }
 412 
 413     return result;
 414 }
 415 
 416 void Package::SetJVMUserArgOverrides(OrderedMap<TString, TString> Value) {
 417     OrderedMap<TString, TString> defaults = GetDefaultJVMUserArgs();
 418     OrderedMap<TString, TString> overrides = Value;
 419 
 420     // 1. Remove entries in the overrides that are the same as the defaults.
 421     std::vector<TString> overrideKeys = GetKeysThatAreNotDuplicates(defaults, overrides);
 422 
 423     // 2. Create an ordered map from the overrides that weren't removed.
 424     FJVMUserArgsOverrides = CreateOrderedMapFromKeyList(overrides, overrideKeys);
 425 
 426     // 3. Overwrite JVM user config overrides with provided key/value pair.
 427     SaveJVMUserArgOverrides(FJVMUserArgsOverrides);
 428 
 429     // 4. Merge defaults and overrides to produce FJVMUserArgs.
 430     MergeJVMDefaultsWithOverrides();
 431 }
 432 
 433 void Package::SaveJVMUserArgOverrides(OrderedMap<TString, TString> Data) {
 434     IniFile userConfig;
 435     Platform& platform = Platform::GetInstance();
 436     std::map<TString, TString> keys = platform.GetKeys();
 437     userConfig.AppendSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], Data);
 438     userConfig.SaveToFile(GetJVMUserArgsConfigFileName());
 439 }
 440 
 441 OrderedMap<TString, TString> Package::GetJVMUserArgs() {
 442     return FJVMUserArgs;
 443 }
 444 
 445 std::vector<TString> GetKeysThatAreNotOverridesOfDefaultValues(OrderedMap<TString, TString> &Defaults,
 446                                                                OrderedMap<TString, TString> &Overrides) {
 447     std::vector<TString> result;
 448     std::vector<TString> keys = Overrides.GetKeys();
 449 
 450     for (unsigned int index = 0; index< keys.size(); index++) {
 451         TString key = keys[index];
 452 
 453         if (Defaults.ContainsKey(key) == true) {
 454             try {
 455                 TString value = Overrides[key];
 456                 Defaults[key] = value;
 457             }
 458             catch (std::out_of_range) {
 459             }
 460         }
 461         else {
 462             result.push_back(key);
 463         }
 464     }
 465 
 466     return result;
 467 }
 468 
 469 void Package::MergeJVMDefaultsWithOverrides() {
 470     // Merge jvmuserarg defaults and jvmuserarg overrides to populate FJVMUserArgs.
 471     // 1. If the key is in the config file and not the java.user.preferences the default value is used,
 472     //    the one from the config file.
 473     // 2. If the key is in the java.user.preferences then the value from the java.user.preferences is used and
 474     //    the config file value is ignored.
 475     // 3. If the key is not in the config file but it is in the java.user.preferences then it is added anyway.
 476     //    And if it is removed it won't show back up.
 477     FJVMUserArgs.Clear();
 478     FJVMUserArgs.Append(FDefaultJVMUserArgs);
 479 
 480     OrderedMap<TString, TString> overrides = GetJVMUserArgOverrides();
 481 
 482     // 1. Iterate over all elements in overrides to see if any items
 483     //    override a default value.
 484     std::vector<TString> keys = GetKeysThatAreNotOverridesOfDefaultValues(FJVMUserArgs, overrides);
 485 
 486 
 487     // 2. All remaining items in overrides are appended to the end.
 488     for (unsigned int index = 0; index< keys.size(); index++) {
 489         TString key = keys[index];
 490         TString value;
 491 
 492         if (overrides.GetValue(key, value) == true) {
 493             FJVMUserArgs.Append(key, value);
 494         }
 495     }
 496 }
 497 
 498 std::list<TString> Package::GetArgs() {
 499     assert(FBootFields != NULL);
 500     return FBootFields->FArgs;
 501 }
 502 
 503 TString Package::GetPackageRootDirectory() {
 504     assert(FBootFields != NULL);
 505     return FBootFields->FPackageRootDirectory;
 506 }
 507 
 508 TString Package::GetPackageAppDirectory() {
 509     assert(FBootFields != NULL);
 510     return FBootFields->FPackageAppDirectory;
 511 }
 512 
 513 TString Package::GetPackageLauncherDirectory() {
 514     assert(FBootFields != NULL);
 515     return FBootFields->FPackageLauncherDirectory;
 516 }
 517 
 518 TString Package::GetAppDataDirectory() {
 519     assert(FBootFields != NULL);
 520     return FBootFields->FAppDataDirectory;
 521 }
 522 
 523 TString Package::GetJVMUserArgsConfigFileName() {
 524     if (FJVMUserArgsConfigFileName.empty()) {
 525         Platform& platform = Platform::GetInstance();
 526 
 527         FJVMUserArgsConfigFileName = FilePath::IncludeTrailingSeparater(platform.GetAppDataDirectory()) +
 528                                         FilePath::IncludeTrailingSeparater(GetPackageAppDataDirectory()) +
 529                                         FilePath::IncludeTrailingSeparater(_T("packager")) +
 530                                         _T("jvmuserargs.cfg");
 531     }
 532 
 533     return FJVMUserArgsConfigFileName;
 534 }
 535 
 536 TString Package::GetAppCDSCacheDirectory() {
 537     if (FAppCDSCacheDirectory.empty()) {
 538         Platform& platform = Platform::GetInstance();
 539         FAppCDSCacheDirectory = FilePath::IncludeTrailingSeparater(platform.GetAppDataDirectory()) +
 540                                 FilePath::IncludeTrailingSeparater(GetPackageAppDataDirectory()) +
 541                                 _T("cache");
 542 
 543         Macros& macros = Macros::GetInstance();
 544         FAppCDSCacheDirectory = macros.ExpandMacros(FAppCDSCacheDirectory);
 545         FAppCDSCacheDirectory = FilePath::FixPathForPlatform(FAppCDSCacheDirectory);
 546     }
 547 
 548     return FAppCDSCacheDirectory;
 549 }
 550 
 551 TString Package::GetAppCDSCacheFileName() {
 552     assert(FBootFields != NULL);
 553 
 554     if (FBootFields->FAppCDSCacheFileName.empty() == false) {
 555         Macros& macros = Macros::GetInstance();
 556         FBootFields->FAppCDSCacheFileName = macros.ExpandMacros(FBootFields->FAppCDSCacheFileName);
 557         FBootFields->FAppCDSCacheFileName = FilePath::FixPathForPlatform(FBootFields->FAppCDSCacheFileName);
 558     }
 559 
 560     return FBootFields->FAppCDSCacheFileName;
 561 }
 562 
 563 TString Package::GetAppID() {
 564     assert(FBootFields != NULL);
 565     return FBootFields->FAppID;
 566 }
 567 
 568 TString Package::GetPackageAppDataDirectory() {
 569     assert(FBootFields != NULL);
 570     return FBootFields->FPackageAppDataDirectory;
 571 }
 572 
 573 TString Package::GetClassPath() {
 574     assert(FBootFields != NULL);
 575     return FBootFields->FClassPath;
 576 }
 577 
 578 TString Package::GetModulePath() {
 579     assert(FBootFields != NULL);
 580     return FBootFields->FModulePath;
 581 }
 582 
 583 TString Package::GetMainJar() {
 584     assert(FBootFields != NULL);
 585     return FBootFields->FMainJar;
 586 }
 587 
 588 TString Package::GetMainModule() {
 589     assert(FBootFields != NULL);
 590     return FBootFields->FMainModule;
 591 }
 592 
 593 TString Package::GetMainClassName() {
 594     assert(FBootFields != NULL);
 595     return FBootFields->FMainClassName;
 596 }
 597 
 598 bool Package::IsRuntimeBundled() {
 599     assert(FBootFields != NULL);
 600     return FBootFields->FIsRuntimeBundled;
 601 }
 602 
 603 TString Package::GetJVMLibraryFileName() {
 604     assert(FBootFields != NULL);
 605 
 606     if (FBootFields->FJVMLibraryFileName.empty() == true) {
 607         Platform& platform = Platform::GetInstance();
 608         if (IsRuntimeBundled() == true) {
 609             Macros& macros = Macros::GetInstance();
 610             TString jvmRuntimePath = macros.ExpandMacros(GetJVMRuntimeDirectory());
 611             FBootFields->FJVMLibraryFileName = platform.GetBundledJVMLibraryFileName(jvmRuntimePath);
 612         }
 613         else {
 614             FBootFields->FJVMLibraryFileName = platform.GetSystemJVMLibraryFileName();
 615         }
 616     }
 617 
 618     return FBootFields->FJVMLibraryFileName;
 619 }
 620 
 621 TString Package::GetJVMRuntimeDirectory() {
 622     assert(FBootFields != NULL);
 623     return FBootFields->FJVMRuntimeDirectory;
 624 }
 625 
 626 TString Package::GetSplashScreenFileName() {
 627     assert(FBootFields != NULL);
 628     return FBootFields->FSplashScreenFileName;
 629 }
 630 
 631 bool Package::HasSplashScreen() {
 632     assert(FBootFields != NULL);
 633     return FilePath::FileExists(FBootFields->FSplashScreenFileName);
 634 }
 635 
 636 TString Package::GetCommandName() {
 637     assert(FBootFields != NULL);
 638     return FBootFields->FCommandName;
 639 }
 640 
 641 TPlatformNumber Package::GetMemorySize() {
 642     assert(FBootFields != NULL);
 643     return FBootFields->FMemorySize;
 644 }
 645 
 646 PackageBootFields::MemoryState Package::GetMemoryState() {
 647     assert(FBootFields != NULL);
 648     return FBootFields->FMemoryState;
 649 }
 650 
 651 DebugState Package::Debugging() {
 652     return FDebugging;
 653 }