org.ekrich.config.impl.SimpleIncluder.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sconfig_sjs1.0-RC2_2.13 Show documentation
Show all versions of sconfig_sjs1.0-RC2_2.13 Show documentation
Configuration library for Scala using HOCON files
The newest version!
/**
* Copyright (C) 2011-2012 Typesafe Inc.
*/
package org.ekrich.config.impl
import java.io.File
import java.net.MalformedURLException
import java.net.URL
import java.{util => ju}
import scala.jdk.CollectionConverters._
import org.ekrich.config.ConfigException
import org.ekrich.config.ConfigFactory
import org.ekrich.config.ConfigIncludeContext
import org.ekrich.config.ConfigIncluder
import org.ekrich.config.ConfigIncluderClasspath
import org.ekrich.config.ConfigIncluderFile
import org.ekrich.config.ConfigIncluderURL
import org.ekrich.config.ConfigObject
import org.ekrich.config.ConfigParseOptions
import org.ekrich.config.ConfigParseable
import org.ekrich.config.ConfigSyntax
object SimpleIncluder {
// ConfigIncludeContext does this for us on its options
private[impl] def clearForInclude(options: ConfigParseOptions) = {
// the class loader and includer are inherited, but not this other
// stuff.
options
.setSyntax(null)
.setOriginDescription(null)
.setAllowMissing(true)
}
// the heuristic includer in static form
private[impl] def includeWithoutFallback(
context: ConfigIncludeContext,
name: String
) = {
// the heuristic is valid URL then URL, else relative to including file;
// relativeTo in a file falls back to classpath inside relativeTo().
var url: URL = null
try url = new URL(name)
catch {
case e: MalformedURLException =>
url = null
}
if (url != null) includeURLWithoutFallback(context, url)
else {
val source =
new RelativeNameSource(context)
fromBasename(source, name, context.parseOptions)
}
}
private[impl] def includeURLWithoutFallback(
context: ConfigIncludeContext,
url: URL
) =
ConfigFactory.parseURL(url, context.parseOptions).root
private[impl] def includeFileWithoutFallback(
context: ConfigIncludeContext,
file: File
) =
ConfigFactory.parseFileAnySyntax(file, context.parseOptions).root
private[impl] def includeResourceWithoutFallback(
context: ConfigIncludeContext,
resource: String
) =
ConfigFactory
.parseResourcesAnySyntax(resource, context.parseOptions)
.root
private[impl] trait NameSource {
def nameToParseable(
name: String,
parseOptions: ConfigParseOptions
): ConfigParseable
}
private[impl] class RelativeNameSource private[impl] (
val context: ConfigIncludeContext
) extends SimpleIncluder.NameSource {
override def nameToParseable(
name: String,
options: ConfigParseOptions
): ConfigParseable = {
val p = context.relativeTo(name)
if (p == null) { // avoid returning null
Parseable.newNotFound(
name,
"include was not found: '" + name + "'",
options
)
} else p
}
}
// this function is a little tricky because there are three places we're
// trying to use it; for 'include "basename"' in a .conf file, for
// loading app.{conf,json,properties} from classpath, and for
// loading app.{conf,json,properties} from the filesystem.
private[impl] def fromBasename(
source: SimpleIncluder.NameSource,
name: String,
options: ConfigParseOptions
) = {
var obj: ConfigObject = null
if (name.endsWith(".conf") || name.endsWith(".json") || name.endsWith(
".properties"
)) {
val p = source.nameToParseable(name, options)
obj = p.parse(p.options().setAllowMissing(options.getAllowMissing))
} else {
val confHandle =
source.nameToParseable(name + ".conf", options)
val jsonHandle =
source.nameToParseable(name + ".json", options)
val propsHandle =
source.nameToParseable(name + ".properties", options)
var gotSomething = false
val fails = new ju.ArrayList[ConfigException.IO]
val syntax = options.getSyntax
obj = SimpleConfigObject.empty(SimpleConfigOrigin.newSimple(name))
if (syntax == null || (syntax eq ConfigSyntax.CONF)) try {
obj = confHandle.parse(
confHandle
.options()
.setAllowMissing(false)
.setSyntax(ConfigSyntax.CONF)
)
gotSomething = true
} catch {
case e: ConfigException.IO =>
fails.add(e)
}
if (syntax == null || (syntax eq ConfigSyntax.JSON)) try {
val parsed = jsonHandle.parse(
jsonHandle
.options()
.setAllowMissing(false)
.setSyntax(ConfigSyntax.JSON)
)
obj = obj.withFallback(parsed)
gotSomething = true
} catch {
case e: ConfigException.IO =>
fails.add(e)
}
if (syntax == null || (syntax eq ConfigSyntax.PROPERTIES)) try {
val parsed = propsHandle.parse(
propsHandle
.options()
.setAllowMissing(false)
.setSyntax(ConfigSyntax.PROPERTIES)
)
obj = obj.withFallback(parsed)
gotSomething = true
} catch {
case e: ConfigException.IO =>
fails.add(e)
}
if (!options.getAllowMissing && !gotSomething) {
if (ConfigImpl.traceLoadsEnabled) {
// the individual exceptions should have been logged already with tracing enabled
ConfigImpl.trace(
"Did not find '" + name + "' with any extension (.conf, .json, .properties); " + "exceptions should have been logged above."
)
}
if (fails.isEmpty) { // this should not happen
throw new ConfigException.BugOrBroken(
"should not be reached: nothing found but no exceptions thrown"
)
} else {
val sb = new StringBuilder
for (t <- fails.asScala) {
sb.append(t.getMessage)
sb.append(", ")
}
sb.setLength(sb.length - 2)
throw new ConfigException.IO(
SimpleConfigOrigin.newSimple(name),
sb.toString,
fails.get(0)
)
}
} else if (!gotSomething)
if (ConfigImpl.traceLoadsEnabled)
ConfigImpl.trace(
"Did not find '" + name + "' with any extension (.conf, .json, .properties); but '" + name + "' is allowed to be missing. Exceptions from load attempts should have been logged above."
)
}
obj
}
// the Proxy is a proxy for an application-provided includer that uses our
// default implementations when the application-provided includer doesn't
// have an implementation.
private[impl] class Proxy private[impl] (val delegater: ConfigIncluder)
extends FullIncluder {
override def withFallback(fallback: ConfigIncluder): ConfigIncluder = { // we never fall back
this
}
override def include(
context: ConfigIncludeContext,
what: String
): ConfigObject =
delegater.include(context, what)
override def includeResources(
context: ConfigIncludeContext,
what: String
): ConfigObject =
if (delegater.isInstanceOf[ConfigIncluderClasspath])
delegater
.asInstanceOf[ConfigIncluderClasspath]
.includeResources(context, what)
else includeResourceWithoutFallback(context, what)
override def includeURL(
context: ConfigIncludeContext,
what: URL
): ConfigObject =
if (delegater.isInstanceOf[ConfigIncluderURL])
delegater
.asInstanceOf[ConfigIncluderURL]
.includeURL(context, what)
else includeURLWithoutFallback(context, what)
override def includeFile(
context: ConfigIncludeContext,
what: File
): ConfigObject =
if (delegater.isInstanceOf[ConfigIncluderFile])
delegater
.asInstanceOf[ConfigIncluderFile]
.includeFile(context, what)
else includeFileWithoutFallback(context, what)
}
private[impl] def makeFull(includer: ConfigIncluder) =
if (includer.isInstanceOf[FullIncluder])
includer.asInstanceOf[FullIncluder]
else new SimpleIncluder.Proxy(includer)
}
class SimpleIncluder private[impl] (var fallback: ConfigIncluder)
extends FullIncluder {
// this is the heuristic includer
override def include(
context: ConfigIncludeContext,
name: String
): ConfigObject = {
val obj = SimpleIncluder.includeWithoutFallback(context, name)
// now use the fallback includer if any and merge
// its result.
if (fallback != null) obj.withFallback(fallback.include(context, name))
else obj
}
override def includeURL(
context: ConfigIncludeContext,
url: URL
): ConfigObject = {
val obj =
SimpleIncluder.includeURLWithoutFallback(context, url)
if (fallback != null && fallback.isInstanceOf[ConfigIncluderURL])
obj.withFallback(
fallback.asInstanceOf[ConfigIncluderURL].includeURL(context, url)
)
else obj
}
override def includeFile(
context: ConfigIncludeContext,
file: File
): ConfigObject = {
val obj =
SimpleIncluder.includeFileWithoutFallback(context, file)
if (fallback != null && fallback.isInstanceOf[ConfigIncluderFile])
obj.withFallback(
fallback.asInstanceOf[ConfigIncluderFile].includeFile(context, file)
)
else obj
}
override def includeResources(
context: ConfigIncludeContext,
resource: String
): ConfigObject = {
val obj =
SimpleIncluder.includeResourceWithoutFallback(context, resource)
if (fallback != null && fallback.isInstanceOf[ConfigIncluderClasspath])
obj.withFallback(
fallback
.asInstanceOf[ConfigIncluderClasspath]
.includeResources(context, resource)
)
else obj
}
override def withFallback(fallback: ConfigIncluder): ConfigIncluder =
if (this eq fallback)
throw new ConfigException.BugOrBroken("trying to create includer cycle")
else if (this.fallback eq fallback) this
else if (this.fallback != null)
new SimpleIncluder(this.fallback.withFallback(fallback))
else new SimpleIncluder(fallback)
}