Merge pull request #2028 from corda/cburlinchon-amqp-contract-attachment-serializer

ENT-1031 AMQP serializer for ContractAttachment, evaluate lazy attachment
This commit is contained in:
Katelyn Baker 2017-11-10 15:12:26 +00:00 committed by GitHub
commit 83857950fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 4 deletions

View File

@ -61,6 +61,7 @@ abstract class AbstractAMQPSerializationScheme : SerializationScheme {
register(net.corda.nodeapi.internal.serialization.amqp.custom.InputStreamSerializer) 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.BitSetSerializer(this))
register(net.corda.nodeapi.internal.serialization.amqp.custom.EnumSetSerializer(this)) register(net.corda.nodeapi.internal.serialization.amqp.custom.EnumSetSerializer(this))
register(net.corda.nodeapi.internal.serialization.amqp.custom.ContractAttachmentSerializer(this))
} }
for (whitelistProvider in serializationWhitelists) for (whitelistProvider in serializationWhitelists)
factory.addToWhitelist(*whitelistProvider.whitelist.toTypedArray()) factory.addToWhitelist(*whitelistProvider.whitelist.toTypedArray())

View File

@ -0,0 +1,32 @@
package net.corda.nodeapi.internal.serialization.amqp.custom
import net.corda.core.contracts.Attachment
import net.corda.core.contracts.ContractAttachment
import net.corda.core.contracts.ContractClassName
import net.corda.core.serialization.MissingAttachmentsException
import net.corda.nodeapi.internal.serialization.GeneratedAttachment
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory
/**
* A serializer for [ContractAttachment] that uses a proxy object to write out the full attachment eagerly.
* @param factory the serializerFactory
*/
class ContractAttachmentSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<ContractAttachment,
ContractAttachmentSerializer.ContractAttachmentProxy>(ContractAttachment::class.java,
ContractAttachmentProxy::class.java, factory) {
override fun toProxy(obj: ContractAttachment): ContractAttachmentProxy {
val bytes = try {
obj.attachment.open().readBytes()
} catch (e: Exception) {
throw MissingAttachmentsException(listOf(obj.id))
}
return ContractAttachmentProxy(GeneratedAttachment(bytes), obj.contract)
}
override fun fromProxy(proxy: ContractAttachmentProxy): ContractAttachment {
return ContractAttachment(proxy.attachment, proxy.contract)
}
data class ContractAttachmentProxy(val attachment: Attachment, val contract: ContractClassName)
}

View File

@ -1,10 +1,6 @@
package net.corda.nodeapi.internal.serialization.amqp package net.corda.nodeapi.internal.serialization.amqp
import net.corda.core.CordaRuntimeException import net.corda.core.CordaRuntimeException
import net.corda.core.contracts.Contract
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TransactionState
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowException import net.corda.core.flows.FlowException
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
@ -13,19 +9,26 @@ import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializationFactory import net.corda.core.serialization.SerializationFactory
import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.LedgerTransaction
import net.corda.client.rpc.RPCException import net.corda.client.rpc.RPCException
import net.corda.core.contracts.*
import net.corda.core.internal.AbstractAttachment
import net.corda.core.serialization.MissingAttachmentsException
import net.corda.nodeapi.internal.serialization.AllWhitelist import net.corda.nodeapi.internal.serialization.AllWhitelist
import net.corda.nodeapi.internal.serialization.EmptyWhitelist import net.corda.nodeapi.internal.serialization.EmptyWhitelist
import net.corda.nodeapi.internal.serialization.GeneratedAttachment
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.Companion.isPrimitive import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.Companion.isPrimitive
import net.corda.testing.BOB_IDENTITY import net.corda.testing.BOB_IDENTITY
import net.corda.testing.MEGA_CORP import net.corda.testing.MEGA_CORP
import net.corda.testing.MEGA_CORP_PUBKEY import net.corda.testing.MEGA_CORP_PUBKEY
import net.corda.testing.contracts.DummyContract
import net.corda.testing.withTestSerialization import net.corda.testing.withTestSerialization
import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.SimpleString
import org.apache.qpid.proton.amqp.* import org.apache.qpid.proton.amqp.*
import org.apache.qpid.proton.codec.DecoderImpl import org.apache.qpid.proton.codec.DecoderImpl
import org.apache.qpid.proton.codec.EncoderImpl import org.apache.qpid.proton.codec.EncoderImpl
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertNotSame import org.junit.Assert.assertNotSame
import org.junit.Assert.assertSame import org.junit.Assert.assertSame
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Ignore import org.junit.Ignore
import org.junit.Test import org.junit.Test
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
@ -993,4 +996,36 @@ class SerializationOutputTests {
obj[Month.AUGUST] = Month.AUGUST.value obj[Month.AUGUST] = Month.AUGUST.value
serdes(obj) serdes(obj)
} }
@Test
fun `test contract attachment serialize`() {
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.ContractAttachmentSerializer(factory))
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ContractAttachmentSerializer(factory2))
val obj = ContractAttachment(GeneratedAttachment("test".toByteArray()), DummyContract.PROGRAM_ID)
val obj2 = serdes(obj, factory, factory2, expectedEqual = false, expectDeserializedEqual = false)
assertEquals(obj.id, obj2.attachment.id)
assertEquals(obj.contract, obj2.contract)
assertArrayEquals(obj.open().readBytes(), obj2.open().readBytes())
}
@Test
fun `test contract attachment throws if missing attachment`() {
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.ContractAttachmentSerializer(factory))
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ContractAttachmentSerializer(factory2))
val obj = ContractAttachment(object : AbstractAttachment({ throw Exception() }) {
override val id = SecureHash.zeroHash
}, DummyContract.PROGRAM_ID)
assertThatThrownBy {
serdes(obj, factory, factory2, expectedEqual = false, expectDeserializedEqual = false)
}.isInstanceOf(MissingAttachmentsException::class.java)
}
} }