2

I don't know if it is possible, but thougt of giving it a try.
I am executing a small perl code within my java program like this

private void executePerlCode() {
    Process process;
    ProcessBuilder processBuilder;
    BufferedReader bufferedReader = null;
    try {
        // this line is used to execute the perl program
        processBuilder = new ProcessBuilder("perl", "D:\\test\\loop.pl");
        process = processBuilder.start();

        // To get the output from perl program
        bufferedReader = new BufferedReader(new InputStreamReader(
                process.getInputStream()));
        String line;
        StringBuffer str = new StringBuffer();
        while ((line = bufferedReader.readLine()) != null) {
            str.append(line);
            System.out.println(line);
        }
        // process.waitFor();

        // Set the output on the textfield
        // jTextArea1.setText(str.toString());

    } catch (Exception e) {
        System.out.println("Exception: " + e.toString());
    } finally {
        try {
            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

And my perl code is

for (my $i=0; $i <= 9; $i++) {
print "$i\n";
sleep(1);
}

I am able to get the output of perl program in my java program. But I want the perl code to give continuous output to java code. Like this, when the loop in perl prints value of 'i' for first time, I should be able to get that value in Java code. So that I can continuously update my Java UI according to the process going on in Perl code.

6
  • Your design is somewhat flawed then. Right now you are executing one process (perl) from another. So when the perl program is complete it gives back a response. If you want something continuous you'll need to write some perl to talk to java, on maybe a named pipe or some common store. Commented Sep 24, 2013 at 6:43
  • @Gideon : Yeah that is exactly what I want, but have no Idea as how to do it. Can you please share some examples where this thing has been implemented. Commented Sep 24, 2013 at 6:45
  • Of course it is possible. The only thing which prevents you from doing so is the line process.waitFor(); inside your code (which waits until the process has terminated). Commented Sep 24, 2013 at 7:50
  • Removed process.waitFor(), still not working as expected. Commented Sep 24, 2013 at 8:21
  • So are you now doing something with each line as it comes in? Is the setText() call inside the loop? Commented Sep 24, 2013 at 8:44

1 Answer 1

3

There are two parts to this:

  1. Making sure that the Perl output is not buffered so output is immediately available
  2. Making Java continuously read from Perl.

To ensure that the Perl output is not buffered you need to add the following line before the for:

STDOUT->autoflush(1);

Making Java continuously read is a little more challenging and the details of the approach will depend on what you intend to do with the output.

Below is an example where all that is required is to redirect the child process's output to the Java's output.

First, a class that extends Thread is required to handle the output of the spawned process:

package com.example;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

public class StreamRedirector extends Thread {

  private InputStream inputStream;
  private OutputStream outputStream;

  public StreamRedirector(InputStream inputStream, OutputStream outputStream) {
    this.inputStream = inputStream;
    this.outputStream = outputStream;
  }

  public void run() {
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
    InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
    String line = null;
    try {
      while ((line = bufferedReader.readLine()) != null) {
        outputStreamWriter.write(line + "\n");
        outputStreamWriter.flush();
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

Then the process can be spawned. In this example, the main code immediately waits for the spawned process to exit:

Runtime rt = Runtime.getRuntime();

Process proc;
try {
  proc = rt.exec(command);
} catch (IOException e) {
  throw new CustomException("Failed to execute.", e);
}

StreamRedirector outStreamRedirector = new StreamRedirector(proc.getInputStream(), System.out);
StreamRedirector errStreamRedirector = new StreamRedirector(proc.getErrorStream(), System.err);

outStreamRedirector.start();
errStreamRedirector.start();

int exitVal;
try {
  outStreamRedirector.join();
  errStreamRedirector.join();
  exitVal = proc.waitFor();
} catch (InterruptedException e) {
  throw new CustomException("Failed to execute.", e);
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks a lot. I can see the output on java console now :-)
But why should we tell perl not to buffer the content? If you execute the same perl script on shell, it works perfectly fine, the output is immediately available. Why this is different when execute from Java?
BTW, I have a simple shell script which prints something every 5 seconds, it works fine on shell and from Java, the output is never buffered, it's immediately available to the other end to consume. However, the same done in perl script has different effects. The perl script works fine on shell by immediately printing the ouput, but the output is buffered when executed from Java process.
We ask perl not to buffer so that java does not have to handle partial lines. This is more of a precaution that anything but, in some situations, it can avoid odd issues.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.