diff --git a/.run/LocalEventDB.run.xml b/.run/LocalEventDB.run.xml
index b3c08668..c16471ee 100644
--- a/.run/LocalEventDB.run.xml
+++ b/.run/LocalEventDB.run.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/boudicca.base/enricher-api/build.gradle.kts b/boudicca.base/enricher-api/build.gradle.kts
new file mode 100644
index 00000000..04ba7375
--- /dev/null
+++ b/boudicca.base/enricher-api/build.gradle.kts
@@ -0,0 +1,26 @@
+plugins {
+ kotlin("jvm")
+ kotlin("plugin.allopen")
+}
+
+repositories {
+ mavenCentral()
+ mavenLocal()
+}
+
+dependencies {
+ api(project(":boudicca.base:semantic-conventions"))
+ implementation("org.jetbrains.kotlin:kotlin-stdlib")
+ implementation(project(":boudicca.base:enricher-openapi"))
+}
+
+java {
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(17))
+ vendor.set(JvmVendorSpec.ADOPTIUM)
+ }
+}
+
+tasks.withType {
+ kotlinOptions.javaParameters = true
+}
diff --git a/boudicca.base/enricher-api/src/main/kotlin/base/boudicca/api/enricher/Enricher.kt b/boudicca.base/enricher-api/src/main/kotlin/base/boudicca/api/enricher/Enricher.kt
new file mode 100644
index 00000000..b0e2a518
--- /dev/null
+++ b/boudicca.base/enricher-api/src/main/kotlin/base/boudicca/api/enricher/Enricher.kt
@@ -0,0 +1,36 @@
+package base.boudicca.api.enricher
+
+import base.boudicca.Event
+import events.boudicca.enricher.openapi.ApiClient
+import events.boudicca.enricher.openapi.api.EnricherControllerApi
+import events.boudicca.enricher.openapi.model.EnrichRequestDTO
+
+class Enricher(enricherUrl: String) {
+
+ private val enricherApi: EnricherControllerApi
+
+ init {
+ if (enricherUrl.isBlank()) {
+ throw IllegalStateException("you need to pass an eventDbUrl!")
+ }
+ val apiClient = ApiClient()
+ apiClient.updateBaseUri(enricherUrl)
+
+ enricherApi = EnricherControllerApi(apiClient)
+ }
+
+ fun enrichEvents(events: List): List {
+ return enricherApi.enrich(EnrichRequestDTO().events(events.map { mapToEnricherEvent(it) })).map { toEvent(it) }
+ }
+
+ private fun toEvent(enricherEvent: events.boudicca.enricher.openapi.model.Event): Event {
+ return Event(enricherEvent.name, enricherEvent.startDate, enricherEvent.data ?: mapOf())
+ }
+
+ private fun mapToEnricherEvent(event: Event): events.boudicca.enricher.openapi.model.Event {
+ return events.boudicca.enricher.openapi.model.Event()
+ .name(event.name)
+ .startDate(event.startDate)
+ .data(event.data)
+ }
+}
\ No newline at end of file
diff --git a/boudicca.base/enricher-utils/build.gradle.kts b/boudicca.base/enricher-utils/build.gradle.kts
index c2ca6902..edb2d399 100644
--- a/boudicca.base/enricher-utils/build.gradle.kts
+++ b/boudicca.base/enricher-utils/build.gradle.kts
@@ -15,8 +15,8 @@ repositories {
dependencies {
implementation("org.json:json:20231013")
- implementation(project(":boudicca.base:enricher-openapi"))
- implementation(project(":boudicca.base:eventdb-openapi"))
+ implementation(project(":boudicca.base:enricher-api"))
+ implementation(project(":boudicca.base:publisher-api"))
}
tasks.withType {
diff --git a/boudicca.base/enricher-utils/src/main/kotlin/base/boudicca/enricher_utils/EnricherTester.kt b/boudicca.base/enricher-utils/src/main/kotlin/base/boudicca/enricher_utils/EnricherTester.kt
index 7a266701..585313b5 100644
--- a/boudicca.base/enricher-utils/src/main/kotlin/base/boudicca/enricher_utils/EnricherTester.kt
+++ b/boudicca.base/enricher-utils/src/main/kotlin/base/boudicca/enricher_utils/EnricherTester.kt
@@ -1,10 +1,9 @@
package base.boudicca.enricher_utils
+import base.boudicca.Event
import base.boudicca.SemanticKeys
-import events.boudicca.enricher.openapi.api.EnricherControllerApi
-import events.boudicca.enricher.openapi.model.EnrichRequestDTO
-import events.boudicca.enricher.openapi.model.Event
-import events.boudicca.openapi.api.EventPublisherResourceApi
+import base.boudicca.api.enricher.Enricher
+import base.boudicca.api.eventdb.publisher.EventDB
private const val EVENTDB_URL = "http://localhost:8081"
private const val ENRICHER_URL = "http://localhost:8085"
@@ -12,16 +11,16 @@ private const val ENRICHER_URL = "http://localhost:8085"
fun main() {
var startTime = System.currentTimeMillis()
- val events = base.boudicca.enricher_utils.getEvents()
+ val events = getEvents()
println("fetch all events took ${System.currentTimeMillis() - startTime}ms")
- val filteredEvents = events.filter { it.data?.get(SemanticKeys.COLLECTORNAME) == "linz termine" }
+ val filteredEvents = events.filter { it.data[SemanticKeys.COLLECTORNAME] == "linz termine" }
startTime = System.currentTimeMillis()
- val enrichedEvents = base.boudicca.enricher_utils.enrich(filteredEvents)
+ val enrichedEvents = enrich(filteredEvents)
println("enrich filtered events took ${System.currentTimeMillis() - startTime}ms")
- base.boudicca.enricher_utils.compare(filteredEvents, enrichedEvents)
+ compare(filteredEvents, enrichedEvents)
}
fun compare(events: List, enrichedEvents: List) {
@@ -31,31 +30,31 @@ fun compare(events: List, enrichedEvents: List) {
for (i in events.indices) {
if (events[i] != enrichedEvents[i]) {
- base.boudicca.enricher_utils.printDiff(events[i], enrichedEvents[i])
+ printDiff(events[i], enrichedEvents[i])
}
}
}
fun printDiff(event: Event, enrichedEvent: Event) {
println()
- base.boudicca.enricher_utils.printValues("name", event.name, enrichedEvent.name)
+ printValues("name", event.name, enrichedEvent.name)
if (event.startDate != enrichedEvent.startDate) {
- base.boudicca.enricher_utils.printValues(
+ printValues(
"startDate",
event.startDate.toString(),
enrichedEvent.startDate.toString()
)
}
- val oldValues = event.data ?: emptyMap()
- val newValues = enrichedEvent.data?.toMutableMap() ?: mutableMapOf()
+ val oldValues = event.data
+ val newValues = enrichedEvent.data.toMutableMap()
for (key in oldValues.keys.sorted()) {
if (oldValues[key] != newValues[key]) {
- base.boudicca.enricher_utils.printValues(key, oldValues[key], newValues[key])
+ printValues(key, oldValues[key], newValues[key])
}
newValues.remove(key)
}
for (key in newValues.keys.sorted()) {
- base.boudicca.enricher_utils.printValues(key, null, newValues[key])
+ printValues(key, null, newValues[key])
}
}
@@ -64,18 +63,9 @@ fun printValues(key: String, oldValue: String?, newValue: String?) {
}
private fun enrich(originalEvents: List): List {
- val apiClient = events.boudicca.enricher.openapi.ApiClient()
- apiClient.updateBaseUri(base.boudicca.enricher_utils.ENRICHER_URL)
- val enricherApi = EnricherControllerApi(apiClient)
-
- return enricherApi.enrich(EnrichRequestDTO().events(originalEvents))
+ return Enricher(ENRICHER_URL).enrichEvents(originalEvents)
}
-
fun getEvents(): List {
- val apiClient = events.boudicca.openapi.ApiClient()
- apiClient.updateBaseUri(base.boudicca.enricher_utils.EVENTDB_URL)
- val eventdbResource = EventPublisherResourceApi(apiClient)
-
- return eventdbResource.eventsGet().map { Event().name(it.name).startDate(it.startDate).data(it.data) }
+ return EventDB(EVENTDB_URL).getAllEvents()
}
diff --git a/boudicca.base/eventcollector-api/build.gradle.kts b/boudicca.base/eventcollector-api/build.gradle.kts
index 6f780273..51422d85 100644
--- a/boudicca.base/eventcollector-api/build.gradle.kts
+++ b/boudicca.base/eventcollector-api/build.gradle.kts
@@ -9,13 +9,13 @@ repositories {
}
dependencies {
- implementation("org.jetbrains.kotlin:kotlin-stdlib")
+ api("org.jetbrains.kotlin:kotlin-stdlib")
implementation("org.apache.velocity:velocity-engine-core:2.3")
implementation("org.apache.velocity.tools:velocity-tools-generic:3.1")
- api("ch.qos.logback:logback-classic:1.4.11")
+ implementation("ch.qos.logback:logback-classic:1.4.11")
api("org.slf4j:slf4j-api:2.0.9")
- api(project(":boudicca.base:eventdb-openapi"))
- api(project(":boudicca.base:enricher-openapi"))
+ implementation(project(":boudicca.base:ingest-api"))
+ implementation(project(":boudicca.base:enricher-api"))
}
java {
diff --git a/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollector.kt b/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollector.kt
index 32ee7f64..7c35acab 100644
--- a/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollector.kt
+++ b/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollector.kt
@@ -1,5 +1,7 @@
package base.boudicca.api.eventcollector
+import base.boudicca.Event
+
interface EventCollector {
fun getName(): String
fun collectEvents(): List
diff --git a/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollectorDebugger.kt b/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollectorDebugger.kt
index e7749bd3..1aaa0633 100644
--- a/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollectorDebugger.kt
+++ b/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollectorDebugger.kt
@@ -1,5 +1,6 @@
package base.boudicca.api.eventcollector
+import base.boudicca.Event
import base.boudicca.api.eventcollector.collections.Collections
class EventCollectorDebugger {
diff --git a/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollectorScheduler.kt b/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollectorScheduler.kt
index a9b455de..550e848b 100644
--- a/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollectorScheduler.kt
+++ b/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/EventCollectorScheduler.kt
@@ -1,16 +1,13 @@
package base.boudicca.api.eventcollector
+import base.boudicca.Event
import base.boudicca.SemanticKeys
+import base.boudicca.api.enricher.Enricher
import base.boudicca.api.eventcollector.collections.Collections
-import events.boudicca.enricher.openapi.api.EnricherControllerApi
-import events.boudicca.enricher.openapi.model.EnrichRequestDTO
-import events.boudicca.openapi.ApiClient
-import events.boudicca.openapi.ApiException
-import events.boudicca.openapi.api.EventIngestionResourceApi
+import base.boudicca.api.eventdb.ingest.EventDB
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.time.Duration
-import java.util.*
import java.util.concurrent.Executors
import java.util.function.Consumer
import java.util.function.Function
@@ -99,7 +96,7 @@ class EventCollectorScheduler(
eventSink.accept(event)
}
}
- } catch (e: ApiException) {
+ } catch (e: RuntimeException) {
LOG.error("could not ingest events, is the core available?", e)
}
} catch (e: Exception) {
@@ -124,16 +121,16 @@ class EventCollectorScheduler(
if (event.name.isBlank()) {
LOG.warn("event has empty name: $event")
}
- for (entry in event.additionalData.entries) {
+ for (entry in event.data.entries) {
if (entry.value.isBlank()) {
LOG.warn("event contains empty field ${entry.key}: $event")
}
}
- if (!event.additionalData.containsKey(SemanticKeys.COLLECTORNAME)) {
+ if (!event.data.containsKey(SemanticKeys.COLLECTORNAME)) {
return Event(
event.name,
event.startDate,
- event.additionalData.toMutableMap().apply { put(SemanticKeys.COLLECTORNAME, collectorName) }
+ event.data.toMutableMap().apply { put(SemanticKeys.COLLECTORNAME, collectorName) }
)
}
return event
@@ -157,21 +154,13 @@ fun createBoudiccaEventSink(eventDbUrl: String?): Consumer {
if (eventDbUrl.isNullOrBlank()) {
throw IllegalStateException("you need to specify the boudicca.eventdb.url property!")
}
- val apiClient = ApiClient()
- apiClient.updateBaseUri(eventDbUrl)
- apiClient.setRequestInterceptor {
- it.header(
- "Authorization",
- "Basic " + Base64.getEncoder()
- .encodeToString(
- Configuration.getProperty("boudicca.ingest.auth")?.encodeToByteArray()
- ?: throw IllegalStateException("you need to specify the boudicca.ingest.auth property!")
- )
- )
- }
- val ingestionApi = EventIngestionResourceApi(apiClient)
+ val userAndPassword = Configuration.getProperty("boudicca.ingest.auth")
+ ?: throw IllegalStateException("you need to specify the boudicca.ingest.auth property!")
+ val user = userAndPassword.split(":")[0]
+ val password = userAndPassword.split(":")[1]
+ val eventDb = EventDB(eventDbUrl, user, password)
return Consumer {
- ingestionApi.ingestAddPost(mapToApiEvent(it))
+ eventDb.ingestEvents(listOf(it))
}
}
@@ -179,34 +168,12 @@ fun createBoudiccaEnricherFunction(enricherUrl: String?): Function,
if (enricherUrl.isNullOrBlank()) {
return null
}
- val apiClient = events.boudicca.enricher.openapi.ApiClient()
- apiClient.updateBaseUri(enricherUrl)
- val enricherApi = EnricherControllerApi(apiClient)
+ val enricher = Enricher(enricherUrl)
return Function, List> { events ->
- enricherApi.enrich(
- EnrichRequestDTO().events(events.map { mapToEnricherEvent(it) })
- ).map { mapToEventCollectorEvent(it) }
+ enricher.enrichEvents(events)
}
}
-private fun mapToApiEvent(event: Event): events.boudicca.openapi.model.Event {
- return events.boudicca.openapi.model.Event()
- .name(event.name)
- .startDate(event.startDate)
- .data(event.additionalData)
-}
-
-private fun mapToEnricherEvent(event: Event): events.boudicca.enricher.openapi.model.Event {
- return events.boudicca.enricher.openapi.model.Event()
- .name(event.name)
- .startDate(event.startDate)
- .data(event.additionalData)
-}
-
-private fun mapToEventCollectorEvent(event: events.boudicca.enricher.openapi.model.Event): Event {
- return Event(event.name, event.startDate, event.data ?: emptyMap())
-}
-
fun retry(log: Logger, function: () -> T): T {
var lastException: Throwable? = null
for (i in 1..5) {
diff --git a/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/TwoStepEventCollector.kt b/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/TwoStepEventCollector.kt
index ffc70183..57cfd21d 100644
--- a/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/TwoStepEventCollector.kt
+++ b/boudicca.base/eventcollector-api/src/main/kotlin/base/boudicca/api/eventcollector/TwoStepEventCollector.kt
@@ -1,5 +1,6 @@
package base.boudicca.api.eventcollector
+import base.boudicca.Event
import org.slf4j.LoggerFactory
abstract class TwoStepEventCollector(private val name: String) : EventCollector {
diff --git a/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/BoudiccaEventDbProperties.kt b/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/BoudiccaEventDbProperties.kt
new file mode 100644
index 00000000..3e6c146e
--- /dev/null
+++ b/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/BoudiccaEventDbProperties.kt
@@ -0,0 +1,18 @@
+package base.boudicca.eventdb
+
+import org.springframework.boot.context.properties.ConfigurationProperties
+
+@ConfigurationProperties(prefix = "boudicca")
+data class BoudiccaEventDbProperties(
+ val store: Store,
+ val ingest: Ingest,
+ val entryKeyNames: List?,
+)
+
+data class Store(
+ val path: String?
+)
+
+data class Ingest(
+ val password: String?
+)
\ No newline at end of file
diff --git a/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/EventDBApplication.kt b/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/EventDBApplication.kt
index d56a882d..621c970f 100644
--- a/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/EventDBApplication.kt
+++ b/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/EventDBApplication.kt
@@ -2,8 +2,8 @@ package base.boudicca.eventdb
import io.swagger.v3.oas.annotations.OpenAPIDefinition
import io.swagger.v3.oas.annotations.servers.Server
-import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import org.springframework.scheduling.annotation.EnableScheduling
@@ -23,6 +23,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
)
@SpringBootApplication
@EnableScheduling
+@EnableConfigurationProperties(BoudiccaEventDbProperties::class)
class EventDBApplication : WebMvcConfigurer {
@Bean
@@ -44,10 +45,10 @@ class EventDBApplication : WebMvcConfigurer {
//TODO this really should be done better....
@Bean
- fun users(@Value("\${boudicca.ingest.password}") ingestPassword: String): UserDetailsService {
+ fun users(boudiccaEventDbProperties: BoudiccaEventDbProperties): UserDetailsService {
val ingestUser = User.builder()
.username("ingest")
- .password("{noop}" + ingestPassword)
+ .password("{noop}" + boudiccaEventDbProperties.ingest.password)
.roles("INGEST")
.build()
return InMemoryUserDetailsManager(ingestUser)
diff --git a/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/model/Event.kt b/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/model/Event.kt
index 2321dc96..af4105d3 100644
--- a/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/model/Event.kt
+++ b/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/model/Event.kt
@@ -8,12 +8,7 @@ data class Event(
val data: Map? = mapOf()
)
-data class EventKey(
- val name: String,
- val startDate: ZonedDateTime,
-) {
- constructor(event: Event) : this(event.name, event.startDate)
-}
+typealias EntryKey = Map
data class InternalEventProperties(
val timeAdded: Long
diff --git a/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/service/EventService.kt b/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/service/EventService.kt
index 527afe3b..73ecfeae 100644
--- a/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/service/EventService.kt
+++ b/boudicca.base/eventdb/src/main/kotlin/base/boudicca/eventdb/service/EventService.kt
@@ -1,8 +1,9 @@
package base.boudicca.eventdb.service
import base.boudicca.SemanticKeys
+import base.boudicca.eventdb.BoudiccaEventDbProperties
+import base.boudicca.eventdb.model.EntryKey
import base.boudicca.eventdb.model.Event
-import base.boudicca.eventdb.model.EventKey
import base.boudicca.eventdb.model.InternalEventProperties
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.DatabindException
@@ -12,7 +13,6 @@ import com.fasterxml.jackson.module.kotlin.KotlinModule
import jakarta.annotation.PreDestroy
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.beans.factory.annotation.Value
import org.springframework.beans.factory.config.ConfigurableBeanFactory
import org.springframework.context.annotation.Scope
import org.springframework.scheduling.annotation.Scheduled
@@ -21,6 +21,7 @@ import java.io.IOException
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import java.time.Duration
+import java.time.format.DateTimeFormatter
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
@@ -32,10 +33,12 @@ import kotlin.io.path.writeBytes
@Service
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) //even if this is the default, we REALLY have to make sure there is only one
-class EventService @Autowired constructor(@Value("\${boudicca.store.path}") private val storePath: String) {
+class EventService @Autowired constructor(
+ private val boudiccaEventDbProperties: BoudiccaEventDbProperties
+) {
private val LOG = LoggerFactory.getLogger(this::class.java)
- private val events = ConcurrentHashMap>()
+ private val events = ConcurrentHashMap>()
private val lastSeenCollectors = ConcurrentHashMap()
private val persistLock = ReentrantLock()
private val needsPersist = AtomicBoolean(false)
@@ -43,8 +46,8 @@ class EventService @Autowired constructor(@Value("\${boudicca.store.path}") priv
.addModule(KotlinModule.Builder().build()).build()
init {
- if (storePath.isNotBlank()) {
- val store = Path.of(storePath)
+ if (!boudiccaEventDbProperties.store.path.isNullOrBlank()) {
+ val store = Path.of(boudiccaEventDbProperties.store.path)
if (store.exists()) {
try {
val storeRead = objectMapper.readValue(
@@ -52,7 +55,7 @@ class EventService @Autowired constructor(@Value("\${boudicca.store.path}") priv
object : TypeReference>>() {})
storeRead.forEach {
- events[EventKey(it.first)] = it
+ events[getEntryKey(it.first)] = it
}
needsPersist.set(false)
@@ -81,7 +84,7 @@ class EventService @Autowired constructor(@Value("\${boudicca.store.path}") priv
}
fun add(event: Event) {
- val eventKey = EventKey(event)
+ val eventKey = getEntryKey(event)
val duplicate = events[eventKey]
//some cheap logging for finding duplicate events between different collectors
if (duplicate != null && duplicate.first.data?.get(SemanticKeys.COLLECTORNAME) != event.data?.get(
@@ -114,7 +117,7 @@ class EventService @Autowired constructor(@Value("\${boudicca.store.path}") priv
toRemoveEvents.forEach {
LOG.debug("removing event because it got too old: {}", it)
- events.remove(EventKey(it.first))
+ events.remove(getEntryKey(it.first))
needsPersist.set(true)
}
}
@@ -138,7 +141,7 @@ class EventService @Autowired constructor(@Value("\${boudicca.store.path}") priv
}
fun persist() {
- if (storePath.isBlank()) {
+ if (boudiccaEventDbProperties.store.path.isNullOrBlank()) {
return
}
persistLock.lock()
@@ -146,7 +149,7 @@ class EventService @Autowired constructor(@Value("\${boudicca.store.path}") priv
if (needsPersist.get()) {
val bytes = objectMapper.writeValueAsBytes(events.values)
try {
- Path.of(storePath)
+ Path.of(boudiccaEventDbProperties.store.path)
.writeBytes(bytes, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)
} catch (e: IOException) {
LOG.error("error persisting store", e)
@@ -157,4 +160,20 @@ class EventService @Autowired constructor(@Value("\${boudicca.store.path}") priv
persistLock.unlock()
}
}
+
+ private fun getEntryKey(event: Event): EntryKey {
+ val data = event.data?.toMutableMap() ?: mutableMapOf()
+ data[SemanticKeys.NAME] = event.name
+ data[SemanticKeys.STARTDATE] = DateTimeFormatter.ISO_DATE_TIME.format(event.startDate)
+
+ val keys =
+ if (!boudiccaEventDbProperties.entryKeyNames.isNullOrEmpty()) {
+ boudiccaEventDbProperties.entryKeyNames
+ } else {
+ data.keys
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ return keys.map { it to data[it] }.filter { it.second != null }.toMap() as EntryKey
+ }
}
diff --git a/boudicca.base/eventdb/src/main/resources/application.properties b/boudicca.base/eventdb/src/main/resources/application.properties
index b9824a10..ae2dd91f 100644
--- a/boudicca.base/eventdb/src/main/resources/application.properties
+++ b/boudicca.base/eventdb/src/main/resources/application.properties
@@ -1,4 +1,5 @@
server.port=8081
#this is the default and should be overwritten of course
boudicca.ingest.password=ingest
-boudicca.store.path=
\ No newline at end of file
+boudicca.store.path=
+boudicca.entryKeyNames=
\ No newline at end of file
diff --git a/boudicca.base/ingest-api/build.gradle.kts b/boudicca.base/ingest-api/build.gradle.kts
new file mode 100644
index 00000000..d42f4741
--- /dev/null
+++ b/boudicca.base/ingest-api/build.gradle.kts
@@ -0,0 +1,26 @@
+plugins {
+ kotlin("jvm")
+ kotlin("plugin.allopen")
+}
+
+repositories {
+ mavenCentral()
+ mavenLocal()
+}
+
+dependencies {
+ api(project(":boudicca.base:semantic-conventions"))
+ implementation("org.jetbrains.kotlin:kotlin-stdlib")
+ implementation(project(":boudicca.base:eventdb-openapi"))
+}
+
+java {
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(17))
+ vendor.set(JvmVendorSpec.ADOPTIUM)
+ }
+}
+
+tasks.withType {
+ kotlinOptions.javaParameters = true
+}
diff --git a/boudicca.base/ingest-api/src/main/kotlin/base/boudicca/api/eventdb/ingest/EventDB.kt b/boudicca.base/ingest-api/src/main/kotlin/base/boudicca/api/eventdb/ingest/EventDB.kt
new file mode 100644
index 00000000..b3cbd7fb
--- /dev/null
+++ b/boudicca.base/ingest-api/src/main/kotlin/base/boudicca/api/eventdb/ingest/EventDB.kt
@@ -0,0 +1,48 @@
+package base.boudicca.api.eventdb.ingest
+
+import base.boudicca.Event
+import events.boudicca.openapi.ApiClient
+import events.boudicca.openapi.api.EventIngestionResourceApi
+import java.util.*
+
+class EventDB(eventDbUrl: String, user: String, password: String) {
+
+ private val ingestApi: EventIngestionResourceApi
+
+ init {
+ if (eventDbUrl.isBlank()) {
+ throw IllegalStateException("you need to pass an eventDbUrl!")
+ }
+ if (user.isBlank()) {
+ throw IllegalStateException("you need to pass an user!")
+ }
+ if (password.isBlank()) {
+ throw IllegalStateException("you need to pass an password!")
+ }
+ val apiClient = ApiClient()
+ apiClient.updateBaseUri(eventDbUrl)
+ apiClient.setRequestInterceptor {
+ it.header(
+ "Authorization",
+ "Basic " + Base64.getEncoder()
+ .encodeToString(
+ ("$user:$password").encodeToByteArray()
+ )
+ )
+ }
+ ingestApi = EventIngestionResourceApi(apiClient)
+ }
+
+ fun ingestEvents(events: List) {
+ for (event in events) {
+ ingestApi.ingestAddPost(mapToRemoteEvent(event))
+ }
+ }
+
+ private fun mapToRemoteEvent(event: Event): events.boudicca.openapi.model.Event {
+ return events.boudicca.openapi.model.Event()
+ .name(event.name)
+ .startDate(event.startDate)
+ .data(event.data)
+ }
+}
\ No newline at end of file
diff --git a/boudicca.base/publisher-api/build.gradle.kts b/boudicca.base/publisher-api/build.gradle.kts
index 38e7810f..d42f4741 100644
--- a/boudicca.base/publisher-api/build.gradle.kts
+++ b/boudicca.base/publisher-api/build.gradle.kts
@@ -9,8 +9,9 @@ repositories {
}
dependencies {
+ api(project(":boudicca.base:semantic-conventions"))
implementation("org.jetbrains.kotlin:kotlin-stdlib")
- api(project(":boudicca.base:eventdb-openapi"))
+ implementation(project(":boudicca.base:eventdb-openapi"))
}
java {
diff --git a/boudicca.base/publisher-api/src/main/kotlin/base/boudicca/api/eventdb/publisher/EventDB.kt b/boudicca.base/publisher-api/src/main/kotlin/base/boudicca/api/eventdb/publisher/EventDB.kt
new file mode 100644
index 00000000..9053133b
--- /dev/null
+++ b/boudicca.base/publisher-api/src/main/kotlin/base/boudicca/api/eventdb/publisher/EventDB.kt
@@ -0,0 +1,25 @@
+package base.boudicca.api.eventdb.publisher
+
+import base.boudicca.Event
+import events.boudicca.openapi.ApiClient
+import events.boudicca.openapi.api.EventPublisherResourceApi
+
+class EventDB(eventDbUrl: String) {
+
+ private val publisherApi: EventPublisherResourceApi
+
+ init {
+ if (eventDbUrl.isBlank()) {
+ throw IllegalStateException("you need to pass an eventDbUrl!")
+ }
+ val apiClient = ApiClient()
+ apiClient.updateBaseUri(eventDbUrl)
+ publisherApi = EventPublisherResourceApi(apiClient)
+ }
+
+ fun getAllEvents(): List {
+ val events = publisherApi.eventsGet()
+
+ return events.map { Event(it.name, it.startDate, it.data ?: emptyMap()) }
+ }
+}
\ No newline at end of file
diff --git a/boudicca.base/publisher-event-html/src/main/kotlin/base/boudicca/publisher/event/html/service/EventService.kt b/boudicca.base/publisher-event-html/src/main/kotlin/base/boudicca/publisher/event/html/service/EventService.kt
index b03b4474..4f92058a 100644
--- a/boudicca.base/publisher-event-html/src/main/kotlin/base/boudicca/publisher/event/html/service/EventService.kt
+++ b/boudicca.base/publisher-event-html/src/main/kotlin/base/boudicca/publisher/event/html/service/EventService.kt
@@ -1,5 +1,6 @@
package base.boudicca.publisher.event.html.service
+import base.boudicca.Event
import base.boudicca.SemanticKeys
import base.boudicca.api.search.BoudiccaQueryBuilder
import base.boudicca.api.search.BoudiccaQueryBuilder.after
@@ -10,12 +11,10 @@ import base.boudicca.api.search.BoudiccaQueryBuilder.durationLonger
import base.boudicca.api.search.BoudiccaQueryBuilder.durationShorter
import base.boudicca.api.search.BoudiccaQueryBuilder.equals
import base.boudicca.api.search.BoudiccaQueryBuilder.isQuery
+import base.boudicca.api.search.QueryDTO
+import base.boudicca.api.search.Search
+import base.boudicca.api.search.SearchResultDTO
import base.boudicca.publisher.event.html.model.SearchDTO
-import base.boudicca.search.openapi.ApiClient
-import base.boudicca.search.openapi.api.SearchResourceApi
-import base.boudicca.search.openapi.model.Event
-import base.boudicca.search.openapi.model.QueryDTO
-import base.boudicca.search.openapi.model.SearchResultDTO
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
@@ -32,13 +31,13 @@ const val DEFAULT_DURATION_SHORTER_VALUE = 24 * 30
private const val SEARCH_TYPE_ALL = "ALL"
@Service
-class EventService @Autowired constructor(@Value("\${boudicca.search.url}") private val search: String) {
- private val searchApi: SearchResourceApi = createSearchApi()
+class EventService @Autowired constructor(@Value("\${boudicca.search.url}") private val searchUrl: String) {
+ private val search: Search = createSearchApi()
private val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy 'um' HH:mm 'Uhr'", Locale.GERMAN)
private val localDateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
fun search(searchDTO: SearchDTO): List