From 02816022f301b64f160d1a722f3fbe165ad42db0 Mon Sep 17 00:00:00 2001 From: Stephen Nesman <94193373+snesm@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:54:26 -0400 Subject: [PATCH] pin ca.uhn.hapi.fhir:org.hl7.fhir.utilities:6.3.24 and ca.uhn.hapi.fhir:org.hl7.fhir.r4:6.3.24 (#15863) * Remediate Snyk finding * Code updates for updated FHIR library --------- Co-authored-by: Michael Kalish --- prime-router/build.gradle.kts | 3 ++ .../main/kotlin/cli/ProcessFhirCommands.kt | 2 +- .../engine/CustomFhirPathFunctions.kt | 2 +- .../translation/hl7/utils/ConstantResolver.kt | 35 ++++++++++++++----- .../hl7/utils/CustomFHIRFunctions.kt | 2 +- .../hl7/utils/FhirPathFunctions.kt | 3 +- .../translation/hl7/utils/FhirPathUtils.kt | 10 +++--- .../hl7/utils/ConstantResolverTests.kt | 28 ++++++++------- .../hl7/utils/FhirPathUtilsTests.kt | 8 ++--- 9 files changed, 58 insertions(+), 35 deletions(-) diff --git a/prime-router/build.gradle.kts b/prime-router/build.gradle.kts index 90a5971f314..b64a5b7208e 100644 --- a/prime-router/build.gradle.kts +++ b/prime-router/build.gradle.kts @@ -858,6 +858,9 @@ dependencies { // https://mvnrepository.com/artifact/ca.uhn.hapi.fhir/hapi-fhir-caching-caffeine implementation("ca.uhn.hapi.fhir:hapi-fhir-caching-caffeine:7.2.2") implementation("ca.uhn.hapi.fhir:hapi-fhir-client:7.2.2") + // pin + implementation("ca.uhn.hapi.fhir:org.hl7.fhir.utilities:6.3.24") + implementation("ca.uhn.hapi.fhir:org.hl7.fhir.r4:6.3.24") implementation("ca.uhn.hapi:hapi-base:2.5.1") implementation("ca.uhn.hapi:hapi-structures-v251:2.5.1") implementation("ca.uhn.hapi:hapi-structures-v27:2.5.1") diff --git a/prime-router/src/main/kotlin/cli/ProcessFhirCommands.kt b/prime-router/src/main/kotlin/cli/ProcessFhirCommands.kt index 32321a12871..0b2d70a7149 100644 --- a/prime-router/src/main/kotlin/cli/ProcessFhirCommands.kt +++ b/prime-router/src/main/kotlin/cli/ProcessFhirCommands.kt @@ -39,11 +39,11 @@ import gov.cdc.prime.router.fhirengine.translation.hl7.utils.FhirPathUtils import gov.cdc.prime.router.fhirengine.utils.FhirTranscoder import gov.cdc.prime.router.fhirengine.utils.HL7Reader import gov.cdc.prime.router.fhirengine.utils.getObservations +import org.hl7.fhir.r4.fhirpath.FHIRLexer.FHIRLexerException import org.hl7.fhir.r4.model.Base import org.hl7.fhir.r4.model.Bundle import org.hl7.fhir.r4.model.Extension import org.hl7.fhir.r4.model.Reference -import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException /** * Process data into/from FHIR. diff --git a/prime-router/src/main/kotlin/fhirengine/engine/CustomFhirPathFunctions.kt b/prime-router/src/main/kotlin/fhirengine/engine/CustomFhirPathFunctions.kt index 5fcfcaeb1f1..0083feea221 100644 --- a/prime-router/src/main/kotlin/fhirengine/engine/CustomFhirPathFunctions.kt +++ b/prime-router/src/main/kotlin/fhirengine/engine/CustomFhirPathFunctions.kt @@ -10,11 +10,11 @@ import gov.cdc.prime.router.common.NPIUtilities import gov.cdc.prime.router.fhirengine.translation.hl7.SchemaException import gov.cdc.prime.router.metadata.GeoData import gov.cdc.prime.router.metadata.LivdLookup +import org.hl7.fhir.r4.fhirpath.FHIRPathUtilityClasses.FunctionDetails import org.hl7.fhir.r4.model.Base import org.hl7.fhir.r4.model.Device import org.hl7.fhir.r4.model.Observation import org.hl7.fhir.r4.model.StringType -import org.hl7.fhir.r4.utils.FHIRPathUtilityClasses.FunctionDetails import java.time.LocalDate import java.util.Date import java.util.UUID diff --git a/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/ConstantResolver.kt b/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/ConstantResolver.kt index 5263b8c0ad4..d15800abd95 100644 --- a/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/ConstantResolver.kt +++ b/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/ConstantResolver.kt @@ -9,14 +9,14 @@ import org.apache.commons.text.StringSubstitutor import org.apache.commons.text.lookup.StringLookup import org.apache.logging.log4j.kotlin.Logging import org.hl7.fhir.exceptions.PathEngineException +import org.hl7.fhir.r4.fhirpath.FHIRPathEngine +import org.hl7.fhir.r4.fhirpath.FHIRPathUtilityClasses +import org.hl7.fhir.r4.fhirpath.TypeDetails import org.hl7.fhir.r4.model.Base import org.hl7.fhir.r4.model.Bundle import org.hl7.fhir.r4.model.IntegerType import org.hl7.fhir.r4.model.StringType -import org.hl7.fhir.r4.model.TypeDetails import org.hl7.fhir.r4.model.ValueSet -import org.hl7.fhir.r4.utils.FHIRPathEngine -import org.hl7.fhir.r4.utils.FHIRPathUtilityClasses.FunctionDetails import java.lang.IllegalArgumentException import java.lang.NumberFormatException @@ -145,7 +145,13 @@ class ConstantSubstitutor { */ class FhirPathCustomResolver(private val customFhirFunctions: FhirPathFunctions? = null) : FHIRPathEngine.IEvaluationContext, Logging { - override fun resolveConstant(appContext: Any?, name: String?, beforeContext: Boolean): List { + override fun resolveConstant( + engine: FHIRPathEngine?, + appContext: Any?, + name: String?, + beforeContext: Boolean, + explicitConstant: Boolean, + ): List { // Name is always passed in from the FHIR path engine require(!name.isNullOrBlank()) @@ -210,7 +216,12 @@ class FhirPathCustomResolver(private val customFhirFunctions: FhirPathFunctions? } } - override fun resolveConstantType(appContext: Any?, name: String?): TypeDetails { + override fun resolveConstantType( + engine: FHIRPathEngine?, + appContext: Any?, + name: String?, + explicitConstant: Boolean, + ): TypeDetails { throw NotImplementedError("Not implemented") } @@ -218,19 +229,25 @@ class FhirPathCustomResolver(private val customFhirFunctions: FhirPathFunctions? throw NotImplementedError("Not implemented") } - override fun resolveFunction(functionName: String?): FunctionDetails? { + override fun resolveFunction( + engine: FHIRPathEngine?, + functionName: String?, + ): FHIRPathUtilityClasses.FunctionDetails? { return CustomFHIRFunctions.resolveFunction(functionName, customFhirFunctions) } override fun checkFunction( + engine: FHIRPathEngine?, appContext: Any?, functionName: String?, + focus: TypeDetails?, parameters: MutableList?, ): TypeDetails { throw NotImplementedError("Not implemented") } override fun executeFunction( + engine: FHIRPathEngine?, appContext: Any?, focus: MutableList?, functionName: String?, @@ -246,7 +263,7 @@ class FhirPathCustomResolver(private val customFhirFunctions: FhirPathFunctions? } } - override fun resolveReference(appContext: Any?, url: String?, refContext: Base?): Base? { + override fun resolveReference(engine: FHIRPathEngine?, appContext: Any?, url: String?, refContext: Base?): Base? { // Name is always passed in from the FHIR path engine require(!url.isNullOrBlank()) @@ -256,11 +273,11 @@ class FhirPathCustomResolver(private val customFhirFunctions: FhirPathFunctions? } } - override fun conformsToProfile(appContext: Any?, item: Base?, url: String?): Boolean { + override fun conformsToProfile(engine: FHIRPathEngine?, appContext: Any?, item: Base?, url: String?): Boolean { throw NotImplementedError("Not implemented") } - override fun resolveValueSet(appContext: Any?, url: String?): ValueSet { + override fun resolveValueSet(engine: FHIRPathEngine?, appContext: Any?, url: String?): ValueSet { throw NotImplementedError("Not implemented") } } \ No newline at end of file diff --git a/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/CustomFHIRFunctions.kt b/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/CustomFHIRFunctions.kt index 8b6fb6f0734..e6986f75388 100644 --- a/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/CustomFHIRFunctions.kt +++ b/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/CustomFHIRFunctions.kt @@ -4,13 +4,13 @@ import ca.uhn.fhir.model.api.TemporalPrecisionEnum import fhirengine.translation.hl7.utils.FhirPathFunctions import fhirengine.translation.hl7.utils.helpers.convertDateToAge import gov.cdc.prime.router.fhirengine.translation.hl7.SchemaException +import org.hl7.fhir.r4.fhirpath.FHIRPathUtilityClasses.FunctionDetails import org.hl7.fhir.r4.model.Base import org.hl7.fhir.r4.model.BaseDateTimeType import org.hl7.fhir.r4.model.BooleanType import org.hl7.fhir.r4.model.DateTimeType import org.hl7.fhir.r4.model.IntegerType import org.hl7.fhir.r4.model.StringType -import org.hl7.fhir.r4.utils.FHIRPathUtilityClasses.FunctionDetails import java.time.DateTimeException import java.time.ZoneId import java.util.TimeZone diff --git a/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathFunctions.kt b/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathFunctions.kt index 19128b571c3..6a7d0da648c 100644 --- a/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathFunctions.kt +++ b/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathFunctions.kt @@ -1,7 +1,8 @@ package fhirengine.translation.hl7.utils +import org.hl7.fhir.r4.fhirpath.FHIRPathUtilityClasses.FunctionDetails import org.hl7.fhir.r4.model.Base -import org.hl7.fhir.r4.utils.FHIRPathUtilityClasses.FunctionDetails + /** * This interface contains the required method signatures required to implement custom FHIR functions */ diff --git a/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathUtils.kt b/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathUtils.kt index d658e2d73f2..e7328517f36 100644 --- a/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathUtils.kt +++ b/prime-router/src/main/kotlin/fhirengine/translation/hl7/utils/FhirPathUtils.kt @@ -8,6 +8,9 @@ import gov.cdc.prime.router.fhirengine.translation.hl7.HL7ConversionException import gov.cdc.prime.router.fhirengine.translation.hl7.SchemaException import gov.cdc.prime.router.fhirengine.translation.hl7.schema.converter.ConverterSchemaElement import org.apache.logging.log4j.kotlin.Logging +import org.hl7.fhir.r4.fhirpath.ExpressionNode +import org.hl7.fhir.r4.fhirpath.FHIRLexer +import org.hl7.fhir.r4.fhirpath.FHIRPathEngine import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext import org.hl7.fhir.r4.model.Base import org.hl7.fhir.r4.model.BaseDateTimeType @@ -15,11 +18,8 @@ import org.hl7.fhir.r4.model.BooleanType import org.hl7.fhir.r4.model.Bundle import org.hl7.fhir.r4.model.DateTimeType import org.hl7.fhir.r4.model.DateType -import org.hl7.fhir.r4.model.ExpressionNode import org.hl7.fhir.r4.model.InstantType import org.hl7.fhir.r4.model.TimeType -import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException -import org.hl7.fhir.r4.utils.FHIRPathEngine import java.time.DateTimeException import java.time.LocalTime import java.time.format.DateTimeFormatter @@ -97,7 +97,7 @@ object FhirPathUtils : Logging { } else { pathEngine.evaluate(appContext, focusResource, bundle, bundle, expressionNode) } - } catch (e: FHIRLexerException) { + } catch (e: FHIRLexer.FHIRLexerException) { logger.error("${e.javaClass.name}: Syntax error in FHIR Path $expression.") emptyList() } catch (e: IndexOutOfBoundsException) { @@ -145,7 +145,7 @@ object FhirPathUtils : Logging { } } catch (e: Exception) { val msg = when (e) { - is FHIRLexerException -> "Syntax error in FHIR Path expression $expression" + is FHIRLexer.FHIRLexerException -> "Syntax error in FHIR Path expression $expression" is SchemaException -> e.message.toString() else -> "Unknown error while evaluating FHIR Path expression $expression for condition. " + diff --git a/prime-router/src/test/kotlin/fhirengine/translation/hl7/utils/ConstantResolverTests.kt b/prime-router/src/test/kotlin/fhirengine/translation/hl7/utils/ConstantResolverTests.kt index 7920025ac12..7f55193b5b0 100644 --- a/prime-router/src/test/kotlin/fhirengine/translation/hl7/utils/ConstantResolverTests.kt +++ b/prime-router/src/test/kotlin/fhirengine/translation/hl7/utils/ConstantResolverTests.kt @@ -86,24 +86,24 @@ class ConstantResolverTests { @Test fun `test fhir path resolver`() { mockkObject(FhirPathUtils) - assertFailure { FhirPathCustomResolver().resolveConstant(null, null, false) } - assertFailure { FhirPathCustomResolver().resolveConstant(null, "const1", false) } + assertFailure { FhirPathCustomResolver().resolveConstant(null, null, null, false, false) } + assertFailure { FhirPathCustomResolver().resolveConstant(null, null, "const1", false, false) } .hasClass(PathEngineException::class.java) val integerValue = 99 val urlPrefix = "https://reportstream.cdc.gov/fhir/StructureDefinition/" val constants = sortedMapOf("const1" to "'value1'", "int1" to "'$integerValue'", "rsext" to "'$urlPrefix'") val context = CustomContext.addConstants(constants, CustomContext(Bundle(), Bundle())) - assertThat(FhirPathCustomResolver().resolveConstant(context, "const2", false)).isEmpty() - assertThat(FhirPathCustomResolver().resolveConstant(context, "const1", false)).isNotNull() - var result = FhirPathCustomResolver().resolveConstant(context, "int1", false) + assertThat(FhirPathCustomResolver().resolveConstant(null, context, "const2", false, false)).isEmpty() + assertThat(FhirPathCustomResolver().resolveConstant(null, context, "const1", false, false)).isNotNull() + var result = FhirPathCustomResolver().resolveConstant(null, context, "int1", false, false) assertThat(result).isNotNull() assertThat(result).isNotEmpty() assertThat(result[0] is IntegerType).isTrue() assertThat((result[0] as IntegerType).value).isEqualTo(integerValue) // Now lets resolve a constant - result = FhirPathCustomResolver().resolveConstant(context, "const1", false) + result = FhirPathCustomResolver().resolveConstant(null, context, "const1", false, false) assertThat(result).isNotNull() assertThat(result.isNotEmpty()) assertThat(result[0].isPrimitive).isTrue() @@ -114,21 +114,21 @@ class ConstantResolverTests { // Test the ability to resolve constants with suffix val urlSuffix = "SomeSuffix" - result = FhirPathCustomResolver().resolveConstant(context, "`rsext-$urlSuffix`", false) + result = FhirPathCustomResolver().resolveConstant(null, context, "`rsext-$urlSuffix`", false, false) assertThat(result).isNotNull() assertThat(result.isNotEmpty()) assertThat(result[0].isPrimitive).isTrue() assertThat(result[0]).isInstanceOf(StringType::class.java) assertThat((result[0] as StringType).value).isEqualTo("$urlPrefix$urlSuffix") - result = FhirPathCustomResolver().resolveConstant(context, "`rsext`", false) + result = FhirPathCustomResolver().resolveConstant(null, context, "`rsext`", false, false) assertThat(result).isNotNull() assertThat(result.isNotEmpty()) assertThat(result[0].isPrimitive).isTrue() assertThat(result[0]).isInstanceOf(StringType::class.java) assertThat((result[0] as StringType).value).isEqualTo(urlPrefix) - result = FhirPathCustomResolver().resolveConstant(context, "unknownconst", false) + result = FhirPathCustomResolver().resolveConstant(null, context, "unknownconst", false, false) assertThat(result).isEmpty() } @@ -144,7 +144,7 @@ class ConstantResolverTests { val constants = sortedMapOf("const1" to "'value1'") // this does not matter but context wants something val context = CustomContext.addConstants(constants, CustomContext(Bundle(), Bundle())) - val result = FhirPathCustomResolver().resolveConstant(context, "const1", false) + val result = FhirPathCustomResolver().resolveConstant(null, context, "const1", false, false) assertThat(result).isNotNull() assertThat(result.isNotEmpty()) assertThat(result.size == 3) @@ -167,6 +167,7 @@ class ConstantResolverTests { val context = CustomContext(Bundle(), Bundle()) assertThat( FhirPathCustomResolver(CustomFhirPathFunctions()).executeFunction( + null, context, mutableListOf(Observation()), "livdTableLookup", @@ -180,6 +181,7 @@ class ConstantResolverTests { val context = CustomContext(Bundle(), Bundle()) assertFailure { FhirPathCustomResolver(CustomFhirPathFunctions()).executeFunction( + null, context, mutableListOf(Observation()), "unknown", @@ -198,15 +200,15 @@ class ConstantResolverTests { val bundle = Bundle() val customContext = CustomContext(bundle, bundle) - assertThat(FhirPathCustomResolver().resolveReference(customContext, org2Url, null)).isNull() + assertThat(FhirPathCustomResolver().resolveReference(null, customContext, org2Url, null)).isNull() bundle.addEntry().resource = org1 bundle.entry[0].fullUrl = "Organization/${org1.id}" - assertThat(FhirPathCustomResolver().resolveReference(customContext, org2Url, null)).isNull() + assertThat(FhirPathCustomResolver().resolveReference(null, customContext, org2Url, null)).isNull() bundle.addEntry().resource = org2 bundle.entry[1].fullUrl = org2Url - val reference = FhirPathCustomResolver().resolveReference(customContext, org2Url, null) + val reference = FhirPathCustomResolver().resolveReference(null, customContext, org2Url, null) assertThat(reference).isNotNull() assertThat(reference).isEqualTo(org2) } diff --git a/prime-router/src/test/kotlin/fhirengine/translation/hl7/utils/FhirPathUtilsTests.kt b/prime-router/src/test/kotlin/fhirengine/translation/hl7/utils/FhirPathUtilsTests.kt index e228719e1ca..173f4a61642 100644 --- a/prime-router/src/test/kotlin/fhirengine/translation/hl7/utils/FhirPathUtilsTests.kt +++ b/prime-router/src/test/kotlin/fhirengine/translation/hl7/utils/FhirPathUtilsTests.kt @@ -28,6 +28,7 @@ import io.mockk.spyk import io.mockk.verify import org.apache.logging.log4j.kotlin.KotlinLogger import org.hl7.fhir.exceptions.PathEngineException +import org.hl7.fhir.r4.fhirpath.FHIRLexer import org.hl7.fhir.r4.model.Bundle import org.hl7.fhir.r4.model.DateTimeType import org.hl7.fhir.r4.model.DateType @@ -37,7 +38,6 @@ import org.hl7.fhir.r4.model.InstantType import org.hl7.fhir.r4.model.Observation import org.hl7.fhir.r4.model.ServiceRequest import org.hl7.fhir.r4.model.TimeType -import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException import org.junit.jupiter.api.BeforeEach import java.util.Date import kotlin.test.Test @@ -69,7 +69,7 @@ class FhirPathUtilsTests { assertThat(FhirPathUtils.parsePath("")).isNull() // Invalid fhir path syntax - assertFailsWith { FhirPathUtils.parsePath("Bundle.#*($&id.exists()") } + assertFailsWith { FhirPathUtils.parsePath("Bundle.#*($&id.exists()") } } @Test @@ -101,7 +101,7 @@ class FhirPathUtilsTests { FhirPathUtils.evaluateCondition(null, bundle, bundle, bundle, path) } catch (e: Exception) { assertThat(e).isInstanceOf() - assertThat(e.cause).isNotNull().isInstanceOf() + assertThat(e.cause).isNotNull().isInstanceOf() } } @@ -193,7 +193,7 @@ class FhirPathUtilsTests { verify { mockedLogger.error( - "org.hl7.fhir.r4.utils.FHIRLexer\$FHIRLexerException: " + + "org.hl7.fhir.r4.fhirpath.FHIRLexer\$FHIRLexerException: " + "Syntax error in FHIR Path Bundle.#*(\$&id.exists()." ) }