Solved

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

Posted on 2003-10-21
9
308 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
 
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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 

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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Problem to start Neon 20 84
Image decoding from Camera 3 72
Java Loop 6 48
how to add new optional parameter to JSP 1 27
INTRODUCTION Working with files is a moderately common task in Java.  For most projects hard coding the file names, using parameters in configuration files, or using command-line arguments is sufficient.   However, when your application has vi…
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 third conditional statement “else if” and use it in an example program. Then additional information about conditional statements is provided, covering the topic thoroughly. Viewers learn about the third conditional statement …
The viewer will learn how to implement Singleton Design Pattern in Java.

914 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

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now