Skip to content

Commit

Permalink
Updated the code to throw expeption when main thread is blocked. (#1795)
Browse files Browse the repository at this point in the history
* Updated the code to throw expeption when main thread is blocked

* Review comments: Updated docs and added message to the exception

* Review changes
  • Loading branch information
aditya-07 committed Jan 25, 2023
1 parent 66290ca commit 8d409c1
Show file tree
Hide file tree
Showing 13 changed files with 367 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,45 +20,45 @@ import ca.uhn.fhir.rest.gclient.UriClientParam
import com.google.android.fhir.FhirEngine
import com.google.android.fhir.getResourceType
import com.google.android.fhir.search.Search
import kotlinx.coroutines.runBlocking
import org.hl7.fhir.instance.model.api.IBaseResource
import org.hl7.fhir.instance.model.api.IIdType
import org.hl7.fhir.r4.model.Library
import org.hl7.fhir.r4.model.Resource
import org.hl7.fhir.r4.model.ResourceType
import org.opencds.cqf.cql.evaluator.fhir.dal.FhirDal

class FhirEngineDal(private val fhirEngine: FhirEngine) : FhirDal {
internal class FhirEngineDal(private val fhirEngine: FhirEngine) : FhirDal {
val libs = mutableMapOf<String, Library>()

override fun read(id: IIdType): IBaseResource = runBlocking {
override fun read(id: IIdType): IBaseResource = runBlockingOrThrowMainThreadException {
val clazz = id.getResourceClass()
fhirEngine.get(getResourceType(clazz), id.idPart)
}

override fun create(resource: IBaseResource): Unit = runBlocking {
override fun create(resource: IBaseResource): Unit = runBlockingOrThrowMainThreadException {
fhirEngine.create(resource as Resource)
}

override fun update(resource: IBaseResource) = runBlocking {
override fun update(resource: IBaseResource) = runBlockingOrThrowMainThreadException {
fhirEngine.update(resource as Resource)
}

override fun delete(id: IIdType) = runBlocking {
override fun delete(id: IIdType) = runBlockingOrThrowMainThreadException {
val clazz = id.getResourceClass()
fhirEngine.delete(getResourceType(clazz), id.idPart)
}

override fun search(resourceType: String): Iterable<IBaseResource> = runBlocking {
val search = Search(type = ResourceType.fromCode(resourceType))
when (resourceType) {
"Library" -> libs.values.plus(fhirEngine.search(search))
else -> fhirEngine.search(search)
}.toMutableList()
}
override fun search(resourceType: String): Iterable<IBaseResource> =
runBlockingOrThrowMainThreadException {
val search = Search(type = ResourceType.fromCode(resourceType))
when (resourceType) {
"Library" -> libs.values.plus(fhirEngine.search(search))
else -> fhirEngine.search(search)
}.toMutableList()
}

override fun searchByUrl(resourceType: String, url: String): Iterable<IBaseResource> =
runBlocking {
runBlockingOrThrowMainThreadException {
val search = Search(type = ResourceType.fromCode(resourceType))
search.filter(UriClientParam("url"), { value = url })

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.hl7.fhir.r4.model.Library
import org.opencds.cqf.cql.evaluator.cql2elm.content.fhir.BaseFhirLibrarySourceProvider
import org.opencds.cqf.cql.evaluator.fhir.adapter.r4.AdapterFactory

class FhirEngineLibraryContentProvider(adapterFactory: AdapterFactory) :
internal class FhirEngineLibraryContentProvider(adapterFactory: AdapterFactory) :
BaseFhirLibrarySourceProvider(adapterFactory) {
val libs = mutableMapOf<String, Library>()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import com.google.android.fhir.search.filter.TokenParamFilterCriterion
import com.google.android.fhir.search.query.XFhirQueryTranslator.applyFilterParam
import java.math.BigDecimal
import java.util.Date
import kotlinx.coroutines.runBlocking
import org.hl7.fhir.r4.model.Coding
import org.hl7.fhir.r4.model.DateTimeType
import org.hl7.fhir.r4.model.Enumerations
Expand All @@ -41,7 +40,7 @@ import org.opencds.cqf.cql.engine.runtime.DateTime
import org.opencds.cqf.cql.engine.runtime.Interval
import org.opencds.cqf.cql.engine.terminology.ValueSetInfo

class FhirEngineRetrieveProvider(private val fhirEngine: FhirEngine) :
internal class FhirEngineRetrieveProvider(private val fhirEngine: FhirEngine) :
TerminologyAwareRetrieveProvider() {
override fun retrieve(
context: String?,
Expand All @@ -56,37 +55,26 @@ class FhirEngineRetrieveProvider(private val fhirEngine: FhirEngine) :
dateLowPath: String?,
dateHighPath: String?,
dateRange: Interval?
): Iterable<Any> {
return runBlocking {
if (dataType == null) {
emptyList()
} else if (contextPath == "id" && contextValue == null) {
emptyList()
} else if (contextPath == "id" && contextValue != null) {
listOfNotNull(
safeGet(fhirEngine, ResourceType.fromCode(dataType), "$contextValue"),
safeGet(fhirEngine, ResourceType.fromCode(dataType), "urn:uuid:$contextValue"),
safeGet(fhirEngine, ResourceType.fromCode(dataType), "urn:oid:$contextValue")
)
} else if (codePath == "id" && codes != null) {
codes.mapNotNull { safeGet(fhirEngine, ResourceType.fromCode(dataType), it.code) }
} else {
val search = Search(ResourceType.fromCode(dataType))

// filter by context
filterByContext(context, contextPath, contextValue, dataType, search)

// filter by code in codes
filterByCode(codePath, codes, search)

// filter by code into valueSet
filterByValueSet(codePath, valueSet, search)

// filter by date in range
filterByDateRange(datePath, dateLowPath, dateHighPath, dateRange, search)

fhirEngine.search(search)
}
): Iterable<Any> = runBlockingOrThrowMainThreadException {
if (dataType == null) {
emptyList()
} else if (contextPath == "id" && contextValue == null) {
emptyList()
} else if (contextPath == "id") {
listOfNotNull(
safeGet(fhirEngine, ResourceType.fromCode(dataType), "$contextValue"),
safeGet(fhirEngine, ResourceType.fromCode(dataType), "urn:uuid:$contextValue"),
safeGet(fhirEngine, ResourceType.fromCode(dataType), "urn:oid:$contextValue")
)
} else if (codePath == "id" && codes != null) {
codes.mapNotNull { safeGet(fhirEngine, ResourceType.fromCode(dataType), it.code) }
} else {
val search = Search(ResourceType.fromCode(dataType))
filterByContext(context, contextPath, contextValue, dataType, search)
filterByCode(codePath, codes, search)
filterByValueSet(codePath, valueSet, search)
filterByDateRange(datePath, dateLowPath, dateHighPath, dateRange, search)
fhirEngine.search(search)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import ca.uhn.fhir.context.FhirContext
import com.google.android.fhir.FhirEngine
import com.google.android.fhir.db.ResourceNotFoundException
import com.google.android.fhir.search.search
import kotlinx.coroutines.runBlocking
import org.hl7.fhir.r4.model.CodeSystem
import org.hl7.fhir.r4.model.Resource
import org.hl7.fhir.r4.model.ResourceType
Expand All @@ -32,7 +31,7 @@ import org.opencds.cqf.cql.engine.terminology.TerminologyProvider
import org.opencds.cqf.cql.engine.terminology.ValueSetInfo
import org.opencds.cqf.cql.evaluator.engine.util.ValueSetUtil

class FhirEngineTerminologyProvider(
internal class FhirEngineTerminologyProvider(
private val fhirContext: FhirContext,
private val fhirEngine: FhirEngine
) : TerminologyProvider {
Expand All @@ -45,6 +44,8 @@ class FhirEngineTerminologyProvider(
override fun `in`(code: Code, valueSet: ValueSetInfo): Boolean {
try {
return expand(valueSet).any { it.code == code.code && it.system == code.system }
} catch (b: BlockingMainThreadException) {
throw b
} catch (e: Exception) {
throw TerminologyProviderException(
"Error performing membership check of Code: $code in ValueSet: ${valueSet.id}",
Expand All @@ -53,63 +54,62 @@ class FhirEngineTerminologyProvider(
}
}

override fun expand(valueSetInfo: ValueSetInfo): MutableIterable<Code> {
try {
val valueSet = resolveValueSet(valueSetInfo)
return ValueSetUtil.getCodesInExpansion(fhirContext, valueSet)
?: ValueSetUtil.getCodesInCompose(fhirContext, valueSet)
} catch (e: Exception) {
throw TerminologyProviderException(
"Error performing expansion of ValueSet: ${valueSetInfo.id}",
e
)
}
}

override fun lookup(code: Code, codeSystem: CodeSystemInfo): Code {
try {
val codeSystems = runBlocking {
fhirEngine.search<CodeSystem> {
filter(CodeSystem.CODE, { value = of(code.code) })
filter(CodeSystem.SYSTEM, { value = codeSystem.id })
override fun expand(valueSetInfo: ValueSetInfo): MutableIterable<Code> =
runBlockingOrThrowMainThreadException {
try {
resolveValueSet(valueSetInfo).let {
ValueSetUtil.getCodesInExpansion(fhirContext, it)
?: ValueSetUtil.getCodesInCompose(fhirContext, it)
}
} catch (e: Exception) {
throw TerminologyProviderException(
"Error performing expansion of ValueSet: ${valueSetInfo.id}",
e
)
}
}

val concept = codeSystems.first().concept.first { it.code == code.code }

return Code().apply {
this.code = code.code
display = concept.display
system = codeSystem.id
override fun lookup(code: Code, codeSystem: CodeSystemInfo): Code =
runBlockingOrThrowMainThreadException {
try {
fhirEngine
.search<CodeSystem> {
filter(CodeSystem.CODE, { value = of(code.code) })
filter(CodeSystem.SYSTEM, { value = codeSystem.id })
}
.first()
.concept
.first { it.code == code.code }
.let {
Code().apply {
this.code = code.code
display = it.display
system = codeSystem.id
}
}
} catch (e: Exception) {
throw TerminologyProviderException(
"Error performing lookup of Code: $code in CodeSystem: ${codeSystem.id}",
e
)
}
} catch (e: Exception) {
throw TerminologyProviderException(
"Error performing lookup of Code: $code in CodeSystem: ${codeSystem.id}",
e
)
}
}

private fun searchByUrl(url: String?): List<ValueSet> {
private suspend fun searchByUrl(url: String?): List<ValueSet> {
if (url == null) return emptyList()
return runBlocking { fhirEngine.search { filter(ValueSet.URL, { value = url }) } }
return fhirEngine.search { filter(ValueSet.URL, { value = url }) }
}

private fun searchByIdentifier(identifier: String?): List<ValueSet> {
private suspend fun searchByIdentifier(identifier: String?): List<ValueSet> {
if (identifier == null) return emptyList()
return runBlocking {
fhirEngine.search { filter(ValueSet.IDENTIFIER, { value = of(identifier) }) }
}
return fhirEngine.search { filter(ValueSet.IDENTIFIER, { value = of(identifier) }) }
}

private fun searchById(id: String): List<ValueSet> {
return runBlocking {
listOfNotNull(
safeGet(fhirEngine, ResourceType.ValueSet, id.removePrefix(URN_OID).removePrefix(URN_UUID))
as? ValueSet
)
}
}
private suspend fun searchById(id: String): List<ValueSet> =
listOfNotNull(
safeGet(fhirEngine, ResourceType.ValueSet, id.removePrefix(URN_OID).removePrefix(URN_UUID))
as? ValueSet
)

private suspend fun safeGet(fhirEngine: FhirEngine, type: ResourceType, id: String): Resource? {
return try {
Expand All @@ -119,7 +119,7 @@ class FhirEngineTerminologyProvider(
}
}

fun resolveValueSet(valueSet: ValueSetInfo): ValueSet {
private suspend fun resolveValueSet(valueSet: ValueSetInfo): ValueSet {
if (valueSet.version != null ||
(valueSet.codeSystems != null && valueSet.codeSystems.isNotEmpty())
) {
Expand All @@ -146,7 +146,7 @@ class FhirEngineTerminologyProvider(
}
}

fun resolveValueSetId(valueSet: ValueSetInfo): String {
suspend fun resolveValueSetId(valueSet: ValueSetInfo): String {
return resolveValueSet(valueSet).idElement.idPart
}
}

0 comments on commit 8d409c1

Please sign in to comment.