Reimport samples to main repo

This commit is contained in:
Mike Hearn
2016-11-17 12:03:40 +01:00
parent 02a90014e7
commit 90b083926f
4211 changed files with 818364 additions and 2 deletions

View File

@ -0,0 +1,35 @@
package net.corda.attachmentdemo
import net.corda.core.crypto.toBase58String
import net.corda.core.node.services.ServiceInfo
import net.corda.node.driver.driver
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.testing.getHostAndPort
import org.junit.Test
import kotlin.concurrent.thread
class AttachmentDemoTest {
@Test fun `runs attachment demo`() {
driver(dsl = {
startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.Companion.type)))
val nodeA = startNode("Bank A").get()
val nodeAApiAddr = nodeA.config.getHostAndPort("webAddress")
val nodeBApiAddr = startNode("Bank B").get().config.getHostAndPort("webAddress")
var recipientReturn: Boolean? = null
var senderReturn: Boolean? = null
val recipientThread = thread {
recipientReturn = AttachmentDemoClientApi(nodeAApiAddr).runRecipient()
}
val senderThread = thread {
val counterpartyKey = nodeA.nodeInfo.legalIdentity.owningKey.toBase58String()
senderReturn = AttachmentDemoClientApi(nodeBApiAddr).runSender(counterpartyKey)
}
recipientThread.join()
senderThread.join()
assert(recipientReturn == true)
assert(senderReturn == true)
}, isDebug = true)
}
}

View File

@ -0,0 +1,54 @@
package net.corda.attachmentdemo
import com.google.common.net.HostAndPort
import net.corda.core.utilities.loggerFor
import net.corda.testing.http.HttpUtils
import joptsimple.OptionParser
import kotlin.system.exitProcess
fun main(args: Array<String>) {
AttachmentDemo().main(args)
}
private class AttachmentDemo {
internal enum class Role() {
SENDER,
RECIPIENT
}
private companion object {
val log = loggerFor<AttachmentDemo>()
}
fun main(args: Array<String>) {
val parser = OptionParser()
val roleArg = parser.accepts("role").withRequiredArg().ofType(Role::class.java).required()
val options = try {
parser.parse(*args)
} catch (e: Exception) {
log.error(e.message)
printHelp(parser)
exitProcess(1)
}
val role = options.valueOf(roleArg)!!
when (role) {
Role.SENDER -> {
val api = AttachmentDemoClientApi(HostAndPort.fromString("localhost:10005"))
api.runSender(api.getOtherSideKey())
}
Role.RECIPIENT -> AttachmentDemoClientApi(HostAndPort.fromString("localhost:10007")).runRecipient()
}
}
private fun printHelp(parser: OptionParser) {
println("""
Usage: attachment-demo --role [RECIPIENT|SENDER] [options]
Please refer to the documentation in docs/build/index.html for more info.
""".trimIndent())
parser.printHelpOn(System.out)
}
}

View File

@ -0,0 +1,35 @@
package net.corda.attachmentdemo
import com.google.common.net.HostAndPort
import net.corda.testing.http.HttpApi
import okhttp3.OkHttpClient
import okhttp3.Request
import java.util.concurrent.TimeUnit
/**
* Interface for using the attachment demo API from a client.
*/
class AttachmentDemoClientApi(val hostAndPort: HostAndPort) {
private val api = HttpApi.fromHostAndPort(hostAndPort, apiRoot)
fun runRecipient(): Boolean {
return api.postJson("await-transaction")
}
fun runSender(otherSide: String): Boolean {
return api.postJson("$otherSide/send")
}
fun getOtherSideKey(): String {
// TODO: Add getJson to the API utils
val client = OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).build()
val request = Request.Builder().url("http://$hostAndPort/$apiRoot/other-side-key").build()
val response = client.newCall(request).execute()
require(response.isSuccessful) // TODO: Handle more gracefully.
return response.body().string()
}
private companion object {
private val apiRoot = "api/attachmentdemo"
}
}

View File

@ -0,0 +1,18 @@
package net.corda.attachmentdemo
import net.corda.core.node.services.ServiceInfo
import net.corda.node.driver.driver
import net.corda.node.services.transactions.SimpleNotaryService
/**
* This file is exclusively for being able to run your nodes through an IDE (as opposed to running deployNodes)
* Do not use in a production environment.
*/
fun main(args: Array<String>) {
driver(dsl = {
startNode("Notary", setOf(ServiceInfo(SimpleNotaryService.Companion.type)))
startNode("Bank A")
startNode("Bank B")
waitForAllNodesToFinish()
}, isDebug = true)
}

View File

@ -0,0 +1,100 @@
package net.corda.attachmentdemo.api
import net.corda.core.contracts.TransactionType
import net.corda.core.crypto.SecureHash
import net.corda.core.failure
import net.corda.core.node.ServiceHub
import net.corda.core.success
import net.corda.core.utilities.ApiUtils
import net.corda.core.utilities.Emoji
import net.corda.core.utilities.loggerFor
import net.corda.protocols.CashCommand
import net.corda.protocols.FinalityProtocol
import net.corda.testing.ALICE_KEY
import java.util.concurrent.CompletableFuture
import javax.ws.rs.*
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
import kotlin.test.assertEquals
@Path("attachmentdemo")
class AttachmentDemoApi(val services: ServiceHub) {
private val utils = ApiUtils(services)
private companion object {
val PROSPECTUS_HASH = SecureHash.parse("decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9")
val logger = loggerFor<AttachmentDemoApi>()
}
@POST
@Path("{party}/send")
@Consumes(MediaType.APPLICATION_JSON)
fun runSender(@PathParam("party") partyKey: String): Response {
return utils.withParty(partyKey) {
// Make sure we have the file in storage
// TODO: We should have our own demo file, not share the trader demo file
if (services.storageService.attachments.openAttachment(PROSPECTUS_HASH) == null) {
javaClass.classLoader.getResourceAsStream("bank-of-london-cp.jar").use {
val id = services.storageService.attachments.importAttachment(it)
assertEquals(PROSPECTUS_HASH, id)
}
}
// Create a trivial transaction that just passes across the attachment - in normal cases there would be
// inputs, outputs and commands that refer to this attachment.
val ptx = TransactionType.General.Builder(notary = null)
ptx.addAttachment(services.storageService.attachments.openAttachment(PROSPECTUS_HASH)!!.id)
// Despite not having any states, we have to have at least one signature on the transaction
ptx.signWith(ALICE_KEY)
// Send the transaction to the other recipient
val tx = ptx.toSignedTransaction()
services.invokeProtocolAsync<Unit>(FinalityProtocol::class.java, tx, emptySet<CashCommand>(), setOf(it)).resultFuture.success {
logger.info("Successfully sent attachment with the FinalityProtocol")
}.failure {
logger.error("Failed to send attachment with the FinalityProtocol")
}
Response.accepted().build()
}
}
@POST
@Path("await-transaction")
@Consumes(MediaType.APPLICATION_JSON)
fun runRecipient(): Response {
val future = CompletableFuture<Response>()
// Normally we would receive the transaction from a more specific protocol, but in this case we let [FinalityProtocol]
// handle receiving it for us.
services.storageService.validatedTransactions.updates.subscribe { event ->
// When the transaction is received, it's passed through [ResolveTransactionsProtocol], which first fetches any
// attachments for us, then verifies the transaction. As such, by the time it hits the validated transaction store,
// we have a copy of the attachment.
val tx = event.tx
val response = if (tx.attachments.isNotEmpty()) {
val attachment = services.storageService.attachments.openAttachment(tx.attachments.first())
assertEquals(PROSPECTUS_HASH, attachment?.id)
logger.info("File received - we're happy!\n\nFinal transaction is:\n\n${Emoji.renderIfSupported(event.tx)}")
Response.ok().entity("Final transaction is: ${Emoji.renderIfSupported(event.tx)}").build()
} else {
Response.serverError().entity("No attachments passed").build()
}
future.complete(response)
}
return future.get()
}
/**
* Gets details of the other side. To be removed when identity API is added.
*/
@GET
@Path("other-side-key")
@Produces(MediaType.APPLICATION_JSON)
fun getOtherSide(): Response? {
val key = services.networkMapCache.partyNodes.first { it != services.myInfo }.legalIdentity.owningKey.toBase58String()
return Response.ok().entity(key).build()
}
}

View File

@ -0,0 +1,16 @@
package net.corda.attachmentdemo.plugin
import net.corda.attachmentdemo.api.AttachmentDemoApi
import net.corda.core.node.CordaPluginRegistry
import net.corda.core.transactions.SignedTransaction
import net.corda.protocols.FinalityProtocol
class AttachmentDemoPlugin : CordaPluginRegistry() {
// A list of classes that expose web APIs.
override val webApis: List<Class<*>> = listOf(AttachmentDemoApi::class.java)
// A list of protocols that are required for this cordapp
override val requiredProtocols: Map<String, Set<String>> = mapOf(
FinalityProtocol::class.java.name to setOf(SignedTransaction::class.java.name, setOf(Unit).javaClass.name, setOf(Unit).javaClass.name)
)
override val servicePlugins: List<Class<*>> = listOf()
}

View File

@ -0,0 +1,2 @@
# Register a ServiceLoader service extending from net.corda.node.CordaPluginRegistry
net.corda.attachmentdemo.plugin.AttachmentDemoPlugin

View File

@ -0,0 +1 @@
These certificates are used for development mode only (and are copies of those contained within the TraderDemo jar file)