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

com.metamx.tranquility.config.TranquilityConfig.scala Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to Metamarkets Group Inc. (Metamarkets) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  Metamarkets licenses this file
 * to you 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.metamx.tranquility.config

import com.metamx.common.IAE
import com.metamx.common.scala.Predef._
import com.metamx.common.scala.Yaml
import com.metamx.common.scala.collection.implicits._
import com.metamx.common.scala.untyped._
import java.io.InputStream
import scala.collection.JavaConverters._

case class TranquilityConfig[ConfigType <: PropertiesBasedConfig](
  globalConfig: ConfigType,
  dataSourceConfigs: Map[String, DataSourceConfig[ConfigType]]
)
{
  validate()

  def getDataSources: java.util.List[String] = {
    dataSourceConfigs.keys.toIndexedSeq.asJava
  }

  def getDataSource(dataSource: String): DataSourceConfig[ConfigType] = {
    dataSourceConfigs.getOrElse(dataSource, null)
  }

  private def validate(): Unit = {
    for ((dataSource, config) <- dataSourceConfigs) {
      require(
        dataSource == config.dataSource,
        "dataSource key[%s] must match value[%s]" format(dataSource, config.dataSource)
      )
    }
  }
}

object TranquilityConfig
{
  def read[ConfigType <: PropertiesBasedConfig](
    in: InputStream,
    clazz: Class[ConfigType]
  ): TranquilityConfig[ConfigType] =
  {
    val yaml = in.withFinally(_.close()) { in =>
      dict(Yaml.load(in))
    }

    val globalProperties = getAsDict(yaml, "properties")
    val globalConfig = PropertiesBasedConfig.fromDict(globalProperties, clazz)

    val dataSources: Dict = getDataSourcesUntyped(yaml)
    val dataSourceConfigs: Map[String, DataSourceConfig[ConfigType]] = for ((dataSource, x) <- dataSources) yield {
      val d = dict(x)
      val dataSourceProperties = getAsDict(d, "properties")
      for (k <- globalConfig.globalPropertyNames) {
        require(!dataSourceProperties.contains(k), s"Property '$k' cannot be per-dataSource (found in[$dataSource]).")
      }

      val dataSourceSpec = getAsDict(d, "spec")
      val dataSourcePropertiesBasedConfig = PropertiesBasedConfig.fromDict(
        globalProperties ++ dataSourceProperties,
        clazz
      )

      (dataSource, DataSourceConfig(dataSource, dataSourcePropertiesBasedConfig, dataSourceSpec))
    }

    TranquilityConfig(globalConfig, dataSourceConfigs)
  }

  def read(
    in: InputStream
  ): TranquilityConfig[PropertiesBasedConfig] =
  {
    read(in, classOf[PropertiesBasedConfig])
  }

  private def getAsDict(d: Dict, k: String): Dict = {
    Option(d.getOrElse(k, null)).map(dict(_)).getOrElse(Dict())
  }

  private def getDataSourcesUntyped[ConfigType <: PropertiesBasedConfig](
    yaml: Dict
  ): Map[String, Dict] =
  {
    val dataSourcesUntyped: Map[String, Dict] = Option(yaml.getOrElse("dataSources", null)).map(normalize(_)) match {
      case None =>
        Map.empty

      case Some(d: Map[_, _]) =>
        dict(d).strictMapValues(dict(_))

      case Some(ds: Seq[_]) =>
        (ds.map(dict(_)) map { d =>
          val dataSourceName = try {
            str(getAsDict(getAsDict(d, "spec"), "dataSchema")("dataSource"))
          }
          catch {
            case e: Exception =>
              throw new IAE(e, "Missing 'spec' -> 'dataSchema' -> 'dataSource' for one of the dataSources")
          }
          dataSourceName -> d
        }).toMap

      case Some(x) =>
        throw new IAE(s"dataSources must be a list or map")
    }

    dataSourcesUntyped
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy