1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.cli.processor.command;
7   
8   import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext;
9   import gov.nist.secauto.metaschema.cli.processor.ExitCode;
10  import gov.nist.secauto.metaschema.cli.processor.ExitStatus;
11  
12  import org.apache.commons.cli.CommandLine;
13  
14  import java.util.Collection;
15  import java.util.Collections;
16  import java.util.LinkedHashMap;
17  import java.util.Map;
18  import java.util.stream.Collectors;
19  
20  import edu.umd.cs.findbugs.annotations.NonNull;
21  
22  public abstract class AbstractParentCommand implements ICommand {
23    @NonNull
24    private final Map<String, ICommand> commandToSubcommandHandlerMap;
25    private final boolean subCommandRequired;
26  
27    @SuppressWarnings("null")
28    protected AbstractParentCommand(boolean subCommandRequired) {
29      this.commandToSubcommandHandlerMap = Collections.synchronizedMap(new LinkedHashMap<>());
30      this.subCommandRequired = subCommandRequired;
31    }
32  
33    protected final void addCommandHandler(ICommand handler) {
34      String commandName = handler.getName();
35      this.commandToSubcommandHandlerMap.put(commandName, handler);
36    }
37  
38    @Override
39    public ICommand getSubCommandByName(String name) {
40      return commandToSubcommandHandlerMap.get(name);
41    }
42  
43    @SuppressWarnings("null")
44    @Override
45    public Collection<ICommand> getSubCommands() {
46      return Collections.unmodifiableCollection(commandToSubcommandHandlerMap.values());
47    }
48  
49    @Override
50    public boolean isSubCommandRequired() {
51      return subCommandRequired;
52    }
53  
54    @Override
55    public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine cmdLine) {
56      return ICommandExecutor.using(callingContext, cmdLine, this::executeCommand);
57    }
58  
59    @NonNull
60    protected ExitStatus executeCommand(
61        @NonNull CallingContext callingContext,
62        @NonNull CommandLine commandLine) {
63      callingContext.showHelp();
64      ExitStatus status;
65      if (isSubCommandRequired()) {
66        status = ExitCode.INVALID_COMMAND
67            .exitMessage("Please use one of the following sub-commands: " +
68                getSubCommands().stream()
69                    .map(ICommand::getName)
70                    .collect(Collectors.joining(", ")));
71      } else {
72        status = ExitCode.OK.exit();
73      }
74      return status;
75    }
76  
77  }