Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

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

Posted on 2003-10-21
9
Medium Priority
?
318 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
Build and deliver software with DevOps

A digital transformation requires faster time to market, shorter software development lifecycles, and the ability to adapt rapidly to changing customer demands. DevOps provides the solution.

 
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

Build and deliver software with DevOps

A digital transformation requires faster time to market, shorter software development lifecycles, and the ability to adapt rapidly to changing customer demands. DevOps provides the solution.

Question has a verified solution.

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

Are you developing a Java application and want to create Excel Spreadsheets? You have come to the right place, this article will describe how you can create Excel Spreadsheets from a Java Application. For the purposes of this article, I will be u…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
This video teaches viewers about errors in exception handling.
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.
Suggested Courses

688 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