pbfunc外部扩展函数_从外部CorDapp扩展和覆盖流

pbfunc外部扩展函数

Corda 4于上周(2月21日)发布,带来了大量的新功能,使Corda更加令人愉快。 老实说,我有点假设有很多新功能。 我快速浏览了变更日志,主要是看到我的贡献被引用,但是我记得看到很多文本行。 那一定是一件好事吧?

无论如何,这些功能之一就是能够扩展和覆盖流程。 当您意识到Corda用Kotlin编写并完全继承了继承性时,听起来并不是很花哨(对于Java也是如此)。 但是,不仅如此。 Corda需要将“发起流程”映射到与其响应的交易对手流程。

当两方使用相同的CorDapp时,这很好。 在这种情况下,不会增加任何额外的复杂性。 另一方面,如果交易对手希望在收到交易后将一些数据发送到外部系统,他们该怎么做? 原始的CorDapp不了解或不关心此系统,因此无法满足这些需求。 能够解决这类问题,使开发人员可以在现有的CorDapps的基础上进行构建,并使它们适应于其用例。 此外,一旦制定了良好的实践,扩展第三方CorDapps将变得更加容易,并且在其他人已经解决了部分问题的同时,不再需要开发团队不断重新发明轮子。 显然,这假定可以访问这些外部CorDapp,但这完全是可能的。 特别是在R3 Marketplace已经展示了一个集合的情况下。

在本文中,我们将专注于扩展和覆盖流程。 此外,我们将采用两种不同观点的观点。

  • CorDapp的开发人员/维护人员
  • 想要使用和改编现有CorDapp的开发人员

为了使该过程正常进行,双方都必须努力以适当的方式编写其应用程序,以便可以利用其收益。

我们将首先查看原始CorDapp必须包含的内容,然后是开发人员必须进行扩展的内容。

在我们进行下一步之前,这里是指向有关扩展和覆盖流程的官方文档的链接。

编写基本流程以允许扩展

以一种易于扩展的方式编写CorDapp可能需要进行大量思考。 这在很大程度上取决于CorDapp维护人员要实现的目标。 为开发人员提供一种扩展CorDapp的方式,以便他们可以将数据发送到外部系统或添加自己的日志记录,这不会造成任何问题。 另一方面,允许更改事务的内容或将事务的内容发送给谁将需要更多的考虑以确保不滥用CorDapp。 我希望在以后的帖子中进一步探讨这个主题。

出于本文的目的,我们将介绍更简单的选项。 让我们直接进入,因为到目前为止有很多文本,没有代码。 下面是将充当“基本”流的SendMessageFlow ,它将在后面的部分中进行扩展:

@InitiatingFlow
open class SendMessageFlow(private val message: MessageState) :FlowLogic<SignedTransaction>() {open fun preTransactionBuild() {// to be implemented by sub type flows - otherwise do nothing}open fun preSignaturesCollected(transaction: SignedTransaction) {// to be implemented by sub type flows - otherwise do nothing}open fun postSignaturesCollected(transaction: SignedTransaction) {// to be implemented by sub type flows - otherwise do nothing}open fun postTransactionCommitted(transaction: SignedTransaction) {// to be implemented by sub type flows - otherwise do nothing}@Suspendablefinal override fun call(): SignedTransaction {logger.info("Started sending message ${message.contents}")preTransactionBuild()val tx = verifyAndSign(transaction())preSignaturesCollected(tx)val sessions = listOf(initiateFlow(message.recipient))val stx = collectSignature(tx, sessions)postSignaturesCollected(stx)return subFlow(FinalityFlow(stx, sessions)).also {logger.info("Finished sending message ${message.contents}")postTransactionCommitted(it)}}// collectSignature// verifyAndSign// transaction
}

我删除了一些功能,因此我们可以专注于重要的事情。

允许扩展此类的第一步甚至有时很重要的步骤是它是open 。 这更像是Kotlin,而不是Java,因为Kotlin中的所有类默认都是final 。 如果您使用Java编写此代码,则只需忽略最后几句话!

接下来,有一系列可以被覆盖的功能。 每个功能已放置在Flow主要执行程序内的适当位置。 Flow运行时将调用它们。 目前,由于没有为CorDapp开发人员提供任何使用,因此为他们提供了空的实现。

关于open功能。 您可以命名它们或将它们放置在任何需要的位置。 我认为这些功能对于希望在基本应用程序提供的内容上增加额外可追溯性的开发人员很有用。

深入了解更多细节。 call函数已被final (与Java中相同),以防止覆盖Flow的全部内容。 如果有人想采用您的Flow并完全取代其“主要”功能,那有什么意义呢? 对我来说,这似乎有点狡猾。 为了消除这种可能性,将其final是明智之举。

稍后,我们将研究如何将此Flow子类化。

下面是与SendMessageResponder交互的SendMessageFlow 。 它遵循与上述相同的概念,因此在以后我仅将其作为参考:

@InitiatedBy(SendMessageFlow::class)
open class SendMessageResponder(private val session: FlowSession) : FlowLogic<Unit>() {open fun postTransactionSigned(transaction: SignedTransaction) {// to be implemented by sub type flows - otherwise do nothing}open fun postTransactionCommitted(transaction: SignedTransaction) {// to be implemented by sub type flows - otherwise do nothing}@Suspendablefinal override fun call() {val stx = subFlow(object : SignTransactionFlow(session) {override fun checkTransaction(stx: SignedTransaction) {}})postTransactionSigned(stx)val committed = subFlow(ReceiveFinalityFlow(otherSideSession = session,expectedTxId = stx.id))postTransactionCommitted(committed)}
}

扩展现有的启动流

在本节中,我们将看到开发人员如何利用在上一个Flow上完成的工作。 它已经具有所有必需的功能。 唯一缺少的是开发人员想要添加的少量额外的可跟踪性。这要归功于基本Flow所添加的功能。 这不会造成任何问题。

让我们从扩展启动流开始。 这样做的要求如下:

  • 扩展基础@InitiatingFlow
  • 不要添加@InitiatingFlow到新的流程(错误会发生,如果你这样做)
  • 引用基本Flow的构造函数(Java中的super
  • 覆盖任何所需的功能
  • 调用新流程而不是基本流程

阅读该列表后,您可能已经意识到,这几乎是对面向对象语言(例如Kotlin和Java)中继承的描述。 Corda内可能还有更多事情要做,但是从您的角度来看,您只是像往常一样编写普通的面向对象代码。

遵循这些要求,我们可以看到扩展的Flow可能是什么样的:

@StartableByRPC
class CassandraSendMessageFlow(private val message: MessageState) :SendMessageFlow(message) {override fun preTransactionBuild() {serviceHub.cordaService(MessageRepository::class.java).save(message,sender = true,committed = false)logger.info("Starting transaction for message: $message")}override fun preSignaturesCollected(transaction: SignedTransaction) {val keys = transaction.requiredSigningKeys - ourIdentity.owningKeylogger.info("Collecting signatures from $keys for transaction for message: $message")}override fun postSignaturesCollected(transaction: SignedTransaction) {logger.info("Collected signatures for transaction for message: $message")}override fun postTransactionCommitted(transaction: SignedTransaction) {serviceHub.cordaService(MessageRepository::class.java).save(message,sender = true,committed = true)logger.info("Committed transaction for message: $message")}
}

我留下了实现我所谈论的额外可追溯性的所有嘈杂函数,但这是由于没有它们的类将有多么空。 由于不需要call 。 此流程仅需要覆盖open功能。 老实说,根本不需要覆盖它们,它们是可选的。 如果需要,此流可以覆盖单个函数,然后将其保留为空。

是否满足上述所有要求?

  • CassandraSendMessageFlow扩展了SendMessageFlow
  • 看不到@InitiatingFlow
  • 在Kotlin中,无论如何都必须调用super构造函数,这样就完成了
  • 在这种情况下,所有功能都被覆盖
  • 我们还没有走这么远

好的,到目前为止是4/5。 那是一个很好的开始。 要划掉列表中的最后一项,我们需要查看其调用方式。 以下是调用基本SendMessageFlowCassandraSendMessageFlow扩展Flow的代码片段。

SendMessageFlow开始:

proxy.startFlow(::SendMessageFlow, messageState)

其次是CassandraSendMessageFlow

proxy.startFlow(::CassandraSendMessageFlow, messageState)

注意区别吗? 在这种情况下,仅流的名称已更改。 没有其他的。

这两个代码段都是完全有效的。 仍然允许调用原始的SendMessageFlow 。 请记住,从我们的角度来看,它只是普通的面向对象代码。 它不会在扩展的Flow中添加多余的代码,但是它仍然可以执行而不会出现问题。 完成此步骤符合扩展@InitiatingFlow的最后要求。

在结束本节之前,这里是Corda文档中需要记住的重要信息:

“您必须确保子类中的发送/接收/子流的顺序与父类兼容。”

我将把它放在以下所有部分中,因为不遵循这将导致您的流程失败。

扩展响应者流程

扩展响应者流的方式与扩展@InitiatingFlow流的方式非常相似。 唯一的区别是它的调用方式。 如文档中所述:

“ Corda会检测到 BaseResponder SubResponder 都已配置为响应发起方。 然后,Corda将计算到 FlowLogic 的跃点, 并选择距离最远的实现,即:子类化最多的实现。”

“最子类化”的陈述是本文的重要内容。 因此,从开发人员的角度来看,他们所需要做的就是扩展外部基本响应程序流,仅此而已。 我非常喜欢之前的需求列表,因此让我们再看一遍扩展响应者流程:

  • 扩展基础@InitiatedBy /响应者流
  • @InitiatedBy添加到新流程
  • 引用基本Flow的构造函数(Java中的super
  • 覆盖任何所需的功能

如果您保持警惕,您可能已经注意到,没有提到如何调用它。 扩展的“响应者流”不需要在其他任何地方调用或引用。 Corda将尽一切努力将所有物品路由到正确的位置。

可以肯定的是,让我们快速看一个例子:

@InitiatedBy(SendMessageFlow::class)
class CassandraSendMessageResponder(session: FlowSession) :SendMessageResponder(session) {override fun postTransactionSigned(transaction: SignedTransaction) {val message = transaction.coreTransaction.outputsOfType<MessageState>().single()logger.info("Signed transaction for message: $message")}override fun postTransactionCommitted(transaction: SignedTransaction) {val message = transaction.coreTransaction.outputsOfType<MessageState>().single()serviceHub.cordaService(MessageRepository::class.java).save(message,sender = false,committed = true)logger.info("Committed transaction for message: $message")}
}

此外,让我们再次回顾“最子类化”的说法。 CassandraSendMessageResponderSendMessageResponder的子类,因此由Corda选择以处理来自启动流的请求。 但是,这可以采取进一步的措施。 如果还有另一个类,例如说SuperSpecialCassandraSendMessageResponder ,那么此流程现在就是Corda将开始使用的流程。 尽管我确实发现这种情况目前不太可能,但绝对值得了解。

再次复制并粘贴此语句,这样您就不会忘记:

“您必须确保子类中的发送/接收/子流的顺序与父类兼容。”

覆盖响应者流程

这是故意的一个单独的部分。 在这里,我们将专门讨论覆盖响应程序流而不是扩展响应流。 您为什么要这样做,有什么区别? 回答第一个问题,开发人员可能想要编写一个与原始基本流程大不相同的Responder Flow,但仍需要与外部CorDapp提供的特定启动流程进行交互。 为此,他们可以覆盖Flow。 另一个描述这个的词可以是“替换”。 原始基本流程完全被覆盖流程取代。 在这种情况下不涉及扩展。

我认为Corda文档在此主题上的措辞非常好:

“虽然子类化方法可能对大多数应用程序有用,但是还有另一种机制可以覆盖这种行为。 例如,如果特定的CordApp用户需要这样一个不同的响应者,以子类化现有流将不是一个好的解决方案,那么这将很有用。”

希望此摘录以及我之前的描述将阐明扩展和覆盖响应程序流之间的区别。

那么,最重要的Flow会是什么样子? 好吧,在合理范围内,您真正想要的任何东西。 也许看起来像下面,尽管我对此表示怀疑:

@InitiatedBy(SendMessageFlow::class)
class OverridingResponder(private val session: FlowSession) :FlowLogic<Unit>() {@Suspendableoverride fun call() {val stx = subFlow(object : SignTransactionFlow(session) {override fun checkTransaction(stx: SignedTransaction) {}})logger.info("Screw the original responder. I'll build my own responder... with blackjack and hookers!")subFlow(ReceiveFinalityFlow(otherSideSession = session,expectedTxId = stx.id))}
}

由于此流程完全替代了原始基本流程,因此它看起来就像普通的响应者流程。 既然是这样,那就好了。 这意味着它有@InitiatedBy引用了Initiating Flow,扩展了FlowLogic并实现了call函数。

最后一次将它放在这里:

“您必须确保子类中的发送/接收/子流的顺序与父类兼容。”

与上一节相比,这在这里更为普遍。 由于整个call函数都已被覆盖,因此您必须确保每个sendreceive都在正确的位置,以便与启动流的交互运行不会出错。

在配置方面,要做更多的事情,而不是扩展Flow。 在这种情况下,我们正在尝试将响应者完全替换为另一个。 为此,我们需要一种方法来告诉节点将交互从“发起流”重定向到新的优先响应器流。 Corda提供了一种做到这一点的方法。

要指定重定向,请将以下内容添加到您的node.conf

flowOverrides {overrides=[{initiator="com.lankydanblog.tutorial.base.flows.SendMessageFlow"responder="com.lankydanblog.tutorial.cassandra.flows.OverridingResponder"}]
}

显然,更改您自己引用的类…

那么这是怎么回事? 这个配置说, SendMessageFlow通常与之交互SendMessageResponder现在将路线OverridingResponder代替。

为了使一切都变得更简单, Cordform插件提供了flowOverride方法作为deployNodes一部分。 然后,将为您生成上面的配置块。 对于上面的示例,使用了以下代码:

node {name "O=PartyA,L=London,C=GB"p2pPort 10002rpcSettings {address("localhost:10006")adminAddress("localhost:10046")}rpcUsers = [[user: "user1", "password": "test", "permissions": ["ALL"]]]cordapp(project(':cordapp-contracts-states'))cordapp(project(':cordapp'))cordapp(project(':cordapp-extended-cassandra'))// the important partflowOverride("com.lankydanblog.tutorial.base.flows.SendMessageFlow","com.lankydanblog.tutorial.cassandra.flows.OverridingResponder")
}

现在,在deployNodes运行并启动了节点之后,来自SendMessageFlow或其任何子类的任何请求现在都将通信路由到OverridingResponder

结论

Corda 4提供的便捷功能之一就是能够从第三方CorDapps(或您自己的)自定义Flows。 这可以通过两种方法来完成,即扩展或覆盖。

扩展将是我在这两者之间的第一选择,但确实需要CorDapp开发人员付出更多的努力。 他们必须提供足够的自定义渠道,而不能放弃对Flows原始功能的控制。 提供很少的自定义可能不会阻止其他开发人员使用他们的CorDapp。 但是,开发人员可能会对缺乏对自己的应用程序的控制感到不满。 这是一个湿滑的坡道,可通过自定义路线来控制原始意图。 另一方面,实际上扩展Flow并不需要太多工作,这使开发人员更容易采用和适应外部Flow。

另一方面,对于CorDapp开发人员而言,覆盖不需要任何工作,而是可以利用外部“响应程序流”将所有内容放入开发人员。 那是因为现有的Flow几乎被丢弃了,并且回溯到原始实现的唯一参考就是指向Initiating Flow的链接。

通过拥抱Flow的扩展和覆盖,CorDapp开发人员将能够利用外部CorDapp,同时仍提供足够的自定义功能来满足他们可能拥有的所有业务需求。 随着时间的流逝,开发人员将推动重用现有CorDapps的使用,因为它们提供了对其他自定义的访问权限,很快将与我们在任何工作中已经利用的开源库的地位相同。

这篇文章中使用的代码可以在我的GitHub上找到 。 它包含CassandraSendMessageFlow的代码,该代码建立与外部Cassandra数据库的连接以保存跟踪样式数据。 它还包含另一个模块,该模块发送HTTP请求作为其基本流扩展的一部分。 如果您在阅读本文后仍然感到好奇,则此存储库可能会有所帮助。

如果您喜欢这篇文章或发现它有帮助(或两者都有),请随时在Twitter上@LankyDanDev关注我,并记住与可能对您有用的任何人分享!

翻译自: https://www.javacodegeeks.com/2019/03/extending-overriding-flows-cordapps.html

pbfunc外部扩展函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/332794.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

表单项标签的input标签的单选框(radio)

<input type"radio" name"gender" value"male"> 男 <input type"radio" name"gender" value"female"> 女1.单选框需要注意的是&#xff0c;如果是属于一组的选项&#xff0c;那么 name 属性的值必须相…

java 6 update 3_Java(TM) 6 Update(java运行环境) V 6.0.450.6 官方版

Java(TM) 6 Update是个JAVA辅助软件&#xff0c;它具备高度的安全性以及跨平台的特性&#xff0c;能让你的电脑或手机运行java程序&#xff0c;用户可使用Java(TM) 6 Update来搭建甚至运行整个ava程序&#xff0c;注意&#xff1a;卸载后JAVA环境的程序将无法运行。过去很可能会…

jep290涉及jdk版本_JDK 9 / JEP 280:字符串串联永远不会相同

jep290涉及jdk版本JEP 280 &#xff08;“ Indify String Concatenation”&#xff09;是与JDK 9一起实现的&#xff0c;根据其“摘要”部分&#xff0c;“更改了javac生成的静态String concatenation字节码序列&#xff0c;以使用对JDK库函数的invokedynamic调用。 ” 通过查看…

label标签/标记

label 标签用于指定表单项的文字描述信息&#xff0c;如下所示&#xff1a; <label for"username">用户名称&#xff1a;</label> <input id"username" name"username">label 标签 的 for 属性指定的值与 input 标签的 id 属…

矩阵累积相乘 java_累积:轻松自定义Java收集器

矩阵累积相乘 javaAccumulative是针对Collector<T, A, R>的中间累积类型A提出的接口Collector<T, A, R>以使定义自定义Java Collector更加容易。 介绍 如果您曾经使用过Java Stream &#xff0c;那么很可能会使用了一些Collector &#xff0c;例如&#xff1a; C…

java socket 传输压缩文件_java基于socket传输zip文件功能示例

本文实例讲述了java基于socket传输zip文件的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;服务器端程序&#xff1a;import java.io.*;import java.net.*;import java.io.BufferedInputStream;public class SocketServer {ServerSocket ssnull;Socket snull;Dat…

css的学习

文章目录内联样式内部样式外部样式CSS语法格式选择器基本选择器ID 选择器元素选择器类选择器不带标签名带标签名通用选择器并集选择器选择器的优先级扩展选择器组合选择器属性选择器伪类选择器伪元素选择器css 是 Cascading Style Sheets&#xff0c;层叠样式表。 层叠含义是多…

java throws catch_java异常处理throws throw try-catch实例

java异常处理throws throw try-catch实例。throw用于方法中&#xff0c;我们可以预见的错误。比如&#xff1a;if(age<0){Exception e new Exception();//创建异常对象throw e;//抛出异常}在java代码中如果发生异常的话&#xff0c;jvm会抛出异常对象&#xff0c;导致程序代…

java 开发人员工具_每个Java开发人员都应该知道的10个基本工具

java 开发人员工具大家好&#xff0c;我们已经到了2019年的第二个月&#xff0c;我相信你们所有人都已经制定了关于2019年学习以及如何实现这些目标的目标。 我一直在撰写一系列文章&#xff0c;为您提供一些知识&#xff0c;使您可以学习和改进以成为2019年更好的全方位开发人…

SpringBoot2.x+mybatis plus3.x集成Activit7版本

文/朱季谦 在Activiti6版本当中&#xff0c;若要集成到Springboot里&#xff0c;需要写一些额外的配置类&#xff0c;我曾经在Activiti工作流框架学习笔记&#xff08;二&#xff09;之springboot2.0整合工作流Activiti6.0一文当中总结过相关配置过程&#xff0c;感兴趣的同学…

camel apache_Apache Camel 3的工作终于开始了

camel apache我们正在开始Apache Camel 3的工作。 我们正在多方面努力改善骆驼并引入新功能。 Guillaume Nodet实际上是在10月初开始了第一项工作&#xff0c;他通过清理代码库&#xff0c;删除不推荐使用的代码和组件&#xff0c;改进了路由引擎和核心中的其他内部组件开始了…

(前端开发)表格中的行全选、全不选、反选以及数据行背景色变换的示例代码

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>表格数据行全选/全不选/反选的示例</title><style>table {border: 1px solid;width: 500px;margin-left: 30%;}th, td {text-align: cente…

future java 多线程_Java多线程之Future与FutureTask

一&#xff1a;Future在使用实现Callable创建线程时&#xff0c;call()方法是有返回值的。那么&#xff0c;我们在编程时用什么来代表这个 线程执行后才能返回的未来结果 呢&#xff1f;那就是 Future类型。顾名思义&#xff0c;Future——未来值&#xff0c;我们用这个未来值来…

switch字符串jdk_从JDK 12删除原始字符串文字

switch字符串jdk已经提出从JDK 12中删除原始字符串文字&#xff08;预览&#xff09; &#xff08;它将在12月13日进入Rampdown第一阶段 &#xff09;。 Brian Goetz撰写了删除此预览功能的动机的详细说明 &#xff08; JEP 326 &#xff09;。 在Java subreddit上也对此进行了…

win7旗舰版安装不了python_怎样在Win7 64位旗舰版安装Python+Eclipse开发环境

自从上周抛弃了WinXP转而安装了Win7&#xff0c;64位后&#xff0c;尝试安装PythonEclipse遇到了一点小问题。现在已经解决&#xff0c;将安装顺序记录如下&#xff0c;供参考。Setp1&#xff0c;到ORACLE网站下载64位的JDK。http://www.oracle.com/technetwork/java/javase/do…

MacOS下的取色器/拾色器推荐

文章目录ColorSnapper2ColorSlurp 不错&#xff0c;App Store 可以下载SipChromaColor PickerPixeur&#xff08;推荐&#xff09;操作说明ColorSnapper2 ColorSlurp 不错&#xff0c;App Store 可以下载 Sip Chroma Color Picker Pixeur&#xff08;推荐&#xff09; 体…

查看oracle会话和进程_带有Oracle Digital Assistant和Fn Project的会话式UI

查看oracle会话和进程在这里和那里&#xff0c;我们看到了无数的预测&#xff0c;很快聊天机器人将在用户与其系统之间的通信中扮演关键角色。 我没有水晶球&#xff0c;也不想等待这个“很快”&#xff0c;所以我决定现在就使这些预言成真&#xff0c;看看它是什么样。 我正在…

设置 input元素placeholder的字体颜色

placeholder 属性提供可描述输入字段预期值的提示信息&#xff08;hint&#xff09;。 该提示会在输入字段为空时显示&#xff0c;并会在字段获得焦点时消失。 placeholder 属性适用于以下的 <input> 类型&#xff1a;text, search, url, telephone, email 以及 passwo…

网页益智游戏怎么制作_休息一下,或者:如何使用Java 12制作出色的益智游戏...

网页益智游戏怎么制作Java 12以实验形式提供了switch表达式以及switch和break语句的新形式。 对于可能很少用到的构造&#xff0c;有大量的新语法和语义-当然&#xff0c;对于那些困惑者和认证考试问题的作者来说&#xff0c;这是一件了不起的礼物。 如果您喜欢Java拼图游戏&am…

java aes 解密 文件_Java AES文件加解密

转自&#xff1a;http://www.webtag123.com/java/4049.htmlAESUtils.javapackage demo.security;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.security.Key;imp…