org.crsh.shell.impl.async.AsyncProcess Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2012 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.crsh.shell.impl.async;
import org.crsh.keyboard.KeyHandler;
import org.crsh.text.Screenable;
import org.crsh.shell.ShellProcess;
import org.crsh.shell.ShellProcessContext;
import org.crsh.shell.ShellResponse;
import org.crsh.text.Style;
import java.io.IOException;
import java.util.concurrent.Callable;
public class AsyncProcess implements ShellProcess {
/** . */
private final String request;
/** . */
private ShellProcessContext caller;
/** . */
private ShellProcess callee;
/** . */
private AsyncShell shell;
/** . */
private Status status;
/** . */
private final Object lock;
AsyncProcess(AsyncShell shell, String request) {
this.shell = shell;
this.request = request;
this.callee = null;
this.status = Status.CONSTRUCTED;
this.lock = new Object();
}
public Status getStatus() {
return status;
}
/** . */
private final ShellProcessContext context = new ShellProcessContext() {
public int getWidth() {
return caller.getWidth();
}
public int getHeight() {
return caller.getHeight();
}
public String getProperty(String name) {
return caller.getProperty(name);
}
public boolean takeAlternateBuffer() throws IOException {
return caller.takeAlternateBuffer();
}
public boolean releaseAlternateBuffer() throws IOException {
return caller.releaseAlternateBuffer();
}
public String readLine(String msg, boolean echo) throws IOException, InterruptedException {
return caller.readLine(msg, echo);
}
public Screenable append(CharSequence s) throws IOException {
caller.append(s);
return this;
}
@Override
public Screenable append(char c) throws IOException {
caller.append(c);
return this;
}
@Override
public Screenable append(CharSequence csq, int start, int end) throws IOException {
caller.append(csq, start, end);
return this;
}
public Screenable append(Style style) throws IOException {
caller.append(style);
return this;
}
public Screenable cls() throws IOException {
caller.cls();
return this;
}
public void flush() throws IOException {
caller.flush();
}
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);
}
};
@Override
public KeyHandler getKeyHandler() {
synchronized (lock) {
if (status != Status.EVALUATING) {
throw new IllegalStateException();
}
}
// Should it be synchronous or not ????
// no clue for now :-)
return callee.getKeyHandler();
}
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 task = new Callable() {
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 void cancel() {
// Construcuted -> ISE
// Evaluating -> Canceled
// Queued -> Canceled
// Cancelled -> Cancelled
// Terminated -> Terminated
boolean cancel;
synchronized (lock) {
switch (status) {
case CONSTRUCTED:
throw new IllegalStateException("Cannot call cancel on process that was not scheduled for execution yet");
case QUEUED:
status = Status.CANCELED;
cancel = false;
break;
case EVALUATING:
status = Status.CANCELED;
cancel = true;
break;
default:
cancel = false;
break;
}
}
//
if (cancel) {
callee.cancel();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy