1
2
3
4
5
6 package gov.nist.secauto.metaschema.cli.commands.metapath;
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 import gov.nist.secauto.metaschema.cli.processor.command.AbstractTerminalCommand;
12 import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor;
13 import gov.nist.secauto.metaschema.core.metapath.StaticContext;
14 import gov.nist.secauto.metaschema.core.metapath.function.FunctionService;
15 import gov.nist.secauto.metaschema.core.metapath.function.IArgument;
16 import gov.nist.secauto.metaschema.core.metapath.function.IFunction;
17
18 import org.apache.commons.cli.CommandLine;
19 import org.apache.logging.log4j.LogManager;
20 import org.apache.logging.log4j.Logger;
21
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.stream.Collectors;
28
29 import edu.umd.cs.findbugs.annotations.NonNull;
30
31
32
33
34
35 class ListFunctionsSubcommand
36 extends AbstractTerminalCommand {
37 private static final Logger LOGGER = LogManager.getLogger(ListFunctionsSubcommand.class);
38
39 @NonNull
40 private static final String COMMAND = "list-functions";
41
42 @Override
43 public String getName() {
44 return COMMAND;
45 }
46
47 @Override
48 public String getDescription() {
49 return "Get a listing of supported Metapath functions";
50 }
51
52 @Override
53 public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine cmdLine) {
54 return ICommandExecutor.using(callingContext, cmdLine, this::executeCommand);
55 }
56
57
58
59
60
61
62
63
64
65
66 @SuppressWarnings({
67 "PMD.OnlyOneReturn",
68 "PMD.AvoidInstantiatingObjectsInLoops",
69 "PMD.CognitiveComplexity"
70 })
71 protected ExitStatus executeCommand(
72 @NonNull CallingContext callingContext,
73 @NonNull CommandLine cmdLine) {
74
75 Map<String, Map<String, List<IFunction>>> namespaceToNameToFunctionMap = FunctionService.getInstance().stream()
76 .collect(Collectors.groupingBy(
77 function -> function.getQName().getNamespaceURI(),
78 Collectors.groupingBy(
79 IFunction::getName,
80 Collectors.toList())));
81
82 Map<String, String> namespaceToPrefixMap = StaticContext.getWellKnownNamespacesMap().entrySet().stream()
83 .collect(Collectors.toMap(entry -> entry.getValue().toASCIIString(), Map.Entry::getKey));
84
85 List<String> namespaces = new ArrayList<>(namespaceToNameToFunctionMap.keySet());
86
87 Collections.sort(namespaces);
88
89 for (String namespace : namespaces) {
90 String prefix = namespaceToPrefixMap.get(namespace);
91
92 if (prefix == null) {
93 LOGGER.atInfo().log("In namespace '{}':", namespace);
94 } else {
95 LOGGER.atInfo().log("In namespace '{}' as '{}':", namespace, prefix);
96 }
97
98 Map<String, List<IFunction>> namespacedFunctions = namespaceToNameToFunctionMap.get(namespace);
99
100 List<String> names = new ArrayList<>(namespacedFunctions.keySet());
101 Collections.sort(names);
102
103 for (String name : names) {
104 List<IFunction> functions = namespacedFunctions.get(name);
105 Collections.sort(functions, Comparator.comparing(IFunction::arity));
106
107 for (IFunction function : functions) {
108 String functionRef = prefix == null
109 ? String.format("Q{%s}%s", function.getQName().getNamespaceURI(), function.getName())
110 : String.format("%s:%s", prefix, function.getName());
111
112 LOGGER.atInfo().log(String.format("%s(%s) as %s",
113 functionRef,
114 function.getArguments().isEmpty()
115 ? ""
116 : function.getArguments().stream().map(IArgument::toSignature)
117 .collect(Collectors.joining(","))
118 + (function.isArityUnbounded() ? ", ..." : ""),
119 function.getResult().toSignature()));
120 }
121 }
122 }
123 return ExitCode.OK.exit();
124 }
125 }