mirror of
https://github.com/corda/corda.git
synced 2025-06-14 13:18:18 +00:00
Cleaned up notary configuration by introducing a notary config option.
extraAdvertisedServiceIds is no longer used for this.
This commit is contained in:
@ -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()
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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 }
|
||||
|
||||
}
|
Reference in New Issue
Block a user