diff --git a/spring-all/pom.xml b/spring-all/pom.xml
index f28fe1f10d..a3a51425e2 100644
--- a/spring-all/pom.xml
+++ b/spring-all/pom.xml
@@ -43,6 +43,12 @@
spring-retry
${springretry.version}
+
+ org.springframework.shell
+ spring-shell
+ ${org.springframework.shell.version}
+
+
@@ -280,6 +286,7 @@
4.3.4.RELEASE
4.2.0.RELEASE
1.1.5.RELEASE
+ 1.2.0.RELEASE
5.2.5.Final
diff --git a/spring-all/src/main/java/org/baeldung/shell/Main.java b/spring-all/src/main/java/org/baeldung/shell/Main.java
new file mode 100644
index 0000000000..3d9f7a5860
--- /dev/null
+++ b/spring-all/src/main/java/org/baeldung/shell/Main.java
@@ -0,0 +1,10 @@
+package org.baeldung.shell;
+
+import java.io.IOException;
+import org.springframework.shell.Bootstrap;
+
+public class Main {
+ public static void main(String[] args) throws IOException {
+ Bootstrap.main(args);
+ }
+}
diff --git a/spring-all/src/main/java/org/baeldung/shell/simple/SimpleBannerProvider.java b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleBannerProvider.java
new file mode 100644
index 0000000000..df7a48cd32
--- /dev/null
+++ b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleBannerProvider.java
@@ -0,0 +1,34 @@
+package org.baeldung.shell.simple;
+
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.shell.plugin.support.DefaultBannerProvider;
+import org.springframework.shell.support.util.OsUtils;
+import org.springframework.stereotype.Component;
+
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class SimpleBannerProvider extends DefaultBannerProvider {
+
+ public String getBanner() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("=======================================").append(OsUtils.LINE_SEPARATOR);
+ buf.append("* Baeldung Shell *").append(OsUtils.LINE_SEPARATOR);
+ buf.append("=======================================").append(OsUtils.LINE_SEPARATOR);
+ buf.append("Version:").append(this.getVersion());
+ return buf.toString();
+ }
+
+ public String getVersion() {
+ return "1.0.1";
+ }
+
+ public String getWelcomeMessage() {
+ return "Welcome to Baeldung CLI";
+ }
+
+ @Override
+ public String getProviderName() {
+ return "Baeldung Banner";
+ }
+}
diff --git a/spring-all/src/main/java/org/baeldung/shell/simple/SimpleCLI.java b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleCLI.java
new file mode 100644
index 0000000000..0bbc62cf2c
--- /dev/null
+++ b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleCLI.java
@@ -0,0 +1,81 @@
+package org.baeldung.shell.simple;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.springframework.shell.Bootstrap;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SimpleCLI implements CommandMarker {
+
+ private String getContentsOfUrlAsString(URL url) {
+ StringBuilder sb = new StringBuilder();
+ try {
+ try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()))) {
+ String inputLine;
+ while ((inputLine = in.readLine()) != null) {
+ sb.append(inputLine);
+ }
+ }
+ } catch (IOException ex) {
+ sb.append("ERROR");
+ }
+ return sb.toString();
+ }
+
+ @CliCommand(
+ value = {"web-get", "wg"},
+ help = "Displays the contents of a URL."
+ )
+ public String webGet(
+ @CliOption(
+ key = {"", "url"},
+ help = "URL whose contents will be displayed."
+ ) URL url) {
+ return getContentsOfUrlAsString(url);
+ }
+
+ @CliCommand(
+ value = {"web-save", "ws"},
+ help = "Saves the contents of a URL.")
+ public String webSave(
+ @CliOption(key = {"", "url"}, help = "URL whose contents will be saved.") URL url,
+ @CliOption(key = {"out", "file"}, mandatory = true, help = "The name of the file.") String file) {
+ String contents = getContentsOfUrlAsString(url);
+ try (PrintWriter out = new PrintWriter(file)) {
+ out.write(contents);
+ } catch (FileNotFoundException ex) {
+ //Ignore
+ }
+ return "Done.";
+ }
+
+ private boolean adminEnableExecuted = false;
+
+ @CliAvailabilityIndicator(value = {"web-save"})
+ public boolean isAdminEnabled() {
+ return adminEnableExecuted;
+ }
+
+ @CliCommand(value = "admin-enable")
+ public String adminEnable() {
+ adminEnableExecuted = true;
+ return "Admin commands enabled.";
+ }
+
+ @CliCommand(value = "admin-disable")
+ public String adminDisable() {
+ adminEnableExecuted = false;
+ return "Admin commands disabled.";
+ }
+}
diff --git a/spring-all/src/main/java/org/baeldung/shell/simple/SimpleHistoryFileNameProvider.java b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleHistoryFileNameProvider.java
new file mode 100644
index 0000000000..cef53adc69
--- /dev/null
+++ b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleHistoryFileNameProvider.java
@@ -0,0 +1,22 @@
+package org.baeldung.shell.simple;
+
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.shell.plugin.support.DefaultHistoryFileNameProvider;
+import org.springframework.stereotype.Component;
+
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class SimpleHistoryFileNameProvider extends DefaultHistoryFileNameProvider {
+
+ @Override
+ public String getHistoryFileName() {
+ return "baeldung-shell.log";
+ }
+
+ @Override
+ public String getProviderName() {
+ return "Baeldung History";
+ }
+
+}
diff --git a/spring-all/src/main/java/org/baeldung/shell/simple/SimplePromptProvider.java b/spring-all/src/main/java/org/baeldung/shell/simple/SimplePromptProvider.java
new file mode 100644
index 0000000000..9a84954e05
--- /dev/null
+++ b/spring-all/src/main/java/org/baeldung/shell/simple/SimplePromptProvider.java
@@ -0,0 +1,21 @@
+package org.baeldung.shell.simple;
+
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.shell.plugin.support.DefaultPromptProvider;
+import org.springframework.stereotype.Component;
+
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class SimplePromptProvider extends DefaultPromptProvider {
+
+ @Override
+ public String getPrompt() {
+ return "baeldung-shell>";
+ }
+
+ @Override
+ public String getProviderName() {
+ return "Baeldung Prompt";
+ }
+}
diff --git a/spring-all/src/main/java/org/baeldung/shell/simple/SimpleURLConverter.java b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleURLConverter.java
new file mode 100644
index 0000000000..66bab5c488
--- /dev/null
+++ b/spring-all/src/main/java/org/baeldung/shell/simple/SimpleURLConverter.java
@@ -0,0 +1,35 @@
+package org.baeldung.shell.simple;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+import org.springframework.shell.core.Completion;
+import org.springframework.shell.core.Converter;
+import org.springframework.shell.core.MethodTarget;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SimpleURLConverter implements Converter {
+
+ @Override
+ public URL convertFromText(String value, Class> requiredType, String optionContext) {
+ try {
+ return new URL(value);
+ } catch (MalformedURLException ex) {
+ //Ignore
+ }
+ return null;
+ }
+
+ @Override
+ public boolean getAllPossibleValues(List completions, Class> requiredType,
+ String existingData, String optionContext, MethodTarget target) {
+ return false;
+ }
+
+ @Override
+ public boolean supports(Class> requiredType, String optionContext) {
+ return URL.class.isAssignableFrom(requiredType);
+ }
+
+}
diff --git a/spring-all/src/main/resources/META-INF/spring/spring-shell-plugin.xml b/spring-all/src/main/resources/META-INF/spring/spring-shell-plugin.xml
new file mode 100644
index 0000000000..aea1a663c1
--- /dev/null
+++ b/spring-all/src/main/resources/META-INF/spring/spring-shell-plugin.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-all/src/test/java/org/baeldung/shell/simple/SimpleCLIUnitTest.java b/spring-all/src/test/java/org/baeldung/shell/simple/SimpleCLIUnitTest.java
new file mode 100644
index 0000000000..0353083943
--- /dev/null
+++ b/spring-all/src/test/java/org/baeldung/shell/simple/SimpleCLIUnitTest.java
@@ -0,0 +1,86 @@
+package org.baeldung.shell.simple;
+
+import java.io.File;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.shell.Bootstrap;
+import org.springframework.shell.core.CommandResult;
+import org.springframework.shell.core.JLineShellComponent;
+
+public class SimpleCLIUnitTest {
+
+ static JLineShellComponent shell;
+
+ @BeforeClass
+ public static void startUp() throws InterruptedException {
+ Bootstrap bootstrap = new Bootstrap();
+ shell = bootstrap.getJLineShellComponent();
+ }
+
+ @AfterClass
+ public static void shutdown() {
+ shell.stop();
+ }
+
+ public static JLineShellComponent getShell() {
+ return shell;
+ }
+
+ @Test
+ public void givenCommandConfig_whenExecutingWebGetCommand_thenCorrectResult() {
+
+ CommandResult resultWebSave = shell.executeCommand("web-get --url https://www.google.com");
+
+ Assert.assertTrue(resultWebSave.isSuccess());
+ }
+
+ @Test
+ public void givenCommandConfig_whenExecutingWebSaveCommand_thenCorrectResult() {
+
+ shell.executeCommand("admin-enable");
+ CommandResult result = shell.executeCommand("web-save --url https://www.google.com --out contents.txt");
+
+ Assert.assertArrayEquals(
+ new boolean[]{
+ result.isSuccess(),
+ new File("contents.txt").exists()},
+ new boolean[]{true, true});
+ }
+
+ @Test
+ public void givenCommandConfig_whenAdminEnableCommandExecuted_thenCorrectAvailability() {
+
+ CommandResult resultAdminDisable = shell.executeCommand("admin-disable");
+ CommandResult resultWebSaveUnavailable = shell.executeCommand("web-save --url https://www.google.com --out contents.txt");
+ CommandResult resultAdminEnable = shell.executeCommand("admin-enable");
+ CommandResult resultWebSaveAvailable = shell.executeCommand("web-save --url https://www.google.com --out contents.txt");
+
+ Assert.assertArrayEquals(
+ new boolean[]{
+ resultAdminDisable.isSuccess(),
+ resultWebSaveUnavailable.isSuccess(),
+ resultAdminEnable.isSuccess(),
+ resultWebSaveAvailable.isSuccess()},
+ new boolean[]{true, false, true, true});
+ }
+
+ @Test
+ public void givenCommandConfig_whenWebSaveCommandExecutedNoOutArgument_thenError() {
+
+ shell.executeCommand("admin-enable");
+ CommandResult resultWebSave = shell.executeCommand("web-save --url https://www.google.com");
+
+ Assert.assertEquals(resultWebSave.isSuccess(), false);
+ }
+
+ @Test
+ public void givenCommandConfig_whenExecutingWebGetCommandWithDefaultArgument_thenCorrectResult() {
+
+ CommandResult result = shell.executeCommand("web-get https://www.google.com");
+
+ Assert.assertEquals(result.isSuccess(), true);
+ }
+
+}