| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| /* |
| * Author: Tomas Holy |
| */ |
| |
| #include "utilsfuncs.h" |
| #include "platformlauncher.h" |
| #include "argnames.h" |
| |
| volatile extern int exitStatus; |
| |
| using namespace std; |
| |
| const char *PlatformLauncher::HELP_MSG = |
| "\nUsage: launcher {options} arguments\n\ |
| \n\ |
| General options:\n\ |
| --help show this help\n\ |
| --jdkhome <path> path to JDK\n\ |
| -J<jvm_option> pass <jvm_option> to JVM\n\ |
| \n\ |
| --cp:p <classpath> prepend <classpath> to classpath\n\ |
| --cp:a <classpath> append <classpath> to classpath\n\ |
| \n\ |
| --fork-java run java in separate process\n\ |
| --trace <path> path for launcher log (for trouble shooting)\n\ |
| \n"; |
| |
| const char *PlatformLauncher::REQ_JAVA_VERSION = "1.8"; |
| |
| const char *PlatformLauncher::OPT_JDK_HOME = "-Djdk.home="; |
| const char *PlatformLauncher::OPT_NB_PLATFORM_HOME = "-Dnetbeans.home="; |
| const char *PlatformLauncher::OPT_NB_CLUSTERS = "-Dnetbeans.dirs="; |
| const char *PlatformLauncher::OPT_NB_USERDIR = "-Dnetbeans.user="; |
| const char *PlatformLauncher::OPT_DEFAULT_USERDIR_ROOT = "-Dnetbeans.default_userdir_root="; |
| const char *PlatformLauncher::OPT_HEAP_DUMP = "-XX:+HeapDumpOnOutOfMemoryError"; |
| const char *PlatformLauncher::OPT_HEAP_DUMP_PATH = "-XX:HeapDumpPath="; |
| const char *PlatformLauncher::OPT_KEEP_WORKING_SET_ON_MINIMIZE = "-Dsun.awt.keepWorkingSetOnMinimize=true"; |
| const char *PlatformLauncher::OPT_CLASS_PATH = "-Djava.class.path="; |
| const char *PlatformLauncher::OPT_SPLASH = "-splash:"; |
| const char *PlatformLauncher::OPT_SPLASH_PATH = "\\var\\cache\\splash.png"; |
| |
| const char *PlatformLauncher::HEAP_DUMP_PATH = "\\var\\log\\heapdump.hprof"; |
| const char *PlatformLauncher::RESTART_FILE_PATH = "\\var\\restart"; |
| |
| const char *PlatformLauncher::UPDATER_MAIN_CLASS = "org/netbeans/updater/UpdaterFrame"; |
| const char *PlatformLauncher::IDE_MAIN_CLASS = "org/netbeans/Main"; |
| |
| PlatformLauncher::PlatformLauncher() |
| : separateProcess(false) |
| , suppressConsole(false) |
| , heapDumpPathOptFound(false) |
| , nosplash(false) |
| , exiting(false) { |
| } |
| |
| PlatformLauncher::PlatformLauncher(const PlatformLauncher& orig) { |
| } |
| |
| PlatformLauncher::~PlatformLauncher() { |
| } |
| |
| bool PlatformLauncher::start(char* argv[], int argc, DWORD *retCode) { |
| if (!checkLoggingArg(argc, argv, false) || !initPlatformDir() || !parseArgs(argc, argv)) { |
| return false; |
| } |
| disableFolderVirtualization(GetCurrentProcess()); |
| |
| if (jdkhome.empty()) { |
| if (!jvmLauncher.initialize(REQ_JAVA_VERSION)) { |
| logErr(false, true, "Cannot find Java %s or higher.", REQ_JAVA_VERSION); |
| return false; |
| } |
| } |
| jvmLauncher.getJavaPath(jdkhome); |
| |
| deleteNewClustersFile(); |
| prepareOptions(); |
| |
| if (nextAction.empty()) { |
| if (shouldAutoUpdateClusters(true)) { |
| // run updater |
| if (!run(true, retCode)) { |
| return false; |
| } |
| } |
| |
| while (true) { |
| // run app |
| if (!run(false, retCode)) { |
| return false; |
| } |
| |
| if (shouldAutoUpdateClusters(false)) { |
| // run updater |
| if (!run(true, retCode)) { |
| return false; |
| } |
| } else if (!restartRequested()) { |
| break; |
| } |
| } |
| } else { |
| if (nextAction == ARG_NAME_LA_START_APP) { |
| return run(false, retCode); |
| } else if (nextAction == ARG_NAME_LA_START_AU) { |
| if (shouldAutoUpdateClusters(false)) { |
| return run(true, retCode); |
| } |
| } else { |
| logErr(false, true, "We should not get here."); |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| bool PlatformLauncher::run(bool updater, DWORD *retCode) { |
| logMsg(updater ? "Starting updater..." : "Starting application..."); |
| constructClassPath(updater); |
| const char *mainClass; |
| if (updater) { |
| mainClass = UPDATER_MAIN_CLASS; |
| nextAction = ARG_NAME_LA_START_APP; |
| } else { |
| DeleteFile((userDir + RESTART_FILE_PATH).c_str()); |
| mainClass = bootclass.empty() ? IDE_MAIN_CLASS : bootclass.c_str(); |
| nextAction = ARG_NAME_LA_START_AU; |
| } |
| |
| string option = OPT_NB_CLUSTERS; |
| option += auClusters.empty() ? clusters : auClusters; |
| javaOptions.push_back(option); |
| |
| option = OPT_CLASS_PATH; |
| option += classPath; |
| javaOptions.push_back(option); |
| |
| jvmLauncher.setSuppressConsole(suppressConsole); |
| bool rc = jvmLauncher.start(mainClass, progArgs, javaOptions, separateProcess, retCode); |
| if (!separateProcess) { |
| exit(0); |
| } |
| |
| javaOptions.pop_back(); |
| javaOptions.pop_back(); |
| return rc; |
| } |
| |
| |
| |
| bool PlatformLauncher::initPlatformDir() { |
| char path[MAX_PATH] = ""; |
| getCurrentModulePath(path, MAX_PATH); |
| logMsg("Module: %s", path); |
| char *bslash = strrchr(path, '\\'); |
| if (!bslash) { |
| return false; |
| } |
| *bslash = '\0'; |
| bslash = strrchr(path, '\\'); |
| if (!bslash) { |
| return false; |
| } |
| *bslash = '\0'; |
| clusters = platformDir = path; |
| logMsg("Platform dir: %s", platformDir.c_str()); |
| return true; |
| } |
| |
| bool PlatformLauncher::parseArgs(int argc, char *argv[]) { |
| #define CHECK_ARG \ |
| if (i+1 == argc) {\ |
| logErr(false, true, "Argument is missing for \"%s\" option.", argv[i]);\ |
| return false;\ |
| } |
| |
| logMsg("Parsing arguments:"); |
| for (int i = 0; i < argc; i++) { |
| logMsg("\t%s", argv[i]); |
| } |
| |
| for (int i = 0; i < argc; i++) { |
| if (strcmp(ARG_NAME_SEPAR_PROC, argv[i]) == 0) { |
| separateProcess = true; |
| logMsg("Run Java in separater process"); |
| } else if (strcmp(ARG_NAME_LAUNCHER_LOG, argv[i]) == 0) { |
| CHECK_ARG; |
| i++; |
| } else if (strcmp(ARG_NAME_LA_START_APP, argv[i]) == 0 |
| || strcmp(ARG_NAME_LA_START_AU, argv[i]) == 0) { |
| nextAction = argv[i]; |
| logMsg("Next launcher action: %s", nextAction.c_str()); |
| } else if (strcmp(ARG_NAME_LA_PPID, argv[i]) == 0) { |
| CHECK_ARG; |
| suppressConsole = false; |
| parentProcID = argv[++i]; |
| logMsg("Parent process ID found: %s", parentProcID.c_str()); |
| } else if (strcmp(ARG_NAME_USER_DIR, argv[i]) == 0) { |
| CHECK_ARG; |
| char tmp[MAX_PATH + 1] = {0}; |
| strncpy(tmp, argv[++i], MAX_PATH); |
| if (strcmp(tmp, "memory") != 0 && !normalizePath(tmp, MAX_PATH)) { |
| logErr(false, true, "User directory path \"%s\" is not valid.", argv[i]); |
| return false; |
| } |
| userDir = tmp; |
| logMsg("User dir: %s", userDir.c_str()); |
| } else if (strcmp(ARG_DEFAULT_USER_DIR_ROOT, argv[i]) == 0) { |
| CHECK_ARG; |
| char tmp[MAX_PATH + 1] = {0}; |
| strncpy(tmp, argv[++i], MAX_PATH); |
| if (strcmp(tmp, "memory") != 0 && !normalizePath(tmp, MAX_PATH)) { |
| logErr(false, true, "Default User directory path \"%s\" is not valid.", argv[i]); |
| return false; |
| } |
| defaultUserDirRoot = tmp; |
| logMsg("Default Userdir root: %s", defaultUserDirRoot.c_str()); |
| } else if (strcmp(ARG_NAME_CLUSTERS, argv[i]) == 0) { |
| CHECK_ARG; |
| clusters = argv[++i]; |
| } else if (strcmp(ARG_NAME_BOOTCLASS, argv[i]) == 0) { |
| CHECK_ARG; |
| bootclass = argv[++i]; |
| } else if (strcmp(ARG_NAME_JDKHOME, argv[i]) == 0) { |
| CHECK_ARG; |
| if (jdkhome.empty()) { |
| jdkhome = argv[++i]; |
| if (!jvmLauncher.initialize(jdkhome.c_str())) { |
| logMsg("Cannot locate java installation in specified jdkhome: %s", jdkhome.c_str()); |
| string errMsg = "Cannot locate java installation in specified jdkhome:\n"; |
| errMsg += jdkhome; |
| errMsg += "\nDo you want to try to use default version?"; |
| jdkhome = ""; |
| if (::MessageBox(NULL, errMsg.c_str(), "Invalid jdkhome specified", MB_ICONQUESTION | MB_YESNO) == IDNO) { |
| return false; |
| } |
| } |
| } else { |
| i++; |
| } |
| } else if (strcmp(ARG_NAME_CP_PREPEND, argv[i]) == 0 |
| || strcmp(ARG_NAME_CP_PREPEND + 1, argv[i]) == 0) { |
| CHECK_ARG; |
| cpBefore += argv[++i]; |
| } else if (strcmp(ARG_NAME_CP_APPEND, argv[i]) == 0 |
| || strcmp(ARG_NAME_CP_APPEND + 1, argv[i]) == 0 |
| || strncmp(ARG_NAME_CP_APPEND + 1, argv[i], 3) == 0 |
| || strncmp(ARG_NAME_CP_APPEND, argv[i], 4) == 0) { |
| CHECK_ARG; |
| cpAfter += argv[++i]; |
| } else if (strncmp("-J", argv[i], 2) == 0) { |
| javaOptions.push_back(argv[i] + 2); |
| if (strncmp(argv[i] + 2, OPT_HEAP_DUMP_PATH, strlen(OPT_HEAP_DUMP_PATH)) == 0) { |
| heapDumpPathOptFound = true; |
| } |
| } else { |
| if (strcmp(argv[i], "-h") == 0 |
| || strcmp(argv[i], "-help") == 0 |
| || strcmp(argv[i], "--help") == 0 |
| || strcmp(argv[i], "/?") == 0) { |
| printToConsole(HELP_MSG); |
| if (!appendHelp.empty()) { |
| printToConsole(appendHelp.c_str()); |
| } |
| } else if (strcmp(ARG_NAME_NOSPLASH, argv[i]) == 0) { |
| nosplash = true; |
| } |
| progArgs.push_back(argv[i]); |
| } |
| } |
| return true; |
| } |
| |
| bool PlatformLauncher::processAutoUpdateCL() { |
| logMsg("processAutoUpdateCL()..."); |
| if (userDir.empty()) { |
| logMsg("\tuserdir empty, quiting"); |
| return false; |
| } |
| string listPath = userDir; |
| listPath += "\\update\\download\\netbeans.dirs"; |
| |
| WIN32_FIND_DATA fd = {0}; |
| HANDLE hFind = 0; |
| hFind = FindFirstFile(listPath.c_str(), &fd); |
| if (hFind == INVALID_HANDLE_VALUE) { |
| logMsg("File \"%s\" does not exist", listPath.c_str()); |
| return false; |
| } |
| FindClose(hFind); |
| |
| FILE *file = fopen(listPath.c_str(), "r"); |
| if (!file) { |
| logErr(true, false, "Cannot open file %s", listPath.c_str()); |
| return false; |
| } |
| |
| int len = fd.nFileSizeLow + 1; |
| char *str = new char[len]; |
| if (!fgets(str, len, file)) { |
| fclose(file); |
| delete[] str; |
| logErr(true, false, "Cannot read from file %s", listPath.c_str()); |
| return false; |
| } |
| len = strlen(str) - 1; |
| if (str[len] == '\n') { |
| str[len] = '\0'; |
| } |
| |
| auClusters = str; |
| fclose(file); |
| delete[] str; |
| return true; |
| } |
| |
| void PlatformLauncher::deleteNewClustersFile() { |
| logMsg("deleteNewClustersFile()..."); |
| if (userDir.empty()) { |
| logMsg("\tuserdir empty, quiting"); |
| return; |
| } |
| string listPath = userDir; |
| listPath += "\\update\\download\\netbeans.dirs"; |
| |
| if (fileExists(listPath.c_str())) { |
| DeleteFileA(listPath.c_str()); |
| logMsg("%s file deleted.", listPath.c_str()); |
| } |
| } |
| |
| // check if new updater exists, if exists install it (replace old one) and remove ...\new_updater directory |
| bool PlatformLauncher::checkForNewUpdater(const char *basePath) { |
| logMsg("checkForNewUpdater() at %s", basePath); |
| BOOL removeDir = false; |
| string srcPath = basePath; |
| srcPath += "\\update\\new_updater\\updater.jar"; |
| WIN32_FIND_DATA fd = {0}; |
| HANDLE hFind = FindFirstFile(srcPath.c_str(), &fd); |
| if (hFind != INVALID_HANDLE_VALUE) { |
| logMsg("New updater found: %s", srcPath.c_str()); |
| FindClose(hFind); |
| string destPath = basePath; |
| destPath += "\\modules\\ext\\updater.jar"; |
| createPath(destPath.c_str()); |
| |
| int i = 0; |
| while (true) { |
| if (MoveFileEx(srcPath.c_str(), destPath.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { |
| break; |
| } |
| if (exiting || ++i > 10) { |
| logErr(true, false, "Failed to move \"%s\" to \"%s\"", srcPath.c_str(), destPath.c_str()); |
| return false; |
| } |
| logErr(true, false, "Failed to move \"%s\" to \"%s\", trying to wait", srcPath.c_str(), destPath.c_str()); |
| Sleep(100); |
| } |
| logMsg("New updater successfully moved from \"%s\" to \"%s\"", srcPath.c_str(), destPath.c_str()); |
| removeDir = true; |
| } else { |
| logMsg("No new updater at %s", srcPath.c_str()); |
| } |
| string locPath = basePath; |
| locPath += "\\update\\new_updater\\updater_*.jar"; |
| hFind = FindFirstFile(locPath.c_str(), &fd); |
| while (hFind != INVALID_HANDLE_VALUE) { |
| string destPath = basePath; |
| string name = fd.cFileName; |
| logMsg("New updater localization found: %s", name.c_str()); |
| destPath += "\\modules\\ext\\locale\\"; |
| destPath += name; |
| |
| string fromPath = basePath; |
| fromPath += "\\update\\new_updater\\"; |
| fromPath += name; |
| |
| createPath(destPath.c_str()); |
| |
| int i = 0; |
| while (true) { |
| if (MoveFileEx(fromPath.c_str(), destPath.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { |
| break; |
| } |
| if (exiting || ++i > 10) { |
| logErr(true, false, "Failed to move \"%s\" to \"%s\"", fromPath.c_str(), destPath.c_str()); |
| return false; |
| } |
| logErr(true, false, "Failed to move \"%s\" to \"%s\", trying to wait", fromPath.c_str(), destPath.c_str()); |
| Sleep(100); |
| } |
| logMsg("New updater successfully moved from \"%s\" to \"%s\"", fromPath.c_str(), destPath.c_str()); |
| removeDir = true; |
| |
| if (!FindNextFile(hFind, &fd)) { |
| break; |
| } |
| } |
| FindClose(hFind); |
| |
| if (removeDir) { |
| srcPath.erase(srcPath.rfind('\\')); |
| logMsg("Removing directory \"%s\"", srcPath.c_str()); |
| if (!RemoveDirectory(srcPath.c_str())) { |
| logErr(true, false, "Failed to remove directory \"%s\"", srcPath.c_str()); |
| } |
| } |
| return true; |
| } |
| |
| bool PlatformLauncher::shouldAutoUpdate(bool firstStart, const char *basePath) { |
| // The logic is following: |
| // if there is an NBM for installation then run updater |
| // unless it is not a first start and we asked to install later (on next start) |
| |
| // then also check if last run left list of modules to disable/uninstall and |
| // did not mark them to be deactivated later (on next start) |
| string path = basePath; |
| path += "\\update\\download\\*.nbm"; |
| logMsg("Checking for updates: %s", path.c_str()); |
| WIN32_FIND_DATA fd; |
| HANDLE hFindNbms = FindFirstFile(path.c_str(), &fd); |
| if (hFindNbms != INVALID_HANDLE_VALUE) { |
| logMsg("Some updates found at %s", path.c_str()); |
| FindClose(hFindNbms); |
| } else { |
| //also check for OSGi jars if *.nbm not found |
| path = basePath; |
| path += "\\update\\download\\*.jar"; |
| hFindNbms = FindFirstFile(path.c_str(), &fd); |
| if (hFindNbms != INVALID_HANDLE_VALUE) { |
| logMsg("Some OSGi updates found at %s", path.c_str()); |
| FindClose(hFindNbms); |
| } |
| } |
| |
| path = basePath; |
| path += "\\update\\download\\install_later.xml"; |
| HANDLE hFind = FindFirstFile(path.c_str(), &fd); |
| if (hFind != INVALID_HANDLE_VALUE) { |
| logMsg("install_later.xml found: %s", path.c_str()); |
| FindClose(hFind); |
| } |
| |
| if (hFindNbms != INVALID_HANDLE_VALUE && (firstStart || hFind == INVALID_HANDLE_VALUE)) { |
| return true; |
| } |
| |
| path = basePath; |
| path += "\\update\\deactivate\\deactivate_later.txt"; |
| hFind = FindFirstFile(path.c_str(), &fd); |
| if (hFind != INVALID_HANDLE_VALUE) { |
| logMsg("deactivate_later.txt found: %s", path.c_str()); |
| FindClose(hFind); |
| } |
| |
| if (firstStart || hFind == INVALID_HANDLE_VALUE) { |
| path = basePath; |
| path += "\\update\\deactivate\\to_disable.txt"; |
| hFind = FindFirstFile(path.c_str(), &fd); |
| if (hFind != INVALID_HANDLE_VALUE) { |
| logMsg("to_disable.txt found: %s", path.c_str()); |
| FindClose(hFind); |
| return true; |
| } |
| |
| path = basePath; |
| path += "\\update\\deactivate\\to_uninstall.txt"; |
| hFind = FindFirstFile(path.c_str(), &fd); |
| if (hFind != INVALID_HANDLE_VALUE) { |
| logMsg("to_uninstall.txt found: %s", path.c_str()); |
| FindClose(hFind); |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| bool PlatformLauncher::shouldAutoUpdateClusters(bool firstStart) { |
| bool runUpdater = false; |
| string cl = processAutoUpdateCL() ? auClusters : clusters; |
| checkForNewUpdater(platformDir.c_str()); |
| runUpdater = shouldAutoUpdate(firstStart, platformDir.c_str()); |
| |
| const char delim = ';'; |
| string::size_type start = cl.find_first_not_of(delim, 0); |
| string::size_type end = cl.find_first_of(delim, start); |
| while (string::npos != end || string::npos != start) { |
| string cluster = cl.substr(start, end - start); |
| checkForNewUpdater(cluster.c_str()); |
| if (!runUpdater) { |
| runUpdater = shouldAutoUpdate(firstStart, cluster.c_str()); |
| } |
| start = cl.find_first_not_of(delim, end); |
| end = cl.find_first_of(delim, start); |
| } |
| |
| checkForNewUpdater(userDir.c_str()); |
| if (!runUpdater) { |
| runUpdater = shouldAutoUpdate(firstStart, userDir.c_str()); |
| } |
| return runUpdater; |
| } |
| |
| void PlatformLauncher::prepareOptions() { |
| string option = OPT_JDK_HOME; |
| option += jdkhome; |
| javaOptions.push_back(option); |
| |
| if (!nosplash) { |
| string splashPath = userDir; |
| splashPath += OPT_SPLASH_PATH; |
| if (fileExists(splashPath.c_str())) { |
| javaOptions.push_back(OPT_SPLASH + splashPath); |
| } |
| } |
| |
| option = OPT_NB_PLATFORM_HOME; |
| option += platformDir; |
| javaOptions.push_back(option); |
| |
| option = OPT_NB_USERDIR; |
| option += userDir; |
| javaOptions.push_back(option); |
| |
| option = OPT_DEFAULT_USERDIR_ROOT; |
| option += defaultUserDirRoot; |
| javaOptions.push_back(option); |
| |
| option = OPT_HEAP_DUMP; |
| javaOptions.push_back(option); |
| |
| if (!heapDumpPathOptFound) { |
| option = OPT_HEAP_DUMP_PATH; |
| option += userDir; |
| option += HEAP_DUMP_PATH; |
| javaOptions.push_back(option); |
| // rename old heap dump to .old |
| string heapdumpfile = userDir + HEAP_DUMP_PATH; |
| if (fileExists(heapdumpfile.c_str())) { |
| string heapdumpfileold = heapdumpfile + ".old"; |
| if (fileExists(heapdumpfileold.c_str())) { |
| DeleteFileA(heapdumpfileold.c_str()); |
| } |
| MoveFile (heapdumpfile.c_str(), heapdumpfileold.c_str()); |
| } |
| } |
| |
| option = OPT_KEEP_WORKING_SET_ON_MINIMIZE; |
| javaOptions.push_back(option); |
| } |
| |
| string & PlatformLauncher::constructClassPath(bool runUpdater) { |
| logMsg("constructClassPath()"); |
| addedToCP.clear(); |
| classPath = cpBefore; |
| |
| addJarsToClassPathFrom(userDir.c_str()); |
| addJarsToClassPathFrom(platformDir.c_str()); |
| |
| if (runUpdater) { |
| const char *baseUpdaterPath = userDir.c_str(); |
| string updaterPath = userDir + "\\modules\\ext\\updater.jar"; |
| |
| // if user updater does not exist, use updater from platform |
| if (!fileExists(updaterPath.c_str())) { |
| baseUpdaterPath = platformDir.c_str(); |
| updaterPath = platformDir + "\\modules\\ext\\updater.jar"; |
| } |
| |
| addToClassPath(updaterPath.c_str(), false); |
| addFilesToClassPath(baseUpdaterPath, "\\modules\\ext\\locale", "updater_*.jar"); |
| } |
| |
| addToClassPath((jdkhome + "\\lib\\dt.jar").c_str(), true); |
| addToClassPath((jdkhome + "\\lib\\tools.jar").c_str(), true); |
| |
| if (!cpAfter.empty()) { |
| addToClassPath(cpAfter.c_str(), false); |
| } |
| logMsg("ClassPath: %s", classPath.c_str()); |
| return classPath; |
| } |
| |
| void PlatformLauncher::addJarsToClassPathFrom(const char *dir) { |
| addFilesToClassPath(dir, "lib\\patches", "*.jar"); |
| addFilesToClassPath(dir, "lib\\patches", "*.zip"); |
| |
| addFilesToClassPath(dir, "lib", "*.jar"); |
| addFilesToClassPath(dir, "lib", "*.zip"); |
| |
| addFilesToClassPath(dir, "lib\\locale", "*.jar"); |
| addFilesToClassPath(dir, "lib\\locale", "*.zip"); |
| } |
| |
| void PlatformLauncher::addFilesToClassPath(const char *dir, const char *subdir, const char *pattern) { |
| logMsg("addFilesToClassPath()\n\tdir: %s\n\tsubdir: %s\n\tpattern: %s", dir, subdir, pattern); |
| string path = dir; |
| path += '\\'; |
| path += subdir; |
| path += '\\'; |
| |
| WIN32_FIND_DATA fd = {0}; |
| string patternPath = path + pattern; |
| HANDLE hFind = FindFirstFile(patternPath.c_str(), &fd); |
| if (hFind == INVALID_HANDLE_VALUE) { |
| logMsg("Nothing found (%s)", patternPath.c_str()); |
| return; |
| } |
| do { |
| string name = subdir; |
| name += fd.cFileName; |
| string fullName = path + fd.cFileName; |
| if (addedToCP.insert(name).second) { |
| addToClassPath(fullName.c_str()); |
| } else { |
| logMsg("\"%s\" already added, skipping \"%s\"", name.c_str(), fullName.c_str()); |
| } |
| } while (FindNextFile(hFind, &fd)); |
| FindClose(hFind); |
| } |
| |
| void PlatformLauncher::addToClassPath(const char *path, bool onlyIfExists) { |
| logMsg("addToClassPath()\n\tpath: %s\n\tonlyIfExists: %s", path, onlyIfExists ? "true" : "false"); |
| if (onlyIfExists && !fileExists(path)) { |
| return; |
| } |
| |
| if (!classPath.empty()) { |
| classPath += ';'; |
| } |
| classPath += path; |
| } |
| |
| void PlatformLauncher::appendToHelp(const char *msg) { |
| if (msg) { |
| appendHelp = msg; |
| } |
| } |
| |
| bool PlatformLauncher::restartRequested() { |
| return fileExists((userDir + RESTART_FILE_PATH).c_str()); |
| } |
| |
| void PlatformLauncher::onExit() { |
| logMsg("onExit()"); |
| if (exitStatus == -252) { |
| logMsg("Exiting from CLI client, will not restart."); |
| return; |
| } |
| |
| if (exiting) { |
| logMsg("Already exiting, no need to schedule restart"); |
| return; |
| } |
| |
| exiting = true; |
| |
| if (separateProcess) { |
| logMsg("JVM in separate process, no need to restart"); |
| return; |
| } |
| |
| bool restart = (nextAction == ARG_NAME_LA_START_APP || (nextAction == ARG_NAME_LA_START_AU && shouldAutoUpdateClusters(false))); |
| if (!restart && restartRequested()) { |
| restart = true; |
| nextAction = ARG_NAME_LA_START_APP; |
| } |
| |
| if (restart) { |
| string cmdLine = GetCommandLine(); |
| logMsg("Old command line: %s", cmdLine.c_str()); |
| string::size_type bslashPos = cmdLine.find_last_of('\\'); |
| string::size_type pos = cmdLine.find(ARG_NAME_LA_START_APP); |
| if ((bslashPos == string::npos || bslashPos < pos) && pos != string::npos) { |
| cmdLine.erase(pos, strlen(ARG_NAME_LA_START_APP)); |
| } |
| pos = cmdLine.find(ARG_NAME_LA_START_AU); |
| if ((bslashPos == string::npos || bslashPos < pos) && pos != string::npos) { |
| cmdLine.erase(pos, strlen(ARG_NAME_LA_START_AU)); |
| } |
| |
| if (*cmdLine.rbegin() != ' ') { |
| cmdLine += ' '; |
| } |
| if (!parentProcID.empty() && cmdLine.find(ARG_NAME_LA_PPID) == string::npos) { |
| cmdLine += ARG_NAME_LA_PPID; |
| cmdLine += ' '; |
| cmdLine += parentProcID; |
| } |
| |
| if (*cmdLine.rbegin() != ' ') { |
| cmdLine += ' '; |
| } |
| cmdLine += nextAction; |
| |
| logMsg("New command line: %s", cmdLine.c_str()); |
| char cmdLineStr[32 * 1024] = ""; |
| strcpy(cmdLineStr, cmdLine.c_str()); |
| STARTUPINFO si = {0}; |
| PROCESS_INFORMATION pi = {0}; |
| si.cb = sizeof(STARTUPINFO); |
| |
| if (!CreateProcess(NULL, cmdLineStr, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { |
| logErr(true, true, "Failed to create process."); |
| return; |
| } |
| CloseHandle(pi.hThread); |
| CloseHandle(pi.hProcess); |
| } |
| } |