From f79d9f949716694d22f6f1da73ed39216fd954f9 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Wed, 27 Apr 2016 23:10:54 -0800 Subject: [PATCH] Jersey server. --- .idea/libraries/kobalt__Compile_.xml | 2 +- .../libraries/kobalt_plugin_api__Compile_.xml | 10 +- kobalt/src/Build.kt | 4 +- .../src/main/kotlin/com/beust/kobalt/Args.kt | 6 +- .../main/kotlin/com/beust/kobalt/Constants.kt | 4 +- .../beust/kobalt/app/remote/JerseyServer.kt | 74 +++++++ .../beust/kobalt/app/remote/KobaltServer.kt | 190 +----------------- .../com/beust/kobalt/app/remote/OldServer.kt | 120 +++++++++++ .../beust/kobalt/app/remote/WasabiServer.kt | 37 ++++ 9 files changed, 254 insertions(+), 193 deletions(-) create mode 100644 src/main/kotlin/com/beust/kobalt/app/remote/JerseyServer.kt create mode 100644 src/main/kotlin/com/beust/kobalt/app/remote/OldServer.kt create mode 100644 src/main/kotlin/com/beust/kobalt/app/remote/WasabiServer.kt diff --git a/.idea/libraries/kobalt__Compile_.xml b/.idea/libraries/kobalt__Compile_.xml index cca04162..d6f2589a 100644 --- a/.idea/libraries/kobalt__Compile_.xml +++ b/.idea/libraries/kobalt__Compile_.xml @@ -49,8 +49,8 @@ - + diff --git a/.idea/libraries/kobalt_plugin_api__Compile_.xml b/.idea/libraries/kobalt_plugin_api__Compile_.xml index ad839a58..9046d1d6 100644 --- a/.idea/libraries/kobalt_plugin_api__Compile_.xml +++ b/.idea/libraries/kobalt_plugin_api__Compile_.xml @@ -1,15 +1,15 @@ - + - + @@ -21,10 +21,10 @@ - - + + @@ -42,8 +42,8 @@ - + diff --git a/kobalt/src/Build.kt b/kobalt/src/Build.kt index d3e1b63d..ecc23f82 100644 --- a/kobalt/src/Build.kt +++ b/kobalt/src/Build.kt @@ -142,13 +142,15 @@ val kobaltApp = project(kobaltPluginApi, wrapper) { "com.squareup.retrofit2:converter-gson:${Versions.retrofit}", "org.codehaus.plexus:plexus-utils:3.0.22", "biz.aQute.bnd:bndlib:2.4.0", + "org.eclipse.jetty:jetty-server:${Versions.jetty}", "org.eclipse.jetty:jetty-servlet:${Versions.jetty}", "org.glassfish.jersey.core:jersey-server:${Versions.jersey}", "org.glassfish.jersey.containers:jersey-container-servlet-core:${Versions.jersey}", "org.glassfish.jersey.containers:jersey-container-jetty-http:${Versions.jersey}", "org.glassfish.jersey.media:jersey-media-moxy:${Versions.jersey}" -// "org.eclipse.jetty.aggregate:jetty-all::uber:9.3.9.M1" + +// "org.wasabi:wasabi:0.1.182" ) } diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt index 42d6ff05..7501cec5 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Args.kt @@ -48,10 +48,6 @@ class Args { @Parameter(names = arrayOf("--noIncremental"), description = "Turn off incremental builds") var noIncremental: Boolean = false - companion object { - const val DEFAULT_SERVER_PORT = 1234 - } - @Parameter(names = arrayOf("--plugins"), description = "Comma-separated list of plug-in Maven id's") var pluginIds: String? = null @@ -59,7 +55,7 @@ class Args { var pluginJarFiles: String? = null @Parameter(names = arrayOf("--port"), description = "Port, if --server was specified") - var port: Int = DEFAULT_SERVER_PORT + var port: Int? = null @Parameter(names = arrayOf("--profiles"), description = "Comma-separated list of profiles to run") var profiles: String? = null diff --git a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Constants.kt b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Constants.kt index 77c0829b..7a95109f 100644 --- a/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Constants.kt +++ b/modules/kobalt-plugin-api/src/main/kotlin/com/beust/kobalt/Constants.kt @@ -10,12 +10,12 @@ object Constants { internal val DEFAULT_REPOS = listOf( // "https://maven-central.storage.googleapis.com/", "http://repo1.maven.org/maven2/", - "https://jcenter.bintray.com/" + "https://jcenter.bintray.com/", + "http://repository.jetbrains.com/all/" // snapshots // "https://oss.sonatype.org/content/repositories/snapshots/" // , "https://repository.jboss.org/nexus/content/repositories/root_repository/" -// , "http://repository.jetbrains.com/all/" ) } diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/JerseyServer.kt b/src/main/kotlin/com/beust/kobalt/app/remote/JerseyServer.kt new file mode 100644 index 00000000..93aa6916 --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/app/remote/JerseyServer.kt @@ -0,0 +1,74 @@ +package com.beust.kobalt.app.remote + +import com.beust.kobalt.Args +import com.beust.kobalt.api.Kobalt +import com.beust.kobalt.api.Project +import com.google.gson.Gson +import org.glassfish.jersey.jetty.JettyHttpContainerFactory +import org.glassfish.jersey.server.ResourceConfig +import org.glassfish.jersey.server.ServerProperties +import javax.ws.rs.GET +import javax.ws.rs.Path +import javax.ws.rs.Produces +import javax.ws.rs.QueryParam +import javax.ws.rs.core.MediaType +import javax.ws.rs.core.UriBuilder + +class JerseyServer(val initCallback: (String) -> List, val cleanUpCallback: () -> Unit) + : KobaltServer .IServer { + + companion object { + lateinit var initCallback: (String) -> List + lateinit var cleanUpCallback: () -> Unit + } + + init { + JerseyServer.initCallback = initCallback + JerseyServer.cleanUpCallback = cleanUpCallback + } + + override fun run(port: Int) { + val baseUri = UriBuilder.fromUri("http://localhost/").port(port).build() + val config = ResourceConfig(KobaltResource::class.java) + with (JettyHttpContainerFactory.createServer(baseUri, config)) { + try { + start() + join() + } finally { + destroy() + } + } + + } +} + +@Path("/v0") +class KobaltResource : ResourceConfig() { + init { + property(ServerProperties.TRACING, "ALL") + } + + @GET + @Path("ping") + @Produces(MediaType.TEXT_PLAIN) + fun getDependencies() = "pong" + + @GET + @Path("getDependencies") + @Produces(MediaType.APPLICATION_JSON) + fun getDependencies(@QueryParam("buildFile") buildFile: String) : String { + try { + val dependencyData = Kobalt.INJECTOR.getInstance(DependencyData::class.java) + val args = Kobalt.INJECTOR.getInstance(Args::class.java) + + val projects = JerseyServer.initCallback(buildFile) + val dd = dependencyData.dependenciesDataFor(buildFile, args) + val result = Gson().toJson(dd) + return result + } catch(ex: Exception) { + return "Error: " + ex.message + } finally { + JerseyServer.cleanUpCallback() + } + } +} diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/KobaltServer.kt b/src/main/kotlin/com/beust/kobalt/app/remote/KobaltServer.kt index 646208be..b02c0466 100644 --- a/src/main/kotlin/com/beust/kobalt/app/remote/KobaltServer.kt +++ b/src/main/kotlin/com/beust/kobalt/app/remote/KobaltServer.kt @@ -1,32 +1,14 @@ package com.beust.kobalt.app.remote -import com.beust.kobalt.Args -import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Project import com.beust.kobalt.homeDir -import com.beust.kobalt.internal.remote.CommandData -import com.beust.kobalt.internal.remote.ICommandSender -import com.beust.kobalt.internal.remote.PingCommand import com.beust.kobalt.misc.KFiles import com.beust.kobalt.misc.log -import com.google.gson.Gson -import com.google.gson.JsonObject -import com.google.gson.JsonParser -import org.glassfish.jersey.jetty.JettyHttpContainerFactory -import org.glassfish.jersey.server.ResourceConfig -import org.glassfish.jersey.server.ServerProperties -import java.io.* +import java.io.File +import java.io.FileWriter import java.lang.management.ManagementFactory -import java.net.ServerSocket -import java.net.SocketException import java.util.* import java.util.concurrent.Callable -import javax.ws.rs.GET -import javax.ws.rs.Path -import javax.ws.rs.Produces -import javax.ws.rs.QueryParam -import javax.ws.rs.core.MediaType -import javax.ws.rs.core.UriBuilder /** * Launch a Kobalt server. If @param{force} is specified, a new server will be launched even if one was detected @@ -35,40 +17,29 @@ import javax.ws.rs.core.UriBuilder * The callbacks are used to initialize and clean up the state before and after each command, so that Kobalt's state * can be properly reset, making the server reentrant. */ -class KobaltServer(val force: Boolean, val port: Int = 1234, +class KobaltServer(val force: Boolean, val givenPort: Int? = null, val initCallback: (String) -> List, - val cleanUpCallback: () -> Unit) : Callable, ICommandSender { + val cleanUpCallback: () -> Unit) : Callable { // var outgoing: PrintWriter? = null - val pending = arrayListOf() - companion object { - lateinit var initCallback: (String) -> List - lateinit var cleanUpCallback: () -> Unit + interface IServer { + fun run(port: Int) } - init { - KobaltServer.initCallback = initCallback - KobaltServer.cleanUpCallback = cleanUpCallback - } - - private val COMMAND_CLASSES = listOf(GetDependenciesCommand::class.java, PingCommand::class.java) - private val COMMANDS = COMMAND_CLASSES.map { - Kobalt.INJECTOR.getInstance(it).let { Pair(it.name, it) } - }.toMap() - override fun call() : Int { - val availablePort = ProcessUtil.findAvailablePort(port) + val port = givenPort ?: ProcessUtil.findAvailablePort(1234) try { if (createServerFile(port, force)) { -// oldRun(port) - privateRun(port) +// OldServer(initCallback, cleanUpCallback).run(port) + JerseyServer(initCallback, cleanUpCallback).run(port) +// WasabiServer(initCallback, cleanUpCallback).run(port) } } catch(ex: Exception) { ex.printStackTrace() } finally { deleteServerFile() } - return availablePort + return port } val SERVER_FILE = KFiles.joinDir(homeDir(KFiles.KOBALT_DOT_DIR, "kobaltServer.properties")) @@ -95,144 +66,5 @@ class KobaltServer(val force: Boolean, val port: Int = 1234, log(1, "KobaltServer deleting $SERVER_FILE") File(SERVER_FILE).delete() } - - lateinit var serverInfo: ServerInfo - - class ServerInfo(val port: Int) { - lateinit var reader: BufferedReader - lateinit var writer: PrintWriter - var serverSocket : ServerSocket? = null - - init { - reset() - } - - fun reset() { - if (serverSocket != null) { - serverSocket!!.close() - } - serverSocket = ServerSocket(port) - var clientSocket = serverSocket!!.accept() - reader = BufferedReader(InputStreamReader(clientSocket.inputStream)) - writer = PrintWriter(clientSocket.outputStream, true) - } - } - - @Path("/v0") - class MyResource : ResourceConfig() { - init { - property(ServerProperties.TRACING, "ALL") - } - - @GET - @Path("ping") - @Produces(MediaType.TEXT_PLAIN) - fun getDependencies() = "pong" - - @GET - @Path("getDependencies") - @Produces(MediaType.APPLICATION_JSON) - fun getDependencies(@QueryParam("buildFile") buildFile: String) : String { - try { - val dependencyData = Kobalt.INJECTOR.getInstance(DependencyData::class.java) - val args = Kobalt.INJECTOR.getInstance(Args::class.java) - - val projects = initCallback(buildFile) - val dd = dependencyData.dependenciesDataFor(buildFile, args) - val result = Gson().toJson(dd) - return result - } catch(ex: Exception) { - return "Error: " + ex.message - } finally { - cleanUpCallback() - } - } - } - - private fun privateRun(port: Int) { - log(1, "Listening to port $port") - - val baseUri = UriBuilder.fromUri("http://localhost/").port(port).build() - val config = ResourceConfig(MyResource::class.java) - with (JettyHttpContainerFactory.createServer(baseUri, config)) { - try { - start() - join() - } finally { - destroy() - } - } - } - - private fun oldRun(port: Int) { - log(1, "Listening to port $port") - var quit = false - serverInfo = ServerInfo(port) - while (!quit) { - if (pending.size > 0) { - log(1, "Emptying the queue, size $pending.size()") - synchronized(pending) { - pending.forEach { sendData(it) } - pending.clear() - } - } - var commandName: String? = null - try { - var line = serverInfo.reader.readLine() - while (!quit && line != null) { - log(1, "Received from client $line") - val jo = JsonParser().parse(line) as JsonObject - commandName = jo.get("name").asString - if ("quit" == commandName) { - log(1, "Quitting") - quit = true - } else { - runCommand(jo, initCallback) - - // Done, send a quit to the client - sendData(CommandData("quit", "")) - - // Clean up all the plug-in actors - cleanUpCallback() - line = serverInfo.reader.readLine() - } - } - if (line == null) { - log(1, "Received null line, resetting the server") - serverInfo.reset() - } - } catch(ex: SocketException) { - log(1, "Client disconnected, resetting") - serverInfo.reset() - } catch(ex: Throwable) { - ex.printStackTrace() - if (commandName != null) { - sendData(CommandData(commandName, null, ex.message)) - } - log(1, "Command failed: ${ex.message}") - } - } - } - - private fun runCommand(jo: JsonObject, initCallback: (String) -> List) { - val command = jo.get("name").asString - if (command != null) { - (COMMANDS[command] ?: COMMANDS["ping"])!!.run(this, jo, initCallback) - } else { - error("Did not find a name in command: $jo") - } - } - - override fun sendData(commandData: CommandData) { - val content = Gson().toJson(commandData) - if (serverInfo.writer != null) { - serverInfo.writer!!.println(content) - } else { - log(1, "Queuing $content") - synchronized(pending) { - pending.add(commandData) - } - } - } } diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/OldServer.kt b/src/main/kotlin/com/beust/kobalt/app/remote/OldServer.kt new file mode 100644 index 00000000..70f23f40 --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/app/remote/OldServer.kt @@ -0,0 +1,120 @@ +package com.beust.kobalt.app.remote + +import com.beust.kobalt.api.Kobalt +import com.beust.kobalt.api.Project +import com.beust.kobalt.internal.remote.CommandData +import com.beust.kobalt.internal.remote.ICommandSender +import com.beust.kobalt.internal.remote.PingCommand +import com.beust.kobalt.misc.log +import com.google.gson.Gson +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import java.io.BufferedReader +import java.io.InputStreamReader +import java.io.PrintWriter +import java.net.ServerSocket +import java.net.SocketException + +class OldServer(val initCallback: (String) -> List, val cleanUpCallback: () -> Unit) + : KobaltServer.IServer, ICommandSender { + val pending = arrayListOf() + + override fun run(port: Int) { + log(1, "Listening to port $port") + var quit = false + serverInfo = ServerInfo(port) + while (!quit) { + if (pending.size > 0) { + log(1, "Emptying the queue, size $pending.size()") + synchronized(pending) { + pending.forEach { sendData(it) } + pending.clear() + } + } + var commandName: String? = null + try { + var line = serverInfo.reader.readLine() + while (!quit && line != null) { + log(1, "Received from client $line") + val jo = JsonParser().parse(line) as JsonObject + commandName = jo.get("name").asString + if ("quit" == commandName) { + log(1, "Quitting") + quit = true + } else { + runCommand(jo, initCallback) + + // Done, send a quit to the client + sendData(CommandData("quit", "")) + + // Clean up all the plug-in actors + cleanUpCallback() + line = serverInfo.reader.readLine() + } + } + if (line == null) { + log(1, "Received null line, resetting the server") + serverInfo.reset() + } + } catch(ex: SocketException) { + log(1, "Client disconnected, resetting") + serverInfo.reset() + } catch(ex: Throwable) { + ex.printStackTrace() + if (commandName != null) { + sendData(CommandData(commandName, null, ex.message)) + } + log(1, "Command failed: ${ex.message}") + } + } + } + + private val COMMAND_CLASSES = listOf(GetDependenciesCommand::class.java, PingCommand::class.java) + private val COMMANDS = COMMAND_CLASSES.map { + Kobalt.INJECTOR.getInstance(it).let { Pair(it.name, it) } + }.toMap() + + private fun runCommand(jo: JsonObject, initCallback: (String) -> List) { + val command = jo.get("name").asString + if (command != null) { + (COMMANDS[command] ?: COMMANDS["ping"])!!.run(this, jo, initCallback) + } else { + error("Did not find a name in command: $jo") + } + } + + lateinit var serverInfo: ServerInfo + + class ServerInfo(val port: Int) { + lateinit var reader: BufferedReader + lateinit var writer: PrintWriter + var serverSocket : ServerSocket? = null + + init { + reset() + } + + fun reset() { + if (serverSocket != null) { + serverSocket!!.close() + } + serverSocket = ServerSocket(port) + var clientSocket = serverSocket!!.accept() + reader = BufferedReader(InputStreamReader(clientSocket.inputStream)) + writer = PrintWriter(clientSocket.outputStream, true) + } + } + + override fun sendData(commandData: CommandData) { + val content = Gson().toJson(commandData) + if (serverInfo.writer != null) { + serverInfo.writer!!.println(content) + } else { + log(1, "Queuing $content") + synchronized(pending) { + pending.add(commandData) + } + } + } + +} diff --git a/src/main/kotlin/com/beust/kobalt/app/remote/WasabiServer.kt b/src/main/kotlin/com/beust/kobalt/app/remote/WasabiServer.kt new file mode 100644 index 00000000..93b9eddc --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/app/remote/WasabiServer.kt @@ -0,0 +1,37 @@ +//package com.beust.kobalt.app.remote +// +//import com.beust.kobalt.Args +//import com.beust.kobalt.api.Project +// +//class WasabiServer(val initCallback: (String) -> List, val cleanUpCallback: () -> Unit) +// : KobaltServer.IServer { +// override fun run(port: Int) { +// with(AppServer(AppConfiguration(port))) { +// get("/", { response.send("Hello World!") }) +// get("/v0/getDependencies", +// { +// val buildFile = request.queryParams["buildFile"] +// if (buildFile != null) { +// +// val projects = initCallback(buildFile) +// val result = try { +// val dependencyData = Kobalt.INJECTOR.getInstance(DependencyData::class.java) +// val args = Kobalt.INJECTOR.getInstance(Args::class.java) +// +// val dd = dependencyData.dependenciesDataFor(buildFile, args) +// Gson().toJson(dd) +// } catch(ex: Exception) { +// "Error: " + ex.message +// } finally { +// cleanUpCallback() +// } +// +// response.send(result) +// } +// } +// ) +// start() +// } +// } +//} +//