001: /*
002: Copyright (C) 2002-2004 MySQL AB
003:
004: This program is free software; you can redistribute it and/or modify
005: it under the terms of version 2 of the GNU General Public License as
006: published by the Free Software Foundation.
007:
008: There are special exceptions to the terms and conditions of the GPL
009: as it is applied to this software. View the full text of the
010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
011: software distribution.
012:
013: This program is distributed in the hope that it will be useful,
014: but WITHOUT ANY WARRANTY; without even the implied warranty of
015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: GNU General Public License for more details.
017:
018: You should have received a copy of the GNU General Public License
019: along with this program; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021:
022:
023:
024: */
025: package com.mysql.jdbc.util;
026:
027: import java.io.File;
028: import java.io.IOException;
029:
030: import java.util.Iterator;
031: import java.util.Properties;
032:
033: import com.mysql.jdbc.StringUtils;
034:
035: /**
036: * Controls a MySQL server using Java RunTime methods
037: *
038: * @version $Id: ServerController.java,v 1.1.2.1 2005/05/13 18:58:39 mmatthews
039: * Exp $
040: * @author Mark Matthews
041: */
042: public class ServerController {
043:
044: /**
045: * Where is the server installed?
046: */
047: public static final String BASEDIR_KEY = "basedir";
048:
049: /**
050: * Where are the databases installed?
051: */
052: public static final String DATADIR_KEY = "datadir";
053:
054: /**
055: * Where is the config file located?
056: */
057:
058: public static final String DEFAULTS_FILE_KEY = "defaults-file";
059:
060: /**
061: * What is the name of the executable to run?
062: */
063:
064: public static final String EXECUTABLE_NAME_KEY = "executable";
065:
066: /**
067: * What is the path to the mysql server executable (if not standard?)
068: */
069:
070: public static final String EXECUTABLE_PATH_KEY = "executablePath";
071:
072: /**
073: * The default executable to run
074: */
075:
076: /**
077: * The process representing the MySQL server
078: */
079: private Process serverProcess = null;
080:
081: /**
082: * The list of properties for this server
083: */
084: private Properties serverProps = null;
085:
086: /**
087: * The system properties
088: */
089: private Properties systemProps = null;
090:
091: /**
092: * Creates a ServerController with the directory for the MySQL server.
093: *
094: * The 'datadir' is set to the same directory.
095: *
096: * @param baseDir
097: * the base directory for the MySQL server.
098: */
099: public ServerController(String baseDir) {
100: setBaseDir(baseDir);
101: }
102:
103: /**
104: * Creates a server controller for the MySQL server with the given basedir
105: * and datadir.
106: *
107: * @param basedir
108: * the basedir to use when starting MySQL.
109: * @param datadir
110: * the datadir to use when starting MySQL.
111: */
112: public ServerController(String basedir, String datadir) {
113: }
114:
115: /**
116: * Sets the basedir to use when starting MySQL.
117: *
118: * @param baseDir
119: * the basedir to use when starting MySQL.
120: */
121: public void setBaseDir(String baseDir) {
122: getServerProps().setProperty(BASEDIR_KEY, baseDir);
123: }
124:
125: /**
126: * Sets the data to use when starting MySQL.
127: *
128: * @param dataDir
129: * the basedir to use when starting MySQL.
130: */
131: public void setDataDir(String dataDir) {
132: getServerProps().setProperty(DATADIR_KEY, dataDir);
133: }
134:
135: /**
136: * Starts the server, returning a java.lang.Process instance that represents
137: * the mysql server.
138: *
139: * @return Process a java.lang.Process instance representing the mysql
140: * server process.
141: * @throws IOException
142: * if an error occurs while starting the mysql server.
143: */
144: public Process start() throws IOException {
145: if (this .serverProcess != null) {
146: throw new IllegalArgumentException("Server already started");
147: } else {
148: this .serverProcess = Runtime.getRuntime().exec(
149: getCommandLine());
150:
151: return this .serverProcess;
152: }
153: }
154:
155: /**
156: * Stops the server (if started)
157: *
158: * @param forceIfNecessary
159: * use forceStop if mysqladmin doesn't shut the server down
160: *
161: * @throws IOException
162: * if an error occurs while stopping the server
163: */
164: public void stop(boolean forceIfNecessary) throws IOException {
165: if (this .serverProcess != null) {
166:
167: String basedir = getServerProps().getProperty(BASEDIR_KEY);
168:
169: StringBuffer pathBuf = new StringBuffer(basedir);
170:
171: if (!basedir.endsWith(File.separator)) {
172: pathBuf.append(File.separator);
173: }
174:
175: String defaultsFilePath = getServerProps().getProperty(
176: DEFAULTS_FILE_KEY);
177:
178: pathBuf.append("bin");
179: pathBuf.append(File.separator);
180: pathBuf.append("mysqladmin shutdown");
181:
182: System.out.println(pathBuf.toString());
183:
184: Process mysqladmin = Runtime.getRuntime().exec(
185: pathBuf.toString());
186:
187: int exitStatus = -1;
188:
189: try {
190: exitStatus = mysqladmin.waitFor();
191: } catch (InterruptedException ie) {
192: ; // ignore
193: }
194:
195: //
196: // Terminate the process if mysqladmin couldn't
197: // do it, and the user requested a force stop.
198: //
199: if (exitStatus != 0 && forceIfNecessary) {
200: forceStop();
201: }
202: }
203: }
204:
205: /**
206: * Forcefully terminates the server process (if started).
207: */
208: public void forceStop() {
209: if (this .serverProcess != null) {
210: this .serverProcess.destroy();
211: this .serverProcess = null;
212: }
213: }
214:
215: /**
216: * Returns the list of properties that will be used to start/control the
217: * server.
218: *
219: * @return Properties the list of properties.
220: */
221: public synchronized Properties getServerProps() {
222: if (this .serverProps == null) {
223: this .serverProps = new Properties();
224: }
225:
226: return this .serverProps;
227: }
228:
229: /**
230: * Returns the full commandline used to start the mysql server, including
231: * and arguments to be passed to the server process.
232: *
233: * @return String the commandline used to start the mysql server.
234: */
235: private String getCommandLine() {
236: StringBuffer commandLine = new StringBuffer(
237: getFullExecutablePath());
238: commandLine.append(buildOptionalCommandLine());
239:
240: return commandLine.toString();
241: }
242:
243: /**
244: * Returns the fully-qualifed path to the 'mysqld' executable
245: *
246: * @return String the path to the server executable.
247: */
248: private String getFullExecutablePath() {
249: StringBuffer pathBuf = new StringBuffer();
250:
251: String optionalExecutablePath = getServerProps().getProperty(
252: EXECUTABLE_PATH_KEY);
253:
254: if (optionalExecutablePath == null) {
255: // build the path using the defaults
256: String basedir = getServerProps().getProperty(BASEDIR_KEY);
257: pathBuf.append(basedir);
258:
259: if (!basedir.endsWith(File.separator)) {
260: pathBuf.append(File.separatorChar);
261: }
262:
263: if (runningOnWindows()) {
264: pathBuf.append("bin");
265: } else {
266: pathBuf.append("libexec");
267: }
268:
269: pathBuf.append(File.separatorChar);
270: } else {
271: pathBuf.append(optionalExecutablePath);
272:
273: if (!optionalExecutablePath.endsWith(File.separator)) {
274: pathBuf.append(File.separatorChar);
275: }
276: }
277:
278: String executableName = getServerProps().getProperty(
279: EXECUTABLE_NAME_KEY, "mysqld");
280:
281: pathBuf.append(executableName);
282:
283: return pathBuf.toString();
284: }
285:
286: /**
287: * Builds the list of command-line arguments that will be passed to the
288: * mysql server to be started.
289: *
290: * @return String the list of command-line arguments.
291: */
292: private String buildOptionalCommandLine() {
293: StringBuffer commandLineBuf = new StringBuffer();
294:
295: if (this .serverProps != null) {
296:
297: for (Iterator iter = this .serverProps.keySet().iterator(); iter
298: .hasNext();) {
299: String key = (String) iter.next();
300: String value = this .serverProps.getProperty(key);
301:
302: if (!isNonCommandLineArgument(key)) {
303: if (value != null && value.length() > 0) {
304: commandLineBuf.append(" \"");
305: commandLineBuf.append("--");
306: commandLineBuf.append(key);
307: commandLineBuf.append("=");
308: commandLineBuf.append(value);
309: commandLineBuf.append("\"");
310: } else {
311: commandLineBuf.append(" --");
312: commandLineBuf.append(key);
313: }
314: }
315: }
316: }
317:
318: return commandLineBuf.toString();
319: }
320:
321: /**
322: * Returns true if the property does not belong as a command-line argument
323: *
324: * @return boolean if the property should not be a command-line argument.
325: */
326: private boolean isNonCommandLineArgument(String propName) {
327: return propName.equals(EXECUTABLE_NAME_KEY)
328: || propName.equals(EXECUTABLE_PATH_KEY);
329: }
330:
331: /**
332: * Lazily creates a list of system properties.
333: *
334: * @return Properties the properties from System.getProperties()
335: */
336: private synchronized Properties getSystemProperties() {
337: if (this .systemProps == null) {
338: this .systemProps = System.getProperties();
339: }
340:
341: return this .systemProps;
342: }
343:
344: /**
345: * Is this ServerController running on a Windows operating system?
346: *
347: * @return boolean if this ServerController is running on Windows
348: */
349: private boolean runningOnWindows() {
350: return StringUtils.indexOfIgnoreCase(getSystemProperties()
351: .getProperty("os.name"), "WINDOWS") != -1;
352: }
353: }
|