Runtime.exec(): can't access streams???

I'm trying to write a program in java that will run an executable that requires user input, and send it the input it requires.  The program in question is a scientific program written in C called proml, that displays a menu on stdout, saves data to a file, and collects the user input via stdin.  It doesn't use stderr.  In case you're interested, the source for proml can be downloaded from ftp://evolution.genetics.washington.edu/pub/phylip/phylip36, in the archive phylip.tar.Z.

Anyway, I don't care about displaying the output, although I wouldn't mind.  I really need to write to the input, though.  What I'm getting is that the process hangs right after it gets launched.  proml normally opens one of its output files ("outfile") as soon as it launches, and it does that, but it doesn't seem to produce any output, and doesn't do anything else.  Here's my code:

import java.io.*;
import java.util.*;

public class ExecTest
{
    public static void main(String args[])
    {
      if (args.length < 1)
      {
          System.out.println("USAGE: java ExecTest <outfile>");
          System.exit(1);
      }

      try{
          FileWriter fw = new FileWriter(args[0]);
          Runtime rt = Runtime.getRuntime();
          String[] cmd = {"proml"};
          Process proc = rt.exec(cmd);
          BufferedWriter in = new
            BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
          in.write("y");
          in.flush();
          System.out.println("I've just flushed :)");

          StreamHandler errHandler = new
            StreamHandler(proc.getErrorStream(), "ERROR");

          StreamHandler outHandler = new
            StreamHandler(proc.getInputStream(), "OUTPUT", fw);

          errHandler.start();
          outHandler.start();

          int exitVal = proc.waitFor();
          System.out.println("Process exit value: " + exitVal);
      }

      catch(Exception e){
          e.printStackTrace();
      }
    }
}


... and a second class:

import java.io.*;

public class StreamHandler extends Thread
{
    InputStream is;
    String type;
    Writer ow;

    public StreamHandler(InputStream is, String type)
    {
      this(is, type, null);
    }

    public StreamHandler(InputStream is, String type, Writer ow)
    {
      this.is = is;
      this.type = type;
      this.ow = ow;
    }

    public void run()
    {
      try
      {
           BufferedWriter bw = null;
            if (ow != null)
                bw = new BufferedWriter(ow);
          
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String line = "";
          String output = "";

            while ((line = br.readLine()) != null)
          {
            if (bw != null && ow != null)
            {
                bw.write(line + "\n");
                bw.flush();
            }

            System.out.println(type + ">" + line);

          }

          if (ow != null)
          {
            bw.write(output);
            bw.flush();
            bw.close();
          }
        }

      catch (IOException ioe)
        {
          ioe.printStackTrace();  
      }
    }
}


What am I doing wrong?
blackwednesdayAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

mightyoneCommented:
runtime uses another shell/cmd window than the new writing. even if it says so in the api. had same problem once.
e.g. you start your prog (java takes a shell/cmd) for the runtimeenvironment your prog uses it´s own Shell/cmd....
if on win platform try using a script with all inputs for your prog.

if you dont´t understand what i mean write a simple hello world prog in c++ and try to catch it´s output from java.....
i never managed...
0
girionisCommented:
> What I'm getting is that the process hangs right after it gets launched.

  This is usually done because you need to read the input and output stream in different threads. Take a look at the following exampel and adjust it as necessary:

import java.io.*;

public class LaunchProcess
{
    public static void main(String [] arg) throws
Exception
    {
        class Threader implements Runnable
        {
            BufferedReader br;
            String ss;

            Threader(InputStream is, String s)
            {
                ss=s;
                br = new BufferedReader(new
InputStreamReader(is));
            }

            public void run()
            {
                try
                {
                    String line;
                    while((line=br.readLine())!=null)
                    {
                        System.out.println(ss+"\t"+line);
                    }
                }
                catch(Exception e){e.printStackTrace();}
            }
        }

        Process p = Runtime.getRuntime().exec(arg);
        Thread out = new Thread(new
Threader(p.getInputStream(),"o"));
        Thread err = new Thread(new
Threader(p.getErrorStream(),"e"));
        System.out.println("Process says");
        out.start();
        err.start();
        p.waitFor();
    }
}
0
blackwednesdayAuthor Commented:
In response to mightyone:
I'm not sure exactly what you're getting at.  If you're saying that I have to handle the streams to and from the process, I'm doing that (although not as neatly and concisely as girionis, admittedly).  I don't know any C++, but I wrote a hello world in both C and Java, and I'm able to catch (and display) the output of both with my java program.

In response to girionis:
I've tried your code, and I have the same problem as with mine.  I'm able to run simple things (like the hello world programs, or ls, pwd, other unix commands), but not proml.  I've tried some other similarly complex C applications as well, but no luck.

Some other notes.  I can run proml from the command line by redirecting a file with the input parameters to it, e.g.:
proml <inputfile
This works.  Normally, though, even before it requires any input parameters, proml should display a menu on the screen, and it doesn't (even if I leave out the bit of code that deals with the stream to the program, i.e., the
 
         BufferedWriter in = new
          BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
         in.write("y");
         in.flush();
         System.out.println("I've just flushed :)");

bit.)

So I'm still looking for answers from you experts... Sorry I can't offer you any more points, I don't have any :(
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

mightyoneCommented:
what i wanted to say is read this link and you will undertsand

http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html

you need

import java.util.*;
import java.io.*;

class StreamGobbler extends Thread
{
    InputStream is;
    String type;
   
    StreamGobbler(InputStream is, String type)
    {
        this.is = is;
        this.type = type;
    }
   
    public void run()
    {
        try
        {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line=null;
            while ( (line = br.readLine()) != null)
                System.out.println(type + ">" + line);    
            } catch (IOException ioe)
              {
                ioe.printStackTrace();  
              }
    }
}

and

import java.util.*;
import java.io.*;

class StreamGobbler extends Thread
{
    InputStream is;
    String type;
   
    StreamGobbler(InputStream is, String type)
    {
        this.is = is;
        this.type = type;
    }
   
    public void run()
    {
        try
        {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line=null;
            while ( (line = br.readLine()) != null)
                System.out.println(type + ">" + line);    
            } catch (IOException ioe)
              {
                ioe.printStackTrace();  
              }
    }
}
0
blackwednesdayAuthor Commented:
I've actually read that article.  That's where I started.  I based my code on it (in fact, there's a bug in the code there: if you try to run ls with it, it doesn't work.  some of the conditions in the StreamGobbler class are wrong).

0
blackwednesdayAuthor Commented:
I'm a little disappointed in the experts... I suppose my question is kind of difficult, but still... anyway, I've solved it on my own, so don't bother thinking to hard about it anymore.  I made a new class,  OutputStreamHandler, modeled on StreamHandler, that sends commands to proml when it asks for them.  So that's that.

Thanks to all who tried to help.

bw
0
girionisCommented:
 Well we do not know everything :)

  Can you please ask a moderator to PAQ the question and refund the points back to yo?
0
YensidModCommented:
blackwednesday solution is:

I wrote another class, to deal with the stream going to the child process, that extends Thread.  Basically, it's the same thing as the StreamHandler class, but with a few minor changes:

import java.io.*;

public class OutputStreamHandler extends Thread
{
    OutputStream os;
    String type;
    String cmds[];

    public OutputStreamHandler(OutputStream os, String type, String cmds[])
    {
     this.os = os;
     this.type = type;
     this.cmds = cmds;
    }

    public void run()
    {
     try
     {
         BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
         String line = "";
         String output = "";

         for(int i = 0; i < cmds.length; i++)
         {
          bw.write(cmds[i] + "\n");
          bw.flush();
         }

         bw.flush();
         bw.close();
     }

     catch(IOException ioe)
     {
         ioe.printStackTrace();
     }
    }
}
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.