Migrate docs to antora

- This is basically copy from main branch minus all
  terminal ui things.
- Relates #971
This commit is contained in:
Janne Valkealahti
2024-01-12 14:02:10 +00:00
parent 09d4bfed51
commit 814ed4958f
108 changed files with 637 additions and 1037 deletions

View File

@@ -0,0 +1,137 @@
[[dynamic-command-availability]]
= Dynamic Command Availability
Registered commands do not always make sense, due to the internal state of the application.
For example, there may be a `download` command, but it only works once the user has used `connect` on a remote
server. Now, if the user tries to use the `download` command, the shell should explain that
the command exists but that it is not available at the time.
Spring Shell lets you do that, even letting you provide a short explanation of the reason for
the command not being available.
There are three possible ways for a command to indicate availability.
They all use a no-arg method that returns an instance of `Availability`.
Consider the following example:
[source, java]
----
@ShellComponent
public class MyCommands {
private boolean connected;
@ShellMethod("Connect to the server.")
public void connect(String user, String password) {
[...]
connected = true;
}
@ShellMethod("Download the nuclear codes.")
public void download() {
[...]
}
public Availability downloadAvailability() {
return connected
? Availability.available()
: Availability.unavailable("you are not connected");
}
}
----
The `connect` method is used to connect to the server (details omitted), altering the state
of the command through the `connected` boolean when done.
The `download` command as marked as unavailable until the user has connected, thanks to the presence
of a method named exactly as the `download` command method with the `Availability` suffix in its name.
The method returns an instance of `Availability`, constructed with one of the two factory methods.
If the command is not available, an explanation has to be provided.
Now, if the user tries to invoke the command while not being connected, here is what happens:
[source]
----
shell:>download
Command 'download' exists but is not currently available because you are not connected.
Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.
----
Information about currently unavailable commands is also used in the integrated help. See xref:commands/builtin/help.adoc[Help].
[TIP]
====
The reason provided when the command is not available should read nicely if appended after "`Because`".
You should not start the sentence with a capital or add a final period
====
If naming the availability method after the name of the command method does not suit you, you
can provide an explicit name by using the `@ShellMethodAvailability` annotation:
[source, java]
----
@ShellMethod("Download the nuclear codes.")
@ShellMethodAvailability("availabilityCheck") // <1>
public void download() {
[...]
}
public Availability availabilityCheck() { // <1>
return connected
? Availability.available()
: Availability.unavailable("you are not connected");
}
----
<1> the names have to match
Finally, it is often the case that several commands in the same class share the same internal state and, thus,
should all be available or unavailable as a group. Instead of having to stick the `@ShellMethodAvailability`
on all command methods, Spring Shell lets you flip things around and put the `@ShellMethodAvailabilty`
annotation on the availability method, specifying the names of the commands that it controls:
[source, java]
----
@ShellMethod("Download the nuclear codes.")
public void download() {
[...]
}
@ShellMethod("Disconnect from the server.")
public void disconnect() {
[...]
}
@ShellMethodAvailability({"download", "disconnect"})
public Availability availabilityCheck() {
return connected
? Availability.available()
: Availability.unavailable("you are not connected");
}
----
[TIP]
=====
The default value for the `@ShellMethodAvailability.value()` attribute is `*`. This special
wildcard matches all command names. This makes it easy to turn all commands of a single class on or off
with a single availability method:
[source,java]
----
@ShellComponent
public class Toggles {
@ShellMethodAvailability
public Availability availabilityOnWeekdays() {
return Calendar.getInstance().get(DAY_OF_WEEK) == SUNDAY
? Availability.available()
: Availability.unavailable("today is not Sunday");
}
@ShellMethod
public void foo() {}
@ShellMethod
public void bar() {}
}
----
=====
TIP: Spring Shell does not impose many constraints on how to write commands and how to organize classes.
However, it is often good practice to put related commands in the same class, and the availability indicators
can benefit from that.

View File

@@ -0,0 +1,6 @@
[[built-in-commands-clear]]
= Clear
:page-section-summary-toc: 1
The `clear` command does what you would expect and clears the screen, resetting the prompt
in the top left corner.

View File

@@ -0,0 +1,9 @@
[[built-in-commands-completion]]
= Completion
:page-section-summary-toc: 1
The `completion` command set lets you create script files that can be used
with am OS shell implementations to provide completion. This is very useful when
working with non-interactive mode.
Currently, the only implementation is for bash, which works with `bash` sub-command.

View File

@@ -0,0 +1,7 @@
[[built-in-commands-exit]]
= Exit
:page-section-summary-toc: 1
The `quit` command (also aliased as `exit`) requests the shell to quit, gracefully
closing the Spring application context. If not overridden, a JLine `History` bean writes a history of all
commands to disk, so that they are available again on the next launch.

View File

@@ -0,0 +1,172 @@
[[built-in-commands-help]]
= Help
Running a shell application often implies that the user is in a graphically limited
environment. Also, while we are nearly always connected in the era of mobile phones,
accessing a web browser or any other rich UI application (such as a PDF viewer) may not always
be possible. This is why it is important that the shell commands are correctly self-documented, and this is where the `help`
command comes in.
Typing `help` + `ENTER` lists all the commands known to the shell (including xref:commands/availability.adoc[unavailable] commands)
and a short description of what they do, similar to the following:
[source, bash]
----
my-shell:>help
AVAILABLE COMMANDS
Built-In Commands
exit: Exit the shell.
help: Display help about available commands
stacktrace: Display the full stacktrace of the last error.
clear: Clear the shell screen.
quit: Exit the shell.
history: Display or save the history of previously run commands
completion bash: Generate bash completion script
version: Show version info
script: Read and execute commands from a file.
----
Typing `help <command>` shows more detailed information about a command, including the available parameters, their
type, whether they are mandatory or not, and other details.
The following listing shows the `help` command applied to itself:
[source, bash]
----
my-shell:>help help
NAME
help - Display help about available commands
SYNOPSIS
help --command String
OPTIONS
--command or -C String
The command to obtain help for.
[Optional]
----
Help is templated and can be customized if needed. Settings are under `spring.shell.command.help` where you can use
`enabled` to disable command, `grouping-mode` taking `group` or `flat` if you want to hide groups by flattening
a structure, `command-template` to define your template for output of a command help, `commands-template` to define
output of a command list.
If `spring.shell.command.help.grouping-mode=flat` is set, then help would show:
[source, bash]
----
my-shell:>help help
AVAILABLE COMMANDS
exit: Exit the shell.
help: Display help about available commands
stacktrace: Display the full stacktrace of the last error.
clear: Clear the shell screen.
quit: Exit the shell.
history: Display or save the history of previously run commands
completion bash: Generate bash completion script
version: Show version info
script: Read and execute commands from a file.
----
Output from `help` and `help <commmand>` are both templated with a default implementation
which can be changed.
Option `spring.shell.command.help.commands-template` defaults to
`classpath:template/help-commands-default.stg` and is passed `GroupsInfoModel`
as a model.
Option `spring.shell.command.help.command-template` defaults to
`classpath:template/help-command-default.stg` and is passed `CommandInfoModel`
as a model.
[[groupsinfomodel-variables]]
.GroupsInfoModel Variables
|===
|Key |Description
|`showGroups`
|`true` if showing groups is enabled. Otherwise, false.
|`groups`
|The commands variables (see xref:commands/builtin/help.adoc#groupcommandinfomodel-variables[GroupCommandInfoModel Variables]).
|`commands`
|The commands variables (see xref:commands/builtin/help.adoc#commandinfomodel-variables[CommandInfoModel Variables]).
|`hasUnavailableCommands`
|`true` if there is unavailable commands. Otherwise, false.
|===
[[groupcommandinfomodel-variables]]
.GroupCommandInfoModel Variables
|===
|Key |Description
|`group`
|The name of a group, if set. Otherwise, empty.
|`commands`
|The commands, if set. Otherwise, empty. Type is a multi value, see xref:commands/builtin/help.adoc#commandinfomodel-variables[CommandInfoModel Variables].
|===
[[commandinfomodel-variables]]
.CommandInfoModel Variables
|===
|Key |Description
|`name`
|The name of a command, if set. Otherwise, null. Type is string and contains full command.
|`names`
|The names of a command, if set. Otherwise, null. Type is multi value essentially `name` splitted.
|`aliases`
|The possible aliases, if set. Type is multi value with strings.
|`description`
|The description of a command, if set. Otherwise, null.
|`parameters`
|The parameters variables, if set. Otherwise empty. Type is a multi value, see xref:commands/builtin/help.adoc#commandparameterinfomodel-variables[CommandParameterInfoModel Variables].
|`availability`
|The availability variables (see xref:commands/builtin/help.adoc#commandavailabilityinfomodel-variables[CommandAvailabilityInfoModel Variables]).
|===
[[commandparameterinfomodel-variables]]
.CommandParameterInfoModel Variables
|===
|Key |Description
|`type`
|The type of a parameter if set. Otherwise, null.
|`arguments`
|The arguments, if set. Otherwise, null. Type is multi value with strings.
|`required`
|`true` if required. Otherwise, false.
|`description`
|The description of a parameter, if set. Otherwise, null.
|`defaultValue`
|The default value of a parameter, if set. Otherwise, null.
|`hasDefaultValue`
|`true` if defaultValue exists. Otherwise, false.
|===
[[commandavailabilityinfomodel-variables]]
.CommandAvailabilityInfoModel Variables
|===
|Key |Description
|`available`
|`true` if available. Otherwise, false.
|`reason`
|The reason if not available if set. Otherwise, null.
|===

View File

@@ -0,0 +1,17 @@
[[built-in-commands-history]]
= History
:page-section-summary-toc: 1
The `history` command shows the history of commands that has been executed.
There are a few configuration options that you can use to configure behavior
of a history. History is kept in a log file, which is enabled by default and can
be turned off by setting `spring.shell.history.enabled`. The name of a log file
is resolved from `spring.application.name` and defaults to `spring-shell.log`,
which you can change by setting `spring.shell.history.name`.
By default, a log file is generated to a current working directory, which you can dictate
by setting `spring.shell.config.location`. This property can contain
a placeholder (`+{userconfig}+`), which resolves to a common shared config directory.
TIP: Run the Spring Shell application to see how the sample application works as it uses these options.

View File

@@ -0,0 +1,11 @@
[[built-in-commands]]
= Built-In Commands
:page-section-summary-toc: 1

View File

@@ -0,0 +1,8 @@
[[built-in-commands-script]]
= Script
:page-section-summary-toc: 1
The `script` command accepts a local file as an argument and replays commands found there, one at a time.
Reading from the file behaves exactly like inside the interactive shell, so lines starting with `//` are considered
to be comments and are ignored, while lines ending with `\` trigger line continuation.

View File

@@ -0,0 +1,10 @@
[[built-in-commands-stacktrace]]
= Stacktrace
:page-section-summary-toc: 1
When an exception occurs inside command code, it is caught by the shell and a simple, one-line message is displayed
so as not to overflow the user with too much information.
There are cases, though, when understanding what exactly happened is important (especially if the exception has a nested cause).
To this end, Spring Shell remembers the last exception that occurred, and the user can later use the `stacktrace`
command to print all the details on the console.

View File

@@ -0,0 +1,33 @@
[[built-in-commands-version]]
= Version
The `version` command shows existing build and git info by integrating into
Boot's `BuildProperties` and `GitProperties` if those exist in the shell application.
By default, only version information is shown, and you can enable other information through configuration
options.
The relevant settings are under `spring.shell.command.version`, where you can use `enabled` to
disable a command and, optionally, define your own template with `template`. You can use the
`show-build-artifact`, `show-build-group`, `show-build-name`, `show-build-time`,
`show-build-version`, `show-git-branch`, `show-git-commit-id`,
`show-git-short-commit-id` and `show-git-commit-time` commands to control
fields in a default template.
The template defaults to `classpath:template/version-default.st`, and you can define
your own, as the following example shows:
[source]
----
<buildVersion>
----
This setting would output something like the following:
[source]
----
X.X.X
----
You can add the following attributes to the default template rendering: `buildVersion`, `buildGroup`,
`buildGroup`, `buildName`, `buildTime`, `gitShortCommitId`, `gitCommitId`,
`gitBranch`, and `gitCommitTime`.

View File

@@ -0,0 +1,82 @@
[[dynamic-command-exitcode-annotation]]
= @ExceptionResolver
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
`@ShellComponent` classes can have `@ExceptionResolver` methods to handle exceptions from component
methods. These are meant for annotated methods.
The exception may match against a top-level exception being propagated (e.g. a direct IOException
being thrown) or against a nested cause within a wrapper exception (e.g. an IOException wrapped
inside an IllegalStateException). This can match at arbitrary cause levels.
For matching exception types, preferably declare the target exception as a method argument, as
the preceding example(s) shows. When multiple exception methods match, a root exception match is
generally preferred to a cause exception match. More specifically, the ExceptionDepthComparator
is used to sort exceptions based on their depth from the thrown exception type.
Alternatively, the annotation declaration may narrow the exception types to match, as the
following example shows:
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-type-in-annotation]
----
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-type-in-method]
----
`@ExceptionResolver` can also return `String` which is used as an output to console. You can
use `@ExitCode` annotation to define return code.
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-exitcode-annotation]
----
`@ExceptionResolver` with `void` return type is automatically handled as handled exception.
You can then also define `@ExitCode` and use `Terminal` if you need to write something
into console.
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-void]
----
[[method-arguments]]
== Method Arguments
`@ExceptionResolver` methods support the following arguments:
[Attributes]
|===
|Method argument |Description
|Exception type
|For access to the raised exception. This is any type of `Exception` or `Throwable`.
|Terminal
|For access to underlying `JLine` terminal to i.e. get its terminal writer.
|===
[[return-values]]
== Return Values
`@ExceptionResolver` methods support the following return values:
[Attributes]
|===
|Return value |Description
|String
|Plain text to return to a shell. Exit code 1 is used in this case.
|CommandHandlingResult
|Plain `CommandHandlingResult` having message and exit code.
|void
|A method with a void return type is considered to have fully handled the exception. Usually
you would define `Terminal` as a method argument and write response using _terminal writer_
from it. As exception is fully handled, Exit code 0 is used in this case.
|===

View File

@@ -0,0 +1,18 @@
[[dynamic-command-exitcode]]
= Exception Handling
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
Exceptions happen from a user code wether it is intentional or not. This section describes
how `spring-shell` handles exceptions and gives instructions and best practices how to
work with it.
Many command line applications when applicable return an _exit code_ which running environment
can use to differentiate if command has been executed successfully or not. In a `spring-shell`
this mostly relates when a command is run on a non-interactive mode meaning one command
is always executed once with an instance of a `spring-shell`. Take a note that _exit code_
always relates to non-interactive shell.

View File

@@ -0,0 +1,31 @@
[[dynamic-command-exitcode-mappings]]
= Exit Code Mappings
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
Default behaviour of an exit codes is as:
- Errors from a command option parsing will result code of `2`
- Any generic error will result result code of `1`
- Obviously in any other case result code is `0`
Every `CommandRegistration` can define its own mappings between _Exception_ and _exit code_.
Essentially we're bound to functionality in `Spring Boot` regarding _exit code_ and simply
integrate into that.
Assuming there is an exception show below which would be thrown from a command:
[source, java, indent=0]
----
include::{snippets}/ExitCodeSnippets.java[tag=my-exception-class]
----
It is possible to define a mapping function between `Throwable` and exit code. You can also
just configure a _class_ to _exit code_ which is just a syntactic sugar within configurations.
[source, java, indent=0]
----
include::{snippets}/ExitCodeSnippets.java[tag=example1]
----
NOTE: Exit codes cannot be customized with annotation based configuration

View File

@@ -0,0 +1,48 @@
[[dynamic-command-exitcode-resolving]]
= Exception Resolving
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
Unhandled exceptions will bubble up into shell's `ResultHandlerService` and then eventually
handled by some instance of `ResultHandler`. Chain of `ExceptionResolver` implementations
can be used to resolve exceptions and gives you flexibility to return message to get written
into console together with exit code which are wrapped within `CommandHandlingResult`.
`CommandHandlingResult` may contain a _message_ and/or _exit code_.
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=my-exception-resolver-class]
----
`CommandExceptionResolver` implementations can be defined globally as bean.
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=my-exception-resolver-class-as-bean]
----
or defined per `CommandRegistration` if it's applicable only for a particular command itself.
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=example1]
----
NOTE: Resolvers defined with a command are handled before global resolvers.
Use you own exception types which can also be an instance of boot's `ExitCodeGenerator` if
you want to define exit code there.
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=my-exception-class]
----
Some build in `CommandExceptionResolver` beans are registered to handle common
exceptions thrown from command parsing. These are registered with _order_
presedence defined in `CommandExceptionResolver.DEFAULT_PRECEDENCE`.
As these beans are used in a given order, `@Order` annotation or `Ordered`
interface from can be used just like in any other spring app. This
is generally useful if you need to control your own beans to get used
either before or after a defaults.

View File

@@ -0,0 +1,38 @@
[[commands-helpoptions]]
= Help Options
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
_Spring Shell_ has a build-in `help` command but not all favour getting command help
from it as you always need to call it with arguments for target command. It's
common in many cli frameworks for every command having options _--help_ and _-h_
to print out command help.
Default functionality is that every command will get modified to have options
_--help_ and _-h_, which if present in a given command will automatically
short circuit command execution into a existing `help` command regardless
what other command-line options is typed.
Below example shows its default settings.
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationHelpOptionsSnippets.java[tag=defaults]
----
It is possible to change default behaviour via configuration options.
[source, yaml]
----
spring:
shell:
help:
enabled: true
long-names: help
short-names: h
command: help
----
NOTE: Commands defined programmationally or via annotations will automatically add
help options. With annotation model you can only turn things off globally, programmatic
model gives option to modify settings per command.

View File

@@ -0,0 +1,26 @@
[[commands-hidden]]
= Hidden Command
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
It is possible to _hide_ a command which is convenient in cases where it is not yet ready for
prime time, is meant for debugging purposes or you have any other reason you dont want to
advertise its presense.
Hidden command can be executed if you know it and its options. It is effectively removed
from:
* Help listing
* Help page for command return "unknown command"
* Command completion in interactive mode
* Bash completion
Below is an example how to define command as _hidden_. It shows available builder methods
to define _hidden_ state.
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationHiddenSnippets.java[tag=snippet1]
----
NOTE: Defining hidden commands is not supported with annotation based configuration

View File

@@ -0,0 +1,18 @@
[[commands]]
= Commands
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
In this section, we go through an actual command registration and leave command options
and execution for later in a documentation. You can find more detailed info in
xref:appendices/techintro/registration.adoc[Command Registration].

View File

@@ -0,0 +1,22 @@
[[commands-interactionmode]]
= Interaction Mode
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
Command registration can define `InteractionMode` which is used to hide commands
depending which mode shell is executing. More about that in xref:execution.adoc#using-shell-execution-interactionmode[Interaction Mode].
You can define it with `CommandRegisration`.
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationInteractionModeSnippets.java[tag=snippet1]
----
Or with `@ShellMethod`.
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationInteractionModeSnippets.java[tag=snippet2]
----

View File

@@ -0,0 +1,52 @@
[[organizing-commands]]
= Organizing Commands
When your shell starts to provide a lot of functionality, you may end up
with a lot of commands, which could be confusing for your users. By typing `help`,
they would see a daunting list of commands, organized in alphabetical order,
which may not always be the best way to show the available commands.
To alleviate this possible confusion, Spring Shell provides the ability to group commands together,
with reasonable defaults. Related commands would then end up in the same group (for example, `User Management Commands`)
and be displayed together in the help screen and other places.
By default, commands are grouped according to the class they are implemented in,
turning the camelCase class name into separate words (so `URLRelatedCommands` becomes `URL Related Commands`).
This is a sensible default, as related commands are often already in the class anyway,
because they need to use the same collaborating objects.
If, however, this behavior does not suit you, you can override the group for a
command in the following ways, in order of priority:
. Specify a `group()` in the `@ShellMethod` annotation.
. Place a `@ShellCommandGroup` on the class in which the command is defined. This applies
the group for all commands defined in that class (unless overridden, as explained earlier).
. Place a `@ShellCommandGroup` on the package (through `package-info.java`)
in which the command is defined. This applies to all the commands defined in the
package (unless overridden at the method or class level, as explained earlier).
The following listing shows an example:
[source,java]
----
public class UserCommands {
@ShellMethod(value = "This command ends up in the 'User Commands' group")
public void foo() {}
@ShellMethod(value = "This command ends up in the 'Other Commands' group",
group = "Other Commands")
public void bar() {}
}
...
@ShellCommandGroup("Other Commands")
public class SomeCommands {
@ShellMethod(value = "This one is in 'Other Commands'")
public void wizz() {}
@ShellMethod(value = "And this one is 'Yet Another Group'",
group = "Yet Another Group")
public void last() {}
}
----

View File

@@ -0,0 +1,45 @@
[[commands-registration-annotation]]
= Annotation
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
`@Command` annotation when used on a method marks it as a candidate for command registration.
In below example a command `example` is defined.
[source, java, indent=0]
----
include::{snippets}/CommandAnnotationSnippets.java[tag=command-anno-in-method]
----
`@Command` annotation can be placed on a class which either defines defaults or shared settings
for `@Command` methods defined in a same class. In below example a command `parent example` is
defined.
[source, java, indent=0]
----
include::{snippets}/CommandAnnotationSnippets.java[tag=command-anno-in-class]
----
Using a `@Command` will not automatically register command targets, instead it is required to use
`@EnableCommand` and/or `@CommandScan` annotations. This model is familiar from other parts
of Spring umbrella and provides better flexibility for a user being inclusive rather than exclusive
for command targets.
You can define target classes using `@EnableCommand`. It will get picked from all _Configuration_
classes.
[source, java, indent=0]
----
include::{snippets}/CommandAnnotationSnippets.java[tag=enablecommand-with-class]
----
You can define target classes using `@CommandScan`. It will get picked from all _Configuration_
classes.
TIP: Define `@CommandScan` in Spring Boot `App` class on a top level and it will automatically
scan all command targets from all packages and classes under `App`.
[source, java, indent=0]
----
include::{snippets}/CommandAnnotationSnippets.java[tag=commandscan-no-args]
----

View File

@@ -0,0 +1,21 @@
[[registration]]
= Registration
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
There are two different ways to define a command: through an annotation model and
through a programmatic model. In the annotation model, you define your methods
in a class and annotate the class and the methods with specific annotations.
In the programmatic model, you use a more low level approach, defining command
registrations (either as beans or by dynamically registering with a command catalog).
Starting from _3.1.x_ a better support for defining commands using
xref:commands/registration/annotation.adoc[annotations] were added. Firstly because eventually standard
package providing xref:commands/registration/legacyannotation.adoc[legacy annotations] will get deprecated
and removed. Secondly so that we're able to provide same set of features than using underlying
`CommandRegistration`. Creating new a annotation model allows us to rethink and modernise that
part without breaking existing applications.

View File

@@ -0,0 +1,48 @@
[[commands-registration-legacyannotation]]
= Legacy Annotation
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
When you use the standard API, methods on beans are turned into executable commands, provided that:
* The bean class bears the `@ShellComponent` annotation. (This is used to restrict the set of beans
that are considered.)
* The method bears the `@ShellMethod` annotation.
[TIP]
====
The `@ShellComponent` is a stereotype annotation that is itself meta-annotated with `@Component`. As a result,
you can use it in addition to the filtering mechanism to declare beans (for example, by using `@ComponentScan`).
You can customize the name of the created bean by using the `value` attribute of the annotation.
====
[source, java, indent=0]
----
include::{snippets}/AnnotationRegistrationSnippets.java[tag=snippet1]
----
The only required attribute of the `@ShellMethod` annotation is its `value` attribute, which should have
a short, one-sentence, description of what the command does. This lets your users
get consistent help about your commands without having to leave the shell (see xref:commands/builtin/help.adoc[Help]).
NOTE: The description of your command should be short -- no more than one or two sentences. For better
consistency, it should start with a capital letter and end with a period.
By default, you need not specify the key for your command (that is, the word(s) that should be used
to invoke it in the shell). The name of the method is used as the command key, turning camelCase names into
dashed, gnu-style, names (for example, `sayHello()` becomes `say-hello`).
You can, however, explicitly set the command key, by using the `key` attribute of the annotation:
[source, java, indent=0]
----
include::{snippets}/AnnotationRegistrationSnippets.java[tag=snippet2]
----
NOTE: The `key` attribute accepts multiple values.
If you set multiple keys for a single method, the command is registered with those different aliases.
TIP: The command key can contain pretty much any character, including spaces. When coming up with names though,
keep in mind that consistency is often appreciated by users. That is, you should avoid mixing dashed-names with
spaced names and other inconsistencies.

View File

@@ -0,0 +1,36 @@
[[commands-registration-programmatic]]
= Programmatic
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
In the programmatic model, `CommandRegistration` can be defined as a `@Bean`
and it will be automatically registered.
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationBeanSnippets.java[tag=plain]
----
If all your commands have something in common, an instance of
a _CommandRegistration.BuilderSupplier_ is created which can
be autowired. Default implementation of this supplier returns
a new builder so you don't need to worry about its internal state.
IMPORTANT: Commands registered programmatically automatically
add _help options_ mentioned in xref:commands/helpoptions.adoc[Help Options].
If bean of this supplier type is defined then auto-configuration
will back off giving you an option to redefine default functionality.
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationBeanSnippets.java[tag=fromsupplier]
----
`CommandRegistrationCustomizer` beans can be defined if you want to centrally
modify builder instance given you by supplier mentioned above.
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationBeanSnippets.java[tag=customizer]
----

View File

@@ -0,0 +1,25 @@
[[writing]]
= Writing
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
When something needs to get written into your console you can always
use JDK's `System.out` which then goes directly into JDK's own streams.
Other recommended way is to use JLine's `Terminal` and get _writer_
instance from there.
If using target endpoints, i.e. _consumer_ which is not expected
to return anything given `CommandContext` contains reference to
`Terminal` and writer can be accessed from there.
[source, java, indent=0]
----
include::{snippets}/WritingSnippets.java[tag=reg-terminal-writer]
----
It's possible to autowire `Terminal` to get access to its writer.
[source, java, indent=0]
----
include::{snippets}/WritingSnippets.java[tag=anno-terminal-writer]
----