From a0b2eb005d4a094de9483eda3b6e197b97f0e9a9 Mon Sep 17 00:00:00 2001 From: Eric Bottard Date: Wed, 14 Mar 2018 23:25:06 +0100 Subject: [PATCH] Implement command interruption via CTRL-C Fixes #209 --- .../java/org/springframework/shell/Shell.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/spring-shell-core/src/main/java/org/springframework/shell/Shell.java b/spring-shell-core/src/main/java/org/springframework/shell/Shell.java index 564849bd..ab9634ff 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/Shell.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/Shell.java @@ -18,6 +18,8 @@ package org.springframework.shell; import java.io.IOException; import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; +import java.nio.channels.ClosedByInterruptException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -33,6 +35,8 @@ import javax.validation.Validator; import javax.validation.ValidatorFactory; import javax.validation.executable.ExecutableValidator; +import org.jline.utils.Signals; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.core.MethodParameter; @@ -134,6 +138,7 @@ public class Shell implements CommandRegistry { if (input == null) { break; } + result = evaluate(input); if (result != NO_INPUT && !(result instanceof ExitRequest)) { resultHandler.handleResult(result); @@ -166,14 +171,26 @@ public class Shell implements CommandRegistry { List wordsForArgs = wordsForArguments(command, words); Method method = methodTarget.getMethod(); + Thread commandThread = Thread.currentThread(); + Object sh = Signals.register("INT", () -> commandThread.interrupt()); try { Object[] args = resolveArgs(method, wordsForArgs); validateArgs(args, methodTarget); + return ReflectionUtils.invokeMethod(method, methodTarget.getBean(), args); } + catch (UndeclaredThrowableException e) { + if (e.getCause() instanceof InterruptedException || e.getCause() instanceof ClosedByInterruptException) { + Thread.interrupted(); // to reset interrupted flag + } + return e.getCause(); + } catch (Exception e) { return e; } + finally { + Signals.unregister("INT", sh); + } } else { return new CommandNotCurrentlyAvailable(command, availability);