in nlpcraft/src/main/scala/org/apache/nlpcraft/internal/util/NCUtils.scala [52:333]
def sysEnv(s: String): Option[String] = sysProps.get(s).orElse(sys.env.get(s))
/**
* Shortcut to convert given JSON to Scala map with default mapping.
*
* @param json JSON to convert.
*/
@throws[Exception]
def jsonToScalaMap(json: String): Map[String, Object] =
GSON.fromJson(json, classOf[java.util.HashMap[String, Object]]).asScala.toMap
/**
* Shortcut to convert given JSON to Java map with default mapping.
*
* @param json JSON to convert.
*/
def jsonToJavaMap(json: String): java.util.Map[String, Object] =
try GSON.fromJson(json, classOf[java.util.HashMap[String, Object]])
catch case e: Exception => E(s"Cannot deserialize JSON to map: '$json'", e)
/**
* Gets now in UTC timezone in milliseconds representation.
*/
def nowUtcMs(): Long = Instant.now().toEpochMilli
/**
* Shortcut - current timestamp in milliseconds.
*/
def now(): Long = System.currentTimeMillis()
/**
* Trims each sequence string and filters out empty ones.
*
* @param s String to process.
*/
private def trimFilter(s: Seq[String]): Seq[String] = s.map(_.strip).filter(_.nonEmpty)
/**
* Splits, trims and filters empty strings for the given string.
*
* @param s String to split.
* @param sep Separator (regex) to split by.
*/
def splitTrimFilter(s: String, sep: String): Seq[String] =
trimFilter(s.split(sep).toIndexedSeq)
/**
* Recursively removes quotes from given string.
*
* @param s
*/
@tailrec
def trimQuotes(s: String): String =
val z = s.strip
if z.startsWith("'") && z.endsWith("'") || z.startsWith("\"") && z.endsWith("\"") then
trimQuotes(z.substring(1, z.length - 1))
else
z
/**
* Recursively removes quotes and replaces escaped quotes from given string.
*
* @param s
*/
@tailrec
private def trimEscapesQuotes(s: String): String =
val z = s.strip
if z.nonEmpty then
if z.head == '\'' && z.last == '\'' then
trimEscapesQuotes(z.substring(1, z.length - 1).replace("\'", "'"))
else if z.head == '"' && z.last == '"' then
trimEscapesQuotes(z.substring(1, z.length - 1).replace("\\\"", "\""))
else
z
else
z
/**
* Recursively removes quotes and replaces escaped quotes from given string.
*
* @param s
*/
@tailrec
def escapesQuotes(s: String): String =
if s.nonEmpty then
if s.head == '\'' && s.last == '\'' then
escapesQuotes(s.substring(1, s.length - 1).replace("\'", "'"))
else if s.head == '"' && s.last == '"' then
escapesQuotes(s.substring(1, s.length - 1).replace("\\\"", "\""))
else
s
else
s
/**
* Makes thread.
*
* @param name Name.
* @param body Thread body.
*/
def mkThread(name: String)(body: Thread => Unit): Thread =
new Thread(name):
@volatile private var stopped = false
override def isInterrupted: Boolean = super.isInterrupted || stopped
override def interrupt(): Unit =
stopped = true
super.interrupt()
override def run(): Unit =
logger.trace(s"Thread started: $name")
try
body(this)
logger.trace(s"Thread exited: $name")
catch
case _: InterruptedException => logger.trace(s"Thread interrupted: $name")
case e: Throwable => logger.warn(s"Unexpected error during '$name' thread execution:", e)
finally
stopped = true
/**
*
* @param prefix
* @param mdlId
* @param body
*/
def mkThread(prefix: String, mdlId: String)(body: Thread => Unit): Thread = mkThread(s"$prefix-@$mdlId")(body)
/**
* Gets resource existing flag.
*
* @param res Resource.
*/
def isResource(res: String): Boolean = getClass.getClassLoader.getResourceAsStream(res) != null
/**
*
* @param url URL to check.
*/
def isUrl(url: String): Boolean =
try
new URL(url)
true
catch
case _: MalformedURLException => false
/**
*
* @param path Local file path to check.
*/
def isFile(path: String): Boolean =
val f = new File(path)
f.exists() && f.isFile
/**
*
* @param f
*/
def isFile(f: File): Boolean = f.exists() && f.isFile
/**
*
* @param src Local filesystem path, resources file or URL.
*/
def getStream(src: String): InputStream =
if isFile(src) then new FileInputStream(new File(src))
else if isResource(src) then
getClass.getClassLoader.getResourceAsStream(src) match
case in if in != null => in
case _ => E(s"Resource not found: $src")
else if isUrl(src) then new URL(src).openStream()
else E(s"Source not found or unsupported: $src")
/**
* Interrupts thread and waits for its finish.
*
* @param t Thread.
*/
def stopThread(t: Thread): Unit =
if t != null then
t.interrupt()
try t.join()
catch case _: InterruptedException => logger.trace("Thread joining was interrupted (ignoring).")
/**
* Checks duplicated elements in collection.
*
* @param list Collection. Note, it should be list.
* @param seen Checked elements.
* @see #getDups
*/
@tailrec
def containsDups[T](list: List[T], seen: Set[T] = Set.empty[T]): Boolean =
list match
case x :: xs => if seen.contains(x) then true else containsDups(xs, seen + x)
case _ => false
/**
* Gets set of duplicate values from given sequence (potentially empty).
*
* @param seq Sequence to check for dups from.
* @tparam T
* @see #containsDups
*/
def getDups[T](seq: Seq[T]): Set[T] = seq.diff(seq.distinct).toSet
/**
* Gets a sequence without dups. It works by checking for dups first, before creating a new
* sequence if dups are found. It's more efficient when dups are rare.
*
* @param seq Sequence with potential dups.
*/
def distinct[T](seq: List[T]): List[T] = if containsDups(seq) then seq.distinct else seq
/**
*
* @param s
*/
def decapitalize(s: String): String = s"${s.head.toLower}${s.tail}"
/**
*
* @param s
*/
def capitalize(s: String): String = s"${s.head.toUpper}${s.tail}"
/**
* Makes absolute path starting from working directory.
*
* @param path Path.
*/
def mkPath(path: String): String = new File(s"${new File("").getAbsolutePath}/$path").getAbsolutePath
/**
* Generates read-only text file with given path and strings.
* Used by text files auto-generators.
*
* @param path Path of the output file.
* @param lines Text data.
* @param sort Whether to sort output or not.
*/
def mkTextFile(path: String, lines: scala.Iterable[Any], sort: Boolean = true): Unit =
val file = new File(path)
Using.resource(new PrintStream(file)) {
ps =>
import java.util.*
// Could be long for large sequences...
val seq = if sort then lines.map(_.toString).toSeq.sorted else lines
ps.println(s"#")
ps.println(s"# Licensed to the Apache Software Foundation (ASF) under one or more")
ps.println(s"# contributor license agreements. See the NOTICE file distributed with")
ps.println(s"# this work for additional information regarding copyright ownership.")
ps.println(s"# The ASF licenses this file to You under the Apache License, Version 2.0")
ps.println(s"# (the 'License'); you may not use this file except in compliance with")
ps.println(s"# the License. You may obtain a copy of the License at")
ps.println(s"#")
ps.println(s"# https://www.apache.org/licenses/LICENSE-2.0")
ps.println(s"#")
ps.println(s"# Unless required by applicable law or agreed to in writing, software")
ps.println(s"# distributed under the License is distributed on an 'AS IS' BASIS,")
ps.println(s"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.")
ps.println(s"# See the License for the specific language governing permissions and")
ps.println(s"# limitations under the License.")
ps.println(s"#")
ps.println(s"# Auto-generated on: ${new Date()}")
ps.println(s"# Total lines: ${seq.size}")
ps.println(s"#")
ps.println(s"# +-------------------------+")
ps.println(s"# | DO NOT MODIFY THIS FILE |")
ps.println(s"# +-------------------------+")
ps.println(s"#")
ps.println()
seq.foreach(ps.println)
// Make the file as read-only.
file.setWritable(false, false)
}