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

com.andrewmccall.faker.yaml.YamlData.scala Maven / Gradle / Ivy

The newest version!
package com.andrewmccall.faker.yaml

import java.io.{File, FileReader}

import com.andrewmccall.faker.{Data, Entry, Faker, SeqEntry, StringEntry}
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.scala.Logging
import org.yaml.snakeyaml.Yaml

import scala.annotation.tailrec
import scala.collection.JavaConverters._

class YamlData(data: Map[String, Any]) extends Data with Logging {

  def this() = {
    this(YamlData.load())
  }

  override def fetch(key: String, locale: Option[String] = None, defaultLocale: String = Faker.defaultLocale): Option[Entry] = {
    logger.debug(s"Fetching key $key")
    Some(fetchIn("\\.".r.split(key), data))
  }

  override def contains(key: String, locale: Option[String] = None, defaultLocale: String = Faker.defaultLocale) : Boolean = {
    containKeys("\\.".r.split(key))
  }

  @tailrec
  private[faker] final def containKeys(key: Seq[String], data: Map[String, Any] = this.data): Boolean = {
    if (!data.contains(key.head)) false
    else if (data.contains(key.head) && key.size == 1) true
    else {
      val value: Any = data(key.head)
      val subMap: Map[String, Any] = value match {
        case j: java.util.Map[String, _] => j.asScala.toMap
        case m: Map[String, Any] => m
        case _ => return false
      }
      containKeys(key.drop(1), subMap)
    }
  }

  @tailrec
  private[yaml] final def fetchIn(key: Array[String], data: Map[String, Any]): Entry = {
    val value: Any = data(key.head)
    if (key.length == 1)
      value match {
        case l: java.util.List[String] => SeqEntry(l.asScala)
        case _ => StringEntry(value.asInstanceOf[String])
      }
    else {
      val values = value match {
        case m: java.util.Map[String, _] => m.asScala.toMap
        case _ => value.asInstanceOf[Map[String, Any]]
      }
      fetchIn(key.drop(1), values)
    }
  }

  /**
    * Fetches any sub-keys for a key in this data.
    *
    * @param key
    * @return
    */
  override def getKeys(): Iterable[String] = data.keys
}

object YamlData {

  private val logger = LogManager.getLogger(getClass)

  def load(): Map[String, Any] = {
    def yaml = new Yaml()

    val files = getFilesForClass(this.getClass, "com/andrewmccall/faker/locales")

    logger.debug(s"Loading keys from ${files.length} files")
    if (logger.isDebugEnabled()) files.foreach(logger.debug)

    val data = files.map(x => {
      yaml.load(new FileReader(x)).asInstanceOf[java.util.Map[String, Any]].asScala.toMap
    })

    data.reduce(merge)
  }

  private[yaml] def merge(one: Map[String, Any], two: Map[String, Any]): Map[String, Any] = {
    val keys = one.keySet ++ two.keySet
    keys.foldLeft(Map.empty[String, Any])((r: Map[String, Any], k: String) => mergeForKey(k, r, one, two))
  }

  private[yaml] def mergeForKey(k: String, r: Map[String, Any], one: Map[String, Any], two: Map[String, Any]): Map[String, Any] = {
    // if the key isn't in one, just use two.

    if (!one.contains(k)) r + (k -> two(k))
    else if (!two.contains(k)) r + (k -> one(k))
    else {
      one(k) match {
        case m: Map[String, _] => two(k) match {
          case m: Map[String, _] => r + (k -> merge(one(k).asInstanceOf[Map[String, Any]], two(k).asInstanceOf[Map[String, Any]]))
          case u: java.util.Map[String, _] =>
            r + (k -> merge(one(k).asInstanceOf[Map[String, Any]], two(k).asInstanceOf[java.util.Map[String, Any]].asScala.toMap))
          case _ => r + (k -> one(k))
        }
        case m: java.util.Map[_, _] => two(k) match {
          case m: Map[String, _] => r + (k -> merge(one(k).asInstanceOf[java.util.Map[String, Any]].asScala.toMap, two(k).asInstanceOf[Map[String, Any]]))
          case u: java.util.Map[String, _] =>
            r + (k -> merge(one(k).asInstanceOf[java.util.Map[String, Any]].asScala.toMap, two(k).asInstanceOf[java.util.Map[String, Any]].asScala.toMap))

        }
        case _ => two(k) match {
          case m: Map[String, _] => r + (k -> two(k))
          case _ => r + (k -> one(k))
        }
      }
    }
  }

  private[yaml] def getFilesForClass(caller: Class[_], path: String): Array[String] = {

    import java.net.URISyntaxException
    import java.util.jar.JarFile

    val jarFile = new File(caller.getProtectionDomain.getCodeSource.getLocation.getPath)

    if (jarFile.isFile) { // Run with JAR file
      val jar = new JarFile(jarFile)
      val entries = jar.entries //gives ALL entries in jar
      import scala.collection.JavaConverters._
      val newFiles = entries.asScala.filter(_.getName.startsWith(path + "/")).filter(_.getName.endsWith(".yml")).map(_.getName)
      jar.close()
      newFiles.toArray
    }
    else { // Run with IDE
      val url = classOf[YamlData].getResource("/" + path)
      if (url != null) try {
        val apps = new File(url.toURI).listFiles()
        apps.filter(f => f.isFile && (f.getName.endsWith(".yml") || f.getName.endsWith("yaml"))).map(_.getPath) ++ apps.filter(_.isDirectory).flatMap(d => getFilesForClass(caller, path + "/" + d.getName))

      }
      catch {
        case ex: URISyntaxException =>
          // never happens
          Array.empty[String]
      } else Array.empty[String]
    }

  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy