001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package gov.nist.secauto.metaschema.cli.commands.metapath; 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; 011import gov.nist.secauto.metaschema.cli.processor.command.AbstractTerminalCommand; 012import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor; 013import gov.nist.secauto.metaschema.core.metapath.StaticContext; 014import gov.nist.secauto.metaschema.core.metapath.function.FunctionService; 015import gov.nist.secauto.metaschema.core.metapath.function.IArgument; 016import gov.nist.secauto.metaschema.core.metapath.function.IFunction; 017 018import org.apache.commons.cli.CommandLine; 019import org.apache.logging.log4j.LogManager; 020import org.apache.logging.log4j.Logger; 021 022import java.util.ArrayList; 023import java.util.Collections; 024import java.util.Comparator; 025import java.util.List; 026import java.util.Map; 027import java.util.stream.Collectors; 028 029import edu.umd.cs.findbugs.annotations.NonNull; 030 031public class ListFunctionsSubcommand 032 extends AbstractTerminalCommand { 033 private static final Logger LOGGER = LogManager.getLogger(ListFunctionsSubcommand.class); 034 035 @NonNull 036 private static final String COMMAND = "list-functions"; 037 038 @Override 039 public String getName() { 040 return COMMAND; 041 } 042 043 @Override 044 public String getDescription() { 045 return "Get a listing of supported Metapath functions"; 046 } 047 048 @Override 049 public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine cmdLine) { 050 return ICommandExecutor.using(callingContext, cmdLine, this::executeCommand); 051 } 052 053 /** 054 * Execute the list functions command. 055 * 056 * @param callingContext 057 * the context of the command execution 058 * @param cmdLine 059 * the parsed command line details 060 * @return the execution result 061 */ 062 @SuppressWarnings({ 063 "PMD.OnlyOneReturn" // readability 064 }) 065 protected ExitStatus executeCommand( 066 @NonNull CallingContext callingContext, 067 @NonNull CommandLine cmdLine) { 068 069 Map<String, Map<String, List<IFunction>>> namespaceToNameToFunctionMap = FunctionService.getInstance().stream() 070 .collect(Collectors.groupingBy( 071 function -> function.getQName().getNamespaceURI(), 072 Collectors.groupingBy( 073 IFunction::getName, 074 Collectors.toList()))); 075 076 Map<String, String> namespaceToPrefixMap = StaticContext.getWellKnownNamespacesMap().entrySet().stream() 077 .collect(Collectors.toMap(entry -> entry.getValue().toASCIIString(), Map.Entry::getKey)); 078 079 List<String> namespaces = new ArrayList<>(namespaceToNameToFunctionMap.keySet()); 080 081 Collections.sort(namespaces); 082 083 for (String namespace : namespaces) { 084 String prefix = namespaceToPrefixMap.get(namespace); 085 086 if (prefix == null) { 087 LOGGER.atInfo().log("In namespace '{}':", namespace); 088 } else { 089 LOGGER.atInfo().log("In namespace '{}' as '{}':", namespace, prefix); 090 } 091 092 Map<String, List<IFunction>> namespacedFunctions = namespaceToNameToFunctionMap.get(namespace); 093 094 List<String> names = new ArrayList<>(namespacedFunctions.keySet()); 095 Collections.sort(names); 096 097 for (String name : names) { 098 List<IFunction> functions = namespacedFunctions.get(name); 099 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}