Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion gorscripts/src/main/java/org/gorpipe/gor/cli/GorCLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.gorpipe.gor.cli.manager.ManagerCommand;
import org.gorpipe.gor.cli.migrator.FolderMigratorCommand;
import org.gorpipe.gor.cli.query.QueryCommand;
import org.gorpipe.gor.cli.server.TestServerCommand;
import org.gorpipe.gor.cli.render.RenderCommand;
import org.gorpipe.logging.GorLogbackUtil;
import picocli.CommandLine;
Expand All @@ -38,7 +39,7 @@
@CommandLine.Command(name="gor",
version="version 1.0",
description = "Command line interface for gor query language and processes.",
subcommands = {QueryCommand.class, FolderMigratorCommand.class})
subcommands = {QueryCommand.class, FolderMigratorCommand.class, TestServerCommand.class})
public class GorCLI extends GorExecCLI implements Runnable {
public static void main(String[] args) {
GorLogbackUtil.initLog("gor");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* BEGIN_COPYRIGHT
*
* Copyright (C) 2011-2013 deCODE genetics Inc.
* Copyright (C) 2013-2019 WuXi NextCode Inc.
* All Rights Reserved.
*
* GORpipe is free software: you can redistribute it and/or modify
* it under the terms of the AFFERO GNU General Public License as published by
* the Free Software Foundation.
*
* GORpipe is distributed "AS-IS" AND WITHOUT ANY WARRANTY OF ANY KIND,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* NON-INFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE. See
* the AFFERO GNU General Public License for the complete license terms.
*
* You should have received a copy of the AFFERO GNU General Public License
* along with GORpipe. If not, see <http://www.gnu.org/licenses/agpl-3.0.html>
*
* END_COPYRIGHT
*/

package org.gorpipe.gor.cli.server;

import gorsat.process.GorTestServer;
import gorsat.process.PipeOptions;
import org.gorpipe.gor.cli.HelpOptions;
import org.gorpipe.gor.model.DbConnection;
import org.gorpipe.gor.session.ProjectContext;
import org.gorpipe.util.ConfigUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine;

import java.io.File;

@CommandLine.Command(name = "test-server",
description = "Start an HTTP server that accepts GOR queries via POST /query",
header = "Start a GOR test server")
public class TestServerCommand extends HelpOptions implements Runnable {

private static final Logger log = LoggerFactory.getLogger(TestServerCommand.class);

@CommandLine.Option(names = {"-p", "--port"}, defaultValue = "4242",
description = "Port to listen on (default: 4242)")
private int port;

@CommandLine.Option(names = {"-d", "--cachedir"},
description = "Path to cache directory for query execution")
private String cacheDir;

@CommandLine.Option(names = {"-w", "--workers"}, defaultValue = "0",
description = "Number of parallel workers for query execution")
private int workers;

@CommandLine.Option(names = {"-c", "--config"},
description = "Loads configuration from external file")
private File configFile;

@Override
public void run() {
try {
ConfigUtil.loadConfig("gor");
DbConnection.initInConsoleApp();

PipeOptions opts = new PipeOptions();
opts.cacheDir_$eq(cacheDir != null ? cacheDir : ProjectContext.DEFAULT_CACHE_DIR);
opts.workers_$eq(workers);
opts.color_$eq("none");
if (configFile != null)
opts.configFile_$eq(configFile.toString());

GorTestServer.start(port, opts);
} catch (Exception e) {
log.error("Failed to start test server: {}", e.getMessage(), e);
System.exit(-1);
}
}
}
6 changes: 3 additions & 3 deletions gortools/src/main/scala/gorsat/Outputs/ColorStdOut.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@

package gorsat.Outputs

import gorsat.Commands.RowHeader
import gorsat.process.PipeInstance
import java.io.OutputStream
import org.gorpipe.gor.model.{Row, RowColorize}

case class ColorStdOut(instance: PipeInstance = null, colorFormatter: RowColorize)
extends OutStream(null , System.out) {
case class ColorStdOut(instance: PipeInstance = null, colorFormatter: RowColorize, dest: OutputStream = System.out)
extends OutStream(null, dest) {

var headerPrinted : Boolean = false

Expand Down
5 changes: 3 additions & 2 deletions gortools/src/main/scala/gorsat/Outputs/NorColorStdOut.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@
package gorsat.Outputs

import gorsat.process.PipeInstance
import java.io.OutputStream
import org.gorpipe.gor.model.{Row, RowColorize}

case class NorColorStdOut(instance: PipeInstance = null, colorFormatter: RowColorize)
extends NorOutStream(null, System.out) {
case class NorColorStdOut(instance: PipeInstance = null, colorFormatter: RowColorize, dest: OutputStream = System.out)
extends NorOutStream(null, dest) {

var headerPrinted : Boolean = false

Expand Down
4 changes: 3 additions & 1 deletion gortools/src/main/scala/gorsat/Outputs/NorStdOut.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@

package gorsat.Outputs

case class NorStdOut(override val header: String = null) extends NorOutStream(header, System.out) {
import java.io.OutputStream

case class NorStdOut(override val header: String = null, dest: OutputStream = System.out) extends NorOutStream(header, dest) {
}
4 changes: 3 additions & 1 deletion gortools/src/main/scala/gorsat/Outputs/StdOut.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

package gorsat.Outputs

case class StdOut( val header: String = null) extends OutStream (header, System.out) {
import java.io.OutputStream

case class StdOut(val header: String = null, dest: OutputStream = System.out) extends OutStream(header, dest) {

}
26 changes: 16 additions & 10 deletions gortools/src/main/scala/gorsat/process/CLIGorExecutionEngine.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import org.gorpipe.gor.RequestStats
import org.gorpipe.gor.driver.meta.DataType
import org.gorpipe.gor.util.DataUtil
import org.gorpipe.gor.model.{RowRotatingColorize, RowTypeColorize}
import java.io.OutputStream

/**
* Execution engine for GOR running as command line. This class takes as input the command line options, construct a
Expand All @@ -39,11 +40,16 @@ import org.gorpipe.gor.model.{RowRotatingColorize, RowTypeColorize}
* @param pipeOptions GorPipe command line options
* @param whitelistedCmdFiles File containing whitelisted commands
* @param securityContext Security context if needed
* @param outputStream Stream to write query results to (defaults to stdout)
*/
class CLIGorExecutionEngine(pipeOptions: PipeOptions, whitelistedCmdFiles:String = null, securityContext:String = null) extends GorExecutionEngine {
class CLIGorExecutionEngine(pipeOptions: PipeOptions, whitelistedCmdFiles:String, securityContext:String, outputStream: OutputStream) extends GorExecutionEngine {

def this(pipeOptions: PipeOptions, whitelistedCmdFiles: String, securityContext: String) = {
this(pipeOptions, whitelistedCmdFiles, securityContext, System.out)
}

def this(args:Array[String], whitelistedCmdFiles:String, securityContext:String) = {
this(PipeOptions.parseInputArguments(args), whitelistedCmdFiles, securityContext)
this(PipeOptions.parseInputArguments(args), whitelistedCmdFiles, securityContext, System.out)
}

override protected def createSession(): GorSession = {
Expand All @@ -66,7 +72,7 @@ class CLIGorExecutionEngine(pipeOptions: PipeOptions, whitelistedCmdFiles:String
if (MacroUtilities.isLastCommandWrite(pipeOptions.query)) instance = null

iterator.thePipeStep = iterator.thePipeStep |
createStdOut(session.getNorContext || iterator.isNorContext, pipeOptions.color, iterator)
createStdOut(session.getNorContext || iterator.isNorContext, pipeOptions.color, iterator, outputStream)

iterator
}
Expand All @@ -83,24 +89,24 @@ class CLIGorExecutionEngine(pipeOptions: PipeOptions, whitelistedCmdFiles:String
}
}

private def createStdOut(isNor: Boolean, color: String, iterator: PipeInstance): OutStream = {
private def createStdOut(isNor: Boolean, color: String, iterator: PipeInstance, out: OutputStream): OutStream = {
val c = color.toLowerCase()

if (isNor) {
if (c.startsWith("r")) {
NorColorStdOut(iterator, new RowRotatingColorize())
NorColorStdOut(iterator, new RowRotatingColorize(), out)
} else if(c.startsWith("t")) {
NorColorStdOut(iterator, new RowTypeColorize())
NorColorStdOut(iterator, new RowTypeColorize(), out)
} else {
NorStdOut(if (iterator == null) null else iterator.getHeader())
NorStdOut(if (iterator == null) null else iterator.getHeader(), out)
}
} else {
if (c.startsWith("r")) {
ColorStdOut(iterator, new RowRotatingColorize())
ColorStdOut(iterator, new RowRotatingColorize(), out)
} else if (c.startsWith("t")) {
ColorStdOut(iterator, new RowTypeColorize())
ColorStdOut(iterator, new RowTypeColorize(), out)
} else {
StdOut(if (iterator == null) null else iterator.getHeader())
StdOut(if (iterator == null) null else iterator.getHeader(), out)
}
}
}
Expand Down
1 change: 0 additions & 1 deletion gortools/src/main/scala/gorsat/process/GorPipe.scala
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ object GorPipe extends GorPipeFirstOrderCommands {
// Initialize database connections
DbConnection.initInConsoleApp()


var exitCode = 0
//todo find a better way to construct

Expand Down
86 changes: 86 additions & 0 deletions gortools/src/main/scala/gorsat/process/GorTestServer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* BEGIN_COPYRIGHT
*
* Copyright (C) 2011-2013 deCODE genetics Inc.
* Copyright (C) 2013-2019 WuXi NextCode Inc.
* All Rights Reserved.
*
* GORpipe is free software: you can redistribute it and/or modify
* it under the terms of the AFFERO GNU General Public License as published by
* the Free Software Foundation.
*
* GORpipe is distributed "AS-IS" AND WITHOUT ANY WARRANTY OF ANY KIND,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* NON-INFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE. See
* the AFFERO GNU General Public License for the complete license terms.
*
* You should have received a copy of the AFFERO GNU General Public License
* along with GORpipe. If not, see <http://www.gnu.org/licenses/agpl-3.0.html>
*
* END_COPYRIGHT
*/

package gorsat.process

import com.sun.net.httpserver.{HttpExchange, HttpServer}
import java.io.ByteArrayOutputStream
import java.net.InetSocketAddress
import org.gorpipe.exceptions.{ExceptionUtilities, GorException}
import org.slf4j.LoggerFactory

object GorTestServer {

private val logger = LoggerFactory.getLogger(this.getClass)

def start(port: Int, baseOptions: PipeOptions): Unit = {
val server = HttpServer.create(new InetSocketAddress(port), 0)

server.createContext("/query", (exchange: HttpExchange) => {
if (exchange.getRequestMethod.equalsIgnoreCase("POST")) {
val query = new String(exchange.getRequestBody.readAllBytes(), "UTF-8").trim
val (status, body) = executeQuery(query, baseOptions)
val bytes = body.getBytes("UTF-8")
exchange.getResponseHeaders.set("Content-Type", "text/plain; charset=UTF-8")
exchange.sendResponseHeaders(status, bytes.length)
val os = exchange.getResponseBody
os.write(bytes)
os.close()
} else {
exchange.sendResponseHeaders(405, -1)
exchange.getResponseBody.close()
}
})

server.start()
System.err.println(s"GOR test server listening on port $port")
logger.info(s"GOR test server started on port $port")

Thread.currentThread().join()
}

private def executeQuery(query: String, baseOptions: PipeOptions): (Int, String) = {
val opts = new PipeOptions()
opts.query = PipeOptions.cleanUpQueryAndSplit(query).mkString(";")
opts.gorRoot = baseOptions.gorRoot
opts.configFile = baseOptions.configFile
opts.aliasFile = baseOptions.aliasFile
opts.cacheDir = baseOptions.cacheDir
opts.color = "none"

val out = new ByteArrayOutputStream()
val engine = new CLIGorExecutionEngine(opts, null, null, out)
try {
engine.execute()
(200, out.toString("UTF-8"))
} catch {
case ge: GorException =>
val msg = ExceptionUtilities.gorExceptionToString(ge)
logger.error("Query failed: {}", msg)
(500, msg)
case ex: Throwable =>
val msg = Option(ex.getMessage).getOrElse(ex.getClass.getName)
logger.error("Query failed: {}", msg, ex)
(500, msg)
}
}
}
Loading