Skip to content

Commit 3116d22

Browse files
authored
Merge pull request #38 from RobWin/td-base-url
Added support for multiple base URLs for the forms of properties, actions, and events.
2 parents b5ac202 + d5119c2 commit 3116d22

File tree

6 files changed

+73
-45
lines changed

6 files changed

+73
-45
lines changed

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

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ open class HttpProtocolServer(
4444
private val wait: Boolean = false,
4545
private val bindHost: String = "0.0.0.0",
4646
private val bindPort: Int = 8080,
47+
private var baseUrls: List<String> = listOf("http://localhost:8080"),
4748
private val createServer: (host: String, port: Int, servient: Servient) -> EmbeddedServer<*, *> = ::defaultServer
4849
) : ProtocolServer {
4950
val things: MutableMap<String, ExposedThing> = mutableMapOf()
5051
var started = false
5152
private var server: EmbeddedServer<*, *>? = null
52-
private var actualAddresses: List<String> = listOf("http://$bindHost:$bindPort")
5353

5454
companion object {
5555
private val log = LoggerFactory.getLogger(HttpProtocolServer::class.java)
@@ -77,27 +77,27 @@ open class HttpProtocolServer(
7777
log.info("Exposing thing '{}' on HttpProtocolServer", thing.id)
7878
things[thing.id] = thing
7979

80-
for (address in actualAddresses) {
80+
for (baseUrl in baseUrls) {
8181
for (contentType in ContentManager.offeredMediaTypes) {
8282
// make reporting of all properties optional?
83-
val href = "$address/${thing.id}/all/properties"
83+
val href = "$baseUrl/${thing.id}/all/properties"
8484
val form = Form(href = href, contentType = contentType, op = listOf( Operation.READ_ALL_PROPERTIES,
8585
Operation.READ_MULTIPLE_PROPERTIES))
8686

8787
thing.forms += form
8888
log.debug("Assign '{}' for reading all properties", href)
8989

90-
exposeProperties(thing, address, contentType)
91-
exposeActions(thing, address, contentType)
92-
exposeEvents(thing, address, contentType)
90+
exposeProperties(thing, baseUrl, contentType)
91+
exposeActions(thing, baseUrl, contentType)
92+
exposeEvents(thing, baseUrl, contentType)
9393
}
9494
}
9595
}
9696

97-
internal fun exposeProperties(thing: ExposedThing, address: String, contentType: String) {
97+
internal fun exposeProperties(thing: ExposedThing, baseUrl: String, contentType: String) {
9898
thing.properties.forEach { (name, property) ->
9999

100-
val href = getHrefWithVariablePattern(address, thing, "properties", name, property)
100+
val href = getHrefWithVariablePattern(baseUrl, thing, "properties", name, property)
101101

102102
// Determine the operations based on readOnly/writeOnly status
103103
val operations = when {
@@ -138,9 +138,9 @@ open class HttpProtocolServer(
138138
}
139139
}
140140

141-
internal fun exposeActions(thing: ExposedThing, address: String, contentType: String) {
141+
internal fun exposeActions(thing: ExposedThing, baseUrl: String, contentType: String) {
142142
thing.actions.forEach { (name, action) ->
143-
val href: String = getHrefWithVariablePattern(address, thing, "actions", name, action)
143+
val href: String = getHrefWithVariablePattern(baseUrl, thing, "actions", name, action)
144144
// Initialize the form using named parameters
145145
val form = Form(
146146
href = href,
@@ -154,9 +154,9 @@ open class HttpProtocolServer(
154154
}
155155
}
156156

157-
internal fun exposeEvents(thing: ExposedThing, address: String, contentType: String) {
157+
internal fun exposeEvents(thing: ExposedThing, baseUrl: String, contentType: String) {
158158
thing.events.forEach { (name, event) ->
159-
val href = getHrefWithVariablePattern(address, thing, "events", name, event)
159+
val href = getHrefWithVariablePattern(baseUrl, thing, "events", name, event)
160160

161161
// Create the form using named parameters directly
162162
val form = Form(
@@ -173,7 +173,7 @@ open class HttpProtocolServer(
173173
}
174174

175175
private fun getHrefWithVariablePattern(
176-
address: String,
176+
baseUrl: String,
177177
thing: ExposedThing,
178178
type: String,
179179
interactionName: String,
@@ -184,7 +184,7 @@ open class HttpProtocolServer(
184184
if (!uriVariables.isNullOrEmpty()) {
185185
variables = "{?" + java.lang.String.join(",", uriVariables) + "}"
186186
}
187-
return "$address/${thing.id}/$type/$interactionName$variables"
187+
return "$baseUrl/${thing.id}/$type/$interactionName$variables"
188188
}
189189

190190
// Destroy a thing

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ class HttpProtocolServerTest {
395395
// Assert
396396
assertTrue(exposedThing.forms.isNotEmpty(), "Expected forms to be added to thing")
397397

398-
val expectedHref = "http://0.0.0.0:8080/${exposedThing.id}/all/properties"
398+
val expectedHref = "http://localhost:8080/${exposedThing.id}/all/properties"
399399
val form = exposedThing.forms.find { it.href == expectedHref }
400400
assertNotNull(form, "Expected form for reading all properties to be added")
401401
assertEquals(CONTENT_TYPE, form.contentType)
@@ -406,12 +406,12 @@ class HttpProtocolServerTest {
406406
fun `exposeProperties should add forms for read write properties`() {
407407
// Arrange
408408
server.started = true
409-
val address = "http://0.0.0.0:8080"
409+
val baseUrl = "http://localhost:8080"
410410
// Act
411-
server.exposeProperties(exposedThing, address, CONTENT_TYPE)
411+
server.exposeProperties(exposedThing, baseUrl, CONTENT_TYPE)
412412

413413
// Assert
414-
val expectedHref = "$address/${exposedThing.id}/properties/$PROPERTY_NAME"
414+
val expectedHref = "$baseUrl/${exposedThing.id}/properties/$PROPERTY_NAME"
415415
val form = exposedThing.properties[PROPERTY_NAME]?.forms?.find { it.href == expectedHref }
416416
assertNotNull(form, "Expected form for property '$PROPERTY_NAME' to be added")
417417

@@ -422,12 +422,12 @@ class HttpProtocolServerTest {
422422
fun `exposeActions should add form for action`() {
423423
// Arrange
424424
server.started = true
425-
val address = "http://0.0.0.0:8080"
425+
val baseUrl = "http://localhost:8080"
426426
// Act
427-
server.exposeActions(exposedThing, address, CONTENT_TYPE)
427+
server.exposeActions(exposedThing, baseUrl, CONTENT_TYPE)
428428

429429
// Assert
430-
val expectedHref = "$address/${exposedThing.id}/actions/$ACTION_NAME"
430+
val expectedHref = "$baseUrl/${exposedThing.id}/actions/$ACTION_NAME"
431431
val form = exposedThing.actions[ACTION_NAME]?.forms?.find { it.href == expectedHref }
432432
assertNotNull(form, "Expected form for action 'action1' to be added")
433433
assertEquals(CONTENT_TYPE, form.contentType, "Content type should match")
@@ -439,12 +439,12 @@ class HttpProtocolServerTest {
439439
fun `exposeEvents should add form for event`() {
440440
// Arrange
441441
server.started = true
442-
val address = "http://0.0.0.0:8080"
442+
val baseUrl = "http://localhost:8080"
443443
// Act
444-
server.exposeEvents(exposedThing, address, CONTENT_TYPE)
444+
server.exposeEvents(exposedThing, baseUrl, CONTENT_TYPE)
445445

446446
// Assert
447-
val expectedHref = "$address/${exposedThing.id}/events/$EVENT_NAME"
447+
val expectedHref = "$baseUrl/${exposedThing.id}/events/$EVENT_NAME"
448448
val form = exposedThing.events[EVENT_NAME]?.forms?.find { it.href == expectedHref }
449449
assertNotNull(form, "Expected form for action 'action1' to be added")
450450
assertEquals(CONTENT_TYPE, form.contentType, "Content type should match")

kotlin-wot-binding-websocket/src/main/kotlin/websocket/WebSocketProtocolServer.kt

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ class WebSocketProtocolServer(
4040
private val wait: Boolean = false,
4141
private val bindHost: String = "0.0.0.0",
4242
private val bindPort: Int = 8080,
43+
private var baseUrls: List<String> = listOf("ws://localhost:8080"),
4344
private val createServer: (host: String, port: Int, servient: Servient) -> EmbeddedServer<*, *> = ::defaultWebSocketServer
4445
) : ProtocolServer {
4546
private val things: MutableMap<String, ExposedThing> = mutableMapOf()
4647

4748
var started = false
4849
private var server: EmbeddedServer<*, *>? = null
49-
private var actualAddresses: List<String> = listOf("ws://$bindHost:$bindPort")
5050

5151
companion object {
5252
private val log = LoggerFactory.getLogger(WebSocketProtocolServer::class.java)
@@ -70,10 +70,10 @@ class WebSocketProtocolServer(
7070

7171
log.info("Exposing thing '{}'", thing.id)
7272
things[thing.id] = thing
73-
for (address in actualAddresses) {
74-
exposeProperties(thing, address)
75-
exposeActions(thing, address)
76-
exposeEvents(thing, address)
73+
for (baseUrl in baseUrls) {
74+
exposeProperties(thing, baseUrl)
75+
exposeActions(thing, baseUrl)
76+
exposeEvents(thing, baseUrl)
7777
}
7878
}
7979

@@ -82,10 +82,10 @@ class WebSocketProtocolServer(
8282
things.remove(thing.id)
8383
}
8484

85-
internal fun exposeProperties(thing: ExposedThing, address: String) {
85+
internal fun exposeProperties(thing: ExposedThing, baseUrl: String) {
8686
thing.properties.forEach { (name, property) ->
8787

88-
val href = "$address/ws"
88+
val href = "$baseUrl/ws"
8989

9090
// Combine all operations (read, write, observe, unobserve) into a single form
9191
val operations = mutableListOf<Operation>()
@@ -113,10 +113,10 @@ class WebSocketProtocolServer(
113113
}
114114
}
115115

116-
internal fun exposeActions(thing: ExposedThing, address: String) {
116+
internal fun exposeActions(thing: ExposedThing, baseUrl: String) {
117117
thing.actions.forEach { (name, action) ->
118118
// Construct the href for the action
119-
val href = "$address/ws" // WebSocket path for actions
119+
val href = "$baseUrl/ws" // WebSocket path for actions
120120

121121
// Create a form for invoking the action
122122
val form = Form(
@@ -132,10 +132,10 @@ class WebSocketProtocolServer(
132132
}
133133
}
134134

135-
internal fun exposeEvents(thing: ExposedThing, address: String) {
135+
internal fun exposeEvents(thing: ExposedThing, baseUrl: String) {
136136
thing.events.forEach { (name, event) ->
137137
// Construct the href for the event
138-
val href = "$address/ws" // WebSocket path for events
138+
val href = "$baseUrl/ws" // WebSocket path for events
139139

140140
// Create a form for subscribing to the event
141141
val form = Form(

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@ wot:
1818
server:
1919
enabled: true
2020
host: localhost
21-
port: 8080
21+
port: 8181
2222
http:
2323
server:
24-
enabled: false
24+
enabled: true
2525
host: localhost
2626
port: 8080
27+
baseUrls:
28+
- http://localhost:8080
29+
- http://not-existing-external-url:8080
2730
mqtt:
2831
server:
2932
enabled: false

kotlin-wot-spring-boot-starter/src/main/kotlin/spring/HttpProperties.kt

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,21 @@ package ai.ancf.lmos.wot.spring
33
import org.springframework.boot.context.properties.ConfigurationProperties
44
import org.springframework.validation.annotation.Validated
55

6+
open class ServerProperties(
7+
var enabled: Boolean = true,
8+
var host: String = "0.0.0.0",
9+
var port: Int = 8080,
10+
var baseUrls: List<String>
11+
)
12+
613
@ConfigurationProperties(prefix = "wot.servient.http.server", ignoreUnknownFields = true)
714
@Validated
8-
data class HttpServerProperties(
9-
var enabled: Boolean = true,
10-
var host: String = "localhost",
11-
var port: Int = 8080
15+
class HttpServerProperties : ServerProperties(
16+
baseUrls = listOf("http://localhost:8080")
17+
)
18+
19+
@ConfigurationProperties(prefix = "wot.servient.websocket.server", ignoreUnknownFields = true)
20+
@Validated
21+
class WebsocketProperties : ServerProperties(
22+
baseUrls = listOf("ws://localhost:8080")
1223
)

kotlin-wot-spring-boot-starter/src/main/kotlin/spring/ServientAutoConfiguration.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@ import org.springframework.context.annotation.Configuration
2222

2323

2424
@AutoConfiguration
25-
@EnableConfigurationProperties(CredentialsProperties::class, HttpServerProperties::class, MqttServerProperties::class, MqttClientProperties::class)
25+
@EnableConfigurationProperties(
26+
CredentialsProperties::class,
27+
HttpServerProperties::class,
28+
WebsocketProperties::class,
29+
MqttServerProperties::class,
30+
MqttClientProperties::class
31+
)
2632
class ServientAutoConfiguration {
2733

2834
@Bean
@@ -55,8 +61,12 @@ class ServientAutoConfiguration {
5561
havingValue = "true",
5662
matchIfMissing = true // By default, enable the server
5763
)
58-
fun webSocketProtocolServer(httpServerProperties: HttpServerProperties): WebSocketProtocolServer {
59-
return WebSocketProtocolServer(bindHost = httpServerProperties.host, bindPort = httpServerProperties.port)
64+
fun webSocketProtocolServer(websocketProperties: WebsocketProperties): WebSocketProtocolServer {
65+
return WebSocketProtocolServer(
66+
bindHost = websocketProperties.host,
67+
bindPort = websocketProperties.port,
68+
baseUrls = websocketProperties.baseUrls
69+
)
6070
}
6171

6272
@Bean
@@ -83,7 +93,11 @@ class ServientAutoConfiguration {
8393
matchIfMissing = true // By default, enable the server
8494
)
8595
fun httpProtocolServer(httpServerProperties: HttpServerProperties): HttpProtocolServer {
86-
return HttpProtocolServer(bindHost = httpServerProperties.host, bindPort = httpServerProperties.port)
96+
return HttpProtocolServer(
97+
bindHost = httpServerProperties.host,
98+
bindPort = httpServerProperties.port,
99+
baseUrls = httpServerProperties.baseUrls
100+
)
87101
}
88102

89103
@Bean

0 commit comments

Comments
 (0)