Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package ws.hafnium.rcon.wrapper;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.PrintStream;
- import java.util.HashSet;
- /**
- * Wraps a console application and allows for the programmatic sending and
- * receiving of text to and from it, as well as other basic functions.
- *
- * @author Chris Bode
- */
- public class ConsoleApplication {
- private final ProcessBuilder builder;
- private Process process;
- private boolean stopped = false;
- private HashSet<ConsoleListener> listeners;
- private PrintStream commandStream;
- private InputHandler handler;
- private Thread shutdownTask;
- /**
- * Creates a new application wrapper for the specified working directory and
- * the specified arguments. The arguments must be in separate strings,
- * starting with the name of the application to run. See
- * {@link ProcessBuilder#ProcessBuilder(String...)} for more details.
- *
- * @param dir
- * @param args
- */
- public ConsoleApplication(File dir, String... args) {
- this(new ProcessBuilder(args));
- this.builder.directory(dir);
- }
- /**
- * Creates a new application wrapper for the process that will be created by
- * the supplied ProcessBuilder. This implementation will force redirection
- * of the error stream regardless of what the supplied ProcessBuilder is
- * configured to do.
- *
- * @param builder
- */
- public ConsoleApplication(final ProcessBuilder builder) {
- this.builder = builder;
- this.builder.redirectErrorStream(true);
- this.listeners = new HashSet<ConsoleListener>();
- }
- /**
- * Start the process.
- *
- * @throws IOException
- */
- public void start() throws IOException {
- if (this.hasStarted())
- throw new IllegalStateException(
- "This process has already been started once.");
- this.process = this.builder.start();
- for (ConsoleListener l : this.listeners) {
- l.onStart(new ConsoleEvent(this));
- }
- this.handler = new InputHandler(this.process.getInputStream());
- new Thread(this.handler).start();
- this.commandStream = new PrintStream(this.process.getOutputStream());
- Runtime.getRuntime().addShutdownHook(
- this.shutdownTask = new Thread(new ShutdownListener()));
- }
- /**
- * Stops the process.
- */
- public void stop() {
- this.process.destroy();
- this.onProcessQuit();
- Runtime.getRuntime().removeShutdownHook(this.shutdownTask);
- }
- public void nuke() {
- this.process.destroy();
- }
- /**
- * Sends a text command to the process.
- *
- * @param command
- */
- public void sendCommand(String command) {
- this.commandStream.println(command);
- this.commandStream.flush();
- this.onConsoleLine("> " + command);
- }
- /**
- * Called when the process closes its output stream.
- */
- private void onStreamQuit() {
- if (this.isRunning())
- this.stop();
- }
- /**
- * Called whenever the process is stopped by any means.
- */
- private void onProcessQuit() {
- this.stopped = true;
- this.commandStream.close();
- if (this.handler != null)
- this.handler.stop();
- for (ConsoleListener l : this.listeners) {
- l.onStop(new ConsoleEvent(this));
- }
- }
- /**
- * Called when the console sends a line.
- *
- * @param line
- */
- private void onConsoleLine(String line) {
- ConsoleLineEvent event = new ConsoleLineEvent(this, line);
- for (ConsoleListener l : this.listeners) {
- l.onLineReceived(event);
- }
- }
- /**
- * Checks if the process is currently running.
- *
- * @return
- */
- public boolean isRunning() {
- return this.hasStarted() && !this.hasStopped();
- }
- /**
- * Checks if the process was running but has now stopped.
- *
- * @return
- */
- public boolean hasStopped() {
- return this.stopped;
- }
- /**
- * Checks if the process has been started. This will return true even if the
- * process was subsequently stopped. To check if the process is currently
- * running, use {@link #isRunning()}.
- *
- * @return
- */
- public boolean hasStarted() {
- return this.process != null;
- }
- /**
- * Add a ConsoleListener to this wrapper.
- *
- * @param l
- */
- public void addListener(ConsoleListener l) {
- this.listeners.add(l);
- }
- /**
- * Remove a ConsoleListener from this wrapper.
- *
- * @param l
- */
- public void removeListener(ConsoleListener l) {
- this.listeners.remove(l);
- }
- /**
- * Handles the wrapped process's input stream, calling appropriate methods
- * on receipt of lines or the closure of the stream.
- *
- * @author Chris
- *
- */
- private class InputHandler implements Runnable {
- private InputStream stream;
- private volatile boolean cont = true;
- public InputHandler(InputStream stream) {
- this.stream = stream;
- }
- public void stop() {
- this.cont = false;
- }
- @Override
- public void run() {
- BufferedReader reader = new BufferedReader(new InputStreamReader(
- this.stream));
- String line;
- try {
- while (this.cont && ((line = reader.readLine()) != null)) {
- ConsoleApplication.this.onConsoleLine(line);
- }
- } catch (IOException e) {
- // Hmm, odd. Oh well!
- } finally {
- try {
- reader.close();
- } catch (IOException e) {
- // Well, we tried!
- }
- }
- if (this.cont)
- ConsoleApplication.this.onStreamQuit();
- this.cont = false;
- }
- }
- private class ShutdownListener implements Runnable {
- @Override
- public void run() {
- ConsoleApplication.this.nuke();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement