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

com.stratio.datasource.util.Config.scala Maven / Gradle / Ivy

/**
 * Copyright (C) 2015 Stratio (http://stratio.com)
 *
 * 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.stratio.datasource.util

import com.stratio.datasource.util.Config.Property

import scala.reflect.ClassTag

/**
 * Abstract config builder, used to set a bunch of properties a build
 * a config object from them.
 *
 * @param properties Map of any-type properties.
 * @tparam Builder Current Builder implementation type.
 */
abstract class ConfigBuilder[Builder<:ConfigBuilder[Builder] ](
  val properties: Map[Property,Any] = Map()) extends Serializable { builder =>

  /**
   * Required properties to build a Mongo config object.
   * At build time, if these properties are not set, an assert
   * exception will be thrown.
   */
  val requiredProperties: List[Property]

  /**
   * Instantiate a brand new Builder from given properties map
   *
   * @param props Map of any-type properties.
   * @return The new builder
   */
  def apply(props: Map[Property,Any]): Builder

  /**
   * Set (override if exists) a single property value given a new one.
   *
   * @param property Property to be set
   * @param value New value for given property
   * @tparam T Property type
   * @return A new builder that includes new value of the specified property
   */
  def set[T](property: Property, value: T): Builder =
    apply(properties + (property -> value))

  /**
   * Build the config object from current builder properties.
   *
   * @return The Mongo configuration object.
   */
  def build(): Config = new Config {

    // TODO Review when refactoring config
    val properties = builder.properties.map { case (k, v) => k.toLowerCase -> v }
    val reqProperties = requiredProperties.map(_.toLowerCase)

    require(
      reqProperties.forall(properties.isDefinedAt),
      s"Not all properties are defined! : ${
        reqProperties.diff(
          properties.keys.toList.intersect(requiredProperties))
      }")

    /**
     * Compare if two Configs have the same properties.
     * @param other Object to compare
     * @return Boolean
     */
    override def equals(other: Any): Boolean = other match {
      case that: Config =>
        properties == that.properties
      case _ => false
    }

    override def hashCode(): Int = {
      val state = Seq(properties)
      state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b)
    }

  }

}

/**
 * Mongo standard configuration object
 */
trait Config extends Serializable {

  /**
   * Contained properties in configuration object
   */
  val properties: Map[Property, Any]

  /**  Returns the value associated with a key, or a default value if the key is not contained in the configuration object.

   *   @param   key Desired property.
   *   @param   default Value in case no binding for `key` is found in the map.
   *   @tparam  T Result type of the default computation.
   *   @return  the value associated with `key` if it exists,
   *            otherwise the result of the `default` computation.
   */
  def getOrElse[T](key: Property, default: => T): T =
    properties.get(key.toLowerCase) collect { case v: T => v } getOrElse default

  /**
   * Gets specified property from current configuration object
   * @param property Desired property
   * @tparam T Property expected value type.
   * @return An optional value of expected type
   */
  def get[T: ClassTag](property: Property): Option[T] =
    properties.get(property.toLowerCase).map(_.asInstanceOf[T])

  /**
   * Gets specified property from current configuration object.
   * It will fail if property is not previously set.
   * @param property Desired property
   * @tparam T Property expected value type
   * @return Expected type value
   */
  def apply[T: ClassTag](property: Property): T = {
    get[T](property).get
  }

}

object Config {

  type Property = String

  /**
   * Defines how to act in case any parameter is not set
   * @param key Key that couldn't be obtained
   * @tparam T Expected type (used to fit in 'getOrElse' cases).
   * @return Throws an IllegalStateException.
   */
  def notFound[T](key: String): T =
    throw new IllegalStateException(s"Parameter $key not specified")

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy