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 public class ListFunctionsSubcommand
32 extends AbstractTerminalCommand {
33 private static final Logger LOGGER = LogManager.getLogger(ListFunctionsSubcommand.class);
34
35 @NonNull
36 private static final String COMMAND = "list-functions";
37
38 @Override
39 public String getName() {
40 return COMMAND;
41 }
42
43 @Override
44 public String getDescription() {
45 return "Get a listing of supported Metapath functions";
46 }
47
48 @Override
49 public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine cmdLine) {
50 return ICommandExecutor.using(callingContext, cmdLine, this::executeCommand);
51 }
52
53
54
55
56
57
58
59
60
61
62 @SuppressWarnings({
63 "PMD.OnlyOneReturn"
64 })
65 protected ExitStatus executeCommand(
66 @NonNull CallingContext callingContext,
67 @NonNull CommandLine cmdLine) {
68
69 Map<String, Map<String, List<IFunction>>> namespaceToNameToFunctionMap = FunctionService.getInstance().stream()
70 .collect(Collectors.groupingBy(
71 function -> function.getQName().getNamespaceURI(),
72 Collectors.groupingBy(
73 IFunction::getName,
74 Collectors.toList())));
75
76 Map<String, String> namespaceToPrefixMap = StaticContext.getWellKnownNamespacesMap().entrySet().stream()
77 .collect(Collectors.toMap(entry -> entry.getValue().toASCIIString(), Map.Entry::getKey));
78
79 List<String> namespaces = new ArrayList<>(namespaceToNameToFunctionMap.keySet());
80
81 Collections.sort(namespaces);
82
83 for (String namespace : namespaces) {
84 String prefix = namespaceToPrefixMap.get(namespace);
85
86 if (prefix == null) {
87 LOGGER.atInfo().log("In namespace '{}':", namespace);
88 } else {
89 LOGGER.atInfo().log("In namespace '{}' as '{}':", namespace, prefix);
90 }
91
92 Map<String, List<IFunction>> namespacedFunctions = namespaceToNameToFunctionMap.get(namespace);
93
94 List<String> names = new ArrayList<>(namespacedFunctions.keySet());
95 Collections.sort(names);
96
97 for (String name : names) {
98 List<IFunction> functions = namespacedFunctions.get(name);
99 Collections.sort(functions, Comparator.comparing(IFunction::arity));
100
101 for (IFunction function : functions) {
102 String functionRef = prefix == null
103 ? String.format("Q{%s}%s", function.getQName().getNamespaceURI(), function.getName())
104 : String.format("%s:%s", prefix, function.getName());
105
106 LOGGER.atInfo().log(String.format("%s(%s) as %s",
107 functionRef,
108 function.getArguments().isEmpty()
109 ? ""
110 : function.getArguments().stream().map(IArgument::toSignature)
111 .collect(Collectors.joining(","))
112 + (function.isArityUnbounded() ? ", ..." : ""),
113 function.getResult().toSignature()));
114 }
115 }
116 }
117 return ExitCode.OK.exit();
118 }
119 }