How to ignore input from `BufferedReader` when using `Thread.sleep()`? - java

I'm trying to make a simple counter that starts between user inputs (3..., 2..., 1..., Go!).
try (var reader = new BufferedReader(new InputStreamReader(System.in))) {
...
try {
for (int i = 0; i < 3; i++) {
System.out.println(i + "...");
Thread.sleep(500);
}
System.out.println("Go!");
} catch (Exception e) {
e.printStackTrace();
}
...
}
The problem is Im still able to press keys between delays, which then gets printed. Is there a way to block BufferedReader while for-each works?

You cannot prevent the user pressing keys while he should be waiting.
For the same reason you cannot prevent your application to receive these characters through System.in up until the BufferedReader. Blocking that is the wrong approach.
What you can do however is ignore those keypresses. But you must prevent that they remain in the input buffer and get evaluated after your loop.
Since you are reading from stdin however, it is not your program to print the characters. I guess it is the terminal emulator that you use when running your console based application. And therefore I am unsure how you can prevent the echo to the console. What undermines my assumption is
https://forums.codeguru.com/showthread.php?466009-Reading-from-stdin-(without-echo)
What proves I am wrong (and what you should try out therefore) is
How to use Scanner to read silently from STDIN in Java?
or more general
https://www.geeksforgeeks.org/ways-to-read-input-from-console-in-java/
Both recommend to suppress the echo by reading from System.console().

Your problem is not related to the BufferedReader, and the solution is probably more complex than what you imagined.
When you run your Java process, it is usually connected to a terminal. This terminal (or emulator) handles your keyboard and usually provides your input line by line to the attached process. The terminal also echos characters as you type. Meaning the Java process does not print the characters you type, you therefor can't prevent them being printed from within the your process.
Terminals and terminal control is highly platform specific. On Linux system you can control the terminal using termios. The flags you want to be disable is ECHO for echoing your keystrokes and ICANON to disable canonical mode so you'd receive input as soon as it is available. You'd have to perform this before your loop. After or in your loop you'd have to consume any input and discard it, enable ECHO and ICANON again. Be aware though that the BufferedReader might have something buffered already and is performing blocking I/O.
termios however is not directly accessible from Java, calls would have to be wrapped through JNI f.i. A quick google search came up with a library called purejavacomm

Related

How to check whether a PrintStream is open without printing to it

I have a GUI program written in Java which outputs data to the command line using System.out.println. The data is intended to be piped into another program. As an example, I'll pipe the program through head:
$ java MyProgram | head -n10
I want my program to exit when the pipe is broken: in this case, this should happen after MyProgram has printed out ten lines of text.
There is a similar question on this site, and the solution given there works fairly well; for example, I could have the following running in its own thread:
while(!System.out.checkError()) {
// sleep 100ms
}
System.exit(0);
The problem is that PrintStream.checkError() seems to return true only after you have tried to print to the stream and failed. For that reason, my program does not in fact exit until it has printed out eleven lines of text: the pipe is broken after the first ten, but System.out continues to return true until I try to pipe through the eleventh line.
Printing out extra 'junk' lines in order to trigger an error on the PrintStream is out of the question, since the program on the right hand side of the pipe may be very sensitive to the data it receives.
Calling System.out.flush() inside the loop has no effect on PrintStream.checkError(), even though the source code for PrintStream indicates that it ought to call the private ensureOpen method in that class.
How can I reliably test whether System.out is open without printing anything to it?
'Real world' example: suppose that I have some program consumer that takes in command line input and does something with it. Certain pieces of input will call consumer to fail silently. Since the input to consumer is sometimes long and abstruse, I write a GUI program InputProvider in Java where I can click buttons and have the corresponding commands printed out to stdout. If I pipe the output of InputProvider into consumer, then I am able to control consumer graphically.
Unfortunately, there seems to be no way for InputProvider to notify the user when consumer has shut down, except by attempting to write to consumer and getting an exception of some kind.
I don't think you can fix this in Java. There's nothing wrong with System.out until you write to it and it fails. Another process (head) ended but the Java process can't know about that.
So I think that you have two options.
don't use pipe to head but limit the output in your Java code - then you'll know when to stop
accept that the last line will fail and handle the exception appropriately
Try to set a new stream for the system that way you'll be able to check if that stream is closed or not: OutputStream output = new FileOutputStream("c:\\data\\system.out.txt"); and PrintStream printOut = new PrintStream(output);. Then set it here: System.setOut(printOut); and inside the if you can check if(printOut.checkError())

Why is not possible to reopen a closed (standard) stream?

System.in is the "standard" input stream which supplies user input data. Once closed, this stream can not be re-opened. One such example is in the case of using a scanner to read the user input as follows:
public class Test {
public static void main(String[] args) {
boolean finished;
do {
Scanner inputScanner = new Scanner(System.in);
finished = inputScanner.hasNext("exit");
boolean validNumber = inputScanner.hasNextDouble();
if (validNumber) {
double number = inputScanner.nextDouble();
System.out.print(number);
} else if (!finished) {
System.out.println("Please try again.");
}
inputScanner.close();
} while (!finished);
}
}
In this example, an instance of type Scanner is created and used to read a series of numbers from the user (please ignore other details with this code which go beyond the scope of this example, I know the scanner should be created and closed outside the loop). After a number is retrieved from user input, the instance of this Scanner (i.e., the input stream) is closed. However, when another number is requested from user, and new instance is created, the input stream cannot be opened again. In case of this example, it creates a infinite loop.
The question is: why is not possible to reopen a closed stream?
why is not possible to reopen a closed stream in Java?
That's simply the nature of the underlying operating system constructs that Java streams represent. A stream is essentially a data conduit. Once you close it, it no longer exists. You may be able to create a new one between the same endpoints, but that yields a fundamentally different stream. We could go into implementation considerations such as buffering and stream positioning, but those are really side issues.
You also asked specifically about the standard streams. These are some of the cases that you cannot recreate. The operating system provides each process with its set of standard streams. Once they are closed, there is no way to obtain equivalents. You can put different streams in their place, but you cannot connect them to the original endpoints.
When you close the standard input stream:
If your input was being provided by a pipe, the other end of the pipe is notified. It will close its end and stop sending data. There is no way to tell it you made a mistake and it should start sending again;
If your input was being provided by a file, the OS drops its reference to the file and completely forgets that you were using it. There is just no way provided for you to reopen standard input and continue reading;
If your input was being provided by the console, it works with a pipe. The console is notified, will close its end of the pipe and stop sending you data.
So there's no way to reopen standard input.
BUT... there is also no reason to close standard input, so just don't do that!
A good pattern to follow is:
The code or class that opens a file is responsible for closing it.
If you pass an InputStream to another method that reads from it, that method should not close it. Leave that to the code that opened it. It's like the streams owner.
Similarly, if you pass an OutputStream to another method that writes to it, that method should not close it. Leave that to the code that owns it. BUT if you wrap the stream in other classes that may buffer some data do call .flush() on them to make sure everything comes out!
If you're writing your own wrapper classes around InputStream and OutputStream, don't close the delegate stream in your finalizer. If a stream needs to be cleaned up during GC, it should handle that itself.
In your example code, just don't close that Scanner. You didn't open standard input, so you shouldn't need to close it.
Because Streams are unbounded. You peek values from streams as you need. Then when done simply close it. Streams does not hold it's all data in memory. Streams are designed to process relatively big amount of data which can't be held in memory. So you can't reopen an stream simply because you already have made a loop over it and exhausted all the data. As stream does not hold those data in memory. They are simply lost and that's why you can't reopen it. The better is you create a new stream than reopen an existing one.
Java standard library has chosen a "standardized" approach to InputStream. Even if you may legitimately perceive some streams, such as data incoming from the input console, as logically re-openable, the InputStream represents a generic approach, as it is intended to cover all the possible InputStreams, which many of them are by their nature not re-openable. As described perfectly in #JohnBollinger's answer.

Windows console breaks when printing while asking for input in Java

I'm experimenting with networking by writing a small chat-room program in Java. Because it's a chat-room, the console is constantly asking for input from the user. My problem is that, after printing a message from another person in the server whilst still asking for input, the console stops showing what I type. Input is still collected, however, so the user can still input messages. There's just no visual feedback. I've tried three different methods of input, BufferedReader (which I'm still currently using), a Scanner, and the system console. They all have the same problem, which leads me to believe it's the windows console. My question is, is it possible to avoid this or is it simply a flaw with the Windows console? Here is my code, with input being the BufferedReader:
// This runs until the console is closed
while(true)
{
// If the user has input something, send it to the server
if(input.ready())
{
String message = input.readLine();
if(!message.equals(""))
{
client.sendString(message);
}
}
// If the server has a message for the client, print it
if(client.input.available() > 0)
{
System.out.println(client.getString());
}
}

Get notification when external application is fully running - Java

I am writing a program in java which can start up applications such as, for example, firefox.
Edit: This program is for linux, specifically ubuntu.
It's easy to start the program:
Runtime.getRuntime().exec("/usr/bin/firefox");
However, I want to retrieve details from the window once it is fully opened or running.
At the moment I'm just calling:
Thread.sleep(delay);
To make sure the window is ready, but this is a poor solution. Different windows requiring different delays is a problem.
Messy.
So my question is, is there any way that I can be notified when firefox (or any other external application for that matter) is fully setup? I don't think I could use Process.waitFor() because the Process won't be finished until firefox is closed.
Thanks in advance!
Update: Process.waitFor() doesn't work. I have tried it and it only returns when firefox is closed, not when it is fully setup. Just for anyone trying it themselves, if another firefox window is already open it will work (which fooled me at first) but if there is no existing window it won't!
You can use Process#waitFor to wait till the command gets executed and then check the exitValue like this:
Process p = Runtime.getRuntime().exec("/usr/bin/firefox");
p.waitFor();
if(p.exitValue()==0) {
//success
} else {
// fail read error stream or out stream for possible causes
}
Ok I have been doing some more thinking and I have a reasonably satisfactory answer.
Instead of waiting until the window is ready, continually search for it with xdotool:
while(line == null){
writer.write("xdotool search --onlyvisible --name " + name + "\n");
writer.flush();
if(reader.ready())
line = reader.readLine();
Thread.sleep(1000);
}
xdotool will only print a string if it finds a window called name.
So if the reader is ready() then you know the window is open.
The Thread.sleep() is necessary because if it is not present xdotool will spit out a bad window error and the reader will read that.
However, it seems to almost be faster to use a standard delay like I spoke about above but this solution will work even for windows which take longer to load, rather than trying to guess a delay.

Printing output of another program to a java text area

I am creating a GUI using Java. This GUI launches a program from the command line using the ProcessBuilder class.
A little information on the process being launched: from the command line, it creates another window and prints information to said window.
In my GUI window, I have a text area to where I would like to redirect said output. I originally intended to use a SwingWorker object to constantly check for more output and not hold up the GUI. To test and make sure I had the original syntax down (without even bringing the GUI into things) I thought I would print the output from the secondary process' window to System.out. However, something seems to be wrong as I can see the output in the secondary process' window, but not the terminal from which I am working.
Excerpt of code is as follows:
Process p = pb.start();
Scanner s = new Scanner(p.getInputStream());
SwingWorker pipe = new SwingWorker<String, Void> (){
public String doInBackground(){
while(run){
if(s.hasNextLine()){
System.out.println("S has next!");
System.out.println(s.nextLine());
}
}
return null;
}
};
pipe.execute();
The boolean run is defined elsewhere in the program and is set to false when the process p exits or is force quit (additional question: is that a really bad idea? I feel like it might be...).
Does anyone have an idea as to why I am never getting any output when I see it being printed to the other window? Initially my reaction was to use p.getOutputStream() but Scanner does not take an outputStream as a paramter.
Thank you for your time.
You should also scan p.getErrorStream() - some programs write to STDERR which is indistinguishable from STDOUT when run from the command line. It is generally good practice to consume both streams, as if either one is not consumed it can cause the external process to hang.
If the external process is writing its output to its own window, it is almost certain that the output is NOT being written to STDOUT, which is what you are reading with your code. If it did so, then the external program's output would be appearing both in its window and in the command line session from which it was launched (if one existed). Without access to the source of the external program it's unlikely you will be able to intercept its output unless the authors made provisions for that functionality (i.e. a command-line switch that redirects output to STDOUT instead of the window).
As to p.getOutputStream(), that returns a stream which is "output" from YOUR point of view -- i.e. you write to it to send data to the process' STDIN. Your use of p.getInputStream() would be correct for the case where the external program writes to its STDOUT.

Categories