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 // No validation of data in config file related to how Java app should be 93 // launched intentionally. 94 // Just read what is in config file and put on jvm's command line as is. 95 96 do { // Run modular app 97 const CfgFile::Properties::const_iterator mainmodule = appOptions.find( 98 PropertyName::mainmodule); 99 if (mainmodule != appOptions.end()) { 100 addArgument(_T("-m")); 101 addArgument(CfgFile::asString(*mainmodule)); 102 } 103 } while (0); 104 105 do { // Run main class 106 const CfgFile::Properties::const_iterator mainclass = appOptions.find( 107 PropertyName::mainclass); 108 if (mainclass != appOptions.end()) { 109 addArgument(CfgFile::asString(*mainclass)); 110 } 111 } while (0); 112 113 do { // Run jar 114 const CfgFile::Properties::const_iterator mainjar = appOptions.find( 115 PropertyName::mainjar); 116 if (mainjar != appOptions.end()) { 117 addArgument(_T("-jar")); 118 addArgument(CfgFile::asString(*mainjar)); 119 } 120 } while (0); 121 122 do { 123 const CfgFile::Properties& section = cfgFile.getProperties( 124 SectionName::ArgOptions); 125 const CfgFile::Properties::const_iterator arguments = section.find( 126 PropertyName::arguments); 127 if (arguments != section.end()) { 128 tstring_array::const_iterator it = arguments->second.begin(); 129 const tstring_array::const_iterator end = arguments->second.end(); 130 for (; it != end; ++it) { 131 addArgument(*it); 132 }; 133 } 134 } while (0); 135 136 return *this; 137 } 138 139 140 bool Jvm::isWithSplash() const { 141 tstring_array::const_iterator it = args.begin(); 142 const tstring_array::const_iterator end = args.end(); 143 for (; it != end; ++it) { 144 if (tstrings::startsWith(*it, _T("-splash:"))) { 145 return true; 146 } 147 } 148 return false; 149 } 150 151 152 namespace { 153 void convertArgs(const std::vector<std::string>& args, std::vector<char*>& argv) { 154 argv.reserve(args.size() + 1); 155 argv.resize(0); 156 157 std::vector<std::string>::const_iterator it = args.begin(); 158 const std::vector<std::string>::const_iterator end = args.end(); 159 160 for (; it != end; ++it) { 161 argv.push_back(const_cast<char*>(it->c_str())); 162 }; 163 164 // Add treminal '0'. 165 argv.push_back(0); 166 } 167 } // namespace 168 169 void Jvm::launch() { 170 typedef int (JNICALL *LaunchFuncType)(int argc, char ** argv, 171 int jargc, const char** jargv, 172 int appclassc, const char** appclassv, 173 const char* fullversion, 174 const char* dotversion, 175 const char* pname, 176 const char* lname, 177 jboolean javaargs, 178 jboolean cpwildcard, 179 jboolean javaw, 180 jint ergo); 181 182 std::vector<char*> argv; 183 #ifdef TSTRINGS_WITH_WCHAR 184 std::vector<std::string> mbcs_args; 185 do { 186 tstring_array::const_iterator it = args.begin(); 187 const tstring_array::const_iterator end = args.end(); 188 for (; it != end; ++it) { 189 mbcs_args.push_back(tstrings::toACP(*it)); 190 } 191 } while (0); 192 convertArgs(mbcs_args, argv); 193 #else 194 convertArgs(args, argv); 195 #endif 196 197 // Don't count terminal '0'. 198 const int argc = (int)argv.size() - 1; 199 200 LOG_TRACE(tstrings::any() << "JVM library: \"" << jvmPath << "\""); 201 202 DllFunction<LaunchFuncType> func(Dll(jvmPath), "JLI_Launch"); 203 int exitStatus = func(argc, argv.data(), 204 0, 0, 205 0, 0, 206 "", 207 "", 208 "java", 209 "java", 210 JNI_FALSE, 211 JNI_FALSE, 212 JNI_FALSE, 213 0); 214 215 if (exitStatus != 0) { 216 JP_THROW("Failed to launch JVM"); 217 } 218 }