Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ refactor: Made folder path for the terminology systems configurable #101

Merged
merged 2 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class ToFhirEngineConfig(toFhirEngineConfig: Config) {
/** Path to the folder where the job definitions are kept. */
lazy val jobRepositoryFolderPath: String = Try(toFhirEngineConfig.getString("mapping-jobs.repository.folder-path")).getOrElse("mapping-jobs")

/** Path to the folder where the terminology system definitions are kept. */
lazy val terminologySystemFolderPath: String = Try(toFhirEngineConfig.getString("terminology-servers.folder-path")).getOrElse("terminology-servers")

/** Timeout for a single mapping */
lazy val mappingTimeout: Duration = Try(toFhirEngineConfig.getDuration("mappings.timeout").toScala).toOption.getOrElse(Duration.apply(5, TimeUnit.SECONDS))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ class RunningJobRegistryTest extends AnyFlatSpec with Matchers {

"it" should "cache a StreamingQuery in blocking mode" in {
val streamingQueryFuture = getMockStreamingQuery()
runningTaskRegistry.registerStreamingQuery("j", "e", "m2", streamingQueryFuture, true)
val jobSubmissionFuture = runningTaskRegistry.registerStreamingQuery("j", "e", "m2", streamingQueryFuture, true)

val streamingQuery = Await.result(streamingQueryFuture, 10 seconds)
Await.result(jobSubmissionFuture, 2 seconds)
val streamingQuery = Await.result(streamingQueryFuture, 2 seconds)
verify(streamingQuery).awaitTermination()

// Registered task should have been deleted after termination
Expand Down Expand Up @@ -66,7 +67,7 @@ class RunningJobRegistryTest extends AnyFlatSpec with Matchers {

"it" should "register batch jobs" in {
runningTaskRegistry.registerBatchJob("j4", "e", Seq("m1", "m2"), Future.apply(
Thread.sleep(2000)
Thread.sleep(1000)
), "")
runningTaskRegistry.getRunningExecutions()("j4").head._2 shouldEqual Seq("m1", "m2")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import com.typesafe.scalalogging.LazyLogging
import io.tofhir.engine.Execution.actorSystem.dispatcher
import io.tofhir.engine.config.ToFhirEngineConfig
import io.tofhir.server.endpoint.CodeSystemEndpoint.SEGMENT_CODE_SYSTEMS
import io.tofhir.server.endpoint.TerminologyServiceManagerEndpoint._
import io.tofhir.server.model.Json4sSupport._
import io.tofhir.server.model.TerminologySystem.TerminologyCodeSystem
import io.tofhir.server.model.ToFhirRestCall
import io.tofhir.server.service.CodeSystemService

class CodeSystemEndpoint extends LazyLogging {
class CodeSystemEndpoint(toFhirEngineConfig: ToFhirEngineConfig) extends LazyLogging {

val service: CodeSystemService = new CodeSystemService()
val service: CodeSystemService = new CodeSystemService(toFhirEngineConfig.terminologySystemFolderPath)

def route(request: ToFhirRestCall): Route = {
pathPrefix(SEGMENT_CODE_SYSTEMS) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import com.typesafe.scalalogging.LazyLogging
import io.tofhir.engine.Execution.actorSystem.dispatcher
import io.tofhir.engine.config.ToFhirEngineConfig
import io.tofhir.server.endpoint.ConceptMapEndpoint.SEGMENT_CONCEPT_MAPS
import io.tofhir.server.endpoint.TerminologyServiceManagerEndpoint._
import io.tofhir.server.model.Json4sSupport._
import io.tofhir.server.model.TerminologySystem.TerminologyConceptMap
import io.tofhir.server.model.ToFhirRestCall
import io.tofhir.server.service.ConceptMapService

class ConceptMapEndpoint extends LazyLogging {
class ConceptMapEndpoint(toFhirEngineConfig: ToFhirEngineConfig) extends LazyLogging {

val service: ConceptMapService = new ConceptMapService()
val service: ConceptMapService = new ConceptMapService(toFhirEngineConfig.terminologySystemFolderPath)

def route(request: ToFhirRestCall): Route = {
pathPrefix(SEGMENT_CONCEPT_MAPS) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ class TerminologyServiceManagerEndpoint(terminologySystemRepository: ITerminolog

private val terminologySystemService: TerminologySystemService = new TerminologySystemService(terminologySystemRepository, mappingJobRepository)

private val conceptMapEndpoint: ConceptMapEndpoint = new ConceptMapEndpoint()
private val codeSystemEndpoint: CodeSystemEndpoint = new CodeSystemEndpoint()
private val conceptMapEndpoint: ConceptMapEndpoint = new ConceptMapEndpoint(toFhirEngineConfig)
private val codeSystemEndpoint: CodeSystemEndpoint = new CodeSystemEndpoint(toFhirEngineConfig)

def route(request: ToFhirRestCall): Route = {
pathPrefix(SEGMENT_TERMINOLOGY) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class ToFhirServerEndpoint(toFhirEngineConfig: ToFhirEngineConfig, webServerConf
val schemaRepository: SchemaFolderRepository = new SchemaFolderRepository(toFhirEngineConfig.schemaRepositoryFolderPath, projectRepository)
val mappingJobRepository: JobFolderRepository = new JobFolderRepository(toFhirEngineConfig.jobRepositoryFolderPath, projectRepository)
val mappingContextRepository: MappingContextFolderRepository = new MappingContextFolderRepository(toFhirEngineConfig.mappingContextRepositoryFolderPath, projectRepository)
val terminologySystemFolderRepository: TerminologySystemFolderRepository = new TerminologySystemFolderRepository(toFhirEngineConfig)
val terminologySystemFolderRepository: TerminologySystemFolderRepository = new TerminologySystemFolderRepository(toFhirEngineConfig.terminologySystemFolderPath)
// Initialize the projects by reading the resources available in the file system
new FolderDBInitializer(toFhirEngineConfig, schemaRepository, mappingRepository, mappingJobRepository, projectRepository, mappingContextRepository).init()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import io.tofhir.server.service.terminology.codesystem.{CodeSystemRepository, IC

import scala.concurrent.Future

class CodeSystemService extends LazyLogging {
class CodeSystemService(terminologySystemFolderPath: String) extends LazyLogging {

private val codeSystemRepository: ICodeSystemRepository = new CodeSystemRepository()
private val codeSystemRepository: ICodeSystemRepository = new CodeSystemRepository(terminologySystemFolderPath)

/**
* Get all code systems for a terminology
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import io.tofhir.server.service.terminology.conceptmap.{ConceptMapRepository, IC

import scala.concurrent.Future

class ConceptMapService extends LazyLogging {
class ConceptMapService(terminologySystemFolderPath: String) extends LazyLogging {

private val conceptMapRepository: IConceptMapRepository = new ConceptMapRepository()
private val conceptMapRepository: IConceptMapRepository = new ConceptMapRepository(terminologySystemFolderPath)

/**
* Get all ConceptMaps for a terminology
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import io.tofhir.engine.Execution.actorSystem.dispatcher
import io.tofhir.engine.config.ToFhirEngineConfig
import io.tofhir.engine.util.FileUtils
import io.tofhir.server.model.{AlreadyExists, BadRequest, ResourceNotFound, TerminologySystem}
import io.tofhir.server.service.terminology.TerminologySystemFolderRepository.{TERMINOLOGY_SYSTEMS_FOLDER, TERMINOLOGY_SYSTEMS_JSON}
import io.tofhir.server.service.terminology.TerminologySystemFolderRepository.getTerminologySystemsJsonPath
import io.tofhir.server.util.FileOperations

import java.io.File
Expand All @@ -13,10 +13,8 @@ import scala.concurrent.Future

/**
* Folder/Directory based terminology system repository implementation.
*
* @param toFhirEngineConfig
*/
class TerminologySystemFolderRepository(toFhirEngineConfig: ToFhirEngineConfig) extends ITerminologySystemRepository {
class TerminologySystemFolderRepository(terminologySystemsFolderPath: String) extends ITerminologySystemRepository {

// terminology system id -> TerminologySystem
private val terminologySystemMap: mutable.Map[String, TerminologySystem] = initMap()
Expand Down Expand Up @@ -44,7 +42,7 @@ class TerminologySystemFolderRepository(toFhirEngineConfig: ToFhirEngineConfig)
if (this.terminologySystemMap.contains(terminologySystem.id)) {
throw AlreadyExists("TerminologySystem already exists.", s"Id ${terminologySystem.id} already exists.")
}
val terminologySystemFolder = FileUtils.getPath(TERMINOLOGY_SYSTEMS_FOLDER, terminologySystem.id).toFile
val terminologySystemFolder = FileUtils.getPath(terminologySystemsFolderPath, terminologySystem.id).toFile
// Update the internal JSON file that we use as our database
val terminologySystemSeq = this.terminologySystemMap.values.toSeq :+ terminologySystem
this.updateTerminologySystemsDBFile(terminologySystemSeq)
Expand Down Expand Up @@ -117,7 +115,7 @@ class TerminologySystemFolderRepository(toFhirEngineConfig: ToFhirEngineConfig)
val updatedTerminologies = this.terminologySystemMap.values.toSeq.filterNot(_.id == id)
this.updateTerminologySystemsDBFile(updatedTerminologies)
//delete the terminology folder
val terminologyFolder = FileUtils.getPath(TERMINOLOGY_SYSTEMS_FOLDER, foundTerminology.id).toFile
val terminologyFolder = FileUtils.getPath(terminologySystemsFolderPath, foundTerminology.id).toFile
org.apache.commons.io.FileUtils.deleteDirectory(terminologyFolder)
// remove the terminology from the map
this.terminologySystemMap.remove(id)
Expand All @@ -135,11 +133,11 @@ class TerminologySystemFolderRepository(toFhirEngineConfig: ToFhirEngineConfig)
private def createConceptMapAndCodeSystemFiles(terminologySystem: TerminologySystem): Future[Unit] = {
Future {
terminologySystem.conceptMaps.foreach(conceptMap => {
val file = FileUtils.getPath(TERMINOLOGY_SYSTEMS_FOLDER, terminologySystem.id, conceptMap.id).toFile
val file = FileUtils.getPath(terminologySystemsFolderPath, terminologySystem.id, conceptMap.id).toFile
file.createNewFile()
})
terminologySystem.codeSystems.foreach(codeSystem => {
val file = FileUtils.getPath(TERMINOLOGY_SYSTEMS_FOLDER, terminologySystem.id, codeSystem.id).toFile
val file = FileUtils.getPath(terminologySystemsFolderPath, terminologySystem.id, codeSystem.id).toFile
file.createNewFile()
})
}
Expand Down Expand Up @@ -167,25 +165,25 @@ class TerminologySystemFolderRepository(toFhirEngineConfig: ToFhirEngineConfig)
// delete concept maps
conceptMapIdsToDelete.foreach { id =>
val conceptMap = existingTerminologySystem.conceptMaps.find(_.id == id).get
val file = FileUtils.getPath(TERMINOLOGY_SYSTEMS_FOLDER, existingTerminologySystem.id, conceptMap.id).toFile
val file = FileUtils.getPath(terminologySystemsFolderPath, existingTerminologySystem.id, conceptMap.id).toFile
file.delete()
}
// delete code systems
codeSystemIdsToDelete.foreach { id =>
val codeSystem = existingTerminologySystem.codeSystems.find(_.id == id).get
val file = FileUtils.getPath(TERMINOLOGY_SYSTEMS_FOLDER, existingTerminologySystem.id, codeSystem.id).toFile
val file = FileUtils.getPath(terminologySystemsFolderPath, existingTerminologySystem.id, codeSystem.id).toFile
file.delete()
}
// add concept maps
conceptMapIdsToAdd.foreach { id =>
val conceptMap = newTerminologySystem.conceptMaps.find(_.id == id).get
val file = FileUtils.getPath(TERMINOLOGY_SYSTEMS_FOLDER, existingTerminologySystem.id, conceptMap.id).toFile
val file = FileUtils.getPath(terminologySystemsFolderPath, existingTerminologySystem.id, conceptMap.id).toFile
file.createNewFile()
}
// add code systems
codeSystemIdsToAdd.foreach { id =>
val codeSystem = newTerminologySystem.codeSystems.find(_.id == id).get
val file = FileUtils.getPath(TERMINOLOGY_SYSTEMS_FOLDER, existingTerminologySystem.id, codeSystem.id).toFile
val file = FileUtils.getPath(terminologySystemsFolderPath, existingTerminologySystem.id, codeSystem.id).toFile
file.createNewFile()
}
}
Expand All @@ -197,11 +195,11 @@ class TerminologySystemFolderRepository(toFhirEngineConfig: ToFhirEngineConfig)
* @return
*/
private def readTerminologySystemsDBFile(): Seq[TerminologySystem] = {
val terminologySystemsFolder = FileUtils.getPath(TERMINOLOGY_SYSTEMS_FOLDER).toFile
val terminologySystemsFolder = FileUtils.getPath(terminologySystemsFolderPath).toFile
if (!terminologySystemsFolder.exists()) {
terminologySystemsFolder.mkdirs()
}
val terminologySystemsJsonFile = FileUtils.getPath(TERMINOLOGY_SYSTEMS_JSON).toFile
val terminologySystemsJsonFile = FileUtils.getPath(getTerminologySystemsJsonPath(terminologySystemsFolderPath)).toFile
if (!terminologySystemsJsonFile.exists()) {
terminologySystemsJsonFile.createNewFile()
FileOperations.writeJsonContent(terminologySystemsJsonFile, Seq.empty[TerminologySystem])
Expand Down Expand Up @@ -251,13 +249,20 @@ class TerminologySystemFolderRepository(toFhirEngineConfig: ToFhirEngineConfig)
}

private def updateTerminologySystemsDBFile(terminologySystems: Seq[TerminologySystem]): Unit = {
val localTerminologyFile = FileUtils.getPath(TERMINOLOGY_SYSTEMS_JSON).toFile
val localTerminologyFile = FileUtils.getPath(getTerminologySystemsJsonPath(terminologySystemsFolderPath)).toFile
FileOperations.writeJsonContent(localTerminologyFile, terminologySystems)
}

}

object TerminologySystemFolderRepository {
val TERMINOLOGY_SYSTEMS_FOLDER = "terminology-systems"
val TERMINOLOGY_SYSTEMS_JSON: String = TERMINOLOGY_SYSTEMS_FOLDER + File.separator + "terminology-systems.json"
/**
* Returns the path for the JSON file keeping the terminology systems
*
* @param terminologySystemFolder
* @return
*/
def getTerminologySystemsJsonPath(terminologySystemFolder: String): String = {
terminologySystemFolder + File.separator + "terminology-systems.json"
}
}
Loading