diff --git a/.ci/api-current.txt b/.ci/api-current.txt index 0fd2a15fc9..8d485ec906 100644 --- a/.ci/api-current.txt +++ b/.ci/api-current.txt @@ -96,21 +96,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 (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 (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) @@ -121,49 +121,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 (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 (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 (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 (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() @@ -171,9 +171,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 (net.corda.core.context.Trace$InvocationId, net.corda.core.context.Trace$SessionId) @@ -1168,6 +1168,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 (net.corda.core.identity.Party) @@ -1669,15 +1670,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() diff --git a/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt b/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt index f8f5c58dcf..81006e9614 100644 --- a/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt +++ b/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt @@ -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))) } ) } diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt index bfb77b4aeb..b95480b95b 100644 --- a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/CordaRPCClientTest.kt @@ -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, 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) diff --git a/core/src/main/kotlin/net/corda/core/context/AuthServiceId.kt b/core/src/main/kotlin/net/corda/core/context/AuthServiceId.kt deleted file mode 100644 index 9edc2680ca..0000000000 --- a/core/src/main/kotlin/net/corda/core/context/AuthServiceId.kt +++ /dev/null @@ -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) \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/context/InvocationContext.kt b/core/src/main/kotlin/net/corda/core/context/InvocationContext.kt index 9ca93033c0..58c1544c21 100644 --- a/core/src/main/kotlin/net/corda/core/context/InvocationContext.kt +++ b/core/src/main/kotlin/net/corda/core/context/InvocationContext.kt @@ -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" } } -} \ No newline at end of file +} + +/** + * Authentication / Authorisation Service ID. + */ +@CordaSerializable +data class AuthServiceId(val value: String) \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/flows/FlowInitiator.kt b/core/src/main/kotlin/net/corda/core/flows/FlowInitiator.kt index 8623169da8..206862d2ec 100644 --- a/core/src/main/kotlin/net/corda/core/flows/FlowInitiator.kt +++ b/core/src/main/kotlin/net/corda/core/flows/FlowInitiator.kt @@ -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) + } } \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt b/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt index a10a3d3fe2..476521f0ec 100644 --- a/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt +++ b/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt @@ -42,7 +42,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. * @@ -52,6 +52,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 { /** This is where you should log things to. */ val logger: Logger get() = stateMachine.logger @@ -60,14 +61,14 @@ abstract class FlowLogic { /** * 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 @@ -77,7 +78,7 @@ abstract class FlowLogic { @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()) @@ -425,6 +426,7 @@ abstract class FlowLogic { // 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<*>) { 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 b6880a8103..5d56f9d638 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt @@ -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 @@ -27,44 +27,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?, - 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? = 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 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 b3f7ebbec3..7b8d3b5754 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt @@ -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 @@ -285,11 +285,11 @@ 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) - is 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) } } diff --git a/node/src/main/kotlin/net/corda/node/services/events/NodeSchedulerService.kt b/node/src/main/kotlin/net/corda/node/services/events/NodeSchedulerService.kt index 72ef0fe6a6..fab75d470c 100644 --- a/node/src/main/kotlin/net/corda/node/services/events/NodeSchedulerService.kt +++ b/node/src/main/kotlin/net/corda/node/services/events/NodeSchedulerService.kt @@ -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 @@ -252,7 +252,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() diff --git a/node/src/main/kotlin/net/corda/node/shell/FlowWatchPrintingSubscriber.kt b/node/src/main/kotlin/net/corda/node/shell/FlowWatchPrintingSubscriber.kt index 7f52b430f2..cb48f1b829 100644 --- a/node/src/main/kotlin/net/corda/node/shell/FlowWatchPrintingSubscriber.kt +++ b/node/src/main/kotlin/net/corda/node/shell/FlowWatchPrintingSubscriber.kt @@ -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 diff --git a/node/src/test/kotlin/net/corda/node/internal/CordaServiceTest.kt b/node/src/test/kotlin/net/corda/node/internal/CordaServiceTest.kt index b7b47d9165..2842e9bab3 100644 --- a/node/src/test/kotlin/net/corda/node/internal/CordaServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/CordaServiceTest.kt @@ -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 @@ -45,7 +45,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() { diff --git a/node/src/test/kotlin/net/corda/node/services/events/ScheduledFlowTests.kt b/node/src/test/kotlin/net/corda/node/services/events/ScheduledFlowTests.kt index 4ff69ccbb2..f40782a3e7 100644 --- a/node/src/test/kotlin/net/corda/node/services/events/ScheduledFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/events/ScheduledFlowTests.kt @@ -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 @@ -121,7 +121,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++ } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeTestUtils.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeTestUtils.kt index 0ce2359249..85248cab2d 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeTestUtils.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeTestUtils.kt @@ -5,7 +5,7 @@ package net.corda.testing.node 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 @@ -62,7 +62,7 @@ fun testContext(owningLegalIdentity: CordaX500Name = CordaX500Name("Test Company /** * Starts an already constructed flow. Note that you must be on the server thread to call this method. [InvocationContext] - * has origin [Origin.RPC] and actor with id "Only For Testing". + * has origin [InvocationOrigin.RPC] and actor with id "Only For Testing". */ fun StartedNodeServices.startFlow(logic: FlowLogic): FlowStateMachine = startFlow(logic, newContext()).getOrThrow()