diff --git a/core/src/main/kotlin/net/corda/core/flows/FlowLogicRef.kt b/core/src/main/kotlin/net/corda/core/flows/FlowLogicRef.kt index c8cdd4c171..7b4ff2e6ce 100644 --- a/core/src/main/kotlin/net/corda/core/flows/FlowLogicRef.kt +++ b/core/src/main/kotlin/net/corda/core/flows/FlowLogicRef.kt @@ -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>) : 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, attachments: List = 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>> - return createKotlin(logic, args) - } - - /** - * Create a [FlowLogicRef] by assuming a single constructor and the given args. - */ - fun create(type: Class>, 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>, args: Map): 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>, vararg args: Any?): FlowLogicRef { - // Build map for each - val argsMap = HashMap(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>, args: Map): () -> 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>, constructor: KFunction>, args: Map): HashMap? { - val params = hashMapOf() - val usedKeys = hashSetOf() - 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, parameter: KParameter, params: HashMap): 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, parameter: KParameter, params: HashMap): 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>, 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) +interface FlowLogicRef + /** * This is just some way to track what attachments need to be in the class loader, but may later include some app diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 27b61df002..f9d35601c6 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -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 startFlow(logic: FlowLogic, flowInitiator: FlowInitiator): FlowStateMachineImpl { 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 = ArrayList() protected val runOnStop: ArrayList = ArrayList() @@ -381,7 +381,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, } } - private fun initialiseFlowLogicFactory(): FlowLogicRefFactory { + private fun initialiseFlowLogicFactory(): FlowLogicRefFactoryInternal { val flowWhitelist = HashMap>() 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): List { diff --git a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt index 92238f5e9e..70b0e9dc91 100644 --- a/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt +++ b/node/src/main/kotlin/net/corda/node/services/api/ServiceHubInternal.kt @@ -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> + 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 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 1772212939..fb9425f268 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 @@ -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() { diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/FlowLogicRefFactoryImpl.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowLogicRefFactoryImpl.kt new file mode 100644 index 0000000000..fd2a9b3e89 --- /dev/null +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/FlowLogicRefFactoryImpl.kt @@ -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) : 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>) : 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, attachments: List = 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>> + return createKotlin(logic, args) + } + + /** + * Create a [FlowLogicRef] by assuming a single constructor and the given args. + */ + override fun create(type: Class>, 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>, args: Map): 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>, vararg args: Any?): FlowLogicRef { + // Build map for each + val argsMap = HashMap(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>, args: Map): () -> 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>, constructor: KFunction>, args: Map): HashMap? { + val params = hashMapOf() + val usedKeys = hashSetOf() + 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, parameter: KParameter, params: HashMap): 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, parameter: KParameter, params: HashMap): 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 + } + } +} \ No newline at end of file diff --git a/core/src/test/java/net/corda/core/flows/FlowLogicRefFromJavaTest.java b/node/src/test/java/net/corda/node/services/events/FlowLogicRefFromJavaTest.java similarity index 76% rename from core/src/test/java/net/corda/core/flows/FlowLogicRefFromJavaTest.java rename to node/src/test/java/net/corda/node/services/events/FlowLogicRefFromJavaTest.java index a71596ee1b..20eb7fa812 100644 --- a/core/src/test/java/net/corda/core/flows/FlowLogicRefFromJavaTest.java +++ b/node/src/test/java/net/corda/node/services/events/FlowLogicRefFromJavaTest.java @@ -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> whiteList = new HashMap<>(); whiteList.put(JavaNoArgFlowLogic.class.getName(), new HashSet<>()); - FlowLogicRefFactory factory = new FlowLogicRefFactory(whiteList); + FlowLogicRefFactory factory = new FlowLogicRefFactoryImpl(whiteList); factory.create(JavaNoArgFlowLogic.class); } } diff --git a/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt b/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt index 96f2bb5362..aa1cf3bc54 100644 --- a/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt +++ b/node/src/test/kotlin/net/corda/node/services/MockServiceHubInternal.kt @@ -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() diff --git a/core/src/test/kotlin/net/corda/core/flows/FlowLogicRefTest.kt b/node/src/test/kotlin/net/corda/node/services/events/FlowLogicRefTest.kt similarity index 89% rename from core/src/test/kotlin/net/corda/core/flows/FlowLogicRefTest.kt rename to node/src/test/kotlin/net/corda/node/services/events/FlowLogicRefTest.kt index d96d878afc..3baa1a7448 100644 --- a/core/src/test/kotlin/net/corda/core/flows/FlowLogicRefTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/events/FlowLogicRefTest.kt @@ -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()))) } diff --git a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt index 8b50e68fed..6870ccdefa 100644 --- a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt @@ -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