0

I am executing processes with Java and parsing their results. However, when I read the output I don't get all the content.

For example, if I execute this with the Windows console:

cmd /c tasklist | FIND "java"

It shows:

javaw.exe    6192 Console     1   683.668 KB
java.exe     8448 Console     1    35.712 KB
java.exe     7252 Console     1    35.736 KB
javaw.exe    3260 Console     1    76.652 KB
java.exe     9728 Console     1    35.532 KB

But if I do the same with a java process only two of them appear:

java.exe     8448 Console     1    35.712 KB
javaw.exe    3260 Console     1    76.652 KB

This is a simplified version of the code:

public static void printPidsOfJavaProcesses() {
    try {
        String[] params = null;
        if (isInWindows()) {
            params = new String[6];
            params[0] = "cmd";
            params[1] = "/c";
            params[2] = "tasklist";
            params[3] = "|";
            params[4] = "FIND";
            params[5] = "\"java\"";
        } else {
            ...
        }

        Process process = ProcessUtil.executeConsoleCommand(params);
        printConsoleOutput(process) 
    } catch (IOException e) {
        log.error("It was not possible to obtain the pids of the active processes");
    }
}

public static void printConsoleOutput(Process process) {
    InputStream input = process.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(input));

    try {
        String line = null;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    } catch (IOException e) {
        log.error("It was not possible to obtain the process output", e);
    }
}

public static Process executeConsoleCommand(String[] params) throws IOException {

    // Create the process
    final ProcessBuilder processBuilder = new ProcessBuilder(params);

    // Redirect errors to avoid deadlocks when the buffer get full
    processBuilder.redirectErrorStream(true);

    // Launch the process
    Process process = processBuilder.start();

    return process;
}

I have searched here and on Google and most people launch and read processes in a similar way, so the cause of the problem might be related with the console command. Do you have any idea? Thanks in advance

rafaborrego
  • 610
  • 1
  • 8
  • 19
  • I don't know the Windows command interpreter that much, but isn't `|` a pipe to send the output of the left command to the input of the right command? – fge Mar 06 '14 at 12:30
  • Yes @fge, the point is to obtain a filtered list of the active processes to get only the java ones. It is similar to do this in linux: `ps -fe | grep "java"` And the `cmd /c` is to avoid problems using pipes with processes – rafaborrego Mar 06 '14 at 12:45
  • OK, so two questions: first, why use `cmd` at all? Is `tasklit` a cmd builtin? Second, why use `FIND` and not Java's methods to do the filtering? – fge Mar 06 '14 at 12:48
  • The `cmd` is a trick that I found [here](http://stackoverflow.com/questions/21201873/java-processbuilder-pipe) for executing with Java a command that contains pipes. I tried without it and there was an error because it couldn't parse `|` as an argument. For filtering I can use the `contains` method but I think that it is more efficient in this way. Anyway, when I execute it without `FIND` I have the same problem, only appear some of the results – rafaborrego Mar 06 '14 at 13:01
  • The trick in the answer you quoted is "not the good one" if I may say so; you should really pipe the output of one command into another using Java itself. Admittedly, this doesn't answer your initial question. – fge Mar 06 '14 at 13:03
  • Odd, I cannot reproduce this (Windows 8.1 x64, Java 1.7.0_51 x86). – Luke Woodward Mar 06 '14 at 13:10
  • I have just tried it on the same computer in a simple java project and it works perfectly as Luke said, I am sorry for not doing it before asking :-( . So the problem is related to the application in which it is executed. It is launched in a job task with Quartz in an application deployed with Tomcat 6 and Java 1.6, and there might be any restriction accessing to process list from Tomcat. I will try to debug more. Thank you for your answers! – rafaborrego Mar 06 '14 at 13:44
  • Maybe the Java process only has permission to query other processes that has ben created by itself (child processes)? – vicenteherrera Jun 19 '14 at 10:26
  • I don't think so, because when I execute it without the FIND command it displays other processes. And it works when I run the code from a simple Java application. I will do some tests to check if it only returns the processes that are being executed inside Tomcat, thanks for the idea. – rafaborrego Jun 19 '14 at 14:13
  • I have solved it using the command `WMIC` instead of `Tasklist`. I have added an answer will all the code. Thanks for your comments! – rafaborrego Aug 14 '14 at 12:30

1 Answers1

0

I have just solved it using WMIC instead of Tasklist. This is the code:

public static List<String> getPidsOfJavaProcesses() throws ProcessException {

    List<String> pids = null;
    boolean isOnWindows = isOnWindows();

    if (isOnWindows) {
        String[] commandParams = getCommandParamsForGettingProcessesOnWindows();
        Process pr = executeConsoleCommand(commandParams);
        pids = getConsoleOutput(pr);
    } else {
        String[] commandParams = getCommandParamsForGettingProcessesOnLinux();
        Process pr = executeConsoleCommand(commandParams);
        List<String> outputLines = getConsoleOutput(pr);
        pids = getJavaPidsFromConsoleOutputOnLinux(outputLines);
    }

    return pids;
}

public static boolean isOnWindows() {
    boolean isOnWindows = false;
    String osName = System.getProperty("os.name");
    if (osName.toLowerCase().contains("windows")) {
        isOnWindows = true;
    }

    return isOnWindows;
}

private static String[] getCommandParamsForGettingProcessesOnLinux() {

    String[] params = new String[3];
    params[0] = "bash";
    params[1] = "-c";
    params[2] = "ps -fe | grep \"java\"";

    return params;
}

private static String[] getCommandParamsForGettingProcessesOnWindows() {

    String[] params = new String[11];
    params[0] = "cmd";
    params[1] = "/c";
    params[2] = "wmic";
    params[3] = "process";
    params[4] = "where";
    params[5] = "name=\"javaw.exe\"";
    params[6] = "get";
    params[7] = "processid";
    params[8] = "|";
    params[9] = "MORE";
    params[10] = "+1";

    return params;
}

public static Process executeConsoleCommand(String[] params) throws ProcessException {

    // Create the process
    final ProcessBuilder processBuilder = new ProcessBuilder(params);

    // Redirect errors to avoid deadlocks when the buffers get full.
    processBuilder.redirectErrorStream(true);

    // Launch the process
    Process process = null;
    try {
        process = processBuilder.start();
    } catch (IOException e) {
        log.error("Exception launching a process", e);
        throw new ProcessException("Exception launching a process", e);
    }

    return process;
}

public static List<String> getConsoleOutput(Process process) throws ProcessException {
    List<String> lines = new ArrayList<String>();
    InputStream input = process.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(input));

    try {
        String line = reader.readLine();
        while (line != null) {
            line = line.trim();
            if (!line.isEmpty()) {
                lines.add(line);
            }
            line = reader.readLine();
        }
    } catch (IOException e) {
        log.error("It was not possible to obtain the process output", e);
        throw new ProcessException("It was not possible to obtain the process output", e);
    } finally {
        try {
            if (input != null) {
                input.close();
            }
            if (reader != null) {
                reader.close();
            }
        } catch (IOException e) {
            log.error("It was not possible to close the console stream", e);
            throw new ProcessException("It was not possible to close the console stream", e);
        }
    }

    return lines;
}
rafaborrego
  • 610
  • 1
  • 8
  • 19