All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.folio_sec.reladomo.scala_api.configuration.DatabaseManager.scala Maven / Gradle / Ivy

/*
 * Copyright 2017 FOLIO Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.folio_sec.reladomo.scala_api.configuration

import java.io.InputStream

import com.folio_sec.reladomo.scala_api.exception.ReladomoConfigurationException
import com.folio_sec.reladomo.scala_api.util.LoanPattern
import com.gs.fw.common.mithra.MithraManagerProvider
import com.gs.fw.common.mithra.mithraruntime._
import org.slf4j.LoggerFactory

import scala.collection.JavaConverters._

object DatabaseManager extends DatabaseManager {}

trait DatabaseManager {

  private[this] val logger = LoggerFactory.getLogger(classOf[DatabaseManager])

  private[this] var allowReloadingRuntimeConfig: Boolean = false

  private[this] val loadedConfig = new scala.collection.mutable.ListBuffer[String]()

  private[this] var currentRuntimeType: Option[MithraRuntimeType] = None

  def loadRuntimeConfig(runtimeConfigXmlClasspath: String): Unit = {
    if (loadedConfig.contains(runtimeConfigXmlClasspath)) {
      if (allowReloadingRuntimeConfig) {
        forciblyLoadRuntimeConfig(runtimeConfigXmlClasspath)
      } else {
        logger.info(
          s"The RuntimeConfig.xml (${runtimeConfigXmlClasspath}) is already loaded. If you'd like to reload the configuration runtime, " +
          "set DatabaseManager#allowReloadingRuntimeConfig as true."
        )
      }
    } else {
      forciblyLoadRuntimeConfig(runtimeConfigXmlClasspath)
    }
  }

  def currentMithraRuntime: Option[MithraRuntimeType] = currentRuntimeType

  def connectionManager(name: String): Option[ConnectionManagerType] = {
    currentMithraRuntime match {
      case Some(runtime) =>
        runtime.getConnectionManagers.asScala.find(
          _.getProperties.asScala.exists(
            prop => prop.getName == "connectionManagerName" && prop.getValue == name
          )
        )
      case _ => None
    }
  }

  def connectionManagerMaxSize(name: String): Option[Int] = {
    for {
      connManager <- connectionManager(name)
      maxPoolSize <- connManager.getProperties.asScala.find(_.getName == "maxPoolSize").map(_.getValue.toInt)
    } yield {
      maxPoolSize
    }
  }

  // ----------------------------------------------
  // private methods

  private[this] def forciblyLoadRuntimeConfig(runtimeConfigXmlClasspath: String): Unit = {
    val globalMithraManager = MithraManagerProvider.getMithraManager
    LoanPattern.using(loadClasspathResourceAsInputStream(runtimeConfigXmlClasspath)) { (configStream: InputStream) =>
      currentRuntimeType.synchronized {
        logger.info(s"Loading the runtime config file: ${runtimeConfigXmlClasspath} ...")
        val configManager = globalMithraManager.getConfigManager
        val runtimeType   = configManager.parseConfiguration(configStream)
        currentRuntimeType = Some(runtimeType)
        runtimeType.getConnectionManagers.asScala.foreach { connMgr =>
          connMgr.getProperties.asScala.find(_.getName == RuntimeConfigKeys.PARENT_CONFIG_LOCATION) match {
            case Some(location) =>
              mergeAbsentValuesFromParent(connMgr, location.getValue)
            case _ =>
          }
          configManager.initializeRuntime(runtimeType)
        }
      }
    }
  }

  private[this] def mergeAbsentValuesFromParent(childConnManager: ConnectionManagerType, parentPath: String): Unit = {
    logger.info(s"Loading a parent runtime config file: ${parentPath} ...")

    val CONFIG_MANAGER = MithraManagerProvider.getMithraManager.getConfigManager
    val parent = LoanPattern.using(loadClasspathResourceAsInputStream(parentPath)) { inputStream =>
      CONFIG_MANAGER.parseConfiguration(inputStream)
    }
    parent.getConnectionManagers.size match {
      case 1 =>
        val parentConnManager = parent.getConnectionManagers.get(0)
        parentConnManager.getProperties.asScala
          .find(_.getName == RuntimeConfigKeys.PARENT_CONFIG_LOCATION) match {
          case Some(location) => mergeAbsentValuesFromParent(parentConnManager, location.getValue)
          case _              =>
        }

        if (parentConnManager.getClassName != childConnManager.getClassName) {
          throw new ReladomoConfigurationException(
            s"ConnectionManager#className in ${parentPath} must be consistent with its child config files"
          )
        } else {
          if (childConnManager.getLoadOperationProvider == null) {
            childConnManager.setLoadOperationProvider(parentConnManager.getLoadOperationProvider)
          }
          if (childConnManager.getReplicationSchemaName == null) {
            childConnManager.setReplicationSchemaName(parentConnManager.getReplicationSchemaName)
          }
          val existingPropNames = childConnManager.getProperties.asScala.map(_.getName)
          parentConnManager.getProperties.asScala.foreach { prop =>
            if (existingPropNames.exists(_ == prop.getName) == false) {
              childConnManager.getProperties.add(prop)
            }
          }
          val existingSchemaNames = childConnManager.getSchemas.asScala.map(_.getName)
          parentConnManager.getSchemas.asScala.foreach { schema =>
            if (existingSchemaNames.exists(_ == schema.getName) == false) {
              childConnManager.getSchemas.add(schema)
            }
          }
          val existingObjConfigClassNames = childConnManager.getMithraObjectConfigurations.asScala.map(_.getClassName)
          parentConnManager.getMithraObjectConfigurations.asScala.foreach { parentObjConfig =>
            if (existingObjConfigClassNames.exists(_ == parentObjConfig.getClassName) == false) {
              childConnManager.getMithraObjectConfigurations.add(parentObjConfig)
            }
          }
          val existingTempObjConfigClassNames =
            childConnManager.getMithraTemporaryObjectConfigurations.asScala.map(_.getClassName)
          parentConnManager.getMithraTemporaryObjectConfigurations.asScala.foreach { parentObjConfig =>
            if (existingTempObjConfigClassNames.exists(_ == parentObjConfig.getClassName) == false) {
              childConnManager.getMithraTemporaryObjectConfigurations.add(parentObjConfig)
            }
          }
        }

      case _ => throw new ReladomoConfigurationException(s"${parentPath} must have a single ConnectionManager")
    }
  }

  private[this] def loadClasspathResourceAsInputStream(filePath: String): InputStream = {
    val stream = getClass.getClassLoader.getResourceAsStream(filePath)
    if (stream == null) throw new Exception("Failed to locate " + filePath + " in classpath")
    else stream
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy