Advertisement
Guest User

Untitled

a guest
Oct 17th, 2012
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5.46 KB | None | 0 0
  1. package ws.hafnium.rcon.wrapper;
  2.  
  3. import java.io.BufferedReader;
  4. import java.io.File;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.io.InputStreamReader;
  8. import java.io.PrintStream;
  9. import java.util.HashSet;
  10.  
  11. /**
  12.  * Wraps a console application and allows for the programmatic sending and
  13.  * receiving of text to and from it, as well as other basic functions.
  14.  *
  15.  * @author Chris Bode
  16.  */
  17. public class ConsoleApplication {
  18.     private final ProcessBuilder builder;
  19.  
  20.     private Process process;
  21.     private boolean stopped = false;
  22.  
  23.     private HashSet<ConsoleListener> listeners;
  24.     private PrintStream commandStream;
  25.  
  26.     private InputHandler handler;
  27.  
  28.     private Thread shutdownTask;
  29.  
  30.     /**
  31.      * Creates a new application wrapper for the specified working directory and
  32.      * the specified arguments. The arguments must be in separate strings,
  33.      * starting with the name of the application to run. See
  34.      * {@link ProcessBuilder#ProcessBuilder(String...)} for more details.
  35.      *
  36.      * @param dir
  37.      * @param args
  38.      */
  39.     public ConsoleApplication(File dir, String... args) {
  40.         this(new ProcessBuilder(args));
  41.         this.builder.directory(dir);
  42.     }
  43.  
  44.     /**
  45.      * Creates a new application wrapper for the process that will be created by
  46.      * the supplied ProcessBuilder. This implementation will force redirection
  47.      * of the error stream regardless of what the supplied ProcessBuilder is
  48.      * configured to do.
  49.      *
  50.      * @param builder
  51.      */
  52.     public ConsoleApplication(final ProcessBuilder builder) {
  53.         this.builder = builder;
  54.         this.builder.redirectErrorStream(true);
  55.  
  56.         this.listeners = new HashSet<ConsoleListener>();
  57.     }
  58.  
  59.     /**
  60.      * Start the process.
  61.      *
  62.      * @throws IOException
  63.      */
  64.     public void start() throws IOException {
  65.         if (this.hasStarted())
  66.             throw new IllegalStateException(
  67.                     "This process has already been started once.");
  68.  
  69.         this.process = this.builder.start();
  70.  
  71.         for (ConsoleListener l : this.listeners) {
  72.             l.onStart(new ConsoleEvent(this));
  73.         }
  74.  
  75.         this.handler = new InputHandler(this.process.getInputStream());
  76.         new Thread(this.handler).start();
  77.  
  78.         this.commandStream = new PrintStream(this.process.getOutputStream());
  79.  
  80.         Runtime.getRuntime().addShutdownHook(
  81.                 this.shutdownTask = new Thread(new ShutdownListener()));
  82.     }
  83.  
  84.     /**
  85.      * Stops the process.
  86.      */
  87.     public void stop() {
  88.         this.process.destroy();
  89.         this.onProcessQuit();
  90.  
  91.         Runtime.getRuntime().removeShutdownHook(this.shutdownTask);
  92.     }
  93.  
  94.     public void nuke() {
  95.         this.process.destroy();
  96.     }
  97.  
  98.     /**
  99.      * Sends a text command to the process.
  100.      *
  101.      * @param command
  102.      */
  103.     public void sendCommand(String command) {
  104.         this.commandStream.println(command);
  105.         this.commandStream.flush();
  106.         this.onConsoleLine("> " + command);
  107.     }
  108.  
  109.     /**
  110.      * Called when the process closes its output stream.
  111.      */
  112.     private void onStreamQuit() {
  113.         if (this.isRunning())
  114.             this.stop();
  115.     }
  116.  
  117.     /**
  118.      * Called whenever the process is stopped by any means.
  119.      */
  120.     private void onProcessQuit() {
  121.         this.stopped = true;
  122.  
  123.         this.commandStream.close();
  124.  
  125.         if (this.handler != null)
  126.             this.handler.stop();
  127.  
  128.         for (ConsoleListener l : this.listeners) {
  129.             l.onStop(new ConsoleEvent(this));
  130.         }
  131.     }
  132.  
  133.     /**
  134.      * Called when the console sends a line.
  135.      *
  136.      * @param line
  137.      */
  138.     private void onConsoleLine(String line) {
  139.         ConsoleLineEvent event = new ConsoleLineEvent(this, line);
  140.  
  141.         for (ConsoleListener l : this.listeners) {
  142.             l.onLineReceived(event);
  143.         }
  144.     }
  145.  
  146.     /**
  147.      * Checks if the process is currently running.
  148.      *
  149.      * @return
  150.      */
  151.     public boolean isRunning() {
  152.         return this.hasStarted() && !this.hasStopped();
  153.     }
  154.  
  155.     /**
  156.      * Checks if the process was running but has now stopped.
  157.      *
  158.      * @return
  159.      */
  160.     public boolean hasStopped() {
  161.         return this.stopped;
  162.     }
  163.  
  164.     /**
  165.      * Checks if the process has been started. This will return true even if the
  166.      * process was subsequently stopped. To check if the process is currently
  167.      * running, use {@link #isRunning()}.
  168.      *
  169.      * @return
  170.      */
  171.     public boolean hasStarted() {
  172.         return this.process != null;
  173.     }
  174.  
  175.     /**
  176.      * Add a ConsoleListener to this wrapper.
  177.      *
  178.      * @param l
  179.      */
  180.     public void addListener(ConsoleListener l) {
  181.         this.listeners.add(l);
  182.     }
  183.  
  184.     /**
  185.      * Remove a ConsoleListener from this wrapper.
  186.      *
  187.      * @param l
  188.      */
  189.     public void removeListener(ConsoleListener l) {
  190.         this.listeners.remove(l);
  191.     }
  192.  
  193.     /**
  194.      * Handles the wrapped process's input stream, calling appropriate methods
  195.      * on receipt of lines or the closure of the stream.
  196.      *
  197.      * @author Chris
  198.      *
  199.      */
  200.     private class InputHandler implements Runnable {
  201.         private InputStream stream;
  202.         private volatile boolean cont = true;
  203.  
  204.         public InputHandler(InputStream stream) {
  205.             this.stream = stream;
  206.         }
  207.  
  208.         public void stop() {
  209.             this.cont = false;
  210.         }
  211.  
  212.         @Override
  213.         public void run() {
  214.             BufferedReader reader = new BufferedReader(new InputStreamReader(
  215.                     this.stream));
  216.             String line;
  217.  
  218.             try {
  219.                 while (this.cont && ((line = reader.readLine()) != null)) {
  220.                     ConsoleApplication.this.onConsoleLine(line);
  221.                 }
  222.             } catch (IOException e) {
  223.                 // Hmm, odd. Oh well!
  224.             } finally {
  225.                 try {
  226.                     reader.close();
  227.                 } catch (IOException e) {
  228.                     // Well, we tried!
  229.                 }
  230.             }
  231.  
  232.             if (this.cont)
  233.                 ConsoleApplication.this.onStreamQuit();
  234.             this.cont = false;
  235.         }
  236.     }
  237.  
  238.     private class ShutdownListener implements Runnable {
  239.         @Override
  240.         public void run() {
  241.             ConsoleApplication.this.nuke();
  242.         }
  243.     }
  244.  
  245. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement