Skip to content

Commit

Permalink
Fix for WFCORE-2272. Cancel running operation on Ctrl-C
Browse files Browse the repository at this point in the history
  • Loading branch information
jfdenise committed Aug 30, 2017
1 parent ba71f93 commit 4713ebe
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -893,10 +893,10 @@ private <T> T execute(Callable<T> c, String msg) throws CommandLineException {
} catch (IOException ex) {
throw new CommandLineException("IO exception for " + msg, ex);
} catch (TimeoutException ex) {
throw new CommandLineException("Timeout exception for " + msg, ex);
throw new CommandLineException("Timeout exception for " + msg);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new CommandLineException("Interrupt exception for " + msg, ex);
throw new CommandLineException("Interrupt exception for " + msg);
} catch (ExecutionException ex) {
Throwable cause = ex.getCause() == null ? ex : ex.getCause();
if (cause instanceof CommandLineException) {
Expand Down
256 changes: 125 additions & 131 deletions cli/src/main/java/org/jboss/as/cli/impl/CommandExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
*/
public class CommandExecutor {

private static final String CANCEL_MSG = "Cancelling running operation...";
private static final String TIMEOUT_CANCEL_MSG = "Timeout. " + CANCEL_MSG;

// A wrapper to allow to override ModelControllerClient.
// Public for testing purpose.
public class TimeoutCommandContext implements CommandContext {
Expand Down Expand Up @@ -158,134 +161,102 @@ public void ensureConnected(long timeoutMillis) throws CommandLineException, IOE
}

private AsyncFuture<OperationResponse> doExecuteOperationAsync(Operation operation, OperationMessageHandler messageHandler) {
if (ctx.getCommandTimeout() > 0) {
AsyncFuture<OperationResponse> task
= wrapped.executeOperationAsync(operation, messageHandler);
setLastHandlerTask(task);
return task;
} else {
return wrapped.executeOperationAsync(operation, messageHandler);
}
AsyncFuture<OperationResponse> task
= wrapped.executeOperationAsync(operation, messageHandler);
setLastHandlerTask(task);
return task;
}

private OperationResponse doExecuteOperation(Operation operation, OperationMessageHandler messageHandler) throws IOException {
if (ctx.getCommandTimeout() > 0) {
AsyncFuture<OperationResponse> task;
task = wrapped.executeOperationAsync(operation, messageHandler);
setLastHandlerTask(task);
try {
return task.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
} catch (ExecutionException ex) {
throw new IOException(ex);
}
} else {
return wrapped.executeOperation(operation, messageHandler);
AsyncFuture<OperationResponse> task;
task = wrapped.executeOperationAsync(operation, messageHandler);
setLastHandlerTask(task);
try {
return task.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
} catch (ExecutionException ex) {
throw new IOException(ex);
}
}

private AsyncFuture<ModelNode> doExecuteAsync(Operation operation, OperationMessageHandler messageHandler) {
if (ctx.getCommandTimeout() > 0) {
AsyncFuture<ModelNode> task
= wrapped.executeAsync(operation, messageHandler);
setLastHandlerTask(task);
return task;
} else {
return wrapped.executeAsync(operation, messageHandler);
}
AsyncFuture<ModelNode> task
= wrapped.executeAsync(operation, messageHandler);
setLastHandlerTask(task);
return task;
}

private AsyncFuture<ModelNode> doExecuteAsync(ModelNode operation, OperationMessageHandler messageHandler) {
if (ctx.getCommandTimeout() > 0) {
AsyncFuture<ModelNode> task
= wrapped.executeAsync(operation, messageHandler);
setLastHandlerTask(task);
return task;
} else {
return wrapped.executeAsync(operation, messageHandler);
}
AsyncFuture<ModelNode> task
= wrapped.executeAsync(operation, messageHandler);
setLastHandlerTask(task);
return task;
}

private ModelNode doExecute(Operation operation) throws IOException {
if (ctx.getCommandTimeout() > 0) {
try {
Future<ModelNode> task
= wrapped.executeAsync(operation, OperationMessageHandler.DISCARD);
setLastHandlerTask(task);
return task.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
} catch (ExecutionException ex) {
throw new IOException(ex);
} catch (Exception ex) {
throw new IOException(ex);
}
} else {
return wrapped.execute(operation);
try {
Future<ModelNode> task
= wrapped.executeAsync(operation, OperationMessageHandler.DISCARD);
setLastHandlerTask(task);
return task.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
} catch (ExecutionException ex) {
throw new IOException(ex);
} catch (Exception ex) {
throw new IOException(ex);
}
}

private ModelNode doExecute(ModelNode operation) throws IOException {
if (ctx.getCommandTimeout() > 0) {
try {
Future<ModelNode> task
= wrapped.executeAsync(operation, OperationMessageHandler.DISCARD);
setLastHandlerTask(task);
return task.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
} catch (ExecutionException ex) {
throw new IOException(ex);
} catch (Exception ex) {
throw new IOException(ex);
}
} else {
return wrapped.execute(operation);
try {
Future<ModelNode> task
= wrapped.executeAsync(operation, OperationMessageHandler.DISCARD);
setLastHandlerTask(task);
return task.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
} catch (ExecutionException ex) {
throw new IOException(ex);
} catch (Exception ex) {
throw new IOException(ex);
}
}

private ModelNode doExecute(ModelNode operation, OperationMessageHandler handler) throws IOException {
if (ctx.getCommandTimeout() > 0) {
try {
Future<ModelNode> task
= wrapped.executeAsync(operation, handler);
setLastHandlerTask(task);
return task.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
} catch (ExecutionException ex) {
throw new IOException(ex);
} catch (Exception ex) {
throw new IOException(ex);
}
} else {
return wrapped.execute(operation, handler);
try {
Future<ModelNode> task
= wrapped.executeAsync(operation, handler);
setLastHandlerTask(task);
return task.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
} catch (ExecutionException ex) {
throw new IOException(ex);
} catch (Exception ex) {
throw new IOException(ex);
}
}

private ModelNode doExecute(Operation operation,
OperationMessageHandler handler) throws IOException {
if (ctx.getCommandTimeout() > 0) {
try {
Future<ModelNode> task
= wrapped.executeAsync(operation, handler);
setLastHandlerTask(task);
return task.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
} catch (ExecutionException ex) {
throw new IOException(ex);
} catch (Exception ex) {
throw new IOException(ex);
}
} else {
return wrapped.execute(operation, handler);
try {
Future<ModelNode> task
= wrapped.executeAsync(operation, handler);
setLastHandlerTask(task);
return task.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
} catch (ExecutionException ex) {
throw new IOException(ex);
} catch (Exception ex) {
throw new IOException(ex);
}
}

Expand All @@ -308,7 +279,11 @@ public void close() throws IOException {

synchronized void timeout() {
timeout = true;
cancelTask(handlerTask);
cancelTask(handlerTask, wrapped, TIMEOUT_CANCEL_MSG);
}

synchronized void interrupted() {
cancelTask(handlerTask, wrapped, CANCEL_MSG);
}

/**
Expand All @@ -320,7 +295,7 @@ synchronized void timeout() {
*/
public synchronized void setLastHandlerTask(Future<?> handlerTask) {
if (timeout) {
cancelTask(handlerTask);
cancelTask(handlerTask, wrapped, CANCEL_MSG);
} else {
this.handlerTask = handlerTask;
}
Expand Down Expand Up @@ -650,48 +625,67 @@ ModelNode execute(Operation op, int timeout, TimeUnit unit) throws CommandLineEx
throw new CommandLineException("CLI not connected");
}

if (timeout <= 0) { //Synchronous
return client.execute(op);
} else { // Guarded execution
Future<ModelNode> task = client.executeAsync(op,
OperationMessageHandler.DISCARD);
try {
return task.get(timeout, unit);
} catch (TimeoutException ex) {
cancelTask(task);
throw ex;
Future<ModelNode> task = client.executeAsync(op,
OperationMessageHandler.DISCARD);
try {
if (timeout <= 0) { //Synchronous
return task.get();
} else { // Guarded execution
try {
return task.get(timeout, unit);
} catch (TimeoutException ex) {
cancelTask(task, ctx, CANCEL_MSG);
throw ex;
}
}
} catch (InterruptedException ex) {
// User sending Ctrl-C
Thread.currentThread().interrupt();
cancelTask(task, ctx, CANCEL_MSG);
throw ex;
}
}

// Public for testing purpose.
public void execute(CommandHandler handler, int timeout, TimeUnit unit) throws
CommandLineException,
InterruptedException, ExecutionException, TimeoutException {
if (timeout <= 0) { //Synchronous
handler.handle(ctx);
} else { // Guarded execution
TimeoutCommandContext context = new TimeoutCommandContext(ctx);
Future<Void> task = executorService.submit(() -> {
handler.handle(context);
return null;
});
try {
task.get(timeout, unit);
} catch (TimeoutException ex) {
// First make the context unusable
context.timeout();
// Then cancel the task.
task.cancel(true);
throw ex;
TimeoutCommandContext context = new TimeoutCommandContext(ctx);
Future<Void> task = executorService.submit(() -> {
handler.handle(context);
return null;
});
try {
if (timeout <= 0) { //Synchronous
task.get();
} else { // Guarded execution
try {
task.get(timeout, unit);
} catch (TimeoutException ex) {
// First make the context unusable
context.timeout();
// Then cancel the task.
task.cancel(true);
throw ex;
}
}
} catch (InterruptedException ex) {
// Could have been interrupted by user (Ctrl-C)
Thread.currentThread().interrupt();
cancelTask(task, context, null);
// Interrupt running operation.
context.interrupted();
throw ex;
}
}

private static void cancelTask(Future<?> task) {
private static void cancelTask(Future<?> task, CommandContext ctx, String msg) {
if (task != null && !(task.isDone()
&& task.isCancelled())) {
try {
if (msg != null) {
ctx.printLine(msg);
}
task.cancel(true);
} catch (Exception cex) {
// XXX OK, task could be already canceled or done.
Expand Down

0 comments on commit 4713ebe

Please sign in to comment.