001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package gov.nist.secauto.metaschema.cli.processor.command;
007
008import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext;
009import gov.nist.secauto.metaschema.cli.processor.ExitCode;
010import gov.nist.secauto.metaschema.cli.processor.ExitStatus;
011
012import org.apache.commons.cli.CommandLine;
013
014import java.util.Collection;
015import java.util.Collections;
016import java.util.LinkedHashMap;
017import java.util.Map;
018import java.util.stream.Collectors;
019
020import edu.umd.cs.findbugs.annotations.NonNull;
021
022public abstract class AbstractParentCommand implements ICommand {
023  @NonNull
024  private final Map<String, ICommand> commandToSubcommandHandlerMap;
025  private final boolean subCommandRequired;
026
027  @SuppressWarnings("null")
028  protected AbstractParentCommand(boolean subCommandRequired) {
029    this.commandToSubcommandHandlerMap = Collections.synchronizedMap(new LinkedHashMap<>());
030    this.subCommandRequired = subCommandRequired;
031  }
032
033  protected final void addCommandHandler(ICommand handler) {
034    String commandName = handler.getName();
035    this.commandToSubcommandHandlerMap.put(commandName, handler);
036  }
037
038  @Override
039  public ICommand getSubCommandByName(String name) {
040    return commandToSubcommandHandlerMap.get(name);
041  }
042
043  @SuppressWarnings("null")
044  @Override
045  public Collection<ICommand> getSubCommands() {
046    return Collections.unmodifiableCollection(commandToSubcommandHandlerMap.values());
047  }
048
049  @Override
050  public boolean isSubCommandRequired() {
051    return subCommandRequired;
052  }
053
054  @Override
055  public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine cmdLine) {
056    return ICommandExecutor.using(callingContext, cmdLine, this::executeCommand);
057  }
058
059  @NonNull
060  protected ExitStatus executeCommand(
061      @NonNull CallingContext callingContext,
062      @NonNull CommandLine commandLine) {
063    callingContext.showHelp();
064    ExitStatus status;
065    if (isSubCommandRequired()) {
066      status = ExitCode.INVALID_COMMAND
067          .exitMessage("Please use one of the following sub-commands: " +
068              getSubCommands().stream()
069                  .map(ICommand::getName)
070                  .collect(Collectors.joining(", ")));
071    } else {
072      status = ExitCode.OK.exit();
073    }
074    return status;
075  }
076
077}