How can I convert Disposable operation to Flow? - kotlin

I'm trying to chain the r2dbc data flow and with the ReactiveElasticsearchOperations client for reactive index operations.
I get the data flow from the common r2dbc repository like:
#Repository
class MyEntityRepository(
private val databaseClient: DatabaseClient,
private val r2dbcConverter: R2dbcConverter
) {
fun findEntities(): Flow<MyEntity> = databaseClient
.sql(ENTITY_QUERY)
.map(::toMyEntity)
.flow()
private fun toMyEntity(row: Row): MyEntity = r2dbcConverter
.read(MyEntity::class.java, row)
}
I need to chain this flow with the ES reactive operations like:
#Service
class IndexManager(
private val repository: MyEntityRepository,
private val operations: ReactiveElasticsearchOperations
) {
fun createIndices(): Flow<Disposable> = repository
.findEntities()
.map { entity -> IndexCoordinates.of("$INDEX_PREFIX-${entity.name}")
} <------- Flow<IndexCoordinates>
.map { indexCoordinates ->
operations.indexOps(indexCoordinates)
.create()
.subscribe() <-------- Flow<Disposable>
}
}
I can't figure it out, how to transform the Disposable into the result, collect all results and return back as a flow...
I'm new to webflux and coroutines. Could anyone advice a way to handle this?

Related

How to enforce relationship between Kotlin classes

Im new to Kotlin and investigating what is/isnt possible
I have a use case as follows:-
As a technical exercise I am attempting to model remote API requests and responses, and enforce relationships between them
My goal is to be able to declare the relationship between Requests and Responses in a clear and succinct way at the top of a Class. This will 1). document the API calls made by this Class, 2). Enforce the relationship so that Request1 can only produce Response1
Pseudo code:-
Requests {
Request1 -> Response1
Request2 -> Response2
...
RequestN -> ResponseN
}
I have defined two interfaces Request & Response and employ them as follows:-
interface Request {
fun <T> response(data : T): Lazy<Response>
}
interface Response
data class Request1(val request: String) : Request {
data class Response1(val output: String) : Response
override fun <T> response(data: T): Lazy<Response> {
return lazy { Response1(data as String) }
}
}
data class Request2(val request: Long) : Request {
data class Response2(val output: Double) : Response
override fun <T> response(data: T): Lazy<Response> {
return lazy { Response2(data as Double) }
}
}
I have a Controller class that makes the API calls as follows:-
class Controller {
fun call(request: Request): Lazy<Response> {
return when (request) {
is Request1 -> request.response("Testing Data")
is Request2 -> request.response(Math.PI)
else -> TODO()
}
}
}
Using the above data classes I can enforce that Request1 is linked to only Response1 and also specify the response data type wrapped by each Response.
Although the above classes provide the functionality and adhere to these rules, they are verbose.
Is there a more succinct approach I could employ to obtain the desired result.
The reason I require this is I am looking for "Self Documenting" code, where a developer can view the definition of Request/Response pairs and association rules and clearly see what is intended.
For example: A developer looking at the final Request definitions can clearly see that Response1 with be generated by Request1. I also want to enforce that Response1 can only ever be produced from Request1.
My example above is simplified, as in "The Real World" the data wrapped by each Response will be sourced from the actual API request call, I have illustrated with "Hard Coded".
I would much rather define Request1 and Response1 on a single line if possible.
UPDATE
I have refactored my original classes as follows:-
interface Request<ResponseData> {
fun response(data: ResponseData): Lazy<Response>
}
interface Response
sealed class Requests<T> : Request<T> {
data class Request1(val request: String) : Requests<String>() {
inner class Response1(val output: String) : Response
override fun response(data: String): Lazy<Response> {
return lazy { Response1(data) }
}
}
data class Request2(val request: Long) : Requests<Double>() {
inner class Response2(val output: Double) : Response
override fun response(data: Double): Lazy<Response> {
return lazy { Response2(data) }
}
}
}
class Controller {
fun <T> call(request: Request<T>): Lazy<Response> {
return when (request) {
is Requests.Request1 -> request.response("Testing Data")
is Requests.Request2 -> request.response(Math.PI)
else -> TODO()
}
}
}
While this version of my code has many benefits from the original, one feature I am still not happy with is that each Request/Response declaration is still quite verbose, e.g. it requires 5 lines of code. Is there an approach I can employ to make each Request/Response pair declaration more succinct?, e.g. take up fewer lines of code.
UPDATE II
Im attempting to refactor my sealed class above so that the overridden function response is defined in the outer sealed class.
interface Request<ResponseData> {
fun response(data: ResponseData): Lazy<Response>
}
interface Response
sealed class Requests<T> : Request<T> {
data class Request1(val request: String) : Requests<String>() {
inner class Response1(val output: String) : Response
}
data class Request2(val request: Long) : Requests<Double>() {
inner class Response2(val output: Double) : Response
}
override fun response(data: T): Lazy<Response> {
return lazy { // What implementation goes here??? // }
}
}
Is this approach possible?
How do I refer to the individual concrete ResponseN classes in the outer sealed class?
Another approach:
data class Box<T, V>(val req: T, val rsp: V)
interface Interaction<RequestT, ResponseT> {
val req: RequestT
fun exec(): Box<RequestT, ResponseT>
}
sealed class Interactions<RequestT, ResponseT> : Interaction<RequestT, ResponseT> {
class Interaction1(override val req: String) : Interaction<String, String> {
override fun exec() = Box(req, "by")
}
class Interaction2(override val req: Long) : Interaction<Long, Double> {
override fun exec() = Box(req, 1.0)
}
}
fun main() {
val interaction1 = Interactions.Interaction1("hi")
val interaction2 = Interactions.Interaction2(42)
println(interaction1.exec()) // Box(req=hi, rsp=by)
println(interaction2.exec()) // Box(req=42, rsp=1.0)
}
Maybe your example is simplified from what you're actually doing, but I don't see the purpose of the Response interface, or the need for separate Request implementations to achieve what your code does:
data class Request<T>(val request: String, val responseType: KClass<out T>) {
fun response(data : T) = lazy { data }
}
class Controller {
fun <T: Any> call(request: Request<T>): Lazy<T> {
#Suppress("UNCHECKED_CAST")
return when (request.responseType) {
String::class -> request.response("Testing Data" as T)
Double::class -> request.response(Math.PI as T)
else -> TODO()
}
}
}
It's kind of an odd use of Lazy though, since you are wrapping a pre-computed value.
My goal is to be able to declare the relationship between Requests and Responses in a clear and succinct way at the top of a Class. This will 1). document the API calls made by this Class, 2). Enforce the relationship so that Request1 can only produce Response1
A great way to enforce the relationships is to separate the interface and implementation levels. Currently you have your interface defined as
interface Request {
fun <T> response(data : T): Lazy<Response>
}
And it does not tell you that the response can vary. It's high level and then you define actual relations in your implementation.
I suggest to decouple relations and the implementation by moving the relations to the interface level.
Here is my suggestion. Forgive me if something does not compile, I'm writing the code from my head, I want to communicate the design ideas and you may have to change some pseudocode.
Let's start with the interface:
interface Response
interface Request // I see that you are using primitive types for requests, so you don't need the interface. But in a real world scenario your requests will probably be more complex than primitive types and then it will make sense to wrap them in this interface. It also makes the code easier to understand - a string can be anything, while a Request is definitely a request.
// This is an interface that actually performs a request, so makes sense to name it in an actionable way
interface Requester<T, M> {
fun <in T: Request, out M: Response> request(data : T): Lazy<M>
}
This declaration tells you that there are different kinds of requests and responses and that there are some relations, but do not say what relations are yet.
Then I would declare the responses and requests implementations in a separate place to keep this code short and to the point
class Request1(val input: String) : Request
class Request2(val input: Double) : Request
class Response1(val output: String) : Response
class Response2(val output: Double) : Response
Then you declare the actual relations
interface Requester1: Requester<Request1, Response1>
interface Requester2: Requester<Request2, Response2>
At this point you have a file that clearly communicates the relation without any implementation details.
This is you final interface code, that solves your request for 1). document the API calls made by this Class, 2). Enforce the relationship so that Request1 can only produce Response1 ⬇️
interface Response
interface Request
interface Requester {
fun <in T: Request, out M: Response> request(data : T): Lazy<M>
}
interface Requester1: Requester<Request1, Response1>
interface Requester2: Requester<Request2, Response2>
Then you can do the implementation in a separate place to keep the interface clean and easy to understand.
sealed class Requests {
data class RequesterImpl1(val request: String) : Requests, Requester1 {
override fun request(data: Request1): Lazy<Response1> {
return lazy { Response1(data) }
}
}
data class RequesterImpl2(val request: Long) : Requests, Requester2 {
override fun request(data: Double2): Lazy<Response2> {
return lazy { Response2(data) }
}
}
}
This is the current design I am using
fun doNothing(): Unit = Unit
interface Interaction<Input, Output> {
interface Response<Output> : Interaction<Unit, Output> {
val output: Output
}
interface Request<Input, Output> : Interaction<Input, Output> {
val input: Input
fun react(output: Output): Response<Output>
}
}
sealed class Interactions<I, O> : Interaction<I, O> {
data class RequestOne(override val input: String) : Interaction.Request<String, Long> {
internal data class ResponseOne(override val output: Long) : Interaction.Response<Long>
override fun react(output: Long): Interaction.Response<Long> = ResponseOne(output)
}
data class RequestTwo(override val input: CustomInput) : Interaction.Request<CustomInput, CustomOutput> {
internal data class ResponseTwo(override val output: CustomOutput) : Interaction.Response<CustomOutput>
override fun react(output: CustomOutput): Interaction.Response<CustomOutput> = ResponseTwo(output)
}
data class RequestThree(override val input: Unit = doNothing()) : Interaction.Request<Unit, CustomOutputTwo> {
internal data class ResponseThree(override val output: CustomOutputTwo) : Interaction.Response<CustomOutputTwo>
override fun react(output: CustomOutputTwo): Interaction.Response<CustomOutputTwo> = ResponseThree(output)
}
data class RequestFour(override val input: Unit = doNothing()) : Interaction.Request<Unit, Unit> {
internal data class ResponseFour(override val output: Unit = doNothing()) : Interaction.Response<Unit>
override fun react(output: Unit): Interaction.Response<Unit> = ResponseFour()
}
data class RequestFive(override val input: CustomInputTwo) : Interaction.Request<CustomInputTwo, Unit> {
internal data class ResponseFive(override val output: Unit = doNothing()) : Interaction.Response<Unit>
override fun react(output: Unit): Interaction.Response<Unit> = ResponseFive()
}
}
I believe this approach enforces the relationships I require between individual Requests and their associated Response types.
The features of this design I would like to improve on is the use of Unit when defining the Response interface.
Also I cannot see a way to improve on the sealed class Interactions<I, O> : Interaction<I, O> {...}, as I never use the Generic I & O
I would also like to be able to define a single fun react(output: Output): Response<Output> within the parent sealed class Interactions instead of having to implement this function in each inner Action data class, however I do not think that is possible.

CUBA Platform push messages from backend to UI

i was wondering if it is possible to send messages from the backend (for example a running task that receives information from an external system) to the UI. In my case it needs to be a specific session (no broadcast) and only on a specific screen
plan B would be polling the backend frequently but i was hoping to get something more "realtime"
I was trying to work something out like this, but i keep getting a NotSerializableException.
#Push
class StorageAccess : Screen(), MessageListener {
#Inject
private lateinit var stationWSService: StationWebSocketService
#Inject
private lateinit var notifications: Notifications
#Subscribe
private fun onInit(event: InitEvent) {
}
#Subscribe("stationPicker")
private fun onStationPickerValueChange(event: HasValue.ValueChangeEvent<StorageUnit>) {
val current = AppUI.getCurrent()
current.userSession.id ?: return
val prevValue = event.prevValue
if (prevValue != null) {
stationWSService.remove(current.userSession.id)
}
val value = event.value ?: return
stationWSService.listen(current.userSession.id, value, this)
}
override fun messageReceived(message: String) {
val current = AppUI.getCurrent()
current.access {
notifications.create().withCaption(message).show()
}
}
#Subscribe
private fun onAfterDetach(event: AfterDetachEvent) {
val current = AppUI.getCurrent()
current.userSession.id ?: return
stationWSService.remove(current.userSession.id)
}
}
-- The callback interface
interface MessageListener : Serializable {
fun messageReceived(message: String);
}
-- The listen method of my backend service
private val listeners: MutableMap<String, MutableMap<UUID, MessageListener>> = HashMap()
override fun listen(id: UUID, storageUnit: StorageUnit, callback: MessageListener) {
val unitStationIP: String = storageUnit.unitStationIP ?: return
if (!listeners.containsKey(unitStationIP))
listeners[unitStationIP] = HashMap()
listeners[unitStationIP]?.set(id, callback)
}
The Exception i get is NotSerializableException: com.haulmont.cuba.web.sys.WebNotifications which happens during adding the listener to the backend: stationWSService.listen(current.userSession.id, value, this)
as far as i understand this is the place where the UI sends the information to the backend - and with it the entire status of the class StorageAccess, including all its members.
is there an elegant solution to this?
regards
There is an add-on that solves exactly this problem: https://github.com/cuba-platform/global-events-addon

Getting spring oauth2 user info data

I have an oauth2 server and client. In client I configured ClientRegistrationRepository:
#Bean
#Conditional(SsoCondition::class)
open fun clientRegistrationRepository(): ClientRegistrationRepository {
val test = ClientRegistration.withRegistrationId(registrationId)
.clientId(clientId)
.clientSecret(clientSecret)
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUriTemplate("{baseUrl}/{action}/oauth2/code/{registrationId}")
.authorizationUri(authorizeUri)
.tokenUri(tokenUri)
.userInfoUri(userInfoUri)
.scope("read", "write")
.userNameAttributeName(userNameAttribute)
.build()
return InMemoryClientRegistrationRepository(test)
}
This works fine and authorization is performed.
The problem is in userInfoUri. This uri is invoked and needed server method is performed. I see the user data and that method return this data.
The method for authorizeUri is:
#GetMapping("/api/user/me")
fun getUserInfo(response: HttpServletResponse, request: HttpServletRequest, principal: Principal): HashMap<String, Any?> {
val authentication = SecurityContextHolder.getContext().authentication
val userData = HashMap<String, Any?>()
userData[OUTER_ID] = principal.name
val ssoUser = authentication.userAuthentication.principal.attributes
// getting data from ssoUser to userData
...
return userData
}
And so the question is: where or how can I get this data in the client application?
I don't know how right this solution, but I got the user data like this:
Creating custom implementation of OAuth2AuthorizedClientService interface:
class CustomOAuth2AuthorizedClientService(private val clientRegistrationRepository: ClientRegistrationRepository) : OAuth2AuthorizedClientService {
private val principalData = ConcurrentHashMap<String, Authentication>()
...
override fun saveAuthorizedClient(authorizedClient: OAuth2AuthorizedClient, principal: Authentication) {
...
val key = ... // create some key
principalData[key] = principal
}
...
fun getPrincipal(key: String): Authentication? {
return authorizedClientsPrincipal[key]
}
}
Creating bean for CustomOAuth2AuthorizedClientService:
#Bean
open fun authorizedClientService(): OAuth2AuthorizedClientService {
return CustomOAuth2AuthorizedClientService(clientRegistrationRepository())
}
where clientRegistrationRepository() is a ClientRegistrationRepository bean.
In the code get user data from CustomOAuth2AuthorizedClientService bean:
#Autowired
private var oAuth2AuthorizedClientService: OAuth2AuthorizedClientService
...
fun test() {
val userData = (oAuth2AuthorizedClientService as CustomOAuth2AuthorizedClientService).getPrincipal(key)
}

jOOQ fetch vs fetchResultSet and close connection in Kotlin

I'm using Kotlin with HikariCP and jOOQ to query my database. I've come to realize that this code works as expected, fetching the rows and closing the connection afterwards:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<String> {
DSL.using(datasource, SQLDialect.POSTGRES_10)
.use { ctx ->
ctx.select(countries.CO_NAME)
.from(countries)
.orderBy(countries.CO_NAME)
.fetch()
return emptyList()
}
}
}
whereas if I use fetchResultSet(), the connection is never closed and the pool dries out:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<String> {
DSL.using(datasource, SQLDialect.POSTGRES_10)
.use { ctx ->
ctx.select(countries.CO_NAME)
.from(countries)
.orderBy(countries.CO_NAME)
.fetchResultSet()
return emptyList()
}
}
}
I've seen that AbstractResultQuery#fetchResultSet() is delegating to a fetchLazy() method, so not sure if it has something to do with that.
If I get the connection myself instead of delegating it to the DSLContext, then it works:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<String> {
val conn = datasource.connection
conn.use {
DSL.using(it, SQLDialect.POSTGRES_10)
.select(countries.CO_NAME)
.from(countries)
.orderBy(countries.CO_NAME)
.fetchResultSet()
return emptyList()
}
}
}
Is this last approach the one I should be using?
It works exactly as specified in the Javadoc:
This is the same as calling fetchLazy().resultSet() and will return a ResultSet wrapping the JDBC driver's ResultSet. Closing this ResultSet may close the producing Statement or PreparedStatement, depending on your setting for keepStatement(boolean).
The point of this method is that you want to consume a JDBC result set rather than having jOOQ consume it for you. So, you're responsible for the resource management.
Given your example code, you should definitely not call this method but call fetch() instead. For example:
class CountriesService(private val datasource: DataSource) {
private val countries = Countries()
fun getCountries(): List<String> {
return
DSL.using(datasource, SQLDialect.POSTGRES_10)
.select(countries.CO_NAME)
.from(countries)
.orderBy(countries.CO_NAME)
.fetch(countries.CO_NAME)
}
}
Notice, you don't need to call that use() method on your DSLContext. While DSLContext extends AutoCloseable, this is only needed when your DSLContext manages the underlying JDBC connection (i.e. when it creates it). In your case, when you pass a data source to DSL.using(), then you don't have to close the DSLContext.

Use a class from a list of generic interface

I am trying to implement a QueryBus. Basically, I want to register a list of QueryHandlers. Each QueryHandler implements a handle method defined by an interface. Each QueryHandler is associated to a Query. I want to be able to retrieve a QueryHandler using the Query and call handle on it.
The thing is the handle has to be generic because each QueryHandler handles a Query differently. They all take a dedicated Query and may return whatever they want.
interface Query<R>
interface QueryHandler<R, Q : Query<R>> {
fun handle(query: Q): R
fun listenTo(): String
}
// DTOs
data class BookDto(val name: String)
// List books query
data class ListBooksQuery(val page: Int = 1): Query<List<BookDto>>
class ListBooksQueryHandler: QueryHandler<List<BookDto>, ListBooksQuery> {
override fun handle(query: ListBooksQuery): List<BookDto> {
return listOf(BookDto("Dune"), BookDto("Dune II"))
}
override fun listenTo(): String = ListBooksQuery::class.toString()
}
// Get book query
data class GetBookQuery(val name: String): Query<BookDto?>
class GetBookQueryHandler: QueryHandler<BookDto?, GetBookQuery> {
override fun handle(query: GetBookQuery): BookDto {
return BookDto("Dune")
}
override fun listenTo(): String = GetBookQuery::class.toString()
}
// Run it!
fun main(args: Array<String>) {
// Initializing query bus
val queryHandlers = mapOf(
with(ListBooksQueryHandler()) {this.listenTo() to this},
with(GetBookQueryHandler()) {this.listenTo() to this}
)
val command = ListBooksQuery()
val result = queryHandlers[command::class.toString()].handle(command)
// Should print the list of BookDto
print(result)
}
I don't even know if its possible, to be honest.
UPDATE 1:
I changed the usage example in the main to show what I am really trying to do. The List was for (bad?) demonstration purpose. I want to store the QueryHandlers and retrieve them from a map.
Additional resources:
Here is what I really want to do:
https://gist.github.com/ValentinTrinque/76b7a32221884a46e657090b9ee60193
UPDATE I've read your gist and tried to come up with a solution that will provide a clean interface to the user of the QueryBusMiddleware.
Note that I used objects instead of classes for the QueryHandler implementations, which felt more natural to me (since there is only one possible entry in the map for each Query implementation).
interface Query<R>
interface QueryHandler<R, Q: Query<R>> {
fun handle(query: Q): R
fun listenTo(): String
}
// DTOs
data class BookDto(val name: String)
// List books query
data class ListBooksQuery(val page: Int = 1): Query<List<BookDto>>
object ListBooksQueryHandler: QueryHandler<List<BookDto>, ListBooksQuery> {
override fun handle(query: ListBooksQuery): List<BookDto> {
return listOf(BookDto("Dune"), BookDto("Dune II"))
}
override fun listenTo(): String = ListBooksQuery::class.toString()
}
// Get book query
data class GetBookQuery(val name: String): Query<BookDto?>
object GetBookQueryHandler: QueryHandler<BookDto?, GetBookQuery> {
override fun handle(query: GetBookQuery): BookDto {
return BookDto("Dune")
}
override fun listenTo(): String = GetBookQuery::class.toString()
}
// Run it!
fun main(args: Array<String>) {
// Initializing query bus
val queryHandlers = listOf(
ListBooksQueryHandler,
GetBookQueryHandler
)
val dispatcher: QueryBusMiddleware = QueryDispatcherMiddleware(queryHandlers)
// Calling query bus
val query = ListBooksQuery()
// Result should be List<BookDto>
val result = dispatcher.dispatch(query)
print(result)
}
interface QueryBusMiddleware {
fun <R, Q : Query<R>> dispatch(query: Q): R
}
class QueryDispatcherMiddleware constructor(handlers: List<QueryHandler<*, *>>) : QueryBusMiddleware {
private val handlers = HashMap<String, QueryHandler<*, *>>()
init {
handlers.forEach { handler -> this.handlers[handler.listenTo()] = handler }
}
override fun <R, Q : Query<R>> dispatch(query: Q): R {
val queryClass = query::class.toString()
val handler = handlers[queryClass] ?: throw Exception("No handler listen to the query: $queryClass")
return handler::class.members.find { it.name == "handle" }!!.call(handler, query) as R
}
}