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