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