From 13001ee6747731a4e915c6081f4e539e6fb03252 Mon Sep 17 00:00:00 2001 From: Christian Sailer Date: Fri, 10 Nov 2017 10:23:19 +0000 Subject: [PATCH] CORDA-781 code review: clean up AMQP scheme --- .../amqp/AMQPSerializationScheme.kt | 70 ++++++++--------- .../kryo/KryoSerializationScheme.kt | 2 +- .../amqp/OverridePKSerializerTest.kt | 75 +++++++++++++++++++ .../amqp/SerializationOutputTests.kt | 12 ++- 4 files changed, 121 insertions(+), 38 deletions(-) create mode 100644 node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/OverridePKSerializerTest.kt diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializationScheme.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializationScheme.kt index 78f3a9752f..df2fd31576 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializationScheme.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializationScheme.kt @@ -29,48 +29,48 @@ abstract class AbstractAMQPSerializationScheme : SerializationScheme { private val serializationWhitelists: List by lazy { ServiceLoader.load(SerializationWhitelist::class.java, this::class.java.classLoader).toList() + DefaultWhitelist } + } - fun registerCustomSerializers(factory: SerializerFactory, publicKeySerializer: CustomSerializer.Implements = net.corda.nodeapi.internal.serialization.amqp.custom.PublicKeySerializer) { - with(factory) { - register(publicKeySerializer) - register(net.corda.nodeapi.internal.serialization.amqp.custom.PrivateKeySerializer) - register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.X500NameSerializer) - register(net.corda.nodeapi.internal.serialization.amqp.custom.BigDecimalSerializer) - register(net.corda.nodeapi.internal.serialization.amqp.custom.CurrencySerializer) - register(net.corda.nodeapi.internal.serialization.amqp.custom.OpaqueBytesSubSequenceSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.InstantSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.DurationSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.LocalDateSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.LocalDateTimeSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.LocalTimeSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.ZonedDateTimeSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.ZoneIdSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.OffsetTimeSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.OffsetDateTimeSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.YearSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.YearMonthSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.MonthDaySerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.PeriodSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.ClassSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.X509CertificateHolderSerializer) - register(net.corda.nodeapi.internal.serialization.amqp.custom.PartyAndCertificateSerializer(factory)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.StringBufferSerializer) - register(net.corda.nodeapi.internal.serialization.amqp.custom.SimpleStringSerializer) - register(net.corda.nodeapi.internal.serialization.amqp.custom.InputStreamSerializer) - register(net.corda.nodeapi.internal.serialization.amqp.custom.BitSetSerializer(this)) - register(net.corda.nodeapi.internal.serialization.amqp.custom.EnumSetSerializer(this)) - } - for (whitelistProvider in serializationWhitelists) - factory.addToWhitelist(*whitelistProvider.whitelist.toTypedArray()) + private fun registerCustomSerializers(factory: SerializerFactory) { + with(factory) { + register(publicKeySerializer) + register(net.corda.nodeapi.internal.serialization.amqp.custom.PrivateKeySerializer) + register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.X500NameSerializer) + register(net.corda.nodeapi.internal.serialization.amqp.custom.BigDecimalSerializer) + register(net.corda.nodeapi.internal.serialization.amqp.custom.CurrencySerializer) + register(net.corda.nodeapi.internal.serialization.amqp.custom.OpaqueBytesSubSequenceSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.InstantSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.DurationSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.LocalDateSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.LocalDateTimeSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.LocalTimeSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.ZonedDateTimeSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.ZoneIdSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.OffsetTimeSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.OffsetDateTimeSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.YearSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.YearMonthSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.MonthDaySerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.PeriodSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.ClassSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.X509CertificateHolderSerializer) + register(net.corda.nodeapi.internal.serialization.amqp.custom.PartyAndCertificateSerializer(factory)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.StringBufferSerializer) + register(net.corda.nodeapi.internal.serialization.amqp.custom.SimpleStringSerializer) + register(net.corda.nodeapi.internal.serialization.amqp.custom.InputStreamSerializer) + register(net.corda.nodeapi.internal.serialization.amqp.custom.BitSetSerializer(this)) + register(net.corda.nodeapi.internal.serialization.amqp.custom.EnumSetSerializer(this)) } + for (whitelistProvider in serializationWhitelists) + factory.addToWhitelist(*whitelistProvider.whitelist.toTypedArray()) } private val serializerFactoriesForContexts = ConcurrentHashMap, SerializerFactory>() protected abstract fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory protected abstract fun rpcServerSerializerFactory(context: SerializationContext): SerializerFactory - open protected val publicKeySerializer = net.corda.nodeapi.internal.serialization.amqp.custom.PublicKeySerializer + open protected val publicKeySerializer: CustomSerializer.Implements = net.corda.nodeapi.internal.serialization.amqp.custom.PublicKeySerializer private fun getSerializerFactory(context: SerializationContext): SerializerFactory { return serializerFactoriesForContexts.computeIfAbsent(Pair(context.whitelist, context.deserializationClassLoader)) { @@ -83,7 +83,7 @@ abstract class AbstractAMQPSerializationScheme : SerializationScheme { rpcServerSerializerFactory(context) else -> SerializerFactory(context.whitelist, context.deserializationClassLoader) } - }.also { registerCustomSerializers(it, publicKeySerializer) } + }.also { registerCustomSerializers(it) } } override fun deserialize(byteSequence: ByteSequence, clazz: Class, context: SerializationContext): T { diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoSerializationScheme.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoSerializationScheme.kt index f951cf76be..737a330bba 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoSerializationScheme.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoSerializationScheme.kt @@ -40,7 +40,7 @@ abstract class AbstractKryoSerializationScheme : SerializationScheme { protected abstract fun rpcClientKryoPool(context: SerializationContext): KryoPool protected abstract fun rpcServerKryoPool(context: SerializationContext): KryoPool - // this can be overriden in derived serialization schemes (e.g. in the enterprise version of CORDA) + // this can be overriden in derived serialization schemes open protected val publicKeySerializer: Serializer = PublicKeySerializer private fun getPool(context: SerializationContext): KryoPool { diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/OverridePKSerializerTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/OverridePKSerializerTest.kt new file mode 100644 index 0000000000..8886e24231 --- /dev/null +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/OverridePKSerializerTest.kt @@ -0,0 +1,75 @@ +package net.corda.nodeapi.internal.serialization.amqp + +import net.corda.core.serialization.SerializationContext +import net.corda.core.utilities.ByteSequence +import net.corda.nodeapi.internal.serialization.AMQP_P2P_CONTEXT +import net.corda.nodeapi.internal.serialization.AMQP_RPC_CLIENT_CONTEXT +import net.corda.nodeapi.internal.serialization.SerializationContextImpl +import net.corda.nodeapi.internal.serialization.amqp.custom.PublicKeySerializer +import org.apache.qpid.proton.codec.Data +import org.assertj.core.api.Assertions +import org.junit.Assert +import org.junit.Test +import java.lang.reflect.Type +import java.security.PublicKey + +class OverridePKSerializerTest { + class SerializerTestException(message: String) : Exception(message) + + class TestPublicKeySerializer : CustomSerializer.Implements(PublicKey::class.java) { + override fun writeDescribedObject(obj: PublicKey, data: Data, type: Type, output: SerializationOutput) { + throw SerializerTestException("Custom write call") + } + + override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): PublicKey { + throw SerializerTestException("Custom read call") + } + + override val schemaForDocumentation: Schema + get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. + + } + + class AMQPTestSerializationScheme : AbstractAMQPSerializationScheme() { + override fun rpcServerSerializerFactory(context: SerializationContext): SerializerFactory { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun canDeserializeVersion(byteSequence: ByteSequence, target: SerializationContext.UseCase): Boolean = true + + override fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override val publicKeySerializer = TestPublicKeySerializer() + + } + + class TestPublicKey : PublicKey { + override fun getAlgorithm(): String { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun getEncoded(): ByteArray { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun getFormat(): String { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + } + + @Test + fun `test publicKeySerializer is overridden`() { + val scheme = AMQPTestSerializationScheme() + val key = TestPublicKey() + + Assertions + .assertThatThrownBy { scheme.serialize(key, AMQP_P2P_CONTEXT) } + .hasMessageMatching("Custom write call") + + + } + +} \ No newline at end of file diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt index d6527fd816..3aaadb5929 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt @@ -36,6 +36,10 @@ import java.nio.ByteBuffer import java.time.* import java.time.temporal.ChronoUnit import java.util.* +import kotlin.reflect.full.declaredFunctions +import kotlin.reflect.full.declaredMemberFunctions +import kotlin.reflect.full.superclasses +import kotlin.reflect.jvm.javaMethod import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -557,11 +561,15 @@ class SerializationOutputTests { fun `test transaction state`() { val state = TransactionState(FooState(), FOO_PROGRAM_ID, MEGA_CORP) + val scheme = AMQPServerSerializationScheme() + val func = scheme::class.superclasses.single { it.simpleName == "AbstractAMQPSerializationScheme" }.java.getDeclaredMethod("registerCustomSerializers", SerializerFactory::class.java) + func.isAccessible = true + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) - AbstractAMQPSerializationScheme.registerCustomSerializers(factory) + func.invoke(scheme, factory) val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) - AbstractAMQPSerializationScheme.registerCustomSerializers(factory2) + func.invoke(scheme, factory2) val desState = serdes(state, factory, factory2, expectedEqual = false, expectDeserializedEqual = false) assertTrue((desState as TransactionState<*>).data is FooState)