1 /* 2 * Copyright (c) 2014, 2019, 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 #include "Package.h" 27 #include "Helpers.h" 28 #include "Macros.h" 29 #include "IniFile.h" 30 31 #include <assert.h> 32 33 34 Package::Package(void) { 35 FInitialized = false; 36 Initialize(); 37 } 38 39 TPlatformNumber StringToPercentageOfNumber(TString Value, 40 TPlatformNumber Number) { 41 TPlatformNumber result = 0; 42 size_t percentage = atoi(PlatformString(Value.c_str())); 43 44 if (percentage > 0 && Number > 0) { 45 result = Number * percentage / 100; 46 } 47 48 return result; 49 } 50 51 void Package::Initialize() { 52 if (FInitialized == true) { 53 return; 54 } 55 56 Platform& platform = Platform::GetInstance(); 57 58 FBootFields = new PackageBootFields(); 59 FDebugging = dsNone; 60 61 FBootFields->FPackageRootDirectory = platform.GetPackageRootDirectory(); 62 FBootFields->FPackageAppDirectory = platform.GetPackageAppDirectory(); 63 FBootFields->FPackageLauncherDirectory = 64 platform.GetPackageLauncherDirectory(); 65 FBootFields->FAppDataDirectory = platform.GetAppDataDirectory(); 66 67 std::map<TString, TString> keys = platform.GetKeys(); 68 69 // Read from configure.cfg/Info.plist 70 AutoFreePtr<ISectionalPropertyContainer> config = 71 platform.GetConfigFile(platform.GetConfigFileName()); 72 73 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 74 keys[CONFIG_APP_ID_KEY], FBootFields->FAppID); 75 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 76 keys[JPACKAGE_APP_DATA_DIR], FBootFields->FPackageAppDataDirectory); 77 FBootFields->FPackageAppDataDirectory = 78 FilePath::FixPathForPlatform(FBootFields->FPackageAppDataDirectory); 79 80 // Main JAR. 81 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 82 keys[CONFIG_MAINJAR_KEY], FBootFields->FMainJar); 83 FBootFields->FMainJar = 84 FilePath::IncludeTrailingSeparator(GetPackageAppDirectory()) 85 + FilePath::FixPathForPlatform(FBootFields->FMainJar); 86 87 // Main Module. 88 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 89 keys[CONFIG_MAINMODULE_KEY], FBootFields->FMainModule); 90 91 // Classpath. 92 // 1. If the provided class path contains main jar then only use 93 // 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], 97 keys[CONFIG_CLASSPATH_KEY], FBootFields->FClassPath); 98 FBootFields->FClassPath = 99 FilePath::FixPathSeparatorForPlatform(FBootFields->FClassPath); 100 101 if (FBootFields->FClassPath.empty() == true) { 102 FBootFields->FClassPath = GetMainJar(); 103 } else if (FBootFields->FClassPath.find(GetMainJar()) == TString::npos) { 104 FBootFields->FClassPath = GetMainJar() 105 + FilePath::PathSeparator() + FBootFields->FClassPath; 106 } 107 108 // Modulepath. 109 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 110 keys[CONFIG_MODULEPATH_KEY], FBootFields->FModulePath); 111 FBootFields->FModulePath = 112 FilePath::FixPathSeparatorForPlatform(FBootFields->FModulePath); 113 114 // Main Class. 115 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 116 keys[CONFIG_MAINCLASSNAME_KEY], FBootFields->FMainClassName); 117 118 // Splash Screen. 119 if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], 120 keys[CONFIG_SPLASH_KEY], 121 FBootFields->FSplashScreenFileName) == true) { 122 FBootFields->FSplashScreenFileName = 123 FilePath::IncludeTrailingSeparator(GetPackageAppDirectory()) 124 + FilePath::FixPathForPlatform(FBootFields->FSplashScreenFileName); 125 126 if (FilePath::FileExists(FBootFields->FSplashScreenFileName) == false) { 127 FBootFields->FSplashScreenFileName = _T(""); 128 } 129 } 130 131 // Runtime. 132 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 133 keys[JVM_RUNTIME_KEY], FBootFields->FJVMRuntimeDirectory); 134 135 // Read jvmargs. 136 PromoteAppCDSState(config); 137 ReadJVMArgs(config); 138 139 // Read args if none were passed in. 140 if (FBootFields->FArgs.size() == 0) { 141 OrderedMap<TString, TString> args; 142 143 if (config->GetSection(keys[CONFIG_SECTION_ARGOPTIONS], args) == true) { 144 FBootFields->FArgs = Helpers::MapToNameValueList(args); 145 } 146 } 147 148 // Auto Memory. 149 TString autoMemory; 150 151 if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], 152 keys[CONFIG_APP_MEMORY], autoMemory) == true) { 153 if (autoMemory == _T("auto") || autoMemory == _T("100%")) { 154 FBootFields->FMemoryState = PackageBootFields::msAuto; 155 FBootFields->FMemorySize = platform.GetMemorySize(); 156 } else if (autoMemory.length() == 2 && isdigit(autoMemory[0]) && 157 autoMemory[1] == '%') { 158 FBootFields->FMemoryState = PackageBootFields::msAuto; 159 FBootFields->FMemorySize = 160 StringToPercentageOfNumber(autoMemory.substr(0, 1), 161 platform.GetMemorySize()); 162 } else if (autoMemory.length() == 3 && isdigit(autoMemory[0]) && 163 isdigit(autoMemory[1]) && autoMemory[2] == '%') { 164 FBootFields->FMemoryState = PackageBootFields::msAuto; 165 FBootFields->FMemorySize = 166 StringToPercentageOfNumber(autoMemory.substr(0, 2), 167 platform.GetMemorySize()); 168 } else { 169 FBootFields->FMemoryState = PackageBootFields::msManual; 170 FBootFields->FMemorySize = 0; 171 } 172 } 173 174 // Debug 175 TString debug; 176 if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], 177 keys[CONFIG_APP_DEBUG], debug) == true) { 178 FBootFields->FArgs.push_back(debug); 179 } 180 } 181 182 void Package::Clear() { 183 FreeBootFields(); 184 FInitialized = false; 185 } 186 187 // This is the only location that the AppCDS state should be modified except 188 // by command line arguments provided by the user. 189 // 190 // The state of AppCDS is as follows: 191 // 192 // -> cdsUninitialized 193 // -> cdsGenCache If -Xappcds:generatecache 194 // -> cdsDisabled If -Xappcds:off 195 // -> cdsEnabled If "AppCDSJVMOptions" section is present 196 // -> cdsAuto If "AppCDSJVMOptions" section is present and 197 // app.appcds.cache=auto 198 // -> cdsDisabled Default 199 // 200 void Package::PromoteAppCDSState(ISectionalPropertyContainer* Config) { 201 Platform& platform = Platform::GetInstance(); 202 std::map<TString, TString> keys = platform.GetKeys(); 203 204 // The AppCDS state can change at this point. 205 switch (platform.GetAppCDSState()) { 206 case cdsEnabled: 207 case cdsAuto: 208 case cdsDisabled: 209 case cdsGenCache: { 210 // Do nothing. 211 break; 212 } 213 214 case cdsUninitialized: { 215 if (Config->ContainsSection( 216 keys[CONFIG_SECTION_APPCDSJVMOPTIONS]) == true) { 217 // If the AppCDS section is present then enable AppCDS. 218 TString appCDSCacheValue; 219 220 // If running with AppCDS enabled, and the configuration has 221 // been setup so "auto" is enabled, then 222 // the launcher will attempt to generate the cache file 223 // automatically and run the application. 224 if (Config->GetValue(keys[CONFIG_SECTION_APPLICATION], 225 _T("app.appcds.cache"), appCDSCacheValue) == true && 226 appCDSCacheValue == _T("auto")) { 227 platform.SetAppCDSState(cdsAuto); 228 } 229 else { 230 platform.SetAppCDSState(cdsEnabled); 231 } 232 } else { 233 234 platform.SetAppCDSState(cdsDisabled); 235 } 236 } 237 } 238 } 239 240 void Package::ReadJVMArgs(ISectionalPropertyContainer* Config) { 241 Platform& platform = Platform::GetInstance(); 242 std::map<TString, TString> keys = platform.GetKeys(); 243 244 // Evaluate based on the current AppCDS state. 245 switch (platform.GetAppCDSState()) { 246 case cdsUninitialized: { 247 throw Exception(_T("Internal Error")); 248 } 249 250 case cdsDisabled: { 251 Config->GetSection(keys[CONFIG_SECTION_JVMOPTIONS], 252 FBootFields->FJVMArgs); 253 break; 254 } 255 256 case cdsGenCache: { 257 Config->GetSection(keys[ 258 CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS], 259 FBootFields->FJVMArgs); 260 break; 261 } 262 263 case cdsAuto: 264 case cdsEnabled: { 265 if (Config->GetValue(keys[CONFIG_SECTION_APPCDSJVMOPTIONS], 266 _T( "-XX:SharedArchiveFile"), 267 FBootFields->FAppCDSCacheFileName) == true) { 268 // File names may contain the incorrect path separators. 269 // The cache file name must be corrected at this point. 270 if (FBootFields->FAppCDSCacheFileName.empty() == false) { 271 IniFile* iniConfig = dynamic_cast<IniFile*>(Config); 272 273 if (iniConfig != NULL) { 274 FBootFields->FAppCDSCacheFileName = 275 FilePath::FixPathForPlatform( 276 FBootFields->FAppCDSCacheFileName); 277 iniConfig->SetValue(keys[ 278 CONFIG_SECTION_APPCDSJVMOPTIONS], 279 _T( "-XX:SharedArchiveFile"), 280 FBootFields->FAppCDSCacheFileName); 281 } 282 } 283 284 Config->GetSection(keys[CONFIG_SECTION_APPCDSJVMOPTIONS], 285 FBootFields->FJVMArgs); 286 } 287 288 break; 289 } 290 } 291 } 292 293 void Package::SetCommandLineArguments(int argc, TCHAR* argv[]) { 294 if (argc > 0) { 295 std::list<TString> args; 296 297 // Prepare app arguments. Skip value at index 0 - 298 // 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 328 // the following YES/NO 329 index++; 330 continue; 331 } 332 #endif //MAC 333 334 args.push_back(arg); 335 } 336 337 if (args.size() > 0) { 338 FBootFields->FArgs = args; 339 } 340 } 341 } 342 343 Package& Package::GetInstance() { 344 static Package instance; 345 // Guaranteed to be destroyed. Instantiated on first use. 346 return instance; 347 } 348 349 Package::~Package(void) { 350 FreeBootFields(); 351 } 352 353 void Package::FreeBootFields() { 354 if (FBootFields != NULL) { 355 delete FBootFields; 356 FBootFields = NULL; 357 } 358 } 359 360 OrderedMap<TString, TString> Package::GetJVMArgs() { 361 return FBootFields->FJVMArgs; 362 } 363 364 std::vector<TString> GetKeysThatAreNotDuplicates(OrderedMap<TString, 365 TString> &Defaults, OrderedMap<TString, TString> &Overrides) { 366 std::vector<TString> result; 367 std::vector<TString> overrideKeys = Overrides.GetKeys(); 368 369 for (size_t index = 0; index < overrideKeys.size(); index++) { 370 TString overridesKey = overrideKeys[index]; 371 TString overridesValue; 372 TString defaultValue; 373 374 if ((Defaults.ContainsKey(overridesKey) == false) || 375 (Defaults.GetValue(overridesKey, defaultValue) == true && 376 Overrides.GetValue(overridesKey, overridesValue) == true && 377 defaultValue != overridesValue)) { 378 result.push_back(overridesKey); 379 } 380 } 381 382 return result; 383 } 384 385 OrderedMap<TString, TString> CreateOrderedMapFromKeyList(OrderedMap<TString, 386 TString> &Map, std::vector<TString> &Keys) { 387 OrderedMap<TString, TString> result; 388 389 for (size_t index = 0; index < Keys.size(); index++) { 390 TString key = Keys[index]; 391 TString value; 392 393 if (Map.GetValue(key, value) == true) { 394 result.Append(key, value); 395 } 396 } 397 398 return result; 399 } 400 401 std::vector<TString> GetKeysThatAreNotOverridesOfDefaultValues( 402 OrderedMap<TString, TString> &Defaults, OrderedMap<TString, 403 TString> &Overrides) { 404 std::vector<TString> result; 405 std::vector<TString> keys = Overrides.GetKeys(); 406 407 for (unsigned int index = 0; index< keys.size(); index++) { 408 TString key = keys[index]; 409 410 if (Defaults.ContainsKey(key) == true) { 411 try { 412 TString value = Overrides[key]; 413 Defaults[key] = value; 414 } 415 catch (std::out_of_range) { 416 } 417 } 418 else { 419 result.push_back(key); 420 } 421 } 422 423 return result; 424 } 425 426 std::list<TString> Package::GetArgs() { 427 assert(FBootFields != NULL); 428 return FBootFields->FArgs; 429 } 430 431 TString Package::GetPackageRootDirectory() { 432 assert(FBootFields != NULL); 433 return FBootFields->FPackageRootDirectory; 434 } 435 436 TString Package::GetPackageAppDirectory() { 437 assert(FBootFields != NULL); 438 return FBootFields->FPackageAppDirectory; 439 } 440 441 TString Package::GetPackageLauncherDirectory() { 442 assert(FBootFields != NULL); 443 return FBootFields->FPackageLauncherDirectory; 444 } 445 446 TString Package::GetAppDataDirectory() { 447 assert(FBootFields != NULL); 448 return FBootFields->FAppDataDirectory; 449 } 450 451 TString Package::GetAppCDSCacheDirectory() { 452 if (FAppCDSCacheDirectory.empty()) { 453 Platform& platform = Platform::GetInstance(); 454 FAppCDSCacheDirectory = FilePath::IncludeTrailingSeparator( 455 platform.GetAppDataDirectory()) 456 + FilePath::IncludeTrailingSeparator( 457 GetPackageAppDataDirectory()) + _T("cache"); 458 459 Macros& macros = Macros::GetInstance(); 460 FAppCDSCacheDirectory = macros.ExpandMacros(FAppCDSCacheDirectory); 461 FAppCDSCacheDirectory = 462 FilePath::FixPathForPlatform(FAppCDSCacheDirectory); 463 } 464 465 return FAppCDSCacheDirectory; 466 } 467 468 TString Package::GetAppCDSCacheFileName() { 469 assert(FBootFields != NULL); 470 471 if (FBootFields->FAppCDSCacheFileName.empty() == false) { 472 Macros& macros = Macros::GetInstance(); 473 FBootFields->FAppCDSCacheFileName = 474 macros.ExpandMacros(FBootFields->FAppCDSCacheFileName); 475 FBootFields->FAppCDSCacheFileName = 476 FilePath::FixPathForPlatform(FBootFields->FAppCDSCacheFileName); 477 } 478 479 return FBootFields->FAppCDSCacheFileName; 480 } 481 482 TString Package::GetAppID() { 483 assert(FBootFields != NULL); 484 return FBootFields->FAppID; 485 } 486 487 TString Package::GetPackageAppDataDirectory() { 488 assert(FBootFields != NULL); 489 return FBootFields->FPackageAppDataDirectory; 490 } 491 492 TString Package::GetClassPath() { 493 assert(FBootFields != NULL); 494 return FBootFields->FClassPath; 495 } 496 497 TString Package::GetModulePath() { 498 assert(FBootFields != NULL); 499 return FBootFields->FModulePath; 500 } 501 502 TString Package::GetMainJar() { 503 assert(FBootFields != NULL); 504 return FBootFields->FMainJar; 505 } 506 507 TString Package::GetMainModule() { 508 assert(FBootFields != NULL); 509 return FBootFields->FMainModule; 510 } 511 512 TString Package::GetMainClassName() { 513 assert(FBootFields != NULL); 514 return FBootFields->FMainClassName; 515 } 516 517 TString Package::GetJVMLibraryFileName() { 518 assert(FBootFields != NULL); 519 520 if (FBootFields->FJVMLibraryFileName.empty() == true) { 521 Platform& platform = Platform::GetInstance(); 522 Macros& macros = Macros::GetInstance(); 523 TString jvmRuntimePath = macros.ExpandMacros(GetJVMRuntimeDirectory()); 524 FBootFields->FJVMLibraryFileName = 525 platform.GetBundledJVMLibraryFileName(jvmRuntimePath); 526 } 527 528 return FBootFields->FJVMLibraryFileName; 529 } 530 531 TString Package::GetJVMRuntimeDirectory() { 532 assert(FBootFields != NULL); 533 return FBootFields->FJVMRuntimeDirectory; 534 } 535 536 TString Package::GetSplashScreenFileName() { 537 assert(FBootFields != NULL); 538 return FBootFields->FSplashScreenFileName; 539 } 540 541 bool Package::HasSplashScreen() { 542 assert(FBootFields != NULL); 543 return FilePath::FileExists(FBootFields->FSplashScreenFileName); 544 } 545 546 TString Package::GetCommandName() { 547 assert(FBootFields != NULL); 548 return FBootFields->FCommandName; 549 } 550 551 TPlatformNumber Package::GetMemorySize() { 552 assert(FBootFields != NULL); 553 return FBootFields->FMemorySize; 554 } 555 556 PackageBootFields::MemoryState Package::GetMemoryState() { 557 assert(FBootFields != NULL); 558 return FBootFields->FMemoryState; 559 } 560 561 DebugState Package::Debugging() { 562 return FDebugging; 563 }