Solved

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

Posted on 2003-10-21
9
315 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Get 15 Days FREE Full-Featured Trial

Benefit from a mission critical IT monitoring with Monitis Premium or get it FREE for your entry level monitoring needs.
-Over 200,000 users
-More than 300,000 websites monitored
-Used in 197 countries
-Recommended by 98% of users

 
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

Salesforce Has Never Been Easier

Improve and reinforce salesforce training & adoption using WalkMe's digital adoption platform. Start saving on costly employee training by creating fast intuitive Walk-Thrus for Salesforce. Claim your Free Account Now

Question has a verified solution.

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

Introduction This article is the first of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article explains our test automation goals. Then rationale is given for the tools we use to a…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
Viewers will learn about the different types of variables in Java and how to declare them. Decide the type of variable desired: Put the keyword corresponding to the type of variable in front of the variable name: Use the equal sign to assign a v…
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.

617 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