Skip to content

Commit

Permalink
Merge pull request #86 from RADAR-base/release-0.5.15
Browse files Browse the repository at this point in the history
Release 0.5.15
  • Loading branch information
blootsvoets authored Nov 7, 2022
2 parents ca3c988 + d93ab0b commit 35c56cb
Show file tree
Hide file tree
Showing 21 changed files with 119 additions and 79 deletions.
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ indent_size = 2

[*.gradle]
indent_size = 4

[*.{kt,kts}]
disabled_rules = no-wildcard-imports
ij_kotlin_allow_trailing_comma_on_call_site = true
ij_kotlin_allow_trailing_comma = true
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1 +1 @@
KAFKA_CONFLUENT_VERSION=7.2.0
KAFKA_CONFLUENT_VERSION=7.3.0
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ name: CI
# Run in master and dev branches and in all pull requests to those branches
on:
push:
branches: [ master, dev ]
branches: [ main, dev ]
pull_request:
branches: [ master, dev ]
branches: [ main, dev ]

env:
DOCKER_IMAGE: radarbase/radar-gateway
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scheduled_snyk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
- cron: '0 2 * * 1'
push:
branches:
- master
- main

jobs:
security:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/snyk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Snyk test
on:
pull_request:
branches:
- master
- main
jobs:
security:
runs-on: ubuntu-latest
Expand Down
31 changes: 19 additions & 12 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,19 @@ plugins {
id("idea")
id("application")
kotlin("jvm")
id("com.avast.gradle.docker-compose") version "0.16.9"
id("com.github.ben-manes.versions") version "0.43.0"
id("com.avast.gradle.docker-compose")
id("com.github.ben-manes.versions")
id("org.jlleitschuh.gradle.ktlint")
}

description = "RADAR Gateway to handle secured data flow to backend."
group = "org.radarbase"
version = "0.5.15"

allprojects {
group = "org.radarbase"
version = "0.5.14"

repositories {
mavenCentral()
maven(url = "https://packages.confluent.io/maven/")
maven(url = "https://oss.sonatype.org/content/repositories/snapshots")
}
repositories {
mavenCentral()
maven(url = "https://packages.confluent.io/maven/")
maven(url = "https://oss.sonatype.org/content/repositories/snapshots")
}

val integrationTestSourceSet = sourceSets.create("integrationTest") {
Expand Down Expand Up @@ -77,9 +75,13 @@ dependencies {
val okhttp3Version: String by project
val radarSchemasVersion: String by project
val mockitoKotlinVersion: String by project
val hamcrestVersion: String by project
testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
testImplementation("org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion")
testImplementation("com.squareup.okhttp3:mockwebserver:$okhttp3Version")
testImplementation("com.squareup.okhttp3:mockwebserver:$okhttp3Version") {
exclude(group = "junit", module = "junit")
}
testImplementation("org.hamcrest:hamcrest:$hamcrestVersion")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion")

testImplementation("org.radarbase:radar-schemas-commons:$radarSchemasVersion")
Expand Down Expand Up @@ -150,6 +152,11 @@ idea {
}
}

ktlint {
val ktlintVersion: String by project
version.set(ktlintVersion)
}

tasks.register("downloadDependencies") {
doFirst {
configurations["compileClasspath"].files
Expand Down
18 changes: 12 additions & 6 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
org.gradle.jvmargs=-Xmx3072m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
kotlin.code.style=official
dockerComposeStopContainers=false
dockerComposeStopContainers=true

kotlinVersion=1.7.20
ktlintVersion=0.45.2
ktlintPluginVersion=11.0.0
dockerComposeVersion=0.16.9
dependencyUpdatesVersion=0.43.0

okhttp3Version=4.10.0
radarJerseyVersion=0.9.0
radarJerseyVersion=0.9.1
radarCommonsVersion=0.15.0
radarSchemasVersion=0.8.0
jacksonVersion=2.13.4.20221013
radarSchemasVersion=0.8.1
jacksonVersion=2.14.0
slf4jVersion=2.0.3
log4j2Version=2.19.0
lzfseVersion=0.1.1
radarAuthVersion=0.8.1
avroVersion=1.11.1
kafkaVersion=7.2.2-ce
confluentVersion=7.2.2
kafkaVersion=7.3.0-ce
confluentVersion=7.3.0

mockitoKotlinVersion=4.0.0
junitVersion=5.9.1
grizzlyVersion=4.0.0
hamcrestVersion=2.2
6 changes: 6 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ rootProject.name = "radar-gateway"

pluginManagement {
val kotlinVersion: String by settings
val ktlintPluginVersion: String by settings
val dockerComposeVersion: String by settings
val dependencyUpdatesVersion: String by settings
plugins {
kotlin("jvm") version kotlinVersion
id("com.avast.gradle.docker-compose") version dockerComposeVersion
id("com.github.ben-manes.versions") version dependencyUpdatesVersion
id("org.jlleitschuh.gradle.ktlint") version ktlintPluginVersion
}
}
2 changes: 1 addition & 1 deletion src/integrationTest/docker/.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
KAFKA_CONFLUENT_VERSION=7.2.0
KAFKA_CONFLUENT_VERSION=7.3.0
RADAR_GATEWAY_TAG=SNAPSHOT
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okio.Buffer
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.CoreMatchers.hasItem
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.MatcherAssert.assertThat
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.runners.model.MultipleFailureException
import org.radarbase.config.ServerConfig
import org.radarbase.data.AvroRecordData
import org.radarbase.gateway.resource.KafkaRootTest.Companion.BASE_URI
Expand All @@ -37,7 +36,7 @@ import java.util.concurrent.atomic.LongAdder
class KafkaTopicsTest {
private fun requestAccessToken(): String {
val clientToken = httpClient.call(Status.OK, "access_token") {
url("${MANAGEMENTPORTAL_URL}/oauth/token")
url("$MANAGEMENTPORTAL_URL/oauth/token")
addHeader("Authorization", Credentials.basic(MP_CLIENT, ""))
post(
FormBody.Builder()
Expand Down Expand Up @@ -65,7 +64,7 @@ class KafkaTopicsTest {
}

return httpClient.call(Status.OK, "access_token") {
url("${MANAGEMENTPORTAL_URL}/oauth/token")
url("$MANAGEMENTPORTAL_URL/oauth/token")
addHeader("Authorization", Credentials.basic(REST_CLIENT, ""))
post(
FormBody.Builder()
Expand All @@ -84,8 +83,10 @@ class KafkaTopicsTest {

val topic = AvroTopic(
"test",
ObservationKey.getClassSchema(), PhoneAcceleration.getClassSchema(),
ObservationKey::class.java, PhoneAcceleration::class.java
ObservationKey.getClassSchema(),
PhoneAcceleration.getClassSchema(),
ObservationKey::class.java,
PhoneAcceleration::class.java
)

val time = System.currentTimeMillis() / 1000.0
Expand Down Expand Up @@ -113,7 +114,6 @@ class KafkaTopicsTest {
results += sendData(BASE_URI, retriever, topic, accessToken, key, value, binary = false, gzip = false)
results.forEach { println(it) }


httpClient.call(Status.OK) {
url("$BASE_URI/topics")
head()
Expand Down Expand Up @@ -229,8 +229,8 @@ class KafkaTopicsTest {
senders.forEach { it.start() }
senders.forEach { it.join() }
senders.mapNotNull { it.exception }
.takeIf { it.isNotEmpty() }
?.let { throw MultipleFailureException(it) }
.reduceOrNull { acc, exception -> acc.apply { addSuppressed(exception) } }
?.let { throw it }

val timeEnd = System.nanoTime()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import org.radarbase.jersey.enhancer.EnhancerFactory
import org.radarbase.jersey.enhancer.Enhancers
import org.radarbase.jersey.enhancer.JerseyResourceEnhancer


/** This binder needs to register all non-Jersey classes, otherwise initialization fails. */
class EcdsaJwtEnhancerFactory(private val config: GatewayConfig) : EnhancerFactory {
override fun createEnhancers(): List<JerseyResourceEnhancer> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import org.radarbase.gateway.io.LzfseEncoder
import org.radarbase.gateway.kafka.*
import org.radarbase.gateway.service.SchedulingService
import org.radarbase.gateway.service.SchedulingServiceFactory
import org.radarbase.jersey.auth.filter.AuthenticationFilter
import org.radarbase.jersey.enhancer.JerseyResourceEnhancer
import org.radarbase.jersey.filter.Filters
import org.radarbase.jersey.service.HealthService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import org.radarbase.gateway.config.GatewayConfig
import org.radarbase.jersey.auth.AuthConfig
import org.radarbase.jersey.auth.MPConfig
import org.radarbase.jersey.enhancer.EnhancerFactory
import org.radarbase.jersey.enhancer.JerseyResourceEnhancer
import org.radarbase.jersey.enhancer.Enhancers
import org.radarbase.jersey.enhancer.JerseyResourceEnhancer

/** This binder needs to register all non-Jersey classes, otherwise initialization fails. */
class ManagementPortalEnhancerFactory(private val config: GatewayConfig) : EnhancerFactory {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class SchemaRetrieverFactory(

@Suppress("DEPRECATION")
val basicCredentials =
(config.kafka.serialization[SCHEMA_REGISTRY_USER_INFO_CONFIG].takeIf { it is String && it.isNotEmpty() }
?: config.kafka.serialization[USER_INFO_CONFIG]).takeIf { it is String && it.isNotEmpty() } as String?
config.kafka.serialization[SCHEMA_REGISTRY_USER_INFO_CONFIG].asNonEmptyString()
?: config.kafka.serialization[USER_INFO_CONFIG].asNonEmptyString()

val headers = if (basicCredentials != null && basicCredentials.contains(':')) {
val (username, password) = basicCredentials.split(':', limit = 2)
Expand All @@ -43,4 +43,10 @@ class SchemaRetrieverFactory(
300,
)
}

companion object {
private fun Any?.asNonEmptyString(): String? =
if (this is String && this.isNotEmpty()) this
else null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ class AvroRecordProcessor(
return keyMapping.jsonToAvro(key, context)
}


/** Parse single record key. */
@Throws(IOException::class)
fun processValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import org.apache.avro.Schema
import org.apache.avro.generic.GenericRecord
import org.apache.avro.generic.GenericRecordBuilder
import org.apache.avro.io.BinaryDecoder
import org.radarbase.auth.authorization.Permission
import org.radarbase.data.RecordData
import org.radarbase.jersey.auth.Auth
import org.radarbase.producer.rest.ParsedSchemaMetadata
Expand Down
53 changes: 29 additions & 24 deletions src/main/kotlin/org/radarbase/gateway/io/JsonNodeExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,24 @@ import org.radarbase.jersey.exception.HttpInvalidContentException
import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets

val JsonNode?.isMissing: Boolean
get() = this == null || this.isNull

fun JsonNode.toAvro(to: Schema, context: AvroParsingContext, defaultVal: JsonNode? = null): Any? {
return if (isNull) {
when {
to.type == Schema.Type.NULL -> null
to.type == Schema.Type.UNION -> toAvroUnion(to, context, defaultVal)
defaultVal.isMissing -> throw invalidContent("No value given to field without default", context)
else -> return defaultVal!!.toAvro(to,
AvroParsingContext(to.type, "default value", context))
defaultVal == null || defaultVal.isNull -> throw invalidContent("No value given to field without default", context)
else -> defaultVal.toAvro(
to,
AvroParsingContext(to.type, "default value", context)
)
}
} else {
when (to.type!!) {
Schema.Type.RECORD -> toAvroObject(to, context)
Schema.Type.LONG, Schema.Type.FLOAT, Schema.Type.DOUBLE, Schema.Type.INT -> toAvroNumber(
to.type,
context)
context,
)
Schema.Type.BOOLEAN -> toAvroBoolean(context)
Schema.Type.ARRAY -> toAvroArray(to, context)
Schema.Type.NULL -> null
Expand All @@ -52,9 +52,11 @@ fun JsonNode.toAvroObject(
val builder = GenericRecordBuilder(schema)
for (field in schema.fields) {
get(field.name())?.let { node ->
val fieldContext = AvroParsingContext(Schema.Type.RECORD,
"${schema.name}.${field.name()}",
context)
val fieldContext = AvroParsingContext(
type = Schema.Type.RECORD,
name = "${schema.name}.${field.name()}",
parent = context,
)
builder[field] = node.toAvro(field.schema(), fieldContext, field.jsonDefaultValue)
}
}
Expand Down Expand Up @@ -114,7 +116,6 @@ fun invalidContent(message: String, context: AvroParsingContext): HttpInvalidCon
throw HttpInvalidContentException("$message (context $context)")
}


fun JsonNode.toAvroString(context: AvroParsingContext): String {
return if (isTextual || isNumber || isBoolean) asText()
else throw invalidContent("Cannot map non-simple types to string: $this", context)
Expand All @@ -128,7 +129,7 @@ fun JsonNode?.toAvroUnion(
return when {
this == null || this.isNull -> {
when {
to.types.any { it.type == Schema.Type.NULL} -> null
to.types.any { it.type == Schema.Type.NULL } -> null
defaultVal != null -> defaultVal.toAvro(to.types.first(), context)
else -> throw invalidContent("Cannot map null value to non-null union", context)
}
Expand All @@ -147,10 +148,10 @@ fun JsonNode?.toAvroUnion(
}
isNumber -> {
val type = to.types.firstOrNull { unionType ->
unionType.type == Schema.Type.LONG
|| unionType.type == Schema.Type.INT
|| unionType.type == Schema.Type.FLOAT
|| unionType.type == Schema.Type.DOUBLE
unionType.type == Schema.Type.LONG ||
unionType.type == Schema.Type.INT ||
unionType.type == Schema.Type.FLOAT ||
unionType.type == Schema.Type.DOUBLE
} ?: throw invalidContent("Cannot map number to non-number union", context)
toAvroNumber(
type.type,
Expand All @@ -159,10 +160,10 @@ fun JsonNode?.toAvroUnion(
}
isTextual -> {
val type = to.types.firstOrNull { unionType ->
unionType.type == Schema.Type.STRING
|| unionType.type == Schema.Type.FIXED
|| unionType.type == Schema.Type.BYTES
|| unionType.type == Schema.Type.ENUM
unionType.type == Schema.Type.STRING ||
unionType.type == Schema.Type.FIXED ||
unionType.type == Schema.Type.BYTES ||
unionType.type == Schema.Type.ENUM
} ?: throw invalidContent("Cannot map text to non-textual union", context)
toAvro(
type,
Expand All @@ -189,8 +190,8 @@ fun JsonNode?.toAvroUnion(
}
isObject -> {
val type = to.types.firstOrNull { unionType ->
unionType.type == Schema.Type.MAP
|| unionType.type == Schema.Type.RECORD
unionType.type == Schema.Type.MAP ||
unionType.type == Schema.Type.RECORD
} ?: throw invalidContent("Cannot map object to non-object union", context)
return toAvro(
type,
Expand Down Expand Up @@ -231,8 +232,12 @@ fun JsonNode.toAvroMap(
if (this !is ObjectNode) throw invalidContent("Can only convert objects to map", context)

return fieldNames().asSequence()
.associateWith { key -> get(key).toAvro(schema,
AvroParsingContext(Schema.Type.MAP, key, context)) }
.associateWith { key ->
get(key).toAvro(
schema,
AvroParsingContext(Schema.Type.MAP, key, context)
)
}
}

fun JsonNode.toAvroBytes(context: AvroParsingContext): ByteBuffer {
Expand Down
Loading

0 comments on commit 35c56cb

Please sign in to comment.