Solved

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

Posted on 2003-10-21
9
310 Views
Last Modified: 2010-05-18
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?
0
Comment
Question by:blackwednesday
  • 3
  • 2
  • 2
  • +1
9 Comments
 
LVL 6

Expert Comment

by:mightyone
ID: 9594934
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
 
LVL 35

Expert Comment

by:girionis
ID: 9596910
> 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
 

Author Comment

by:blackwednesday
ID: 9600162
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
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
LVL 6

Expert Comment

by:mightyone
ID: 9600683
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
 

Author Comment

by:blackwednesday
ID: 9600990
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
 

Author Comment

by:blackwednesday
ID: 9608433
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
 
LVL 35

Expert Comment

by:girionis
ID: 9610177
 Well we do not know everything :)

  Can you please ask a moderator to PAQ the question and refund the points back to yo?
0
 

Accepted Solution

by:
YensidMod earned 0 total points
ID: 9636011
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

Featured Post

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
eclipse buid path vs tomcat lib path 10 34
maven module vs maven project 3 47
maven disable workspace resolution 1 23
Eclipse for Java EE development 2 28
Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:

830 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question