Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.11.1 #81

Merged
merged 13 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/snyk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ jobs:
--all-sub-projects
--configuration-matching='^runtimeClasspath$'
--org=radar-base
--policy-path=$PWD/.snyk
--policy-path=.snyk
--severity-threshold=high
1 change: 1 addition & 0 deletions .snyk
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ ignore:
expires: 2023-14-30T10:58:31.820Z
created: 2022-10-31T10:58:31.828Z
patch: {}
severityThreshold: high
10 changes: 5 additions & 5 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm") version "1.9.10"
kotlin("jvm") version "1.9.22"
}

repositories {
Expand All @@ -11,11 +11,11 @@ repositories {

tasks.withType<KotlinCompile> {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
jvmTarget.set(JvmTarget.JVM_17)
}
}

tasks.withType<JavaCompile> {
sourceCompatibility = "11"
targetCompatibility = "11"
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
32 changes: 16 additions & 16 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
@Suppress("ConstPropertyName")
object Versions {
const val project = "0.11.0"
const val kotlin = "1.9.10"
const val project = "0.11.1"
const val kotlin = "1.9.22"

const val java: Int = 17
const val jersey = "3.1.3"
const val grizzly = "4.0.0"
const val okhttp = "4.11.0"
const val junit = "5.10.0"
const val jersey = "3.1.5"
const val grizzly = "4.0.2"
const val okhttp = "4.12.0"
const val junit = "5.10.1"
const val hamcrest = "2.2"
const val mockitoKotlin = "5.1.0"
const val mockitoKotlin = "5.2.1"

const val hk2 = "3.0.4"
const val hk2 = "3.0.5"
const val managementPortal = "2.1.0"
const val radarCommons = "1.1.1"
const val radarCommons = "1.1.2"
const val javaJwt = "4.4.0"
const val jakartaWsRs = "3.1.0"
const val jakartaAnnotation = "2.1.1"
const val jackson = "2.15.3"
const val jackson = "2.16.1"
const val slf4j = "2.0.9"
const val log4j2 = "2.20.0"
const val jakartaXmlBind = "4.0.1"
const val jakartaJaxbCore = "4.0.3"
const val jakartaJaxbRuntime = "4.0.3"
const val jakartaJaxbCore = "4.0.4"
const val jakartaJaxbRuntime = "4.0.4"
const val jakartaValidation = "3.0.2"
const val hibernateValidator = "8.0.1.Final"
const val glassfishJakartaEl = "4.0.2"
const val jakartaActivation = "2.1.2"
const val swagger = "2.2.17"
const val swagger = "2.2.20"
const val mustache = "0.9.11"

const val hibernate = "6.3.1.Final"
const val liquibase = "4.24.0"
const val postgres = "42.6.0"
const val hibernate = "6.4.2.Final"
const val liquibase = "4.25.1"
const val postgres = "42.7.2"
const val h2 = "2.2.224"

const val wrapper = "8.4"
Expand Down
5 changes: 5 additions & 0 deletions radar-jersey-hibernate/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@ dependencies {
testImplementation("org.hamcrest:hamcrest:${Versions.hamcrest}")
testImplementation("com.squareup.okhttp3:okhttp:${Versions.okhttp}")
}

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,39 @@ import jakarta.persistence.EntityManager
import jakarta.persistence.EntityManagerFactory
import jakarta.ws.rs.core.Context
import jakarta.ws.rs.ext.Provider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import liquibase.command.CommandScope
import liquibase.command.core.UpdateCommandStep
import liquibase.command.core.helpers.DbUrlConnectionCommandStep.DATABASE_ARG
import liquibase.database.DatabaseFactory
import liquibase.database.jvm.JdbcConnection
import org.glassfish.jersey.server.monitoring.ApplicationEvent
import org.glassfish.jersey.server.monitoring.ApplicationEventListener
import org.glassfish.jersey.server.monitoring.RequestEvent
import org.glassfish.jersey.server.monitoring.RequestEventListener
import org.hibernate.HibernateException
import org.hibernate.Session
import org.radarbase.jersey.hibernate.RadarEntityManagerFactoryFactory.Companion.useEntityManager
import org.radarbase.jersey.coroutines.AsyncApplicationEventListener
import org.radarbase.jersey.hibernate.config.DatabaseConfig
import org.radarbase.jersey.service.AsyncCoroutineService
import org.slf4j.LoggerFactory
import java.sql.Connection

@Provider
class DatabaseInitialization(
@Context private val entityManagerFactory: jakarta.inject.Provider<EntityManagerFactory>,
@Context private val dbConfig: DatabaseConfig,
) : ApplicationEventListener {
@Context private val asyncCoroutineService: AsyncCoroutineService,
) : AsyncApplicationEventListener(asyncCoroutineService) {

override fun onEvent(event: ApplicationEvent) {
override suspend fun process(event: ApplicationEvent) {
if (event.type != ApplicationEvent.Type.INITIALIZATION_APP_FINISHED) return
if (!dbConfig.liquibase.enable) return

try {
entityManagerFactory.get().useEntityManager { em ->
em.useConnection { connection ->
if (dbConfig.liquibase.enable) {
withContext(Dispatchers.IO) {
entityManagerFactory.get().useEntityManager { em ->
em.useConnection { connection ->
initializeLiquibase(connection)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package org.radarbase.jersey.hibernate
import jakarta.persistence.EntityManager
import jakarta.persistence.EntityManagerFactory
import jakarta.ws.rs.core.Context
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.glassfish.jersey.internal.inject.DisposableSupplier
import org.slf4j.LoggerFactory

Expand All @@ -26,3 +28,14 @@ class RadarEntityManagerFactory(
private val logger = LoggerFactory.getLogger(RadarEntityManagerFactory::class.java)
}
}

/**
* Run code with entity manager. Can be used for opening a repository outside of a request.
*/
@Suppress("unused")
suspend fun <T> RadarEntityManagerFactory.useEntityManager(block: suspend (EntityManager) -> T): T =
withContext(Dispatchers.IO) {
get()
}.use { entityManager ->
block(entityManager)
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,16 @@ class RadarEntityManagerFactoryFactory(

companion object {
private val logger = LoggerFactory.getLogger(RadarEntityManagerFactoryFactory::class.java)
}
}

/**
* Use an EntityManager for the duration of [method]. No reference of the passed
* [EntityManager] should be returned, either directly or indirectly.
*/
@Suppress("unused")
inline fun <T> EntityManagerFactory.useEntityManager(method: (EntityManager) -> T): T {
val entityManager = createEntityManager()
return try {
method(entityManager)
} finally {
entityManager.close()
}
}
/**
* Use an EntityManager for the duration of [method]. No reference of the passed
* [EntityManager] should be returned, either directly or indirectly.
*/
@Suppress("unused")
inline fun <T> EntityManagerFactory.useEntityManager(method: (EntityManager) -> T): T {
return createEntityManager().use { entityManager ->
method(entityManager)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import org.radarbase.jersey.enhancer.JerseyResourceEnhancer
import org.radarbase.jersey.hibernate.config.DatabaseConfig
import org.radarbase.jersey.hibernate.config.HibernateResourceEnhancer

class MockResourceEnhancerFactory(private val config: AuthConfig, private val databaseConfig: DatabaseConfig) :
class MockResourceEnhancerFactory(
private val config: AuthConfig,
private val databaseConfig: DatabaseConfig,
) :
EnhancerFactory {
override fun createEnhancers(): List<JerseyResourceEnhancer> = listOf(
MockResourceEnhancer(),
Expand Down
5 changes: 5 additions & 0 deletions radar-jersey/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ dependencies {
testImplementation("org.mockito.kotlin:mockito-kotlin:${Versions.mockitoKotlin}")
}

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

tasks.processResources {
val properties = mapOf("version" to project.version)
inputs.properties(properties)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.radarbase.jersey.coroutines

import org.glassfish.jersey.server.monitoring.ApplicationEvent
import org.glassfish.jersey.server.monitoring.ApplicationEventListener
import org.glassfish.jersey.server.monitoring.RequestEvent
import org.glassfish.jersey.server.monitoring.RequestEventListener
import org.radarbase.jersey.service.AsyncCoroutineService

/** Listen for application events. */
abstract class AsyncApplicationEventListener(
private val asyncService: AsyncCoroutineService,
) : ApplicationEventListener {
override fun onEvent(event: ApplicationEvent?) {
event ?: return
asyncService.runBlocking {
process(event)
}
}

/**
* Process incoming events. Inside processEvent a request scope is already present
* so repositories can be accessed.
*/
protected abstract suspend fun process(event: ApplicationEvent)

override fun onRequest(requestEvent: RequestEvent?): RequestEventListener? = null
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.glassfish.jersey.process.internal.RequestContext
import org.glassfish.jersey.process.internal.RequestScope
import org.radarbase.jersey.exception.HttpServerUnavailableException
import org.slf4j.LoggerFactory
Expand All @@ -14,28 +15,16 @@ import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

class CoroutineRequestWrapper(
private val timeout: Duration? = 30.seconds,
requestScope: RequestScope? = null,
location: String? = null,
private val requestContext: RequestContext?,
config: CoroutineRequestConfig,
) {
private val job = Job()
private val timeout = config.timeout

val coroutineContext: CoroutineContext

private val requestContext = try {
if (requestScope != null) {
requestScope.suspendCurrent()
?: requestScope.createContext()
} else {
null
}
} catch (ex: Throwable) {
logger.debug("Cannot create request scope: {}", ex.toString())
null
}

init {
var context = job + contextName(location) + Dispatchers.Default
var context = job + contextName(config.location) + Dispatchers.Default
if (requestContext != null) {
context += CoroutineRequestContext(requestContext)
}
Expand All @@ -60,11 +49,43 @@ class CoroutineRequestWrapper(
}

companion object {
private val logger = LoggerFactory.getLogger(CoroutineRequestWrapper::class.java)

@Suppress("DEPRECATION", "KotlinRedundantDiagnosticSuppress")
private fun contextName(location: String?) = CoroutineName(
"Request coroutine ${location ?: ""}#${Thread.currentThread().id}",
)
}
}

data class CoroutineRequestConfig(
var timeout: Duration? = 30.seconds,
var requestScope: RequestScope? = null,
var location: String? = null,
)

fun CoroutineRequestWrapper(requestScope: RequestScope? = null, block: CoroutineRequestConfig.(hasExistingScope: Boolean) -> Unit): CoroutineRequestWrapper {
var newlyCreated = false
val requestContext = try {
if (requestScope != null) {
requestScope.suspendCurrent() ?: run {
newlyCreated = true
requestScope.createContext()
}
} else {
null
}
} catch (ex: Throwable) {
logger.debug("Cannot create request scope: {}", ex.toString())
null
}
val config = CoroutineRequestConfig().apply {
if (requestScope != null && requestContext != null) {
requestScope.runInScope(requestContext) { block(!newlyCreated) }
} else {
block(!newlyCreated)
}
}
return CoroutineRequestWrapper(requestContext, config)
}

private val logger = LoggerFactory.getLogger(CoroutineRequestWrapper::class.java)
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

interface AsyncCoroutineService {
/**
* Run a block with the async coroutine service contexts. If no request scope was created yet,
* this will create one within the coroutine. It can be accessed via [runInRequestScope].
*/
suspend fun <T> withContext(name: String = "AsyncCoroutineService.withContext", block: suspend () -> T): T

/**
* Run an AsyncResponse as a coroutine. The result of [block] will be used as the response. If
Expand Down
Loading
Loading