diff --git a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt index 6e766d04c1..eb66be0174 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt @@ -16,6 +16,7 @@ import net.corda.core.node.services.Vault import net.corda.core.transactions.SignedTransaction import rx.Observable import java.io.InputStream +import java.io.OutputStream import java.time.Instant data class StateMachineInfo( @@ -99,6 +100,11 @@ interface CordaRPCOps : RPCOps { */ fun attachmentExists(id: SecureHash): Boolean + /** + * Download an attachment JAR by ID + */ + fun openAttachment(id: SecureHash): InputStream + /** * Uploads a jar to the node, returns it's hash. */ diff --git a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt index a0132f8423..df4f40122d 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt @@ -102,6 +102,7 @@ class CordaRPCOpsImpl( } override fun attachmentExists(id: SecureHash) = services.storageService.attachments.openAttachment(id) != null + override fun openAttachment(id: SecureHash) = services.storageService.attachments.openAttachment(id)!!.open() override fun uploadAttachment(jar: InputStream) = services.storageService.attachments.importAttachment(jar) override fun authoriseContractUpgrade(state: StateAndRef<*>, upgradedContractClass: Class>) = services.vaultService.authoriseContractUpgrade(state, upgradedContractClass) override fun deauthoriseContractUpgrade(state: StateAndRef<*>) = services.vaultService.deauthoriseContractUpgrade(state) diff --git a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt index 82ced2da6a..8f0df1e30b 100644 --- a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt +++ b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt @@ -25,15 +25,22 @@ import net.corda.testing.expectEvents import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork.MockNode import net.corda.testing.sequence +import org.apache.commons.io.IOUtils import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.Before import org.junit.Test import rx.Observable +import java.io.ByteArrayOutputStream +import java.util.* import kotlin.test.assertEquals import kotlin.test.assertFalse class CordaRPCOpsImplTest { + private companion object { + val testJar = "net/corda/node/testing/test.jar" + } + lateinit var network: MockNetwork lateinit var aliceNode: MockNode lateinit var notaryNode: MockNode @@ -199,4 +206,24 @@ class CordaRPCOpsImplTest { ) } } + + @Test + fun `can upload an attachment`() { + val inputJar = Thread.currentThread().contextClassLoader.getResourceAsStream(testJar) + val secureHash = rpc.uploadAttachment(inputJar) + assert(rpc.attachmentExists(secureHash)) + } + + @Test + fun `can download an uploaded attachment`() { + val inputJar = Thread.currentThread().contextClassLoader.getResourceAsStream(testJar) + val secureHash = rpc.uploadAttachment(inputJar) + val bufferFile = ByteArrayOutputStream() + val bufferRpc = ByteArrayOutputStream() + + IOUtils.copy(Thread.currentThread().contextClassLoader.getResourceAsStream(testJar), bufferFile) + IOUtils.copy(rpc.openAttachment(secureHash), bufferRpc) + + assert(Arrays.equals(bufferFile.toByteArray(), bufferRpc.toByteArray())) + } } diff --git a/node/src/test/resources/net/corda/node/testing/test.jar b/node/src/test/resources/net/corda/node/testing/test.jar new file mode 100644 index 0000000000..9ce0b7d2d2 Binary files /dev/null and b/node/src/test/resources/net/corda/node/testing/test.jar differ