Skip to content

Commit 85e95ea

Browse files
author
Robert Winkler
committed
Migrated DataSchema to JsonNode and enhanced Spring Boot WoTRuntime
1 parent d8893a0 commit 85e95ea

File tree

40 files changed

+726
-824
lines changed

40 files changed

+726
-824
lines changed

kotlin-wot-binding-http/src/main/kotlin/http/HttpProtocolServer.kt

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package ai.ancf.lmos.wot.binding.http
22

3+
import ai.ancf.lmos.wot.JsonMapper
34
import ai.ancf.lmos.wot.Servient
45
import ai.ancf.lmos.wot.content.Content
56
import ai.ancf.lmos.wot.content.ContentCodecException
@@ -9,14 +10,14 @@ import ai.ancf.lmos.wot.thing.ThingDescription
910
import ai.ancf.lmos.wot.thing.form.Form
1011
import ai.ancf.lmos.wot.thing.form.Operation
1112
import ai.ancf.lmos.wot.thing.schema.ContentListener
12-
import ai.ancf.lmos.wot.thing.schema.DataSchemaValue
13-
import ai.ancf.lmos.wot.thing.schema.DataSchemaValue.*
1413
import ai.ancf.lmos.wot.thing.schema.InteractionAffordance
1514
import ai.ancf.lmos.wot.thing.schema.WoTExposedThing
1615
import ai.anfc.lmos.wot.binding.ProtocolServer
1716
import ai.anfc.lmos.wot.binding.ProtocolServerException
1817
import com.fasterxml.jackson.databind.DeserializationFeature
18+
import com.fasterxml.jackson.databind.JsonNode
1919
import com.fasterxml.jackson.databind.SerializationFeature
20+
import com.fasterxml.jackson.databind.node.*
2021
import io.ktor.http.*
2122
import io.ktor.serialization.jackson.*
2223
import io.ktor.server.application.*
@@ -228,26 +229,26 @@ fun Application.setupRouting(servient: Servient) {
228229
val response: MutableMap<String, Any?> = mutableMapOf()
229230
for ((key, value) in properties) {
230231
// Assuming content is not null as it's checked earlier
231-
when (val schemaValue: DataSchemaValue = ContentManager.contentToValue(value, null)) {
232-
is BooleanValue -> {
233-
response[key] = schemaValue.value
232+
when (val jsonNode: JsonNode = ContentManager.contentToValue(value, null)) {
233+
is BooleanNode -> {
234+
response[key] = jsonNode.asBoolean()
234235
}
235-
is IntegerValue -> {
236-
response[key] = schemaValue.value
236+
is IntNode -> {
237+
response[key] = jsonNode.asInt()
237238
}
238-
is NumberValue -> {
239-
response[key] = schemaValue.value
239+
is LongNode -> {
240+
response[key] = jsonNode.asLong()
240241
}
241-
is StringValue -> {
242-
response[key] = schemaValue.value
242+
is TextNode -> {
243+
response[key] = jsonNode.asText()
243244
}
244-
is ObjectValue -> {
245-
response[key] = schemaValue.value
245+
is ObjectNode -> {
246+
response[key] = JsonMapper.instance.convertValue(jsonNode, Map::class.java)
246247
}
247-
is ArrayValue -> {
248-
response[key] = schemaValue.value
248+
is ArrayNode -> {
249+
response[key] = JsonMapper.instance.convertValue(jsonNode, Array::class.java)
249250
}
250-
is NullValue -> {
251+
is NullNode -> {
251252
response[key] = null
252253
}
253254
}

kotlin-wot-binding-http/src/test/kotlin/http/HttpProtocolServerTest.kt

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import ai.ancf.lmos.wot.thing.exposedThing
77
import ai.ancf.lmos.wot.thing.form.Operation
88
import ai.ancf.lmos.wot.thing.form.Operation.READ_PROPERTY
99
import ai.ancf.lmos.wot.thing.form.Operation.WRITE_PROPERTY
10-
import ai.ancf.lmos.wot.thing.schema.*
11-
import ai.ancf.lmos.wot.thing.schema.DataSchemaValue.IntegerValue
12-
import ai.ancf.lmos.wot.thing.schema.DataSchemaValue.StringValue
10+
import ai.ancf.lmos.wot.thing.schema.InteractionInput
11+
import ai.ancf.lmos.wot.thing.schema.StringSchema
12+
import ai.ancf.lmos.wot.thing.schema.stringSchema
13+
import ai.ancf.lmos.wot.thing.schema.toInteractionInputValue
1314
import ai.anfc.lmos.wot.binding.ProtocolServerException
1415
import com.fasterxml.jackson.databind.DeserializationFeature
1516
import com.fasterxml.jackson.databind.SerializationFeature
17+
import com.fasterxml.jackson.databind.node.NullNode
1618
import io.ktor.client.*
1719
import io.ktor.client.call.*
1820
import io.ktor.client.plugins.contentnegotiation.*
@@ -85,17 +87,17 @@ class HttpProtocolServerTest {
8587
}.setPropertyReadHandler(PROPERTY_NAME_2) {
8688
5.toInteractionInputValue()
8789
}.setActionHandler(ACTION_NAME) { input, _->
88-
val inputString = input.value() as StringValue
89-
"${inputString.value} 10".toInteractionInputValue()
90+
val inputString = input.value()
91+
"${inputString.asText()} 10".toInteractionInputValue()
9092
}.setPropertyWriteHandler(PROPERTY_NAME) { input, _->
91-
val inputInt = input.value() as IntegerValue
92-
inputInt.value.toInteractionInputValue()
93+
val inputInt = input.value()
94+
inputInt.asInt().toInteractionInputValue()
9395
}.setActionHandler(ACTION_NAME_2) { input, _->
9496
"10".toInteractionInputValue()
9597
}.setActionHandler(ACTION_NAME_3) { input, _->
96-
InteractionInput.Value(DataSchemaValue.NullValue)
98+
InteractionInput.Value(NullNode.instance)
9799
}.setActionHandler(ACTION_NAME_4) { _, _->
98-
InteractionInput.Value(DataSchemaValue.NullValue)
100+
InteractionInput.Value(NullNode.instance)
99101
}
100102

101103
@BeforeTest

kotlin-wot-binding-mqtt/src/test/kotlin/integration/MqttProtocolServerTest.kt

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import ai.ancf.lmos.wot.content.ContentManager
77
import ai.ancf.lmos.wot.thing.ExposedThing
88
import ai.ancf.lmos.wot.thing.exposedThing
99
import ai.ancf.lmos.wot.thing.form.Form
10-
import ai.ancf.lmos.wot.thing.schema.DataSchemaValue
1110
import ai.ancf.lmos.wot.thing.schema.StringSchema
1211
import ai.ancf.lmos.wot.thing.schema.stringSchema
1312
import ai.ancf.lmos.wot.thing.schema.toInteractionInputValue
@@ -94,12 +93,12 @@ class MqttProtocolServerTest {
9493
}.setPropertyReadHandler(PROPERTY_NAME) {
9594
"\"testOutput\"".toInteractionInputValue()
9695
}.setActionHandler(ACTION_NAME) { input, _ ->
97-
val inputString = input.value() as DataSchemaValue.StringValue
98-
"\"${inputString.value} 10\"".toInteractionInputValue()
96+
val inputString = input.value()
97+
"\"${inputString.textValue()} 10\"".toInteractionInputValue()
9998
}.setPropertyWriteHandler(PROPERTY_NAME) { input, _ ->
10099
try {
101-
val inputInt = input.value() as DataSchemaValue.StringValue
102-
inputInt.value.toInteractionInputValue()
100+
val inputInt = input.value()
101+
inputInt.textValue().toInteractionInputValue()
103102
} catch (e: Exception) {
104103
throw IllegalArgumentException("Invalid input", e)
105104
}
@@ -207,8 +206,8 @@ class MqttProtocolServerTest {
207206

208207
// Verify that the event is emitted in the flow
209208
val content = awaitItem()
210-
val stringValue = ContentManager.contentToValue(content, StringSchema()) as DataSchemaValue.StringValue
211-
assertEquals("\"testEvent\"", stringValue.value)
209+
val stringValue = ContentManager.contentToValue(content, StringSchema())
210+
assertEquals("\"testEvent\"", stringValue.textValue())
212211

213212
// Optionally verify no further emissions or complete the flow
214213
cancelAndIgnoreRemainingEvents()
@@ -229,8 +228,8 @@ class MqttProtocolServerTest {
229228

230229
// Verify that the event is emitted in the flow
231230
val content = awaitItem()
232-
val stringValue = ContentManager.contentToValue(content, StringSchema()) as DataSchemaValue.StringValue
233-
assertEquals("\"testPropertyChange\"", stringValue.value)
231+
val stringValue = ContentManager.contentToValue(content, StringSchema())
232+
assertEquals("\"testPropertyChange\"", stringValue.textValue())
234233

235234
// Optionally verify no further emissions or complete the flow
236235
cancelAndIgnoreRemainingEvents()

kotlin-wot-binding-websocket/src/test/kotlin/websocket/WebSocketProtocolClientTest.kt

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import ai.ancf.lmos.wot.binding.websocket.WebSocketProtocolServer
88
import ai.ancf.lmos.wot.thing.ExposedThing
99
import ai.ancf.lmos.wot.thing.exposedThing
1010
import ai.ancf.lmos.wot.thing.schema.*
11+
import com.fasterxml.jackson.databind.node.NullNode
1112
import io.mockk.clearAllMocks
1213
import kotlinx.coroutines.runBlocking
1314
import kotlinx.coroutines.test.runTest
@@ -87,24 +88,24 @@ class WebSocketProtocolClientTest {
8788
}.setPropertyReadHandler(PROPERTY_NAME_2) {
8889
"test".toInteractionInputValue()
8990
}.setActionHandler(ACTION_NAME) { input, _->
90-
val inputString = input.value() as DataSchemaValue.StringValue
91-
"${inputString.value} 10".toInteractionInputValue()
91+
val inputString = input.value()
92+
"${inputString.asText()} 10".toInteractionInputValue()
9293
}.setPropertyWriteHandler(PROPERTY_NAME) { input, _->
93-
val inputInt = input.value() as DataSchemaValue.IntegerValue
94-
property1 = inputInt.value
94+
val inputInt = input.value()
95+
property1 = inputInt.asInt()
9596
property1.toInteractionInputValue()
9697
}.setPropertyWriteHandler(PROPERTY_NAME_2) { input, _->
97-
val inputInt = input.value() as DataSchemaValue.StringValue
98-
property2 = inputInt.value
98+
val inputInt = input.value()
99+
property2 = inputInt.asText()
99100
property2.toInteractionInputValue()
100101
}.setActionHandler(ACTION_NAME_2) { input, _->
101102
"test test".toInteractionInputValue()
102103
}.setActionHandler(ACTION_NAME_3) { input, _->
103-
val inputString = input.value() as DataSchemaValue.StringValue
104-
property2 = inputString.value
105-
InteractionInput.Value(DataSchemaValue.NullValue)
104+
val inputString = input.value()
105+
property2 = inputString.asText()
106+
InteractionInput.Value(NullNode.instance)
106107
}.setActionHandler(ACTION_NAME_4) { _, _->
107-
InteractionInput.Value(DataSchemaValue.NullValue)
108+
InteractionInput.Value(NullNode.instance)
108109
}.setEventSubscribeHandler(EVENT_NAME) { _ ->
109110
}
110111

@@ -131,18 +132,18 @@ class WebSocketProtocolClientTest {
131132
fun `should get property`() = runBlocking {
132133

133134
val readProperty1 = thing.readProperty(PROPERTY_NAME).value()
134-
assertEquals(10, (readProperty1 as DataSchemaValue.IntegerValue).value)
135+
assertEquals(10, (readProperty1).asInt())
135136

136137
val readProperty2 = thing.readProperty(PROPERTY_NAME_2).value()
137-
assertEquals("test", (readProperty2 as DataSchemaValue.StringValue).value)
138+
assertEquals("test", (readProperty2).asText())
138139

139140
}
140141

141142
@Test
142143
fun `should get all properties`() = runBlocking {
143144
val readPropertyMap = thing.readAllProperties()
144-
assertEquals(10, (readPropertyMap[PROPERTY_NAME]?.value() as DataSchemaValue.IntegerValue).value)
145-
assertEquals("test", (readPropertyMap[PROPERTY_NAME_2]?.value() as DataSchemaValue.StringValue).value)
145+
assertEquals(10, readPropertyMap[PROPERTY_NAME]?.value()?.asInt())
146+
assertEquals("test", readPropertyMap[PROPERTY_NAME_2]?.value()?.asText())
146147
}
147148

148149
@Test
@@ -166,21 +167,21 @@ class WebSocketProtocolClientTest {
166167
fun `should invoke action`() = runBlocking {
167168
val response = thing.invokeAction(ACTION_NAME, "test".toDataSchemeValue())
168169

169-
assertEquals("test 10", (response as DataSchemaValue.StringValue).value)
170+
assertEquals("test 10", response.asText())
170171
}
171172

172173
@Test
173174
fun `should invoke action without input`() = runBlocking {
174175
val response = thing.invokeAction(ACTION_NAME_2)
175176

176-
assertEquals("test test", (response as DataSchemaValue.StringValue).value)
177+
assertEquals("test test", response.asText())
177178
}
178179

179180
@Test
180181
fun `should invoke action without output`(): Unit = runBlocking {
181182
val response = thing.invokeAction(ACTION_NAME_3, "test".toDataSchemeValue())
182183
assertEquals("test", property2)
183-
assertIs<DataSchemaValue.NullValue>(response)
184+
assertIs<NullNode>(response)
184185
}
185186

186187

kotlin-wot-binding-websocket/src/test/kotlin/websocket/WebSocketProtocolServerTest.kt

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import ai.ancf.lmos.wot.Servient
55
import ai.ancf.lmos.wot.binding.websocket.*
66
import ai.ancf.lmos.wot.thing.ExposedThing
77
import ai.ancf.lmos.wot.thing.exposedThing
8-
import ai.ancf.lmos.wot.thing.schema.*
9-
import ai.ancf.lmos.wot.thing.schema.DataSchemaValue.IntegerValue
10-
import ai.ancf.lmos.wot.thing.schema.DataSchemaValue.StringValue
8+
import ai.ancf.lmos.wot.thing.schema.InteractionInput
9+
import ai.ancf.lmos.wot.thing.schema.StringSchema
10+
import ai.ancf.lmos.wot.thing.schema.stringSchema
11+
import ai.ancf.lmos.wot.thing.schema.toInteractionInputValue
1112
import ai.anfc.lmos.wot.binding.ProtocolServerException
1213
import com.fasterxml.jackson.databind.node.IntNode
1314
import com.fasterxml.jackson.databind.node.NullNode
@@ -81,17 +82,17 @@ class WebSocketProtocolServerTest {
8182
}.setPropertyReadHandler(PROPERTY_NAME_2) {
8283
5.toInteractionInputValue()
8384
}.setActionHandler(ACTION_NAME) { input, _->
84-
val inputString = input.value() as StringValue
85-
"${inputString.value} 10".toInteractionInputValue()
85+
val inputString = input.value()
86+
"${inputString.asText()} 10".toInteractionInputValue()
8687
}.setPropertyWriteHandler(PROPERTY_NAME) { input, _->
87-
val inputInt = input.value() as IntegerValue
88-
inputInt.value.toInteractionInputValue()
88+
val inputInt = input.value()
89+
inputInt.asInt().toInteractionInputValue()
8990
}.setActionHandler(ACTION_NAME_2) { input, _->
9091
"10".toInteractionInputValue()
9192
}.setActionHandler(ACTION_NAME_3) { input, _->
92-
InteractionInput.Value(DataSchemaValue.NullValue)
93+
InteractionInput.Value(NullNode.instance)
9394
}.setActionHandler(ACTION_NAME_4) { _, _->
94-
InteractionInput.Value(DataSchemaValue.NullValue)
95+
InteractionInput.Value(NullNode.instance)
9596
}.setEventSubscribeHandler(EVENT_NAME) { _ ->
9697
}
9798

kotlin-wot-integration-tests/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66

77
dependencies {
88
api(project(":kotlin-wot-binding-http"))
9-
//api(project(":kotlin-wot-binding-websocket"))
9+
api(project(":kotlin-wot-binding-websocket"))
1010
api(project(":kotlin-wot-binding-mqtt"))
1111
api(project(":kotlin-wot-spring-boot-starter"))
1212
implementation("ai.ancf.lmos:arc-azure-client:0.111.0")

kotlin-wot-integration-tests/src/main/kotlin/integration/AgentConfiguration.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,23 @@ class AgentConfiguration {
2929
) {
3030

3131
val thingDescription =
32-
wot.requestThingDescription("http://remotelab.esi.cit.tum.de:8080/virtual-coffee-machine-1_1")
32+
wot.requestThingDescription("http://plugfest.thingweb.io/http-data-schema-thing")
3333

3434
val testThing = wot.consume(thingDescription)
3535

36-
val availableResources = testThing.genericReadProperty<Resources>("allAvailableResources")
36+
val availableResources = testThing.genericReadProperty<String>("int")
3737

38+
availableResources
39+
40+
/*
3841
"""
3942
The coffee machine has the following resources available:
4043
- Milk: ${availableResources.milk} ml
4144
- Water: ${availableResources.water} ml
4245
- Chocolate: ${availableResources.chocolate} grams
4346
- Coffee Beans: ${availableResources.coffeeBeans} grams
4447
"""
48+
*/
4549
}
4650
}
4751

kotlin-wot-integration-tests/src/main/kotlin/integration/SpringApplication.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ package ai.ancf.lmos.wot.integration
22

33
import org.springframework.boot.autoconfigure.SpringBootApplication
44
import org.springframework.boot.runApplication
5-
import spring.ThingRuntime
65

76

87
fun main(args: Array<String>) {
98
runApplication<ThingAgentApplication>(*args)
109
}
1110

1211
@SpringBootApplication
13-
class ThingAgentApplication : ThingRuntime() {
12+
class ThingAgentApplication {
1413

1514
}

kotlin-wot-integration-tests/src/main/kotlin/integration/ThingAgent.kt

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package ai.ancf.lmos.wot.integration
22

33
import ai.ancf.lmos.arc.agents.AgentProvider
44
import ai.ancf.lmos.arc.agents.ChatAgent
5+
import ai.ancf.lmos.arc.agents.User
56
import ai.ancf.lmos.arc.agents.conversation.AssistantMessage
6-
import ai.ancf.lmos.arc.agents.conversation.Conversation
77
import ai.ancf.lmos.arc.agents.conversation.latest
8+
import ai.ancf.lmos.arc.agents.conversation.toConversation
89
import ai.ancf.lmos.arc.agents.getAgentByName
910
import ai.ancf.lmos.arc.core.getOrThrow
1011
import ai.ancf.lmos.wot.reflection.annotations.*
@@ -25,21 +26,12 @@ class ThingAgent(agentProvider: AgentProvider, @Property(name = "modelTemperatur
2526

2627
val agent = agentProvider.getAgentByName("My Agent") as ChatAgent
2728

28-
/*
29-
private val model: AzureOpenAiChatModel = AzureOpenAiChatModel.builder()
30-
.apiKey("af12dab9c046453e82dcf4b24af90bca")
31-
.deploymentName("GPT35T-1106")
32-
.endpoint("https://gpt4-uk.openai.azure.com/")
33-
.temperature(modelConfiguration.modelTemperature)
34-
.build();
35-
*/
36-
3729
@Property(name = "observableProperty", title = "Observable Property", readOnly = true)
3830
val observableProperty : MutableStateFlow<String> = MutableStateFlow("Hello World")
3931

4032
@Action(name = "ask", title = "Ask", description = "Ask the agent a question.")
41-
suspend fun ask(conversation : Conversation) : String {
42-
val assistantMessage = agent.execute(conversation).getOrThrow().latest<AssistantMessage>() ?:
33+
suspend fun ask(chat : Chat) : String {
34+
val assistantMessage = agent.execute(chat.message.toConversation(User("myId"))).getOrThrow().latest<AssistantMessage>() ?:
4335
throw RuntimeException("No Assistant response")
4436
messageFlow.emit(assistantMessage.content)
4537
return assistantMessage.content
@@ -53,3 +45,5 @@ class ThingAgent(agentProvider: AgentProvider, @Property(name = "modelTemperatur
5345

5446
data class ModelConfiguration(val modelTemperature: Double, val maxTokens: Int)
5547

48+
data class Chat(val message: String)
49+

kotlin-wot-integration-tests/src/main/resources/application.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@ arc:
99

1010
wot:
1111
servient:
12+
websocket:
13+
server:
14+
enabled: true
15+
host: localhost
16+
port: 8080
1217
http:
1318
server:
19+
enabled: false
1420
host: localhost
1521
port: 8080
1622
mqtt:

0 commit comments

Comments
 (0)