Add dynamic command availability
Introduce availability concept on MethodTarget (with reason if not available) Add bridge to @CliAvailabilityIndicator to Legacy registrar Fixes #138 Add help for unavailable commands Add standard API for availability
This commit is contained in:
@@ -18,14 +18,16 @@ package org.springframework.shell.legacy;
|
||||
|
||||
import static org.springframework.util.StringUtils.collectionToDelimitedString;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.shell.Availability;
|
||||
import org.springframework.shell.ConfigurableCommandRegistry;
|
||||
import org.springframework.shell.core.CommandMarker;
|
||||
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
|
||||
import org.springframework.shell.core.annotation.CliCommand;
|
||||
import org.springframework.shell.MethodTarget;
|
||||
import org.springframework.shell.MethodTargetRegistrar;
|
||||
@@ -56,7 +58,8 @@ public class LegacyMethodTargetRegistrar implements MethodTargetRegistrar {
|
||||
ReflectionUtils.doWithMethods(clazz, method -> {
|
||||
CliCommand cliCommand = method.getAnnotation(CliCommand.class);
|
||||
for (String key : cliCommand.value()) {
|
||||
MethodTarget target = new MethodTarget(method, bean, cliCommand.help());
|
||||
Supplier<Availability> availabilityIndicator = bridgeAvailabilityIndicator(key, bean);
|
||||
MethodTarget target = new MethodTarget(method, bean, cliCommand.help(), availabilityIndicator);
|
||||
registry.register(key, target);
|
||||
commands.put(key, target);
|
||||
}
|
||||
@@ -64,6 +67,28 @@ public class LegacyMethodTargetRegistrar implements MethodTargetRegistrar {
|
||||
}
|
||||
}
|
||||
|
||||
private Supplier<Availability> bridgeAvailabilityIndicator(String commandKey, Object bean) {
|
||||
Class<?> clazz = bean.getClass();
|
||||
Set<Method> candidates = new HashSet<>();
|
||||
|
||||
ReflectionUtils.doWithMethods(clazz, candidates::add,
|
||||
method -> method.getAnnotation(CliAvailabilityIndicator.class) != null
|
||||
&& Arrays.asList(method.getAnnotation(CliAvailabilityIndicator.class).value()).contains(commandKey));
|
||||
|
||||
switch (candidates.size()) {
|
||||
case 0:
|
||||
return null;
|
||||
case 1:
|
||||
return () -> {
|
||||
boolean available = (Boolean) ReflectionUtils.invokeMethod(candidates.iterator().next(), bean);
|
||||
return available ? Availability.available() : Availability.unavailable("[Unknown reason]");
|
||||
};
|
||||
default:
|
||||
throw new IllegalStateException("Looks like there are several @" + CliAvailabilityIndicator.class.getSimpleName()
|
||||
+ " for '" + commandKey + "'. Found " + candidates);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + " contributing "
|
||||
|
||||
@@ -56,7 +56,7 @@ public class LegacyMethodTargetRegistrarTest {
|
||||
|
||||
assertThat(targets).contains(entry(
|
||||
"register module",
|
||||
new MethodTarget(LegacyCommands.REGISTER_METHOD, legacyCommands, "Register a new module" )
|
||||
MethodTarget.of("register", legacyCommands, "Register a new module")
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user