public void end(ShellResponse response) { // Always leave the status in terminated status if the method succeeds // Cancelled -> Terminated // Evaluating -> Terminated // Terminated -> Terminated synchronized (lock) { switch (status) { case CONSTRUCTED: case QUEUED: throw new AssertionError("Should not happen"); case CANCELED: // We substitute the response response = ShellResponse.cancelled(); status = Status.TERMINATED; break; case EVALUATING: status = Status.TERMINATED; break; case TERMINATED: throw new IllegalStateException("Cannot end a process already terminated"); } } // caller.end(response); }
public void execute(ShellProcessContext processContext) { // Constructed -> Queued synchronized (lock) { if (status != Status.CONSTRUCTED) { throw new IllegalStateException("State was " + status); } // Update state status = Status.QUEUED; callee = shell.shell.createProcess(request); caller = processContext; } // Create the task Callable<AsyncProcess> task = new Callable<AsyncProcess>() { public AsyncProcess call() throws Exception { try { // Cancelled -> Cancelled // Queued -> Evaluating ShellResponse response; synchronized (lock) { switch (status) { case CANCELED: // Do nothing it was canceled in the mean time response = ShellResponse.cancelled(); break; case QUEUED: // Ok we are going to run it status = Status.EVALUATING; response = null; break; default: // Just in case but this can only be called by the queue throw new AssertionError(); } } // Execute the process if we are in evalating state if (response == null) { // Here the status could already be in status cancelled // it is a race condition, execution still happens // but the callback of the callee to the end method will make the process // terminate and use a cancel response try { callee.execute(context); response = ShellResponse.ok(); } catch (Throwable t) { response = ShellResponse.internalError("Unexpected throwable when executing process", t); } } // Make the callback // Calling terminated twice will have no effect try { context.end(response); } catch (Throwable t) { // Log it } // We return this but we don't really care for now return AsyncProcess.this; } finally { synchronized (shell.lock) { shell.processes.remove(AsyncProcess.this); } } } }; // synchronized (shell.lock) { if (!shell.closed) { shell.executor.submit(task); shell.processes.add(this); } else { boolean invokeEnd; synchronized (lock) { invokeEnd = status != Status.TERMINATED; status = Status.TERMINATED; } if (invokeEnd) { caller.end(ShellResponse.cancelled()); } } } }
public String getProperty(String name) { return caller.getProperty(name); }
public String readLine(String msg, boolean echo) { return caller.readLine(msg, echo); }
public int getWidth() { return caller.getWidth(); }