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

org.vertexium.cli.VertexiumShell Maven / Gradle / Ivy

There is a newer version: 4.10.0
Show newest version
package org.vertexium.cli;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import groovy.lang.Binding;
import groovy.lang.Closure;
import groovy.lang.GroovyShell;
import jline.TerminalFactory;
import jline.UnixTerminal;
import jline.UnsupportedTerminal;
import jline.WindowsTerminal;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.tools.shell.AnsiDetector;
import org.codehaus.groovy.tools.shell.Groovysh;
import org.codehaus.groovy.tools.shell.IO;
import org.codehaus.groovy.tools.shell.Interpreter;
import org.codehaus.groovy.tools.shell.util.Logger;
import org.codehaus.groovy.tools.shell.util.NoExitSecurityManager;
import org.codehaus.groovy.tools.shell.util.Preferences;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.AnsiConsole;
import org.vertexium.Graph;
import org.vertexium.GraphFactory;
import org.vertexium.Visibility;
import org.vertexium.cli.commands.*;
import org.vertexium.cli.model.LazyEdgeMap;
import org.vertexium.cli.model.LazyVertexMap;
import org.vertexium.query.GeoCompare;
import org.vertexium.type.GeoPoint;
import org.vertexium.util.ConfigurationUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class VertexiumShell {
    private Groovysh groovysh;

    private static class Parameters extends ParametersBase {
        @Parameter(names = {"-C"}, description = "Suppress colors")
        private boolean suppressColor;

        @Parameter(names = {"-T"}, description = "Terminal type")
        private String terminalType = TerminalFactory.AUTO;

        @Parameter(names = {"-e"}, description = "String to evaluate")
        private String evalString = null;

        @Parameter(names = {"-ef"}, description = "File to evaluate")
        private List evalFiles = new ArrayList<>();

        @Parameter(names = {"-t"}, description = "Time")
        private Long time = null;

        @Parameter(description = "File names to execute")
        private List fileNames = new ArrayList<>();
    }

    public int run(String[] args) throws Exception {
        Parameters params = new Parameters();
        JCommander j = new JCommander(params, args);
        if (params.help) {
            j.usage();
            return -1;
        }

        setTerminalType(params.terminalType, params.suppressColor);

        Map config = ConfigurationUtils.loadConfig(params.getConfigFileNames(), params.configPropertyPrefix);
        Graph graph = new GraphFactory().createGraph(config);

        System.setProperty("groovysh.prompt", "vertexium");

        // IO must be constructed AFTER calling setTerminalType()/AnsiConsole.systemInstall(),
        // else wrapped System.out does not work on Windows.
        final IO io = new IO();

        Logger.io = io;

        CliVertexiumCypherQueryContext.setLabelPropertyName(params.cypherLabelProperty);

        CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
        VertexiumScript.setGraph(graph);
        if (params.authorizations != null) {
            VertexiumScript.setAuthorizations(params.getAuthorizations(graph));
        }
        VertexiumScript.setTime(params.time);
        compilerConfiguration.setScriptBaseClass(VertexiumScript.class.getName());

        Binding binding = new Binding();

        GroovyShell groovyShell = new GroovyShell(this.getClass().getClassLoader(), binding, compilerConfiguration);
        Closure resultHook = new Closure(this) {
            @Override
            public Object call(Object... args) {
                Object obj = args[0];
                boolean showLastResult = !io.isQuiet() && (io.isVerbose() || Preferences.getShowLastResult());
                if (showLastResult) {
                    // avoid String.valueOf here because it bypasses pretty-printing of Collections,
                    // e.g. String.valueOf( ['a': 42] ) != ['a': 42].toString()
                    io.out.println("@|bold ===>|@ " + VertexiumScript.resultToString(obj));
                }
                return null;
            }
        };

        groovysh = new Groovysh(io);
        setGroovyShell(groovysh, groovyShell);
        setResultHook(groovysh, resultHook);

        Groovysh shell = createShell();
        shell.execute("import " + Visibility.class.getPackage().getName() + ".*;");
        shell.execute("v = new " + LazyVertexMap.class.getName() + "();");
        shell.execute("e = new " + LazyEdgeMap.class.getName() + "();");
        shell.execute("g = " + VertexiumScript.class.getName() + ".getGraph();");
        shell.execute("auths = " + VertexiumScript.class.getName() + ".getAuthorizations();");
        shell.execute("time = " + VertexiumScript.class.getName() + ".getTime();");
        shell.execute("cypher = { code -> " + VertexiumScript.class.getName() + ".executeCypher(code) };");
        startGroovysh(params, shell, params.evalString, params.fileNames);
        return 0;
    }

    private void setGroovyShell(Groovysh groovysh, GroovyShell groovyShell) throws NoSuchFieldException, IllegalAccessException {
        Field interpField = groovysh.getClass().getDeclaredField("interp");
        interpField.setAccessible(true);

        Field shellField = Interpreter.class.getDeclaredField("shell");
        shellField.setAccessible(true);

        Interpreter interpreter = (Interpreter) interpField.get(groovysh);
        shellField.set(interpreter, groovyShell);
    }

    private void setResultHook(Groovysh groovysh, Closure resultHook) throws NoSuchFieldException, IllegalAccessException {
        Field resultHookField = Groovysh.class.getDeclaredField("resultHook");
        resultHookField.setAccessible(true);

        resultHookField.set(groovysh, resultHook);
    }

    public Groovysh getGroovysh() {
        return groovysh;
    }

    public static void main(final String[] args) throws Exception {
        int result = new VertexiumShell().run(args);
        System.exit(result);
    }

    private Groovysh createShell() {
        final Groovysh shell = getGroovysh();

        // Add a hook to display some status when shutting down...
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            //
            // FIXME: We need to configure JLine to catch CTRL-C for us... Use gshell-io's InputPipe
            //

            if (shell.getHistory() != null) {
                try {
                    shell.getHistory().flush();
                } catch (IOException e) {
                    System.out.println("Could not flush history.");
                }
            }
        }));

        shell.register(new GetAuthsCommand(shell));
        shell.register(new SetAuthsCommand(shell));
        shell.register(new GetTimeCommand(shell));
        shell.register(new SetTimeCommand(shell));
        shell.register(new NowCommand(shell));
        return shell;
    }

    /**
     * @param evalString commands that will be executed at startup after loading files given with filenames param
     * @param filenames  files that will be loaded at startup
     */
    protected void startGroovysh(Parameters params, Groovysh shell, String evalString, List filenames) {
        int code;
        SecurityManager psm = System.getSecurityManager();
        System.setSecurityManager(new NoExitSecurityManager());

        System.out.println("  _    __          __            _");
        System.out.println(" | |  / /__  _____/ /____  _  __(_)_  ______ ___");
        System.out.println(" | | / / _ \\/ ___/ __/ _ \\| |/_/ / / / / __ `__ \\");
        System.out.println(" | |/ /  __/ /  / /_/  __/>