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.core.util.ObjectUtils;
9   
10  import java.util.List;
11  import java.util.ServiceLoader;
12  import java.util.ServiceLoader.Provider;
13  import java.util.stream.Collectors;
14  
15  import edu.umd.cs.findbugs.annotations.NonNull;
16  import nl.talsmasoftware.lazy4j.Lazy;
17  
18  /**
19   * A service that loads commands using SPI.
20   * <p>
21   * This class implements the singleton pattern to ensure a single instance of
22   * the command service is used throughout the application.
23   *
24   * @see ServiceLoader for more information
25   */
26  public final class CommandService {
27    private static final Lazy<CommandService> INSTANCE = Lazy.lazy(CommandService::new);
28    @NonNull
29    private final ServiceLoader<ICommand> loader;
30  
31    /**
32     * Get the singleton instance of the function service.
33     *
34     * @return the service instance
35     */
36    public static CommandService getInstance() {
37      return INSTANCE.get();
38    }
39  
40    /**
41     * Construct a new service.
42     * <p>
43     * Initializes the ServiceLoader for ICommand implementations.
44     * <p>
45     * This constructor is private to enforce the singleton pattern.
46     */
47    private CommandService() {
48      ServiceLoader<ICommand> loader = ServiceLoader.load(ICommand.class);
49      assert loader != null;
50      this.loader = loader;
51    }
52  
53    /**
54     * Get the function service loader instance.
55     *
56     * @return the service loader instance.
57     */
58    @NonNull
59    private ServiceLoader<ICommand> getLoader() {
60      return loader;
61    }
62  
63    /**
64     * Get the loaded commands.
65     *
66     * @return the list of loaded commands
67     */
68    @NonNull
69    public List<ICommand> getCommands() {
70      return ObjectUtils.notNull(getLoader().stream()
71          .map(Provider<ICommand>::get)
72          .collect(Collectors.toUnmodifiableList()));
73    }
74  }