コマンドの可用性

アプリケーションの内部状態により、登録されたコマンドが必ずしも意味を成すとは限りません。例: download コマンドがあるかもしれませんが、ユーザーが リモートサーバーで connect を使用した場合にのみ機能します。これで、ユーザーが download コマンドを使用しようとすると、シェルはコマンドが存在するが、その時点では使用できないことを説明する必要があります。Spring Shell を使用すると、コマンドが使用できない理由の簡単な説明を提供することさえできます。

プログラマティック

プログラムによる登録では、Supplier<Availability> を受け取る availability メソッドを使用できます。

private boolean connected;

@Bean
public CommandRegistration connect(
		CommandRegistration.BuilderSupplier builder) {
	return builder.get()
		.command("connect")
		.withOption()
			.longNames("connected")
			.required()
			.type(boolean.class)
			.and()
		.withTarget()
			.consumer(ctx -> {
				boolean connected = ctx.getOptionValue("connected");
				this.connected = connected;
			})
			.and()
		.build();
}

@Bean
public CommandRegistration download(
		CommandRegistration.BuilderSupplier builder) {
	return builder.get()
		.command("download")
		.availability(() -> {
			return connected
				? Availability.available()
				: Availability.unavailable("you are not connected");
		})
		.withTarget()
			.consumer(ctx -> {
				// do something
			})
			.and()
		.build();
}

アノテーション

アノテーションベースのコマンドでは、@CommandAvailability と AvailabilityProvider を一緒に使用できます。

@Command
class MyCommands {

	private boolean connected;

	@Command(command = "connect")
	public void connect(String user, String password) {
		connected = true;
	}


	@Command(command = "download")
	@CommandAvailability(provider = "downloadAvailability")
	public void download(
	) {
		// do something
	}

	@Bean
	public AvailabilityProvider downloadAvailability() {
		return () -> connected
			? Availability.available()
			: Availability.unavailable("you are not connected");
	}
}

従来のアノテーション

コマンドが可用性を示すには、3 つの方法があります。それらはすべて、Availability のインスタンスを返す引数なしのメソッドを使用します。次の例を検討してください。

@ShellComponent
public class MyCommands {

	private boolean connected;

	@ShellMethod("Connect to the server.")
	public void connect(String user, String password) {
		// do something
		connected = true;
	}

	@ShellMethod("Download the nuclear codes.")
	public void download() {
		// do something
	}

	public Availability downloadAvailability() {
		return connected
			? Availability.available()
			: Availability.unavailable("you are not connected");
	}
}

connect メソッドはサーバーへの接続に使用され (詳細は省略)、完了時に connected ブール値を介してコマンドの状態を変更します。download コマンドは、名前に Availability サフィックスが付いた download コマンドメソッドとまったく同じ名前のメソッドが存在するため、ユーザーが接続するまで使用できないとマークされます。このメソッドは、2 つのファクトリメソッドのいずれかで構築された 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.

現在使用できないコマンドに関する情報も、統合ヘルプで使用されます。ヘルプを参照してください。

コマンドが使用できない場合に提供される理由は、"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 名前は一致する必要があります

最後に、同じクラスの複数のコマンドが同じ内部状態を共有することがよくあるため、グループとしてすべてを使用可能または使用不可にする必要があります。すべてのコマンドメソッドに @ShellMethodAvailability を貼り付ける代わりに、Spring Shell を使用すると、状況を反転させて可用性メソッドに @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 は、コマンドの書き方やクラスの編成方法に多くの制約を課していません。ただし、関連するコマンドを同じクラスに配置することは、多くの場合良い方法であり、可用性インジケーターはそれによって恩恵を受けることができます。