Cleaned up notary configuration by introducing a notary config option.

extraAdvertisedServiceIds is no longer used for this.
This commit is contained in:
Shams Asari
2017-10-05 12:27:45 +01:00
parent 83f37417ae
commit 727cd0e55c
88 changed files with 600 additions and 716 deletions

View File

@ -1,6 +1,7 @@
package net.corda.nodeapi
import net.corda.nodeapi.config.OldConfig
import net.corda.nodeapi.config.toConfig
data class User(
@OldConfig("user")
@ -8,9 +9,6 @@ data class User(
val password: String,
val permissions: Set<String>) {
override fun toString(): String = "${javaClass.simpleName}($username, permissions=$permissions)"
fun toMap() = mapOf(
"username" to username,
"password" to password,
"permissions" to permissions
)
@Deprecated("Use toConfig().root().unwrapped() instead")
fun toMap(): Map<String, Any> = toConfig().root().unwrapped()
}

View File

@ -2,18 +2,23 @@
package net.corda.nodeapi.config
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigUtil
import com.typesafe.config.ConfigValueFactory
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.noneOrSingle
import net.corda.core.internal.uncheckedCast
import net.corda.core.utilities.NetworkHostAndPort
import org.slf4j.LoggerFactory
import java.lang.reflect.Field
import java.lang.reflect.ParameterizedType
import java.net.Proxy
import java.net.URL
import java.nio.file.Path
import java.nio.file.Paths
import java.time.Instant
import java.time.LocalDate
import java.time.temporal.Temporal
import java.util.*
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
@ -71,8 +76,8 @@ private fun Config.getSingleValue(path: String, type: KType): Any? {
NetworkHostAndPort::class -> NetworkHostAndPort.parse(getString(path))
Path::class -> Paths.get(getString(path))
URL::class -> URL(getString(path))
Properties::class -> getConfig(path).toProperties()
CordaX500Name::class -> CordaX500Name.parse(getString(path))
Properties::class -> getConfig(path).toProperties()
else -> if (typeClass.java.isEnum) {
parseEnum(typeClass.java, getString(path))
} else {
@ -126,4 +131,65 @@ private fun parseEnum(enumType: Class<*>, name: String): Enum<*> = enumBridge<Pr
private fun <T : Enum<T>> enumBridge(clazz: Class<T>, name: String): T = java.lang.Enum.valueOf(clazz, name)
/**
* Convert the receiver object into a [Config]. This does the inverse action of [parseAs].
*/
fun Any.toConfig(): Config = ConfigValueFactory.fromMap(toConfigMap()).toConfig()
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
// Reflect over the fields of the receiver and generate a value Map that can use to create Config object.
private fun Any.toConfigMap(): Map<String, Any> {
val values = HashMap<String, Any>()
for (field in javaClass.declaredFields) {
if (field.isSynthetic) continue
field.isAccessible = true
val value = field.get(this) ?: continue
val configValue = if (value is String || value is Boolean || value is Number) {
// These types are supported by Config as use as is
value
} else if (value is Temporal || value is NetworkHostAndPort || value is CordaX500Name || value is Path || value is URL) {
// These types make sense to be represented as Strings and the exact inverse parsing function for use in parseAs
value.toString()
} else if (value is Enum<*>) {
// Expicitly use the Enum's name in case the toString is overridden, which would make parsing problematic.
value.name
} else if (value is Properties) {
// For Properties we treat keys with . as nested configs
ConfigFactory.parseMap(uncheckedCast(value)).root()
} else if (value is Iterable<*>) {
value.toConfigIterable(field)
} else {
// Else this is a custom object recursed over
value.toConfigMap()
}
values[field.name] = configValue
}
return values
}
// For Iterables figure out the type parameter and apply the same logic as above on the individual elements.
private fun Iterable<*>.toConfigIterable(field: Field): Iterable<Any?> {
val elementType = (field.genericType as ParameterizedType).actualTypeArguments[0] as Class<*>
return when (elementType) {
// For the types already supported by Config we can use the Iterable as is
String::class.java -> this
Integer::class.java -> this
java.lang.Long::class.java -> this
java.lang.Double::class.java -> this
java.lang.Boolean::class.java -> this
LocalDate::class.java -> map(Any?::toString)
Instant::class.java -> map(Any?::toString)
NetworkHostAndPort::class.java -> map(Any?::toString)
Path::class.java -> map(Any?::toString)
URL::class.java -> map(Any?::toString)
CordaX500Name::class.java -> map(Any?::toString)
Properties::class.java -> map { ConfigFactory.parseMap(uncheckedCast(it)).root() }
else -> if (elementType.isEnum) {
map { (it as Enum<*>).name }
} else {
map { it?.toConfigMap() }
}
}
}
private val logger = LoggerFactory.getLogger("net.corda.nodeapi.config")

View File

@ -76,54 +76,66 @@ class ConfigParsingTest {
testPropertyType<URLData, URLListData, URL>(URL("http://localhost:1234"), URL("http://localhost:1235"), valuesToString = true)
}
@Test
fun CordaX500Name() {
testPropertyType<CordaX500NameData, CordaX500NameListData, CordaX500Name>(
CordaX500Name(organisation = "Mock Party", locality = "London", country = "GB"),
CordaX500Name(organisation = "Mock Party 2", locality = "London", country = "GB"),
valuesToString = true)
}
@Test
fun `flat Properties`() {
val config = config("value" to mapOf("key" to "prop"))
assertThat(config.parseAs<PropertiesData>().value).isEqualTo(Properties().apply { this["key"] = "prop" })
val data = PropertiesData(Properties().apply { this["key"] = "prop" })
assertThat(config.parseAs<PropertiesData>()).isEqualTo(data)
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
fun `Properties key with dot`() {
val config = config("value" to mapOf("key.key2" to "prop"))
assertThat(config.parseAs<PropertiesData>().value).isEqualTo(Properties().apply { this["key.key2"] = "prop" })
val data = PropertiesData(Properties().apply { this["key.key2"] = "prop" })
assertThat(config.parseAs<PropertiesData>().value).isEqualTo(data.value)
}
@Test
fun `nested Properties`() {
val config = config("value" to mapOf("first" to mapOf("second" to "prop")))
assertThat(config.parseAs<PropertiesData>().value).isEqualTo(Properties().apply { this["first.second"] = "prop" })
val data = PropertiesData(Properties().apply { this["first.second"] = "prop" })
assertThat(config.parseAs<PropertiesData>().value).isEqualTo(data.value)
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
fun `List of Properties`() {
val config = config("values" to listOf(emptyMap(), mapOf("key" to "prop")))
assertThat(config.parseAs<PropertiesListData>().values).containsExactly(
val data = PropertiesListData(listOf(
Properties(),
Properties().apply { this["key"] = "prop" })
Properties().apply { this["key"] = "prop" }))
assertThat(config.parseAs<PropertiesListData>().values).isEqualTo(data.values)
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
fun `Set`() {
val config = config("values" to listOf("a", "a", "b"))
assertThat(config.parseAs<StringSetData>().values).containsOnly("a", "b")
val data = StringSetData(setOf("a", "b"))
assertThat(config("values" to listOf("a", "a", "b")).parseAs<StringSetData>()).isEqualTo(data)
assertThat(data.toConfig()).isEqualTo(config("values" to listOf("a", "b")))
assertThat(empty().parseAs<StringSetData>().values).isEmpty()
}
@Test
fun x500Name() {
testPropertyType<X500NameData, X500NameListData, CordaX500Name>(CordaX500Name(organisation = "Mock Party", locality = "London", country = "GB"), CordaX500Name(organisation = "Mock Party 2", locality = "London", country = "GB"), valuesToString = true)
}
@Test
fun `multi property data class`() {
val data = config(
val config = config(
"b" to true,
"i" to 123,
"l" to listOf("a", "b"))
.parseAs<MultiPropertyData>()
val data = config.parseAs<MultiPropertyData>()
assertThat(data.i).isEqualTo(123)
assertThat(data.b).isTrue()
assertThat(data.l).containsExactly("a", "b")
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
@ -133,6 +145,7 @@ class ConfigParsingTest {
"value" to "nested"))
val data = NestedData(StringData("nested"))
assertThat(config.parseAs<NestedData>()).isEqualTo(data)
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
@ -143,12 +156,14 @@ class ConfigParsingTest {
mapOf("value" to "2")))
val data = DataListData(listOf(StringData("1"), StringData("2")))
assertThat(config.parseAs<DataListData>()).isEqualTo(data)
assertThat(data.toConfig()).isEqualTo(config)
}
@Test
fun `default value property`() {
assertThat(config("a" to 3).parseAs<DefaultData>()).isEqualTo(DefaultData(3, 2))
assertThat(config("a" to 3, "defaultOfTwo" to 3).parseAs<DefaultData>()).isEqualTo(DefaultData(3, 3))
assertThat(DefaultData(3).toConfig()).isEqualTo(config("a" to 3, "defaultOfTwo" to 2))
}
@Test
@ -156,12 +171,14 @@ class ConfigParsingTest {
assertThat(empty().parseAs<NullableData>().nullable).isNull()
assertThat(config("nullable" to null).parseAs<NullableData>().nullable).isNull()
assertThat(config("nullable" to "not null").parseAs<NullableData>().nullable).isEqualTo("not null")
assertThat(NullableData(null).toConfig()).isEqualTo(empty())
}
@Test
fun `old config property`() {
assertThat(config("oldValue" to "old").parseAs<OldData>().newValue).isEqualTo("old")
assertThat(config("newValue" to "new").parseAs<OldData>().newValue).isEqualTo("new")
assertThat(OldData("old").toConfig()).isEqualTo(config("newValue" to "old"))
}
private inline fun <reified S : SingleData<V>, reified L : ListData<V>, V : Any> testPropertyType(
@ -177,6 +194,7 @@ class ConfigParsingTest {
val config = config("value" to if (valueToString) value.toString() else value)
val data = constructor.call(value)
assertThat(config.parseAs<T>().value).isEqualTo(data.value)
assertThat(data.toConfig()).isEqualTo(config)
}
private inline fun <reified T : ListData<V>, V : Any> testListProperty(value1: V, value2: V, valuesToString: Boolean) {
@ -187,6 +205,7 @@ class ConfigParsingTest {
val config = config("values" to configValues.take(n))
val data = constructor.call(rawValues.take(n))
assertThat(config.parseAs<T>().values).isEqualTo(data.values)
assertThat(data.toConfig()).isEqualTo(config)
}
assertThat(empty().parseAs<T>().values).isEmpty()
}
@ -228,8 +247,8 @@ class ConfigParsingTest {
data class PathListData(override val values: List<Path>) : ListData<Path>
data class URLData(override val value: URL) : SingleData<URL>
data class URLListData(override val values: List<URL>) : ListData<URL>
data class X500NameData(override val value: CordaX500Name) : SingleData<CordaX500Name>
data class X500NameListData(override val values: List<CordaX500Name>) : ListData<CordaX500Name>
data class CordaX500NameData(override val value: CordaX500Name) : SingleData<CordaX500Name>
data class CordaX500NameListData(override val values: List<CordaX500Name>) : ListData<CordaX500Name>
data class PropertiesData(override val value: Properties) : SingleData<Properties>
data class PropertiesListData(override val values: List<Properties>) : ListData<Properties>
data class MultiPropertyData(val i: Int, val b: Boolean, val l: List<String>)
@ -242,5 +261,4 @@ class ConfigParsingTest {
val newValue: String)
enum class TestEnum { Value1, Value2 }
}