Dynamic Command Availability

已注册的命令并不总是合理的,这是因为应用程序的内部状态。例如,可能有一个 download 命令,但它仅在用户在远程服务器上使用 connect 后才起作用。现在,如果用户尝试使用 download 命令,shell 应解释该命令存在,但目前不可用。即使让你提供不可用原因的简短说明,Spring Shell 也可以让你这样做。

命令有三种可能的方法来指示可用性。它们都使用 no-arg 方法,该方法返回 Availability 的实例。请考虑以下示例:

@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");
    }
}

connect 方法用于连接到服务器(省略了详细信息),并通过 connected 布尔值在完成时更改命令的状态。download 命令在用户连接之前标记为不可用,这要归功于一个方法,其名称完全与 download 命令方法相同,并在其名称中添加了 Availability 后缀。该方法返回 Availability 的实例,该实例是由两个工厂方法之一构建的。如果命令不可用,则必须提供解释。现在,如果用户尝试在未连接时调用该命令,将会发生以下情况:

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.

有关当前不可用命令的信息也会用于集成帮助。请参阅 Help

当命令不可用时的原因应该在 “Because” 后附加时很好地阅读。 你不应该以大写字母开头句子或添加一个句号。

如果以命令方法的名称命名可用性方法不适合你,你可以使用 @ShellMethodAvailability 注解提供明确的名称:

    @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 这些名称必须匹配

最后,常常出现的情况是,同一类中的多个命令共享相同的内部状态,因此应该全部以一组形式可用或不可用。Spring Shell 让你可以颠倒过来,不用将 @ShellMethodAvailability 粘贴到所有命令方法上,而是将 @ShellMethodAvailabilty 注解放在可用性方法上,指定受其控制的命令的名称:

    @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");
    }

@ShellMethodAvailability.value() 属性的默认值是 *。此特殊通配符匹配所有命令名称。这使得通过一个可用性方法轻松地开启或关闭单个类的所有命令:

@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() {}
}

Spring Shell 没有对如何编写命令和组织类施加太多约束。但是,通常将相关命令放在同一个类中是一种良好的做法,并且可用性指示符可以从中受益。