Skip to content

Commit

Permalink
Merge pull request #17 from RADAR-base/release-0.3.1
Browse files Browse the repository at this point in the history
Release 0.3.1
  • Loading branch information
blootsvoets authored Oct 1, 2020
2 parents d86294d + 09cc6d8 commit 88fd565
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 22 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repositories {
}
dependencies {
api("org.radarbase:radar-jersey:0.2.4")
api("org.radarbase:radar-jersey:0.3.1")
}
```

Expand Down Expand Up @@ -54,7 +54,8 @@ class MyEnhancerFactory(private val config: MyConfigClass): EnhancerFactory {
MyResourceEnhancer(),
// RADAR OAuth2 enhancement
ConfigLoader.Enhancers.radar(AuthConfig(
managementPortalUrl = "http://...",
managementPortal = MPConfig(
url = "http://..."),
jwtResourceName = "res_MyResource")),
// Use ManagementPortal OAuth implementation
ConfigLoader.Enhancers.managementPortal,
Expand Down Expand Up @@ -83,7 +84,15 @@ class MyEnhancerFactory(private val config: MyConfigClass): EnhancerFactory {
}
}
```
Ensure that a class implementing `org.radarbase.jersey.auth.ProjectService` is added to the binder.
Ensure that a class implementing `org.radarbase.jersey.auth.ProjectService` is added to the binder. This is done automatically if you configure a `MPConfig.clientId` and `MPConfig.clientSecret`. Then the projects will be fetched from ManagementPortal.

The following variables will be fetched from environment variables if set:\
`MANAGEMENT_PORTAL_CLIENT_ID` sets `AuthConfig.managementPortal.clientId`\
`MANAGEMENT_PORTAL_CLIENT_SECRET` sets `AuthConfig.managementPortal.clientSecret`\
`AUTH_KEYSTORE_PASSWORD` sets `AuthConfig.jwtKeystorePassword`\
`DATABASE_URL` sets `DatabaseConfig.url`\
`DATABASE_USER` sets `DatabaseConfig.user`\
`DATABASE_PASSWORD` sets `DatabaseConfig.password`

This factory can then be specified in your main method, by adding it to your `MyConfigClass` definition:
```kotlin
Expand Down
12 changes: 6 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ plugins {

allprojects {
group = 'org.radarbase'
version = '0.3.0'
version = '0.3.1'

ext {
jerseyVersion = "2.31"
jerseyVersion = "2.32"
grizzlyVersion = "2.4.4"
okhttpVersion = "4.8.1"
junitVersion = "5.6.2"
okhttpVersion = "4.9.0"
junitVersion = "5.7.0"
}
}

Expand All @@ -24,7 +24,7 @@ ext {
website = 'http://radar-base.org'

hk2Version = "2.6.1"
managementPortalVersion = "0.5.8"
managementPortalVersion = "0.6.0"
jakartaWsRsVersion = "2.1.6"
jakartaAnnotationVersion = "1.3.5"
jacksonVersion = "2.11.2"
Expand Down Expand Up @@ -105,7 +105,7 @@ test {
}

wrapper {
gradleVersion = "6.6"
gradleVersion = "6.6.1"
}

apply from: "gradle/publishing.gradle"
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
2 changes: 1 addition & 1 deletion radar-jersey-hibernate/src/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# radar-jersey-hibernate

Extension module of radar-jersey to use Hibernate in a Jersey project. Default database configuration is for PostgreSQL, but any JDBC driver compatible with Hibernate can be used. The module is activated by adding `HibernateResourceEnhancer` to your `EnhancerFactory` with a given database configuration. When this is done, `Provider<EntityManager>` can be injected via the `Context` annotation.
Extension module `radar-jersey-hibernate` of radar-jersey to use Hibernate in a Jersey project. Default database configuration is for PostgreSQL, but any JDBC driver compatible with Hibernate can be used. The module is activated by adding `HibernateResourceEnhancer` to your `EnhancerFactory` with a given database configuration. When this is done, `Provider<EntityManager>` can be injected via the `Context` annotation.

To make full use if the module, let any database-using classes extend `HibernateRepository`. Any database operations must be wrapped in a `transact { doSomething() }` or `createTransaction { doSomething() }.use { result -> doSomething result }`. Both closures have EntityManager as `this` object, meaning that `createQuery` and derivatives should be called without referencing an additional `EntityManager`.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.radarbase.jersey.hibernate.config

import org.radarbase.jersey.config.ConfigLoader.copyEnv


data class DatabaseConfig(
/** Classes that can be used in Hibernate queries. */
Expand All @@ -12,7 +14,12 @@ data class DatabaseConfig(
val properties: Map<String, String> = emptyMap(),
val liquibase: LiquibaseConfig = LiquibaseConfig(),
val healthCheckValiditySeconds: Long = 60
)
) {
fun withEnv(): DatabaseConfig = this
.copyEnv("DATABASE_URL") { copy(url = it) }
.copyEnv("DATABASE_USER") { copy(user = it) }
.copyEnv("DATABASE_PASSWORD") { copy(password = it) }
}

data class LiquibaseConfig(
val enable: Boolean = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class HibernateResourceEnhancer(
override val classes: Array<Class<*>> = arrayOf(DatabaseInitialization::class.java)

override fun AbstractBinder.enhance() {
bind(databaseConfig)
bind(databaseConfig.withEnv())
.to(DatabaseConfig::class.java)

bind(DatabaseHealthMetrics::class.java)
Expand Down
24 changes: 17 additions & 7 deletions src/main/kotlin/org/radarbase/jersey/auth/AuthConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
package org.radarbase.jersey.auth

import com.fasterxml.jackson.annotation.JsonIgnore
import org.radarbase.jersey.config.ConfigLoader.copyEnv
import org.radarbase.jersey.config.ConfigLoader.copyOnChange
import java.time.Duration

data class AuthConfig(
Expand All @@ -29,7 +31,11 @@ data class AuthConfig(
val jwtKeystoreAlias: String? = null,
/** Key password for the key alias in the p12 keystore. */
val jwtKeystorePassword: String? = null,
)
) {
fun withEnv(): AuthConfig = this
.copyOnChange(managementPortal, { it.withEnv() }) { copy(managementPortal = it) }
.copyEnv("AUTH_KEYSTORE_PASSWORD") { copy(jwtKeystorePassword = it) }
}

data class MPConfig(
/** URL for the current service to find the ManagementPortal installation. */
Expand All @@ -43,10 +49,14 @@ data class MPConfig(
/** Interval after which the list of subjects in a project should be refreshed (minutes). */
val syncParticipantsIntervalMin: Long = 5,
) {
/** Interval after which the list of projects should be refreshed. */
@JsonIgnore
val syncProjectsInterval: Duration = Duration.ofMinutes(syncProjectsIntervalMin)
/** Interval after which the list of subjects in a project should be refreshed. */
@JsonIgnore
val syncParticipantsInterval: Duration = Duration.ofMinutes(syncParticipantsIntervalMin)
/** Interval after which the list of projects should be refreshed. */
@JsonIgnore
val syncProjectsInterval: Duration = Duration.ofMinutes(syncProjectsIntervalMin)
/** Interval after which the list of subjects in a project should be refreshed. */
@JsonIgnore
val syncParticipantsInterval: Duration = Duration.ofMinutes(syncParticipantsIntervalMin)

fun withEnv(): MPConfig = this
.copyEnv("MANAGEMENT_PORTAL_CLIENT_ID") { copy(clientId = it) }
.copyEnv("MANAGEMENT_PORTAL_CLIENT_SECRET") { copy(clientSecret = it) }
}
9 changes: 9 additions & 0 deletions src/main/kotlin/org/radarbase/jersey/config/ConfigLoader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,13 @@ object ConfigLoader {
val httpException = HttpExceptionResourceEnhancer()
val generalException = GeneralExceptionResourceEnhancer()
}

inline fun <T> T.copyEnv(key: String, doCopy: T.(String?) -> T): T = copyOnChange<T, String?>(null, { System.getenv(key) }, doCopy)

inline fun <T, V> T.copyOnChange(original: V, modification: (V) -> V, doCopy: T.(V) -> T): T {
val newValue = modification(original)
return if (newValue != original) {
doCopy(newValue)
} else this
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import javax.inject.Singleton
*/
class ManagementPortalResourceEnhancer(private val config: AuthConfig) : JerseyResourceEnhancer {
override fun AbstractBinder.enhance() {
val config = config.withEnv()
bindFactory(TokenValidatorFactory::class.java)
.to(TokenValidator::class.java)
.`in`(Singleton::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class RadarJerseyResourceEnhancer(
}

override fun AbstractBinder.enhance() {
bind(config)
bind(config.withEnv())
.to(AuthConfig::class.java)

bind(OkHttpClient().newBuilder()
Expand All @@ -59,7 +59,7 @@ class RadarJerseyResourceEnhancer(
// Bind factories.
bindFactory(AuthFactory::class.java)
.proxy(true)
.proxyForSameScope(false)
.proxyForSameScope(true)
.to(Auth::class.java)
.`in`(RequestScoped::class.java)
}
Expand Down
53 changes: 53 additions & 0 deletions src/test/kotlin/org/radarbase/jersey/auth/AuthConfigTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.radarbase.jersey.auth

import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.hamcrest.Matchers.not
import org.junit.jupiter.api.Test
import java.util.*

internal class AuthConfigTest {
@Test
fun testEnv() {
val config = AuthConfig(jwtResourceName = "res_test")

setEnv(mapOf(
"AUTH_KEYSTORE_PASSWORD" to "test",
"MANAGEMENT_PORTAL_CLIENT_ID" to "clId",
"MANAGEMENT_PORTAL_CLIENT_SECRET" to "clSecret",
))
val newConfig = config.withEnv()
assertThat(newConfig, not(equalTo(config)))
assertThat(newConfig, equalTo(
config.copy(
managementPortal = config.managementPortal.copy(
clientId = "clId",
clientSecret = "clSecret",
),
jwtKeystorePassword = "test",
)))
}

@Suppress("UNCHECKED_CAST")
@Throws(Exception::class)
fun setEnv(newenv: Map<String, String>) {
try {
val processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment")
processEnvironmentClass.putAll(null, "theEnvironment", newenv)
processEnvironmentClass.putAll(null, "theCaseInsensitiveEnvironment", newenv)
} catch (e: NoSuchFieldException) {
Collections::class.java.declaredClasses
.filter { "java.util.Collections\$UnmodifiableMap" == it.name }
.forEach { it.putAll(System.getenv(), "m", newenv) }
}
}

@Suppress("UNCHECKED_CAST")
private fun Class<*>.putAll(obj: Any?, fieldName: String, map: Map<String, String>) {
getDeclaredField(fieldName)
.apply { isAccessible = true }
.let { it.get(obj) as MutableMap<String, String> }
.putAll(map)

}
}

0 comments on commit 88fd565

Please sign in to comment.