how to read output and provide input to subprocess in java - java

I want to make a Java program to run another Java program. I wrote some code to run another Java program. Jhon.java is a Java file from which I execute the Add.class file. But there is problem while reading output and provide input to subprocess. I have this code.
import java.io.*;
class Jhon
{
public static void main(String args[])
{
try
{
String command="java Add";
Process proc=Runtime.getRuntime().exec(command);
Thread t1=new A(proc);
t1.start();
Thread t2=new B(proc);
t2.start();
proc.waitFor();
t1.join();
t2.join();
}
catch(Exception e)
{}
}
}
class A extends Thread
{
Process proc;
A(Process proc)
{
this.proc=proc;
}
public void run()
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try
{
while(true)
{
String s = br.readLine();
OutputStream out = proc.getOutputStream();
out.write(s.getBytes());
out.close();
}
}
catch(Exception e)
{}
}
}
class B extends Thread
{
Process proc;
B(Process proc)
{
this.proc=proc;
}
public void run()
{
try
{
String line="";
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while((line=br.readLine())!=null)
{
System.out.println(line);
}
}
catch(Exception e)
{}
}
}
This is the Add.java file which is executed by Jhon.java file
import java.io.*;
class Add
{
public static void main(String args[])
{
int a,b,c;
try
{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter first number");
a=Integer.parseInt(br.readLine());
System.out.println("Enter second number");
b=Integer.parseInt(br.readLine());
c=a+b;
System.out.println("Addition is "+c);
}
catch(IOException e)
{
System.out.println(e);
}
}
}
When I execute the Add.java file from Jhon.java file it asks to enter the first number. After providing the first number, it asks to enter the second number. After providing the second number, it does not print addition. The terminal hangs . So what am I doing wrong? Please give me a solution.

Your class A reads the first line of input, calls getOutputStream() and os.write() to (begin to) send that line to the subprocess and then calls os.close(). After flushing the data, that closes the pipe that communicates to the standard input of the subprocess. It then loops around to read the next line and tries to getOutputStream and write and close again, but the write does nothing because it is buffered and the close actually fails because the pipe is closed but it suppresses the internal exception, I believe so autoclose is safe. It then waits for further input.
Your class Add in the subprocess successfully reads the first line; when it tries to read the second line its standard input (the pipe from the master) has been closed normally, which is considered "EOF" (End Of File). br.readLine() returns null to indicate EOF, but you pass it to Integer.parseInt which causes a NullPointerException, which isn't caught (it's not a subtype of IOException) so the Java default is to display a stacktrace on standard error and exit. Standard error for a subprocess is piped to the master as a separate stream (not "Input" stream) and your master isn't looking at it, so that information is lost.
Meanwhile (the thread for) your class A is still waiting for input. If you enter whatever the end-of-input signal is on your platform (usually control-D on Unix but can be configured to something else, control-Z on Windows) it will treat that as EOF, readLine will return null and so s.getBytes() will throw a NullPointerException which your catch(IOException){} will silently discard, and it will exit with no indication of the numerous problems that actually occurred.
Moral: in addition to trying to write correct code in the first place, realize that humans don't get everything perfect every time, so don't throw away exceptions unless you know for certain what caused them -- and at your stage of learning you don't know. And try not to throw away other error information either (in this case the error stream from the subprocess).
Fixes:
call getOutputStream only once, and for each input line (in the loop if you keep the loop but see next) do os.write(line) and os.flush() but NOT os.close().
either rearrange this to be synchronous as #MadProgrammer commented, or else arrange so that your input-and-send thread t1 terminates when the subprocess exits, or equivalently when the receive-and-display thread t2 terminates -- which it does when br.readLine()==null indicating EOF because the subprocess exited, which class B does test correctly unlike class A. This is hard to do automatically because A is already sitting in readLine which cannot be interrupted, at least not reliably. One simple possibility is to output a message telling the user to now enter the end-of-input signal, and code A to handle EOF correctly.
or, a real kludge but for completeness, make t1 a daemon thread and don't join it. Then main will return which terminates the main thread once the subprocess has exited and t2 has terminated, and the JVM will exit without waiting for t1. Because this is usually a Bad Idea I won't give you 'teh codez' but a little googling will find how to do this.

Related

Interrupt Scanner nextLine() (alternatives)

I have the following thread:
Thread t1 = new Thread() {
#Override
public void run() {
while (!progress.equals(duration)) {
try {
Thread.sleep(1000);
progress = progress.plusSeconds(1);
// synchronized (this) { while (paused) { this.wait(); } }
} catch (InterruptedException e) {
interrupt();
}
}
}
};
t1.start();
I'm trying to implement a functionality which allows the user to pause and stop this thread using the console. Basically, this:
Scanner sc = new Scanner(System.in);
int choice;
while (t1.isAlive()) {
System.out.println("Choose an option:\n1. Pause/Resume\n2. Stop");
choice = Integer.parseInt(sc.nextLine());
// if (choice == 1) { ... } else if (choice == 2) { t1.interrupt() }
// synchronized (t1) { t1.notify(); }
}
My problem is that once t1 dies, t1.isAlive() evaluates to false, but the program doesn't exit the while loop because it is stuck waiting for one last input from the user. I want to interrupt sc.nextLine(), but I read it is not possible because the thread is blocked. How could I do this?
I tried the following:
Thread t2;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (t1.isAlive()) {
t2 = new Thread() {
#Override
public void run() {
try {
while (!br.ready())
Thread.sleep(200);
choice = Integer.parseInt(br.readLine());
} catch (InterruptedException e) {
} catch (IOException e) {
}
}
};
t2.start();
}
Supposedly, this should allow me to interrupt t2, but I must be doing something wrong because it keeps printing Chose an option: 1. Pause/Resume 2. Stop, so I cannot check if it works.
The crucial issue is that the API of System.in makes no guarantees. A JVM can fulfill the complete JVM spec even if it has a System.in such that, if it is interrupted, nothing happens and it is in fact completely impossible to interrupt System.in, aside from System.exit.
However, most JVM implementations fortunately don't quite work that way: If you raise the interrupt flag on any given thread, 3 things are going to happen:
Any method that is specced to definitely look at em will be interrupted: These are all methods that are declared to throws InterruptedException. All these methods will, if the thread's interrupt flag is raised, stop waiting immediately, lower the flag, and return by way of throwing InterruptedException. Yes, this means that if you first raise the interrupt flag (someThread.interrupt() raises the flag and doesn't do anything else; it's other methods that look at it that makes the magic work), and then invoke e.g. Thread.sleep, the sleep calls returns immediately (by throwing InterruptedEx) and waits no even a single millisecond.
Methods that pause a thread but which are not specced to definitely deal with it properly are in limboland: It is up to the implementation of the java runtime if anything happens. However, usually something will happen. These methods almost always throw some sort of checked exception (for DB connections, SQLEx, for network, file, and pipe operations, IOException); any code that is currently waiting to send or receive data on one of these things will deal with a raised interrupt flag by lowering the flag, aborting the operation, and returning by way of throwing that checked exception with a message that indicates an interruption occurred.
If code is executing that doesn't respond to the interrupt flag at all, then nothing happens: The flag stays raised and the JVM is not going to do anything else; the point of the interrupt flag is that it just gets raised and then you wait until the thread runs code that looks at it. Hopefully, that will happen very soon, but there are no guarantees.
That means that most likely all you need to do is:
In T1
Have some sort of AtomicBoolean object that will be set to true by t1 once the job is completed.
t1 will also raise the interrupt flag of t2 when the job is completed.
In T2
Protect your readLine() call by putting it in a try/catch block, catching IOException. If there is a loop you may also want to consider checking the interrupt flag yourself, in case it is set in between readLine() invokes; you do this with Thread.interrupted(), which returns true and lowers the flag if the flag is up. Generally, something like while (!Thread.interrupted() && other conditions) { /* main loop here */ }.
In the IOException catch handler, check t1's 'we are done' flag (that AtomicBoolean). If it says 'we are done', then interpret the IOEx as simply being notified that the job is done (so, don't log it anywhere - you were expecting it to happen). If, however, the 'we are done' flag isn't set yet, then that IOException is indicating an actual I/O problem with the input pipe, which can happen of course. You should proceed as normal (which usually means, throw it onwards so that the app crashes with a full log, you can't sanely respond to the input pipe getting I/O issues other than to exit with debug info about what happend). So, just throw that IOException. If you can't, throw new UncheckedIOException(thatIoException); is what you are looking for.
The caveat
Just because it works on your system does not mean it will work anywhere else, unfortunately. As I said, on some VM impls System.in.read() is just not interruptable, period. Nothing you can do, other than extremely drastic steps: Stop being a command line app and show a swing GUI window instead or make it a web app of some sort.
Closing notes
ready() and available() are almost completely useless. They aren't broken, in the sense that they do exactly what their javadoc says these methods do, but if you carefully read that javadoc, you'll realize that what they provide is completely useless. The only real way to know if data is available is to actually attempt to read it, which then leads you into the trap of: Well, on some platforms, that's not interruptable. Yup. Sucks. No reliable solution, in the sense that the API guarantees it'll work on all platforms, is available. 99.5% of all code out there that calls these methods is broken. It is highly unlikely that you'd ever want to call these methods.
It looks like an innocent topic, but actually it's a bit more complicated. When you are reading from the standard input, you usually just end up in a call to the operating system. Which will not return until it has actual input to return with, and has no idea about the interruption mechanism of Java. It's described as a by-product here.
What you can do is providing your own InputStream instead of using System.in directly, and implement its read() method in a way that it goes into System.in.read() only when System.in.available() says so. Until then just repeat the check with some delay, like using Thread.sleep() which is prepared to get interrupted anyway:
public static void main(String[] args) {
Thread main = Thread.currentThread();
// try (Scanner sc = new Scanner(System.in)) {
try (Scanner sc = new Scanner(new InputStream() {
#Override
public int read() throws IOException {
while (System.in.available() == 0)
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
throw new IOException();
}
return System.in.read();
}
})) {
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException ie) {
}
main.interrupt();
}
}).start();
String line = sc.nextLine();
System.out.println(line);
System.out.println(main.isInterrupted());
} catch (Exception ex) {
System.out.println("Time's up, probably. Actual exception: " + ex);
System.out.println(main.isInterrupted());
}
}
If you comment the try(Scanner...-})) { block and uncomment the single-line variant, you can try how it doesn't work in itself: you will always have to input something, only the result of System.out.println(main.isInterrupted()); will tell you if you did it in 5 seconds or it took more time.
Side note: in your own attempt you were interrupting the timer thread itself, you need a reference to the other thread instead, here in this example that's the Thread main variable.

java program crashes at Scanner initialization

I'm using scanner to read lines from file and replace some text in each line based on given pattern. This is done inside an API. My program is a multithreaded one. At once, more than one thread can call this particular API.
Following is the line scanner initialization line where the thread crashes:
public static void replaceInFile(Properties replacements, Path targetFile) {
...
Scanner in = new Scanner(targetFile, "UTF-8");
...
}
I'm sure no single file will be accessed by two threads at once. Can anyone hint me in the right direction as to what is happening?
UPDATE:
public Void call() throws Exception {
Iterator it = paths.iterator();
while(it.hasNext()){
try {
String filePath = it.next().toString();
//BuildUtil replacer = new BuildUtil();
BuildUtil.replaceInFile(replacements, Paths.get(filePath));
} catch(Exception e) {
e.printStackTrace();
}
}
This is the call() of the thread. Now I observe that it shows "Frame not available" even before stepping into the BuildUtils's replaceInFile method and sometimes after entering in there..I'm not able to figure out what's wrong.. The main thread is exiting I think but I see nothing strange happening here which should make it exit unexpectedly.
I found it. Actually it was my stupidity. I forgot to wait for the threads to exit and so the main thread exited even before threads could complete. Sorry for bothering!
So now I do :
for (int i = 0; i < threadsUsed; i++) {
pool.take().get();
}
for all the threads and shutdown the executor service in finally block

Java interactive console

I'm currently developing a Java command-line application and I want to make it interactive. I mean, I have 2 threads:
one thread is permanently writing some information to stdout
the second thread only reads from stdin and is waiting for some commands from the user
But the point is, it's really annoying when I'm typing a command while the first thread writes something to stdout, the command is "cut".
For example:
I want to type the command 'set infolevel 2', and while I'm typing that, the first thread outputs "some information 1234".
My console output may look like this:
set inf // user typing command into stdin
some information 1234 // first thread writes out information
olevel 2 // continuing reading command from stdin
It would be very awsome if someone could tell me if there's a library/API something like that. Thanks!
I guess you would be using System.out.println for output to the console and new Scanner(System.in); for reading input.
Essentially System.out is a PrintStream and System.in is a InputStream and are different object (and streams) but they both use same source (I guess IDE console or command prompt in your case) so when 2 or more threads will try to use the same source then you will get the behavior you have mentioned because by default same source/console is used by the host environment or user. Read below from Java source:
System.out
/**
* The "standard" input stream. This stream is already
* open and ready to supply input data. Typically this stream
* corresponds to keyboard input or another input source specified by
* the host environment or user.
*/
System.in
/**
* The "standard" output stream. This stream is already
* open and ready to accept output data. Typically this stream
* corresponds to display output or another output destination
* specified by the host environment or user.
As far as I know, there are really no such API's to help you out what you are looking for but there are couple of work around options:
Please note, IMHO Option 3 or any similar solution which is based on synchronization is something which you may not want because it will limit your output'ing capabilities
Option 1:
Configure a different console device and then access it using System.console(). In this case, you will have different sources for read and write to console and hence you will not get what you are seeing. If you don't explicitly configure anything then by default you will get System.console() as NULL
Option 2:
Instead of writing the output to console, use a file to write the output. This will ensure that your input and output stream are not messing up with each other.
Option 3:
If you have same source for both read and write to console, then synchronize the access. Below is same code but please be mindful that you could still see some overlap for the time when object lock is being acquired and released but once lock is acquired or released on System.out or System.in then you will not see overlap.
public class Test {
static Object object = new Object();
public static void main(String[] args) {
new Thread(){
#Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object) {
Date date = new Date();
System.out.println("I am coming from first thread i.e. " + Thread.currentThread().getId() + " : " + date);
}
}
}
}.start();
new Thread(){
#Override
public void run() {
Scanner scanner = new Scanner(System.in);
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object) {
scanner.next();
}
}
}
}.start();
}
}
It seems you need to synchronize the two threads on some kind of object. Something like : private Object lockObject = new Object(); Thread t1 = new Thread() { public void run() {synchronized( lockObject ){ //your code } } };
You could either use locking as svasa suggested in his answer, or modify your code so that you have one thread that does both input and output, and the other thread does the computational work. Use an ArrayBlockingQueue to send the output of the work thread to the I/O thread.

In Windows: Get unbuffered stdout from C program into Java program InputStream [Now with minimal example!]

SOLVED:
HovecraftFullOfEels found my mistake. See the comments on his answer below. I was calling run() on a Thread object when I should have been calling start(). In my original program, that meant it blocked on stderr until the program quit and then got stdout all at once.
UPDATE:
As requested, I've produced a minimal example. Here's the producer:
package producer;
public class Producer {
public static void main(String[] args) throws InterruptedException {
for (int i=0; i<10; i++) {
System.out.println(i);
System.out.flush();
Thread.sleep(1000);
}
}
}
Here's the consumer:
package consumer;
import java.io.IOException;
import java.io.InputStream;
public class Consumer {
static class Dumper extends Thread {
InputStream r;
boolean print;
Dumper(InputStream r, boolean print) {
this.r = r;
this.print = print;
}
#Override
public void run() {
int c;
try {
while ((c = r.read()) != -1) {
if (print) System.out.print((char)c);
}
r.close();
} catch (IOException ex) {}
}
}
public static void main(String[] args) throws Exception {
Process p = Runtime.getRuntime().exec("java -jar C:\\Users\\millerti\\Documents\\NetBeansProjects\\Producer\\dist\\Producer.jar");
new Dumper(p.getErrorStream(), false).run();
new Dumper(p.getInputStream(), true).run();
p.waitFor();
}
}
Expected behavior: Since the producer flushes its output and the consumer is completely unbuffered, the consumer should get the producer's output in real time.
Observed behavior: The consumer receives the producer's output all at once only when the producer finished.
Original post:
I'm working with another developer on a Windows application. She has written a C program (which we can modify) that performs a media conversion and prints progress messages (in percentage) to stdout. I am writing a graphical front-end in Java, and I would like my program to capture those messages and update a GUI element.
The relevant C program code looks like this:
printf ("progress_msg: %d%%\n", currentProgress);
fflush(stdout);
In the Java program, I'm using Runtime.getRuntime().exec() to run the C program and grabbing the raw InputStream objects for C program's stdout and stderr. (The stderr is just being thrown away by another thread.) I'm parsing the stdout stream, looking for those messages (well, I was, using a BufferedReader, but right now, I'm trying to debug this, so I'm talking directly to the low-level InputStream byte source.)
The problem is that although there is no buffering on the Java side (that I know of) and there's an fflush in the C program, the stdout text appears all at once only when the C program finishes. This is unlike when I run it from the command prompt, where the messages come out gradually as expected.
So clearly, there's some buffering going on. Is the Process facility in Java doing some buffering that I don't know about? If so, is there a way to turn it off? Does fflush(stdout) in Windows not work in the expected way? What is the proper Windows equivalent?
Thanks.
Note: I have found two related stackoverflows, but they do not answer this question. In particular, we CAN modify the C program, there's no line buffering, and we ARE doing a proper flush (as far as we know). See I want realtime output of my Runtime.getRuntime().exec() and Unbuffered subprocess stdout on windows.
A wild guess from my part, but you state:
... I am writing a graphical front-end in Java, and I would like my program to capture those messages and update a GUI element.
...
In the Java program, I'm using Runtime.getRuntime().exec() to run the C program and grabbing the raw InputStream objects for C program's stdout and stderr. ... I'm parsing the stdout stream, looking for those messages ...
The problem is that although there is no buffering on the Java side (that I know of) and there's an fflush in the C program, the stdout text appears all at once only when the C program finishes.
I again have to guess as you've left out important details, all code, but if your front end is a Swing GUI, then the symptoms you've described suggest that you're trying to get all information on the Swing event thread. If this is a Swing application, a solution is to make sure to read the output of the Stream in a background thread such as that provided by a SwingWorker, to make sure that you buffer this data that you're reading in, and to then display it in the GUI in a thread-safe way (again using a SwingWorker, especially its publish/process method pair).
For better help, please give us better information and code, preferably a small, in fact minimal, example program that we can run and test and improve.
Edit
My test program:
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Consumer {
static class StreamGobbler implements Runnable {
private String name;
private boolean print;
private Scanner scanner;
public StreamGobbler(String name, InputStream inputStream, boolean print) {
this.name = name;
this.print = print;
scanner = new Scanner(inputStream);
}
#Override
public void run() {
System.out.printf("in %s run method%n", name);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (print) {
String output = String.format("From %s: %s%n", name, line);
System.out.printf(output);
}
}
if (scanner != null) {
scanner.close();
}
}
}
private static final String PRODUCER_PATH = "C:/Users/Pete/Documents/Fubar/Java/producer.jar";
public static void main(String[] args) {
List<String> command = new ArrayList<>();
command.add("java.exe");
command.add("-jar");
command.add(PRODUCER_PATH);
try {
ProcessBuilder pBuilder = new ProcessBuilder(command);
Process process = pBuilder.start();
StreamGobbler errorGobbler = new StreamGobbler("Error Gobbler", process.getErrorStream(), true);
StreamGobbler inputGobbler = new StreamGobbler("Input Gobbler", process.getInputStream(), true);
new Thread(errorGobbler).start();
new Thread(inputGobbler).start();
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}

Java console output from another thread dropped

I have a problem with the console output of one of my threads being dropped (in Java). The situation is as follows: I spawn a thread that listens (using a blocking method) for incoming messages. These messages are then asynchronously written to the console. Meanwhile, I read in the user input on the console via System.console().readLine().
The problem is that the text is never written to the console at all. I mean, as the readLine() method is blocking, I would have expected the console at least to show the output that has been written to the console as soon as something is entered in the main thread.. Or am I missing the point here?
The relevant source is
// ...
// handle receiving messages
(new Thread() {
#Override
public void run() {
while (executing) received(new String(subSocket.recv(0)));
}
}).start();
// ...
String input;
try {
while ((input = System.console().readLine()) != null && !input.equals(".")) {
pubSocket.send(input.getBytes(), 0);
Thread.yield();
}
}
catch (Exception ex) { }
finally {executing = false;}
And the received method is
public void received(String s) {
System.console().format("(%s)", s);
System.console().flush();
}
What am I doing wrong? Or is there a better way to do this? I mean, I tried to use a BufferedReader encapsulating the input stream in order to read it linewise and used System.out.format() along with it.. To the same effect - Nothing :(.
Cheers,
fxx
Try something like,
Implement a thread to read from input and store it in synchronized map/vector/list etc..
Another thread is listening on that collection, which will then process the message.
I think this should help in some way... Main thing is, don't run the loop on system input. Give it a try.

Categories

Resources