ENT-11251: Upgrade to Kotlin language version 1.9 (#7660)

This commit is contained in:
Shams Asari 2024-01-25 13:51:19 +00:00 committed by GitHub
parent 3d90c1d850
commit 63f8e220c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 73 additions and 74 deletions

View File

@ -5,7 +5,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import static org.gradle.api.JavaVersion.VERSION_17
import static org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
import static org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_8
import static org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
buildscript {
// For sharing constants between builds
@ -284,8 +284,8 @@ allprojects {
tasks.withType(KotlinCompile).configureEach {
compilerOptions {
languageVersion = KOTLIN_1_8
apiVersion = KOTLIN_1_8
languageVersion = KOTLIN_1_9
apiVersion = KOTLIN_1_9
jvmTarget = JVM_17
javaParameters = true // Useful for reflection.
freeCompilerArgs = ['-Xjvm-default=all-compatibility']

View File

@ -5,6 +5,6 @@ owasp.failOnError=false
owasp.failBuildOnCVSS=11.0
compilation.allWarningsAsErrors=false
test.parallel=false
kotlin_version=1.9.0
kotlin_version=1.9.20
commons_lang3_version=3.12.0
json_api_version=1.1.4

View File

@ -10,7 +10,11 @@ import net.corda.node.services.config.AuthDataSourceType
import net.corda.node.services.config.PasswordEncryption
import net.corda.node.services.config.SecurityConfiguration
import net.corda.nodeapi.internal.config.User
import org.apache.shiro.authc.*
import org.apache.shiro.authc.AuthenticationException
import org.apache.shiro.authc.AuthenticationInfo
import org.apache.shiro.authc.AuthenticationToken
import org.apache.shiro.authc.SimpleAuthenticationInfo
import org.apache.shiro.authc.UsernamePasswordToken
import org.apache.shiro.authc.credential.PasswordMatcher
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher
import org.apache.shiro.authz.AuthorizationInfo
@ -34,13 +38,8 @@ private typealias AuthServiceConfig = SecurityConfiguration.AuthService
class RPCSecurityManagerImpl(config: AuthServiceConfig, cacheFactory: NamedCacheFactory) : RPCSecurityManager {
override val id = config.id
private val manager: DefaultSecurityManager
private val manager: DefaultSecurityManager = buildImpl(config, cacheFactory)
init {
manager = buildImpl(config, cacheFactory)
}
@Throws(FailedLoginException::class)
override fun authenticate(principal: String, password: Password): AuthorizingSubject {
password.use {
val authToken = UsernamePasswordToken(principal, it.value)
@ -83,11 +82,12 @@ class RPCSecurityManagerImpl(config: AuthServiceConfig, cacheFactory: NamedCache
}
return DefaultSecurityManager(realm).also {
// Setup optional cache layer if configured
it.cacheManager = config.options?.cache?.let {
it.cacheManager = config.options?.cache?.let { options ->
CaffeineCacheManager(
timeToLiveSeconds = it.expireAfterSecs,
maxSize = it.maxEntries,
cacheFactory = cacheFactory)
timeToLiveSeconds = options.expireAfterSecs,
maxSize = options.maxEntries,
cacheFactory = cacheFactory
)
}
}
}
@ -193,8 +193,7 @@ private typealias ShiroCache<K, V> = org.apache.shiro.cache.Cache<K, V>
/*
* Adapts a [com.github.benmanes.caffeine.cache.Cache] to a [org.apache.shiro.cache.Cache] implementation.
*/
private fun <K : Any, V> Cache<K, V>.toShiroCache() = object : ShiroCache<K, V> {
private fun <K : Any, V : Any> Cache<K, V>.toShiroCache() = object : ShiroCache<K, V> {
private val impl = this@toShiroCache
override operator fun get(key: K) = impl.getIfPresent(key)
@ -231,13 +230,13 @@ private class CaffeineCacheManager(val maxSize: Long,
private val instances = ConcurrentHashMap<String, ShiroCache<*, *>>()
override fun <K : Any, V> getCache(name: String): ShiroCache<K, V> {
override fun <K : Any, V : Any> getCache(name: String): ShiroCache<K, V> {
val result = instances[name] ?: buildCache<K, V>(name)
instances.putIfAbsent(name, result)
return uncheckedCast(result)
}
private fun <K : Any, V> buildCache(name: String): ShiroCache<K, V> {
private fun <K : Any, V : Any> buildCache(name: String): ShiroCache<K, V> {
logger.info("Constructing cache '$name' with maximumSize=$maxSize, TTL=${timeToLiveSeconds}s")
return cacheFactory.buildNamed<K, V>("RPCSecurityManagerShiroCache_$name").toShiroCache()
}
@ -245,4 +244,4 @@ private class CaffeineCacheManager(val maxSize: Long,
companion object {
private val logger = loggerFor<CaffeineCacheManager>()
}
}
}

View File

@ -15,17 +15,17 @@ class PersistentPartyInfoCache(private val networkMapCache: PersistentNetworkMap
private val database: CordaPersistence) {
// probably better off using a BiMap here: https://www.baeldung.com/guava-bimap
private val cordaX500NameToPartyIdCache = NonInvalidatingCache<CordaX500Name, SecureHash?>(
cacheFactory = cacheFactory,
name = "RecoveryPartyInfoCache_byCordaX500Name") { key ->
database.transaction { queryByCordaX500Name(session, key) }
}
private val cordaX500NameToPartyIdCache = NonInvalidatingCache<CordaX500Name, SecureHash>(
cacheFactory = cacheFactory,
name = "RecoveryPartyInfoCache_byCordaX500Name"
) { key -> database.transaction { queryByCordaX500Name(session, key) } }
private val partyIdToCordaX500NameCache = NonInvalidatingCache<SecureHash, CordaX500Name?>(
cacheFactory = cacheFactory,
name = "RecoveryPartyInfoCache_byPartyId") { key ->
database.transaction { queryByPartyId(session, key) }
}
private val partyIdToCordaX500NameCache = NonInvalidatingCache<SecureHash, CordaX500Name>(
cacheFactory = cacheFactory,
name = "RecoveryPartyInfoCache_byPartyId"
) { key ->
database.transaction { queryByPartyId(session, key) }
}
private lateinit var trackNetworkMapUpdates: Observable<NetworkMapCache.MapChange>

View File

@ -1,7 +1,6 @@
package net.corda.node.utilities
import com.github.benmanes.caffeine.cache.LoadingCache
import com.github.benmanes.caffeine.cache.Weigher
import net.corda.core.crypto.SecureHash
import net.corda.core.internal.NamedCacheFactory
import net.corda.core.utilities.contextLogger
@ -10,7 +9,6 @@ import net.corda.nodeapi.internal.persistence.contextTransaction
import net.corda.nodeapi.internal.persistence.currentDBSession
import org.hibernate.Session
import org.hibernate.internal.SessionImpl
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
@ -22,7 +20,8 @@ import java.util.stream.Stream
*
* This class relies heavily on the fact that compute operations in the cache are atomic for a particular key.
*/
abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
@Suppress("TooManyFunctions")
abstract class AppendOnlyPersistentMapBase<K : Any, V, E, out EK>(
val toPersistentEntityKey: (K) -> EK,
val fromPersistentEntity: (E) -> Pair<K, V>,
val toPersistentEntity: (key: K, value: V) -> E,
@ -326,9 +325,9 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
}
// No one is writing, but we haven't looked in the database yet. This can only be when there are no writers.
class Unknown<K, T>(private val map: AppendOnlyPersistentMapBase<K, T, *, *>,
private val key: K,
private val _valueLoader: () -> T?) : Transactional<T>() {
class Unknown<K : Any, T>(private val map: AppendOnlyPersistentMapBase<K, T, *, *>,
private val key: K,
private val _valueLoader: () -> T?) : Transactional<T>() {
override val value: T
get() = valueWithoutIsolationDelegate.value ?: throw NoSuchElementException("Not present")
override val isPresent: Boolean
@ -351,11 +350,11 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
// Written in a transaction (uncommitted) somewhere, but there's a small window when this might be seen after commit,
// hence the committed flag.
class InFlight<K, T>(private val map: AppendOnlyPersistentMapBase<K, T, *, *>,
private val key: K,
val weight: Int,
private val _readerValueLoader: () -> T?,
private val _writerValueLoader: () -> T = { throw IllegalAccessException("No value loader provided") }) : Transactional<T>() {
class InFlight<K : Any, T>(private val map: AppendOnlyPersistentMapBase<K, T, *, *>,
private val key: K,
val weight: Int,
private val _readerValueLoader: () -> T?,
private val _writerValueLoader: () -> T = { throw IllegalAccessException("No value loader provided") }) : Transactional<T>() {
// A flag to indicate this has now been committed, but hasn't yet been replaced with Committed. This also
// de-duplicates writes of the Committed value to the cache.
@ -363,10 +362,10 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
// What to do if a non-writer needs to see the value and it hasn't yet been committed to the database.
// Can be updated into a no-op once evaluated.
private val readerValueLoader = AtomicReference<() -> T?>(_readerValueLoader)
private val readerValueLoader = AtomicReference(_readerValueLoader)
// What to do if a writer needs to see the value and it hasn't yet been committed to the database.
// Can be updated into a no-op once evaluated.
private val writerValueLoader = AtomicReference<() -> T>(_writerValueLoader)
private val writerValueLoader = AtomicReference(_writerValueLoader)
fun alsoWrite(_value: T) {
// Make the lazy loader the writers see actually just return the value that has been set.
@ -382,11 +381,11 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
// and then stop saying the transaction is writing the key.
tx.onCommit {
strongMap.cache.asMap().computeIfPresent(strongKey) { _, transactional: Transactional<T> ->
if (transactional is Transactional.InFlight<*, T>) {
if (transactional is InFlight<*, T>) {
transactional.committed.set(true)
val value = transactional.peekableValue
if (value != null) {
Transactional.Committed(value)
Committed(value)
} else {
transactional
}
@ -447,7 +446,7 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
}
// Open for tests to override
open class AppendOnlyPersistentMap<K, V, E, out EK>(
open class AppendOnlyPersistentMap<K : Any, V, E, out EK>(
cacheFactory: NamedCacheFactory,
name: String,
toPersistentEntityKey: (K) -> EK,
@ -466,7 +465,7 @@ open class AppendOnlyPersistentMap<K, V, E, out EK>(
}
// Same as above, but with weighted values (e.g. memory footprint sensitive).
class WeightBasedAppendOnlyPersistentMap<K, V, E, out EK>(
class WeightBasedAppendOnlyPersistentMap<K : Any, V, E, out EK>(
cacheFactory: NamedCacheFactory,
name: String,
toPersistentEntityKey: (K) -> EK,
@ -485,7 +484,7 @@ class WeightBasedAppendOnlyPersistentMap<K, V, E, out EK>(
override val cache = NonInvalidatingWeightBasedCache(
cacheFactory = cacheFactory,
name = name,
weigher = Weigher { key, value: Transactional<V> ->
weigher = { key, value: Transactional<V> ->
value.shallowSize + if (value is Transactional.InFlight<*, *>) {
value.weight * 2
} else {

View File

@ -6,21 +6,17 @@ import com.github.benmanes.caffeine.cache.LoadingCache
import com.github.benmanes.caffeine.cache.Weigher
import net.corda.core.internal.NamedCacheFactory
class NonInvalidatingCache<K, V> private constructor(
val cache: LoadingCache<K, V>
) : LoadingCache<K, V> by cache {
constructor(cacheFactory: NamedCacheFactory, name: String, loadFunction: (K) -> V) :
this(buildCache(cacheFactory, name, loadFunction))
class NonInvalidatingCache<K : Any, V : Any> private constructor(val cache: LoadingCache<K, V>) : LoadingCache<K, V> by cache {
constructor(cacheFactory: NamedCacheFactory, name: String, loadFunction: (K) -> V?) : this(buildCache(cacheFactory, name, loadFunction))
private companion object {
private fun <K, V> buildCache(cacheFactory: NamedCacheFactory, name: String, loadFunction: (K) -> V): LoadingCache<K, V> {
private fun <K : Any, V : Any> buildCache(cacheFactory: NamedCacheFactory, name: String, loadFunction: (K) -> V?): LoadingCache<K, V> {
return cacheFactory.buildNamed(name, NonInvalidatingCacheLoader(loadFunction))
}
}
// TODO look into overriding loadAll() if we ever use it
class NonInvalidatingCacheLoader<K, V>(val loadFunction: (K) -> V) : CacheLoader<K, V> {
class NonInvalidatingCacheLoader<K : Any, V : Any>(val loadFunction: (K) -> V?) : CacheLoader<K, V> {
override fun reload(key: K, oldValue: V): V {
throw IllegalStateException("Non invalidating cache refreshed")
}
@ -29,16 +25,17 @@ class NonInvalidatingCache<K, V> private constructor(
}
}
class NonInvalidatingWeightBasedCache<K, V> private constructor(
val cache: LoadingCache<K, V>
) : LoadingCache<K, V> by cache {
constructor (cacheFactory: NamedCacheFactory, name: String, weigher: Weigher<K, V>, loadFunction: (K) -> V) :
class NonInvalidatingWeightBasedCache<K : Any, V : Any> private constructor(val cache: LoadingCache<K, V>) : LoadingCache<K, V> by cache {
constructor(cacheFactory: NamedCacheFactory, name: String, weigher: Weigher<K, V>, loadFunction: (K) -> V?) :
this(buildCache(cacheFactory, name, weigher, loadFunction))
private companion object {
private fun <K, V> buildCache(cacheFactory: NamedCacheFactory, name: String, weigher: Weigher<K, V>, loadFunction: (K) -> V): LoadingCache<K, V> {
private fun <K : Any, V : Any> buildCache(cacheFactory: NamedCacheFactory,
name: String,
weigher: Weigher<K, V>,
loadFunction: (K) -> V?): LoadingCache<K, V> {
val builder = Caffeine.newBuilder().weigher(weigher)
return cacheFactory.buildNamed(builder, name, NonInvalidatingCache.NonInvalidatingCacheLoader(loadFunction))
}
}
}
}

View File

@ -7,17 +7,20 @@ import com.github.benmanes.caffeine.cache.LoadingCache
import com.github.benmanes.caffeine.cache.RemovalListener
import net.corda.core.internal.NamedCacheFactory
class NonInvalidatingUnboundCache<K, V> private constructor(
val cache: LoadingCache<K, V>
) : LoadingCache<K, V> by cache {
constructor(name: String, cacheFactory: NamedCacheFactory, loadFunction: (K) -> V, removalListener: RemovalListener<K, V> = RemovalListener { _, _, _ -> },
class NonInvalidatingUnboundCache<K : Any, V : Any> private constructor(val cache: LoadingCache<K, V>) : LoadingCache<K, V> by cache {
constructor(name: String,
cacheFactory: NamedCacheFactory,
loadFunction: (K) -> V?,
removalListener: RemovalListener<K, V> = RemovalListener { _, _, _ -> },
keysToPreload: () -> Iterable<K> = { emptyList() }) :
this(buildCache(name, cacheFactory, loadFunction, removalListener, keysToPreload))
private companion object {
private fun <K, V> buildCache(name: String, cacheFactory: NamedCacheFactory, loadFunction: (K) -> V, removalListener: RemovalListener<K, V>,
keysToPreload: () -> Iterable<K>): LoadingCache<K, V> {
private fun <K : Any, V : Any> buildCache(name: String,
cacheFactory: NamedCacheFactory,
loadFunction: (K) -> V?,
removalListener: RemovalListener<K, V>,
keysToPreload: () -> Iterable<K>): LoadingCache<K, V> {
val builder = Caffeine.newBuilder().removalListener(removalListener).executor(SameThreadExecutor.getExecutor())
return cacheFactory.buildNamed(builder, name, NonInvalidatingCacheLoader(loadFunction)).apply {
getAll(keysToPreload())
@ -26,11 +29,11 @@ class NonInvalidatingUnboundCache<K, V> private constructor(
}
// TODO look into overriding loadAll() if we ever use it
private class NonInvalidatingCacheLoader<K, V>(val loadFunction: (K) -> V) : CacheLoader<K, V> {
private class NonInvalidatingCacheLoader<K : Any, V : Any>(val loadFunction: (K) -> V?) : CacheLoader<K, V> {
override fun reload(key: K, oldValue: V): V {
throw IllegalStateException("Non invalidating cache refreshed")
}
override fun load(key: K) = loadFunction(key)
}
}
}

View File

@ -10,7 +10,7 @@ import java.util.*
/**
* Implements an unbound caching layer on top of a table accessed via Hibernate mapping.
*/
class PersistentMap<K : Any, V, E, out EK>(
class PersistentMap<K : Any, V : Any, E, out EK>(
name: String,
val toPersistentEntityKey: (K) -> EK,
val fromPersistentEntity: (E) -> Pair<K, V>,
@ -126,7 +126,7 @@ class PersistentMap<K : Any, V, E, out EK>(
return result
}
private class NotReallyMutableEntry<K, V>(key: K, value: V) : AbstractMap.SimpleImmutableEntry<K, V>(key, value), MutableMap.MutableEntry<K, V> {
private class NotReallyMutableEntry<K, V>(key: K, value: V) : SimpleImmutableEntry<K, V>(key, value), MutableMap.MutableEntry<K, V> {
override fun setValue(newValue: V): V {
throw UnsupportedOperationException("Not really mutable. Implement if really required.")
}

View File

@ -820,8 +820,9 @@ class FlowFrameworkTests {
}
// When ported to ENT use the existing API there to properly retry the flow
@Suppress("FunctionNaming") // For some reason this test produces invalid class names if the function name contains spaces
@Test(timeout=300_000)
fun `Hospitalized flow, resets to 'RUNNABLE' and clears exception when retried`() {
fun Hospitalized_flow_resets_to_RUNNABLE_and_clears_exception_when_retried() {
var firstRun = true
var counter = 0
val waitUntilHospitalizedTwice = Semaphore(-1)