All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metaeffekt.artifact.analysis.utils.ArgParser Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.metaeffekt.artifact.analysis.utils;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * This class can be given a number of arguments and then parse a given args string.
* Every argument can have the following data: *
    *
  • required (Boolean)
  • *
  • identifiers (Set)
  • *
  • description (String)
  • *
  • parameterType (Argument.ParameterType: String, Integer, Long, Float, Double, Boolean, String[], Any, None)
  • *
  • parameterName (String)
  • *
  • defaultParameterValue (String, Integer, Long, Float, Double, Boolean, String[])
  • *
  • validParameterValues (Set)
  • *
  • parameterRequired (Boolean)
  • *
* When parsing the args string, the syntax is checked first. If any invalid values are found, an exception with a * fitting error message is thrown.

*

* If the args string was parsable, a Results object is returned containing the individual argument data. */ public class ArgParser implements Iterable { private final Set arguments = new HashSet<>(); private String prefix = null; private boolean prefixRequired = false; private boolean failOnDoubleArguments = true; public ArgParser setPrefix(String prefix) { this.prefix = prefix; return this; } public ArgParser setPrefixRequired(boolean prefixRequired) { this.prefixRequired = prefixRequired; return this; } public ArgParser setFailOnDoubleArguments(boolean failOnDoubleArguments) { this.failOnDoubleArguments = failOnDoubleArguments; return this; } public ArgParser addArgument(Argument argument) { for (Argument checkArg : arguments) for (String identifier : argument.identifiers) if (checkArg.identifiers.contains(identifier)) return this; arguments.add(argument); return this; } public boolean removeArgument(Argument argument) { return arguments.remove(argument); } public boolean matches(String args) { try { parse(args); return true; } catch (Exception e) { return false; } } public boolean matches(String[] args) { try { parse(args); return true; } catch (Exception e) { return false; } } public Results parse(String[] args) { return parse(String.join(" ", args)); } public Results parse(String args) { if (prefix != null && prefix.length() > 0) { if (prefixRequired && !args.matches("^" + prefix + ".*")) throw new ArgParserException("Missing prefix '" + prefix + "' for input: " + args); args = args.replaceAll("^" + prefix, ""); } return parseInputStringArray(args.trim().split(" ")); } private Results parseInputStringArray(String[] args) { List remainingArguments = new ArrayList<>(arguments); List results = new ArrayList<>(); int currentArgumentIndex = 0; // find arguments for (int i = 0; i < args.length && remainingArguments.size() > 0; i++) { int finalI = i; Argument currentArgument = remainingArguments.stream().filter(arg -> arg.containsIdentifier(args[finalI])).findFirst().orElse(null); if (currentArgument != null) { remainingArguments.remove(currentArgument); StringBuilder parameterBuilder = new StringBuilder(); while (true) { i++; if (i < args.length) { int finalI2 = i; if (remainingArguments.stream().anyMatch(arg -> arg.containsIdentifier(args[finalI2]))) { i--; break; } else { if (arguments.stream().filter(arg -> arg.containsIdentifier(args[finalI2])).findFirst().orElse(null) != null) { if (failOnDoubleArguments) { String highlighted = String.join(" ", args); for (String identifier : currentArgument.identifiers) highlighted = highlightIdentifier(highlighted, identifier); throw new ArgParserException("Argument appears twice in args string\n" + currentArgument + "\n" + highlighted); } else { i--; break; } } } if (parameterBuilder.length() > 0) parameterBuilder.append(" "); parameterBuilder.append(args[finalI2]); } else break; } String parameter = parameterBuilder.toString(); if (parameter.length() > 0) { if (!currentArgument.hasParameterCorrectType(parameter)) throw new ArgParserException("Argument parameter is of wrong type\n" + currentArgument + "\nGot: " + parameter + "\nExpected: " + currentArgument.parameterType.toString().toLowerCase()); if (!currentArgument.parameterIsInValidValues(parameter)) throw new ArgParserException("Argument parameter is not in allowed values set\n" + currentArgument + "\nGot: " + parameter + "\nExpected: " + String.join(",", currentArgument.validParameterValues)); } else { if (currentArgument.parameterRequired) throw new ArgParserException("Missing argument parameter\n" + currentArgument + "\nExpected: " + currentArgument.parameterType.toString().toLowerCase()); parameter = null; } if (parameter == null) { if (currentArgument.defaultParameterValue != null) results.add(new Result(currentArgument, currentArgumentIndex, currentArgument.defaultParameterValue)); else results.add(new Result(currentArgument, currentArgumentIndex, null)); } else { results.add(new Result(currentArgument, currentArgumentIndex, parameter)); } currentArgumentIndex++; } } // check if there are still any required arguments for (Argument currentArgument : remainingArguments) if (currentArgument.required) throw new ArgParserException("Invalid argument syntax for '" + currentArgument + "' in '" + String.join(" ", args) + "'"); // set default values for (Argument currentArgument : remainingArguments) if (currentArgument.defaultParameterValue != null) { results.add(new Result(currentArgument, currentArgumentIndex, currentArgument.defaultParameterValue)); currentArgumentIndex++; } return new Results(results); } public String commandSyntax() { List sortedArguments = arguments.stream().sorted().collect(Collectors.toList()); StringBuilder syntax = new StringBuilder(); if (prefix != null && prefix.length() > 0) syntax.append(prefixRequired ? "" : "[").append(prefix).append(prefixRequired ? "" : "]"); for (Argument argument : sortedArguments) syntax.append(syntax.length() == 0 ? "" : " ").append(argument); return syntax.toString(); } public String toString(boolean verbose) { StringBuilder header = new StringBuilder(); if (prefix != null && prefix.length() > 0) header.append(prefixRequired ? "" : "[").append(prefix).append(prefixRequired ? "" : "]"); List sortedArguments = arguments.stream().sorted().collect(Collectors.toList()); for (Argument argument : sortedArguments) header.append(" ").append(argument); StringBuilder args = new StringBuilder(); if (verbose) { for (Argument argument : sortedArguments) if (argument.description != null && argument.description.length() > 0) { if (args.length() > 0) args.append("\n"); args.append(" ").append(argument).append("\n"); args.append(" ").append(argument.description); } } return header + (args.length() > 0 ? "\n" + args : ""); } @Override public String toString() { return toString(true); } public Stream stream() { return arguments.stream(); } @Override public Iterator iterator() { return arguments.iterator(); } public static class Results implements Iterable { private final List results; public Results(List results) { this.results = results; } public List getResults() { return results; } public Result getResult(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().orElse(null); } public String getParameter(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().map(Result::getParameter).orElse(null); } public String get(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().map(Result::getParameter).orElse(null); } public int getIndex(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().map(Result::getIndex).orElse(-1); } public Argument getArgument(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().map(Result::getArgument).orElse(null); } public String getParameter(Argument argument) { return results.stream().filter(result -> result.argument == argument).findFirst().map(Result::getParameter).orElse(null); } public int getIndex(Argument argument) { return results.stream().filter(result -> result.argument == argument).findFirst().map(Result::getIndex).orElse(-1); } public boolean isPresent(String identifier) { return results.stream().anyMatch(result -> result.argument.identifiers.contains(identifier)); } public boolean isAbsent(String identifier) { return results.stream().noneMatch(result -> result.argument.identifiers.contains(identifier)); } public String getString(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().map(Result::getString).orElse(null); } public String[] getStringArray(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().map(Result::getStringArray).orElse(null); } public boolean getBoolean(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().map(Result::getBoolean).orElse(false); } public float getFloat(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().map(Result::getFloat).orElse(-1f); } public double getDouble(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().map(Result::getDouble).orElse(-1d); } public long getLong(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().map(Result::getLong).orElse(-1L); } public int getInt(String identifier) { return results.stream().filter(result -> result.argument.identifiers.contains(identifier)).findFirst().map(Result::getInt).orElse(-1); } public Stream stream() { return results.stream(); } @Override public Iterator iterator() { return results.iterator(); } } public static class Result { private final Argument argument; private final int index; private final String parameter; private Result(Argument argument, int index, String parameter) { this.argument = argument; this.index = index; this.parameter = parameter; } public Argument getArgument() { return argument; } public int getIndex() { return index; } public String getParameter() { return parameter; } public String getString() { return parameter; } public String[] getStringArray() { return parameter.split(" "); } public boolean getBoolean() { return parameter.toLowerCase().matches("(true|1)"); } public float getFloat() { return Float.parseFloat(parameter); } public double getDouble() { return Double.parseDouble(parameter); } public long getLong() { return Long.parseLong(parameter); } public int getInt() { return Integer.parseInt(parameter); } } public static class Argument implements Comparable { private ParameterType parameterType = ParameterType.NONE; private String parameterName = null; private String defaultParameterValue = null; private final Set validParameterValues = new HashSet<>(); private boolean parameterRequired = false; private boolean required = false; private final Set identifiers = new HashSet<>(); private String description = null; public Argument() { } public Argument setParameterType(ParameterType parameterType) { this.parameterType = parameterType; return this; } public Argument setParameterRequired(boolean parameterRequired) { this.parameterRequired = parameterRequired; return this; } public Argument setRequired(boolean required) { this.required = required; return this; } public Argument setDescription(String description) { this.description = description; return this; } public Argument setParameterName(String parameterName) { this.parameterName = parameterName; return this; } public Argument setDefaultParameterValue(String defaultParameterValue) { this.defaultParameterValue = defaultParameterValue; return this; } public Argument setDefaultParameterValue(boolean defaultParameterValue) { this.defaultParameterValue = "" + defaultParameterValue; return this; } public Argument setDefaultParameterValue(double defaultParameterValue) { this.defaultParameterValue = "" + defaultParameterValue; return this; } public Argument setDefaultParameterValue(float defaultParameterValue) { this.defaultParameterValue = "" + defaultParameterValue; return this; } public Argument setDefaultParameterValue(int defaultParameterValue) { this.defaultParameterValue = "" + defaultParameterValue; return this; } public Argument setDefaultParameterValue(long defaultParameterValue) { this.defaultParameterValue = "" + defaultParameterValue; return this; } public Argument setDefaultParameterValue(String[] defaultParameterValue) { this.defaultParameterValue = String.join(" ", defaultParameterValue); return this; } public Argument addIdentifier(String... identifier) { identifiers.addAll(Arrays.stream(identifier).collect(Collectors.toSet())); return this; } public Argument removeIdentifier(String identifier) { identifiers.remove(identifier); return this; } public Argument addValidParameterValue(String... value) { validParameterValues.addAll(Arrays.stream(value).collect(Collectors.toSet())); return this; } public Argument addValidParameterValue(List values) { validParameterValues.addAll(values); return this; } public Argument removeValidParameterValue(String value) { validParameterValues.remove(value); return this; } public boolean isRequired() { return required; } public String getDescription() { return description; } public Set getIdentifiers() { return identifiers; } public ParameterType getParameterType() { return parameterType; } public String getDefaultParameterValue() { return defaultParameterValue; } public String getParameterName() { return parameterName; } public boolean containsIdentifier(String identifier) { return identifiers.contains(identifier); } public boolean hasParameterCorrectType(String parameter) { switch (parameterType) { case STRING: case STRING_ARRAY: case ANY: return parameter != null; case INTEGER: return parameter.matches("-?\\d{1,10}"); case LONG: return parameter.matches("-?\\d{1,19}"); case FLOAT: case DOUBLE: return parameter.matches("-?[0-9]*\\.?[0-9]+"); case BOOLEAN: return parameter.toLowerCase().matches("(true|false|1|0)"); } return false; } public boolean parameterIsInValidValues(String parameter) { return validParameterValues.size() == 0 || validParameterValues.contains(parameter); } @Override public String toString() { StringBuilder arg = new StringBuilder(); arg.append(required ? "" : "["); arg.append(identifiers.stream().sorted().collect(Collectors.joining(","))); if (parameterType != ParameterType.NONE) { arg.append(parameterRequired ? " <" : " ["); if (parameterName != null) arg.append(parameterName).append(":"); if (validParameterValues.size() > 0) arg.append(validParameterValues.stream().sorted().collect(Collectors.joining("|"))); else arg.append(parameterType.toString().toLowerCase()); arg.append(parameterRequired ? ">" : "]"); } arg.append(required ? "" : "]"); return arg.toString(); } @Override public int compareTo(Argument o) { int required = Boolean.compare(o.required, this.required); if (required == 0 && identifiers.size() > 0 && o.identifiers.size() > 0) return identifiers.stream().findAny().orElse("z").replace("-", "").compareTo(o.identifiers.stream().findAny().orElse("z").replace("-", "")); return required; } public enum ParameterType { STRING, STRING_ARRAY, INTEGER, LONG, FLOAT, DOUBLE, BOOLEAN, ANY, NONE } } private static class ArgParserException extends IllegalArgumentException { public ArgParserException(String message) { super(message); } } private static String highlightIdentifier(String str, String highlight) { return str.replaceAll("(^| )" + highlight + "($| )", " --> " + highlight + " <-- "); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy