All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.infobip.kafkistry.webapp.hazelcast.HazelcastConfig.kt Maven / Gradle / Ivy

The newest version!
package com.infobip.kafkistry.webapp.hazelcast

import com.hazelcast.config.Config
import com.hazelcast.config.NetworkConfig
import com.hazelcast.config.TcpIpConfig
import com.hazelcast.core.Hazelcast
import com.hazelcast.core.HazelcastInstance
import org.springframework.beans.factory.ObjectProvider
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.context.properties.NestedConfigurationProperty
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.session.FlushMode
import org.springframework.session.config.SessionRepositoryCustomizer
import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository
import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession


/**
 * Hazelcast is, at time of writing this documentation, used for 2 things:
 *  - providing distributed session storage, meaning, when spring http session is created on one instance,
 *    the next incoming http request will be visible on other instances
 *  - providing platform for publishing and receiving KafkistryEvents between the same and between different
 *    instances of application
 */
@EnableHazelcastHttpSession(flushMode = FlushMode.IMMEDIATE)
@Configuration
@ConditionalOnProperty("app.hazelcast.enabled", matchIfMissing = true)
@EnableConfigurationProperties(HazelcastProperties::class)
class HazelcastConfig(
    private val hazelcastProperties: HazelcastProperties,
    customDiscoveryProvider: ObjectProvider
) {

    private val customDiscovery = customDiscoveryProvider.getIfAvailable {
        emptyIpsDiscovery
    }

    @Bean
    fun hazelcastInstance(): HazelcastInstance {
        val config = Config().apply {
            clusterName = hazelcastProperties.group
            networkConfig.apply {
                port = hazelcastProperties.port
                publicAddress = hazelcastProperties.advertiseAddress + ":" + hazelcastProperties.port
                join.apply {
                    multicastConfig.isEnabled = false
                    when (hazelcastProperties.discovery.type) {
                        DiscoveryType.NONE -> Unit
                        DiscoveryType.CUSTOM_IMPLEMENTATION -> tcpIpConfig.addMembers(customDiscovery.getSeedIps())
                        DiscoveryType.LOCALHOST_IP -> tcpIpConfig.addMembers("127.0.0.1")
                        DiscoveryType.MULTICAST -> run { multicastConfig.isEnabled = true }
                        DiscoveryType.STATIC_IPS -> tcpIpConfig.addMembers(hazelcastProperties.discovery.memberIps)
                    }
                }
            }
        }
        return Hazelcast.newHazelcastInstance(config)
    }

    @Bean
    fun hazelcastSessionRepositoryCustomizer(
        serverFactory: AbstractServletWebServerFactory,
    ): SessionRepositoryCustomizer {
        return SessionRepositoryCustomizer {
            it.setDefaultMaxInactiveInterval(serverFactory.session.timeout)
        }
    }

    private fun TcpIpConfig.addMembers(memberIps: String) = addMembers(listOf(memberIps))

    private fun TcpIpConfig.addMembers(memberIps: List) {
        isEnabled = true
        memberIps.forEach { addMember(it) }
    }

}

@ConfigurationProperties(prefix = "app.hazelcast")
class HazelcastProperties {

    var enabled = true
    var port: Int = NetworkConfig.DEFAULT_PORT
    var group = "kafkistry"
    var advertiseAddress = "127.0.0.1"

    @NestedConfigurationProperty
    val discovery = HazelcastDiscoveryProperties()
}

class HazelcastDiscoveryProperties {

    var type = DiscoveryType.MULTICAST
    var memberIps = ""
}

enum class DiscoveryType {
    NONE,
    CUSTOM_IMPLEMENTATION,
    LOCALHOST_IP,
    MULTICAST,
    STATIC_IPS
}

interface CustomDiscoveryIpsProvider {

    fun getSeedIps(): List
}

private val emptyIpsDiscovery = object : CustomDiscoveryIpsProvider {
    override fun getSeedIps(): List = emptyList()
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy