CORDA-1007 - Tweak the way invocation context is integrated to reduce the pain for devs using the old API (#2447) (#2524)

Minor tweaks to the invocation context code.

1) Un-deprecate FlowInitiator, move the deprecation to the field. This
   eliminates large numbers of warnings and means developers are warned
   only once in the place where they obtain one.

2) Add documentation for StateMachineInfo and create a type alias to give
   it a better name in an ABI compatible way.

3) Improve markup on InvocationContext

4) Rename field from just "context" to "invocationContext" (Context is vague)
This commit is contained in:
Katelyn Baker 2018-02-13 13:12:26 +00:00 committed by GitHub
parent 7d6f15b7ba
commit f0e52e1eed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 141 additions and 131 deletions

View File

@ -90,21 +90,21 @@ public static final class net.corda.core.context.Actor$Companion extends java.la
public String toString()
##
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.context.InvocationContext extends java.lang.Object
public <init>(net.corda.core.context.Origin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor)
@org.jetbrains.annotations.NotNull public final net.corda.core.context.Origin component1()
public <init>(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor)
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationOrigin component1()
@org.jetbrains.annotations.NotNull public final net.corda.core.context.Trace component2()
@org.jetbrains.annotations.Nullable public final net.corda.core.context.Actor component3()
@org.jetbrains.annotations.Nullable public final net.corda.core.context.Trace component4()
@org.jetbrains.annotations.Nullable public final net.corda.core.context.Actor component5()
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext copy(net.corda.core.context.Origin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor)
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext copy(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor)
public boolean equals(Object)
@org.jetbrains.annotations.Nullable public final net.corda.core.context.Actor getActor()
@org.jetbrains.annotations.Nullable public final net.corda.core.context.Trace getExternalTrace()
@org.jetbrains.annotations.Nullable public final net.corda.core.context.Actor getImpersonatedActor()
@org.jetbrains.annotations.NotNull public final net.corda.core.context.Origin getOrigin()
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationOrigin getOrigin()
@org.jetbrains.annotations.NotNull public final net.corda.core.context.Trace getTrace()
public int hashCode()
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public static final net.corda.core.context.InvocationContext newInstance(net.corda.core.context.Origin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor)
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public static final net.corda.core.context.InvocationContext newInstance(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor)
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public static final net.corda.core.context.InvocationContext peer(net.corda.core.identity.CordaX500Name, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor)
@org.jetbrains.annotations.NotNull public final java.security.Principal principal()
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public static final net.corda.core.context.InvocationContext rpc(net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor)
@ -115,49 +115,49 @@ public static final class net.corda.core.context.Actor$Companion extends java.la
public static final net.corda.core.context.InvocationContext$Companion Companion
##
public static final class net.corda.core.context.InvocationContext$Companion extends java.lang.Object
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext newInstance(net.corda.core.context.Origin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor)
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext newInstance(net.corda.core.context.InvocationOrigin, net.corda.core.context.Trace, net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Actor)
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext peer(net.corda.core.identity.CordaX500Name, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor)
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext rpc(net.corda.core.context.Actor, net.corda.core.context.Trace, net.corda.core.context.Trace, net.corda.core.context.Actor)
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext scheduled(net.corda.core.contracts.ScheduledStateRef, net.corda.core.context.Trace, net.corda.core.context.Trace)
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext service(String, net.corda.core.identity.CordaX500Name, net.corda.core.context.Trace, net.corda.core.context.Trace)
@kotlin.jvm.JvmStatic @org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext shell(net.corda.core.context.Trace, net.corda.core.context.Trace)
##
@net.corda.core.serialization.CordaSerializable public abstract class net.corda.core.context.Origin extends java.lang.Object
@net.corda.core.serialization.CordaSerializable public abstract class net.corda.core.context.InvocationOrigin extends java.lang.Object
@org.jetbrains.annotations.NotNull public abstract java.security.Principal principal()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.context.Origin$Peer extends net.corda.core.context.Origin
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.context.InvocationOrigin$Peer extends net.corda.core.context.InvocationOrigin
public <init>(net.corda.core.identity.CordaX500Name)
@org.jetbrains.annotations.NotNull public final net.corda.core.identity.CordaX500Name component1()
@org.jetbrains.annotations.NotNull public final net.corda.core.context.Origin$Peer copy(net.corda.core.identity.CordaX500Name)
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationOrigin$Peer copy(net.corda.core.identity.CordaX500Name)
public boolean equals(Object)
@org.jetbrains.annotations.NotNull public final net.corda.core.identity.CordaX500Name getParty()
public int hashCode()
@org.jetbrains.annotations.NotNull public java.security.Principal principal()
public String toString()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.context.Origin$RPC extends net.corda.core.context.Origin
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.context.InvocationOrigin$RPC extends net.corda.core.context.InvocationOrigin
public <init>(net.corda.core.context.Actor)
@org.jetbrains.annotations.NotNull public final net.corda.core.context.Origin$RPC copy(net.corda.core.context.Actor)
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationOrigin$RPC copy(net.corda.core.context.Actor)
public boolean equals(Object)
public int hashCode()
@org.jetbrains.annotations.NotNull public java.security.Principal principal()
public String toString()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.context.Origin$Scheduled extends net.corda.core.context.Origin
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.context.InvocationOrigin$Scheduled extends net.corda.core.context.InvocationOrigin
public <init>(net.corda.core.contracts.ScheduledStateRef)
@org.jetbrains.annotations.NotNull public final net.corda.core.contracts.ScheduledStateRef component1()
@org.jetbrains.annotations.NotNull public final net.corda.core.context.Origin$Scheduled copy(net.corda.core.contracts.ScheduledStateRef)
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationOrigin$Scheduled copy(net.corda.core.contracts.ScheduledStateRef)
public boolean equals(Object)
@org.jetbrains.annotations.NotNull public final net.corda.core.contracts.ScheduledStateRef getScheduledState()
public int hashCode()
@org.jetbrains.annotations.NotNull public java.security.Principal principal()
public String toString()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.context.Origin$Service extends net.corda.core.context.Origin
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.context.InvocationOrigin$Service extends net.corda.core.context.InvocationOrigin
public <init>(String, net.corda.core.identity.CordaX500Name)
@org.jetbrains.annotations.NotNull public final String component1()
@org.jetbrains.annotations.NotNull public final net.corda.core.identity.CordaX500Name component2()
@org.jetbrains.annotations.NotNull public final net.corda.core.context.Origin$Service copy(String, net.corda.core.identity.CordaX500Name)
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationOrigin$Service copy(String, net.corda.core.identity.CordaX500Name)
public boolean equals(Object)
@org.jetbrains.annotations.NotNull public final net.corda.core.identity.CordaX500Name getOwningLegalIdentity()
@org.jetbrains.annotations.NotNull public final String getServiceClassName()
@ -165,9 +165,9 @@ public static final class net.corda.core.context.InvocationContext$Companion ext
@org.jetbrains.annotations.NotNull public java.security.Principal principal()
public String toString()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.context.Origin$Shell extends net.corda.core.context.Origin
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.context.InvocationOrigin$Shell extends net.corda.core.context.InvocationOrigin
@org.jetbrains.annotations.NotNull public java.security.Principal principal()
public static final net.corda.core.context.Origin$Shell INSTANCE
public static final net.corda.core.context.InvocationOrigin$Shell INSTANCE
##
@net.corda.core.serialization.CordaSerializable public final class net.corda.core.context.Trace extends java.lang.Object
public <init>(net.corda.core.context.Trace$InvocationId, net.corda.core.context.Trace$SessionId)
@ -1160,6 +1160,7 @@ public static final class net.corda.core.flows.FinalityFlow$Companion extends ja
public String toString()
##
@net.corda.core.serialization.CordaSerializable public abstract class net.corda.core.flows.FlowInitiator extends java.lang.Object implements java.security.Principal
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext getInvocationContext()
##
@net.corda.core.serialization.CordaSerializable public static final class net.corda.core.flows.FlowInitiator$Peer extends net.corda.core.flows.FlowInitiator
public <init>(net.corda.core.identity.Party)
@ -1628,15 +1629,14 @@ public @interface net.corda.core.messaging.RPCReturnsObservables
@org.jetbrains.annotations.NotNull public final String component2()
@org.jetbrains.annotations.NotNull public final net.corda.core.flows.FlowInitiator component3()
@org.jetbrains.annotations.Nullable public final net.corda.core.messaging.DataFeed component4()
@org.jetbrains.annotations.Nullable public final net.corda.core.context.InvocationContext component5()
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext context()
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext component5()
@org.jetbrains.annotations.NotNull public final net.corda.core.messaging.StateMachineInfo copy(net.corda.core.flows.StateMachineRunId, String, net.corda.core.flows.FlowInitiator, net.corda.core.messaging.DataFeed)
@org.jetbrains.annotations.NotNull public final net.corda.core.messaging.StateMachineInfo copy(net.corda.core.flows.StateMachineRunId, String, net.corda.core.flows.FlowInitiator, net.corda.core.messaging.DataFeed, net.corda.core.context.InvocationContext)
public boolean equals(Object)
@org.jetbrains.annotations.Nullable public final net.corda.core.context.InvocationContext getContext()
@org.jetbrains.annotations.NotNull public final String getFlowLogicClassName()
@org.jetbrains.annotations.NotNull public final net.corda.core.flows.StateMachineRunId getId()
@org.jetbrains.annotations.NotNull public final net.corda.core.flows.FlowInitiator getInitiator()
@org.jetbrains.annotations.NotNull public final net.corda.core.context.InvocationContext getInvocationContext()
@org.jetbrains.annotations.Nullable public final net.corda.core.messaging.DataFeed getProgressTrackerStepAndUpdates()
public int hashCode()
@org.jetbrains.annotations.NotNull public String toString()

View File

@ -2,7 +2,7 @@ package net.corda.client.jfx
import net.corda.client.jfx.model.NodeMonitorModel
import net.corda.client.jfx.model.ProgressTrackingEvent
import net.corda.core.context.Origin
import net.corda.core.context.InvocationOrigin
import net.corda.core.contracts.Amount
import net.corda.core.contracts.ContractState
import net.corda.core.crypto.isFulfilledBy
@ -148,8 +148,8 @@ class NodeMonitorModelTest {
// ISSUE
expect { add: StateMachineUpdate.Added ->
issueSmId = add.id
val context = add.stateMachineInfo.context()
require(context.origin is Origin.RPC && context.principal().name == "user1")
val context = add.stateMachineInfo.invocationContext
require(context.origin is InvocationOrigin.RPC && context.principal().name == "user1")
},
expect { remove: StateMachineUpdate.Removed ->
require(remove.id == issueSmId)
@ -157,8 +157,8 @@ class NodeMonitorModelTest {
// MOVE - N.B. There are other framework flows that happen in parallel for the remote resolve transactions flow
expect(match = { it.stateMachineInfo.flowLogicClassName == CashPaymentFlow::class.java.name }) { add: StateMachineUpdate.Added ->
moveSmId = add.id
val context = add.stateMachineInfo.context()
require(context.origin is Origin.RPC && context.principal().name == "user1")
val context = add.stateMachineInfo.invocationContext
require(context.origin is InvocationOrigin.RPC && context.principal().name == "user1")
},
expect(match = { it is StateMachineUpdate.Removed && it.id == moveSmId }) {
}
@ -169,8 +169,8 @@ class NodeMonitorModelTest {
sequence(
// MOVE
expect { add: StateMachineUpdate.Added ->
val context = add.stateMachineInfo.context()
require(context.origin is Origin.Peer && aliceNode.isLegalIdentity(aliceNode.identityFromX500Name((context.origin as Origin.Peer).party)))
val context = add.stateMachineInfo.invocationContext
require(context.origin is InvocationOrigin.Peer && aliceNode.isLegalIdentity(aliceNode.identityFromX500Name((context.origin as InvocationOrigin.Peer).party)))
}
)
}

View File

@ -154,11 +154,11 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", C
},
expect { update: StateMachineUpdate.Added ->
checkRpcNotification(update.stateMachineInfo, rpcUser.username, historicalIds, externalTrace, impersonatedActor)
sessionId = update.stateMachineInfo.context().trace.sessionId
sessionId = update.stateMachineInfo.invocationContext.trace.sessionId
},
expect { update: StateMachineUpdate.Added ->
checkRpcNotification(update.stateMachineInfo, rpcUser.username, historicalIds, externalTrace, impersonatedActor)
assertThat(update.stateMachineInfo.context().trace.sessionId).isEqualTo(sessionId)
assertThat(update.stateMachineInfo.invocationContext.trace.sessionId).isEqualTo(sessionId)
}
)
}
@ -166,15 +166,13 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", C
}
private fun checkShellNotification(info: StateMachineInfo) {
val context = info.context()
assertThat(context.origin).isInstanceOf(Origin.Shell::class.java)
val context = info.invocationContext
assertThat(context.origin).isInstanceOf(InvocationOrigin.Shell::class.java)
}
private fun checkRpcNotification(info: StateMachineInfo, rpcUsername: String, historicalIds: MutableSet<Trace.InvocationId>, externalTrace: Trace?, impersonatedActor: Actor?) {
val context = info.context()
assertThat(context.origin).isInstanceOf(Origin.RPC::class.java)
val context = info.invocationContext
assertThat(context.origin).isInstanceOf(InvocationOrigin.RPC::class.java)
assertThat(context.externalTrace).isEqualTo(externalTrace)
assertThat(context.impersonatedActor).isEqualTo(impersonatedActor)
assertThat(context.actor?.id?.value).isEqualTo(rpcUsername)

View File

@ -1,9 +0,0 @@
package net.corda.core.context
import net.corda.core.serialization.CordaSerializable
/**
* Authentication / Authorisation Service ID.
*/
@CordaSerializable
data class AuthServiceId(val value: String)

View File

@ -9,52 +9,50 @@ import java.security.Principal
* Models the information needed to trace an invocation in Corda.
* Includes initiating actor, origin, trace information, and optional external trace information to correlate clients' IDs.
*
* @param origin origin of the invocation.
* @param trace Corda invocation trace.
* @param actor acting agent of the invocation, used to derive the security principal.
* @param externalTrace optional external invocation trace for cross-system logs correlation.
* @param impersonatedActor optional impersonated actor, used for logging but not for authorisation.
* @property origin Origin of the invocation.
* @property trace Corda invocation trace.
* @property actor Acting agent of the invocation, used to derive the security principal.
* @property externalTrace Optional external invocation trace for cross-system logs correlation.
* @property impersonatedActor Optional impersonated actor, used for logging but not for authorisation.
*/
@CordaSerializable
data class InvocationContext(val origin: Origin, val trace: Trace, val actor: Actor?, val externalTrace: Trace? = null, val impersonatedActor: Actor? = null) {
data class InvocationContext(val origin: InvocationOrigin, val trace: Trace, val actor: Actor?, val externalTrace: Trace? = null, val impersonatedActor: Actor? = null) {
companion object {
/**
* Creates an [InvocationContext] with a [Trace] that defaults to a [java.util.UUID] as value and [java.time.Instant.now] timestamp.
*/
@JvmStatic
fun newInstance(origin: Origin, trace: Trace = Trace.newInstance(), actor: Actor? = null, externalTrace: Trace? = null, impersonatedActor: Actor? = null) = InvocationContext(origin, trace, actor, externalTrace, impersonatedActor)
fun newInstance(origin: InvocationOrigin, trace: Trace = Trace.newInstance(), actor: Actor? = null, externalTrace: Trace? = null, impersonatedActor: Actor? = null) = InvocationContext(origin, trace, actor, externalTrace, impersonatedActor)
/**
* Creates an [InvocationContext] with [Origin.RPC] origin.
* Creates an [InvocationContext] with [InvocationOrigin.RPC] origin.
*/
@JvmStatic
fun rpc(actor: Actor, trace: Trace = Trace.newInstance(), externalTrace: Trace? = null, impersonatedActor: Actor? = null): InvocationContext = newInstance(Origin.RPC(actor), trace, actor, externalTrace, impersonatedActor)
fun rpc(actor: Actor, trace: Trace = Trace.newInstance(), externalTrace: Trace? = null, impersonatedActor: Actor? = null): InvocationContext = newInstance(InvocationOrigin.RPC(actor), trace, actor, externalTrace, impersonatedActor)
/**
* Creates an [InvocationContext] with [Origin.Peer] origin.
* Creates an [InvocationContext] with [InvocationOrigin.Peer] origin.
*/
@JvmStatic
fun peer(party: CordaX500Name, trace: Trace = Trace.newInstance(), externalTrace: Trace? = null, impersonatedActor: Actor? = null): InvocationContext = newInstance(Origin.Peer(party), trace, null, externalTrace, impersonatedActor)
fun peer(party: CordaX500Name, trace: Trace = Trace.newInstance(), externalTrace: Trace? = null, impersonatedActor: Actor? = null): InvocationContext = newInstance(InvocationOrigin.Peer(party), trace, null, externalTrace, impersonatedActor)
/**
* Creates an [InvocationContext] with [Origin.Service] origin.
* Creates an [InvocationContext] with [InvocationOrigin.Service] origin.
*/
@JvmStatic
fun service(serviceClassName: String, owningLegalIdentity: CordaX500Name, trace: Trace = Trace.newInstance(), externalTrace: Trace? = null): InvocationContext = newInstance(Origin.Service(serviceClassName, owningLegalIdentity), trace, null, externalTrace)
fun service(serviceClassName: String, owningLegalIdentity: CordaX500Name, trace: Trace = Trace.newInstance(), externalTrace: Trace? = null): InvocationContext = newInstance(InvocationOrigin.Service(serviceClassName, owningLegalIdentity), trace, null, externalTrace)
/**
* Creates an [InvocationContext] with [Origin.Scheduled] origin.
* Creates an [InvocationContext] with [InvocationOrigin.Scheduled] origin.
*/
@JvmStatic
fun scheduled(scheduledState: ScheduledStateRef, trace: Trace = Trace.newInstance(), externalTrace: Trace? = null): InvocationContext = newInstance(Origin.Scheduled(scheduledState), trace, null, externalTrace)
fun scheduled(scheduledState: ScheduledStateRef, trace: Trace = Trace.newInstance(), externalTrace: Trace? = null): InvocationContext = newInstance(InvocationOrigin.Scheduled(scheduledState), trace, null, externalTrace)
/**
* Creates an [InvocationContext] with [Origin.Shell] origin.
* Creates an [InvocationContext] with [InvocationOrigin.Shell] origin.
*/
@JvmStatic
fun shell(trace: Trace = Trace.newInstance(), externalTrace: Trace? = null): InvocationContext = InvocationContext(Origin.Shell, trace, null, externalTrace)
fun shell(trace: Trace = Trace.newInstance(), externalTrace: Trace? = null): InvocationContext = InvocationContext(InvocationOrigin.Shell, trace, null, externalTrace)
}
/**
@ -83,11 +81,10 @@ data class Actor(val id: Id, val serviceId: AuthServiceId, val owningLegalIdenti
}
/**
* Invocation origin for tracing purposes.
* Represents the source of an action such as a flow start, an RPC, a shell command etc.
*/
@CordaSerializable
sealed class Origin {
sealed class InvocationOrigin {
/**
* Returns the [Principal] for a given [Actor].
*/
@ -96,32 +93,28 @@ sealed class Origin {
/**
* Origin was an RPC call.
*/
data class RPC(private val actor: Actor) : Origin() {
data class RPC(private val actor: Actor) : InvocationOrigin() {
override fun principal() = Principal { actor.id.value }
}
/**
* Origin was a message sent by a [Peer].
*/
data class Peer(val party: CordaX500Name) : Origin() {
data class Peer(val party: CordaX500Name) : InvocationOrigin() {
override fun principal() = Principal { party.toString() }
}
/**
* Origin was a Corda Service.
*/
data class Service(val serviceClassName: String, val owningLegalIdentity: CordaX500Name) : Origin() {
data class Service(val serviceClassName: String, val owningLegalIdentity: CordaX500Name) : InvocationOrigin() {
override fun principal() = Principal { serviceClassName }
}
/**
* Origin was a scheduled activity.
*/
data class Scheduled(val scheduledState: ScheduledStateRef) : Origin() {
data class Scheduled(val scheduledState: ScheduledStateRef) : InvocationOrigin() {
override fun principal() = Principal { "Scheduler" }
}
@ -129,8 +122,13 @@ sealed class Origin {
/**
* Origin was the Shell.
*/
object Shell : Origin() {
object Shell : InvocationOrigin() {
override fun principal() = Principal { "Shell User" }
}
}
}
/**
* Authentication / Authorisation Service ID.
*/
@CordaSerializable
data class AuthServiceId(val value: String)

View File

@ -1,45 +1,69 @@
package net.corda.core.flows
import net.corda.core.context.Actor
import net.corda.core.context.AuthServiceId
import net.corda.core.context.InvocationContext
import net.corda.core.context.InvocationOrigin
import net.corda.core.contracts.ScheduledStateRef
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.serialization.CordaSerializable
import java.security.Principal
/**
* FlowInitiator holds information on who started the flow. We have different ways of doing that: via RPC [FlowInitiator.RPC],
* communication started by peer node [FlowInitiator.Peer], scheduled flows [FlowInitiator.Scheduled]
* or via the Corda Shell [FlowInitiator.Shell].
* Please note that [FlowInitiator] has been superceded by [net.corda.core.context.InvocationContext], which offers
* more detail for the same event.
*
* FlowInitiator holds information on who started the flow. We have different ways of doing that: via [FlowInitiator.RPC],
* communication started by peer nodes ([FlowInitiator.Peer]), scheduled flows ([FlowInitiator.Scheduled])
* or via the Corda Shell ([FlowInitiator.Shell]).
*/
@Deprecated("Do not use these types. Future releases might remove them.")
@CordaSerializable
sealed class FlowInitiator : Principal {
/** Started using [net.corda.core.messaging.CordaRPCOps.startFlowDynamic]. */
@Deprecated("Do not use this type. Future releases might remove it.")
data class RPC(val username: String) : FlowInitiator() {
override fun getName(): String = username
}
/** Started when we get new session initiation request. */
@Deprecated("Do not use this type. Future releases might remove it.")
data class Peer(val party: Party) : FlowInitiator() {
override fun getName(): String = party.name.toString()
}
/** Started by a CordaService. */
@Deprecated("Do not use this type. Future releases might remove it.")
data class Service(val serviceClassName: String) : FlowInitiator() {
override fun getName(): String = serviceClassName
}
/** Started as scheduled activity. */
@Deprecated("Do not use this type. Future releases might remove it.")
data class Scheduled(val scheduledState: ScheduledStateRef) : FlowInitiator() {
override fun getName(): String = "Scheduler"
}
// TODO When proper ssh access enabled, add username/use RPC?
@Deprecated("Do not use this type. Future releases might remove it.")
object Shell : FlowInitiator() {
override fun getName(): String = "Shell User"
}
/**
* Returns an [InvocationContext], which is equivalent to this object but expressed using the successor to this
* class hierarchy (which is now deprecated). The returned object has less information than it could have, so
* prefer to use fetch an invocation context directly if you can (e.g. in [net.corda.core.messaging.StateMachineInfo])
*/
val invocationContext: InvocationContext get() {
val unknownName = CordaX500Name("UNKNOWN", "UNKNOWN", "GB")
var actor: Actor? = null
val origin: InvocationOrigin
when (this) {
is FlowInitiator.RPC -> {
actor = Actor(Actor.Id(this.username), AuthServiceId("UNKNOWN"), unknownName)
origin = InvocationOrigin.RPC(actor)
}
is FlowInitiator.Peer -> origin = InvocationOrigin.Peer(this.party.name)
is FlowInitiator.Service -> origin = InvocationOrigin.Service(this.serviceClassName, unknownName)
FlowInitiator.Shell -> origin = InvocationOrigin.Shell
is FlowInitiator.Scheduled -> origin = InvocationOrigin.Scheduled(this.scheduledState)
}
return InvocationContext.newInstance(origin = origin, actor = actor)
}
}

View File

@ -43,7 +43,7 @@ import java.time.Instant
* also has a version property to allow you to version your flow and enables a node to restrict support for the flow to
* that particular version.
*
* Functions that suspend the flow (including all functions on [FlowSession]) accept a [maySkipCheckpoint] parameter
* Functions that suspend the flow (including all functions on [FlowSession]) accept a maySkipCheckpoint parameter
* defaulting to false, false meaning a checkpoint should always be created on suspend. This parameter may be set to
* true which allows the implementation to potentially optimise away the checkpoint, saving a roundtrip to the database.
*
@ -53,6 +53,7 @@ import java.time.Instant
* parameter the flow must be prepared for scenarios where a previous running of the flow *already committed its
* relevant database transactions*. Only set this option to true if you know what you're doing.
*/
@Suppress("DEPRECATION", "DeprecatedCallableAddReplaceWith")
abstract class FlowLogic<out T> {
/** This is where you should log things to. */
val logger: Logger get() = stateMachine.logger
@ -61,14 +62,14 @@ abstract class FlowLogic<out T> {
/**
* Return the outermost [FlowLogic] instance, or null if not in a flow.
*/
@JvmStatic
@Suppress("unused") @JvmStatic
val currentTopLevel: FlowLogic<*>? get() = (Strand.currentStrand() as? FlowStateMachine<*>)?.logic
/**
* If on a flow, suspends the flow and only wakes it up after at least [duration] time has passed. Otherwise,
* just sleep for [duration]. This sleep function is not designed to aid scheduling, for which you should
* consider using [SchedulableState]. It is designed to aid with managing contention for which you have not
* managed via another means.
* consider using [net.corda.core.contracts.SchedulableState]. It is designed to aid with managing contention
* for which you have not managed via another means.
*
* Warning: long sleeps and in general long running flows are highly discouraged, as there is currently no
* support for flow migration! This method will throw an exception if you attempt to sleep for longer than
@ -78,7 +79,7 @@ abstract class FlowLogic<out T> {
@JvmStatic
@Throws(FlowException::class)
fun sleep(duration: Duration) {
if (duration.compareTo(Duration.ofMinutes(5)) > 0) {
if (duration > Duration.ofMinutes(5)) {
throw FlowException("Attempt to sleep for longer than 5 minutes is not supported. Consider using SchedulableState.")
}
(Strand.currentStrand() as? FlowStateMachine<*>)?.sleepUntil(Instant.now() + duration) ?: Strand.sleep(duration.toMillis())
@ -428,6 +429,7 @@ abstract class FlowLogic<out T> {
// This is the flow used for managing sessions. It defaults to the current flow but if this is an inlined sub-flow
// then it will point to the flow it's been inlined to.
@Suppress("LeakingThis")
private var flowUsedForSessions: FlowLogic<*> = this
private fun maybeWireUpProgressTracking(subLogic: FlowLogic<*>) {

View File

@ -4,7 +4,7 @@ import net.corda.core.concurrent.CordaFuture
import net.corda.core.context.Actor
import net.corda.core.context.AuthServiceId
import net.corda.core.context.InvocationContext
import net.corda.core.context.Origin
import net.corda.core.context.InvocationOrigin
import net.corda.core.contracts.ContractState
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowInitiator
@ -29,44 +29,40 @@ import java.io.InputStream
import java.security.PublicKey
import java.time.Instant
private val unknownName = CordaX500Name("UNKNOWN", "UNKNOWN", "GB")
/**
* Represents information about a flow (the name "state machine" is legacy, Kotlin users can use the [FlowInfo] type
* alias). You can access progress tracking, information about why the flow was started and so on.
*/
@CordaSerializable
data class StateMachineInfo @JvmOverloads constructor(
/** A univerally unique ID ([java.util.UUID]) representing this particular instance of the named flow. */
val id: StateMachineRunId,
/** The JVM class name of the flow code. */
val flowLogicClassName: String,
val initiator: FlowInitiator,
/**
* An object representing information about the initiator of the flow. Note that this field is
* superceded by the [invocationContext] property, which has more detail.
*/
@Deprecated("There is more info available using 'context'") val initiator: FlowInitiator,
/** A [DataFeed] of the current progress step as a human readable string, and updates to that string. */
val progressTrackerStepAndUpdates: DataFeed<String, String>?,
val context: InvocationContext? = null
/** An [InvocationContext] describing why and by whom the flow was started. */
val invocationContext: InvocationContext = initiator.invocationContext
) {
fun context(): InvocationContext = context ?: contextFrom(initiator)
private fun contextFrom(initiator: FlowInitiator): InvocationContext {
var actor: Actor? = null
val origin: Origin
when (initiator) {
is FlowInitiator.RPC -> {
actor = Actor(Actor.Id(initiator.username), AuthServiceId("UNKNOWN"), unknownName)
origin = Origin.RPC(actor)
}
is FlowInitiator.Peer -> origin = Origin.Peer(initiator.party.name)
is FlowInitiator.Service -> origin = Origin.Service(initiator.serviceClassName, unknownName)
is FlowInitiator.Shell -> origin = Origin.Shell
is FlowInitiator.Scheduled -> origin = Origin.Scheduled(initiator.scheduledState)
}
return InvocationContext.newInstance(origin = origin, actor = actor)
}
@Suppress("DEPRECATION")
fun copy(id: StateMachineRunId = this.id,
flowLogicClassName: String = this.flowLogicClassName,
initiator: FlowInitiator = this.initiator,
progressTrackerStepAndUpdates: DataFeed<String, String>? = this.progressTrackerStepAndUpdates): StateMachineInfo {
return copy(id = id, flowLogicClassName = flowLogicClassName, initiator = initiator, progressTrackerStepAndUpdates = progressTrackerStepAndUpdates, context = context)
return copy(id = id, flowLogicClassName = flowLogicClassName, initiator = initiator, progressTrackerStepAndUpdates = progressTrackerStepAndUpdates, invocationContext = invocationContext)
}
override fun toString(): String = "${javaClass.simpleName}($id, $flowLogicClassName)"
}
/** An alias for [StateMachineInfo] which uses more modern terminology. */
typealias FlowInfo = StateMachineInfo
@CordaSerializable
sealed class StateMachineUpdate {
abstract val id: StateMachineRunId

View File

@ -3,7 +3,7 @@ package net.corda.node.internal
import net.corda.client.rpc.notUsed
import net.corda.core.concurrent.CordaFuture
import net.corda.core.context.InvocationContext
import net.corda.core.context.Origin
import net.corda.core.context.InvocationOrigin
import net.corda.core.contracts.ContractState
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowInitiator
@ -311,15 +311,15 @@ internal class CordaRPCOpsImpl(
val principal = origin.principal().name
return when (origin) {
is Origin.RPC -> FlowInitiator.RPC(principal)
is Origin.Peer -> services.identityService.wellKnownPartyFromX500Name((origin as Origin.Peer).party)?.let { FlowInitiator.Peer(it) } ?: throw IllegalStateException("Unknown peer with name ${(origin as Origin.Peer).party}.")
is Origin.Service -> FlowInitiator.Service(principal)
Origin.Shell -> FlowInitiator.Shell
is Origin.Scheduled -> FlowInitiator.Scheduled((origin as Origin.Scheduled).scheduledState)
is InvocationOrigin.RPC -> FlowInitiator.RPC(principal)
is InvocationOrigin.Peer -> services.identityService.wellKnownPartyFromX500Name((origin as InvocationOrigin.Peer).party)?.let { FlowInitiator.Peer(it) } ?: throw IllegalStateException("Unknown peer with name ${(origin as InvocationOrigin.Peer).party}.")
is InvocationOrigin.Service -> FlowInitiator.Service(principal)
is InvocationOrigin.Shell -> FlowInitiator.Shell
is InvocationOrigin.Scheduled -> FlowInitiator.Scheduled((origin as InvocationOrigin.Scheduled).scheduledState)
}
}
companion object {
private val log = contextLogger()
}
}
}

View File

@ -3,7 +3,7 @@ package net.corda.node.services.events
import co.paralleluniverse.fibers.Suspendable
import com.google.common.util.concurrent.ListenableFuture
import net.corda.core.context.InvocationContext
import net.corda.core.context.Origin
import net.corda.core.context.InvocationOrigin
import net.corda.core.contracts.SchedulableState
import net.corda.core.contracts.ScheduledActivity
import net.corda.core.contracts.ScheduledStateRef
@ -256,7 +256,7 @@ class NodeSchedulerService(private val clock: CordaClock,
if (scheduledFlow != null) {
flowName = scheduledFlow.javaClass.name
// TODO refactor the scheduler to store and propagate the original invocation context
val context = InvocationContext.newInstance(Origin.Scheduled(scheduledState))
val context = InvocationContext.newInstance(InvocationOrigin.Scheduled(scheduledState))
val future = flowStarter.startFlow(scheduledFlow, context).flatMap { it.resultFuture }
future.then {
unfinishedSchedules.countDown()

View File

@ -72,7 +72,7 @@ class FlowWatchPrintingSubscriber(private val toStream: RenderPrintWriter) : Sub
table.add(RowElement().add(
LabelElement(formatFlowId(smmUpdate.id)),
LabelElement(formatFlowName(smmUpdate.stateMachineInfo.flowLogicClassName)),
LabelElement(formatInvocationContext(smmUpdate.stateMachineInfo.context())),
LabelElement(formatInvocationContext(smmUpdate.stateMachineInfo.invocationContext)),
LabelElement("In progress")
).style(stateColor(smmUpdate).fg()))
indexMap[smmUpdate.id] = table.rows.size - 1

View File

@ -4,7 +4,7 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StartableByService
import net.corda.core.context.InvocationContext
import net.corda.core.context.Origin
import net.corda.core.context.InvocationOrigin
import net.corda.core.node.AppServiceHub
import net.corda.core.node.ServiceHub
import net.corda.core.node.services.CordaService
@ -46,7 +46,7 @@ class TestCordaService(val appServiceHub: AppServiceHub): SingletonSerializeAsTo
fun startServiceFlow() {
val handle = appServiceHub.startFlow(DummyServiceFlow())
val context = handle.returnValue.get()
assertEquals(this.javaClass.name, (context.origin as Origin.Service).serviceClassName)
assertEquals(this.javaClass.name, (context.origin as InvocationOrigin.Service).serviceClassName)
}
fun startServiceFlowAndTrack() {

View File

@ -2,7 +2,7 @@ package net.corda.node.services.events
import co.paralleluniverse.fibers.Suspendable
import net.corda.core.concurrent.CordaFuture
import net.corda.core.context.Origin
import net.corda.core.context.InvocationOrigin
import net.corda.core.contracts.*
import net.corda.core.flows.FinalityFlow
import net.corda.core.flows.FlowLogic
@ -122,7 +122,7 @@ class ScheduledFlowTests {
aliceNode.smm.track().updates.subscribe {
if (it is StateMachineManager.Change.Add) {
val context = it.logic.stateMachine.context
if (context.origin is Origin.Scheduled)
if (context.origin is InvocationOrigin.Scheduled)
countScheduledFlows++
}
}

View File

@ -6,7 +6,7 @@ import net.corda.core.concurrent.CordaFuture
import net.corda.core.context.Actor
import net.corda.core.context.AuthServiceId
import net.corda.core.context.InvocationContext
import net.corda.core.context.Origin
import net.corda.core.context.InvocationOrigin
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
@ -65,7 +65,8 @@ fun testActor(owningLegalIdentity: CordaX500Name = CordaX500Name("Test Company I
fun testContext(owningLegalIdentity: CordaX500Name = CordaX500Name("Test Company Inc.", "London", "GB")) = InvocationContext.rpc(testActor(owningLegalIdentity))
/**
* Creates a new [InvocationContext] for testing purposes.
* Starts an already constructed flow. Note that you must be on the server thread to call this method. [InvocationContext]
* has origin [InvocationOrigin.RPC] and actor with id "Only For Testing".
*/
fun StartedNodeServices.newContext() = testContext(myInfo.chooseIdentity().name)