/**
** Copyright (C) SAS Institute, All rights reserved.
** General Public License: http://www.opensource.org/licenses/gpl-license.php
**/
package org.safs.tools;
import java.io.IOException;
import java.util.Enumeration;
import org.safs.tools.consoles.GenericProcessCapture;
/**
* Various utilities for monitoring or otherwise interrogating native system processes.
* This "Generic" version does all logging to System.out
* <p>
* Subclasses should override the debug(String) method to log to alternative mechanisms
* and should override the
* <p>
* This class contains no extended SAFS dependencies and can be readily packaged and distributed
* for non-SAFS installations.
* @author canagl 2012.03.27 Original Release
*/
public class GenericProcessMonitor {
/**
* Writes to System.out .
* Subclasses should override to log to alternate sinks.
* @param message
*/
protected static void debug(String message){
System.out.println(message);
}
/**
* Subclasses may wish to override to return a different subclass of GenericProcessCapture.
* @param aproc
* @return
*/
protected static GenericProcessCapture getProcessCapture(Process aproc){
return new GenericProcessCapture(aproc);
}
/**
* Return true or false that a given process is running on the system.
* On Windows we are using the tasklist.exe output for comparison.
* On Unix we are using ps -f output for comparison.
* @param procid CMD name(nix ps-f) or IMAGE(win qprocess.exe) or PID to seek.
* @return true if the procid (CMD or IMAGE or numeric PID) is running/listed.
* @throws IOException if any error occurs in getting the processes for evaluation.
*/
public static boolean isProcessRunning(String procid)throws IOException{
//String wincmd = "qprocess.exe * /SYSTEM"; // alternative
String wincmd = "tasklist.exe";
String unxcmd = "ps -f";
GenericProcessCapture console = null;
boolean success = false;
boolean run = false;
try{
Process proc = Runtime.getRuntime().exec(wincmd);
console = getProcessCapture(proc);
Thread athread = new Thread(console);
athread.start();
proc.waitFor();
run = true;
success = (proc.exitValue()==0);
}catch(Exception x){
// something else was wrong with the underlying process
debug(wincmd +", "+ x.getClass().getSimpleName()+": "+ x.getMessage());
}
if(! run){
try{
Process proc = Runtime.getRuntime().exec(unxcmd);
console = getProcessCapture(proc);
Thread athread = new Thread(console);
athread.start();
proc.waitFor();
success = (proc.exitValue()==0);
}catch(Exception x){
// something else was wrong with the underlying process
debug(unxcmd +", "+ x.getClass().getSimpleName()+": "+ x.getMessage());
}
}
if(success){
success = false;
boolean isNumeric = false;
int pid = 0;
int pidindex = 0;
String pidtest = null;
try{
pid = Integer.parseInt(procid);
isNumeric = true;
}catch(NumberFormatException n){ }
String line = null;
Enumeration reader = console.getData().elements();
while((!success) && (reader.hasMoreElements())){
line = (String)reader.nextElement();
if(isNumeric){
pidindex = line.indexOf(procid);
if(pidindex > 0){
try{
// grab a character before and after and make sure it is not alpha
pidtest = line.substring(pidindex -1, procid.length()+pidindex+1).trim();
success = ( pid == Integer.parseInt(pidtest));
}catch(Exception x){/*ignore*/}
}
}else{
success = line.contains(procid);
}
}
}
return success;
}
/**
* Attempt to forcefully kill a given process by name or PID.
* On Windows we are using taskkill.exe.
* On Unix we are using kill -9 for PID, or killall for process names.
* Of course, this must be used with care!
* @param procid CMD name(nix ps-f) or IMAGE(win qprocess.exe) or PID to kill.
* @return true if the shutdown attempt returned with success, false otherwise.
* @throws IOException if no shutdown attempt was ever able to execute.
*/
public static boolean shutdownProcess(String procid)throws IOException{
boolean isNumeric = false;
try{ isNumeric = Integer.parseInt(procid) > 0;}
catch(NumberFormatException n){ }
String wincmd = "taskkill.exe /f ";
wincmd += isNumeric ? "/pid " : "/im ";
wincmd += procid;
String unxcmd = isNumeric ? "kill -9 "+ procid:"killall "+ procid;
GenericProcessCapture console = null;
boolean run = false;
boolean success = false;
try{
Process proc = Runtime.getRuntime().exec(wincmd);
console = getProcessCapture(proc);
Thread athread = new Thread(console);
athread.start();
proc.waitFor();
run = true;
success = (proc.exitValue()==0);
}catch(Exception x){
// something else was wrong with the underlying process
debug(wincmd +", "+ x.getClass().getSimpleName()+": "+ x.getMessage());
}
if(! run){
try{
Process proc = Runtime.getRuntime().exec(unxcmd);
console = getProcessCapture(proc);
Thread athread = new Thread(console);
athread.start();
proc.waitFor();
run = true;
success = (proc.exitValue()==0);
}catch(Exception x){
// something else was wrong with the underlying process
debug(unxcmd +", "+ x.getClass().getSimpleName()+": "+ x.getMessage());
}
}
if (!run) throw new IOException("Neither WIN nor UNX shutdownProcess commands executed properly using procid: "+ procid);
return success;
}
}