Forwarding all input to Java Process - java

I'm trying to forward the input to the process. It's a minecraft server so I need to send commands to it. I try in this way but it doesn't send anything. (I've also checked the log file)
public static void main(String[] args) throws IOException {
File file = new File("spigot.jar");
if(file.exists()) {
ProcessBuilder builder = new ProcessBuilder("java", "-jar", "spigot.jar");
Process p = builder.start();
new Thread(() -> {
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String s = "";
try {
while((s = br.readLine()) != null) {
System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
new Thread(()-> {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String cmd = "";
try {
while((cmd = input.readLine()) != null) {
bw.write(cmd);
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
while(true) {
if(!p.isAlive()) {
System.out.println("Server closed.");
System.exit(0);
}
}
}).start();
} else {
System.out.println("spigot.jar not found.");
System.exit(0);
}
}
EDIT:
I rewrote the code using threads but i'm getting the same problem

Solved.
I need to add "bw.newline()" to send ENTER, and make the server execute my command

Related

Running External Program in Eclipse

I am able to print the output of an external program in Eclipse via the code below (found online, not mine). I would like to be able to pass a command to the program and THEN print the output of the program but I don't know how to pass commands to the program. Any suggestions would be appreciated, thanks!
Code:
String line;
Process p = Runtime.getRuntime().exec("Z:/LPCXpresso/test10/Debug/arm-none-eabi-readelf.exe");
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = bri.readLine()) != null) {
System.out.println(line);
}
bri.close();
while ((line = bre.readLine()) != null) {
System.out.println(line);
}
bre.close();
p.waitFor();
First I would recommend using ProcessBuilder instead of Runtime.getRuntime().exec(...)
Second to be able to interact with the different streams of the process started you need to do it concurrently, i.e. for each stream create an own Thread where you interact with it.
Here is a sample code wihch illustrates interaction with the command line prompt in windows cmd.exe
public static void main(String... args) throws Exception {
ProcessBuilder pb = new ProcessBuilder("cmd.exe");
Process proc = pb.start();
// handle each of proc's streams in a separate thread
ExecutorService handlerThreadPool = Executors.newFixedThreadPool(3);
handlerThreadPool.submit(new Runnable() {
#Override
public void run() {
// we want to write to the stdin of the process
BufferedWriter stdin = new BufferedWriter(
new OutputStreamWriter(proc.getOutputStream()));
// read from our own stdin so we can write it to proc's stdin
BufferedReader myStdin =
new BufferedReader(new InputStreamReader(System.in));
String line = null;
try {
do {
line = myStdin.readLine();
stdin.write(String.format("%s%n", line));
stdin.flush();
} while(! "exit".equalsIgnoreCase(line));
} catch(IOException e) {
e.printStackTrace();
}
}
});
handlerThreadPool.submit(new Runnable() {
#Override
public void run() {
// we want to read the stdout of the process
BufferedReader stdout = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
String line;
try {
while(null != (line = stdout.readLine())) {
System.out.printf("[stdout] %s%n", line);
}
} catch(IOException e) {
e.printStackTrace();
}
}
});
handlerThreadPool.submit(new Runnable() {
#Override
public void run() {
// we want to read the stderr of the process
BufferedReader stderr = new BufferedReader(
new InputStreamReader(proc.getErrorStream()));
String line;
try {
while(null != (line = stderr.readLine())) {
System.err.printf("[stderr] %s%n", line);
}
} catch(IOException e) {
e.printStackTrace();
}
}
});
// wait for the process to terminate
int exitCode = proc.waitFor();
System.out.printf("Process terminated with exit code %d%n", exitCode);
handlerThreadPool.shutdown();
}
You could make it simple and redirect of the process stderr to stdout using ProcessBuilder#redirectErrorStream(true) before starting the process and then have only 2 threads, one for input and one for output

Why does multithreading my single-threaded simple echo server cause it to stop working?

This single threaded echo server works fine.
public class Server {
public static void main(String[] args) throws IOException {
try (ServerSocket sc = new ServerSocket(1111)) {
while (true) {
try (Socket dataSocket = sc.accept();
BufferedReader is = new BufferedReader(
new InputStreamReader(
dataSocket.getInputStream()));
PrintWriter out = new PrintWriter(
dataSocket.getOutputStream());) {
String line;
while ((line = is.readLine()) != null) {
System.out.println(line);
out.println(line);
out.flush();
if (line.equals("Bye."))
break;
}
}
}
}
}
}
But why does this multi-threaded version not work? It simply passes input and output streams to construct a TestServer1 thread and start it. Nothing special. But somehow when a client connects to this server, A "Stream close" exception is thrown in run() and "error in run" is printed.
public class TestServer1 extends Thread{
BufferedReader in;
PrintWriter out;
public TestServer1(BufferedReader in, PrintWriter out){
this.in=in;
this.out=out;
}
#Override
public void run(){
String line;
try{
while ((line = in.readLine()) != null) {
System.out.println(line);
out.println(line);
out.flush();
if (line.equals("Bye."))
break;
}
} catch (IOException e){
System.out.println("error in run");
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
try (ServerSocket sc = new ServerSocket(1111)) {
while (true) {
try (Socket dataSocket = sc.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(
dataSocket.getInputStream()));
PrintWriter out = new PrintWriter(
dataSocket.getOutputStream());) {
TestServer1 ts1=new TestServer1(in, out);
ts1.start();
}
}
}
}
}
Here is the stacktrace
error in run
java.io.IOException: Stream closed
at java.io.BufferedReader.ensureOpen(BufferedReader.java:115)
at java.io.BufferedReader.readLine(BufferedReader.java:310)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at server.TestServer1.run(TestServer1.java:22)
Java 7: Try with resources
With Java 7, you can create one or more “resources” in the try
statement. A “resources” is something that implements the
java.lang.AutoCloseable interface. This resource would be
automatically closed and the end of the try block.
See more at: http://www.vineetmanohar.com/2011/03/java-7-try-with-auto-closable-resources/#sthash.cnvRzGIZ.dpuf
From javadocs:
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
In this example, the resource declared in the try-with-resources statement is a BufferedReader. The declaration statement appears within parentheses immediately after the try keyword. The class BufferedReader, in Java SE 7 and later, implements the interface java.lang.AutoCloseable. Because the BufferedReader instance is declared in a try-with-resource statement, it will be closed regardless of whether the try statement completes normally or abruptly (as a result of the method BufferedReader).
Link : http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
So probably this can be reason , your streams are closed automatically when it goes out of scope.
the try () is the reason. the stream will be closed after the try (.....) block.
Please test this code:
while (true) {
try {
Socket dataSocket = sc.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(
dataSocket.getInputStream()));
PrintWriter out = new PrintWriter(
dataSocket.getOutputStream());
TestServer1 ts1 = new TestServer1 (in, out);
ts1.start();
} catch (Exception e) {
e.printStackTrace();
}
}
P.S: You need to close the stream in the thread run() method.
Try this version out below - its untested. But as I said in my comment, I believe you are closing the output stream prematurely in your TryWithResources
public class TestServer1 extends Thread{
Socket connection;
public TestServer1(Socket connection){
this.connection = connection;
}
#Override
public void run(){
try (BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
PrintWriter out = new PrintWriter(connection.getOutputStream());) {
String line;
try {
while ((line = in.readLine()) != null) {
System.out.println(line);
out.println(line);
out.flush();
if (line.equals("Bye."))
break;
} catch (IOException e){
System.out.print("error in run");
}
}
}
public static void main(String[] args) throws IOException {
try (ServerSocket sc = new ServerSocket(1111)) {
while (true) {
try (Socket dataSocket = sc.accept()) {
TestServer1 ts1=new TestServer1(dataSocket);
ts1.start();
}
}
}
}
}
Based on the answers from #Amir, #LFF and #Abhijeet, I put together the following version, and it works. The main take aways is: "Socket dataSocket = sc.accept()" should not be put into "try()" as a resource; otherwise, the main thread will close it. It should be closed by the child thread in "run()".
Thank you all for your help.
public class ThreadedServer extends Thread {
private Socket dataSocket;
public ThreadedServer(Socket dataSocket) throws IOException {
this.dataSocket = dataSocket;
}
#Override
public void run() {
String line;
try (BufferedReader in = new BufferedReader(new InputStreamReader(
dataSocket.getInputStream()));
PrintWriter out = new PrintWriter(dataSocket.getOutputStream());) {
while ((line = in.readLine()) != null) {
System.out.println(line);
out.println(line);
out.flush();
if (line.equals("Bye."))
break;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
dataSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
try (ServerSocket sc = new ServerSocket(1111)) {
while (true) {
try {
Socket dataSocket = sc.accept();
ThreadedServer ts = new ThreadedServer(dataSocket);
ts.start();
} finally {
}
}
}
}

Process.getOutputStream() doesn't work?

So I'm starting a Bukkit (Minecraft) server from a GUI.
ProcessBuilder builder = new ProcessBuilder();
builder.redirectErrorStream(true);
builder.command("java", "-jar", file.getAbsolutePath());
try {
p = builder.start();
input = new BufferedReader(new InputStreamReader(p.getInputStream()));
output = new DataOutputStream(p.getOutputStream());
} catch (IOException e) {
Logger.logError(e);
return;
}
There are no errors, and the server itself starts correctly. The input stream works correctly too, as I get all the input as I should. Now, I have this method to send a command to the server.
public void send(String message) {
try {
output.writeUTF(message + "\n");
output.flush();
} catch (IOException e) {
Logger.logError(e);
}
}
For some reason though, it doesn't work. I'm not sure if I missed a step, or am looking over something, etc. Any help would be greatly appreciated!
I suspect the DataOutputStream is writing data in a non-conventional way towards the OutputStream, try using a PrintWriter object instead.
Consider this:
try {
p = builder.start();
input = new BufferedReader(new InputStreamReader(p.getInputStream()));
output = new PrintWriter(p.getOutputStream());
} catch (IOException e) {
Logger.logError(e);
return;
}
The Send method:
public void send(String message) {
output.println(message);
output.flush();
}
P.S You no longer need the try-catch around the output.println() as PrintWriter's print and println methods don't throw IOException.
From bukkit's plugin perspective (read my comment if you have no clue what this is):
final JavaPlugin Inst = ... //This plugin's object
try(BufferedReader Reader = new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF-8")))){
while((Line = Reader.readLine()) != null){
final String L = Line;
Bukkit.getScheduler().runTask(Inst, new Runnable(){
#Override
public void run() {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), L);
}
});
}
}catch(IOException ex){
//Handle this
}

Runtime.exec never returns when reading system.in

Here is my sample code, I want to handle the command from standard input while running a new sub process. However, the exec method never returns if I read the system.in. The command in the exec() is very simple and has nothing to do with the stdin.
I'm wondering about is there any way to solve this? How can I start a new sub process while start another thread reading stdin?
public static void main(String[] args){
new Thread(new Runnable(){
public void run(){
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String command = null;
try{
while((command = reader.readLine()) != null){
System.out.println("Command Received:" + command);
}
}catch(Exception ex){
ex.printStackTrace();
//failed to listening command
}
}
}).start();
Process process = null;
try {
process = Runtime.getRuntime().exec("java -cp C:/agenttest Test");
System.out.println("never returns");
process.waitFor();
} catch (IOException e) {
throw new RuntimeException( e );
} catch (InterruptedException e) {
throw new RuntimeException( e );
}
}
The Test class is very simple, here is the Test.java
public static void main(String[] args){
System.out.println("Standard out");
System.out.println("Standard out");
System.err.println("Standard err");
System.out.println("Standard out");
try{
Thread.sleep(10000);
}catch(InterruptedException ex){}
}
The problem could be that you're not handling the error stream and input stream and are overrunning the platform's buffers. Try handling that output as per the famous article, When Runtime.exec() won't.
For example:
import java.io.*;
public class TestMain {
private static final String JAVA_CMD = "java";
private static final String CP = "-cp";
// *** your CLASS_PATH and PROG Strings will of course be different ***
private static final String CLASS_PATH = "C:/Users/hovercraft/Documents/workspace/Yr 2012A/bin";
private static final String PROG = "yr12.m07.b.Test2";
private static final String[] CMD_ARRAY = { JAVA_CMD, CP, CLASS_PATH, PROG };
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
String command = null;
try {
while ((command = reader.readLine()) != null) {
System.out.println("Command Received:" + command);
}
} catch (Exception ex) {
ex.printStackTrace();
// failed to listening command
}
}
}).start();
Process process = null;
try {
ProcessBuilder processBuilder = new ProcessBuilder(CMD_ARRAY);
process = processBuilder.start();
InputStream inputStream = process.getInputStream();
setUpStreamGobbler(inputStream, System.out);
InputStream errorStream = process.getErrorStream();
setUpStreamGobbler(errorStream, System.err);
System.out.println("never returns");
process.waitFor();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void setUpStreamGobbler(final InputStream is, final PrintStream ps) {
final InputStreamReader streamReader = new InputStreamReader(is);
new Thread(new Runnable() {
public void run() {
BufferedReader br = new BufferedReader(streamReader);
String line = null;
try {
while ((line = br.readLine()) != null) {
ps.println("process stream: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
You should keep reading the input stream, otherwise it will get blocked. It has nothing to do with JVM but the underyling operating system.

A Java program that runs an external "java myprog < input.txt > output.txt"

I want to write a Java program that runs an external "java myprog < input.txt > output.txt" command. The eventual goal is to run this command on two different programs and compare their output similarity from their respective output files.
I think I've read just about every relevant article about using ProcessBuilder to run an external program, and the few entries about handling user input in that external program, but I still can't get things working. From what I have read, I think the best approach is to not run the exact command above, but instead read the input.txt file and feed it byte-by-byte into the Process object, then collect the output and write it to output.txt ... I am 100% open to other options.
I put together the code below based on my readings. It seems to correctly feed input from input.txt into myprog, but when I try to print the external program's output to the console to verify, the program hangs at the point where (surprise) user input is expected in myprog.
I get the same issues with and without the redirectErrorStream(true) line.
I really want this to be in Java since I plan to share the source code with the people whose program outputs I will compare, and they are primarily only familiar with Java.
import java.io.*;
import java.util.*;
public class test7 {
public static void main(String args[]) {
try {
// WANT: "java myprog < input.txt > output.txt"
String inputFile = "input.txt";
String outputFile = "output.txt";
ProcessBuilder pb = new ProcessBuilder("java","myprog");
pb.redirectErrorStream(true); // merge stdout, stderr of process
Process p = pb.start();
// write input to the running program
OutputStream pos = p.getOutputStream();
InputStream fis = new FileInputStream(inputFile);
int read = 0;
while ( (read = fis.read()) != -1) {
pos.write(read);
}
fis.close();
// get output of running program
InputStreamReader isr = new InputStreamReader(p.getInputStream());
BufferedReader br = new BufferedReader(isr);
// HANGS HERE WHEN USER INPUT REQUIRED
String lineRead;
while ((lineRead = br.readLine()) != null) {
System.out.println(lineRead);
}
}
catch (IOException e) {
e.printStackTrace();
}
} // end main
}
Here is the content of myprog.java:
import java.io.*;
public class myprog {
public static void main(String args[]) throws IOException {
System.out.println("Hello world!");
System.out.println("Enter something:");
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
// the readLine() command causes ProcessBuilder to hang
cin.readLine();
}
}
And the input.txt file is just
p
The output.txt file should be
Hello world!
Enter something:
I wonder if your problem is partly to do with not using separate threads for reading input and writing output. For instance:
public static void main(String args[]) {
try {
// WANT: "java myprog < input.txt > output.txt"
String inputFile = "input.txt";
String outputFile = "output.txt";
// my ProcessBuilder Strings will be different from yours
ProcessBuilder pb = new ProcessBuilder("java", "-cp", ".;bin;",
"yr12.m04.a.MyProg");
pb.redirectErrorStream(true);
Process p = pb.start();
final OutputStream pos = p.getOutputStream();
final PrintWriter pw = new PrintWriter(pos);
final InputStream fis = new FileInputStream(inputFile);
final BufferedReader fileBr = new BufferedReader(new InputStreamReader(fis));
InputStreamReader isr = new InputStreamReader(p.getInputStream());
final BufferedReader br = new BufferedReader(isr);
new Thread(new Runnable() {
public void run() {
String lineRead;
try {
while ((lineRead = br.readLine()) != null) {
System.out.println(lineRead);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
String lineRead;
while ((lineRead = fileBr.readLine()) != null) {
pw.println(lineRead);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (pw != null) {
pw.close();
}
if (fileBr != null) {
try {
fileBr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
} // end main
Have you thought about using Runtime.getRuntime().exec() instead?
Process proc = Runtime.getRuntime().exec("java myprog "+inputFile+" "+outputFile);
You could include the jar of the 'myprog' and call the main() method yourself. Even more so if myprog is in your domain you could get rid of the main method altogether.

Categories