1 /* 2 * Copyright (c) 2020, 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 <cstring> 27 #include <jni.h> 28 #include "JvmLauncher.h" 29 #include "Log.h" 30 #include "Dll.h" 31 #include "CfgFile.h" 32 #include "FileUtils.h" 33 #include "Toolbox.h" 34 #include "ErrorHandling.h" 35 36 37 Jvm& Jvm::initFromConfigFile(const CfgFile& cfgFile) { 38 const CfgFile::Properties& appOptions = cfgFile.getProperties( 39 SectionName::Application); 40 41 do { 42 const CfgFile::Properties::const_iterator modulepath = appOptions.find( 43 PropertyName::modulepath); 44 if (modulepath != appOptions.end()) { 45 tstring_array::const_iterator it = modulepath->second.begin(); 46 const tstring_array::const_iterator end = modulepath->second.end(); 47 for (; it != end; ++it) { 48 addArgument(_T("--module-path")); 49 addArgument(*it); 50 }; 51 } 52 } while (0); 53 54 do { 55 const CfgFile::Properties::const_iterator classpath = appOptions.find( 56 PropertyName::classpath); 57 if (classpath != appOptions.end()) { 58 addArgument(_T("-classpath")); 59 addArgument(CfgFile::asPathList(*classpath)); 60 } 61 } while (0); 62 63 do { 64 const CfgFile::Properties::const_iterator splash = appOptions.find( 65 PropertyName::splash); 66 if (splash != appOptions.end()) { 67 const tstring splashPath = CfgFile::asString(*splash); 68 if (FileUtils::isFileExists(splashPath)) { 69 addArgument(_T("-splash:") + splashPath); 70 } else { 71 LOG_WARNING(tstrings::any() 72 << "Splash property ignored. File \"" 73 << splashPath << "\" not found"); 74 } 75 } 76 } while (0); 77 78 do { 79 const CfgFile::Properties& section = cfgFile.getProperties( 80 SectionName::JavaOptions); 81 const CfgFile::Properties::const_iterator javaOptions = section.find( 82 PropertyName::javaOptions); 83 if (javaOptions != section.end()) { 84 tstring_array::const_iterator it = javaOptions->second.begin(); 85 const tstring_array::const_iterator end = javaOptions->second.end(); 86 for (; it != end; ++it) { 87 addArgument(*it); 88 }; 89 } 90 } while (0); 91 92 do { 93 addArgument(_T("-Djpackage.app-path=") 94 + SysInfo::getProcessModulePath()); 95 } while (0); 96 97 // No validation of data in config file related to how Java app should be 98 // launched intentionally. 99 // Just read what is in config file and put on jvm's command line as is. 100 101 do { // Run modular app 102 const CfgFile::Properties::const_iterator mainmodule = appOptions.find( 103 PropertyName::mainmodule); 104 if (mainmodule != appOptions.end()) { 105 addArgument(_T("-m")); 106 addArgument(CfgFile::asString(*mainmodule)); 107 } 108 } while (0); 109 110 do { // Run main class 111 const CfgFile::Properties::const_iterator mainclass = appOptions.find( 112 PropertyName::mainclass); 113 if (mainclass != appOptions.end()) { 114 addArgument(CfgFile::asString(*mainclass)); 115 } 116 } while (0); 117 118 do { // Run jar 119 const CfgFile::Properties::const_iterator mainjar = appOptions.find( 120 PropertyName::mainjar); 121 if (mainjar != appOptions.end()) { 122 addArgument(_T("-jar")); 123 addArgument(CfgFile::asString(*mainjar)); 124 } 125 } while (0); 126 127 do { 128 const CfgFile::Properties& section = cfgFile.getProperties( 129 SectionName::ArgOptions); 130 const CfgFile::Properties::const_iterator arguments = section.find( 131 PropertyName::arguments); 132 if (arguments != section.end()) { 133 tstring_array::const_iterator it = arguments->second.begin(); 134 const tstring_array::const_iterator end = arguments->second.end(); 135 for (; it != end; ++it) { 136 addArgument(*it); 137 }; 138 } 139 } while (0); 140 141 return *this; 142 } 143 144 145 bool Jvm::isWithSplash() const { 146 tstring_array::const_iterator it = args.begin(); 147 const tstring_array::const_iterator end = args.end(); 148 for (; it != end; ++it) { 149 if (tstrings::startsWith(*it, _T("-splash:"))) { 150 return true; 151 } 152 } 153 return false; 154 } 155 156 157 namespace { 158 void convertArgs(const std::vector<std::string>& args, std::vector<char*>& argv) { 159 argv.reserve(args.size() + 1); 160 argv.resize(0); 161 162 std::vector<std::string>::const_iterator it = args.begin(); 163 const std::vector<std::string>::const_iterator end = args.end(); 164 165 for (; it != end; ++it) { 166 argv.push_back(const_cast<char*>(it->c_str())); 167 }; 168 169 // Add treminal '0'. 170 argv.push_back(0); 171 } 172 } // namespace 173 174 void Jvm::launch() { 175 typedef int (JNICALL *LaunchFuncType)(int argc, char ** argv, 176 int jargc, const char** jargv, 177 int appclassc, const char** appclassv, 178 const char* fullversion, 179 const char* dotversion, 180 const char* pname, 181 const char* lname, 182 jboolean javaargs, 183 jboolean cpwildcard, 184 jboolean javaw, 185 jint ergo); 186 187 std::vector<char*> argv; 188 #ifdef TSTRINGS_WITH_WCHAR 189 std::vector<std::string> mbcs_args; 190 do { 191 tstring_array::const_iterator it = args.begin(); 192 const tstring_array::const_iterator end = args.end(); 193 for (; it != end; ++it) { 194 mbcs_args.push_back(tstrings::toACP(*it)); 195 } 196 } while (0); 197 convertArgs(mbcs_args, argv); 198 #else 199 convertArgs(args, argv); 200 #endif 201 202 // Don't count terminal '0'. 203 const int argc = (int)argv.size() - 1; 204 205 LOG_TRACE(tstrings::any() << "JVM library: \"" << jvmPath << "\""); 206 207 DllFunction<LaunchFuncType> func(Dll(jvmPath), "JLI_Launch"); 208 int exitStatus = func(argc, argv.data(), 209 0, 0, 210 0, 0, 211 "", 212 "", 213 "java", 214 "java", 215 JNI_FALSE, 216 JNI_FALSE, 217 JNI_FALSE, 218 0); 219 220 if (exitStatus != 0) { 221 JP_THROW("Failed to launch JVM"); 222 } 223 }