From dbe9e073bf9d662f66f90ac221d9ac5aca51589a Mon Sep 17 00:00:00 2001 From: Peter Vlugter Date: Tue, 8 Mar 2011 20:29:50 +0800 Subject: [PATCH] Reduce config footprint --- .../main/scala/akka/config/Attributes.scala | 346 ---------------- .../src/main/scala/akka/config/Config.scala | 81 ++-- .../main/scala/akka/config/ConfigMap.scala | 369 ------------------ .../main/scala/akka/config/ConfigParser.scala | 113 ++---- .../scala/akka/config/Configuration.scala | 233 ++++++----- .../akka/config/ConfigurationString.scala | 117 ------ .../main/scala/akka/config/Configure.scala | 41 -- .../akka/config/EnvironmentAttributes.scala | 83 ---- .../src/main/scala/akka/config/Importer.scala | 84 +--- .../scala/akka/dispatch/Dispatchers.scala | 16 +- .../scala/akka/dispatch/MessageHandling.scala | 10 +- 11 files changed, 201 insertions(+), 1292 deletions(-) delete mode 100644 akka-actor/src/main/scala/akka/config/Attributes.scala delete mode 100644 akka-actor/src/main/scala/akka/config/ConfigMap.scala delete mode 100644 akka-actor/src/main/scala/akka/config/ConfigurationString.scala delete mode 100644 akka-actor/src/main/scala/akka/config/Configure.scala delete mode 100644 akka-actor/src/main/scala/akka/config/EnvironmentAttributes.scala diff --git a/akka-actor/src/main/scala/akka/config/Attributes.scala b/akka-actor/src/main/scala/akka/config/Attributes.scala deleted file mode 100644 index b8936ede57..0000000000 --- a/akka-actor/src/main/scala/akka/config/Attributes.scala +++ /dev/null @@ -1,346 +0,0 @@ -/** - * Copyright (C) 2009-2011 Scalable Solutions AB - * - * Based on Configgy by Robey Pointer. - * Copyright 2009 Robey Pointer - * http://www.apache.org/licenses/LICENSE-2.0 - */ - -package akka.config - -import java.util.regex.Pattern -import scala.collection.{immutable, mutable, Map} -import scala.util.Sorting -import akka.config.string._ - - -private[config] abstract class Cell -private[config] case class StringCell(value: String) extends Cell -private[config] case class AttributesCell(attr: Attributes) extends Cell -private[config] case class StringListCell(array: Array[String]) extends Cell - - -/** - * Actual implementation of ConfigMap. - * Stores items in Cell objects, and handles interpolation and key recursion. - */ -private[config] class Attributes(val config: Configuration, val name: String) extends ConfigMap { - - private val cells = new mutable.HashMap[String, Cell] - var inheritFrom: Option[ConfigMap] = None - - def this(config: Configuration, name: String, copyFrom: ConfigMap) = { - this(config, name) - copyFrom.copyInto(this) - } - - def keys: Iterator[String] = cells.keysIterator - - def getName() = name - - override def toString() = { - val buffer = new StringBuilder("{") - buffer ++= name - buffer ++= (inheritFrom match { - case Some(a: Attributes) => " (inherit=" + a.name + ")" - case None => "" - }) - buffer ++= ": " - for (key <- sortedKeys) { - buffer ++= key - buffer ++= "=" - buffer ++= (cells(key) match { - case StringCell(x) => "\"" + x.quoteC + "\"" - case AttributesCell(x) => x.toString - case StringListCell(x) => x.mkString("[", ",", "]") - }) - buffer ++= " " - } - buffer ++= "}" - buffer.toString - } - - override def equals(obj: Any) = { - if (! obj.isInstanceOf[Attributes]) { - false - } else { - val other = obj.asInstanceOf[Attributes] - (other.sortedKeys.toList == sortedKeys.toList) && - (cells.keys forall (k => { cells(k) == other.cells(k) })) - } - } - - /** - * Look up a value cell for a given key. If the key is compound (ie, - * "abc.xyz"), look up the first segment, and if it refers to an inner - * Attributes object, recursively look up that cell. If it's not an - * Attributes or it doesn't exist, return None. For a non-compound key, - * return the cell if it exists, or None if it doesn't. - */ - private def lookupCell(key: String): Option[Cell] = { - val elems = key.split("\\.", 2) - if (elems.length > 1) { - cells.get(elems(0)) match { - case Some(AttributesCell(x)) => x.lookupCell(elems(1)) - case None => inheritFrom match { - case Some(a: Attributes) => - a.lookupCell(key) - case _ => None - } - case _ => None - } - } else { - cells.get(elems(0)) match { - case x @ Some(_) => x - case None => inheritFrom match { - case Some(a: Attributes) => a.lookupCell(key) - case _ => None - } - } - } - } - - /** - * Determine if a key is compound (and requires recursion), and if so, - * return the nested Attributes block and simple key that can be used to - * make a recursive call. If the key is simple, return None. - * - * If the key is compound, but nested Attributes objects don't exist - * that match the key, an attempt will be made to create the nested - * Attributes objects. If one of the key segments already refers to an - * attribute that isn't a nested Attribute object, a ConfigException - * will be thrown. - * - * For example, for the key "a.b.c", the Attributes object for "a.b" - * and the key "c" will be returned, creating the "a.b" Attributes object - * if necessary. If "a" or "a.b" exists but isn't a nested Attributes - * object, then an ConfigException will be thrown. - */ - @throws(classOf[ConfigException]) - private def recurse(key: String): Option[(Attributes, String)] = { - val elems = key.split("\\.", 2) - if (elems.length > 1) { - val attr = (cells.get(elems(0)) match { - case Some(AttributesCell(x)) => x - case Some(_) => throw new ConfigException("Illegal key " + key) - case None => createNested(elems(0)) - }) - attr.recurse(elems(1)) match { - case ret @ Some((a, b)) => ret - case None => Some((attr, elems(1))) - } - } else { - None - } - } - - def replaceWith(newAttributes: Attributes): Unit = { - // stash away subnodes and reinsert them. - val subnodes = for ((key, cell @ AttributesCell(_)) <- cells.toList) yield (key, cell) - cells.clear - cells ++= newAttributes.cells - for ((key, cell) <- subnodes) { - newAttributes.cells.get(key) match { - case Some(AttributesCell(newattr)) => - cell.attr.replaceWith(newattr) - cells(key) = cell - case None => - cell.attr.replaceWith(new Attributes(config, "")) - } - } - } - - private def createNested(key: String): Attributes = { - val attr = new Attributes(config, if (name.equals("")) key else (name + "." + key)) - cells(key) = new AttributesCell(attr) - attr - } - - def getString(key: String): Option[String] = { - lookupCell(key) match { - case Some(StringCell(x)) => Some(x) - case Some(StringListCell(x)) => Some(x.toList.mkString("[", ",", "]")) - case _ => None - } - } - - def getConfigMap(key: String): Option[ConfigMap] = { - lookupCell(key) match { - case Some(AttributesCell(x)) => Some(x) - case _ => None - } - } - - def configMap(key: String): ConfigMap = makeAttributes(key, true) - - private[config] def makeAttributes(key: String): Attributes = makeAttributes(key, false) - - private[config] def makeAttributes(key: String, withInherit: Boolean): Attributes = { - if (key == "") { - return this - } - recurse(key) match { - case Some((attr, name)) => - attr.makeAttributes(name, withInherit) - case None => - val cell = if (withInherit) lookupCell(key) else cells.get(key) - cell match { - case Some(AttributesCell(x)) => x - case Some(_) => throw new ConfigException("Illegal key " + key) - case None => createNested(key) - } - } - } - - def getList(key: String): Seq[String] = { - lookupCell(key) match { - case Some(StringListCell(x)) => x - case Some(StringCell(x)) => Array[String](x) - case _ => Array[String]() - } - } - - def setString(key: String, value: String): Unit = { - recurse(key) match { - case Some((attr, name)) => attr.setString(name, value) - case None => cells.get(key) match { - case Some(AttributesCell(_)) => throw new ConfigException("Illegal key " + key) - case _ => cells.put(key, new StringCell(value)) - } - } - } - - def setList(key: String, value: Seq[String]): Unit = { - recurse(key) match { - case Some((attr, name)) => attr.setList(name, value) - case None => cells.get(key) match { - case Some(AttributesCell(_)) => throw new ConfigException("Illegal key " + key) - case _ => cells.put(key, new StringListCell(value.toArray)) - } - } - } - - def setConfigMap(key: String, value: ConfigMap): Unit = { - recurse(key) match { - case Some((attr, name)) => attr.setConfigMap(name, value) - case None => - val subName = if (name == "") key else (name + "." + key) - cells.get(key) match { - case Some(AttributesCell(_)) => - cells.put(key, new AttributesCell(new Attributes(config, subName, value))) - case None => - cells.put(key, new AttributesCell(new Attributes(config, subName, value))) - case _ => - throw new ConfigException("Illegal key " + key) - } - } - } - - def contains(key: String): Boolean = { - recurse(key) match { - case Some((attr, name)) => attr.contains(name) - case None => cells.contains(key) - } - } - - def remove(key: String): Boolean = { - recurse(key) match { - case Some((attr, name)) => attr.remove(name) - case None => { - cells.removeKey(key) match { - case Some(_) => true - case None => false - } - } - } - } - - def asMap: Map[String, String] = { - var ret = immutable.Map.empty[String, String] - for ((key, value) <- cells) { - value match { - case StringCell(x) => ret = ret.update(key, x) - case StringListCell(x) => ret = ret.update(key, x.mkString("[", ",", "]")) - case AttributesCell(x) => - for ((k, v) <- x.asMap) { - ret = ret.update(key + "." + k, v) - } - } - } - ret - } - - def toConfigString: String = { - toConfigList().mkString("", "\n", "\n") - } - - private def toConfigList(): List[String] = { - val buffer = new mutable.ListBuffer[String] - for (key <- Sorting.stableSort(cells.keys.toList)) { - cells(key) match { - case StringCell(x) => - buffer += (key + " = \"" + x.quoteC + "\"") - case StringListCell(x) => - buffer += (key + " = [") - buffer ++= x.map { " \"" + _.quoteC + "\"," } - buffer += "]" - case AttributesCell(node) => - buffer += (key + node.inheritFrom.map { " (inherit=\"" + _.asInstanceOf[Attributes].name + "\")" }.getOrElse("") + " {") - buffer ++= node.toConfigList().map { " " + _ } - buffer += "}" - } - } - buffer.toList - } - - // substitute "$(...)" strings with looked-up vars - // (and find "\$" and replace them with "$") - private val INTERPOLATE_RE = """(? "" - case attr :: xs => attr.getString(key) match { - case Some(x) => x - case None => lookup(key, xs) - } - } - } - - s.regexSub(INTERPOLATE_RE) { m => - if (m.matched == "\\$") { - "$" - } else { - lookup(m.group(1), List(this, root, EnvironmentAttributes)) - } - } - } - - protected[config] def interpolate(key: String, s: String): String = { - recurse(key) match { - case Some((attr, name)) => attr.interpolate(this, s) - case None => interpolate(this, s) - } - } - - // make a deep copy of the Attributes tree. - def copy(): Attributes = { - copyInto(new Attributes(config, name)) - } - - def copyInto[T <: ConfigMap](attr: T): T = { - inheritFrom match { - case Some(a: Attributes) => a.copyInto(attr) - case _ => - } - for ((key, value) <- cells.elements) { - value match { - case StringCell(x) => attr(key) = x - case StringListCell(x) => attr(key) = x - case AttributesCell(x) => attr.setConfigMap(key, x.copy()) - } - } - attr - } -} diff --git a/akka-actor/src/main/scala/akka/config/Config.scala b/akka-actor/src/main/scala/akka/config/Config.scala index 59c8417b69..4dcdbd40e5 100644 --- a/akka-actor/src/main/scala/akka/config/Config.scala +++ b/akka-actor/src/main/scala/akka/config/Config.scala @@ -52,64 +52,38 @@ object Config { (envConf orElse systemConf).map("akka." + _ + ".conf").getOrElse("akka.conf") } - if (System.getProperty("akka.config", "") != "") { - val configFile = System.getProperty("akka.config", "") - try { - Configure.configure(configFile) - println("Config loaded from -Dakka.config=" + configFile) - } catch { - case cause: ParseException => - val e = new ConfigurationException( - "Config could not be loaded from -Dakka.config=" + configFile + - "\n\tdue to: " + cause.toString) - EventHandler notifyListeners EventHandler.Error(e, this) - throw e - } - Configure.config - } else if (getClass.getClassLoader.getResource(confName) ne null) { - try { - Configure.configureFromResource(confName, getClass.getClassLoader) - println("Config [" + confName + "] loaded from the application classpath.") - } catch { - case cause: ParseException => - val e = new ConfigurationException( - "Can't load '" + confName + "' config file from application classpath," + - "\n\tdue to: " + cause.toString) - EventHandler notifyListeners EventHandler.Error(e, this) - throw e - } - Configure.config - } else if (HOME.isDefined) { - try { + try { + if (System.getProperty("akka.config", "") != "") { + val configFile = System.getProperty("akka.config", "") + println("Loading config from -Dakka.config=" + configFile) + Configuration.fromFile(configFile) + } else if (getClass.getClassLoader.getResource(confName) ne null) { + println("Loading config [" + confName + "] from the application classpath.") + Configuration.fromResource(confName, getClass.getClassLoader) + } else if (HOME.isDefined) { val configFile = HOME.get + "/config/" + confName - Configure.configure(configFile) + println("AKKA_HOME is defined as [" + HOME.get + "], loading config from [" + configFile + "].") + Configuration.fromFile(configFile) + } else { println( - "AKKA_HOME is defined as [" + HOME.getOrElse(throwNoAkkaHomeException) + - "], config loaded from [" + configFile + "].") - } catch { - case cause: ParseException => - val e = throw new ConfigurationException( - "AKKA_HOME is defined as [" + HOME.get + "] " + - "\n\tbut the 'akka.conf' config file can not be found at [" + HOME.get + "/config/"+ confName + "]," + - "\n\tdue to: " + cause.toString) - EventHandler notifyListeners EventHandler.Error(e, this) - throw e + "\nCan't load '" + confName + "'." + + "\nOne of the three ways of locating the '" + confName + "' file needs to be defined:" + + "\n\t1. Define the '-Dakka.config=...' system property option." + + "\n\t2. Put the '" + confName + "' file on the classpath." + + "\n\t3. Define 'AKKA_HOME' environment variable pointing to the root of the Akka distribution." + + "\nI have no way of finding the '" + confName + "' configuration file." + + "\nUsing default values everywhere.") + Configuration.fromString("") // default empty config } - Configure.config - } else { - println( - "\nCan't load '" + confName + "'." + - "\nOne of the three ways of locating the '" + confName + "' file needs to be defined:" + - "\n\t1. Define the '-Dakka.config=...' system property option." + - "\n\t2. Put the '" + confName + "' file on the classpath." + - "\n\t3. Define 'AKKA_HOME' environment variable pointing to the root of the Akka distribution." + - "\nI have no way of finding the '" + confName + "' configuration file." + - "\nUsing default values everywhere.") - Configuration.fromString("") // default empty config + } catch { + case e => + EventHandler notifyListeners EventHandler.Error(e, this) + throw e } } val CONFIG_VERSION = config.getString("akka.version", VERSION) + if (VERSION != CONFIG_VERSION) throw new ConfigurationException( "Akka JAR version [" + VERSION + "] is different than the provided config version [" + CONFIG_VERSION + "]") @@ -117,9 +91,4 @@ object Config { val startTime = System.currentTimeMillis def uptime = (System.currentTimeMillis - startTime) / 1000 - - def throwNoAkkaHomeException = throw new ConfigurationException( - "Akka home is not defined. Either:" + - "\n\t1. Define 'AKKA_HOME' environment variable pointing to the root of the Akka distribution." + - "\n\t2. Add the '-Dakka.home=...' option pointing to the root of the Akka distribution.") } diff --git a/akka-actor/src/main/scala/akka/config/ConfigMap.scala b/akka-actor/src/main/scala/akka/config/ConfigMap.scala deleted file mode 100644 index 0e210b9b9f..0000000000 --- a/akka-actor/src/main/scala/akka/config/ConfigMap.scala +++ /dev/null @@ -1,369 +0,0 @@ -/** - * Copyright (C) 2009-2011 Scalable Solutions AB - * - * Based on Configgy by Robey Pointer. - * Copyright 2009 Robey Pointer - * http://www.apache.org/licenses/LICENSE-2.0 - */ - -package akka.config - -import scala.collection.Map -import scala.util.Sorting - - -class ConfigException(reason: String) extends Exception(reason) - - -/** - * Abstract trait for a map of string keys to strings, string lists, or (nested) ConfigMaps. - * Integers and booleans may also be stored and retrieved, but they are converted to/from - * strings in the process. - */ -trait ConfigMap { - private val TRUE = "true" - private val FALSE = "false" - - - // ----- required methods - - /** - * Lookup an entry in this map, and if it exists and can be represented - * as a string, return it. Strings will be returned as-is, and string - * lists will be returned as a combined string. Nested AttributeMaps - * will return None as if there was no entry present. - */ - def getString(key: String): Option[String] - - /** - * Lookup an entry in this map, and if it exists and is a nested - * ConfigMap, return it. If the entry is a string or string list, - * it will return None as if there was no entry present. - */ - def getConfigMap(key: String): Option[ConfigMap] - - /** - * Lookup an entry in this map, and if it exists and is a nested - * ConfigMap, return it. If not, create an empty map with this name - * and return that. - * - * @throws ConfigException if the key already refers to a string or - * string list - */ - def configMap(key: String): ConfigMap - - /** - * Lookup an entry in this map, and if it exists and can be represented - * as a string list, return it. String lists will be returned as-is, and - * strings will be returned as an array of length 1. If the entry doesn't - * exist or is a nested ConfigMap, an empty sequence is returned. - */ - def getList(key: String): Seq[String] - - /** - * Set a key/value pair in this map. If an entry already existed with - * that key, it's replaced. - * - * @throws ConfigException if the key already refers to a nested - * ConfigMap - */ - def setString(key: String, value: String): Unit - - /** - * Set a key/value pair in this map. If an entry already existed with - * that key, it's replaced. - * - * @throws ConfigException if the key already refers to a nested - * ConfigMap - */ - def setList(key: String, value: Seq[String]): Unit - - /** - * Put a nested ConfigMap inside this one. If an entry already existed with - * that key, it's replaced. The ConfigMap is deep-copied at insert-time. - * - * @throws ConfigException if the key already refers to a value that isn't - * a nested ConfigMap - */ - def setConfigMap(key: String, value: ConfigMap): Unit - - /** - * Returns true if this map contains the given key. - */ - def contains(key: String): Boolean - - /** - * Remove an entry with the given key, if it exists. Returns true if - * an entry was actually removed, false if not. - */ - def remove(key: String): Boolean - - /** - * Return an iterator across the keys of this map. - */ - def keys: Iterator[String] - - /** - * Return a new (immutable) map containing a deep copy of all the keys - * and values from this AttributeMap. Keys from nested maps will be - * compound (like `"inner.name"`). - */ - def asMap(): Map[String, String] - - /** - * Make a deep copy of this ConfigMap. Any inheritance chains will be - * deep-copied, but the inheritance will not be preserved: the copied - * ConfigMap stands alone as its own set of objects, reflecting the - * frozen state of any inherited ConfigMaps. - */ - def copy(): ConfigMap - - /** - * Make this ConfigMap inherit default values from another ConfigMap. - * Any attributes that aren't explicitly set will fall back to the inherited - * ConfigMap on lookup. - */ - def inheritFrom_=(config: Option[ConfigMap]): Unit - - /** - * Return any ConfigMap that is used as a fall back on lookups. - */ - def inheritFrom: Option[ConfigMap] - - - // ----- convenience methods - - /** - * If the requested key is present, return its value. Otherwise, return - * the given default value. - */ - def getString(key: String, defaultValue: String): String = { - getString(key) match { - case Some(x) => x - case None => defaultValue - } - } - - /** - * If the requested key is present and can be converted into an int - * (via `String.toInt`), return that int. Otherwise, return `None`. - */ - def getInt(key: String): Option[Int] = { - getString(key) match { - case Some(x) => { - try { - Some(x.toInt) - } catch { - case _: NumberFormatException => None - } - } - case None => None - } - } - - /** - * If the requested key is present and can be converted into an int - * (via `String.toInt`), return that int. Otherwise, - * return the given default value. - */ - def getInt(key: String, defaultValue: Int): Int = { - getInt(key) match { - case Some(n) => n - case None => defaultValue - } - } - - /** - * If the requested key is present and can be converted into a long - * (via `String.toLong`), return that long. Otherwise, return `None`. - */ - def getLong(key: String): Option[Long] = { - getString(key) match { - case Some(x) => { - try { - Some(x.toLong) - } catch { - case _: NumberFormatException => None - } - } - case None => None - } - } - - /** - * If the requested key is present and can be converted into a long - * (via `String.toLong`), return that long. Otherwise, - * return the given default value. - */ - def getLong(key: String, defaultValue: Long): Long = { - getLong(key) match { - case Some(n) => n - case None => defaultValue - } - } - - /** - * If the requested key is present and can be converted into a double - * (via `String.toDouble`), return that double. Otherwise, return `None`. - */ - def getDouble(key: String): Option[Double] = { - getString(key) match { - case Some(x) => { - try { - Some(x.toDouble) - } catch { - case _: NumberFormatException => None - } - } - case None => None - } - } - - /** - * If the requested key is present and can be converted into a double - * (via `String.toDouble`), return that double. Otherwise, - * return the given default value. - */ - def getDouble(key: String, defaultValue: Double): Double = { - getDouble(key) match { - case Some(n) => n - case None => defaultValue - } - } - - /** - * If the requested key is present and can be converted into a bool - * (by being either `"true"` or `"false"`), - * return that bool. Otherwise, return `None`. - */ - def getBool(key: String): Option[Boolean] = { - getString(key) match { - case Some(x) => - if (x != TRUE && x != FALSE) throw new ConfigException("invalid boolean value") - Some(x.equals(TRUE)) - case None => None - } - } - - /** - * If the requested key is present and can be converted into a bool - * (by being either `"true"` or `"false"`), - * return that bool. Otherwise, return the given default value. - */ - def getBool(key: String, defaultValue: Boolean): Boolean = { - getBool(key) match { - case Some(b) => b - case None => defaultValue - } - } - - /** - * Set the given key to an int value, by converting it to a string - * first. - */ - def setInt(key: String, value: Int): Unit = setString(key, value.toString) - - /** - * Set the given key to a long value, by converting it to a string - * first. - */ - def setLong(key: String, value: Long): Unit = setString(key, value.toString) - - /** - * Set the given key to a double value, by converting it to a string - * first. - */ - def setDouble(key: String, value: Double): Unit = setString(key, value.toString) - - /** - * Set the given key to a bool value, by converting it to a string - * first. - */ - def setBool(key: String, value: Boolean): Unit = { - setString(key, if (value) TRUE else FALSE) - } - - /** - * Return the keys of this map, in sorted order. - */ - def sortedKeys() = { - // :( why does this have to be done manually? - val keys = this.keys.toList.toArray - Sorting.quickSort(keys) - keys - } - - /** - * Convert this ConfigMap into a string which could be written into a config file. - */ - def toConfigString: String - - def copyInto[T <: ConfigMap](configMap: T): T - - def copyInto(obj: AnyRef) { - val cls = obj.getClass - //val log = Logger.get(cls) - val methods = cls.getMethods().filter { method => - method.getName().endsWith("_$eq") && method.getParameterTypes().size == 1 - }.toList - keys.foreach { key => - val setters = methods.filter { _.getName() == key + "_$eq" } -/* if (setters.size == 0) { - log.warning("Ignoring config key '%s' which doesn't have a setter in class %s", key, cls) - }*/ - setters.foreach { method => - val expectedType = method.getParameterTypes().first.getCanonicalName - val param = expectedType match { - case "int" => getInt(key) - case "long" => getLong(key) - case "float" => getDouble(key).map { _.toFloat } - case "double" => getDouble(key) - case "boolean" => getBool(key) - case "java.lang.String" => getString(key) - case _ => None // ignore for now - } - param.map { p => method.invoke(obj, p.asInstanceOf[Object]) } - } - } - } - - /** - * If the requested key is present, return its value as a string. Otherwise, throw a - * ConfigException. `toInt` and `toBoolean` may be called on the - * returned string if an int or bool is desired. - */ - def apply(key: String): String = getString(key) match { - case None => throw new ConfigException("undefined config: " + key) - case Some(v) => v - } - - /** Equivalent to `getString(key, defaultValue)`. */ - def apply(key: String, defaultValue: String) = getString(key, defaultValue) - - /** Equivalent to `getInt(key, defaultValue)`. */ - def apply(key: String, defaultValue: Int) = getInt(key, defaultValue) - - /** Equivalent to `getLong(key, defaultValue)`. */ - def apply(key: String, defaultValue: Long) = getLong(key, defaultValue) - - /** Equivalent to `getBool(key, defaultValue)`. */ - def apply(key: String, defaultValue: Boolean) = getBool(key, defaultValue) - - /** Equivalent to `setString(key, value)`. */ - def update(key: String, value: String) = setString(key, value) - - /** Equivalent to `setInt(key, value)`. */ - def update(key: String, value: Int) = setInt(key, value) - - /** Equivalent to `setLong(key, value)`. */ - def update(key: String, value: Long) = setLong(key, value) - - /** Equivalent to `setBool(key, value)`. */ - def update(key: String, value: Boolean) = setBool(key, value) - - /** Equivalent to `setList(key, value)`. */ - def update(key: String, value: Seq[String]) = setList(key, value) - - /** Get the name of the current config map. */ - def getName(): String -} diff --git a/akka-actor/src/main/scala/akka/config/ConfigParser.scala b/akka-actor/src/main/scala/akka/config/ConfigParser.scala index 7d8485897a..6190beb826 100644 --- a/akka-actor/src/main/scala/akka/config/ConfigParser.scala +++ b/akka-actor/src/main/scala/akka/config/ConfigParser.scala @@ -8,117 +8,68 @@ package akka.config -import scala.collection.mutable.Stack +import scala.collection.mutable import scala.util.parsing.combinator._ -import scala.util.parsing.input.CharSequenceReader -import akka.config.string._ -/** - * An exception thrown when parsing a config file, if there was an error - * during parsing. The `reason` string will contain the parsing - * error details. - */ -class ParseException(reason: String, cause: Throwable) extends Exception(reason, cause) { - def this(reason: String) = this(reason, null) - def this(cause: Throwable) = this(null, cause) -} +class ConfigParser(var prefix: String = "", map: mutable.Map[String, Any] = mutable.Map.empty[String, Any], importer: Importer) extends RegexParsers { + val sections = mutable.Stack[String]() + def createPrefix = { + prefix = if (sections.isEmpty) "" else sections.toList.reverse.mkString("", ".", ".") + } -private[config] class ConfigParser(var attr: Attributes, val importer: Importer) extends RegexParsers { - - val sections = new Stack[String] - var prefix = "" - - // Stack reversed iteration order from 2.7 to 2.8!! - def sectionsString = sections.toList.reverse.mkString(".") + override val whiteSpace = """(\s+|#[^\n]*\n)+""".r // tokens - override val whiteSpace = """(\s+|#[^\n]*\n)+""".r + val numberToken: Parser[String] = """-?\d+(\.\d+)?""".r val stringToken: Parser[String] = ("\"" + """([^\\\"]|\\[^ux]|\\\n|\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2})*""" + "\"").r + val booleanToken: Parser[String] = "(true|on|false|off)".r val identToken: Parser[String] = """([\da-zA-Z_][-\w]*)(\.[a-zA-Z_][-\w]*)*""".r - val assignToken: Parser[String] = """=|\?=""".r - val tagNameToken: Parser[String] = """[a-zA-Z][-\w]*""".r + val assignToken: Parser[String] = "=".r + val sectionToken: Parser[String] = """[a-zA-Z][-\w]*""".r + // values - def root = rep(includeFile | includeOptFile | assignment | toggle | sectionOpen | sectionClose | - sectionOpenBrace | sectionCloseBrace) + def value: Parser[Any] = number | string | list | boolean + def number = numberToken + def string = stringToken ^^ { s => s.substring(1, s.length - 1) } + def list = "[" ~> repsep(string | numberToken, opt(",")) <~ (opt(",") ~ "]") + def boolean = booleanToken + + // parser + + def root = rep(includeFile | assignment | sectionOpen | sectionClose) def includeFile = "include" ~> string ^^ { case filename: String => - new ConfigParser(attr.makeAttributes(sectionsString), importer) parse importer.importFile(filename) - } - - def includeOptFile = "include?" ~> string ^^ { - case filename: String => - new ConfigParser(attr.makeAttributes(sections.mkString(".")), importer) parse importer.importFile(filename, false) + new ConfigParser(prefix, map, importer) parse importer.importFile(filename) } def assignment = identToken ~ assignToken ~ value ^^ { - case k ~ a ~ v => if (a match { - case "=" => true - case "?=" => ! attr.contains(prefix + k) - }) v match { - case x: Long => attr(prefix + k) = x - case x: String => attr(prefix + k) = x - case x: Array[String] => attr(prefix + k) = x - case x: Boolean => attr(prefix + k) = x - } + case k ~ a ~ v => map(prefix + k) = v } - def toggle = identToken ~ trueFalse ^^ { case k ~ v => attr(prefix + k) = v } - - def sectionOpen = "<" ~> tagNameToken ~ rep(tagAttribute) <~ ">" ^^ { - case name ~ attrList => openBlock(name, attrList) - } - def tagAttribute = opt(whiteSpace) ~> (tagNameToken <~ "=") ~ string ^^ { case k ~ v => (k, v) } - def sectionClose = " tagNameToken <~ ">" ^^ { name => closeBlock(Some(name)) } - - def sectionOpenBrace = tagNameToken ~ opt("(" ~> rep(tagAttribute) <~ ")") <~ "{" ^^ { - case name ~ attrListOption => openBlock(name, attrListOption.getOrElse(Nil)) - } - def sectionCloseBrace = "}" ^^ { x => closeBlock(None) } - - private def openBlock(name: String, attrList: List[(String, String)]) = { - val parent = if (sections.size > 0) attr.makeAttributes(sectionsString) else attr + def sectionOpen = sectionToken <~ "{" ^^ { name => sections push name - prefix = sectionsString + "." - val newBlock = attr.makeAttributes(sectionsString) - for ((k, v) <- attrList) k match { - case "inherit" => - newBlock.inheritFrom = Some(if (parent.getConfigMap(v).isDefined) parent.makeAttributes(v) else attr.makeAttributes(v)) - case _ => - throw new ParseException("Unknown block modifier") - } + createPrefix } - private def closeBlock(name: Option[String]) = { + def sectionClose = "}" ^^ { _ => if (sections.isEmpty) { failure("dangling close tag") } else { - val last = sections.pop - if (name.isDefined && last != name.get) { - failure("got closing tag for " + name.get + ", expected " + last) - } else { - prefix = if (sections.isEmpty) "" else sectionsString + "." - } + sections.pop + createPrefix } } - - def value: Parser[Any] = number | string | stringList | trueFalse - def number = numberToken ^^ { x => if (x.contains('.')) x else x.toLong } - def string = stringToken ^^ { s => attr.interpolate(prefix, s.substring(1, s.length - 1).unquoteC) } - def stringList = "[" ~> repsep(string | numberToken, opt(",")) <~ (opt(",") ~ "]") ^^ { list => list.toArray } - def trueFalse: Parser[Boolean] = ("(true|on)".r ^^ { x => true }) | ("(false|off)".r ^^ { x => false }) - - - def parse(in: String): Unit = { + def parse(in: String): Map[String, Any] = { parseAll(root, in) match { - case Success(result, _) => result - case x @ Failure(msg, z) => throw new ParseException(x.toString) - case x @ Error(msg, _) => throw new ParseException(x.toString) + case Success(result, _) => map.toMap + case x @ Failure(msg, _) => throw new ConfigurationException(x.toString) + case x @ Error(msg, _) => throw new ConfigurationException(x.toString) } } } diff --git a/akka-actor/src/main/scala/akka/config/Configuration.scala b/akka-actor/src/main/scala/akka/config/Configuration.scala index 6ab17e2d9d..6756a0b89f 100644 --- a/akka-actor/src/main/scala/akka/config/Configuration.scala +++ b/akka-actor/src/main/scala/akka/config/Configuration.scala @@ -9,148 +9,135 @@ package akka.config import java.io.File -import scala.collection.{Map, Set} -import scala.collection.{immutable, mutable} - -class Configuration extends ConfigMap { - private var root = new Attributes(this, "") - private var reloadAction: Option[() => Unit] = None - - /** - * Importer for resolving "include" lines when loading config files. - * By default, it's a FilesystemImporter based on the current working - * directory. - */ - var importer: Importer = new FilesystemImporter(new File(".").getCanonicalPath) - - - /** - * Read config data from a string and use it to populate this object. - */ - def load(data: String) { - reloadAction = Some(() => configure(data)) - reload() - } - - /** - * Read config data from a file and use it to populate this object. - */ - def loadFile(filename: String) { - reloadAction = Some(() => configure(importer.importFile(filename))) - reload() - } - - /** - * Read config data from a file and use it to populate this object. - */ - def loadFile(path: String, filename: String) { - importer = new FilesystemImporter(path) - loadFile(filename) - } - - /** - * Reloads the configuration from whatever source it was previously loaded - * from, undoing any in-memory changes. This is a no-op if the configuration - * data has not be loaded from a source (file or string). - */ - def reload() { - reloadAction.foreach(_()) - } - - private def configure(data: String) { - val newRoot = new Attributes(this, "") - new ConfigParser(newRoot, importer) parse data - root.replaceWith(newRoot) - } - - override def toString = root.toString - - // ----- implement AttributeMap by wrapping our root object: - - def getString(key: String): Option[String] = root.getString(key) - def getConfigMap(key: String): Option[ConfigMap] = root.getConfigMap(key) - def configMap(key: String): ConfigMap = root.configMap(key) - def getList(key: String): Seq[String] = root.getList(key) - def setString(key: String, value: String): Unit = root.setString(key, value) - def setList(key: String, value: Seq[String]): Unit = root.setList(key, value) - def setConfigMap(key: String, value: ConfigMap): Unit = root.setConfigMap(key, value) - def contains(key: String): Boolean = root.contains(key) - def remove(key: String): Boolean = root.remove(key) - def keys: Iterator[String] = root.keys - def asMap(): Map[String, String] = root.asMap() - def toConfigString = root.toConfigString - def copy(): ConfigMap = root.copy() - def copyInto[T <: ConfigMap](m: T): T = root.copyInto(m) - def inheritFrom = root.inheritFrom - def inheritFrom_=(config: Option[ConfigMap]) = root.inheritFrom=(config) - def getName(): String = root.name -} object Configuration { - /** - * Create a configuration object from a config file of the given path - * and filename. The filename must be relative to the path. The path is - * used to resolve filenames given in "include" lines. - */ - def fromFile(path: String, filename: String): Configuration = { - val config = new Configuration - config.loadFile(path, filename) - config + val DefaultPath = new File(".").getCanonicalPath + val DefaultImporter = new FilesystemImporter(DefaultPath) + + def load(data: String, importer: Importer = DefaultImporter): Configuration = { + val parser = new ConfigParser(importer = importer) + new Configuration(parser parse data) + } + + def fromFile(filename: String, importer: Importer): Configuration = { + load(importer.importFile(filename), importer) + } + + def fromFile(path: String, filename: String): Configuration = { + val importer = new FilesystemImporter(path) + fromFile(filename, importer) } - /** - * Create a Configuration object from a config file of the given filename. - * The base folder will be extracted from the filename and used as a base - * path for resolving filenames given in "include" lines. - */ def fromFile(filename: String): Configuration = { val n = filename.lastIndexOf('/') if (n < 0) { - fromFile(new File(".").getCanonicalPath, filename) + fromFile(DefaultPath, filename) } else { fromFile(filename.substring(0, n), filename.substring(n + 1)) } } - /** - * Create a Configuration object from the given named resource inside this jar - * file, using the system class loader. "include" lines will also operate - * on resource paths. - */ - def fromResource(name: String): Configuration = { - fromResource(name, ClassLoader.getSystemClassLoader) + def fromResource(filename: String): Configuration = { + fromResource(filename, ClassLoader.getSystemClassLoader) } - /** - * Create a Configuration object from the given named resource inside this jar - * file, using a specific class loader. "include" lines will also operate - * on resource paths. - */ - def fromResource(name: String, classLoader: ClassLoader): Configuration = { - val config = new Configuration - config.importer = new ResourceImporter(classLoader) - config.loadFile(name) - config + def fromResource(filename: String, classLoader: ClassLoader): Configuration = { + val importer = new ResourceImporter(classLoader) + fromFile(filename, importer) } - /** - * Create a Configuration object from a map of String keys and String values. - */ - def fromMap(m: Map[String, String]) = { - val config = new Configuration - for ((k, v) <- m.elements) { - config(k) = v - } - config + def fromMap(map: Map[String, Any]) = { + new Configuration(map) } - /** - * Create a Configuration object from a string containing a config file's contents. - */ def fromString(data: String): Configuration = { - val config = new Configuration - config.load(data) - config + load(data) + } +} + +class Configuration(val map: Map[String, Any]) { + private val trueValues = Set("true", "on") + private val falseValues = Set("false", "off") + + def contains(key: String): Boolean = map contains key + + def keys: Iterable[String] = map.keys + + def getString(key: String): Option[String] = map.get(key).map(_.toString) + + def getString(key: String, defaultValue: String): String = getString(key).getOrElse(defaultValue) + + def getList(key: String): Seq[String] = map(key).asInstanceOf[Seq[String]] + + def getInt(key: String): Option[Int] = { + try { + Some(map(key).toString.toInt) + } catch { + case _ => None + } + } + + def getInt(key: String, defaultValue: Int): Int = getInt(key).getOrElse(defaultValue) + + def getLong(key: String): Option[Long] = { + try { + Some(map(key).toString.toLong) + } catch { + case _ => None + } + } + + def getLong(key: String, defaultValue: Long): Long = getLong(key).getOrElse(defaultValue) + + def getFloat(key: String): Option[Float] = { + try { + Some(map(key).toString.toFloat) + } catch { + case _ => None + } + } + + def getFloat(key: String, defaultValue: Float): Float = getFloat(key).getOrElse(defaultValue) + + def getDouble(key: String): Option[Double] = { + try { + Some(map(key).toString.toDouble) + } catch { + case _ => None + } + } + + def getDouble(key: String, defaultValue: Double): Double = getDouble(key).getOrElse(defaultValue) + + def getBoolean(key: String): Option[Boolean] = { + getString(key) flatMap { s => + val isTrue = trueValues.contains(s) + if (!isTrue && !falseValues.contains(s)) None + else Some(isTrue) + } + } + + def getBoolean(key: String, defaultValue: Boolean): Boolean = getBool(key).getOrElse(defaultValue) + + def getBool(key: String): Option[Boolean] = getBoolean(key) + + def getBool(key: String, defaultValue: Boolean): Boolean = getBoolean(key, defaultValue) + + def apply(key: String): String = getString(key) match { + case None => throw new ConfigurationException("undefined config: " + key) + case Some(v) => v + } + + def apply(key: String, defaultValue: String) = getString(key, defaultValue) + def apply(key: String, defaultValue: Int) = getInt(key, defaultValue) + def apply(key: String, defaultValue: Long) = getLong(key, defaultValue) + def apply(key: String, defaultValue: Boolean) = getBool(key, defaultValue) + + def getSection(name: String): Option[Configuration] = { + val l = name.length + 1 + val m = map.collect { case (k, v) if k.startsWith(name) => (k.substring(l), v) } + if (m.isEmpty) None + else Some(new Configuration(m)) } } diff --git a/akka-actor/src/main/scala/akka/config/ConfigurationString.scala b/akka-actor/src/main/scala/akka/config/ConfigurationString.scala deleted file mode 100644 index da117801ca..0000000000 --- a/akka-actor/src/main/scala/akka/config/ConfigurationString.scala +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (C) 2009-2011 Scalable Solutions AB - * - * Based on Configgy by Robey Pointer. - * Copyright 2009 Robey Pointer - * http://www.apache.org/licenses/LICENSE-2.0 - */ - -package akka.config - -import scala.util.matching.Regex - - -final class ConfigurationString(wrapped: String) { - /** - * For every section of a string that matches a regular expression, call - * a function to determine a replacement (as in python's - * `re.sub`). The function will be passed the Matcher object - * corresponding to the substring that matches the pattern, and that - * substring will be replaced by the function's result. - * - * For example, this call: - * - * "ohio".regexSub("""h.""".r) { m => "n" } - * - * will return the string `"ono"`. - * - * The matches are found using `Matcher.find()` and so - * will obey all the normal java rules (the matches will not overlap, - * etc). - * - * @param re the regex pattern to replace - * @param replace a function that takes Regex.MatchData objects and - * returns a string to substitute - * @return the resulting string with replacements made - */ - def regexSub(re: Regex)(replace: (Regex.MatchData => String)): String = { - var offset = 0 - var out = new StringBuilder - - for (m <- re.findAllIn(wrapped).matchData) { - if (m.start > offset) { - out.append(wrapped.substring(offset, m.start)) - } - - out.append(replace(m)) - offset = m.end - } - - if (offset < wrapped.length) { - out.append(wrapped.substring(offset)) - } - out.toString - } - - private val QUOTE_RE = "[\u0000-\u001f\u007f-\uffff\\\\\"]".r - - /** - * Quote a string so that unprintable chars (in ASCII) are represented by - * C-style backslash expressions. For example, a raw linefeed will be - * translated into "\n". Control codes (anything below 0x20) - * and unprintables (anything above 0x7E) are turned into either - * "\xHH" or "\\uHHHH" expressions, depending on - * their range. Embedded backslashes and double-quotes are also quoted. - * - * @return a quoted string, suitable for ASCII display - */ - def quoteC(): String = { - regexSub(QUOTE_RE) { m => - m.matched.charAt(0) match { - case '\r' => "\\r" - case '\n' => "\\n" - case '\t' => "\\t" - case '"' => "\\\"" - case '\\' => "\\\\" - case c => - if (c <= 255) { - "\\x%02x".format(c.asInstanceOf[Int]) - } else { - "\\u%04x" format c.asInstanceOf[Int] - } - } - } - } - - // we intentionally don't unquote "\$" here, so it can be used to escape interpolation later. - private val UNQUOTE_RE = """\\(u[\dA-Fa-f]{4}|x[\dA-Fa-f]{2}|[/rnt\"\\])""".r - - /** - * Unquote an ASCII string that has been quoted in a style like - * {@link #quoteC} and convert it into a standard unicode string. - * "\\uHHHH" and "\xHH" expressions are unpacked - * into unicode characters, as well as "\r", "\n", - * "\t", "\\", and '\"'. - * - * @return an unquoted unicode string - */ - def unquoteC() = { - regexSub(UNQUOTE_RE) { m => - val ch = m.group(1).charAt(0) match { - // holy crap! this is terrible: - case 'u' => Character.valueOf(Integer.valueOf(m.group(1).substring(1), 16).asInstanceOf[Int].toChar) - case 'x' => Character.valueOf(Integer.valueOf(m.group(1).substring(1), 16).asInstanceOf[Int].toChar) - case 'r' => '\r' - case 'n' => '\n' - case 't' => '\t' - case x => x - } - ch.toString - } - } -} - -object string { - implicit def stringToConfigurationString(s: String): ConfigurationString = new ConfigurationString(s) -} - diff --git a/akka-actor/src/main/scala/akka/config/Configure.scala b/akka-actor/src/main/scala/akka/config/Configure.scala deleted file mode 100644 index 90c4680950..0000000000 --- a/akka-actor/src/main/scala/akka/config/Configure.scala +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (C) 2009-2011 Scalable Solutions AB - * - * Based on Configgy by Robey Pointer. - * Copyright 2009 Robey Pointer - * http://www.apache.org/licenses/LICENSE-2.0 - */ - -package akka.config - -import java.io.File - -object Configure { - private var _config: Configuration = null - - def config = _config - - def config_=(c: Configuration) { - _config = c - } - - def configure(path: String, filename: String): Unit = { - config = Configuration.fromFile(path, filename) - } - - def configure(filename: String): Unit = { - config = Configuration.fromFile(filename) - } - - def configureFromResource(name: String) = { - config = Configuration.fromResource(name) - } - - def configureFromResource(name: String, classLoader: ClassLoader) = { - config = Configuration.fromResource(name, classLoader) - } - - def configureFromString(data: String) = { - config = Configuration.fromString(data) - } -} diff --git a/akka-actor/src/main/scala/akka/config/EnvironmentAttributes.scala b/akka-actor/src/main/scala/akka/config/EnvironmentAttributes.scala deleted file mode 100644 index ee1d417224..0000000000 --- a/akka-actor/src/main/scala/akka/config/EnvironmentAttributes.scala +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (C) 2009-2011 Scalable Solutions AB - * - * Based on Configgy by Robey Pointer. - * Copyright 2009 Robey Pointer - * http://www.apache.org/licenses/LICENSE-2.0 - */ - -package akka.config - -import java.net.InetAddress -import scala.collection.{immutable, mutable} -import scala.collection.JavaConversions - -/** - * A ConfigMap that wraps the system environment. This is used as a - * fallback when looking up "$(...)" substitutions in config files. - */ -private[config] object EnvironmentAttributes extends ConfigMap { - - private val env = immutable.Map.empty[String, String] ++ (JavaConversions.asMap(System.getenv()).elements) - - // deal with java.util.Properties extending - // java.util.Hashtable[Object, Object] and not - // java.util.Hashtable[String, String] - private def getSystemProperties(): mutable.HashMap[String,String] = { - val map = new mutable.HashMap[String, String] - for (entry <- JavaConversions.asMap(System.getProperties()).elements) { - entry match { - case (k: String, v: String) => map.put(k, v) - case _ => - } - } - map - } - - def getName() = "" - - def getString(key: String): Option[String] = { - getSystemProperties().get(key).orElse(env.get(key)) - } - - def getConfigMap(key: String): Option[ConfigMap] = None - def configMap(key: String): ConfigMap = error("not implemented") - - def getList(key: String): Seq[String] = getString(key) match { - case None => Array[String]() - case Some(x) => Array[String](x) - } - - def setString(key: String, value: String): Unit = error("read-only attributes") - def setList(key: String, value: Seq[String]): Unit = error("read-only attributes") - def setConfigMap(key: String, value: ConfigMap): Unit = error("read-only attributes") - - def contains(key: String): Boolean = { - env.contains(key) || getSystemProperties().contains(key) - } - - def remove(key: String): Boolean = error("read-only attributes") - def keys: Iterator[String] = (getSystemProperties().keySet ++ env.keySet).elements - def asMap(): Map[String, String] = error("not implemented") - def toConfigString = error("not implemented") - def copy(): ConfigMap = this - def copyInto[T <: ConfigMap](m: T) = m - def inheritFrom: Option[ConfigMap] = None - def inheritFrom_=(config: Option[ConfigMap]) = error("not implemented") - - - try { - val addr = InetAddress.getLocalHost - val ip = addr.getHostAddress - val dns = addr.getHostName - - if (ip ne null) { - env("HOSTIP") = ip - } - if (dns ne null) { - env("HOSTNAME") = dns - } - } catch { - case _ => // pass - } -} diff --git a/akka-actor/src/main/scala/akka/config/Importer.scala b/akka-actor/src/main/scala/akka/config/Importer.scala index c1204032ef..1bec00208a 100644 --- a/akka-actor/src/main/scala/akka/config/Importer.scala +++ b/akka-actor/src/main/scala/akka/config/Importer.scala @@ -16,49 +16,28 @@ import java.io.{BufferedReader, File, FileInputStream, InputStream, InputStreamR * parsing. This is used to handle `include` directives in config files. */ trait Importer { - /** - * Imports a requested file and returns the string contents of that file, - * if the file exists, and empty string if it does not exist and `required` - * is false. - * - * If the file couldn't be imported, throws a `ParseException`. - */ - @throws(classOf[ParseException]) - def importFile(filename: String, required: Boolean): String - /** - * Imports a requested file and returns the string contents of that file. - * If the file couldn't be imported, throws a `ParseException`. - */ - @throws(classOf[ParseException]) - def importFile(filename: String): String = importFile(filename, true) + def importFile(filename: String): String private val BUFFER_SIZE = 8192 - /** - * Exhaustively reads an InputStream and converts it into a String (using - * UTF-8 encoding). This is meant as a helper function for custom Importer - * classes. - * - * No exceptions are caught! - */ protected def streamToString(in: InputStream): String = { - val reader = new BufferedReader(new InputStreamReader(in, "UTF-8")) - val buffer = new Array[Char](BUFFER_SIZE) - val out = new StringBuilder - var n = 0 - while (n >= 0) { - n = reader.read(buffer, 0, buffer.length) - if (n >= 0) { - out.append(buffer, 0, n) - } - } try { + val reader = new BufferedReader(new InputStreamReader(in, "UTF-8")) + val buffer = new Array[Char](BUFFER_SIZE) + val sb = new StringBuilder + var n = 0 + while (n >= 0) { + n = reader.read(buffer, 0, buffer.length) + if (n >= 0) { + sb.appendAll(buffer, 0, n) + } + } in.close() + sb.toString } catch { - case _ => + case x => throw new ConfigurationException(x.toString) } - out.toString } } @@ -67,21 +46,11 @@ trait Importer { * An Importer that looks for imported config files in the filesystem. * This is the default importer. */ -class FilesystemImporter(val baseFolder: String) extends Importer { - def importFile(filename: String, required: Boolean): String = { - var f = new File(filename) - if (! f.isAbsolute) { - f = new File(baseFolder, filename) - } - if (!required && !f.exists) { - "" - } else { - try { - streamToString(new FileInputStream(f)) - } catch { - case x => throw new ParseException(x.toString) - } - } +class FilesystemImporter(val baseDir: String) extends Importer { + def importFile(filename: String): String = { + val f = new File(filename) + val file = if (f.isAbsolute) f else new File(baseDir, filename) + streamToString(new FileInputStream(file)) } } @@ -91,19 +60,8 @@ class FilesystemImporter(val baseFolder: String) extends Importer { * of the system class loader (usually the jar used to launch this app). */ class ResourceImporter(classLoader: ClassLoader) extends Importer { - def importFile(filename: String, required: Boolean): String = { - try { - val stream = classLoader.getResourceAsStream(filename) - if (stream eq null) { - if (required) { - throw new ParseException("Can't find resource: " + filename) - } - "" - } else { - streamToString(stream) - } - } catch { - case x => throw new ParseException(x.toString) - } + def importFile(filename: String): String = { + val stream = classLoader.getResourceAsStream(filename) + streamToString(stream) } } diff --git a/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala b/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala index e41eef444b..ae0b3d3f9b 100644 --- a/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala +++ b/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala @@ -9,7 +9,7 @@ import akka.actor.newUuid import akka.config.Config._ import akka.util.{Duration,ReflectiveAccess} -import akka.config.ConfigMap +import akka.config.Configuration import java.util.concurrent.TimeUnit @@ -57,7 +57,7 @@ object Dispatchers { val MAILBOX_TYPE: MailboxType = if (MAILBOX_CAPACITY < 0) UnboundedMailbox() else BoundedMailbox() lazy val defaultGlobalDispatcher = { - config.getConfigMap("akka.actor.default-dispatcher").flatMap(from).getOrElse(globalExecutorBasedEventDrivenDispatcher) + config.getSection("akka.actor.default-dispatcher").flatMap(from).getOrElse(globalExecutorBasedEventDrivenDispatcher) } object globalExecutorBasedEventDrivenDispatcher extends ExecutorBasedEventDrivenDispatcher("global", THROUGHPUT, THROUGHPUT_DEADLINE_TIME_MILLIS, MAILBOX_TYPE) @@ -155,7 +155,7 @@ object Dispatchers { * or else use the supplied default dispatcher */ def fromConfig(key: String, default: => MessageDispatcher = defaultGlobalDispatcher): MessageDispatcher = - config getConfigMap key flatMap from getOrElse default + config getSection key flatMap from getOrElse default /* * Creates of obtains a dispatcher from a ConfigMap according to the format below @@ -180,7 +180,7 @@ object Dispatchers { * Throws: IllegalArgumentException if the value of "type" is not valid * IllegalArgumentException if it cannot */ - def from(cfg: ConfigMap): Option[MessageDispatcher] = { + def from(cfg: Configuration): Option[MessageDispatcher] = { cfg.getString("type") map { case "ExecutorBasedEventDriven" => new ExecutorBasedEventDrivenDispatcherConfigurator() case "ExecutorBasedEventDrivenWorkStealing" => new ExecutorBasedEventDrivenWorkStealingDispatcherConfigurator() @@ -203,11 +203,11 @@ object Dispatchers { } object GlobalExecutorBasedEventDrivenDispatcherConfigurator extends MessageDispatcherConfigurator { - def configure(config: ConfigMap): MessageDispatcher = Dispatchers.globalExecutorBasedEventDrivenDispatcher + def configure(config: Configuration): MessageDispatcher = Dispatchers.globalExecutorBasedEventDrivenDispatcher } class ExecutorBasedEventDrivenDispatcherConfigurator extends MessageDispatcherConfigurator { - def configure(config: ConfigMap): MessageDispatcher = { + def configure(config: Configuration): MessageDispatcher = { configureThreadPool(config, threadPoolConfig => new ExecutorBasedEventDrivenDispatcher( config.getString("name", newUuid.toString), config.getInt("throughput", Dispatchers.THROUGHPUT), @@ -218,7 +218,7 @@ class ExecutorBasedEventDrivenDispatcherConfigurator extends MessageDispatcherCo } class ExecutorBasedEventDrivenWorkStealingDispatcherConfigurator extends MessageDispatcherConfigurator { - def configure(config: ConfigMap): MessageDispatcher = { + def configure(config: Configuration): MessageDispatcher = { configureThreadPool(config, threadPoolConfig => new ExecutorBasedEventDrivenWorkStealingDispatcher( config.getString("name", newUuid.toString), config.getInt("throughput", Dispatchers.THROUGHPUT), @@ -226,4 +226,4 @@ class ExecutorBasedEventDrivenWorkStealingDispatcherConfigurator extends Message mailboxType(config), threadPoolConfig)).build } -} \ No newline at end of file +} diff --git a/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala b/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala index 653e35cf01..efc9f96e72 100644 --- a/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala +++ b/akka-actor/src/main/scala/akka/dispatch/MessageHandling.scala @@ -6,7 +6,7 @@ package akka.dispatch import java.util.concurrent._ import atomic. {AtomicInteger, AtomicBoolean, AtomicReference, AtomicLong} -import akka.config.ConfigMap +import akka.config.Configuration import akka.config.Config.TIME_UNIT import akka.util.{Duration, Switch, ReentrantGuard, HashCode, ReflectiveAccess} import java.util.concurrent.ThreadPoolExecutor.{AbortPolicy, CallerRunsPolicy, DiscardOldestPolicy, DiscardPolicy} @@ -35,7 +35,7 @@ final case class FutureInvocation(future: CompletableFuture[Any], function: () = def run = future complete (try { Right(function.apply) } catch { - case e: Exception => + case e: Exception => EventHandler notifyListeners EventHandler.Error(e, this) Left(e) }) @@ -209,16 +209,16 @@ trait MessageDispatcher { * Trait to be used for hooking in new dispatchers into Dispatchers.fromConfig */ abstract class MessageDispatcherConfigurator { - def configure(config: ConfigMap): MessageDispatcher + def configure(config: Configuration): MessageDispatcher - def mailboxType(config: ConfigMap): MailboxType = { + def mailboxType(config: Configuration): MailboxType = { val capacity = config.getInt("mailbox-capacity", Dispatchers.MAILBOX_CAPACITY) // FIXME how do we read in isBlocking for mailbox? Now set to 'false'. if (capacity < 0) UnboundedMailbox() else BoundedMailbox(false, capacity, Duration(config.getInt("mailbox-push-timeout-time", Dispatchers.MAILBOX_PUSH_TIME_OUT.toMillis.toInt), TIME_UNIT)) } - def configureThreadPool(config: ConfigMap, createDispatcher: => (ThreadPoolConfig) => MessageDispatcher): ThreadPoolConfigDispatcherBuilder = { + def configureThreadPool(config: Configuration, createDispatcher: => (ThreadPoolConfig) => MessageDispatcher): ThreadPoolConfigDispatcherBuilder = { import ThreadPoolConfigDispatcherBuilder.conf_? //Apply the following options to the config if they are present in the config