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 }