001package org.nuxeo.launcher.process;
002
003import static java.nio.charset.StandardCharsets.UTF_8;
004
005import java.io.IOException;
006import java.util.List;
007import java.util.regex.Matcher;
008import java.util.regex.Pattern;
009
010import org.apache.commons.io.IOUtils;
011
012/**
013 * {@link ProcessManager} implementation for Windows.
014 * <p>
015 * Requires wmic.exe and taskkill.exe, that should be available at least on Windows XP, Windows Vista, and Windows 7
016 * (except Home versions).
017 */
018public class WindowsProcessManager implements ProcessManager {
019
020    protected static final boolean PID_ENABLED = true;
021
022    private static final Pattern PROCESS_GET_LINE = Pattern.compile("^(.*?)\\s+(\\d+)\\s*$");
023
024    @Override
025    public String findPid(String regex) throws IOException {
026        Pattern commandPattern = Pattern.compile(regex);
027        for (String line : execute("wmic", "process", "get", "CommandLine,ProcessId")) {
028            Matcher lineMatcher = PROCESS_GET_LINE.matcher(line);
029            if (lineMatcher.matches()) {
030                String commandLine = lineMatcher.group(1);
031                String pid = lineMatcher.group(2);
032                Matcher commandMatcher = commandPattern.matcher(commandLine);
033                if (commandMatcher.find()) {
034                    return pid;
035                }
036            }
037        }
038        return null;
039    }
040
041    @Override
042    public void kill(Process process, String pid) throws IOException {
043        execute("taskkill", "/t", "/f", "/pid", pid);
044    }
045
046    public boolean isUsable() {
047        try {
048            execute("wmic", "quit");
049            execute("taskkill", "/?");
050            return true;
051        } catch (IOException ioException) {
052            return false;
053        }
054    }
055
056    private List<String> execute(String... command) throws IOException {
057        Process process = new ProcessBuilder(command).start();
058        process.getOutputStream().close(); // don't wait for stdin
059        List<String> lines = IOUtils.readLines(process.getInputStream(), UTF_8);
060        try {
061            process.waitFor();
062        } catch (InterruptedException e) {
063            Thread.currentThread().interrupt();
064            throw new RuntimeException(e);
065        }
066        return lines;
067    }
068
069    @Override
070    public boolean canFindPid() {
071        return PID_ENABLED;
072    }
073
074}