com.yahoo.yqlplus.engine.tools.YQLPlusRun.java Source code

Java tutorial

Introduction

Here is the source code for com.yahoo.yqlplus.engine.tools.YQLPlusRun.java

Source

/*
 * Copyright (c) 2016 Yahoo Inc.
 * Licensed under the terms of the Apache version 2.0 license.
 * See LICENSE file for terms.
 */

package com.yahoo.yqlplus.engine.tools;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.MappingJsonFactory;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Names;
import com.yahoo.yqlplus.api.trace.TraceRequest;
import com.yahoo.yqlplus.engine.CompiledProgram;
import com.yahoo.yqlplus.engine.ProgramResult;
import com.yahoo.yqlplus.engine.YQLPlusCompiler;
import com.yahoo.yqlplus.engine.YQLResultSet;
import com.yahoo.yqlplus.engine.guice.JavaEngineModule;
import org.apache.commons.cli.*;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;

/**
 * Run a CQL script from the command line.  Prints the results.
 */
public class YQLPlusRun {
    private JsonFactory factory = new MappingJsonFactory();

    protected Options createOptions() {
        Options options = new Options();
        options.addOption(new Option("h", "help", false, "Display help"));
        options.addOption(new Option("c", "command", true, "Execute a script from the command line"));
        options.addOption(new Option("s", "source", false, "Dump source of generated script"));
        options.addOption(new Option("v", "verbose", false, "Enable verbose tracing"));
        options.addOption(new Option("p", "path", true, "Add a module directory"));

        // -l <port> (listen on a port? for dev-time running of a web server)
        // a way to import a library?

        // command -h -Dargname=argval -Dargname=argvalue... -c {command} [<file>]

        options.addOption(OptionBuilder.withArgName("argument=value").hasArgs(2).withValueSeparator()
                .withDescription("define named argument").create("D"));
        return options;
    }

    public final int run(String[] strings) throws Exception {
        Options options = createOptions();
        CommandLineParser parser = new GnuParser();
        CommandLine command;
        try {
            command = parser.parse(options, strings);
        } catch (ParseException e) {
            System.err.println("Command line parse exception: " + e.getMessage());
            return -1;
        }
        if (command.hasOption("help")) {
            HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp(getClass().getName(), options);
            return 0;
        }
        //        LogManager manager = LogManager.getLogManager();
        //        String logLevel = command.getOptionValue("loglevel", "WARNING");
        //        Logger logger = Logger.getGlobal();
        //        logger.setLevel(Level.parse(logLevel));
        return run(command);
    }

    @SuppressWarnings("unchecked")
    public int run(CommandLine command) throws Exception {
        String script = null;
        String filename = null;
        if (command.hasOption("command")) {
            script = command.getOptionValue("command");
            filename = "<command line>";
        }
        List<String> scriptAndArgs = (List<String>) command.getArgList();
        if (filename == null && scriptAndArgs.size() < 1) {
            System.err.println("No script specified.");
            return -1;
        } else if (script == null) {
            filename = scriptAndArgs.get(0);
            Path scriptPath = Paths.get(filename);
            if (!Files.isRegularFile(scriptPath)) {
                System.err.println(scriptPath + " is not a file.");
                return -1;
            }
            script = Charsets.UTF_8.decode(ByteBuffer.wrap(Files.readAllBytes(scriptPath))).toString();
        }
        List<String> paths = Lists.newArrayList();
        if (command.hasOption("path")) {
            paths.addAll(Arrays.asList(command.getOptionValues("path")));
        }
        // TODO: this isn't going to be very interesting without some sources
        Injector injector = Guice.createInjector(new JavaEngineModule());
        YQLPlusCompiler compiler = injector.getInstance(YQLPlusCompiler.class);
        CompiledProgram program = compiler.compile(script);
        if (command.hasOption("source")) {
            program.dump(System.out);
            return 0;
        }
        // TODO: read command line arguments to pass to program
        ExecutorService outputThreads = Executors.newSingleThreadExecutor();
        ProgramResult result = program.run(Maps.<String, Object>newHashMap(), true);
        for (String name : result.getResultNames()) {
            final ListenableFuture<YQLResultSet> future = result.getResult(name);
            future.addListener(new Runnable() {
                @Override
                public void run() {
                    try {
                        YQLResultSet resultSet = future.get();
                        System.out.println(new String((byte[]) resultSet.getResult()));
                    } catch (InterruptedException | ExecutionException e) {
                        e.printStackTrace();
                    }

                }
            }, outputThreads);
        }
        Future<TraceRequest> done = result.getEnd();
        try {
            done.get(10000L, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException | TimeoutException e) {
            e.printStackTrace();
        }
        outputThreads.awaitTermination(1L, TimeUnit.SECONDS);
        return 0;
    }

    private static class ModulePathModule extends AbstractModule {
        private List<String> paths;

        private ModulePathModule(List<String> paths) {
            this.paths = paths;
        }

        @Override
        protected void configure() {
            Multibinder<String> mbinder = Multibinder.newSetBinder(binder(), String.class,
                    Names.named("modulePath"));
            for (String path : paths) {
                mbinder.addBinding().toInstance(path);
            }
        }
    }

    @Subscribe
    public void event(Object event) throws IOException {
        JsonGenerator gen = factory.createGenerator(System.err);
        gen.writeStartObject();
        gen.writeStringField("type", event.getClass().getName());
        gen.writeFieldName("event");
        gen.writeObject(event);
        gen.writeEndObject();
        gen.flush();
        System.err.println();
    }

    public static void main(String[] args) throws Exception {
        System.exit(new YQLPlusRun().run(args));
    }
}