co.cask.cdap.cli.util.ArgumentParser.java Source code

Java tutorial

Introduction

Here is the source code for co.cask.cdap.cli.util.ArgumentParser.java

Source

/*
 * Copyright  2014 Cask Data, Inc.
 *
 * 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 co.cask.cdap.cli.util;

import co.cask.cdap.cli.ProgramIdArgument;
import co.cask.common.cli.util.Parser;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static co.cask.common.cli.util.Parser.MANDATORY_ARG_BEGINNING;
import static co.cask.common.cli.util.Parser.MANDATORY_ARG_ENDING;
import static co.cask.common.cli.util.Parser.OPTIONAL_PART_BEGINNING;
import static co.cask.common.cli.util.Parser.OPTIONAL_PART_ENDING;

/**
 * Utility class for parsing arguments from user input based on command pattern.
 */
public class ArgumentParser {

    /**
     * Parses a map in the format: "key1=a key2=b .."
     *
     * @param mapString {@link String} representation of the map
     * @return the map
     */
    public static Map<String, String> parseMap(String mapString) {
        if (mapString == null || mapString.isEmpty()) {
            return ImmutableMap.of();
        }

        ImmutableMap.Builder<String, String> result = ImmutableMap.builder();
        List<String> tokens = Parser.parseInput(mapString);
        for (String token : tokens) {
            int firstEquals = token.indexOf('=');
            if (firstEquals > 0) {
                String key = token.substring(0, firstEquals);
                String value = token.substring(firstEquals + 1, token.length());
                result.put(extractValue(key), extractValue(value));
            }
        }
        return result.build();
    }

    /**
     * @param value string that may be surrounded by quotes
     * @return unquoted string if quoted, otherwise the original string
     */
    private static String extractValue(String value) {
        if ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith("\"") && value.endsWith("\""))) {
            return value.substring(1, value.length() - 1);
        }
        return value;
    }

    /**
     * Parses program id from user input.
     *
     * @param programId the program id
     * @return ProgramIdArgument
     */
    public static ProgramIdArgument parseProgramId(String programId) {
        if (programId == null) {
            return null;
        }
        String[] split = programId.split("\\.");
        if (split.length != 2) {
            return null;
        }
        return new ProgramIdArgument(split[0], split[1]);
    }

    /**
     * Parses params from user input.
     *
     * @param input user input to be parsed
     * @param pattern pattern by which to parse
     * @return parsed params
     */
    public static Map<String, String> getArguments(String input, String pattern) {
        if (input == null || pattern == null) {
            return Collections.emptyMap();
        }
        input = cutNotFullyEnteredToken(input);
        Map<String, String> arguments = Maps.newHashMap();
        List<String> patternTokens = Parser.parsePattern(pattern);
        List<String> inputTokens = Parser.parseInput(input);
        while (!patternTokens.isEmpty() && !inputTokens.isEmpty()) {
            String patternPart = patternTokens.get(0);
            String inputPart = inputTokens.get(0);
            if (patternPart.startsWith((Character.toString(OPTIONAL_PART_BEGINNING)))
                    && patternPart.endsWith((Character.toString(OPTIONAL_PART_ENDING)))) {
                arguments.putAll(parseOptional(inputTokens, getEntry(patternPart)));
            } else {
                if (patternPart.startsWith((Character.toString(MANDATORY_ARG_BEGINNING)))
                        && patternPart.endsWith((Character.toString(MANDATORY_ARG_ENDING)))) {
                    arguments.put(getEntry(patternPart), tryGetInputEntry(inputPart));
                } else if (!patternPart.equals(inputPart)) {
                    return Collections.emptyMap();
                }
                inputTokens.remove(0);
            }
            patternTokens.remove(0);
        }
        return arguments;
    }

    /**
     * Parses params from optional part.
     *
     * @param splitInput optional part to be parsed
     * @param pattern pattern by which to parse
     * @return parsed params
     */
    private static Map<String, String> parseOptional(List<String> splitInput, String pattern) {
        ImmutableMap.Builder<String, String> args = ImmutableMap.builder();

        List<String> copyInput = new ArrayList<>(splitInput);
        List<String> splitPattern = Parser.parsePattern(pattern);

        while (!splitPattern.isEmpty()) {
            if (copyInput.isEmpty()) {
                return Collections.emptyMap();
            }
            String patternPart = splitPattern.get(0);
            String inputPart = tryGetInputEntry(copyInput.get(0));
            if (patternPart.startsWith((Character.toString(MANDATORY_ARG_BEGINNING)))
                    && patternPart.endsWith((Character.toString(MANDATORY_ARG_ENDING)))) {
                args.put(getEntry(patternPart), inputPart);
            } else if (patternPart.startsWith((Character.toString(OPTIONAL_PART_BEGINNING)))
                    && patternPart.endsWith((Character.toString(OPTIONAL_PART_ENDING)))) {
                args.putAll(parseOptional(copyInput, getEntry(patternPart)));
            } else if (!patternPart.equals(inputPart)) {
                return Collections.emptyMap();
            }
            splitPattern.remove(0);
            copyInput.remove(0);
        }

        splitInput.clear();
        splitInput.addAll(copyInput);
        return args.build();
    }

    /**
     * Cuts last not fully entered token,
     * where token is a word or some expression in quotes or double quotes.
     *
     * @param input the input to cut
     * @return cutted input
     */
    private static String cutNotFullyEnteredToken(String input) {
        int index = input.lastIndexOf(" ");
        return input.substring(0, index == -1 ? input.length() : index);
    }

    /**
     * Retrieves entry from input {@link String}.
     *
     * @param input the input
     * @return entry {@link String}
     */
    private static String tryGetInputEntry(String input) {
        if (input.startsWith("'") && input.endsWith("'") || input.startsWith("\"") && input.endsWith("\"")) {
            return getEntry(input);
        }
        return input;
    }

    /**
     * Retrieves entry from input {@link String}.
     * For example, for input "<some input>" returns "some input".
     *
     * @param input the input
     * @return entry {@link String}
     */
    private static String getEntry(String input) {
        return input.substring(1, input.length() - 1);
    }
}