Skip to content

Commit feff7e7

Browse files
committed
Merge remote-tracking branch 'origin/main' into node-reference-resolution
# Conflicts: # model-client/build.gradle.kts
2 parents 326289e + 7fcd8bf commit feff7e7

File tree

33 files changed

+470
-47
lines changed

33 files changed

+470
-47
lines changed

.github/workflows/build.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@ jobs:
2121
distribution: 'temurin'
2222
java-version: '11'
2323
- name: Build
24+
uses: gradle/gradle-build-action@v2
2425
env:
2526
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26-
run: ./gradlew build publishToMavenLocal -PciBuild=true
27+
with:
28+
arguments: |
29+
--build-cache
30+
build
31+
publishToMavenLocal
32+
-PciBuild=true
2733
- name: Test Model API Generator Gradle Plugin
2834
env:
2935
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
= mps-model-server-plugin
2+
3+
== Health checks
4+
5+
The plugin offers a set of health checks via HTTP on port 48305 and path `/health`.
6+
Health checks can be enabled adding query parameters with the health check name and the value `true` to the request.
7+
8+
=== indexer
9+
10+
The check fails, if the indexer is currently running for one of the opened projects.
11+
12+
[NOTE]
13+
====
14+
This check indicates a healthy system until a project is opened.
15+
Combine it with the `projects` health check to effectively wait for the system to be ready to serve data immediately.
16+
====
17+
18+
=== projects
19+
20+
Reports an unhealthy system whenever no project is loaded.
21+
22+
=== virtualFolders
23+
24+
Reports an unhealthy system when no virtual folders are available.
25+
This might also be true in case a project without virtual folders is fully loaded.

docs/global/modules/core/partials/nav-reference.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
* xref:core:reference/component-model-api-gen.adoc[]
55
* xref:core:reference/component-model-api-gen-gradle.adoc[]
66
* xref:core:reference/component-light-model-client.adoc[]
7+
* xref:core:reference/component-mps-model-server-plugin.adoc[]

gradle/libs.versions.toml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
1212
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
1313
gitVersion = { id = "com.palantir.git-version", version = "3.0.0" }
1414
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version = "11.5.1" }
15-
spotless = { id = "com.diffplug.spotless", version = "6.20.0" }
15+
spotless = { id = "com.diffplug.spotless", version = "6.21.0" }
1616
tasktree = { id = "com.dorongold.task-tree", version = "2.1.1" }
1717
modelix-mps-buildtools = { id = "org.modelix.mps.build-tools", version = "1.1.0" }
18-
dokka = {id = "org.jetbrains.dokka", version = "1.8.20"}
18+
dokka = {id = "org.jetbrains.dokka", version = "1.9.0"}
1919

2020
[versions]
2121
kotlin = "1.9.10"
2222
kotlinCoroutines="1.7.3"
23-
ktor="2.3.3"
23+
ktor="2.3.4"
2424
kotlinHtml="0.8.0"
2525
kotlinSerialization="1.6.0"
2626
ignite="2.15.0"
@@ -34,7 +34,7 @@ kotlin-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-s
3434
kotlin-serialization-yaml = { group = "com.charleskorn.kaml", name = "kaml", version = "0.55.0" }
3535
kotlin-logging = { group = "io.github.microutils", name = "kotlin-logging", version = "3.0.5" }
3636
kotlin-collections-immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version = "0.3.5" }
37-
kotlin-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version = "0.4.0" }
37+
kotlin-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version = "0.4.1" }
3838

3939
kotlin-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinCoroutines" }
4040
kotlin-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinCoroutines" }
@@ -55,14 +55,15 @@ ktor-server-websockets = { group = "io.ktor", name = "ktor-server-websockets", v
5555

5656
ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" }
5757
ktor-client-content-negotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktor" }
58+
ktor-client-mock = { group = "io.ktor", name = "ktor-client-mock", version.ref = "ktor" }
5859
ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktor" }
5960
ktor-client-websockets = { group = "io.ktor", name = "ktor-client-websockets", version.ref = "ktor" }
6061
ktor-client-js = { group = "io.ktor", name = "ktor-client-js", version.ref = "ktor" }
6162
ktor-client-auth = { group = "io.ktor", name = "ktor-client-auth", version.ref = "ktor" }
6263

6364
ktor-serialization-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktor" }
6465

65-
keycloak-authz-client = { group = "org.keycloak", name = "keycloak-authz-client", version = "22.0.1" }
66+
keycloak-authz-client = { group = "org.keycloak", name = "keycloak-authz-client", version = "22.0.3" }
6667
guava = { group = "com.google.guava", name = "guava", version = "32.1.2-jre" }
6768
modelix-incremental = { group = "org.modelix", name = "incremental", version = "0.2.0" }
6869
kotlinpoet = { group = "com.squareup", name = "kotlinpoet", version = "1.14.2" }
@@ -79,11 +80,11 @@ ignite-indexing = { group = "org.apache.ignite", name = "ignite-indexing", versi
7980
logback-classic = { group = "ch.qos.logback", name = "logback-classic", version = "1.4.11" }
8081
postgresql = { group = "org.postgresql", name = "postgresql", version = "42.6.0" }
8182
jcommander = { group = "com.beust", name = "jcommander", version = "1.82" }
82-
cucumber-java = { group = "io.cucumber", name = "cucumber-java", version = "7.13.0" }
83+
cucumber-java = { group = "io.cucumber", name = "cucumber-java", version = "7.14.0" }
8384
junit = { group = "junit", name = "junit", version = "4.13.2" }
8485

8586
apache-cxf-sse = { group = "org.apache.cxf", name = "cxf-rt-rs-sse", version.ref = "apacheCxf" }
8687
apache-cxf-client = { group = "org.apache.cxf", name = "cxf-rt-rs-client", version.ref = "apacheCxf" }
8788

8889
semver = { group = "org.semver", name = "api", version = "0.9.33"}
89-
dokka-versioning = { group = "org.jetbrains.dokka", name = "versioning-plugin", version = "1.8.20"}
90+
dokka-versioning = { group = "org.jetbrains.dokka", name = "versioning-plugin", version = "1.9.0"}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package org.modelix.metamodel
15+
16+
import org.modelix.model.api.INode
17+
import org.modelix.model.api.addNewChild
18+
19+
inline fun <reified NodeT : ITypedNode> INode.addNewChild(concept: INonAbstractConcept<NodeT>) =
20+
addNewChild(null, concept.untyped()).typed<NodeT>()
21+
22+
inline fun <reified NodeT : ITypedNode> INode.addNewChild(role: String, concept: INonAbstractConcept<NodeT>) =
23+
addNewChild(role, concept.untyped()).typed<NodeT>()

model-client/build.gradle.kts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ kotlin {
5555
}
5656
val commonTest by getting {
5757
dependencies {
58+
implementation(libs.ktor.client.mock)
59+
implementation(libs.kotlin.coroutines.test)
5860
implementation(kotlin("test"))
5961
}
6062
}
@@ -80,10 +82,6 @@ kotlin {
8082
implementation(libs.ktor.serialization.json)
8183
}
8284
}
83-
val jvmTest by getting {
84-
dependencies {
85-
}
86-
}
8785
val jsMain by getting {
8886
dependencies {
8987
implementation(kotlin("stdlib-js"))
@@ -92,10 +90,6 @@ kotlin {
9290
implementation(npm("js-base64", "^3.4.5"))
9391
}
9492
}
95-
val jsTest by getting {
96-
dependencies {
97-
}
98-
}
9993
}
10094
}
10195

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (c) 2023.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.modelix.model.client2
18+
19+
internal expect interface Closable {
20+
fun close()
21+
}

model-client/src/commonMain/kotlin/org/modelix/model/client2/IModelClientV2.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,19 @@ import org.modelix.model.lazy.BranchReference
1919
import org.modelix.model.lazy.RepositoryId
2020
import org.modelix.model.server.api.ModelQuery
2121

22+
/**
23+
* This interface is meant exclusively for model client usage.
24+
*
25+
* It is designed to ensure decoupling between model client usage operations and other aspects,
26+
* such as lifecycle management.
27+
* Users of this interface cannot incidentally depend on non-usage functionality.
28+
* See also: [Interface segregation principle](https://en.wikipedia.org/wiki/Interface_segregation_principle)
29+
*
30+
* Specifically, this interface should not be used for managing the client's lifecycle,
31+
* as the lifecycle management may vary depending on the specific implementation.
32+
* If you need to manage the client's lifecycle, use the methods in the class interface of the concrete implementations,
33+
* such as [ModelClientV2].
34+
*/
2235
interface IModelClientV2 {
2336
fun getClientId(): Int
2437
fun getIdGenerator(): IIdGenerator

model-client/src/commonMain/kotlin/org/modelix/model/client2/ModelClientV2.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import io.ktor.client.request.post
2424
import io.ktor.client.request.setBody
2525
import io.ktor.client.statement.bodyAsText
2626
import io.ktor.http.ContentType
27+
import io.ktor.http.URLBuilder
2728
import io.ktor.http.appendPathSegments
2829
import io.ktor.http.contentType
2930
import io.ktor.http.takeFrom
@@ -49,7 +50,7 @@ import kotlin.time.Duration.Companion.seconds
4950
class ModelClientV2(
5051
private val httpClient: HttpClient,
5152
val baseUrl: String,
52-
) : IModelClientV2 {
53+
) : IModelClientV2, Closable {
5354
private var clientId: Int = 0
5455
private var idGenerator: IIdGenerator = IdGeneratorDummy()
5556
private var userId: String? = null
@@ -90,7 +91,7 @@ class ModelClientV2(
9091
val response = httpClient.post {
9192
url {
9293
takeFrom(baseUrl)
93-
appendPathSegments("repositories", repository.id, "init")
94+
appendPathSegmentsEncodingSlash("repositories", repository.id, "init")
9495
}
9596
}
9697
val delta = response.body<VersionDelta>()
@@ -110,7 +111,7 @@ class ModelClientV2(
110111
return httpClient.get {
111112
url {
112113
takeFrom(baseUrl)
113-
appendPathSegments("repositories", repository.id, "branches")
114+
appendPathSegmentsEncodingSlash("repositories", repository.id, "branches")
114115
}
115116
}.bodyAsText().lines().map { repository.getBranchReference(it) }
116117
}
@@ -138,7 +139,7 @@ class ModelClientV2(
138139
val response = httpClient.post {
139140
url {
140141
takeFrom(baseUrl)
141-
appendPathSegments("repositories", branch.repositoryId.id, "branches", branch.branchName)
142+
appendPathSegmentsEncodingSlash("repositories", branch.repositoryId.id, "branches", branch.branchName)
142143
}
143144
contentType(ContentType.Application.Json)
144145
val body = VersionDelta(version.getContentHash(), null, objectsMap = objects)
@@ -154,7 +155,7 @@ class ModelClientV2(
154155
val response = httpClient.get {
155156
url {
156157
takeFrom(baseUrl)
157-
appendPathSegments("repositories", branch.repositoryId.id, "branches", branch.branchName)
158+
appendPathSegmentsEncodingSlash("repositories", branch.repositoryId.id, "branches", branch.branchName)
158159
if (lastKnownVersion != null) {
159160
parameters["lastKnown"] = lastKnownVersion.hash
160161
}
@@ -170,7 +171,7 @@ class ModelClientV2(
170171
val response = httpClient.get {
171172
url {
172173
takeFrom(baseUrl)
173-
appendPathSegments("repositories", branch.repositoryId.id, "branches", branch.branchName, "poll")
174+
appendPathSegmentsEncodingSlash("repositories", branch.repositoryId.id, "branches", branch.branchName, "poll")
174175
if (lastKnownVersion != null) {
175176
parameters["lastKnown"] = lastKnownVersion.hash
176177
}
@@ -189,6 +190,10 @@ class ModelClientV2(
189190
TODO("Not yet implemented")
190191
}
191192

193+
override fun close() {
194+
httpClient.close()
195+
}
196+
192197
private fun createVersion(baseVersion: CLVersion?, delta: VersionDelta): CLVersion {
193198
return if (baseVersion == null) {
194199
CLVersion(
@@ -280,5 +285,8 @@ expect class ModelClientV2PlatformSpecificBuilder() : ModelClientV2Builder
280285
fun VersionDelta.checkObjectHashes() {
281286
HashUtil.checkObjectHashes(objectsMap)
282287
}
288+
private fun URLBuilder.appendPathSegmentsEncodingSlash(vararg components: String): URLBuilder {
289+
return appendPathSegments(components.toList(), true)
290+
}
283291

284292
fun VersionDelta.getAllObjects(): Map<String, String> = objectsMap + objects.associateBy { HashUtil.sha256(it) }

model-client/src/commonMain/kotlin/org/modelix/model/client2/ReplicatedModel.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import org.modelix.model.lazy.CLTree
1717
import org.modelix.model.lazy.CLVersion
1818
import org.modelix.model.operations.OTBranch
1919
import org.modelix.model.server.api.ModelQuery
20+
import kotlin.coroutines.cancellation.CancellationException
2021

2122
class ReplicatedModel(val client: IModelClientV2, val branchRef: BranchReference, val query: ModelQuery? = null) {
2223
private val scope = CoroutineScope(Dispatchers.Default)
@@ -62,6 +63,9 @@ class ReplicatedModel(val client: IModelClientV2, val branchRef: BranchReference
6263
} as CLVersion
6364
remoteVersionReceived(newRemoteVersion)
6465
nextDelayMs = 0
66+
} catch (ex: CancellationException) {
67+
LOG.debug { "Stop to poll branch $branchRef after disposing." }
68+
throw ex
6569
} catch (ex: Throwable) {
6670
LOG.error(ex) { "Failed to poll branch $branchRef" }
6771
nextDelayMs = (nextDelayMs * 3 / 2).coerceIn(1000, 30000)

0 commit comments

Comments
 (0)