diff --git a/platform/build-scripts/src/org/jetbrains/intellij/build/CommunityLibraryLicenses.kt b/platform/build-scripts/src/org/jetbrains/intellij/build/CommunityLibraryLicenses.kt index cf7cccf0e08d..9a2b79330603 100644 --- a/platform/build-scripts/src/org/jetbrains/intellij/build/CommunityLibraryLicenses.kt +++ b/platform/build-scripts/src/org/jetbrains/intellij/build/CommunityLibraryLicenses.kt @@ -1224,6 +1224,9 @@ object CommunityLibraryLicenses { jetbrainsLibrary("find-classes-model-experimental"), jetbrainsLibrary("find-file-model"), jetbrainsLibrary("find-file-model-experimental"), + jetbrainsLibrary("jetbrains.fleet.kernel"), + jetbrainsLibrary("jetbrains.fleet.rpc"), + jetbrainsLibrary("jetbrains.fleet.rpc.server"), jetbrainsLibrary("git-learning-project"), jetbrainsLibrary("intellij.remoterobot.remote.fixtures"), jetbrainsLibrary("intellij.remoterobot.robot.server.core"), diff --git a/platform/core-api/src/com/intellij/fleet/rpc/FleetRpc.kt b/platform/core-api/src/com/intellij/fleet/rpc/FleetRpc.kt deleted file mode 100644 index 0f7a8ff1e327..000000000000 --- a/platform/core-api/src/com/intellij/fleet/rpc/FleetRpc.kt +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.fleet.rpc - -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.client.ClientAppSession -import com.intellij.openapi.client.currentSession -import com.intellij.openapi.components.service -import fleet.rpc.core.FleetTransportFactory -import org.jetbrains.annotations.ApiStatus - -@ApiStatus.Internal -@ApiStatus.Experimental -interface FleetRpc { - companion object { - fun getInstance(session: ClientAppSession): FleetRpc = session.service() - fun getCurrentInstance(): FleetRpc = ApplicationManager.getApplication().currentSession.service() - } - - fun getTransportFactory(): FleetTransportFactory -} - - diff --git a/platform/kernel/backend/intellij.platform.kernel.backend.iml b/platform/kernel/backend/intellij.platform.kernel.backend.iml new file mode 100644 index 000000000000..69ba99de14f3 --- /dev/null +++ b/platform/kernel/backend/intellij.platform.kernel.backend.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/kernel/backend/resources/intellij.platform.kernel.backend.xml b/platform/kernel/backend/resources/intellij.platform.kernel.backend.xml new file mode 100644 index 000000000000..119c0b16fd39 --- /dev/null +++ b/platform/kernel/backend/resources/intellij.platform.kernel.backend.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/platform/kernel/backend/src/RemoteApiProvider.kt b/platform/kernel/backend/src/RemoteApiProvider.kt new file mode 100644 index 000000000000..ec92812f8279 --- /dev/null +++ b/platform/kernel/backend/src/RemoteApiProvider.kt @@ -0,0 +1,18 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.platform.kernel.backend + +import com.intellij.openapi.extensions.ExtensionPointName +import fleet.rpc.RemoteApi +import org.jetbrains.annotations.ApiStatus +import kotlin.reflect.KClass + +interface RemoteApiProvider { + data class RemoteApiDescriptor>(val klass: KClass, val service: () -> T) + + fun getApis(): List> + + companion object { + @ApiStatus.Internal + val EP_NAME = ExtensionPointName("com.intellij.platform.kernel.backend.remoteApiProvider") + } +} \ No newline at end of file diff --git a/platform/kernel/backend/src/RemoteApiRegistry.kt b/platform/kernel/backend/src/RemoteApiRegistry.kt new file mode 100644 index 000000000000..75c056ddc415 --- /dev/null +++ b/platform/kernel/backend/src/RemoteApiRegistry.kt @@ -0,0 +1,56 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.platform.kernel.backend + +import com.intellij.openapi.extensions.ExtensionPointListener +import com.intellij.openapi.extensions.PluginDescriptor +import com.intellij.platform.kernel.backend.RemoteApiProvider.Companion.EP_NAME +import com.intellij.platform.kernel.rpc.RemoteApiProviderService +import com.intellij.util.containers.ContainerUtil +import fleet.rpc.RemoteApi +import fleet.rpc.core.InstanceId +import kotlinx.coroutines.CoroutineScope +import java.util.concurrent.ConcurrentHashMap +import kotlin.collections.set +import kotlin.reflect.KClass + +class RemoteApiRegistry(private val coroutineScope: CoroutineScope) : RemoteApiProviderService { + private val remoteApis = ConcurrentHashMap>, RemoteApi>>() + private val visitedEPs = ContainerUtil.createConcurrentWeakKeyWeakValueMap() + + init { + EP_NAME.addExtensionPointListener(coroutineScope, object : ExtensionPointListener { + override fun extensionAdded(extension: RemoteApiProvider, pluginDescriptor: PluginDescriptor) { + if (visitedEPs.putIfAbsent(extension, Unit) == null) { + val apis = extension.getApis() + for (api in apis) { + remoteApis[api.klass.toInstanceId] = api.klass to api.service() + } + } + } + + override fun extensionRemoved(extension: RemoteApiProvider, pluginDescriptor: PluginDescriptor) { + visitedEPs.remove(extension) + val apis = extension.getApis() + synchronized(this) { + apis.forEach { api -> + remoteApis.remove(api.klass.toInstanceId) + } + } + } + }) + EP_NAME.extensions.filter { visitedEPs.putIfAbsent(it, Unit) == null }.flatMap { it.getApis() }.forEach { api -> + remoteApis[api.klass.toInstanceId] = api.klass to api.service() + } + } + + override fun > resolve(kclass: KClass): T { + return remoteApis[kclass.toInstanceId]?.second as? T ?: throw IllegalStateException("No remote API found for $kclass") + } + + fun resolve(instanceId: InstanceId): Pair>, RemoteApi> { + return remoteApis[instanceId] ?: throw IllegalStateException("No remote API found for $instanceId") + } +} + +private val KClass>.toInstanceId: InstanceId + get() = InstanceId(this.qualifiedName!!) diff --git a/platform/kernel/monolith/intellij.platform.kernel.monolith.iml b/platform/kernel/monolith/intellij.platform.kernel.monolith.iml new file mode 100644 index 000000000000..de5859c3d5e7 --- /dev/null +++ b/platform/kernel/monolith/intellij.platform.kernel.monolith.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/kernel/monolith/resources/intellij.platform.kernel.monolith.xml b/platform/kernel/monolith/resources/intellij.platform.kernel.monolith.xml new file mode 100644 index 000000000000..7d98f628cee6 --- /dev/null +++ b/platform/kernel/monolith/resources/intellij.platform.kernel.monolith.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/platform/kernel/monolith/src/MonolithKernelService.kt b/platform/kernel/monolith/src/MonolithKernelService.kt new file mode 100644 index 000000000000..7bd915fce5ef --- /dev/null +++ b/platform/kernel/monolith/src/MonolithKernelService.kt @@ -0,0 +1,35 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.platform.kernel.monolith + +import com.intellij.platform.kernel.KernelService +import com.intellij.platform.kernel.util.CommonInstructionSet +import com.intellij.platform.kernel.util.KernelRpcSerialization +import com.intellij.platform.kernel.util.ReadTracker +import com.intellij.platform.kernel.util.withKernel +import fleet.kernel.Kernel +import fleet.kernel.kernel +import fleet.kernel.rebase.LeaderKernelMiddleware +import fleet.kernel.rebase.encoder +import fleet.kernel.rete.Rete +import kotlinx.coroutines.* + +internal class MonolithKernelService(coroutineScope: CoroutineScope) : KernelService { + override val kernel: Kernel + override val rete: Rete + + init { + val kernelDeferred: CompletableDeferred = CompletableDeferred() + val reteDeferred : CompletableDeferred = CompletableDeferred() + + coroutineScope.launch(start = CoroutineStart.UNDISPATCHED) { + withKernel(middleware = LeaderKernelMiddleware(KernelRpcSerialization, CommonInstructionSet.encoder())) { + kernelDeferred.complete(kernel()) + reteDeferred.complete(currentCoroutineContext()[Rete]!!) + ReadTracker.subscribeForChanges() + } + } + kernel = kernelDeferred.getCompleted() + rete = reteDeferred.getCompleted() + } +} + diff --git a/platform/kernel/shared/intellij.platform.kernel.iml b/platform/kernel/shared/intellij.platform.kernel.iml new file mode 100644 index 000000000000..d9765246bab4 --- /dev/null +++ b/platform/kernel/shared/intellij.platform.kernel.iml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + $KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar + $MAVEN_REPOSITORY$/jetbrains/fleet/rhizomedb-compiler-plugin/1.9.20-0.17/rhizomedb-compiler-plugin-1.9.20-0.17.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/kernel/shared/resources/META-INF/services/fleet.util.logging.KLoggerFactory b/platform/kernel/shared/resources/META-INF/services/fleet.util.logging.KLoggerFactory new file mode 100644 index 000000000000..6984072c157b --- /dev/null +++ b/platform/kernel/shared/resources/META-INF/services/fleet.util.logging.KLoggerFactory @@ -0,0 +1 @@ +com.intellij.platform.kernel.util.IjLoggerFactory \ No newline at end of file diff --git a/platform/kernel/shared/resources/intellij.platform.kernel.xml b/platform/kernel/shared/resources/intellij.platform.kernel.xml new file mode 100644 index 000000000000..0bb1f9b01c4b --- /dev/null +++ b/platform/kernel/shared/resources/intellij.platform.kernel.xml @@ -0,0 +1,2 @@ + + diff --git a/platform/core-api/src/com/intellij/fleet/kernel/KernelService.kt b/platform/kernel/shared/src/KernelService.kt similarity index 71% rename from platform/core-api/src/com/intellij/fleet/kernel/KernelService.kt rename to platform/kernel/shared/src/KernelService.kt index 76e70a2df270..875b164561c6 100644 --- a/platform/core-api/src/com/intellij/fleet/kernel/KernelService.kt +++ b/platform/kernel/shared/src/KernelService.kt @@ -1,5 +1,5 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.fleet.kernel +package com.intellij.platform.kernel import com.intellij.openapi.application.ApplicationManager import fleet.kernel.DbSource @@ -7,10 +7,8 @@ import fleet.kernel.Kernel import fleet.kernel.rete.Rete import fleet.kernel.withCondition import kotlinx.coroutines.* -import org.jetbrains.annotations.ApiStatus +import kotlin.coroutines.CoroutineContext -@ApiStatus.Internal -@ApiStatus.Experimental interface KernelService { val kernel: Kernel val rete: Rete @@ -18,9 +16,11 @@ interface KernelService { val instance: KernelService get() = ApplicationManager.getApplication().getService(KernelService::class.java) + val kernelCoroutineContext: CoroutineContext + get() = instance.kernel + instance.rete + DbSource(instance.kernel.dbState, instance.kernel.toString()) + fun CoroutineScope.saga(condition: () -> Boolean = { true }, block: suspend CoroutineScope.() -> T): Deferred { - val instance = instance - return async(instance.kernel + instance.rete + DbSource(instance.kernel.dbState, instance.kernel.toString())) { + return async(kernelCoroutineContext) { withCondition(condition, block) } } diff --git a/platform/kernel/shared/src/rpc/RemoteApiProviderService.kt b/platform/kernel/shared/src/rpc/RemoteApiProviderService.kt new file mode 100644 index 000000000000..2f0592fa1492 --- /dev/null +++ b/platform/kernel/shared/src/rpc/RemoteApiProviderService.kt @@ -0,0 +1,16 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.platform.kernel.rpc + +import com.intellij.openapi.application.ApplicationManager +import fleet.rpc.RemoteApi +import kotlin.reflect.KClass + +interface RemoteApiProviderService { + fun > resolve(klass: KClass): T + + companion object { + fun > resolve(klass: KClass): T { + return ApplicationManager.getApplication().getService(RemoteApiProviderService::class.java).resolve(klass) + } + } +} \ No newline at end of file diff --git a/platform/kernel/shared/src/util/KLogger.kt b/platform/kernel/shared/src/util/KLogger.kt new file mode 100644 index 000000000000..40f8f031fa0d --- /dev/null +++ b/platform/kernel/shared/src/util/KLogger.kt @@ -0,0 +1,79 @@ +package com.intellij.platform.kernel.util + +import com.intellij.openapi.diagnostic.Logger +import fleet.util.logging.* +import kotlin.reflect.KClass + +class IjLogger(private val logger: Logger) : BaseLogger { + override val isTraceEnabled: Boolean + get() = logger.isTraceEnabled + override val isDebugEnabled: Boolean + get() = logger.isDebugEnabled + override val isInfoEnabled: Boolean + get() = true + override val isWarnEnabled: Boolean + get() = true + override val isErrorEnabled: Boolean + get() = true + + override fun trace(message: Any?) { + logger.trace(message?.toString() ?: "null") + } + + override fun trace(t: Throwable?, message: Any?) { + logger.trace(message?.toString() ?: "null") + if (t != null) { + logger.trace(t) + } + } + + override fun debug(message: Any?) { + logger.debug(message?.toString() ?: "null") + } + + override fun debug(t: Throwable?, message: Any?) { + logger.debug(message?.toString() ?: "null", t) + } + + override fun info(message: Any?) { + logger.info(message?.toString() ?: "null") + } + + override fun info(t: Throwable?, message: Any?) { + logger.info(message?.toString() ?: "null", t) + } + + override fun warn(message: Any?) { + logger.warn(message?.toString() ?: "null") + } + + override fun warn(t: Throwable?, message: Any?) { + logger.warn(message?.toString() ?: "null", t) + } + + override fun error(message: Any?) { + logger.error(message.toString()) + } + + override fun error(t: Throwable?, message: Any?) { + logger.error(message?.toString() ?: "null", t) + } +} + +class IjLoggerFactory : KLoggerFactory { + override fun logger(owner: KClass<*>): KLogger { + return KLogger(IjLogger(Logger.getInstance(owner.java))) + } + + override fun logger(owner: Class<*>): KLogger { + return KLogger(IjLogger(Logger.getInstance(owner))) + } + + override fun logger(owner: Any): KLogger { + return KLogger(IjLogger(Logger.getInstance(owner.toString()))) + } + + override fun logger(name: String): KLogger { + return KLogger(IjLogger(Logger.getInstance(name))) + } +} \ No newline at end of file diff --git a/platform/ide-core/src/com/intellij/kernel/ReadTrackingIndex.kt b/platform/kernel/shared/src/util/ReadTrackingIndex.kt similarity index 98% rename from platform/ide-core/src/com/intellij/kernel/ReadTrackingIndex.kt rename to platform/kernel/shared/src/util/ReadTrackingIndex.kt index 3d5d8b9ea327..eb8e24684a49 100644 --- a/platform/ide-core/src/com/intellij/kernel/ReadTrackingIndex.kt +++ b/platform/kernel/shared/src/util/ReadTrackingIndex.kt @@ -1,5 +1,5 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.kernel +package com.intellij.platform.kernel.util import com.jetbrains.rhizomedb.Datom import com.jetbrains.rhizomedb.Pattern @@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.ints.IntConsumer import it.unimi.dsi.fastutil.ints.IntOpenHashSet import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap import it.unimi.dsi.fastutil.longs.LongOpenHashSet +import kotlin.collections.set internal class ReadTrackingIndex : ReadTrackingContext { companion object { diff --git a/platform/ide-core/src/com/intellij/kernel/Entities.kt b/platform/kernel/shared/src/util/entities.kt similarity index 92% rename from platform/ide-core/src/com/intellij/kernel/Entities.kt rename to platform/kernel/shared/src/util/entities.kt index ca61b22103b6..c1ba51bb702b 100644 --- a/platform/ide-core/src/com/intellij/kernel/Entities.kt +++ b/platform/kernel/shared/src/util/entities.kt @@ -1,5 +1,5 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.kernel +package com.intellij.platform.kernel.util import com.jetbrains.rhizomedb.CascadeDeleteBy import com.jetbrains.rhizomedb.Unique diff --git a/platform/ide-core/src/com/intellij/kernel/KernelService.kt b/platform/kernel/shared/src/util/kernelUtils.kt similarity index 73% rename from platform/ide-core/src/com/intellij/kernel/KernelService.kt rename to platform/kernel/shared/src/util/kernelUtils.kt index c20c55e549c4..18ff2ce1f129 100644 --- a/platform/ide-core/src/com/intellij/kernel/KernelService.kt +++ b/platform/kernel/shared/src/util/kernelUtils.kt @@ -1,7 +1,6 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.kernel +package com.intellij.platform.kernel.util -import com.intellij.fleet.kernel.KernelService import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.asContextElement import com.intellij.util.concurrency.annotations.RequiresEdt @@ -11,7 +10,6 @@ import fleet.kernel.Kernel import fleet.kernel.KernelMiddleware import fleet.kernel.kernel import fleet.kernel.rebase.* -import fleet.kernel.rete.Rete import fleet.kernel.rete.withRete import fleet.kernel.subscribe import fleet.rpc.core.Serialization @@ -26,7 +24,7 @@ import java.util.concurrent.atomic.AtomicInteger @ApiStatus.Internal @ApiStatus.Experimental -suspend fun withKernel(scope: CoroutineScope, middleware: KernelMiddleware, body: suspend () -> T) { +suspend fun withKernel(middleware: KernelMiddleware, body: suspend () -> T) { val entityClasses = listOf(Kernel::class.java.classLoader).flatMap(::collectEntityClasses) fleet.kernel.withKernel(entityClasses, middleware = middleware) { currentKernel -> withRete { @@ -99,30 +97,6 @@ object ReadTracker { } } -val FleetRpcSerialization = Serialization(SerializersModule { +val KernelRpcSerialization = Serialization(SerializersModule { registerCRUDInstructions() }) - -class BaseKernelService(coroutineScope: CoroutineScope) : KernelService { - private val kernelDeferred: CompletableDeferred = CompletableDeferred() - private val reteDeferred : CompletableDeferred = CompletableDeferred() - - init { - coroutineScope.launch(start = CoroutineStart.ATOMIC) { - withKernel(this, middleware = LeaderKernelMiddleware(FleetRpcSerialization, CommonInstructionSet.encoder())) { - kernelDeferred.complete(kernel()) - reteDeferred.complete(currentCoroutineContext()[Rete]!!) - ReadTracker.subscribeForChanges() - } - } - runBlocking { - kernelDeferred.await() - reteDeferred.await() - } - } - - override val kernel: Kernel - get() = kernelDeferred.getCompleted() - override val rete: Rete - get() = reteDeferred.getCompleted() -} \ No newline at end of file diff --git a/platform/ide-core/src/com/intellij/kernel/Model.kt b/platform/kernel/shared/src/util/models.kt similarity index 98% rename from platform/ide-core/src/com/intellij/kernel/Model.kt rename to platform/kernel/shared/src/util/models.kt index 9c53b879209b..5508be49c625 100644 --- a/platform/ide-core/src/com/intellij/kernel/Model.kt +++ b/platform/kernel/shared/src/util/models.kt @@ -1,7 +1,7 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.kernel +package com.intellij.platform.kernel.util -import com.intellij.fleet.kernel.KernelService +import com.intellij.platform.kernel.KernelService import com.intellij.util.concurrency.annotations.RequiresEdt import com.jetbrains.rhizomedb.EID import com.jetbrains.rhizomedb.entity @@ -153,7 +153,6 @@ private class ModelChangeScopeImpl(val sharedChangeScope: SharedChangeScope) : M val value = serialization.json.encodeToJsonElement(serialization.kSerializer(ktype), value) val viewModel = lookupOne(ViewModelEntity::modelId, id) if (viewModel == null) { - println("Aha") throw IllegalStateException("ViewModelEntity not found for model $id") } val alreadyExist = lookupOne(ModelPropertyEntity::id, fqn)