From 29afc6a008e2b11cf68841346b8df15bff27e60d Mon Sep 17 00:00:00 2001 From: Gerard Klijs Date: Mon, 29 Jan 2024 17:17:30 +0100 Subject: [PATCH] Add a notification list to the api, and will log any notifications on the correct leven when returned from the server. --- .../api/notifications/Notification.kt | 26 ++++++ .../api/notifications/NotificationLevel.kt | 30 +++++++ .../api/notifications/NotificationList.kt | 24 +++++ .../client/AxoniqConsoleRSocketClient.kt | 88 +++++++++++-------- 4 files changed, 132 insertions(+), 36 deletions(-) create mode 100644 console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/Notification.kt create mode 100644 console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/NotificationLevel.kt create mode 100644 console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/NotificationList.kt diff --git a/console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/Notification.kt b/console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/Notification.kt new file mode 100644 index 0000000..410e1e4 --- /dev/null +++ b/console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/Notification.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022-2024. AxonIQ B.V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.axoniq.console.framework.api.notifications + +import com.fasterxml.jackson.annotation.JsonProperty + +data class Notification( + @JsonProperty("l") + val level: NotificationLevel, + @JsonProperty("m") + val message: String, +) \ No newline at end of file diff --git a/console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/NotificationLevel.kt b/console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/NotificationLevel.kt new file mode 100644 index 0000000..fbde22f --- /dev/null +++ b/console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/NotificationLevel.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022-2024. AxonIQ B.V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.axoniq.console.framework.api.notifications + +import com.fasterxml.jackson.annotation.JsonProperty + +enum class NotificationLevel { + @JsonProperty("d") + Debug, + + @JsonProperty("i") + Info, + + @JsonProperty("w") + Warn +} \ No newline at end of file diff --git a/console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/NotificationList.kt b/console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/NotificationList.kt new file mode 100644 index 0000000..dcccc13 --- /dev/null +++ b/console-framework-client-api/src/main/java/io/axoniq/console/framework/api/notifications/NotificationList.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022-2024. AxonIQ B.V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.axoniq.console.framework.api.notifications + +import com.fasterxml.jackson.annotation.JsonProperty + +data class NotificationList( + @JsonProperty("l") + val messages: List, +) \ No newline at end of file diff --git a/console-framework-client/src/main/java/io/axoniq/console/framework/client/AxoniqConsoleRSocketClient.kt b/console-framework-client/src/main/java/io/axoniq/console/framework/client/AxoniqConsoleRSocketClient.kt index c1a7ec2..4dac784 100644 --- a/console-framework-client/src/main/java/io/axoniq/console/framework/client/AxoniqConsoleRSocketClient.kt +++ b/console-framework-client/src/main/java/io/axoniq/console/framework/client/AxoniqConsoleRSocketClient.kt @@ -18,6 +18,8 @@ package io.axoniq.console.framework.client import io.axoniq.console.framework.api.ClientSettings import io.axoniq.console.framework.api.Routes +import io.axoniq.console.framework.api.notifications.NotificationLevel +import io.axoniq.console.framework.api.notifications.NotificationList import io.axoniq.console.framework.client.strategy.RSocketPayloadEncodingStrategy import io.netty.buffer.ByteBufAllocator import io.netty.buffer.CompositeByteBuf @@ -28,6 +30,7 @@ import io.rsocket.metadata.WellKnownMimeType import io.rsocket.transport.netty.client.TcpClientTransport import org.axonframework.lifecycle.Lifecycle import org.axonframework.lifecycle.Phase +import org.slf4j.Logger import org.slf4j.LoggerFactory import reactor.core.publisher.Mono import reactor.netty.tcp.TcpClient @@ -52,19 +55,19 @@ import kotlin.math.pow */ @Suppress("MemberVisibilityCanBePrivate") class AxoniqConsoleRSocketClient( - private val environmentId: String, - private val accessToken: String, - private val applicationName: String, - private val host: String, - private val port: Int, - private val secure: Boolean, - private val initialDelay: Long, - private val setupPayloadCreator: SetupPayloadCreator, - private val registrar: RSocketHandlerRegistrar, - private val encodingStrategy: RSocketPayloadEncodingStrategy, - private val clientSettingsService: ClientSettingsService, - private val executor: ScheduledExecutorService, - private val nodeName: String, + private val environmentId: String, + private val accessToken: String, + private val applicationName: String, + private val host: String, + private val port: Int, + private val secure: Boolean, + private val initialDelay: Long, + private val setupPayloadCreator: SetupPayloadCreator, + private val registrar: RSocketHandlerRegistrar, + private val encodingStrategy: RSocketPayloadEncodingStrategy, + private val clientSettingsService: ClientSettingsService, + private val executor: ScheduledExecutorService, + private val nodeName: String, ) : Lifecycle { private val heartbeatOrchestrator = HeartbeatOrchestrator() private var maintenanceTask: ScheduledFuture<*>? = null @@ -92,10 +95,13 @@ class AxoniqConsoleRSocketClient( * Sends a message to the AxonIQ Console. If there is no connection active, does nothing silently. * The connection will automatically be setup. Losing a few reports is no problem. */ - fun send(route: String, payload: Any): Mono { + fun send(route: String, payload: Any): Mono { return rsocket ?.requestResponse(encodingStrategy.encode(payload, createRoutingMetadata(route))) - ?.then() + ?.map { + val notifications = encodingStrategy.decode(it, NotificationList::class.java) + logger.log(notifications) + } ?: Mono.empty() } @@ -106,7 +112,7 @@ class AxoniqConsoleRSocketClient( * 60 seconds. */ fun start() { - if(this.maintenanceTask != null) { + if (this.maintenanceTask != null) { return } this.maintenanceTask = executor.scheduleWithFixedDelay( @@ -143,12 +149,12 @@ class AxoniqConsoleRSocketClient( private fun createRSocket(): RSocket { val authentication = io.axoniq.console.framework.api.ConsoleClientAuthentication( - identification = io.axoniq.console.framework.api.ConsoleClientIdentifier( - environmentId = environmentId, - applicationName = applicationName, - nodeName = nodeName - ), - accessToken = accessToken + identification = io.axoniq.console.framework.api.ConsoleClientIdentifier( + environmentId = environmentId, + applicationName = applicationName, + nodeName = nodeName + ), + accessToken = accessToken ) val setupPayload = encodingStrategy.encode( @@ -156,14 +162,14 @@ class AxoniqConsoleRSocketClient( createSetupMetadata(authentication) ) val rsocket = RSocketConnector.create() - .metadataMimeType(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.string) - .dataMimeType(encodingStrategy.getMimeType().string) - .setupPayload(setupPayload) - .acceptor { _, rsocket -> - Mono.just(registrar.createRespondingRSocketFor(rsocket)) - } - .connect(tcpClientTransport()) - .block()!! + .metadataMimeType(WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.string) + .dataMimeType(encodingStrategy.getMimeType().string) + .setupPayload(setupPayload) + .acceptor { _, rsocket -> + Mono.just(registrar.createRespondingRSocketFor(rsocket)) + } + .connect(tcpClientTransport()) + .block()!! return rsocket } @@ -181,15 +187,15 @@ class AxoniqConsoleRSocketClient( } private fun tcpClientTransport() = - TcpClientTransport.create(tcpClient()) + TcpClientTransport.create(tcpClient()) private fun tcpClient(): TcpClient { val client = TcpClient.create() - .host(host) - .port(port) - .doOnDisconnected { - disposeCurrentConnection() - } + .host(host) + .port(port) + .doOnDisconnected { + disposeCurrentConnection() + } return if (secure) { return client.secure() } else client @@ -280,4 +286,14 @@ class AxoniqConsoleRSocketClient( } } } + + private fun Logger.log(notificationList: NotificationList) { + notificationList.messages.forEach { + when (it.level) { + NotificationLevel.Debug -> this.debug(it.message) + NotificationLevel.Info -> this.info(it.message) + NotificationLevel.Warn -> this.warn(it.message) + } + } + } }