Skip to content

Commit

Permalink
Migrates engine to HAPI 6.8 while forcing Workflow to stay on 6.0 (go…
Browse files Browse the repository at this point in the history
…ogle#2245)

* Migrates engine to HAPI 6.8 while forcing Workflow to stay on 6.0

* comment
  • Loading branch information
vitorpamplona authored and Santosh Pingle committed Oct 18, 2023
1 parent f77d3a3 commit 7a87ccc
Show file tree
Hide file tree
Showing 23 changed files with 279 additions and 54 deletions.
2 changes: 1 addition & 1 deletion buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ dependencies {

implementation("com.spotify.ruler:ruler-gradle-plugin:1.2.1")

implementation("ca.uhn.hapi.fhir:hapi-fhir-structures-r4:6.0.1")
implementation("ca.uhn.hapi.fhir:hapi-fhir-structures-r4:6.8.0")
implementation("com.squareup:kotlinpoet:1.12.0")
}
36 changes: 22 additions & 14 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ object Dependencies {
// Version 3.0 uses java.lang.System.Logger, which is not available on Android
// Replace for Guava when this PR gets merged: https://github.com/hapifhir/hapi-fhir/pull/3977
const val caffeine = "com.github.ben-manes.caffeine:caffeine:${Versions.caffeine}"
const val guavaCaching = "ca.uhn.hapi.fhir:hapi-fhir-caching-guava:${Versions.hapiFhir}"
}

object Jackson {
Expand All @@ -99,7 +100,7 @@ object Dependencies {

const val annotations = "$coreGroup:jackson-annotations:${Versions.jackson}"
const val bom = "$mainGroup:jackson-bom:${Versions.jackson}"
const val core = "$coreGroup:jackson-core:${Versions.jackson}"
const val core = "$coreGroup:jackson-core:${Versions.jacksonCore}"
const val databind = "$coreGroup:jackson-databind:${Versions.jackson}"
const val dataformatXml = "$dataformatGroup:jackson-dataformat-xml:${Versions.jackson}"
const val jaxbAnnotations = "$moduleGroup:jackson-module-jaxb-annotations:${Versions.jackson}"
Expand Down Expand Up @@ -243,30 +244,28 @@ object Dependencies {
const val stdlib = "1.8.20"
}

const val androidFhirCommon = "0.1.0-alpha04"
const val androidFhirCommon = "0.1.0-alpha05"
const val androidFhirEngine = "0.1.0-beta03"
const val androidFhirKnowledge = "0.1.0-alpha01"
const val apacheCommonsCompress = "1.21"
const val desugarJdkLibs = "2.0.3"
const val caffeine = "2.9.1"
const val fhirUcum = "1.0.3"
const val gson = "2.9.1"
const val guava = "28.2-android"
const val guava = "32.1.2-android"

// Hapi FHIR and HL7 Core Components are interlinked.
// Newer versions of HapiFhir don't work on Android due to the use of Caffeine 3+
// Wait for this to release (6.3): https://github.com/hapifhir/hapi-fhir/pull/4196
const val hapiFhir = "6.0.1"

// Newer versions don't work on Android due to Apache Commons Codec:
// Wait for this fix: https://github.com/hapifhir/org.hl7.fhir.core/issues/1046
const val hapiFhirCore = "5.6.36"
const val hapiFhir = "6.8.0"
const val hapiFhirCore = "6.0.22"

const val http = "4.11.0"

// Maximum version that supports Android API Level 24:
// Maximum Jackson libraries (excluding core) version that supports Android API Level 24:
// https://github.com/FasterXML/jackson-databind/issues/3658
const val jackson = "2.13.5"

// Maximum Jackson Core library version that supports Android API Level 24:
const val jacksonCore = "2.15.2"

const val jsonToolsPatch = "1.13"
const val jsonAssert = "1.5.1"
const val material = "1.9.0"
Expand Down Expand Up @@ -312,13 +311,22 @@ object Dependencies {
exclude(group = "org.apache.httpcomponents")
}

fun Configuration.forceGuava() {
// Removes caffeine
exclude(module = "hapi-fhir-caching-caffeine")
exclude(group = "com.github.ben-manes.caffeine", module = "caffeine")

resolutionStrategy {
force(guava)
force(HapiFhir.guavaCaching)
}
}

fun Configuration.forceHapiVersion() {
// Removes newer versions of caffeine and manually imports 2.9
// Removes newer versions of hapi and keeps on 6.0.1
// (newer versions don't work on Android)
resolutionStrategy {
force(HapiFhir.caffeine)

force(HapiFhir.fhirBase)
force(HapiFhir.fhirClient)
force(HapiFhir.fhirCoreConvertors)
Expand Down
9 changes: 4 additions & 5 deletions buildSrc/src/main/kotlin/FirebaseTestLabConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ fun Project.configureFirebaseTestLabForLibraries() {
"clearPackageData" to "true",
),
)
flakyTestAttempts.set(3)
devices.set(
listOf(
mapOf(
Expand All @@ -43,7 +42,7 @@ fun Project.configureFirebaseTestLabForLibraries() {
"locale" to "en_US",
),
mapOf(
"model" to "panther",
"model" to "MediumPhone.arm",
"version" to "${project.extensions.getByType(LibraryExtension::class.java).compileSdk}",
"locale" to "en_US",
),
Expand All @@ -64,8 +63,6 @@ fun Project.configureFirebaseTestLabForMicroBenchmark() {
"clearPackageData" to "true",
),
)
// some of the benchmark tests get timed-out in the default 15m
testTimeout.set("45m")
devices.set(
listOf(
mapOf(
Expand All @@ -86,7 +83,9 @@ private fun FlankGradleExtension.commonConfigurationForFirebaseTestLab(project:
},
)
useOrchestrator.set(true)
maxTestShards.set(20)
flakyTestAttempts.set(1)
maxTestShards.set(10)
testTimeout.set("45m")
directoriesToPull.set(listOf("/sdcard/Download"))
resultsBucket.set("android-fhir-build-artifacts")
resultsDir.set(
Expand Down
4 changes: 4 additions & 0 deletions buildSrc/src/main/kotlin/LicenseeConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ fun Project.configureLicensee() {
ignoreDependencies("org.jacoco", "org.jacoco.agent") {
because("JaCoCo is used in tests only, so it is not distributed with our library")
}
allowDependency("org.javassist", "javassist", "3.29.0-GA") {
because("Multi-licensed under Apache. https://github.com/jboss-javassist/javassist")
}
// Remove once Evaluator 3 migration is over
allowDependency("org.javassist", "javassist", "3.20.0-GA") {
because("Multi-licensed under Apache. https://github.com/jboss-javassist/javassist")
}
Expand Down
4 changes: 4 additions & 0 deletions catalog/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Dependencies.forceGuava

plugins {
id(Plugins.BuildPlugins.application)
id(Plugins.BuildPlugins.kotlinAndroid)
Expand Down Expand Up @@ -40,6 +42,8 @@ android {
kotlin { jvmToolchain(11) }
}

configurations { all { forceGuava() } }

dependencies {
androidTestImplementation(Dependencies.AndroidxTest.extJunit)
androidTestImplementation(Dependencies.Espresso.espressoCore)
Expand Down
9 changes: 8 additions & 1 deletion contrib/barcode/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Dependencies.forceGuava

plugins {
id(Plugins.BuildPlugins.androidLib)
id(Plugins.BuildPlugins.kotlinAndroid)
Expand Down Expand Up @@ -44,7 +46,12 @@ android {
kotlin { jvmToolchain(11) }
}

configurations { all { exclude(module = "xpp3") } }
configurations {
all {
exclude(module = "xpp3")
forceGuava()
}
}

dependencies {
androidTestImplementation(Dependencies.AndroidxTest.core)
Expand Down
15 changes: 13 additions & 2 deletions datacapture/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import Dependencies.forceGuava
import Dependencies.forceHapiVersion
import Dependencies.forceJacksonVersion
import java.net.URL

plugins {
Expand Down Expand Up @@ -52,7 +55,15 @@ android {

afterEvaluate { configureFirebaseTestLabForLibraries() }

configurations { all { exclude(module = "xpp3") } }
configurations {
all {
exclude(module = "xpp3")
exclude(group = "net.sf.saxon", module = "Saxon-HE")
forceGuava()
forceHapiVersion()
forceJacksonVersion()
}
}

dependencies {
androidTestImplementation(Dependencies.AndroidxTest.core)
Expand All @@ -77,10 +88,10 @@ dependencies {
implementation(Dependencies.Androidx.coreKtx)
implementation(Dependencies.Androidx.fragmentKtx)
implementation(Dependencies.Glide.glide)
implementation(Dependencies.HapiFhir.guavaCaching)
implementation(Dependencies.HapiFhir.validation) {
exclude(module = "commons-logging")
exclude(module = "httpclient")
exclude(group = "net.sf.saxon", module = "Saxon-HE")
}
implementation(Dependencies.Kotlin.kotlinCoroutinesCore)
implementation(Dependencies.Kotlin.stdlib)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ import org.hl7.fhir.r4.utils.FHIRPathEngine
* Resolves constants defined in the fhir path expressions beyond those defined in the specification
*/
internal object FHIRPathEngineHostServices : FHIRPathEngine.IEvaluationContext {
override fun resolveConstant(appContext: Any?, name: String?, beforeContext: Boolean): Base? =
(appContext as? Map<*, *>)?.get(name) as? Base
override fun resolveConstant(
appContext: Any?,
name: String?,
beforeContext: Boolean,
): List<Base>? =
((appContext as? Map<*, *>)?.get(name) as? Base)?.let { listOf(it) } ?: emptyList()

override fun resolveConstantType(appContext: Any?, name: String?): TypeDetails {
throw UnsupportedOperationException()
Expand Down Expand Up @@ -59,15 +63,15 @@ internal object FHIRPathEngineHostServices : FHIRPathEngine.IEvaluationContext {
throw UnsupportedOperationException()
}

override fun resolveReference(appContext: Any?, url: String?): Base {
override fun resolveReference(appContext: Any?, url: String?, refContext: Base?): Base? {
throw UnsupportedOperationException()
}

override fun conformsToProfile(appContext: Any?, item: Base?, url: String?): Boolean {
throw UnsupportedOperationException()
}

override fun resolveValueSet(appContext: Any?, url: String?): ValueSet {
override fun resolveValueSet(appContext: Any?, url: String?): ValueSet? {
throw UnsupportedOperationException()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -775,13 +775,21 @@ private fun Base.asExpectedReferenceType(): Type {
this@asExpectedReferenceType as Resource
Reference().apply {
reference =
"${this@asExpectedReferenceType.resourceType}/${this@asExpectedReferenceType.logicalId}"
if (this@asExpectedReferenceType.resourceType != null) {
"${this@asExpectedReferenceType.resourceType}/${this@asExpectedReferenceType.logicalId}"
} else {
this@asExpectedReferenceType.logicalId
}
}
}
this is IdType ->
Reference().apply {
reference =
"${this@asExpectedReferenceType.resourceType}/${this@asExpectedReferenceType.idPart}"
if (this@asExpectedReferenceType.resourceType != null) {
"${this@asExpectedReferenceType.resourceType}/${this@asExpectedReferenceType.idPart}"
} else {
this@asExpectedReferenceType.idPart
}
}
else -> throw FHIRException("Expression supplied does not evaluate to IdType.")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4400,7 +4400,7 @@ class QuestionnaireViewModelTest {
Extension(
"http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerExpression",
Expression().apply {
this.expression = "Observation?subject={{%patient.id}}"
this.expression = "Observation?subject=Patient/{{%patient.id}}"
this.language = Expression.ExpressionLanguage.APPLICATION_XFHIRQUERY.toCode()
},
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,28 @@ class FHIRPathEngineHostServicesTest {
fun testFHIRPathHostServices_resolveConstantKeyNotPresent_returnsNull() {
val answer = FHIRPathEngineHostServices.resolveConstant(mapOf("A" to IntegerType(1)), "B", true)

assertThat(answer).isNull()
assertThat(answer).isEmpty()
}

@Test
fun testFHIRPathHostServices_resolveConstantKeyAndValuePresent_returnsNotNull() {
val answer = FHIRPathEngineHostServices.resolveConstant(mapOf("A" to IntegerType(1)), "A", true)

assertThat((answer as Type).asStringValue()).isEqualTo("1")
assertThat((answer?.first() as Type).asStringValue()).isEqualTo("1")
}

@Test
fun testFHIRPathHostServices_resolveConstantKeyPresentAndValueNotPresent_returnsNull() {
val answer = FHIRPathEngineHostServices.resolveConstant(mapOf("A" to null), "A", true)

assertThat(answer).isNull()
assertThat(answer).isEmpty()
}

@Test
fun testFHIRPathHostServices_resolveConstantNullAppContext_returnsNull() {
val answer = FHIRPathEngineHostServices.resolveConstant(null, "A", true)

assertThat(answer).isNull()
assertThat(answer).isEmpty()
}

@Test
Expand Down Expand Up @@ -97,7 +97,7 @@ class FHIRPathEngineHostServicesTest {
@Test
fun testFHIRPathHostServices_resolveReference_throwsUnsupportedOperationException() {
assertThrows(UnsupportedOperationException::class.java) {
FHIRPathEngineHostServices.resolveReference(mapOf<Any, Any>(), "")
FHIRPathEngineHostServices.resolveReference(mapOf<Any, Any>(), "", null)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1564,7 +1564,7 @@ class ResourceMapperTest {
val questionnaireResponse = ResourceMapper.populate(questionnaire, patient)

assertThat((questionnaireResponse.item[0].answer[0].value as Reference).reference)
.isEqualTo(patient.id)
.isEqualTo(patient.idPart)
}

@Test
Expand Down
4 changes: 4 additions & 0 deletions demo/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Dependencies.forceGuava

plugins {
id(Plugins.BuildPlugins.application)
id(Plugins.BuildPlugins.kotlinAndroid)
Expand Down Expand Up @@ -38,6 +40,8 @@ android {
kotlin { jvmToolchain(11) }
}

configurations { all { forceGuava() } }

dependencies {
androidTestImplementation(Dependencies.AndroidxTest.extJunit)
androidTestImplementation(Dependencies.Espresso.espressoCore)
Expand Down
2 changes: 2 additions & 0 deletions engine/benchmark/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Dependencies.forceGuava
import Dependencies.forceHapiVersion
import Dependencies.forceJacksonVersion
import Dependencies.removeIncompatibleDependencies
Expand Down Expand Up @@ -50,6 +51,7 @@ afterEvaluate { configureFirebaseTestLabForMicroBenchmark() }
configurations {
all {
removeIncompatibleDependencies()
forceGuava()
forceHapiVersion()
forceJacksonVersion()
}
Expand Down
18 changes: 18 additions & 0 deletions engine/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import Dependencies.forceGuava
import Dependencies.forceHapiVersion
import Dependencies.forceJacksonVersion
import codegen.GenerateSearchParamsTask
import java.net.URL

Expand Down Expand Up @@ -84,6 +87,10 @@ configurations {
exclude(module = "jakarta.activation-api")
exclude(module = "javax.activation")
exclude(module = "jakarta.xml.bind-api")

forceGuava()
forceHapiVersion()
forceJacksonVersion()
}
}

Expand All @@ -98,6 +105,17 @@ dependencies {

api(Dependencies.HapiFhir.structuresR4) { exclude(module = "junit") }

// We have removed the dependency on Caffeine from HAPI due to conflicts with android
// Guave Caching must be individually loaded instead.
implementation(Dependencies.HapiFhir.guavaCaching)

// Validation to load system types into FhirPath's Context
// The loading happens via a ResourceStream in XML and thus
// XML parsers are also necessary.
implementation(Dependencies.HapiFhir.validationR4)
implementation(Dependencies.woodstox)
implementation(Dependencies.xerces)

coreLibraryDesugaring(Dependencies.desugarJdkLibs)

implementation(Dependencies.Androidx.datastorePref)
Expand Down
Loading

0 comments on commit 7a87ccc

Please sign in to comment.