Skip to content

Commit

Permalink
Tomcat support (#185)
Browse files Browse the repository at this point in the history
* TomcatExecutionListener

* Catch exceptions and allow running

* Ignore default Tomcat server port

* Changelog entry

* Format fix

* Environment variable for tomcat server port
  • Loading branch information
Razz4780 authored Oct 25, 2023
1 parent 1652125 commit a6a1295
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 3 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
1 change: 1 addition & 0 deletions changelog.d/183.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed Tomcat support.
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -25,7 +27,7 @@ class IdeaRunConfigurationExtension : RunConfigurationExtension() {
private val runningProcessEnvs = ConcurrentHashMap<Project, Map<String, String>>()

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))
Expand Down
26 changes: 26 additions & 0 deletions modules/products/tomcat/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -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"))
}
Original file line number Diff line number Diff line change
@@ -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<String, List<EnvironmentVariable>> = 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<MirrordProjectService>()

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)
}
}
3 changes: 2 additions & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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-<module>, I think this is required IntelliJ wise.
Expand Down
6 changes: 6 additions & 0 deletions src/main/resources/META-INF/mirrord-tomcat.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<idea-plugin>
<projectListeners>
<listener class="com.metalbear.mirrord.products.tomcat.TomcatExecutionListener"
topic="com.intellij.execution.ExecutionListener"/>
</projectListeners>
</idea-plugin>
1 change: 1 addition & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,5 @@
<depends optional="true" config-file="mirrord-goland.xml">org.jetbrains.plugins.go</depends>
<depends optional="true" config-file="mirrord-js.xml">NodeJS</depends>
<depends optional="true" config-file="mirrord-rider.xml">com.intellij.modules.rider</depends>
<depends optional="true" config-file="mirrord-tomcat.xml">Tomcat</depends>
</idea-plugin>

0 comments on commit a6a1295

Please sign in to comment.