From a6a12950c1e2dcaee590d95579b41cc7e48eb61a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Smolarek?= <34063647+Razz4780@users.noreply.github.com> Date: Wed, 25 Oct 2023 16:30:52 +0200 Subject: [PATCH] Tomcat support (#185) * TomcatExecutionListener * Catch exceptions and allow running * Ignore default Tomcat server port * Changelog entry * Format fix * Environment variable for tomcat server port --- build.gradle.kts | 1 + changelog.d/183.fixed.md | 1 + .../idea/IdeaRunConfigurationExtension.kt | 6 +- modules/products/tomcat/build.gradle.kts | 26 +++++ .../tomcat/TomcatExecutionListener.kt | 97 +++++++++++++++++++ settings.gradle.kts | 3 +- .../resources/META-INF/mirrord-tomcat.xml | 6 ++ src/main/resources/META-INF/plugin.xml | 1 + 8 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 changelog.d/183.fixed.md create mode 100644 modules/products/tomcat/build.gradle.kts create mode 100644 modules/products/tomcat/src/main/kotlin/com/metalbear/mirrord/products/tomcat/TomcatExecutionListener.kt create mode 100644 src/main/resources/META-INF/mirrord-tomcat.xml diff --git a/build.gradle.kts b/build.gradle.kts index 75d1ec72..482681be 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -44,6 +44,7 @@ dependencies { implementation(project(":mirrord-products-goland")) implementation(project(":mirrord-products-nodejs")) implementation(project(":mirrord-products-rider")) + implementation(project(":mirrord-products-tomcat")) testImplementation("com.intellij.remoterobot:remote-robot:$remoteRobotVersion") testImplementation("com.intellij.remoterobot:remote-fixtures:$remoteRobotVersion") testImplementation("com.intellij.remoterobot:ide-launcher:0.11.19.414") diff --git a/changelog.d/183.fixed.md b/changelog.d/183.fixed.md new file mode 100644 index 00000000..6320425a --- /dev/null +++ b/changelog.d/183.fixed.md @@ -0,0 +1 @@ +Fixed Tomcat support. \ No newline at end of file diff --git a/modules/products/idea/src/main/kotlin/com/metalbear/mirrord/products/idea/IdeaRunConfigurationExtension.kt b/modules/products/idea/src/main/kotlin/com/metalbear/mirrord/products/idea/IdeaRunConfigurationExtension.kt index 2e6ae54f..4580f2b5 100644 --- a/modules/products/idea/src/main/kotlin/com/metalbear/mirrord/products/idea/IdeaRunConfigurationExtension.kt +++ b/modules/products/idea/src/main/kotlin/com/metalbear/mirrord/products/idea/IdeaRunConfigurationExtension.kt @@ -15,7 +15,9 @@ import com.intellij.openapi.components.service import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration import com.intellij.openapi.project.Project import com.intellij.openapi.util.Key -import com.metalbear.mirrord.* +import com.metalbear.mirrord.CONFIG_ENV_NAME +import com.metalbear.mirrord.MirrordLogger +import com.metalbear.mirrord.MirrordProjectService import java.util.concurrent.ConcurrentHashMap class IdeaRunConfigurationExtension : RunConfigurationExtension() { @@ -25,7 +27,7 @@ class IdeaRunConfigurationExtension : RunConfigurationExtension() { private val runningProcessEnvs = ConcurrentHashMap>() override fun isApplicableFor(configuration: RunConfigurationBase<*>): Boolean { - val applicable = !configuration.name.startsWith("Build ") + val applicable = !configuration.name.startsWith("Build ") && !configuration.name.startsWith("Tomcat") if (!applicable) { MirrordLogger.logger.info("Configuration name %s ignored".format(configuration.name)) diff --git a/modules/products/tomcat/build.gradle.kts b/modules/products/tomcat/build.gradle.kts new file mode 100644 index 00000000..98306961 --- /dev/null +++ b/modules/products/tomcat/build.gradle.kts @@ -0,0 +1,26 @@ +fun properties(key: String) = project.findProperty(key).toString() + +plugins { + // Java support + id("java") + // Kotlin support + id("org.jetbrains.kotlin.jvm") version "1.8.22" + // Gradle IntelliJ Plugin + id("org.jetbrains.intellij") version "1.+" +} + +tasks { + buildSearchableOptions { + enabled = false + } +} + +intellij { + version.set(properties("platformVersion")) + type.set("IU") + plugins.set(listOf("Tomcat:223.7571.182", "com.intellij.javaee.app.servers.integration")) +} + +dependencies { + implementation(project(":mirrord-core")) +} diff --git a/modules/products/tomcat/src/main/kotlin/com/metalbear/mirrord/products/tomcat/TomcatExecutionListener.kt b/modules/products/tomcat/src/main/kotlin/com/metalbear/mirrord/products/tomcat/TomcatExecutionListener.kt new file mode 100644 index 00000000..06f2e074 --- /dev/null +++ b/modules/products/tomcat/src/main/kotlin/com/metalbear/mirrord/products/tomcat/TomcatExecutionListener.kt @@ -0,0 +1,97 @@ +@file:Suppress("UnstableApiUsage") + +package com.metalbear.mirrord.products.tomcat + +import com.intellij.execution.ExecutionListener +import com.intellij.execution.process.ProcessHandler +import com.intellij.execution.runners.ExecutionEnvironment +import com.intellij.execution.target.createEnvironmentRequest +import com.intellij.execution.util.EnvironmentVariable +import com.intellij.execution.wsl.target.WslTargetEnvironmentRequest +import com.intellij.javaee.appServers.run.configuration.RunnerSpecificLocalConfigurationBit +import com.intellij.notification.NotificationType +import com.intellij.openapi.components.service +import com.metalbear.mirrord.CONFIG_ENV_NAME +import com.metalbear.mirrord.MirrordLogger +import com.metalbear.mirrord.MirrordProjectService +import java.util.concurrent.ConcurrentHashMap + +private const val DEFAULT_TOMCAT_SERVER_PORT: String = "8005" + +private fun getTomcatServerPort(): String { + return System.getenv("MIRRORD_TOMCAT_SERVER_PORT") ?: DEFAULT_TOMCAT_SERVER_PORT +} + +class TomcatExecutionListener : ExecutionListener { + private val savedEnvs: ConcurrentHashMap> = ConcurrentHashMap() + + private fun getConfig(env: ExecutionEnvironment): RunnerSpecificLocalConfigurationBit? { + if (!env.toString().startsWith("Tomcat")) { + return null + } + + val settings = env.configurationSettings ?: return null + + return if (settings is RunnerSpecificLocalConfigurationBit) { + settings + } else { + null + } + } + + override fun processStartScheduled(executorId: String, env: ExecutionEnvironment) { + getConfig(env)?.let { config -> + val envVars = config.envVariables + + val service = env.project.service() + + MirrordLogger.logger.debug("wsl check") + val wsl = when (val request = createEnvironmentRequest(env.runProfile, env.project)) { + is WslTargetEnvironmentRequest -> request.configuration.distribution!! + else -> null + } + + try { + val mirrordEnv = service.execManager.wrapper("idea").apply { + this.wsl = wsl + configFromEnv = envVars.find { e -> e.name == CONFIG_ENV_NAME }?.VALUE + }.start()?.first?.let { it + mapOf(Pair("MIRRORD_DETECT_DEBUGGER_PORT", "javaagent")) }.orEmpty().toMutableMap() + + // This should allow clean shutdown of the app even if `outgoing` feature is enabled. + mirrordEnv["MIRRORD_IGNORE_DEBUGGER_PORTS"] = getTomcatServerPort() + + savedEnvs[executorId] = envVars.toList() + envVars.addAll(mirrordEnv.map { (k, v) -> EnvironmentVariable(k, v, false) }) + config.setEnvironmentVariables(envVars) + } catch (_: Throwable) { + // Error notifications were already fired. + // We can't abort the execution here, so we let the app run without mirrord. + service.notifier.notifySimple( + "Cannot abort run due to platform limitations, running without mirrord", + NotificationType.WARNING + ) + } + } + + super.processStartScheduled(executorId, env) + } + + private fun restoreEnv(executorId: String, config: RunnerSpecificLocalConfigurationBit) { + val saved = savedEnvs.remove(executorId) ?: return + config.setEnvironmentVariables(saved) + } + + override fun processNotStarted(executorId: String, env: ExecutionEnvironment) { + getConfig(env)?.let { + restoreEnv(executorId, it) + } + super.processNotStarted(executorId, env) + } + + override fun processStarted(executorId: String, env: ExecutionEnvironment, handler: ProcessHandler) { + getConfig(env)?.let { + restoreEnv(executorId, it) + } + super.processStarted(executorId, env, handler) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 746f316e..b8f10ac8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -7,7 +7,8 @@ include( "modules/products/pycharm", "modules/products/rubymine", "modules/products/nodejs", - "modules/products/rider" + "modules/products/rider", + "modules/products/tomcat" ) // Rename modules to mirrord-, I think this is required IntelliJ wise. diff --git a/src/main/resources/META-INF/mirrord-tomcat.xml b/src/main/resources/META-INF/mirrord-tomcat.xml new file mode 100644 index 00000000..ab2236b7 --- /dev/null +++ b/src/main/resources/META-INF/mirrord-tomcat.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index d41a5456..49a8bb95 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -72,4 +72,5 @@ org.jetbrains.plugins.go NodeJS com.intellij.modules.rider + Tomcat