Skip to content

Commit 942108e

Browse files
committed
Update docs
- Split adoc files - Relates #383
1 parent 412053d commit 942108e

17 files changed

+1639
-1649
lines changed

spring-shell-docs/src/main/asciidoc/extending-spring-shell.adoc

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
== Getting Started
2+
To see what Spring Shell has to offer, we can write a trivial shell application that
3+
has a simple command to add two numbers.
4+
5+
=== Writing a Simple Boot Application
6+
7+
Starting with version 2, Spring Shell has been rewritten from the ground up with various
8+
enhancements in mind, one of which is easy integration with Spring Boot, although it is
9+
not a strong requirement.
10+
For the purpose of this tutorial, we create a simple Boot application by
11+
using https://start.spring.io. This minimal application depends only on `spring-boot-starter`
12+
and configures the `spring-boot-maven-plugin` to generate an executable über-jar:
13+
14+
====
15+
[source, xml]
16+
----
17+
...
18+
<dependencies>
19+
<dependency>
20+
<groupId>org.springframework.boot</groupId>
21+
<artifactId>spring-boot-starter</artifactId>
22+
</dependency>
23+
...
24+
</dependencies>
25+
----
26+
====
27+
28+
[[using-spring-shell-add-dependency]]
29+
=== Adding a Dependency on Spring Shell
30+
31+
The easiest way to get going with Spring Shell is to depend on the `{starter-artifactId}` artifact.
32+
This comes with everything one needs to use Spring Shell and plays nicely with Boot,
33+
configuring only the necessary beans as needed:
34+
35+
====
36+
[source, xml, subs=attributes+]
37+
----
38+
...
39+
<dependency>
40+
<groupId>org.springframework.shell</groupId>
41+
<artifactId>{spring-shell-starter}</artifactId>
42+
<version>{project-version}</version>
43+
</dependency>
44+
...
45+
----
46+
====
47+
48+
CAUTION: Given that Spring Shell starts the REPL by virtue of this dependency being present,
49+
you need to either skip tests when you build (`-DskipTests`) throughout this tutorial or remove the sample integration test
50+
that was generated by https://start.spring.io. If you do not remove it, the integration test creates
51+
the Spring `ApplicationContext` and, depending on your build tool, stays stuck in the eval loop or crashes with a NPE.
52+
53+
[[using-spring-shell-your-first-command]]
54+
=== Your First Command
55+
56+
Now we can add our first command. To do so, create a new class (named whatever you want) and
57+
annotate it with `@ShellComponent` (a variation of `@Component` that is used to restrict
58+
the set of classes that are scanned for candidate commands).
59+
60+
Then create an `add` method that takes two ints (`a` and `b`) and returns their sum. Annotate it
61+
with `@ShellMethod` and provide a description of the command in the annotation (the only piece of
62+
information that is required):
63+
64+
====
65+
[source, java]
66+
----
67+
package com.example.demo;
68+
69+
import org.springframework.shell.standard.ShellMethod;
70+
import org.springframework.shell.standard.ShellComponent;
71+
72+
@ShellComponent
73+
public class MyCommands {
74+
75+
@ShellMethod("Add two integers together.")
76+
public int add(int a, int b) {
77+
return a + b;
78+
}
79+
}
80+
----
81+
====
82+
83+
[[using-spring-shell-try-application]]
84+
=== Trying the Application
85+
86+
To build the application and run the generated jar, run the following command:
87+
88+
====
89+
[source, bash]
90+
----
91+
./mvnw clean install -DskipTests
92+
[...]
93+
94+
java -jar target/demo-0.0.1-SNAPSHOT.jar
95+
----
96+
====
97+
98+
You are greeted by the following screen (the banner comes from Spring Boot and can be
99+
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-banner[customized]:
100+
101+
====
102+
[source]
103+
----
104+
shell:>
105+
----
106+
====
107+
108+
A yellow `shell:>` prompt invites you to type commands. Type `add 1 2`, press `ENTER`, and admire the magic:
109+
110+
====
111+
[source, bash]
112+
----
113+
shell:>add 1 2
114+
3
115+
----
116+
====
117+
118+
Try to play with the shell (hint: there is a `help` command). When you are done, type `exit` and press `ENTER`.
119+
120+
The rest of this document delves deeper into the whole Spring Shell programming model.
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
= Spring Shell Reference Documentation
2-
Eric Bottard; Janne Valkealahti; Jay Bryant;
2+
Eric Bottard; Janne Valkealahti; Jay Bryant, Corneil du Plessis;
33
:doctype: book
44
:hide-uri-scheme:
55
:icons: font
66
:experimental: // For kbd: macro
7+
:spring-shell-starter: spring-shell-starter
78

8-
ifdef::backend-html5[]
99
*{projectVersion}*
1010

1111
(C) 2017 - 2022 VMware, Inc.
@@ -15,10 +15,8 @@ others, provided that you do not charge any fee for such copies and further
1515
provided that each copy contains this Copyright Notice, whether distributed in
1616
print or electronically._
1717

18-
// ======================================================================================
18+
include::introduction.adoc[]
1919

20-
include::what-is-spring-shell.adoc[]
20+
include::getting-started.adoc[]
2121

22-
include::using-spring-shell.adoc[]
23-
24-
// include::extending-spring-shell.adoc[]
22+
include::using-shell.adoc[]

spring-shell-docs/src/main/asciidoc/what-is-spring-shell.adoc renamed to spring-shell-docs/src/main/asciidoc/introduction.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
== What is Spring Shell?
1+
== Introduction
22

3+
=== What is Spring Shell?
34
Not all applications need a fancy web user interface!
45
Sometimes, interacting with an application through an interactive terminal is
56
the most appropriate way to get things done.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
[[dynamic-command-availability]]
2+
=== Dynamic Command Availability
3+
4+
Registered commands do not always make sense, due to the internal state of the application.
5+
For example, there may be a `download` command, but it only works once the user has used `connect` on a remote
6+
server. Now, if the user tries to use the `download` command, the shell should gracefully explain that
7+
the command exist but that it is not available at the time.
8+
Spring Shell lets you do that, even letting you provide a short explanation of the reason for
9+
the command not being available.
10+
11+
There are three possible ways for a command to indicate availability.
12+
They all leverage a no-arg method that returns an instance of `Availability`.
13+
Consider the following example:
14+
15+
====
16+
[source, java]
17+
----
18+
@ShellComponent
19+
public class MyCommands {
20+
21+
private boolean connected;
22+
23+
@ShellMethod("Connect to the server.")
24+
public void connect(String user, String password) {
25+
[...]
26+
connected = true;
27+
}
28+
29+
@ShellMethod("Download the nuclear codes.")
30+
public void download() {
31+
[...]
32+
}
33+
34+
public Availability downloadAvailability() {
35+
return connected
36+
? Availability.available()
37+
: Availability.unavailable("you are not connected");
38+
}
39+
}
40+
----
41+
====
42+
43+
The `connect` method is used to connect to the server (details omitted), altering the state
44+
of the command through the `connected` boolean when done.
45+
The `download` command as marked as unavailable until the user has connected, thanks to the presence
46+
of a method named exactly as the `download` command method with the `Availability` suffix in its name.
47+
The method returns an instance of `Availability`, constructed with one of the two factory methods.
48+
If the command is not available, an explanation has to be provided.
49+
Now, if the user tries to invoke the command while not being connected, here is what happens:
50+
51+
====
52+
[source]
53+
----
54+
shell:>download
55+
Command 'download' exists but is not currently available because you are not connected.
56+
Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.
57+
----
58+
====
59+
60+
Information about currently unavailable commands is also used in the integrated help. See <<help-command>>.
61+
62+
[TIP]
63+
====
64+
The reason provided when the command is not available should read nicely if appended after "`Because`".
65+
66+
You should not start the sentence with a capital or add a final period
67+
====
68+
69+
If naming the availability method after the name of the command method does not suit you, you
70+
can provide an explicit name by using the `@ShellMethodAvailability` annotation:
71+
72+
====
73+
[source, java]
74+
----
75+
@ShellMethod("Download the nuclear codes.")
76+
@ShellMethodAvailability("availabilityCheck") // <1>
77+
public void download() {
78+
[...]
79+
}
80+
81+
public Availability availabilityCheck() { // <1>
82+
return connected
83+
? Availability.available()
84+
: Availability.unavailable("you are not connected");
85+
}
86+
----
87+
<1> the names have to match
88+
====
89+
90+
Lastly, it is often the case that several commands in the same class share the same internal state and, thus,
91+
should all be available or unavailable as a group. Instead of having to stick the `@ShellMethodAvailability`
92+
on all command methods, Spring Shell lets you flip things around and put the `@ShellMethodAvailabilty`
93+
annotation on the availability method, specifying the names of the commands that it controls:
94+
95+
====
96+
[source, java]
97+
----
98+
@ShellMethod("Download the nuclear codes.")
99+
public void download() {
100+
[...]
101+
}
102+
103+
@ShellMethod("Disconnect from the server.")
104+
public void disconnect() {
105+
[...]
106+
}
107+
108+
@ShellMethodAvailability({"download", "disconnect"})
109+
public Availability availabilityCheck() {
110+
return connected
111+
? Availability.available()
112+
: Availability.unavailable("you are not connected");
113+
}
114+
----
115+
====
116+
117+
[TIP]
118+
=====
119+
The default value for the `@ShellMethodAvailability.value()` attribute is `*`. This special
120+
wildcard matches all command names. This makes it easy to turn all commands of a single class on or off
121+
with a single availability method:
122+
123+
====
124+
[source,java]
125+
----
126+
@ShellComponent
127+
public class Toggles {
128+
@ShellMethodAvailability
129+
public Availability availabilityOnWeekdays() {
130+
return Calendar.getInstance().get(DAY_OF_WEEK) == SUNDAY
131+
? Availability.available()
132+
: Availability.unavailable("today is not Sunday");
133+
}
134+
135+
@ShellMethod
136+
public void foo() {}
137+
138+
@ShellMethod
139+
public void bar() {}
140+
}
141+
----
142+
====
143+
=====
144+
145+
TIP: Spring Shell does not impose many constraints on how to write commands and how to organize classes.
146+
However, it is often good practice to put related commands in the same class, and the availability indicators
147+
can benefit from that.

0 commit comments

Comments
 (0)