An InputStream that can be inserted into - java

Is it possible to make an InputStream that is identical to a base InputStream, except that when the base stream is blocked, bytes can be inserted into the stream by calling a method? Sketch:
public class HackInputStream extends InputStream {
public HackInputStream (InputStream base) { /* stuff */ }
public int read() throws IOException { /* stuff */ }
public void insertByte(byte b) { /* stuff */ }
}
I will only be inserting bytes when the base stream is definitely blocked, so race conditions shouldn't be an issue. I tried to implement this class using one thread that read bytes greedily from the base stream into a LinkedBlockingQueue. insertByte inserted the byte directly into the queue, and read simply read bytes from the queue, blocking when the queue was empty.
This almost worked... but when I made a Scanner using new Scanner(new HackInputStream(System.in), the nextLine method didn't work. Unfortunately, the reason I wanted this weird class in the first place was to unblock a blocked Scanner!
(Here's the problem I'm trying to solve, in case someone has a better solution:
My program is a "shell" that launches tasks (threads) when given commands. Some of these tasks terminate on their own, and some do not. I want to return immediately to the command prompt when the task terminates, but in case the task never terminates, I want to terminate it by entering a newline.
Currently, the main thread waits for the task to terminate, while a watchdog threads waits for a newline, terminating the task if it receives one. Right now, if the task terminates on its own, I can't enter a command without manually entering a newline. The watchdog thread is uninterruptibly blocked, and it will consume the next line of input no matter what, possibly causing the next command to go unread. I'm trying to change System.in so that I can feed it newlines programmatically.)

Update: I solved my problem in a much simpler way by only calling Scanner.nextLine() if the task was still running.

Related

Reuse an InputStream to a Process in Java

I am using ProcessBuilder to input and receive information from a C++ program, using Java. After starting the process once, I would like to be able to input new strings, and receive their output, without having to restart the entire process. This is the approach I have taken thus far:
public void getData(String sentence) throws InterruptedException, IOException{
InputStream stdout = process.getInputStream();
InputStreamReader isr = new InputStreamReader(stdout);
OutputStream stdin = process.getOutputStream();
OutputStreamWriter osr = new OutputStreamWriter(stdin);
BufferedWriter writer = new BufferedWriter(osr);
BufferedReader reader = new BufferedReader(isr);
writer.write(sentence);
writer.close();
String ch = reader.readLine();
preprocessed="";
while (ch!=null){
preprocessed = preprocessed+"~"+ch;
ch = reader.readLine();
}
reader.close();
}
Each time I want to send an input to the running process, I call this method. However, there is an issue: the first time I send an input, it is fine, and the output is received perfectly. However, the second time I call it, I receive the error
java.io.IOException: Stream closed
which is unexpected, as everything is theoretically recreated when the method is called again. Moreover, removing the line the closes the BufferedWriter results in the code halting at the following line, as if the BufferedReader is waiting for the BufferedWriter to be closed.
One final thing - even when I create a NEW BufferedWriter and instruct the method to use that when called for the second time, I get the same exception, which I do not understand at all.
Is there any way this can be resolved?
Thanks a lot!
Your unexpected IOException happens because when Readers and Writers are closed, they close their underlying streams in turn.
When you call your method the first time, everything appears to work. But you close the writer, which closes the process output stream, which closes stdin from the perspective of the process. Not sure what your C++ binary looks like, but probably it just exits happily when it's done with all its input.
So subsequent calls to your method don't work.
There's a separate but similar issue on the Reader side. You call readLine() until it returns null, meaning the Reader has felt the end of the stream. But this only happens when the process is completely done with its stdout.
You need some way of identifying when you're done processing a unit of work (whatever you mean by "sentence") without waiting for the whole entire stream to end. The stream has no concept of the logical pause between outputs. It's just a continuous stream. Reader and Writer are just a thin veneer to buffer between bytes and characters but basically work the same as streams.
Maybe the outputs could have delimiters. Or you could send the length of each chunk of output before actually sending the output and distinguish outputs that way. Or maybe you know in advance how long each response will be?
You only get one shot through streams. So they will have to outlive this method. You can't be opening and closing streams if you want to avoid restarting your process every time. (There are other ways for processes to communicate, e.g. sockets, but that's probably out of scope.)
On an orthogonal note, appending to a StringBuilder is generally more efficient than a big loop of string concatenations when you're accumulating your output.
You might also have some thread check process.exitValue() or otherwise make sure the process is working as intended.
Don't keep trying to create and close your Streams, because once you close it, it's closed for good. Create them once, then in your getData(...) method use the existing Streams. Only close your Streams or their wrapping classes when you're fully done with them.
Note that you should open and close the Streams in the same method, and thus may need additional methods or classes to help you process the Streams. Consider creating a Runnable class for this and then reading from the Streams in another Thread. Also don't ignore the error stream, as that may be sending key information that you will need to fully understand what's going on here.

how to reopen and interrupt keyboard stream?

I have a very simple question.
Based on Java I/O scheme, whenever a thread is waiting for some data, so it will be blocked? is it true? something like this.
byte[] _buff=new byte[1024];
int _r=_in.read(_buff);//it blocks until some data is available
and the just possible way to give up reading is closing the stream by another thread, is it right? something like this.
void run(){
_in.close();
}
so if I am right with above scenarios, so why this is impossible just interrupt a thread which is reading from System.in by closing the stream. I run a thread that just waits for 5 seconds then wants to interrupt/give up rest of the reading from the stream.
void _read_data(){
System.out.print("enter y to save the workspace ");
new Thread(_cancel_thread).start();
int _r=System.in.read();//blocks
}
///////////
void run(){
try{
Thread.sleep(5000);
System.in.close();//doesn't work.
}catch(Exception _ex){}
}
Questions:
1.How to close the stream?! why the closing stream thread cannot close the stream?!
2.Once the stream got closed, how to open it again?!
For the first question, I think this is because maybe(I don't know, not sure) the stream is kinda locked by lower-level, so while it's locked, another thread is just waiting to acquire the lock and close it.
and for second one, I really don't know is there any class(stream) which works with keyboard stream or not, but why do you really want to close it? just keep the stream somewhere (like in=System.in), then redirect the standard stream to another stream by calling System.setIn(newStream), then whenever you want to give keyboard stream back, reset the stream with the reference.
Closing the default system input stream is not good idea, I suggest you utilize either JConsol or jNativeHook, these guys do not block, instead they listen for events.

Is there a way to know if a user pressed the key ENTER using readline() method? - Java

I want to recognize if a user sent a text, using readline method from BufferedReader. While the user didn't send anything, the Thread keeps sleeping. Is there a way to do this? I'm trying for a long time, but no success yet.. I guess I have to recognize if a ENTER key was pressed.. but I donwt know how to do this.. The interface of my program is the console..
The problem is: I have a client-server program. When a client enters a message, the message prompts on the screen of the another user/client. But, if the user doesn't send a message in 10 seconds, I want a message to appear on the screen.. So I have a Thread.sleep(1000). The problem is I don't know when to wakeuo the Thread.
while((mensagem == null) || (!mensagem.trim().equals(""))) {
Thread.sleep(10000);
sendToAll(output, "[Your turn] ", "");
mensagem = input.readLine();
}
The last line isn't correct also, because I don't want to force the user to type, and this way I'm forcing, 'cause I stop on input.readLine().
SOLUTION:
I resolved the problem using the method setSoTimeout(10000).. This is the code:
public Server(Socket socket) throws SocketException{
this.connection = socket;
this.connection.setSoTimeout(10000);
}
public void run(){
[...]
while((msg != null) && !(msg.trim().equals(""))){
try{
msg = input.readLine();
sendToAll(output, ": ", msg);
} catch (SocketTimeoutException e) {
sendToAll(output, "Time out ", "");
}
}
Thank you all for the ideas!! :)
You read entire lines like this:
String in;
while ((in = br.readLine()) != null) {
// If this is triggered, in contains a whole line and if the input came from console that means enter was pressed
}
Edit: responding to your edit:
input.readLine() is a blocking method. It will continue to attempt read a full line until a line is received, exception thrown, or EOF is reached. Your issue is that you want a 10 seconds timeout. Correct me if I'm wrong.
The way to do this is to create a timer or a thread that isn't blocked by the call to interrupt your .readLine() call. You should have all I/O in its own thread already, so from another thread (main thread, or using a Timer) you need to create a timed event that will interrupt the blocked thread. Example using Timer, add this right before the loop:
java.util.Timer t = new java.util.Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
IOHandlerClass.this.interrupt();
}
}, 10000);
Substitute IOHandlerClass with the name of the class that this code is put inside (you didn't post your code, so I don't know the name).
Now, this will cause an InterruptException to be thrown after 10 seconds unless you stop the timer. So, surround your code with a try-catch to catch that exception and if it's thrown you display the error message. Remember to cancel the timer if you do infact get valid response within the 10 seconds timeout.
You need to understand what is going on here, on both the Java side and the console side.
On the Java side, the readLine() call is simply attempting to read characters until it sees either a valid "end of line" sequence, the end of the input stream. It is a blocking call, and there is no way to specify a timeout in the API that you are using.
On the Console side, console is watching for keyboard events and accumulating them in a line buffer:
When it sees a key event for a data character (a digit, letter, whatever), it adds the character to the buffer.
When it sees a meta character (e.g. a "delete") it performs the appropriate edit on the line buffer. For example, it might delete a character from the line buffer at the 'cursor' position.
When it sees an ENTER key, it adds an end-of-line sequence to the line buffer, and sends the line.
Details will depend on the console program and how the user has configured it. However, the fact remains that until the user types ENTER, nothing will be sent to the "pipe" that connects the console to the Java application. In short, the Java application won't see anything.
What this means is that the Java application can't tell if the user is typing or not.
So what can the Java application do?
You could use a Timer to send an interrupt to the blocked Java thread (the one doing the readLine() call) after a few seconds / minutes. This will cause the readLine() call to unblock and throw an IOException. However, there are problem with this approach:
There is a potential race condition where the timer fires after the readLine() call finishes, and the interrupt goes to application itself. This could cause problems, depending on what the application does with interrupts. You should be able to avoid this using a properly synchronized flag that the primary thread sets when the readLine call returns.
It is not entirely clear, but there are signs that if you get an interrupt on a pipe, the underlying channel is automatically closed. That would mean that you couldn't ask the user for any more input.
The second approach might be to replace your BufferedReader / readLine() code with something that uses NIO channel selectors. Among other things, a Selector allows you to wait with a timeout for a channel to have readable data. You'd then need to implement buffering and readline on top of that.
If you wanted to know if the user had typed at the console, you'd need to put the console into non-line-editing mode. This cannot be done in pure Java, but there are 3rd-party libraries that do this kind of thing.

How to asynchronously read stdin?

Is there an elegant way to fire an event when characters are available from System.in? I'd like to avoid polling InputStream.available().
You would have to create a separate thread that blocks in read until something is available.
If you don't want to actually eat up the input, you would have to wrap it with an internal buffer, read into the buffer, shout, and when asked for the input, give back data from the buffer.
You could solve it like this:
InputStream stdin = System.in;
// Create a wrapper (with it's own dedicated read-thread)
MyListenableInputStream listenableInputStream =
new MyListenableInputStream(stdin);
// Update System.in with something more useful.
System.setIn(listenableInputStream);
Sure...start a thread that blocks on the input and then calls your event method when it gets something.
Very generally speaking:
If you already have an event reactor running, create a thread and have it block on read(). When there's data available, have that thread enqueue an event for the reactor to process. If you can't do this, most event reactors provide an InvokeLater, or CallLater method, for you to run some code in the event processing thread.
After notifying or scheduling a function call, go back to blocking on read().
If you want something elegant you could easily implement an ObservableInputStream which accepts a Listener that gets warned about availability of data but you will have to implement it with an inner thread that periodically checks for data and call the listener in case.
Think about the fact that streams aren't supposed to be used as object that send small packets but a continuous stream of bytes, that's why this approach would work only if the data that is given to the input stream doesn't effectively arrives too often (otherwise it would keep calling the listener ad libitum). In addition you will have to care about consistency, if data arrive when something is already available and the listener is warned then something can take all the bytes (which you should place in a temporary buffer) but if there's more data that just arrived you should decide how to handle (give it together with buffer, place in buffer and call listener again, etc)
new Thread(){
public void run() {
while(System.in.get()){
}
}.start();

java inputStream Freezing

Im trying to run a thread that goes to a socket, grabs the input stream, and reads it. Im creating hundreds of these threads and have set the timeout for reading and yet the thread still stays at the read() line.
public void readPack() {
socket.setSoTimeout(4*1000);
if (socket.isConnected()) {
buffer parse = new buffer();
parse.addByte((byte) skt.getInputStream().read());
parseIncoming(parse);
}
} catch (Exception e) {}
}
Strange code. You create a buffer, read one byte into it, then parse that byte, then repeat the whole process. One byte surely doesn't take much parsing. You are never checking for -1 from the read so this loop will spin endlessly when the peer disconnects. And finally Socket.isConnected() isn't a useful test, and specifically it doesn't detect the peer disconnecting.
Call skt.available(), and then call read that many times, or use skt.read(byte[]). Other wise skt.read() will block. The timeout your setting is to connect to the socket, and not a read timeout.

Categories

Resources