/* Copyright (C) 2004 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.mysql.management.util; import java.io.File; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; @SuppressWarnings({ "rawtypes", "unchecked" }) public final class ProcessUtil { private String pid; private PrintStream out; private PrintStream err; private String killCommand; private Utils utils; private File installDir; public ProcessUtil(String pid, PrintStream out, PrintStream err, File installDir) { this(pid, out, err, installDir, new Utils()); } public ProcessUtil(String pid, PrintStream out, PrintStream err, File installDir, Utils utils) { this.installDir = installDir; this.pid = (pid != null) ? pid.trim() : "-1"; this.out = out; this.err = err; this.utils = utils; if (utils.files().isWindows()) { this.killCommand = getWindowsKillFile().getPath(); } else { this.killCommand = "kill"; } } /* called from constructor */ final File getWindowsKillFile() { File parent = new File(installDir, "c-mxj-utils"); File kill = new File(parent, "kill.exe"); if (!kill.exists()) { utils.streams().createFileFromResource("kill.exe", kill); } return kill; } String pid() { return pid; } public void kill() { kill(false); } public void forceKill() { Exceptions.VoidBlock block = new Exceptions.VoidBlock() { @Override public void inner() { kill(true); } }; block.execNotThrowingExceptions(err); } /** * @param force */ private void kill(boolean force) { String threadName = "killing process " + pid; if (force) { threadName = "force " + threadName; } launchShell(threadName, killArgs(force), 10); } String[] killArgs(boolean force) { List args = new ArrayList(); args.add(killCommand); if (force) { args.add("-9"); } args.add(pid); return utils.str().toStringArray(args); } public boolean isRunning() { String threadName = "is_process_" + pid + "_running"; Shell shell = launchShell(threadName, isRunningArgs(), 5); if (!shell.hasReturned()) { return false; } return shell.returnCode() == 0; } private Shell launchShell(String threadName, String[] args, int seconds) { Shell shell = utils.shellFactory().newShell(args, threadName, out, err); shell.start(); int fraction = 20; int loops = (fraction * seconds); do { utils.threads().pause((1000 / fraction)); } while (!shell.hasReturned() && loops-- > 0); if (!shell.hasReturned()) { err.println("Thread \"" + threadName + "\" may be hung"); err.println("(did not return after " + seconds + " seconds)"); err.println("command line used: "); err.println(new ListToString("", " ", "").toString(args)); } return shell; } String[] isRunningArgs() { return new String[] { killCommand, "-0", pid }; } public void killNoThrow() { Exceptions.VoidBlock block = new Exceptions.VoidBlock() { @Override public void inner() { kill(); } }; block.execNotThrowingExceptions(err); } }