Move the implementation of the FlowLogicRefFactory internal to the node as it is an implementation detail, not an API.

This commit is contained in:
Matthew Nesbit 2017-05-08 11:30:51 +01:00
parent 489661a289
commit bfa7d50d37
9 changed files with 235 additions and 197 deletions

View File

@ -1,194 +1,30 @@
package net.corda.core.flows
import com.google.common.primitives.Primitives
import net.corda.core.crypto.SecureHash
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SingletonSerializeAsToken
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.util.*
import kotlin.reflect.KFunction
import kotlin.reflect.KParameter
import kotlin.reflect.jvm.javaConstructor
import kotlin.reflect.jvm.javaType
/**
* A class for conversion to and from [FlowLogic] and [FlowLogicRef] instances.
*
* Validation of types is performed on the way in and way out in case this object is passed between JVMs which might have differing
* whitelists.
*
* TODO: Ways to populate whitelist of "blessed" flows per node/party
* TODO: Ways to populate argument types whitelist. Per node/party or global?
* TODO: Align with API related logic for passing in FlowLogic references (FlowRef)
* TODO: Actual support for AppContext / AttachmentsClassLoader
* The public factory interface for creating validated FlowLogicRef instances as part of the scheduling framework.
* Typically this would be used from within the nextScheduledActivity method of a QueryableState to specify
* the flow to run at the scheduled time.
*/
class FlowLogicRefFactory(val flowWhitelist: Map<String, Set<String>>) : SingletonSerializeAsToken() {
constructor() : this(mapOf())
// Pending real dependence on AppContext for class loading etc
@Suppress("UNUSED_PARAMETER")
private fun validateFlowClassName(className: String, appContext: AppContext) {
// TODO: make this specific to the attachments in the [AppContext] by including [SecureHash] in whitelist check
require(flowWhitelist.containsKey(className)) { "${FlowLogic::class.java.simpleName} of ${FlowLogicRef::class.java.simpleName} must have type on the whitelist: $className" }
}
// Pending real dependence on AppContext for class loading etc
@Suppress("UNUSED_PARAMETER")
private fun validateArgClassName(className: String, argClassName: String, appContext: AppContext) {
// TODO: consider more carefully what to whitelist and how to secure flows
// For now automatically accept standard java.lang.* and kotlin.* types.
// All other types require manual specification at FlowLogicRefFactory construction time.
if (argClassName.startsWith("java.lang.") || argClassName.startsWith("kotlin.")) {
return
}
// TODO: make this specific to the attachments in the [AppContext] by including [SecureHash] in whitelist check
require(flowWhitelist[className]!!.contains(argClassName)) { "Args to $className must have types on the args whitelist: $argClassName, but it has ${flowWhitelist[className]}" }
}
/**
* Create a [FlowLogicRef] for the Kotlin primary constructor of a named [FlowLogic]
*/
fun createKotlin(flowLogicClassName: String, args: Map<String, Any?>, attachments: List<SecureHash> = emptyList()): FlowLogicRef {
val context = AppContext(attachments)
validateFlowClassName(flowLogicClassName, context)
for (arg in args.values.filterNotNull()) {
validateArgClassName(flowLogicClassName, arg.javaClass.name, context)
}
val clazz = Class.forName(flowLogicClassName)
require(FlowLogic::class.java.isAssignableFrom(clazz)) { "$flowLogicClassName is not a FlowLogic" }
@Suppress("UNCHECKED_CAST")
val logic = clazz as Class<FlowLogic<FlowLogic<*>>>
return createKotlin(logic, args)
}
/**
* Create a [FlowLogicRef] by assuming a single constructor and the given args.
*/
fun create(type: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef {
// TODO: This is used via RPC but it's probably better if we pass in argument names and values explicitly
// to avoid requiring only a single constructor.
val argTypes = args.map { it?.javaClass }
val constructor = try {
type.kotlin.constructors.single { ctor ->
// Get the types of the arguments, always boxed (as that's what we get in the invocation).
val ctorTypes = ctor.javaConstructor!!.parameterTypes.map { Primitives.wrap(it) }
if (argTypes.size != ctorTypes.size)
return@single false
for ((argType, ctorType) in argTypes.zip(ctorTypes)) {
if (argType == null) continue // Try and find a match based on the other arguments.
if (!ctorType.isAssignableFrom(argType)) return@single false
}
true
}
} catch (e: IllegalArgumentException) {
throw IllegalFlowLogicException(type, "due to ambiguous match against the constructors: $argTypes")
} catch (e: NoSuchElementException) {
throw IllegalFlowLogicException(type, "due to missing constructor for arguments: $argTypes")
}
// Build map of args from array
val argsMap = args.zip(constructor.parameters).map { Pair(it.second.name!!, it.first) }.toMap()
return createKotlin(type, argsMap)
}
/**
* Create a [FlowLogicRef] by trying to find a Kotlin constructor that matches the given args.
*
* TODO: Rethink language specific naming.
*/
fun createKotlin(type: Class<out FlowLogic<*>>, args: Map<String, Any?>): FlowLogicRef {
// TODO: we need to capture something about the class loader or "application context" into the ref,
// perhaps as some sort of ThreadLocal style object. For now, just create an empty one.
val appContext = AppContext(emptyList())
validateFlowClassName(type.name, appContext)
// Check we can find a constructor and populate the args to it, but don't call it
createConstructor(appContext, type, args)
return FlowLogicRef(type.name, appContext, args)
}
/**
* Create a [FlowLogicRef] by trying to find a Java constructor that matches the given args.
*/
private fun createJava(type: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef {
// Build map for each
val argsMap = HashMap<String, Any?>(args.size)
var index = 0
args.forEach { argsMap["arg${index++}"] = it }
return createKotlin(type, argsMap)
}
fun toFlowLogic(ref: FlowLogicRef): FlowLogic<*> {
validateFlowClassName(ref.flowLogicClassName, ref.appContext)
val klass = Class.forName(ref.flowLogicClassName, true, ref.appContext.classLoader).asSubclass(FlowLogic::class.java)
return createConstructor(ref.appContext, klass, ref.args)()
}
private fun createConstructor(appContext: AppContext, clazz: Class<out FlowLogic<*>>, args: Map<String, Any?>): () -> FlowLogic<*> {
for (constructor in clazz.kotlin.constructors) {
val params = buildParams(appContext, clazz, constructor, args) ?: continue
// If we get here then we matched every parameter
return { constructor.callBy(params) }
}
throw IllegalFlowLogicException(clazz, "as could not find matching constructor for: $args")
}
private fun buildParams(appContext: AppContext, clazz: Class<out FlowLogic<*>>, constructor: KFunction<FlowLogic<*>>, args: Map<String, Any?>): HashMap<KParameter, Any?>? {
val params = hashMapOf<KParameter, Any?>()
val usedKeys = hashSetOf<String>()
for (parameter in constructor.parameters) {
if (!tryBuildParam(args, parameter, params)) {
return null
} else {
usedKeys += parameter.name!!
}
}
if ((args.keys - usedKeys).isNotEmpty()) {
// Not all args were used
return null
}
params.values.forEach { if (it is Any) validateArgClassName(clazz.name, it.javaClass.name, appContext) }
return params
}
private fun tryBuildParam(args: Map<String, Any?>, parameter: KParameter, params: HashMap<KParameter, Any?>): Boolean {
val containsKey = parameter.name in args
// OK to be missing if optional
return (parameter.isOptional && !containsKey) || (containsKey && paramCanBeBuilt(args, parameter, params))
}
private fun paramCanBeBuilt(args: Map<String, Any?>, parameter: KParameter, params: HashMap<KParameter, Any?>): Boolean {
val value = args[parameter.name]
params[parameter] = value
return (value is Any && parameterAssignableFrom(parameter.type.javaType, value)) || parameter.type.isMarkedNullable
}
private fun parameterAssignableFrom(type: Type, value: Any): Boolean {
if (type is Class<*>) {
if (type.isPrimitive) {
return Primitives.unwrap(value.javaClass) == type
} else {
return type.isAssignableFrom(value.javaClass)
}
} else if (type is ParameterizedType) {
return parameterAssignableFrom(type.rawType, value)
} else {
return false
}
}
interface FlowLogicRefFactory {
fun create(type: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef
}
@CordaSerializable
class IllegalFlowLogicException(type: Class<*>, msg: String) : IllegalArgumentException("${FlowLogicRef::class.java.simpleName} cannot be constructed for ${FlowLogic::class.java.simpleName} of type ${type.name} $msg")
/**
* A class representing a [FlowLogic] instance which would be possible to safely pass out of the contract sandbox.
* A handle interface representing a [FlowLogic] instance which would be possible to safely pass out of the contract sandbox.
* Use FlowLogicRefFactory to construct a concrete security checked instance.
*
* Only allows a String reference to the FlowLogic class, and only allows restricted argument types as per [FlowLogicRefFactory].
*/
// TODO: align this with the existing [FlowRef] in the bank-side API (probably replace some of the API classes)
@CordaSerializable
data class FlowLogicRef internal constructor(val flowLogicClassName: String, val appContext: AppContext, val args: Map<String, Any?>)
interface FlowLogicRef
/**
* This is just some way to track what attachments need to be in the class loader, but may later include some app

View File

@ -12,7 +12,6 @@ import net.corda.core.crypto.Party
import net.corda.core.crypto.X509Utilities
import net.corda.core.flows.FlowInitiator
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowLogicRefFactory
import net.corda.core.flows.FlowVersion
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.RPCOps
@ -46,6 +45,7 @@ import net.corda.node.services.network.PersistentNetworkMapService
import net.corda.node.services.persistence.*
import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.schema.NodeSchemaService
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
import net.corda.node.services.statemachine.FlowStateMachineImpl
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.statemachine.flowVersion
@ -134,7 +134,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
// Internal only
override val monitoringService: MonitoringService = MonitoringService(MetricRegistry())
override val flowLogicRefFactory: FlowLogicRefFactory get() = flowLogicFactory
override val flowLogicRefFactory: FlowLogicRefFactoryInternal get() = flowLogicFactory
override fun <T> startFlow(logic: FlowLogic<T>, flowInitiator: FlowInitiator): FlowStateMachineImpl<T> {
return serverThread.fetchFrom { smm.add(logic, flowInitiator) }
@ -173,7 +173,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
lateinit var net: MessagingService
lateinit var netMapCache: NetworkMapCacheInternal
lateinit var scheduler: NodeSchedulerService
lateinit var flowLogicFactory: FlowLogicRefFactory
lateinit var flowLogicFactory: FlowLogicRefFactoryInternal
lateinit var schemas: SchemaService
val customServices: ArrayList<Any> = ArrayList()
protected val runOnStop: ArrayList<Runnable> = ArrayList()
@ -381,7 +381,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
}
}
private fun initialiseFlowLogicFactory(): FlowLogicRefFactory {
private fun initialiseFlowLogicFactory(): FlowLogicRefFactoryInternal {
val flowWhitelist = HashMap<String, Set<String>>()
for ((flowClass, extraArgumentTypes) in defaultFlowWhiteList) {
@ -398,7 +398,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
}
}
return FlowLogicRefFactory(flowWhitelist)
return FlowLogicRefFactoryImpl(flowWhitelist)
}
private fun makePluginServices(tokenizableServices: MutableList<Any>): List<Any> {

View File

@ -2,10 +2,7 @@ package net.corda.node.services.api
import com.google.common.annotations.VisibleForTesting
import com.google.common.util.concurrent.ListenableFuture
import net.corda.core.flows.FlowInitiator
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowLogicRefFactory
import net.corda.core.flows.FlowStateMachine
import net.corda.core.flows.*
import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.NodeInfo
import net.corda.core.node.PluginServiceHub
@ -50,6 +47,11 @@ interface NetworkMapCacheInternal : NetworkMapCache {
}
interface FlowLogicRefFactoryInternal : FlowLogicRefFactory {
val flowWhitelist: Map<String, Set<String>>
fun toFlowLogic(ref: FlowLogicRef): FlowLogic<*>
}
@CordaSerializable
sealed class NetworkCacheError : Exception() {
/** Indicates a failure to deregister, because of a rejected request from the remote node */
@ -62,7 +64,7 @@ abstract class ServiceHubInternal : PluginServiceHub {
}
abstract val monitoringService: MonitoringService
abstract val flowLogicRefFactory: FlowLogicRefFactory
abstract val flowLogicRefFactory: FlowLogicRefFactoryInternal
abstract val schemaService: SchemaService
abstract override val networkMapCache: NetworkMapCacheInternal
abstract val schedulerService: SchedulerService

View File

@ -9,11 +9,11 @@ import net.corda.core.contracts.ScheduledStateRef
import net.corda.core.contracts.StateRef
import net.corda.core.flows.FlowInitiator
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowLogicRefFactory
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.loggerFor
import net.corda.core.utilities.trace
import net.corda.node.services.api.FlowLogicRefFactoryInternal
import net.corda.node.services.api.SchedulerService
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.utilities.*
@ -44,7 +44,7 @@ import javax.annotation.concurrent.ThreadSafe
*/
@ThreadSafe
class NodeSchedulerService(private val services: ServiceHubInternal,
private val flowLogicRefFactory: FlowLogicRefFactory,
private val flowLogicRefFactory: FlowLogicRefFactoryInternal,
private val schedulerTimerExecutor: Executor = Executors.newSingleThreadExecutor(),
private val unfinishedSchedules: ReusableLatch = ReusableLatch())
: SchedulerService, SingletonSerializeAsToken() {

View File

@ -0,0 +1,191 @@
package net.corda.node.services.statemachine
import com.google.common.primitives.Primitives
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.AppContext
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowLogicRef
import net.corda.core.flows.IllegalFlowLogicException
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.node.services.api.FlowLogicRefFactoryInternal
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.util.*
import kotlin.reflect.KFunction
import kotlin.reflect.KParameter
import kotlin.reflect.jvm.javaConstructor
import kotlin.reflect.jvm.javaType
/**
* The internal concrete implementation of the FlowLogicRef marker interface.
*/
@CordaSerializable
data class FlowLogicRefImpl internal constructor(val flowLogicClassName: String, val appContext: AppContext, val args: Map<String, Any?>) : FlowLogicRef
/**
* A class for conversion to and from [FlowLogic] and [FlowLogicRef] instances.
*
* Validation of types is performed on the way in and way out in case this object is passed between JVMs which might have differing
* whitelists.
*
* TODO: Ways to populate whitelist of "blessed" flows per node/party
* TODO: Ways to populate argument types whitelist. Per node/party or global?
* TODO: Align with API related logic for passing in FlowLogic references (FlowRef)
* TODO: Actual support for AppContext / AttachmentsClassLoader
*/
class FlowLogicRefFactoryImpl(override val flowWhitelist: Map<String, Set<String>>) : SingletonSerializeAsToken(), FlowLogicRefFactoryInternal {
constructor() : this(mapOf())
// Pending real dependence on AppContext for class loading etc
@Suppress("UNUSED_PARAMETER")
private fun validateFlowClassName(className: String, appContext: AppContext) {
// TODO: make this specific to the attachments in the [AppContext] by including [SecureHash] in whitelist check
require(flowWhitelist.containsKey(className)) { "${FlowLogic::class.java.simpleName} of ${FlowLogicRef::class.java.simpleName} must have type on the whitelist: $className" }
}
// Pending real dependence on AppContext for class loading etc
@Suppress("UNUSED_PARAMETER")
private fun validateArgClassName(className: String, argClassName: String, appContext: AppContext) {
// TODO: consider more carefully what to whitelist and how to secure flows
// For now automatically accept standard java.lang.* and kotlin.* types.
// All other types require manual specification at FlowLogicRefFactory construction time.
if (argClassName.startsWith("java.lang.") || argClassName.startsWith("kotlin.")) {
return
}
// TODO: make this specific to the attachments in the [AppContext] by including [SecureHash] in whitelist check
require(flowWhitelist[className]!!.contains(argClassName)) { "Args to $className must have types on the args whitelist: $argClassName, but it has ${flowWhitelist[className]}" }
}
/**
* Create a [FlowLogicRef] for the Kotlin primary constructor of a named [FlowLogic]
*/
fun createKotlin(flowLogicClassName: String, args: Map<String, Any?>, attachments: List<SecureHash> = emptyList()): FlowLogicRef {
val context = AppContext(attachments)
validateFlowClassName(flowLogicClassName, context)
for (arg in args.values.filterNotNull()) {
validateArgClassName(flowLogicClassName, arg.javaClass.name, context)
}
val clazz = Class.forName(flowLogicClassName)
require(FlowLogic::class.java.isAssignableFrom(clazz)) { "$flowLogicClassName is not a FlowLogic" }
@Suppress("UNCHECKED_CAST")
val logic = clazz as Class<FlowLogic<FlowLogic<*>>>
return createKotlin(logic, args)
}
/**
* Create a [FlowLogicRef] by assuming a single constructor and the given args.
*/
override fun create(type: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef {
// TODO: This is used via RPC but it's probably better if we pass in argument names and values explicitly
// to avoid requiring only a single constructor.
val argTypes = args.map { it?.javaClass }
val constructor = try {
type.kotlin.constructors.single { ctor ->
// Get the types of the arguments, always boxed (as that's what we get in the invocation).
val ctorTypes = ctor.javaConstructor!!.parameterTypes.map { Primitives.wrap(it) }
if (argTypes.size != ctorTypes.size)
return@single false
for ((argType, ctorType) in argTypes.zip(ctorTypes)) {
if (argType == null) continue // Try and find a match based on the other arguments.
if (!ctorType.isAssignableFrom(argType)) return@single false
}
true
}
} catch (e: IllegalArgumentException) {
throw IllegalFlowLogicException(type, "due to ambiguous match against the constructors: $argTypes")
} catch (e: NoSuchElementException) {
throw IllegalFlowLogicException(type, "due to missing constructor for arguments: $argTypes")
}
// Build map of args from array
val argsMap = args.zip(constructor.parameters).map { Pair(it.second.name!!, it.first) }.toMap()
return createKotlin(type, argsMap)
}
/**
* Create a [FlowLogicRef] by trying to find a Kotlin constructor that matches the given args.
*
* TODO: Rethink language specific naming.
*/
fun createKotlin(type: Class<out FlowLogic<*>>, args: Map<String, Any?>): FlowLogicRef {
// TODO: we need to capture something about the class loader or "application context" into the ref,
// perhaps as some sort of ThreadLocal style object. For now, just create an empty one.
val appContext = AppContext(emptyList())
validateFlowClassName(type.name, appContext)
// Check we can find a constructor and populate the args to it, but don't call it
createConstructor(appContext, type, args)
return FlowLogicRefImpl(type.name, appContext, args)
}
/**
* Create a [FlowLogicRef] by trying to find a Java constructor that matches the given args.
*/
private fun createJava(type: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef {
// Build map for each
val argsMap = HashMap<String, Any?>(args.size)
var index = 0
args.forEach { argsMap["arg${index++}"] = it }
return createKotlin(type, argsMap)
}
override fun toFlowLogic(ref: FlowLogicRef): FlowLogic<*> {
if (ref !is FlowLogicRefImpl) throw IllegalFlowLogicException(ref.javaClass, "FlowLogicRef was not created via correct FlowLogicRefFactory interface")
validateFlowClassName(ref.flowLogicClassName, ref.appContext)
val klass = Class.forName(ref.flowLogicClassName, true, ref.appContext.classLoader).asSubclass(FlowLogic::class.java)
return createConstructor(ref.appContext, klass, ref.args)()
}
private fun createConstructor(appContext: AppContext, clazz: Class<out FlowLogic<*>>, args: Map<String, Any?>): () -> FlowLogic<*> {
for (constructor in clazz.kotlin.constructors) {
val params = buildParams(appContext, clazz, constructor, args) ?: continue
// If we get here then we matched every parameter
return { constructor.callBy(params) }
}
throw IllegalFlowLogicException(clazz, "as could not find matching constructor for: $args")
}
private fun buildParams(appContext: AppContext, clazz: Class<out FlowLogic<*>>, constructor: KFunction<FlowLogic<*>>, args: Map<String, Any?>): HashMap<KParameter, Any?>? {
val params = hashMapOf<KParameter, Any?>()
val usedKeys = hashSetOf<String>()
for (parameter in constructor.parameters) {
if (!tryBuildParam(args, parameter, params)) {
return null
} else {
usedKeys += parameter.name!!
}
}
if ((args.keys - usedKeys).isNotEmpty()) {
// Not all args were used
return null
}
params.values.forEach { if (it is Any) validateArgClassName(clazz.name, it.javaClass.name, appContext) }
return params
}
private fun tryBuildParam(args: Map<String, Any?>, parameter: KParameter, params: HashMap<KParameter, Any?>): Boolean {
val containsKey = parameter.name in args
// OK to be missing if optional
return (parameter.isOptional && !containsKey) || (containsKey && paramCanBeBuilt(args, parameter, params))
}
private fun paramCanBeBuilt(args: Map<String, Any?>, parameter: KParameter, params: HashMap<KParameter, Any?>): Boolean {
val value = args[parameter.name]
params[parameter] = value
return (value is Any && parameterAssignableFrom(parameter.type.javaType, value)) || parameter.type.isMarkedNullable
}
private fun parameterAssignableFrom(type: Type, value: Any): Boolean {
if (type is Class<*>) {
if (type.isPrimitive) {
return Primitives.unwrap(value.javaClass) == type
} else {
return type.isAssignableFrom(value.javaClass)
}
} else if (type is ParameterizedType) {
return parameterAssignableFrom(type.rawType, value)
} else {
return false
}
}
}

View File

@ -1,8 +1,14 @@
package net.corda.core.flows;
package net.corda.node.services.events;
import org.junit.*;
import net.corda.core.flows.FlowLogic;
import net.corda.core.flows.FlowLogicRefFactory;
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl;
import org.junit.Test;
import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class FlowLogicRefFromJavaTest {
@ -55,7 +61,7 @@ public class FlowLogicRefFromJavaTest {
argsList.add(ParamType1.class.getName());
argsList.add(ParamType2.class.getName());
whiteList.put(JavaFlowLogic.class.getName(), argsList);
FlowLogicRefFactory factory = new FlowLogicRefFactory(whiteList);
FlowLogicRefFactory factory = new FlowLogicRefFactoryImpl(whiteList);
factory.create(JavaFlowLogic.class, new ParamType1(1), new ParamType2("Hello Jack"));
}
@ -63,7 +69,7 @@ public class FlowLogicRefFromJavaTest {
public void testNoArg() {
Map<String, Set<String>> whiteList = new HashMap<>();
whiteList.put(JavaNoArgFlowLogic.class.getName(), new HashSet<>());
FlowLogicRefFactory factory = new FlowLogicRefFactory(whiteList);
FlowLogicRefFactory factory = new FlowLogicRefFactoryImpl(whiteList);
factory.create(JavaNoArgFlowLogic.class);
}
}

View File

@ -4,7 +4,6 @@ import com.codahale.metrics.MetricRegistry
import net.corda.core.crypto.Party
import net.corda.core.flows.FlowInitiator
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowLogicRefFactory
import net.corda.core.node.NodeInfo
import net.corda.core.node.services.*
import net.corda.core.transactions.SignedTransaction
@ -13,6 +12,7 @@ import net.corda.node.serialization.NodeClock
import net.corda.node.services.api.*
import net.corda.node.services.messaging.MessagingService
import net.corda.node.services.schema.NodeSchemaService
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
import net.corda.node.services.statemachine.FlowStateMachineImpl
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.transactions.InMemoryTransactionVerifierService
@ -30,7 +30,7 @@ open class MockServiceHubInternal(
val mapCache: NetworkMapCacheInternal? = MockNetworkMapCache(),
val scheduler: SchedulerService? = null,
val overrideClock: Clock? = NodeClock(),
val flowFactory: FlowLogicRefFactory? = FlowLogicRefFactory(),
val flowFactory: FlowLogicRefFactoryInternal? = FlowLogicRefFactoryImpl(),
val schemas: SchemaService? = NodeSchemaService(),
val customTransactionVerifierService: TransactionVerifierService? = InMemoryTransactionVerifierService(2)
) : ServiceHubInternal() {
@ -56,7 +56,7 @@ open class MockServiceHubInternal(
get() = throw UnsupportedOperationException()
override val monitoringService: MonitoringService = MonitoringService(MetricRegistry())
override val flowLogicRefFactory: FlowLogicRefFactory
override val flowLogicRefFactory: FlowLogicRefFactoryInternal
get() = flowFactory ?: throw UnsupportedOperationException()
override val schemaService: SchemaService
get() = schemas ?: throw UnsupportedOperationException()

View File

@ -1,6 +1,8 @@
package net.corda.core.flows
package net.corda.node.services.events
import net.corda.core.days
import net.corda.core.flows.FlowLogic
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
import org.junit.Before
import org.junit.Test
import java.time.Duration
@ -34,12 +36,12 @@ class FlowLogicRefTest {
override fun call() = Unit
}
lateinit var factory: FlowLogicRefFactory
lateinit var factory: FlowLogicRefFactoryImpl
@Before
fun setup() {
// We have to allow Java boxed primitives but Kotlin warns we shouldn't be using them
factory = FlowLogicRefFactory(mapOf(Pair(KotlinFlowLogic::class.java.name, setOf(ParamType1::class.java.name, ParamType2::class.java.name)),
factory = FlowLogicRefFactoryImpl(mapOf(Pair(KotlinFlowLogic::class.java.name, setOf(ParamType1::class.java.name, ParamType2::class.java.name)),
Pair(KotlinNoArgFlowLogic::class.java.name, setOf())))
}

View File

@ -12,6 +12,7 @@ import net.corda.core.utilities.ALICE_KEY
import net.corda.core.utilities.DUMMY_NOTARY
import net.corda.node.services.MockServiceHubInternal
import net.corda.node.services.persistence.DBCheckpointStorage
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.vault.NodeVaultService
import net.corda.node.utilities.AffinityExecutor
@ -45,7 +46,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
// We have to allow Java boxed primitives but Kotlin warns we shouldn't be using them
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
val factory = FlowLogicRefFactory(mapOf(Pair(TestFlowLogic::class.java.name, setOf(NodeSchedulerServiceTest::class.java.name, Integer::class.java.name))))
val factory = FlowLogicRefFactoryImpl(mapOf(Pair(TestFlowLogic::class.java.name, setOf(NodeSchedulerServiceTest::class.java.name, Integer::class.java.name))))
lateinit var services: MockServiceHubInternal