I want to verify something, because in my head it makes sense, but in Java, it doesn't work.
I am trying to run another Jar file through my application. A Minecraft server, to be precise. I have all the basics down (using ProcessBuilder
, executing with arguments, waiting for an exit code, etc.), but there is one thing that I cannot figure out. Sending commands to the application. Here part of my CommandLineSender
class:
public class CommandLineSender extends Thread {
private BufferedWriter output;
private InputStream source; // Set to System.in when creating the object
private boolean stopRequested;
public CommandLineSender(Process sendTo, InputStream source) {
this.output = new BufferedWriter(new OutputStreamWriter(sendTo.getOutputStream()));
this.source = source;
System.out.println("Source InputStream initiated: " + source.toString());
this.stopRequested = false;
}
@Override
public void run() {
System.out.println("Run called.");
Scanner cmdScanner = new Scanner(source);
while (cmdScanner.hasNextLine() && !stopRequested) {
System.out.println("Has next line");
String msg = cmdScanner.nextLine();
write(msg);
System.out.println("Wrote: " + msg);
}
// Close the scanner and BufferedWriter
System.out.println("Closed.");
}
// Other various methods
protected void write(String msg) {
try {
output.write(msg);
} catch (IOException e) {
System.err.println("Unable to write message because of an unhandled IOException: " + e.getMessage());
}
}
The output I get is this:
(Default Minecraft server output)
help // My command
Has next line
Wrote: help
This may not matter, but I am executing my server with these arguments:
java -Xmx1024M -Xms1024M -jar (path to server jar) nogui
Thank you for your time.
Here is an example of a Java program that manipulates a C program through its process (you can manipulate a Java program too). I wrote this some years ago. There is the receiver program in C or Java and the sender in Java. Take a look:
C Receiver
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
int main() {
char message[50] = {0};
while ( true ) {
gets( message );
printf( "string \"%s\" received...\n", message );
// forces the streams to flush
fflush( stdout );
fflush( stderr ); // the java program will not write in the error stream, so this line (for this example) is irrelevant
// if the java program send a "end" command (message here) it will break the while
if ( !strcmp( "end", message ) ) {
break;
}
}
return 0;
}
Java Receiver (equal the C program)
import java.util.*;
public class MessageReceiver {
public static void main( String[] args ) {
Scanner scan = new Scanner( System.in );
while ( true ) {
String message = scan.nextLine();
System.out.printf( "string \"%s\" received...\n", message );
System.out.flush();
System.err.flush();
if ( message.equals( "end" ) ) {
break;
}
}
}
}
Java Sender
import java.io.*;
import java.util.*;
public class Sender {
/**
* @param args the command line arguments
*/
public static void main( String[] args ) {
new Sender().execute();
}
public void execute() {
try {
// executes the command (the C executable)
Process process = Runtime.getRuntime().exec( "MessageReceiver.exe" );
// or, executes the MessageReceiver class
//Process process = Runtime.getRuntime().exec( "java MessageReceiver" );
// create the stream gobblers, one for the input stream and one for the
// error stream. these gobblers will consume these streams.
StreamGobbler sgInput = new StreamGobbler(
process.getInputStream(), "input" );
StreamGobbler sgError = new StreamGobbler(
process.getErrorStream(), "error" );
// creates a thread for each stream gobbler and start them
new Thread( sgInput ).start();
new Thread( sgError ).start();
// creates a PrintWriter using the process output stream
PrintWriter writer = new PrintWriter( process.getOutputStream() );
// preparing to read user input
Scanner scan = new Scanner( System.in );
while ( true ) {
System.out.println( "Send a command: " );
String command = scan.nextLine();
// sends the command to the process
// simulating an user input (note the \n)
writer.write( command );
writer.write( "\n" );
writer.flush();
// if the command is end, finalizes this app too
if ( command.equals( "end" ) ) {
break;
}
}
} catch ( IOException ioe ) {
ioe.printStackTrace();
}
}
/**
* Threads to consume the process streams.
* Based in the implementation presented here:
* http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=1
*
* @author David Buzatto
*/
private class StreamGobbler implements Runnable {
private InputStream is;
private String type;
private FileWriter fw;
public StreamGobbler( InputStream is, String type ) {
this.is = is;
this.type = type;
}
public StreamGobbler( InputStream is, String type, File file )
throws IOException {
this.is = is;
this.type = type;
this.fw = new FileWriter( file );
}
@Override
public void run() {
try {
InputStreamReader isr = new InputStreamReader( is );
BufferedReader br = new BufferedReader( isr );
String line = null;
while ( ( line = br.readLine() ) != null ) {
if ( fw != null ) {
fw.write( line + "\n" );
} else {
System.out.println( type + ">" + line );
}
}
if ( fw != null ) {
fw.close();
}
} catch ( IOException ioe ) {
ioe.printStackTrace();
}
}
}
}
To run the code, compile the C program or the MessageReceiver class. Put the executables in the same folder of your Sender class, compiles it and run. The "end" command will finish the receiver and the sender.
Take a look in this article too: http://www.javaworld.com/jw-12-2000/jw-1229-traps.html