/*
* ProActive Parallel Suite(TM):
* The Open Source library for parallel and distributed
* Workflows & Scheduling, Orchestration, Cloud Automation
* and Big Data Analysis on Enterprise Grids & Clouds.
*
* Copyright (c) 2007 - 2017 ActiveEon
* Contact: contact@activeeon.com
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation: version 3 of
* the License.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If needed, contact us to obtain a release under GPL Version 2 or 3
* or a different license than the AGPL.
*/
package org.ow2.tests;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.ptql.ProcessFinder;
import org.objectweb.proactive.utils.OperatingSystem;
/**
* Kill all Java processes matching a pattern
*
*
* @author ProActive team
* @since ProActive 5.2.0
*/
public class ProcessCleaner {
final private Pattern pattern;
public ProcessCleaner(String regex) {
this(Pattern.compile(regex));
}
public ProcessCleaner(Pattern pattern) {
this.pattern = pattern;
}
/**
* Get PID of all alive Java processes matching the pattern.
*
* @return
* PIDs
* @throws IOException
* If PIDs cannot be retrieved
*/
final public Set<Integer> getAliveProcesses() throws IOException {
return getAliveProcesses(false);
}
final public Set<Integer> getAliveProcesses(boolean printProcesses) throws IOException {
// JPS is only available on some JDK
// We need a fall back in case jps does not exist.
try {
getJavaTool("jps");
Set<Integer> pids = getAliveWithJps(printProcesses);
pids.addAll(getAliveWithSigar(printProcesses));
return pids;
} catch (FileNotFoundException e) {
return getAliveWithNative();
}
}
private Set<Integer> getAliveWithSigar(boolean printProcesses) {
Sigar sigar = new Sigar();
try {
long[] pids = new ProcessFinder(sigar).find("State.Name.eq=java,Args.*.re=" + pattern);
Set<Integer> setOfPids = new HashSet<>();
for (long pid : pids) {
setOfPids.add((int) pid);
if (printProcesses)
System.out.println("Running java processes matching regex:" + pid);
}
return setOfPids;
} catch (SigarException e) {
return Collections.emptySet();
}
}
private Set<Integer> getAliveWithJps(boolean printProcesses) throws IOException {
ProcessBuilder pb = new ProcessBuilder(getJavaTool("jps").getAbsolutePath(), "-mlv");
pb.redirectErrorStream(true);
Process p = pb.start();
Set<Integer> pids = new HashSet<>();
Reader r = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(r);
String line;
while ((line = br.readLine()) != null) {
Matcher m = this.pattern.matcher(line);
if (m.matches()) {
if (printProcesses)
System.out.println("Running java processes matching regex:" + line);
String pid = line.substring(0, line.indexOf(" "));
pids.add(Integer.parseInt(pid));
}
}
return pids;
}
private Set<Integer> getAliveWithNative() throws IOException {
OperatingSystem os = OperatingSystem.getOperatingSystem();
switch (os) {
case unix:
ProcessBuilder pb;
// Mac Os
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("mac")) {
// Mac OS / Mac Os X
pb = new ProcessBuilder("/bin/sh",
"-c",
"for PID in $(ps axc|awk \"{if (\\$5==\\\"java\\\") print \\$1}\") ; do ps $PID | grep -q -- '" +
this.pattern.toString() + "' && echo $PID ; done");
} else {
// Linux / Unix
pb = new ProcessBuilder("/bin/sh",
"-c",
"for PID in $(pidof java) ; do grep -q -- '" + this.pattern.toString() +
"' /proc/$PID/cmdline && echo $PID ; done");
}
pb.redirectErrorStream(true);
Process p = pb.start();
Set<Integer> pids = new HashSet<>();
Reader r = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(r);
String line;
while ((line = br.readLine()) != null) {
pids.add(Integer.parseInt(line));
}
return pids;
default:
throw new IllegalStateException("Unsupported operating system");
}
}
/**
* Kill all alive Java processes matching the pattern.
*
* @throws IOException
* If some processes cannot be killed
*/
final public void killAliveProcesses() throws IOException {
ProcessKiller pk = ProcessKiller.get();
Set<Integer> pids = this.getAliveProcesses();
for (int pid : pids) {
try {
// printStackTrace(pid);
pk.kill(pid);
System.err.println("Killed process " + pid);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
Set<Integer> pidsLeft = getAliveProcesses(true);
if (!pidsLeft.isEmpty()) {
System.err.println("Processes left running: " + pidsLeft);
}
}
private void printStackTrace(int pid) {
try {
ProcessBuilder pb = new ProcessBuilder(getJavaTool("jstack").getAbsolutePath(), "" + pid);
pb.redirectErrorStream(true);
Process p = pb.start();
Reader r = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(r);
String line;
while ((line = br.readLine()) != null) {
System.err.println(line);
}
br.close();
r.close();
} catch (Exception e) {
System.err.println("Cannot print stack trace of the process with pid " + pid);
}
}
/**
* Returns the command to start the jps util
*
* @return command to start jps
*/
static private File getJavaTool(String name) throws FileNotFoundException {
final String osSpecificName;
switch (OperatingSystem.getOperatingSystem()) {
case unix:
osSpecificName = name;
break;
case windows:
osSpecificName = name + ".exe";
break;
default:
throw new IllegalStateException("Unsupported operating system");
}
File ret = new File(getJavaBinDir(), osSpecificName);
if (!ret.exists()) {
throw new FileNotFoundException(name + " not found: " + ret + " does not exist");
}
return ret;
}
/**
* Returns the Java bin dir
*
* @return Java bin/ dir
*/
static private File getJavaBinDir() {
return new File(System.getProperty("java.home") + File.separatorChar + ".." + File.separatorChar + "bin" +
File.separatorChar);
}
public static void main(String[] args) throws IOException {
System.out.println("Killing all processes related to the test execution");
new ProcessCleaner(".*proactive.test=true.*").killAliveProcesses();
}
}