Java output stream to subprocess flush results in IOException - java

I have a subprocess receiving data from stdin line by line. Then it receives $X$ line, it stops reading input streams, performs internal task on it, then exits.
Now I wrote some tester for it:
public class MessageShowTester {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
Process p = Runtime.getRuntime().exec("java -jar \"/home/user/NetBeansProjects/MessageShow/dist/MessageShow.jar\"");
p.getOutputStream().write("Hi\n$X$\n".getBytes());
p.getOutputStream().flush();
}
}
As the result I receive IOException on p.getOutputStream().flush()line. Much stranger is that another application I use the same construction doesn't share such behavior.
There is a limited version of MessageShow as example, that fails same way on tester, but works well from IDE.
public class MessageShow {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
String message="";
String temp="";
while(true)
{
temp = new Scanner(System.in).nextLine();
if("$X$".equals(temp)) break;
message+=temp;
message+="\n";
}
JOptionPane.showMessageDialog(null, message);
}
}
Stack trace:
Exception in thread "main" java.io.IOException: Broken pipe
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:315)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at messageshowtester.MessageShowTester.main(MessageShowTester.java:23)
Java Result: 1

If the subprocess finishes quickly, the parent process may not yet have done the flush. In this situation, the pipe between the processes has already been closed on the subprocess side and you'll see
Exception in thread "main" java.io.IOException: Stream closed
or similar.
You shouldn't need the explicit flush. For passing a single line to a subprocess, consider a process parameter.
Less confident about what works and what not, but I have found that using
PrintWriter pw = new PrintWriter( p.getOutputStream() );
pw.println("hifile.dat");
pw.println("$X$");
pw.close();
succeeds in passing both lines to the subprocess.
In the subprocess,
Scanner scanner = new Scanner(System.in);
while(true){
temp = scanner.nextLine();
if("$X$".equals(temp)) break;
message+=temp;
}
is better than recreating a Scanner for each line, although it doesn't influence the fate of the subprocess.

Related

Compile and run a Java program from another Java program

I am writing a program that takes the path to the input ".java" file with a main method. The program should then compile that file, and run it.
Let's say that the program I am trying to compile and run looks like this:
Main.java
public class Main {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
The program that performs compilation and tries to run it:
Evaluator.java
/**
* Matches any .java file.
*/
private static final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:**.java");
private static String path;
/**
* Program entry point. Obtains the path to the .java file as a command line argument.
*
* #param args One argument from the command line: path to the .java file.
* #throws Exception
*/
public static void main(String[] args) throws Exception {
if (args.length != 1) {
throw new IllegalArgumentException(
"Expected exactly one argument from the command line.");
}
if (!matcher.matches(Paths.get(args[0]))) {
throw new IllegalArgumentException(
String.format("File %s is not a valid java file.", args[0]));
}
// path is in a valid format
path = args[0];
// compile a program
compile();
// run a program
run();
}
/**
* Compiles a program.
*
* #throws Exception
*/
private static void compile() throws Exception {
System.out.println("Compiling the program ...");
Process p = Runtime.getRuntime().exec("javac " + path);
output("Std.In", p.getInputStream());
output("Std.Out", p.getErrorStream());
p.waitFor();
System.out.println("Program successfully compiled!\n");
}
/**
* Runs a program.
*
* #throws Exception
*/
private static void run() throws Exception {
System.out.println("Executing the program ...");
Process p = Runtime.getRuntime().exec("java " + getProgramName(path));
output("Std.In", p.getInputStream());
output("Std.Out", p.getErrorStream());
p.waitFor();
System.out.println("Program finished!");
}
private static void output(String stream, InputStream in) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(in, CS));
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
System.out.println(String.format("%s: %s", stream, line));
}
}
private static String getProgramName(String path) {
return path.replace(".java", "");
}
}
My "Main.java" file is located in the project root. I am running the program with a command line argument "./Main.java". Doing so, compiles the program correctly and yields a new file "Main.class". However, the run method outputs as follows:
Std.Out: Error: Could not find or load main class ..Main
What should be the problem here?
Try to set to java process you're launching the correct working directory and then set the related classpath.
This should help.
Update
I suggest to use the method Runtime.getRuntime().exec(String command, String[] envp, File dir).
Last parameter dir is the process working directory.
The Problem here is you are passing argument
./Main.java
instead, you should pass Main.java as an argument else you need to change your getProgramName() method to return the Class name correctly.
Which will let you compile the program perfectly with javac command but problem happens when you need to run the program because that command should be
java Main
whereas you are trying to execute
java ./Main

Read stdout stream from subprocess as it becomes available

In my Java application, I need to execute some scripts as subprocesses and monitor the output on stdout from Java so that I can react when necessary to some output.
I am using apache commons-exec to spawn the subprocess and redirect stdout of the executed script to an input stream.
The problem that I am having is that when reading from the stream, the Java process is blocked until the subprocess is finished execution. I cannot wait until the end of the subprocess to react to the output, but I need to read it asynchronously as it becomes available.
Below is my Java code:
public class SubProcessReact {
public static class LogOutputStreamImpl extends LogOutputStream {
#Override
protected void processLine(String line, int logLevel) {
System.out.println("R: " + line);
}
}
public static void main (String[] args) throws IOException, InterruptedException {
CommandLine cl = CommandLine.parse("python printNumbers.py");
DefaultExecutor e = new DefaultExecutor();
ExecuteStreamHandler sh = new PumpStreamHandler(new LogOutputStreamImpl());
e.setStreamHandler(sh);
Thread th = new Thread(() -> {
try {
e.execute(cl);
} catch (IOException e1) {
e1.printStackTrace();
}
});
th.start();
}
}
For this example, the subprocess is a python script which counts upwards with a one second delay between outputs so that I can verify that the Java code is responding as data comes in.
Python Code:
import time
for x in range(0,10):
print x
time.sleep(1)
I would expect LogOutputStreamImpl to print each line as it comes, but what is actually happening is that it reading the stream blocks until the subprocess is completed, and then all of the output is printed.
Is there something I could do to make this work as I intend?
Why use a third-party library to do something Java SE already does well? Personally, I prefer to depend on as few external libraries as possible, in order to make my programs easily portable and to reduce the points of failure:
ProcessBuilder builder = new ProcessBuilder("python", "printNumbers.py");
builder.inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE);
Process process = builder.start();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
reader.lines().forEach(line -> System.out.println("R: " + line));
}
process.waitFor();

Redirecting STDIN and STDOUT of C program in Android

I am trying to port a C program to android using JNI. I have been able to set up the program and get java and c working fine together. The problem is I need to be able to use STDIN since the C program reads input from STDIN and returns a response through STDOUT (C program is a server-client application).
I don't know if it is worth mentioning but the C program uses STDIN_FILENO file descriptor for reading input from STDIN.
How do I read from STDOUT and WRITE to STDIN using Java?
I did some research and found some vague explanation at the following link: https://groups.google.com/forum/#!topic/android-ndk/Brm6jPr4C0Y that I don't understand.
Here's is the C code https://github.com/unekwu/kemi/blob/master/jni/dnscat/dnscat.c#L1270
More Details
The C program is usually run from command line like
dnscat --dns <ip> <port>
After which it starts listening for messages from the user. Normally entered from stdin.
Now in my Android app,
I'm able to run it with JNI by calling main and different name and passing ann array of strings to it. I'v verify the program starts up correcting. The problem is how I'll send the messages to the program since there's no stdin on android.
I've created a project in github, which you can download from here.
It creates 2 named pipes (FIFO), one for input and other for output.
It opens up one end of the pipe in write only mode in native code and other end of the pipe in read only mode in Java code. The file descriptor in native code is mapped to STDOUT i.e. 1, thereafter any writes to STDOUT in native code, will be redirected to other end of pipe which can read in Java code.
It opens up one end of the pipe in read only mode in native code and other end of the pipe in write only mode in Java code. The file descriptor in native code is mapped to STDIN i.e. 0, thereafter any writes to other end of pipe in Java code, will be read by native code using STDIN.
To achieve STDOUT redirection:
Native Code:
/*
* Step 1: Make a named pipe
* Step 2: Open the pipe in Write only mode. Java code will open it in Read only mode.
* Step 3: Make STDOUT i.e. 1, a duplicate of opened pipe file descriptor.
* Step 4: Any writes from now on to STDOUT will be redirected to the the pipe and can be read by Java code.
*/
int out = mkfifo(outfile, 0664);
int fdo = open(outfile, O_WRONLY);
dup2(fdo, 1);
setbuf(stdout, NULL);
fprintf(stdout, "This string will be written to %s", outfile);
fprintf(stdout, "\n");
fflush(stdout);
close(fdo);
Java Code:
/*
* This thread is used for reading content which will be written by native code using STDOUT.
*/
new Thread(new Runnable() {
#Override
public void run() {
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(mOutfile));
while(in.ready()) {
final String str = in.readLine();
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(RedirectionJni.this, str, Toast.LENGTH_LONG).show();
}
});
}
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
To achieve STDIN redirection:
Native Code:
/*
* Step 1: Make a named pipe
* Step 2: Open the pipe in Read only mode. Java code will open it in Write only mode.
* Step 3: Make STDIN i.e. 0, a duplicate of opened pipe file descriptor.
* Step 4: Any reads from STDIN, will be actually read from the pipe and JAVA code will perform write operations.
*/
int in = mkfifo(infile, 0664);
int fdi = open(infile, O_RDONLY);
dup2(fdi, 0);
char buf[256] = "";
fscanf(stdin, "%*s %99[^\n]", buf); // Use this format to read white spaces.
close(fdi);
Java Code:
/*
* This thread is used for writing content which will be read by native code using STDIN.
*/
new Thread(new Runnable() {
#Override
public void run() {
BufferedWriter out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(mInfile)));
String content = "This content is written to " + mInfile;
out.write(content.toCharArray(), 0, content.toCharArray().length);
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
Let me know if you need any help.
In the Java Code, get a command line by
Process p;
p = Runtime.getRuntime().exec("su"); // or execute something else, su is just to get root
DataOutputStream dos = new DataOutputStream(p.getOutputStream());
dos.writeBytes(ForExampleABinaryPath+" &\n");
dos.flush();
// to read (might has to run parallel in different thread)
InputStream is = p.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
is.readLine() // will get you a line o null
using write && flush and read in parallel, you might be able to achieve your goals.
good luck

Java Process "The pipe has been ended" problem

I am using Java Process API to write a class that receives binary input from the network (say via TCP port A), processes it and writes binary output to the network (say via TCP port B). I am using Windows XP. The code looks like this. There are two functions called run() and receive(): run is called once at the start, while receive is called whenever there is a new input received via the network. Run and receive are called from different threads.
The run process starts an exe and receives the input and output stream of the exe. Run also starts a new thread to write output from the exe on to the port B.
public void run() {
try {
Process prc = // some exe is `start`ed using ProcessBuilder
OutputStream procStdIn = new BufferedOutputStream(prc.getOutputStream());
InputStream procStdOut = new BufferedInputStream(prc.getInputStream());
Thread t = new Thread(new ProcStdOutputToPort(procStdOut));
t.start();
prc.waitFor();
t.join();
procStdIn.close();
procStdOut.close();
} catch (Exception e) {
e.printStackTrace();
printError("Error : " + e.getMessage());
}
}
The receive forwards the received input from the port A to the exe.
public void receive(byte[] b) throws Exception {
procStdIn.write(b);
}
class ProcStdOutputToPort implements Runnable {
private BufferedInputStream bis;
public ProcStdOutputToPort(BufferedInputStream bis) {
this.bis = bis;
}
public void run() {
try {
int bytesRead;
int bufLen = 1024;
byte[] buffer = new byte[bufLen];
while ((bytesRead = bis.read(buffer)) != -1) {
// write output to the network
}
} catch (IOException ex) {
Logger.getLogger().log(Level.SEVERE, null, ex);
}
}
}
The problem is that I am getting the following stack inside receive() and the prc.waitfor() returns immediately afterwards. The line number shows that the stack is while writing to the exe.
The pipe has been ended
java.io.IOException: The pipe has been ended
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:260)
at java.io.BufferedOutputStream.write(BufferedOutputStream.java:105)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
at java.io.BufferedOutputStream.write(BufferedOutputStream.java:109)
at java.io.FilterOutputStream.write(FilterOutputStream.java:80)
at xxx.receive(xxx.java:86)
Any advice about this will be appreciated.
This means you are writing to the pipe after the other end has already closed it.
That indicates a major error in your application protocol.
I have had the same problem recently and I have found a solution.
First of all, "The pipe has been ended" error is not a Java error - it comes from Windows system. According to MSDN:
The using process has closed the pipe or, if you are trying to write
to the pipe, there are no available readers.
Not very informative. However, if process has closed the pipe itself, it may mean that some errors occurred in process.
To check this, redirect errors coming from process, for instance, to a file:
File f = new File("errors.txt");
pb.redirectError(f);
In my case (I've been trying to execute SrcML parser) file contained this:
.\libs\srcML-Win\src2srcml.exe: unrecognised option `--language Java'
Try 'src2srcml --help' for more information.
Fixing this solved the problem.

Java, Junit - Capture the standard input / Output for use in a unit test [duplicate]

This question already has answers here:
JUnit test for System.out.println()
(14 answers)
Closed 8 years ago.
I'm writing integration tests using JUnit to automate the testing of a console based application. The application is homework but this part isn't the homework. I want to automate these tests to be more productive -- I don't want to have to go back and retest already tested parts of the application. (Standard reasons to use Unit tests)
Anyway, I can't figure out or find an article on capturing the output so that I can do assertEquals on it nor providing automated input. I don't care if the output/input goes to the console/output pane. I only need to have the test execute and verify the the output is what is expected given the input.
Anyone have an article or code to help out with this.
Use System.setOut() (and System.setErr()) to redirect the output to an arbitrary printstream - which can be one that you read from programmatically.
For example:
final ByteArrayOutputStream myOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(myOut));
// test stuff here...
final String standardOutput = myOut.toString();
The System class has methods setIn(), setOut() and setErr() that allow you to set the standard input, output and error streams, e.g. to a ByteArrayOutputStream that you can inspect at will.
Here is the solution in place of ByteArrayOutputStream. It does not add anything to the idea of System.setOut. Rather, I want to share the implementation that is better than capturing everything into ByteArrayOutputStream. I prefer to capture only selected information and let all log messages to appear in the console as they are logged rather than capturing everything into a balckbox (of which size?) for later processing.
/**
* Once started, std output is redirected to this thread.
* Thread redirects all data to the former system.out and
* captures some strings.*/
static abstract class OutputCaputre extends Thread {
// overrdie these methods for System.err
PrintStream getDownstream() { return System.out;}
void restoreDownstream() { System.setOut(downstream);}
// will be called for every line in the log
protected abstract void userFilter(String line);
final PrintStream downstream;
public final PipedInputStream pis;
private final PipedOutputStream pos;
OutputCaputre() throws IOException {
downstream = getDownstream();
pos = new PipedOutputStream();
pis = new PipedInputStream(pos);
System.setOut(new PrintStream(pos));
start();
}
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(pis));
// once output is resotred, we must terminate
while (true) {
String line = br.readLine();
if (line == null) {
return;
}
downstream.println(line);
userFilter(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void terminate() throws InterruptedException, IOException {
restoreDownstream(); // switch back to std
pos.close(); // there will be no more data - signal that
join(); // and wait until capture completes
}
};
Here is an example of using the class:
OutputCaputre outputCapture = new OutputCaputre() {
protected void userFilter(String line) {
downstream.println("Capture: " + line);
}
};
System.out.println("do you see me captured?");
// here is your test
outputCapture.terminate(); // finally, stop capturing

Categories

Resources