Skip to content

Commit 9162e1e

Browse files
committed
tests are green #21
1 parent 6b106d9 commit 9162e1e

File tree

7 files changed

+233
-102
lines changed

7 files changed

+233
-102
lines changed

core/src/main/kotlin/org/utbot/jcdb/impl/index/HierarchyExtension.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class HierarchyExtension(private val db: CompilationDatabase, private val cp: Cl
2525
suspend fun findOverrides(methodId: MethodId): List<MethodId> {
2626
val desc = methodId.description()
2727
val name = methodId.name
28-
val subClasses = findSubClasses(methodId.classId, allHierarchy = true)
28+
val subClasses = cp.findSubClasses(methodId.classId, allHierarchy = true)
2929
return subClasses.mapNotNull {
3030
it.findMethodOrNull(name, desc)
3131
}

remote-rd/src/main/kotlin/org/utbot/jcdb/remote/rd/InternalApi.kt

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ class GetClasspathReq(val locations: List<String>) {
3232
}
3333
}
3434

35-
class GetClassReq(val cpKey: String, val className: String) {
35+
abstract class ClasspathBasedReq(val cpKey: String)
36+
37+
open class GetClassReq(cpKey: String, val className: String) : ClasspathBasedReq(cpKey) {
3638

3739
companion object : IMarshaller<GetClassReq> {
3840

@@ -70,4 +72,49 @@ class GetClassRes(val location: String?, val serializedClassInfo: ByteArray) {
7072
buffer.writeByteArray(value.serializedClassInfo)
7173
}
7274
}
75+
}
76+
77+
class GetSubClassesReq(cpKey: String, className: String, val allHierarchy: Boolean) :
78+
GetClassReq(cpKey, className) {
79+
80+
companion object : IMarshaller<GetSubClassesReq> {
81+
82+
override val _type: KClass<GetSubClassesReq> = GetSubClassesReq::class
83+
84+
override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): GetSubClassesReq {
85+
return GetSubClassesReq(
86+
buffer.readString(),
87+
buffer.readString(),
88+
buffer.readBoolean()
89+
)
90+
}
91+
92+
override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: GetSubClassesReq) {
93+
buffer.writeString(value.cpKey)
94+
buffer.writeString(value.className)
95+
buffer.writeBoolean(value.allHierarchy)
96+
}
97+
}
98+
}
99+
100+
class GetSubClassesRes(val classes: List<GetClassRes>) {
101+
102+
companion object : IMarshaller<GetSubClassesRes> {
103+
104+
override val _type: KClass<GetSubClassesRes> = GetSubClassesRes::class
105+
106+
override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): GetSubClassesRes {
107+
return GetSubClassesRes(
108+
buffer.readArray {
109+
GetClassRes.read(ctx, buffer)
110+
}.toList()
111+
)
112+
}
113+
114+
override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: GetSubClassesRes) {
115+
buffer.writeArray(value.classes.toTypedArray()) {
116+
GetClassRes.write(ctx, buffer, it)
117+
}
118+
}
119+
}
73120
}

remote-rd/src/main/kotlin/org/utbot/jcdb/remote/rd/RDServer.kt

Lines changed: 12 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
package org.utbot.jcdb.remote.rd
22

3-
import com.jetbrains.rd.framework.*
4-
import com.jetbrains.rd.framework.base.IRdBindable
5-
import com.jetbrains.rd.framework.base.static
6-
import com.jetbrains.rd.framework.impl.RdCall
3+
import com.jetbrains.rd.framework.IdKind
4+
import com.jetbrains.rd.framework.Identities
5+
import com.jetbrains.rd.framework.Protocol
6+
import com.jetbrains.rd.framework.SocketWire
77
import com.jetbrains.rd.util.lifetime.Lifetime
88
import com.jetbrains.rd.util.threading.SingleThreadScheduler
99
import kotlinx.coroutines.runBlocking
10-
import kotlinx.serialization.cbor.Cbor
11-
import kotlinx.serialization.encodeToByteArray
12-
import org.utbot.jcdb.api.ClassId
1310
import org.utbot.jcdb.api.ClasspathSet
1411
import org.utbot.jcdb.api.Hook
1512
import org.utbot.jcdb.compilationDatabase
1613
import org.utbot.jcdb.impl.CompilationDatabaseImpl
17-
import org.utbot.jcdb.impl.types.*
1814
import org.utbot.jcdb.remote.rd.client.RemoteCompilationDatabase
19-
import java.io.File
2015
import java.util.concurrent.ConcurrentHashMap
2116

2217

@@ -36,73 +31,24 @@ class RDServer(port: Int, val db: CompilationDatabaseImpl) : Hook {
3631
lifetimeDef
3732
)
3833

39-
private val getClasspath = RdCall<GetClasspathReq, String>(null, null) { req ->
40-
val key = req.locations.sorted().joinToString()
41-
val cp = runBlocking {
42-
db.classpathSet(req.locations.map { File(it) })
43-
}
44-
classpaths[key] = cp
45-
key
46-
}.makeAsync()
47-
48-
private val closeClasspath = RdCall<String, Unit>(null, null) { req ->
49-
classpaths[req]?.close()
50-
classpaths.remove(req)
51-
}.makeAsync()
52-
53-
private val getClass = RdCall<GetClassReq, GetClassRes?>(null, null) { req ->
54-
val key = req.cpKey
55-
val cp = classpaths[key] ?: throw IllegalStateException("No classpath found by key $key. \n Create it first")
56-
runBlocking {
57-
when (val classId = cp.findClassOrNull(req.className)) {
58-
is ClassId -> {
59-
val bytes = Cbor.encodeToByteArray(classId.convertToContainer())
60-
val url = classId.location?.locationURL
61-
GetClassRes(url?.toString(), bytes)
62-
}
63-
else -> null
64-
}
65-
}
66-
}.makeAsync()
34+
private val resources = listOf(
35+
GetClasspathResource(classpaths),
36+
CloseClasspathResource(classpaths),
37+
GetClassResource(classpaths),
38+
GetSubClassesResource(classpaths),
39+
)
6740

6841
override fun afterStart() {
69-
scheduler.invokeOrQueue {
70-
getClasspath.static(1)
71-
closeClasspath.static(3)
72-
getClass.static(2)
73-
74-
serverProtocol.bindStatic(getClasspath, "get-classpath")
75-
serverProtocol.bindStatic(closeClasspath, "close-classpath")
76-
serverProtocol.bindStatic(getClass, "get-class")
77-
}
42+
resources.forEach { it.serverCall(serverProtocol, db) }
7843
scheduler.flush()
7944
}
8045

8146
override fun afterStop() {
82-
println("TERMINATED: " + lifetimeDef.terminate(true))
83-
}
84-
85-
private fun <T : IRdBindable> IProtocol.bindStatic(x: T, name: String): T {
86-
x.bind(lifetimeDef, this, name)
87-
return x
88-
}
89-
90-
private suspend fun ClassId.convertToContainer(): ClassInfoContainer {
91-
return when (this) {
92-
is ArrayClassIdImpl -> ArrayClassInfo(elementClass.convertToContainer())
93-
is ClassIdImpl -> info()
94-
is PredefinedPrimitive -> info
95-
else -> throw IllegalStateException("Can't convert class ${name} to serializable class info")
96-
}
47+
lifetimeDef.terminate(true)
9748
}
9849

9950
}
10051

101-
fun <T, X> RdCall<T, X>.makeAsync(): RdCall<T, X> {
102-
async = true
103-
return this
104-
}
105-
10652
fun main() {
10753
val db = runBlocking {
10854
compilationDatabase {
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package org.utbot.jcdb.remote.rd
2+
3+
import com.jetbrains.rd.framework.IMarshaller
4+
import com.jetbrains.rd.framework.IProtocol
5+
import com.jetbrains.rd.framework.Protocol
6+
import com.jetbrains.rd.framework.base.IRdBindable
7+
import com.jetbrains.rd.framework.base.static
8+
import com.jetbrains.rd.framework.impl.RdCall
9+
import kotlinx.coroutines.runBlocking
10+
import kotlinx.serialization.cbor.Cbor
11+
import kotlinx.serialization.encodeToByteArray
12+
import org.utbot.jcdb.api.ClassId
13+
import org.utbot.jcdb.api.ClasspathSet
14+
import org.utbot.jcdb.api.CompilationDatabase
15+
import org.utbot.jcdb.impl.types.*
16+
import java.io.File
17+
import java.util.concurrent.ConcurrentHashMap
18+
19+
abstract class CallResource<REQUEST, RESPONSE>(val id: Int, val name: String) {
20+
21+
private val clientProperty: RdCall<REQUEST, RESPONSE> get() = RdCall<REQUEST, RESPONSE>().static(id).makeAsync()
22+
23+
private fun serverProperty(db: CompilationDatabase): RdCall<REQUEST, RESPONSE> {
24+
return RdCall<REQUEST, RESPONSE>(null, null) { req ->
25+
db.handler(req)
26+
}.makeAsync().static(id)
27+
}
28+
29+
abstract fun CompilationDatabase.handler(req: REQUEST): RESPONSE
30+
open val serializers: List<IMarshaller<*>> = emptyList()
31+
32+
fun clientCall(protocol: Protocol): RdCall<REQUEST, RESPONSE> {
33+
return protocol.register("client") { clientProperty }
34+
}
35+
36+
fun serverCall(protocol: Protocol, db: CompilationDatabase): RdCall<REQUEST, RESPONSE> {
37+
return protocol.register("server") { serverProperty(db) }
38+
}
39+
40+
private fun Protocol.register(prefix: String, getter: () -> RdCall<REQUEST, RESPONSE>): RdCall<REQUEST, RESPONSE> {
41+
this@CallResource.serializers.forEach {
42+
serializers.register(it)
43+
}
44+
val property = getter()
45+
scheduler.queue {
46+
bindStatic(property, "$prefix-${this@CallResource.name}")
47+
}
48+
return property
49+
}
50+
51+
52+
private fun <T : IRdBindable> IProtocol.bindStatic(x: T, name: String): T {
53+
x.bind(lifetime, this, name)
54+
return x
55+
}
56+
57+
private fun <T, X> RdCall<T, X>.makeAsync(): RdCall<T, X> {
58+
async = true
59+
return this
60+
}
61+
62+
}
63+
64+
class GetClasspathResource(private val classpaths: ConcurrentHashMap<String, ClasspathSet> = ConcurrentHashMap()) :
65+
CallResource<GetClasspathReq, String>(1, "get-classpath") {
66+
67+
override val serializers = listOf(GetClasspathReq)
68+
69+
override fun CompilationDatabase.handler(req: GetClasspathReq): String {
70+
val key = req.locations.sorted().joinToString()
71+
val cp = runBlocking {
72+
classpathSet(req.locations.map { File(it) })
73+
}
74+
classpaths[key] = cp
75+
return key
76+
}
77+
}
78+
79+
class CloseClasspathResource(private val classpaths: ConcurrentHashMap<String, ClasspathSet> = ConcurrentHashMap()) :
80+
CallResource<String, Unit>(2, "close-classpath") {
81+
82+
override fun CompilationDatabase.handler(req: String) {
83+
classpaths[req]?.close()
84+
classpaths.remove(req)
85+
}
86+
}
87+
88+
abstract class AbstractClasspathResource<REQUEST : ClasspathBasedReq, RESPONSE>(
89+
id: Int, name: String, private val classpaths: ConcurrentHashMap<String, ClasspathSet> = ConcurrentHashMap()
90+
) : CallResource<REQUEST, RESPONSE>(id, name) {
91+
92+
override fun CompilationDatabase.handler(req: REQUEST): RESPONSE {
93+
val key = req.cpKey
94+
val cp = classpaths[key] ?: throw IllegalStateException("No classpath found by key $key. \n Create it first")
95+
return runBlocking {
96+
cp.handler(req)
97+
}
98+
}
99+
100+
protected abstract suspend fun ClasspathSet.handler(req: REQUEST): RESPONSE
101+
102+
protected suspend fun ClassId.toGetClass(): GetClassRes {
103+
val bytes = Cbor.encodeToByteArray(convertToContainer())
104+
val url = location?.locationURL
105+
return GetClassRes(url?.toString(), bytes)
106+
}
107+
108+
}
109+
110+
111+
class GetClassResource(classpaths: ConcurrentHashMap<String, ClasspathSet> = ConcurrentHashMap()) :
112+
AbstractClasspathResource<GetClassReq, GetClassRes?>(3, "get-class", classpaths) {
113+
114+
override suspend fun ClasspathSet.handler(req: GetClassReq): GetClassRes? {
115+
return findClassOrNull(req.className)?.toGetClass()
116+
}
117+
}
118+
119+
class GetSubClassesResource(classpaths: ConcurrentHashMap<String, ClasspathSet> = ConcurrentHashMap()) :
120+
AbstractClasspathResource<GetSubClassesReq, GetSubClassesRes>(4, "get-sub-classes", classpaths) {
121+
122+
override val serializers = listOf(GetSubClassesRes, GetSubClassesReq)
123+
124+
override suspend fun ClasspathSet.handler(req: GetSubClassesReq): GetSubClassesRes {
125+
val subclasses = findSubClasses(req.className, req.allHierarchy).map { it.toGetClass() }
126+
return GetSubClassesRes(subclasses)
127+
}
128+
}
129+
130+
131+
private suspend fun ClassId.convertToContainer(): ClassInfoContainer {
132+
return when (this) {
133+
is ArrayClassIdImpl -> ArrayClassInfo(elementClass.convertToContainer())
134+
is ClassIdImpl -> info()
135+
is PredefinedPrimitive -> info
136+
else -> throw IllegalStateException("Can't convert class ${name} to serializable class info")
137+
}
138+
}
139+

remote-rd/src/main/kotlin/org/utbot/jcdb/remote/rd/client/RemoteClasspathSet.kt

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,33 @@ import org.utbot.jcdb.api.CompilationDatabase
1010
import org.utbot.jcdb.impl.types.*
1111
import org.utbot.jcdb.remote.rd.GetClassReq
1212
import org.utbot.jcdb.remote.rd.GetClassRes
13+
import org.utbot.jcdb.remote.rd.GetSubClassesReq
14+
import org.utbot.jcdb.remote.rd.GetSubClassesRes
1315

1416
class RemoteClasspathSet(
1517
private val key: String,
18+
override val db: CompilationDatabase,
1619
private val getClass: RdCall<GetClassReq, GetClassRes?>,
17-
private val close: RdCall<String, Unit>
20+
private val close: RdCall<String, Unit>,
21+
private val getSubClasses: RdCall<GetSubClassesReq, GetSubClassesRes>
1822
) : ClasspathSet {
1923

2024
override val locations: List<ByteCodeLocation>
2125
get() = emptyList()
2226

23-
override val db: CompilationDatabase
24-
get() = TODO("Not yet implemented")
25-
2627
override suspend fun refreshed(closeOld: Boolean) = this
2728

2829
override suspend fun findClassOrNull(name: String): ClassId? {
29-
val res = getClass.startSuspending(GetClassReq(key, name)) ?: return null
30-
val info = Cbor.decodeFromByteArray<ClassInfoContainer>(res.serializedClassInfo)
31-
return info.asClassId(res.location)
30+
return getClass.startSuspending(GetClassReq(key, name))?.asClassId() ?: return null
3231
}
3332

3433
override suspend fun findSubClasses(name: String, allHierarchy: Boolean): List<ClassId> {
35-
TODO("Not yet implemented")
34+
val res = getSubClasses.startSuspending(GetSubClassesReq(key, name, allHierarchy))
35+
return res.classes.map { it.asClassId() }
3636
}
3737

3838
override suspend fun findSubClasses(classId: ClassId, allHierarchy: Boolean): List<ClassId> {
39-
TODO("Not yet implemented")
39+
return findSubClasses(classId.name, allHierarchy)
4040
}
4141

4242
override suspend fun <T> query(key: String, term: String): List<T> {
@@ -55,9 +55,15 @@ class RemoteClasspathSet(
5555
return when (this) {
5656
is ArrayClassInfo -> ArrayClassIdImpl(elementInfo.asClassId(location))
5757
is ClassInfo -> RemoteClassId(location, this, this@RemoteClasspathSet)
58-
is PredefinedClassInfo -> PredefinedPrimitives.of(name, this@RemoteClasspathSet) ?: throw IllegalStateException("unsupported predefined name $name")
58+
is PredefinedClassInfo -> PredefinedPrimitives.of(name, this@RemoteClasspathSet)
59+
?: throw IllegalStateException("unsupported predefined name $name")
5960
else -> throw IllegalStateException("unsupported class info container type ${this.javaClass.name}")
6061
}
6162
}
6263

64+
private fun GetClassRes.asClassId(): ClassId {
65+
val info = Cbor.decodeFromByteArray<ClassInfoContainer>(serializedClassInfo)
66+
return info.asClassId(location)
67+
}
68+
6369
}

0 commit comments

Comments
 (0)