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