com.epam.dlab.backendapi.core.commands.CommandParserMock.java Source code

Java tutorial

Introduction

Here is the source code for com.epam.dlab.backendapi.core.commands.CommandParserMock.java

Source

/***************************************************************************
    
 Copyright (c) 2016, EPAM SYSTEMS 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 com.epam.dlab.backendapi.core.commands;

import com.epam.dlab.exceptions.DlabException;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.MoreObjects;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;

import java.io.IOException;
import java.util.*;

/**
 * Parse command for emulate commands of Docker.
 */
public class CommandParserMock {
    private ObjectMapper MAPPER = new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true)
            .setSerializationInclusion(JsonInclude.Include.NON_NULL);

    private String command;
    private String action;
    private String resourceType;
    private String imageType;
    private String requestId;
    private String responsePath;
    private String name;
    private String json;
    private Map<String, String> envMap = new HashMap<>();
    private Map<String, String> varMap = new HashMap<>();
    private List<String> otherArgs = new ArrayList<>();
    private Map<String, String> variables = new HashMap<>();
    private boolean dockerCommand;

    public CommandParserMock() {
    }

    public CommandParserMock(String command, String uuid) {
        parse(command, uuid);
    }

    /**
     * Return the name of docker command.
     */
    public String getCommand() {
        return command;
    }

    /**
     * Return the name of docker action.
     */
    public String getAction() {
        return action;
    }

    /**
     * Return the type of resource.
     */
    public String getResourceType() {
        return resourceType;
    }

    /**
     * Return the image type.
     */
    public String getImageType() {
        return imageType;
    }

    /**
     * Return the request id.
     */
    public String getRequestId() {
        return requestId;
    }

    /**
     * Return the path for response files.
     */
    public String getResponsePath() {
        return responsePath;
    }

    /**
     * Return name of docker container.
     */
    public String getName() {
        return name;
    }

    /**
     * Return content of Json if present otherwise <b>null</b>.
     */
    public String getJson() {
        return json;
    }

    /**
     * Return map of environment variables.
     */
    public Map<String, String> getVariables() {
        return variables;
    }

    /**
     * Add argument to list.
     *
     * @param args list of arguments.
     * @param arg  argument.
     */
    private void addArgToList(List<String> args, String arg) {
        if (arg == null) {
            return;
        }
        if (arg.length() > 1) {
            if (arg.startsWith("'") && arg.endsWith("'")) {
                arg = arg.substring(1, arg.length() - 1);
            }
            if (arg.startsWith("\"") && arg.endsWith("\"")) {
                arg = arg.substring(1, arg.length() - 1);
            }
        }
        arg = arg.trim();
        if (arg.isEmpty()) {
            return;
        }

        args.add(arg);
    }

    /**
     * Extract arguments from command line.
     *
     * @param cmd command line.
     * @return List of arguments.
     */
    private List<String> extractArgs(String cmd) {
        boolean isQuote = false;
        boolean isDoubleQuote = false;
        List<String> args = new ArrayList<>();
        int pos = 0;

        for (int i = 0; i < cmd.length(); i++) {
            final char c = cmd.charAt(i);
            if (c == '\'') {
                isQuote = !isQuote;
                continue;
            }
            if (c == '"') {
                isDoubleQuote = !isDoubleQuote;
                continue;
            }

            if (!isQuote && !isDoubleQuote && c == ' ') {
                addArgToList(args, cmd.substring(pos, i));
                pos = i + 1;
            }
        }
        if (!isQuote && !isDoubleQuote) {
            addArgToList(args, cmd.substring(pos));
        }

        return args;
    }

    /**
     * Return the value of argument.
     *
     * @param args    list of arguments.
     * @param index   index of named arguments
     * @param argName name of argument.
     */
    private String getArgValue(List<String> args, int index, String argName) {
        if (!args.get(index).equals(argName)) {
            return null;
        }
        args.remove(index);
        if (index < args.size()) {
            String value = args.get(index);
            args.remove(index);
            return value;
        }
        throw new DlabException("Argument \"" + argName + "\" detected but not have value");
    }

    /**
     * Return pair name/value separated.
     *
     * @param argName   name of argument.
     * @param value     value.
     * @param separator separator.
     */
    private Pair<String, String> getPair(String argName, String value, String separator) {
        String[] array = value.split(separator);
        if (array.length != 2) {
            throw new DlabException("Invalid value for \"" + argName + "\": " + value);
        }
        return new ImmutablePair<>(array[0], array[1]);
    }

    /**
     * Return name of docker image.
     *
     * @param args list of arguments.
     * @throws if image name not found.
     */
    public static String getImageName(List<String> args) {
        for (String s : args) {
            if (s.startsWith("docker.dlab-")) {
                return s;
            }
        }
        throw new DlabException("Name of docker image not found");
    }

    /**
     * Extract Json properties from Json content.
     *
     * @param jsonContent Json content.
     * @return
     */
    private Map<String, String> getJsonVariables(String jsonContent) {
        Map<String, String> vars = new HashMap<>();
        if (jsonContent == null) {
            return vars;
        }

        JsonNode json;
        try {
            json = MAPPER.readTree(jsonContent);
        } catch (IOException e) {
            throw new DlabException("Can't parse json content: " + e.getLocalizedMessage(), e);
        }

        Iterator<String> keys = json.fieldNames();
        while (keys.hasNext()) {
            String key = keys.next();
            String value = getTextValue(json.get(key));
            if (value != null) {
                vars.put(key, value);
            }
        }
        return vars;
    }

    /**
     * Return the value of json property or <b>null</b>.
     *
     * @param jsonNode - Json node.
     */
    private String getTextValue(JsonNode jsonNode) {
        return jsonNode != null ? jsonNode.textValue() : null;
    }

    /**
     * Parse command line.
     *
     * @param cmd command line.
     */
    public void parse(String cmd, String uuid) {
        command = null;
        action = null;
        resourceType = null;
        imageType = null;
        requestId = uuid;
        responsePath = null;
        name = null;
        json = null;

        envMap.clear();
        varMap.clear();
        otherArgs.clear();
        variables.clear();

        List<String> args = extractArgs(cmd);
        dockerCommand = args.contains("docker");
        int i = 0;
        String s;
        Pair<String, String> p;

        while (i < args.size()) {
            if ((s = getArgValue(args, i, "-v")) != null) {
                p = getPair("-v", s, ":");
                varMap.put(p.getValue(), p.getKey());
            } else if ((s = getArgValue(args, i, "-e")) != null) {
                p = getPair("-e", s, "=");
                envMap.put(p.getKey(), p.getValue());
            } else if ((s = getArgValue(args, i, "docker")) != null
                    || (s = getArgValue(args, i, "python")) != null) {
                command = s;
            } else if ((s = getArgValue(args, i, "--action")) != null) {
                action = s;
            } else if ((s = getArgValue(args, i, "--name")) != null) {
                name = s;
            } else if ((s = getArgValue(args, i, "echo")) != null) {
                if (s.equals("-e")) {
                    if (i >= args.size()) {
                        throw new DlabException("Argument \"echo -e\" detected but not have value");
                    }
                    s = args.get(i);
                    args.remove(i);
                }
                json = s;
            } else if ((s = getArgValue(args, i, "--result_path")) != null) {
                responsePath = s;
                varMap.put("/response", responsePath);
                args.remove(i);
            } else {
                i++;
            }
        }

        if (args.size() > 0) {
            otherArgs.addAll(args);
        }

        resourceType = envMap.get("conf_resource");
        if (isDockerCommand()) {
            imageType = getImageName(args);
            imageType = imageType.replace("docker.dlab-", "").replace(":latest", "");
        }
        responsePath = varMap.get("/response");

        variables.putAll(envMap);
        variables.putAll(getJsonVariables(json));
        variables.put("request_id", requestId);
        variables.put("instance_id", "i-" + requestId.replace("-", "").substring(0, 17));
        variables.put("cluster_id", "j-" + requestId.replace("-", "").substring(0, 13).toUpperCase());
        variables.put("notebook_id", requestId.replace("-", "").substring(17, 22));
    }

    public boolean isDockerCommand() {
        return dockerCommand;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this).add("command", command).add("action", action)
                .add("resourceType", resourceType).add("imageType", imageType).add("requestId", requestId)
                .add("responsePath", responsePath).add("name", name).add("environment", envMap)
                .add("variable", varMap).add("others", otherArgs).add("json", json).toString();
    }
}