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 aba12670e0..f8a678471a 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt @@ -15,6 +15,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( @@ -98,6 +99,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 6bf007ddf3..20b2dca198 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt @@ -101,6 +101,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 currentNodeTime(): Instant = Instant.now(services.clock) override fun uploadFile(dataType: String, name: String?, file: InputStream): String { diff --git a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt index 170840485f..562e8fd10a 100644 --- a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt +++ b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt @@ -24,15 +24,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 @@ -196,4 +203,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