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