开发者

Execute external program using ProcessBuilder and provide input

I'm trying to execute an external program with Java using ProcessBuilder, but it expects input from the user.

To be more specific, the program is PGSQL (Postgres SQL), when it's executed the program prompts the user for a password. The only way to bypass that is to save a file in the user home containing the passwords, I'm trying to avoid that, so I want to execute the program from Java and send the password using the process' output str开发者_开发问答eam.

The code works fine when the program doesn't expect any user input, but when I delete the password file from the user home, the program hangs. I see that it's being executed, but nothing happens. If I debug it, it reaches the while and then nothing happens until I kill the process.

This is the code, any help will be greatly appreciated.

@Test
public void testSQLExecution() throws Exception {
String path = "C:/tmp";
List<String> commandList = new ArrayList<String>();
commandList.add("psql");
commandList.add("-f");
commandList.add("test.sql");
commandList.add("-h");
commandList.add(HOST);
commandList.add("-p");
commandList.add(PORT);
commandList.add("-U");
commandList.add(DATABASE);
commandList.add(SCHEMA);

ProcessBuilder processBuilder = new ProcessBuilder(commandList);
processBuilder.directory(new File(path));
processBuilder.redirectErrorStream(true);

Process p = processBuilder.start();

String line;
BufferedReader input = new BufferedReader(new InputStreamReader(p
    .getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(p
    .getOutputStream()));

out.write("password");
out.newLine();
out.flush();
out.close();

    // When this line is reached, the execution halts.
while (input.ready() && (line = input.readLine()) != null) {
    System.out.println(line);
}

if (p.waitFor() != 0) {
    Assert.fail("The process did not run succesfully.");
}

input.close();
}

Thanks a lot.


I believe the prompt is going to STDERR, not STDOUT, so you'll have to open a stream connected to that and read there. When you try to read from STDOUT your code hangs waiting for output that will never arrive.

EDIT: I see you have redirected the error stream in the ProcessBuilder.

One other possibility is that the BufferedReader is waiting for a newline to finish reading, and the prompt does not end with a newline.


Been a long time, but got exactly the same problem. Here is a SSCCE that should work:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Toto
{

    private static Logger logger = LoggerFactory.getLogger(Toto.class);

    static class Params 
    {
        public String getUserName() {
            return "PUT USERNAME HERE";
        }
        public String getHost() {
            return "PUT HOST HERE";
        }
        public String getDbName() {
            return "PUT DBNAME HERE";
        }
        public char[] getPassword() {
            return new char[]{'p','a','s','s','w','o','r','d'};
        }
        public String getSqlFile() {
            return "PUT SQL COMMAND FILE HERE";
        }
    }

    public static void main(String[] args)
    {
        Params params = new Params();

        try {
            final String userName   = params.getUserName();
            final String host       = params.getHost();
            final String dbName     = params.getDbName();
            final char[] pass       = params.getPassword();
            if (userName == null || host == null || dbName == null || pass == null) {
                logger.error("Missing the following info to execute the SQL command file: {} {} {} {}"  , userName  == null ? "username": ""
                    , host      == null ? "host"    : ""
                        , dbName    == null ? "database": ""
                            , pass      == null ? "password": "");
                return;
            }
            List<String> sb = new ArrayList<String>();
            sb.add("psql");
            sb.add("-h");
            sb.add(host);
            sb.add("-U");
            sb.add(userName);
            sb.add("-d");
            sb.add(dbName);
            sb.add("-f");
            sb.add(params.getSqlFile());
            //              sb.add("-W"); // force password prompt
            logger.debug("Executing the following command: {}", sb.toString());
            ProcessBuilder pb = new ProcessBuilder(sb);
            final Process p = pb.start();
            final BufferedReader stdinReader = new BufferedReader(new InputStreamReader(p.getInputStream()));
            final BufferedReader stderrReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    try
                    {

                        OutputStreamWriter s = new OutputStreamWriter(p.getOutputStream());
                        s.write(pass);
                        s.write(System.getProperty("line.separator"));
                        s.flush();
                        System.out.println("Pass written");
                    }
                    catch(IOException e)
                    {
                        logger.error("Exception raised in the thread writting password to psql", e);
                    }
                }
            }).start();

            new Thread(new Runnable()
            {

                @Override
                public void run()
                {
                    try
                    {
                        String s;
                        while (( s=stdinReader.readLine()) != null) {
                            logger.debug("psql [STDOUT]: {}", s);
                        }
                    }
                    catch(IOException e)
                    {
                        logger.error("Exception raised in thread displaying stdout of psql", e);
                    }
                }
            }).start();
            new Thread(new Runnable()
            {

                @Override
                public void run()
                {
                    try
                    {
                        String s;
                        while (( s=stderrReader.readLine()) != null) {
                            logger.error("psql [STDERR]: {}", s);
                        }
                    }
                    catch(IOException e)
                    {
                        logger.error("Exception raised in thread displaying stderr of psql", e);
                    }
                }
            }).start();
            int returnVal = p.waitFor();
            logger.debug("Process ended with return val {} ", returnVal);

        }
        catch (Exception e) {
            logger.error("Exception raised while executing the results on server", e);
        }

    }

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜