1

I'm trying to enter some value in external application using Java.

Java application looks like this:

Runtime runtime = Runtime.getRuntime();
// ... str build ...
proc = runtime.exec(str);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
bw.write(value);
bw.flush();
bw.close();
if (proc.waitFor() != 0) 
    // error msg
// the end

Application hangs at waitFor method.

External application looks like this:

welcome banner

please enter 8 character input:

Welcome banner is printed using printf and input is taken with SetConsoleMode/ReadConsoleInput. ReadConsoleInput reads one char and they are masked with * character.

Help

2 Answers2

2

you can use:

proc.getOutputStream().write("some date".getBytes())

keep in mind that you HAVE to read everything the app send to stdout and stderr, else it might get stuck writing there. I use a generic class to read it in a different thread. usage is like:

InputStreamSucker inSucker = new InputStreamSucker(proc.getInputStream());
InputStreamSucker errSucker = new InputStreamSucker(proc.getErrorStream());
proc.waitFor();
int exit = process.exitValue();
inSucker.join();
errSucker.join();

InputStreamSucker code is here:

public class InputStreamSucker extends Thread
{
    static Logger logger = Logger.getLogger(InputStreamSucker.class);

    private final BufferedInputStream m_in;

    private final ByteArrayOutputStream m_out;

    private final File m_outFile;

    public InputStreamSucker(InputStream in) throws FileNotFoundException
    {
        this(in, null);
    }


    public InputStreamSucker(InputStream in, File outFile) throws FileNotFoundException
    {
        m_in = new BufferedInputStream(in, 4096);
        m_outFile = outFile;
        m_out = new ByteArrayOutputStream();
        start();
    }

    @Override
    public void run()
    {
        try
        {
            int c;
            while ((c = m_in.read()) != -1)
            {
                m_out.write(c);
            }
        }
        catch (IOException e)
        {
            logger.error("Error pumping stream", e);
        }
        finally
        {
            if (m_in != null)
            {
                try
                {
                    m_in.close();
                } 
                catch (IOException e)
                {
                }
            }

            try
            {
                m_out.close();
            }
            catch (IOException e)
            {
                logger.error("Error closing out stream", e);
            }

            if (m_outFile != null)
            {
                byte data[] = m_out.toByteArray();
                if (data.length > 0)
                {
                    FileOutputStream fo = null;
                    try
                    {
                        fo = new FileOutputStream(m_outFile);
                        fo.write(data);
                    }
                    catch (IOException e)
                    {
                        logger.error("Error writing " + m_outFile);
                    }
                    finally
                    {
                        try
                        {
                            if (fo != null) fo.close();
                        }
                        catch (IOException e)
                        {
                            logger.error("Error closing " + m_outFile);
                        }
                    }
                }
            }
        }
    }

    public String getOutput()
    {
        return new String(m_out.toByteArray());
    }
}
Omry Yadan
  • 31,280
  • 18
  • 64
  • 87
  • Omry, does the order matter? I should first read input/error stream and then write? –  Sep 14 '09 at 12:45
  • Omry, thanks for the code, I've tried it, but it still stucks at waitFor. –  Sep 14 '09 at 13:02
  • well, if your process is waiting for input, you should provide it. you can hack my code to print to System.out, so you will see what's happening with your process. you can also just tail the log file. make sure you use proc.getOutputStream().write() to send data to your process. – Omry Yadan Sep 14 '09 at 13:16
  • Thx Omry, I already did System.out in your code and while output is read, at least to point where the external app is asking me to enter the value. Btw, when I type value in application they are displayed using * character, but I dont see then when I write value using Java - that probably means the write wasn't successful? :( –  Sep 14 '09 at 13:20
  • Java successfully reads this: welcome banner please enter 8 character input: At this point Java writes input and they should be displayed with * character :-( –  Sep 14 '09 at 13:21
  • Maybe should I write one byte at the time? Because of ReadConsoleInput implementation in external application? –  Sep 14 '09 at 13:23
  • oh. try to call the flush() method of the output stream after write the data. – Omry Yadan Sep 14 '09 at 13:57
  • I see you already do it. if you program expects an enter send a newline (\n) – Omry Yadan Sep 14 '09 at 13:58
  • the timing of sending the output MAY matter if your program is behaving strangely. – Omry Yadan Sep 14 '09 at 14:01
0

Got the answer! The trick is to use WriteConsoleInput() API because program expects keyboard event, not text ... That's why the waitFor() waited forever! :)