From adeee346e4ba8f9aa4b9c950f76f25a73ecfee79 Mon Sep 17 00:00:00 2001 From: Shubham Goyal <shubham1g5@gmail.com> Date: Thu, 5 Dec 2024 16:09:35 +0530 Subject: [PATCH] separate loading of entities from references into a method --- .../org/commcare/tasks/EntityLoaderHelper.kt | 21 ++++-- .../org/commcare/tasks/PrimeEntityCache.kt | 24 ++++++ .../commcare/tasks/PrimeEntityCacheHelper.kt | 74 +++++++++++++++++++ 3 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 app/src/org/commcare/tasks/PrimeEntityCache.kt create mode 100644 app/src/org/commcare/tasks/PrimeEntityCacheHelper.kt diff --git a/app/src/org/commcare/tasks/EntityLoaderHelper.kt b/app/src/org/commcare/tasks/EntityLoaderHelper.kt index 35cd11c99..e55c75354 100644 --- a/app/src/org/commcare/tasks/EntityLoaderHelper.kt +++ b/app/src/org/commcare/tasks/EntityLoaderHelper.kt @@ -35,8 +35,22 @@ class EntityLoaderHelper( } } - fun loadEntities(nodeset: TreeReference): Pair<List<Entity<TreeReference>>, List<TreeReference>>? { + /** + * Loads and prepares a list of entities derived from the given nodeset + */ + fun loadEntities(nodeset: TreeReference): Pair<List<Entity<TreeReference>>, List<TreeReference>> { val references = factory.expandReferenceList(nodeset) + val entities = loadEntitiesWithReferences(references) + factory.prepareEntities(entities) + factory.printAndClearTraces("build") + return Pair<List<Entity<TreeReference>>, List<TreeReference>>(entities, references) + } + + + /** + * Loads a list of entities corresponding to the given references + */ + private fun loadEntitiesWithReferences(references: List<TreeReference>): MutableList<Entity<TreeReference>>? { val entities: MutableList<Entity<TreeReference>> = ArrayList() focusTargetIndex = -1 var indexInFullList = 0 @@ -53,10 +67,7 @@ class EntityLoaderHelper( indexInFullList++ } } - - factory.prepareEntities(entities) - factory.printAndClearTraces("build") - return Pair<List<Entity<TreeReference>>, List<TreeReference>>(entities, references) + return entities } override fun cancel() { diff --git a/app/src/org/commcare/tasks/PrimeEntityCache.kt b/app/src/org/commcare/tasks/PrimeEntityCache.kt new file mode 100644 index 000000000..8c8bb72b5 --- /dev/null +++ b/app/src/org/commcare/tasks/PrimeEntityCache.kt @@ -0,0 +1,24 @@ +package org.commcare.tasks + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import org.commcare.CommCareApplication +import org.commcare.utils.SessionUnavailableException + +class PrimeEntityCache(appContext: Context, workerParams: WorkerParameters) + : Worker(appContext, workerParams) { + + override fun doWork(): Result { + try { + PrimeEntityCacheHelper.getInstance().primeEntityCache() + return Result.success(); + } catch (_: SessionUnavailableException) { + } + return Result.failure() + } + + override fun onStopped() { + PrimeEntityCacheHelper.getInstance().cancel() + } +} diff --git a/app/src/org/commcare/tasks/PrimeEntityCacheHelper.kt b/app/src/org/commcare/tasks/PrimeEntityCacheHelper.kt new file mode 100644 index 000000000..4065f957e --- /dev/null +++ b/app/src/org/commcare/tasks/PrimeEntityCacheHelper.kt @@ -0,0 +1,74 @@ +package org.commcare.tasks + +import io.reactivex.functions.Cancellable +import okhttp3.internal.notifyAll +import org.commcare.CommCareApplication +import org.commcare.suite.model.Detail +import org.commcare.suite.model.EntityDatum +import org.commcare.utils.AndroidCommCarePlatform +import org.javarosa.core.model.condition.EvaluationContext + +class PrimeEntityCacheHelper private constructor() : Cancellable { + + private var entityLoaderHelper: EntityLoaderHelper? = null + private var inProgress = false + + companion object { + @Volatile + private var instance: PrimeEntityCacheHelper? = null + + fun getInstance() = + instance ?: synchronized(this) { + instance ?: PrimeEntityCacheHelper().also { instance = it } + } + } + + fun primeEntityCache() { + checkPreConditions() + primeEntityCacheForApp(CommCareApplication.instance().commCarePlatform) + clearState() + } + + private fun primeEntityCacheForApp(commCarePlatform: AndroidCommCarePlatform) { + inProgress = true + val commandMap = commCarePlatform.commandToEntryMap + for (command in commandMap.keys()) { + val entry = commandMap[command]!! + val sessionDatums = entry.sessionDataReqs + for (sessionDatum in sessionDatums) { + if (sessionDatum is EntityDatum) { + val shortDetailId = sessionDatum.shortDetail + if (shortDetailId != null) { + val detail = commCarePlatform.getDetail(shortDetailId) + primeCacheForDetail(detail, sessionDatum) + } + } + } + } + } + + private fun primeCacheForDetail(detail: Detail, sessionDatum: EntityDatum) { + if (detail.shouldCache()) { + entityLoaderHelper = EntityLoaderHelper(detail, evalCtx()) + entityLoaderHelper!!.loadEntities(sessionDatum.nodeset) + } + } + + private fun evalCtx(): EvaluationContext { + return CommCareApplication.instance().currentSessionWrapper.evaluationContext + } + + private fun clearState() { + entityLoaderHelper = null + inProgress = false + } + + private fun checkPreConditions() { + require(CommCareApplication.instance().session.isActive) { "User session must be active to prime entity cache" } + require(!inProgress) { "We are already priming the cache" } + } + + override fun cancel() { + entityLoaderHelper?.cancel() + } +}