/* * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License, version 2.0, as published by the * Free Software Foundation. * * This program is also distributed with certain software (including but not * limited to OpenSSL) that is licensed under separate terms, as designated in a * particular file or component or in included license documentation. The * authors of MySQL hereby grant you an additional permission to link the * program and your derivative works with the separately licensed software that * they have included with MySQL. * * Without limiting anything contained in the foregoing, this file, which is * part of MySQL Connector/J, is also subject to the Universal FOSS Exception, * version 1.0, a copy of which can be found at * http://oss.oracle.com/licenses/universal-foss-exception. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, * for more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.mysql.cj.admin; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.Properties; import com.mysql.cj.Constants; import com.mysql.cj.util.StringUtils; /** * Controls a MySQL server using Java RunTime methods */ public class ServerController { /** * Where is the server installed? */ public static final String BASEDIR_KEY = "basedir"; /** * Where are the databases installed? */ public static final String DATADIR_KEY = "datadir"; /** * Where is the config file located? */ public static final String DEFAULTS_FILE_KEY = "defaults-file"; /** * What is the name of the executable to run? */ public static final String EXECUTABLE_NAME_KEY = "executable"; /** * What is the path to the mysql server executable (if not standard?) */ public static final String EXECUTABLE_PATH_KEY = "executablePath"; /** * The default executable to run */ /** * The process representing the MySQL server */ private Process serverProcess = null; /** * The list of properties for this server */ private Properties serverProps = null; /** * The system properties */ //private Properties systemProps = null; /** * Creates a ServerController with the directory for the MySQL server. * * The 'datadir' is set to the same directory. * * @param baseDir * the base directory for the MySQL server. */ public ServerController(String baseDir) { setBaseDir(baseDir); } /** * Creates a server controller for the MySQL server with the given basedir * and datadir. * * @param basedir * the basedir to use when starting MySQL. * @param datadir * the datadir to use when starting MySQL. */ public ServerController(String basedir, String datadir) { } /** * Sets the basedir to use when starting MySQL. * * @param baseDir * the basedir to use when starting MySQL. */ public void setBaseDir(String baseDir) { getServerProps().setProperty(BASEDIR_KEY, baseDir); } /** * Sets the data to use when starting MySQL. * * @param dataDir * the basedir to use when starting MySQL. */ public void setDataDir(String dataDir) { getServerProps().setProperty(DATADIR_KEY, dataDir); } /** * Starts the server, returning a java.lang.Process instance that represents * the mysql server. * * @return Process a java.lang.Process instance representing the mysql * server process. * @throws IOException * if an error occurs while starting the mysql server. */ public Process start() throws IOException { if (this.serverProcess != null) { throw new IllegalArgumentException("Server already started"); } this.serverProcess = Runtime.getRuntime().exec(getCommandLine()); return this.serverProcess; } /** * Stops the server (if started) * * @param forceIfNecessary * use forceStop if mysqladmin doesn't shut the server down * * @throws IOException * if an error occurs while stopping the server */ public void stop(boolean forceIfNecessary) throws IOException { if (this.serverProcess != null) { String basedir = getServerProps().getProperty(BASEDIR_KEY); StringBuilder pathBuf = new StringBuilder(basedir); if (!basedir.endsWith(File.separator)) { pathBuf.append(File.separator); } //String defaultsFilePath = getServerProps().getProperty(DEFAULTS_FILE_KEY); pathBuf.append("bin"); pathBuf.append(File.separator); pathBuf.append("mysqladmin shutdown"); System.out.println(pathBuf.toString()); Process mysqladmin = Runtime.getRuntime().exec(pathBuf.toString()); int exitStatus = -1; try { exitStatus = mysqladmin.waitFor(); } catch (InterruptedException ie) { // ignore } // // Terminate the process if mysqladmin couldn't do it, and the user requested a force stop. // if (exitStatus != 0 && forceIfNecessary) { forceStop(); } } } /** * Forcefully terminates the server process (if started). */ public void forceStop() { if (this.serverProcess != null) { this.serverProcess.destroy(); this.serverProcess = null; } } /** * Returns the list of properties that will be used to start/control the * server. * * @return Properties the list of properties. */ public synchronized Properties getServerProps() { if (this.serverProps == null) { this.serverProps = new Properties(); } return this.serverProps; } /** * Returns the full commandline used to start the mysql server, including * and arguments to be passed to the server process. * * @return String the commandline used to start the mysql server. */ private String getCommandLine() { StringBuilder commandLine = new StringBuilder(getFullExecutablePath()); commandLine.append(buildOptionalCommandLine()); return commandLine.toString(); } /** * Returns the fully-qualifed path to the 'mysqld' executable * * @return String the path to the server executable. */ private String getFullExecutablePath() { StringBuilder pathBuf = new StringBuilder(); String optionalExecutablePath = getServerProps().getProperty(EXECUTABLE_PATH_KEY); if (optionalExecutablePath == null) { // build the path using the defaults String basedir = getServerProps().getProperty(BASEDIR_KEY); pathBuf.append(basedir); if (!basedir.endsWith(File.separator)) { pathBuf.append(File.separatorChar); } if (runningOnWindows()) { pathBuf.append("bin"); } else { pathBuf.append("libexec"); } pathBuf.append(File.separatorChar); } else { pathBuf.append(optionalExecutablePath); if (!optionalExecutablePath.endsWith(File.separator)) { pathBuf.append(File.separatorChar); } } String executableName = getServerProps().getProperty(EXECUTABLE_NAME_KEY, "mysqld"); pathBuf.append(executableName); return pathBuf.toString(); } /** * Builds the list of command-line arguments that will be passed to the * mysql server to be started. * * @return String the list of command-line arguments. */ private String buildOptionalCommandLine() { StringBuilder commandLineBuf = new StringBuilder(); if (this.serverProps != null) { for (Iterator iter = this.serverProps.keySet().iterator(); iter.hasNext();) { String key = (String) iter.next(); String value = this.serverProps.getProperty(key); if (!isNonCommandLineArgument(key)) { if (value != null && value.length() > 0) { commandLineBuf.append(" \""); commandLineBuf.append("--"); commandLineBuf.append(key); commandLineBuf.append("="); commandLineBuf.append(value); commandLineBuf.append("\""); } else { commandLineBuf.append(" --"); commandLineBuf.append(key); } } } } return commandLineBuf.toString(); } /** * Returns true if the property does not belong as a command-line argument * * @return boolean if the property should not be a command-line argument. */ private boolean isNonCommandLineArgument(String propName) { return propName.equals(EXECUTABLE_NAME_KEY) || propName.equals(EXECUTABLE_PATH_KEY); } /** * Is this ServerController running on a Windows operating system? * * @return boolean if this ServerController is running on Windows */ private boolean runningOnWindows() { return StringUtils.indexOfIgnoreCase(Constants.OS_NAME, "WINDOWS") != -1; } }