diff --git a/build.gradle b/build.gradle
index 7578f0a3fd..1a291b7279 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ buildscript {
file("publish.properties").withInputStream { props.load(it) }
// Our version: bump this on release.
- ext.corda_version = "0.8.1"
+ ext.corda_version = "0.8.2"
ext.gradle_plugins_version = props.getProperty("gradlePluginsVersion")
// Dependency versions. Can run 'gradle dependencyUpdates' to find new versions of things.
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/docs/source/getting-set-up-fault-finding.rst b/docs/source/getting-set-up-fault-finding.rst
index a3de482eb7..5f2b1c3038 100644
--- a/docs/source/getting-set-up-fault-finding.rst
+++ b/docs/source/getting-set-up-fault-finding.rst
@@ -6,7 +6,7 @@ Milestone releases
When you clone the corda or cordapp-template repos, they will default to the master branch. The master branch is being continuously developed upon, and its features may not align with the state of Corda as described in the docs. Additionally, the master branch of the CorDapp Template may break in response to changes in the main corda repo.
-When developing on Corda, you should always check out the latest stable release tag instead, by running ``git checkout release-M8.1``.
+When developing on Corda, you should always check out the latest stable release tag instead, by running ``git checkout release-M8.2``.
Java issues
-----------
diff --git a/docs/source/getting-set-up.rst b/docs/source/getting-set-up.rst
index ce2b59e0c4..dd85083860 100644
--- a/docs/source/getting-set-up.rst
+++ b/docs/source/getting-set-up.rst
@@ -76,7 +76,7 @@ and a basic CorDapp that you can use as the basis for your own CorDapps is avail
You can clone both of these repos to your local machine by running the command ``git clone [repo URL]``.
By default, both repos will be on the ``master`` branch. However, this is an unstable development branch. You should check
-out the latest milestone release (currently Milestone 8.1) instead by running ``git checkout release-M8.1``.
+out the latest milestone release (currently Milestone 8.2) instead by running ``git checkout release-M8.2``.
Opening Corda/CorDapps in IDEA
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 0ededb0acc..dab43f8372 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -2,7 +2,7 @@ Welcome to the Corda documentation!
===================================
`Corda `_ is an open-source distributed ledger platform. The latest *milestone* (i.e. stable)
-release is M8.1. The codebase is on `GitHub `_, and our community can be found on
+release is M8.2. The codebase is on `GitHub `_, and our community can be found on
`Slack `_ and in our `forum `_.
If you're new to Corda, you should start by learning about its motivating vision and architecture. A good introduction
diff --git a/docs/source/release-notes.rst b/docs/source/release-notes.rst
index 2f2e0cac91..de0779e0b7 100644
--- a/docs/source/release-notes.rst
+++ b/docs/source/release-notes.rst
@@ -3,6 +3,11 @@ Release notes
Here are brief summaries of what's changed between each snapshot release.
+Milestone 8.2
+-------------
+
+* Added an openAttachment endpoint to the RPC interface to allow downloading of attachments via RPC.
+
Milestone 8.1
-------------
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