Skip to content

Commit 0a85c54

Browse files
committed
Resolve issues with SpringAnalyzerProcess
1 parent 8ffdeb4 commit 0a85c54

File tree

17 files changed

+118
-109
lines changed

17 files changed

+118
-109
lines changed

utbot-core/src/main/kotlin/org/utbot/common/StandardStreamUtil.kt

Lines changed: 0 additions & 21 deletions
This file was deleted.

utbot-framework-api/src/main/kotlin/org/utbot/framework/process/CommonProcessArgs.kt

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,24 @@ import java.io.File
66
import java.nio.file.Path
77
import kotlin.io.path.pathString
88

9-
private val javaExecutablePathString: Path
10-
get() = JdkInfoService.jdkInfoProvider.info.path.resolve("bin${File.separatorChar}${osSpecificJavaExecutable()}")
9+
object CommonProcessArgs {
10+
private val javaExecutablePathString: Path
11+
get() = JdkInfoService.provide().path.resolve("bin${File.separatorChar}${osSpecificJavaExecutable()}")
1112

12-
fun obtainCommonProcessCommandLineArgs(
13-
debugPort: Int,
14-
runWithDebug: Boolean,
15-
suspendExecutionInDebugMode: Boolean,
16-
): List<String> = buildList {
17-
val suspendValue = if (suspendExecutionInDebugMode) "y" else "n"
18-
val debugArgument = "-agentlib:jdwp=transport=dt_socket,server=n,suspend=${suspendValue},quiet=y,address=$debugPort"
19-
.takeIf { runWithDebug }
13+
fun obtainCommonProcessCommandLineArgs(
14+
debugPort: Int,
15+
runWithDebug: Boolean,
16+
suspendExecutionInDebugMode: Boolean,
17+
): List<String> = buildList {
18+
val suspendValue = if (suspendExecutionInDebugMode) "y" else "n"
19+
val debugArgument = "-agentlib:jdwp=transport=dt_socket,server=n,suspend=${suspendValue},quiet=y,address=$debugPort"
20+
.takeIf { runWithDebug }
2021

21-
add(javaExecutablePathString.pathString)
22-
val javaVersionSpecificArgs = OpenModulesContainer.javaVersionSpecificArguments
23-
if (javaVersionSpecificArgs.isNotEmpty()) {
24-
addAll(javaVersionSpecificArgs)
22+
add(javaExecutablePathString.pathString)
23+
val javaVersionSpecificArgs = OpenModulesContainer.javaVersionSpecificArguments
24+
if (javaVersionSpecificArgs.isNotEmpty()) {
25+
addAll(javaVersionSpecificArgs)
26+
}
27+
debugArgument?.let { add(it) }
2528
}
26-
debugArgument?.let { add(it) }
27-
}
29+
}

utbot-framework/src/main/kotlin/org/utbot/framework/process/SpringAnalyzerProcess.kt

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ import org.utbot.rd.ProcessWithRdServer
1111
import org.utbot.rd.exceptions.InstantProcessDeathException
1212
import org.utbot.rd.generated.LoggerModel
1313
import org.utbot.rd.generated.loggerModel
14-
import org.utbot.rd.generated.synchronizationModel
1514
import org.utbot.rd.loggers.UtRdKLogger
16-
import org.utbot.rd.loggers.setupRdLogger
15+
import org.utbot.rd.loggers.setup
1716
import org.utbot.rd.onSchedulerBlocking
1817
import org.utbot.rd.rdPortArgument
1918
import org.utbot.rd.startBlocking
@@ -28,6 +27,8 @@ class SpringAnalyzerProcessInstantDeathException :
2827
InstantProcessDeathException(UtSettings.springAnalyzerProcessDebugPort, UtSettings.runSpringAnalyzerProcessWithDebug)
2928

3029
private const val SPRING_ANALYZER_JAR_FILENAME = "utbot-spring-analyzer-shadow.jar"
30+
private const val SPRING_ANALYZER_JAR_PATH = "lib/$SPRING_ANALYZER_JAR_FILENAME"
31+
private const val UNKNOWN_MODIFICATION_TIME = 0L
3132
private val logger = KotlinLogging.logger {}
3233
private val rdLogger = UtRdKLogger(logger, "")
3334

@@ -36,16 +37,34 @@ class SpringAnalyzerProcess private constructor(
3637
) : ProcessWithRdServer by rdProcess {
3738

3839
companion object {
39-
private fun obtainProcessSpecificCommandLineArgs(port: Int): List<String> {
40-
val jarFile =
41-
Files.createDirectories(utBotTempDirectory.toFile().resolve("spring-analyzer").toPath())
42-
.toFile().resolve(SPRING_ANALYZER_JAR_FILENAME)
43-
FileUtils.copyURLToFile(
44-
this::class.java.classLoader.getResource("lib/$SPRING_ANALYZER_JAR_FILENAME"),
45-
jarFile
46-
)
47-
return listOf(
48-
"-Dorg.apache.commons.logging.LogFactory=org.utbot.rd.loggers.RDApacheCommonsLogFactory",
40+
private val jarFile by lazy {
41+
Files.createDirectories(utBotTempDirectory.toFile().resolve("spring-analyzer").toPath())
42+
.toFile().resolve(SPRING_ANALYZER_JAR_FILENAME).also { jarFile ->
43+
val resource = this::class.java.classLoader.getResource(SPRING_ANALYZER_JAR_PATH)
44+
?: error("Unable to find \"$SPRING_ANALYZER_JAR_PATH\" in resources, make sure it's on the classpath")
45+
val resourceConnection = resource.openConnection()
46+
val lastResourceModification = try {
47+
resourceConnection.lastModified
48+
} finally {
49+
resourceConnection.getInputStream().close()
50+
}
51+
if (
52+
!jarFile.exists() ||
53+
jarFile.lastModified() == UNKNOWN_MODIFICATION_TIME ||
54+
lastResourceModification == UNKNOWN_MODIFICATION_TIME ||
55+
jarFile.lastModified() < lastResourceModification
56+
)
57+
FileUtils.copyURLToFile(resource, jarFile)
58+
}
59+
}
60+
61+
private fun obtainSpringAnalyzerProcessCommandLine(port: Int): List<String> {
62+
return CommonProcessArgs.obtainCommonProcessCommandLineArgs(
63+
debugPort = UtSettings.springAnalyzerProcessDebugPort,
64+
runWithDebug = UtSettings.runSpringAnalyzerProcessWithDebug,
65+
suspendExecutionInDebugMode = UtSettings.suspendSpringAnalyzerProcessExecutionInDebugMode,
66+
) + listOf(
67+
"-Dorg.apache.commons.logging.LogFactory=org.utbot.spring.loggers.RDApacheCommonsLogFactory",
4968
"-jar",
5069
jarFile.path,
5170
rdPortArgument(port)
@@ -56,11 +75,7 @@ class SpringAnalyzerProcess private constructor(
5675

5776
suspend operator fun invoke(): SpringAnalyzerProcess = LifetimeDefinition().terminateOnException { lifetime ->
5877
val rdProcess = startUtProcessWithRdServer(lifetime) { port ->
59-
val cmd = obtainCommonProcessCommandLineArgs(
60-
debugPort = UtSettings.springAnalyzerProcessDebugPort,
61-
runWithDebug = UtSettings.runSpringAnalyzerProcessWithDebug,
62-
suspendExecutionInDebugMode = UtSettings.suspendSpringAnalyzerProcessExecutionInDebugMode,
63-
) + obtainProcessSpecificCommandLineArgs(port)
78+
val cmd = obtainSpringAnalyzerProcessCommandLine(port)
6479
val process = ProcessBuilder(cmd)
6580
.directory(Files.createTempDirectory(utBotTempDirectory, "spring-analyzer").toFile())
6681
.start()
@@ -73,20 +88,14 @@ class SpringAnalyzerProcess private constructor(
7388
}
7489
rdProcess.awaitProcessReady()
7590
val proc = SpringAnalyzerProcess(rdProcess)
76-
setupRdLogger(rdProcess, proc.loggerModel, rdLogger)
91+
proc.loggerModel.setup(rdLogger, proc.lifetime)
7792
return proc
7893
}
7994
}
8095

8196
private val springAnalyzerModel: SpringAnalyzerProcessModel = onSchedulerBlocking { protocol.springAnalyzerProcessModel }
8297
private val loggerModel: LoggerModel = onSchedulerBlocking { protocol.loggerModel }
8398

84-
init {
85-
lifetime.onTermination {
86-
protocol.synchronizationModel.stopProcess.fire(Unit)
87-
}
88-
}
89-
9099
fun getBeanQualifiedNames(
91100
classpath: List<String>,
92101
configuration: String,

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessMain.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import org.utbot.rd.RdSettingsContainerFactory
2121
import org.utbot.rd.findRdPort
2222
import org.utbot.rd.generated.loggerModel
2323
import org.utbot.rd.generated.settingsModel
24-
import org.utbot.rd.generated.synchronizationModel
2524
import org.utbot.rd.loggers.UtRdRemoteLoggerFactory
25+
import org.utbot.rd.StandardStreamUtil
2626
import java.io.File
2727
import java.net.URLClassLoader
2828
import java.security.AllPermission
@@ -83,7 +83,7 @@ object InstrumentedProcessMain
8383
*/
8484
fun main(args: Array<String>) = runBlocking {
8585
// We don't want user code to litter the standard output, so we redirect it.
86-
silentlyCloseStandardStreams()
86+
StandardStreamUtil.silentlyCloseStandardStreams()
8787

8888
if (!args.contains(DISABLE_SANDBOX_OPTION)) {
8989
permissions {
@@ -97,7 +97,7 @@ fun main(args: Array<String>) = runBlocking {
9797

9898
try {
9999
ClientProtocolBuilder().withProtocolTimeout(messageFromMainTimeout).start(port) {
100-
synchronizationModel.initRemoteLogging.adviseOnce(lifetime) {
100+
loggerModel.initRemoteLogging.adviseOnce(lifetime) {
101101
Logger.set(Lifetime.Eternal, UtRdRemoteLoggerFactory(loggerModel))
102102
this.protocol.scheduler.queue { warmupMockito() }
103103
}

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/InstrumentedProcessRunner.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import org.utbot.common.scanForResourcesContaining
66
import org.utbot.common.utBotTempDirectory
77
import org.utbot.framework.UtSettings
88
import org.utbot.framework.plugin.services.WorkingDirService
9-
import org.utbot.framework.process.obtainCommonProcessCommandLineArgs
9+
import org.utbot.framework.process.CommonProcessArgs
1010
import org.utbot.instrumentation.agent.DynamicClassTransformer
1111
import org.utbot.rd.rdPortArgument
1212
import java.io.File
@@ -15,7 +15,7 @@ private val logger = KotlinLogging.logger {}
1515

1616
class InstrumentedProcessRunner {
1717
private val cmds: List<String> by lazy {
18-
obtainCommonProcessCommandLineArgs(
18+
CommonProcessArgs.obtainCommonProcessCommandLineArgs(
1919
debugPort = UtSettings.instrumentedProcessDebugPort,
2020
runWithDebug = UtSettings.runInstrumentedProcessWithDebug,
2121
suspendExecutionInDebugMode = UtSettings.suspendInstrumentedProcessExecutionInDebugMode

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/InstrumentedProcess.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@ import org.utbot.rd.ProcessWithRdServer
1414
import org.utbot.rd.exceptions.InstantProcessDeathException
1515
import org.utbot.rd.generated.LoggerModel
1616
import org.utbot.rd.generated.loggerModel
17-
import org.utbot.rd.generated.synchronizationModel
1817
import org.utbot.rd.loggers.UtRdKLogger
19-
import org.utbot.rd.loggers.UtRdRemoteLogger
20-
import org.utbot.rd.loggers.setupRdLogger
18+
import org.utbot.rd.loggers.setup
2119
import org.utbot.rd.onSchedulerBlocking
2220
import org.utbot.rd.startUtProcessWithRdServer
2321
import org.utbot.rd.terminateOnException
@@ -64,7 +62,7 @@ class InstrumentedProcess private constructor(
6462
logger.trace("rd process started")
6563

6664
val proc = InstrumentedProcess(classLoader, rdProcess)
67-
setupRdLogger(rdProcess, proc.loggerModel, rdLogger)
65+
proc.loggerModel.setup(rdLogger, proc.lifetime)
6866

6967
proc.lifetime.onTermination {
7068
logger.trace { "process is terminating" }

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ import org.utbot.framework.codegen.tree.ututils.UtilClassKind
2020
import org.utbot.framework.plugin.api.*
2121
import org.utbot.framework.plugin.services.JdkInfo
2222
import org.utbot.framework.plugin.services.WorkingDirService
23+
import org.utbot.framework.process.CommonProcessArgs
2324
import org.utbot.framework.process.generated.*
2425
import org.utbot.framework.process.generated.MethodDescription
25-
import org.utbot.framework.process.obtainCommonProcessCommandLineArgs
2626
import org.utbot.framework.util.Conflict
2727
import org.utbot.framework.util.ConflictTriggers
2828
import org.utbot.instrumentation.util.KryoHelper
@@ -102,25 +102,26 @@ class EngineProcess private constructor(val project: Project, private val classN
102102

103103
private const val startFileName = "org.utbot.framework.process.EngineProcessMainKt"
104104

105-
private fun obtainProcessSpecificCommandLineArgs(port: Int) = listOf(
106-
"-ea",
107-
log4j2ConfigSwitch,
108-
"-cp",
109-
pluginClasspath,
110-
startFileName,
111-
rdPortArgument(port)
112-
)
105+
private fun obtainEngineProcessCommandLine(port: Int): List<String> =
106+
CommonProcessArgs.obtainCommonProcessCommandLineArgs(
107+
debugPort = UtSettings.engineProcessDebugPort,
108+
runWithDebug = UtSettings.runEngineProcessWithDebug,
109+
suspendExecutionInDebugMode = UtSettings.suspendEngineProcessExecutionInDebugMode,
110+
) + listOf(
111+
"-ea",
112+
log4j2ConfigSwitch,
113+
"-cp",
114+
pluginClasspath,
115+
startFileName,
116+
rdPortArgument(port)
117+
)
113118

114119
fun createBlocking(project: Project, classNameToPath: Map<String, String?>): EngineProcess = runBlocking { EngineProcess(project, classNameToPath) }
115120

116121
suspend operator fun invoke(project: Project, classNameToPath: Map<String, String?>): EngineProcess =
117122
LifetimeDefinition().terminateOnException { lifetime ->
118123
val rdProcess = startUtProcessWithRdServer(lifetime) { port ->
119-
val cmd = obtainCommonProcessCommandLineArgs(
120-
debugPort = UtSettings.engineProcessDebugPort,
121-
runWithDebug = UtSettings.runEngineProcessWithDebug,
122-
suspendExecutionInDebugMode = UtSettings.suspendEngineProcessExecutionInDebugMode,
123-
) + obtainProcessSpecificCommandLineArgs(port)
124+
val cmd = obtainEngineProcessCommandLine(port)
124125
val directory = WorkingDirService.provide().toFile()
125126
val builder = ProcessBuilder(cmd).directory(directory)
126127
val process = builder.start()

utbot-rd/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ dependencies {
6969
implementation group: 'com.jetbrains.rd', name: 'rd-core', version: rdVersion
7070

7171
implementation group: 'io.github.microutils', name: 'kotlin-logging', version: kotlinLoggingVersion
72-
implementation group: 'commons-logging', name: 'commons-logging', version: commonsLoggingVersion
7372

7473
processWithRdServerMockImplementation project(':utbot-rd')
7574

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.utbot.rd
2+
3+
import org.utbot.common.silent
4+
import java.io.OutputStream
5+
import java.io.PrintStream
6+
7+
object StandardStreamUtil {
8+
fun silentlyCloseStandardStreams() {
9+
// we should change out/err streams as not to spend time on user output
10+
// and also because rd default logging system writes some initial values to stdout, polluting it as well
11+
val tmpStream = PrintStream(object : OutputStream() {
12+
override fun write(b: Int) {}
13+
})
14+
val prevOut = System.out
15+
val prevError = System.err
16+
System.setOut(tmpStream)
17+
System.setErr(tmpStream)
18+
// stdin/stderr should be closed as not to leave hanging descriptors
19+
// and we cannot log any exceptions here as rd remote logging is still not configured
20+
// so we pass any exceptions
21+
silent { prevOut.close() }
22+
silent { prevError.close() }
23+
}
24+
}

utbot-rd/src/main/kotlin/org/utbot/rd/generated/LoggerModel.Generated.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import kotlin.jvm.JvmStatic
1818
* #### Generated from [LoggerModel.kt:8]
1919
*/
2020
class LoggerModel private constructor(
21+
private val _initRemoteLogging: RdSignal<Unit>,
2122
private val _log: RdSignal<LogArguments>,
2223
private val _getCategoryMinimalLogLevel: RdCall<String, Int>
2324
) : RdExtBase() {
@@ -47,13 +48,14 @@ class LoggerModel private constructor(
4748
}
4849

4950

50-
const val serializationHash = -6259198217478203203L
51+
const val serializationHash = 1686273842005935878L
5152

5253
}
5354
override val serializersOwner: ISerializersOwner get() = LoggerModel
5455
override val serializationHash: Long get() = LoggerModel.serializationHash
5556

5657
//fields
58+
val initRemoteLogging: IAsyncSignal<Unit> get() = _initRemoteLogging
5759
val log: IAsyncSignal<LogArguments> get() = _log
5860

5961
/**
@@ -64,18 +66,21 @@ class LoggerModel private constructor(
6466
//methods
6567
//initializer
6668
init {
69+
_initRemoteLogging.async = true
6770
_log.async = true
6871
_getCategoryMinimalLogLevel.async = true
6972
}
7073

7174
init {
75+
bindableChildren.add("initRemoteLogging" to _initRemoteLogging)
7276
bindableChildren.add("log" to _log)
7377
bindableChildren.add("getCategoryMinimalLogLevel" to _getCategoryMinimalLogLevel)
7478
}
7579

7680
//secondary constructor
7781
private constructor(
7882
) : this(
83+
RdSignal<Unit>(FrameworkMarshallers.Void),
7984
RdSignal<LogArguments>(LogArguments),
8085
RdCall<String, Int>(FrameworkMarshallers.String, FrameworkMarshallers.Int)
8186
)
@@ -86,6 +91,7 @@ class LoggerModel private constructor(
8691
override fun print(printer: PrettyPrinter) {
8792
printer.println("LoggerModel (")
8893
printer.indent {
94+
print("initRemoteLogging = "); _initRemoteLogging.print(printer); println()
8995
print("log = "); _log.print(printer); println()
9096
print("getCategoryMinimalLogLevel = "); _getCategoryMinimalLogLevel.print(printer); println()
9197
}
@@ -94,6 +100,7 @@ class LoggerModel private constructor(
94100
//deepClone
95101
override fun deepClone(): LoggerModel {
96102
return LoggerModel(
103+
_initRemoteLogging.deepClonePolymorphic(),
97104
_log.deepClonePolymorphic(),
98105
_getCategoryMinimalLogLevel.deepClonePolymorphic()
99106
)

0 commit comments

Comments
 (0)