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

ai.lum.common.ConfigFactory.scala Maven / Gradle / Ivy

/*
 * Copyright (C) 2009-2019 Lightbend Inc. 
 *
 * 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 ai.lum.common

import java.io.File
import java.util.Properties
import java.util.{ Map => JMap }
import scala.collection.JavaConverters._
import com.typesafe.config._
import com.typesafe.config.{ ConfigFactory => TypesafeConfigFactory }
import com.typesafe.config.impl.ConfigImpl

object ConfigFactory {

  /**
   * Returns an empty Configuration object.
   */
  def empty = TypesafeConfigFactory.empty()

  /**
   * Returns the reference configuration object.
   */
  def reference = TypesafeConfigFactory.defaultReference()

  /**
   * Create a new Configuration from the given key-value pairs.
   */
  def from(data: (String, Any)*): Config = from(data.toMap)

  /**
   * Create a new Configuration from the data passed as a Map.
   */
  def from(data: Map[String, Any]): Config = {

    def toJava(data: Any): Any = data match {
      case map: Map[_, _]        => map.mapValues(toJava).toMap.asJava
      case iterable: Iterable[_] => iterable.map(toJava).asJava
      case v                     => v
    }

    TypesafeConfigFactory.parseMap(toJava(data).asInstanceOf[JMap[String, Any]])

  }

  /**
   * Create a new Configuration from the given properties.
   */
  def from(properties: Properties): Config = {
    // Iterating through the system properties is prone to ConcurrentModificationExceptions
    // Typesafe config maintains a cache for this purpose.  So, if the passed in properties *are* the system
    // properties, use the Typesafe config cache, otherwise it should be safe to parse it ourselves.
    if (properties eq System.getProperties) {
      ConfigImpl.systemPropertiesAsConfig()
    } else {
      TypesafeConfigFactory.parseProperties(properties)
    }
  }

  /**
   * Load a new Configuration.
   */
  def load(
    classLoader: ClassLoader = getClass().getClassLoader(),
    properties: Properties = System.getProperties(),
    directSettings: Map[String, Any] = Map.empty,
    allowMissingApplicationConf: Boolean = true
  ): Config = {

    // Get configuration from the system properties.
    val systemPropertyConfig = from(properties)

    // Inject our direct settings into the config.
    val directConfig: Config = from(directSettings)

    // Resolve application.conf ourselves because:
    // - we may want to load configuration when application.conf is missing.
    // - We also want to delay binding and resolving reference.conf, which
    //   is usually part of the default application.conf loading behavior.
    // - We want to read config.file and config.resource settings from our
    //   own properties and directConfig rather than system properties.
    val applicationConfig: Config = {
      def setting(key: String): Option[Any] = {
        directSettings.get(key).orElse(Option(properties.getProperty(key)))
      }
      {
        setting("config.resource").map(resource => TypesafeConfigFactory.parseResources(classLoader, resource.toString))
      }.orElse {
        setting("config.file").map(fileName => TypesafeConfigFactory.parseFileAnySyntax(new File(fileName.toString)))
      }.getOrElse {
        val parseOptions = ConfigParseOptions.defaults
          .setClassLoader(classLoader)
          .setAllowMissing(allowMissingApplicationConf)
        TypesafeConfigFactory.defaultApplication(parseOptions)
      }
    }

    // Resolve reference.conf ourselves because ConfigFactory.defaultReference resolves values.
    val referenceConfig: Config = TypesafeConfigFactory.parseResources(classLoader, "reference.conf")

    // Combine all the config together into one big config
    val combinedConfig: Config = Seq(
      systemPropertyConfig,
      directConfig,
      applicationConfig,
      referenceConfig
    ).reduceLeft(_.withFallback(_))

    // Resolve settings. Default settings in referenceConfig,
    // can now be substituted with values in applicationConfig.
    val resolvedConfig = combinedConfig.resolve

    resolvedConfig

  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy