diff --git a/client/rpc/src/integration-test/java/net/corda/client/rpc/CordaRPCJavaClientTest.java b/client/rpc/src/integration-test/java/net/corda/client/rpc/CordaRPCJavaClientTest.java index 714b0d4316..4c0245462d 100644 --- a/client/rpc/src/integration-test/java/net/corda/client/rpc/CordaRPCJavaClientTest.java +++ b/client/rpc/src/integration-test/java/net/corda/client/rpc/CordaRPCJavaClientTest.java @@ -32,7 +32,7 @@ import static net.corda.testing.TestConstants.getALICE; public class CordaRPCJavaClientTest extends NodeBasedTest { public CordaRPCJavaClientTest() { - super(Collections.singletonList("net.corda.finance.contracts")); + super(Arrays.asList("net.corda.finance.contracts", CashSchemaV1.class.getPackage().getName())); } private List perms = Arrays.asList(startFlowPermission(CashPaymentFlow.class), startFlowPermission(CashIssueFlow.class)); @@ -53,7 +53,6 @@ public class CordaRPCJavaClientTest extends NodeBasedTest { public void setUp() throws ExecutionException, InterruptedException { CordaFuture> nodeFuture = startNotaryNode(getALICE().getName(), singletonList(rpcUser), true); node = nodeFuture.get(); - node.getInternals().registerCustomSchemas(Collections.singleton(CashSchemaV1.INSTANCE)); client = new CordaRPCClient(requireNonNull(node.getInternals().getConfiguration().getRpcAddress())); } 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 be6f05715a..277769354c 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 @@ -2,6 +2,7 @@ package net.corda.client.rpc import net.corda.core.crypto.random63BitValue import net.corda.core.flows.FlowInitiator +import net.corda.core.internal.packageName import net.corda.core.messaging.FlowProgressHandle import net.corda.core.messaging.StateMachineUpdate import net.corda.core.messaging.startFlow @@ -32,7 +33,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue -class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts")) { +class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", CashSchemaV1::class.packageName)) { private val rpcUser = User("user1", "test", permissions = setOf( startFlowPermission(), startFlowPermission() @@ -48,7 +49,6 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts")) @Before fun setUp() { node = startNotaryNode(ALICE.name, rpcUsers = listOf(rpcUser)).getOrThrow() - node.internals.registerCustomSchemas(setOf(CashSchemaV1)) client = CordaRPCClient(node.internals.configuration.rpcAddress!!) } diff --git a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt index 5f26ef2e48..2f101b869f 100644 --- a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt @@ -300,3 +300,6 @@ fun TransactionBuilder.toWireTransaction(services: ServicesForResolution, serial * @suppress */ fun TransactionBuilder.toLedgerTransaction(services: ServiceHub, serializationContext: SerializationContext) = toLedgerTransactionWithContext(services, serializationContext) + +/** Convenience method to get the package name of a class literal. */ +val KClass<*>.packageName get() = java.`package`.name diff --git a/core/src/test/kotlin/net/corda/core/internal/InternalUtilsTest.kt b/core/src/test/kotlin/net/corda/core/internal/InternalUtilsTest.kt index b2f31384db..0a2fb69f26 100644 --- a/core/src/test/kotlin/net/corda/core/internal/InternalUtilsTest.kt +++ b/core/src/test/kotlin/net/corda/core/internal/InternalUtilsTest.kt @@ -61,6 +61,7 @@ class InternalUtilsTest { assertArrayEquals(intArrayOf(1, 2, 3, 4), (1 until 5).stream().toArray()) assertArrayEquals(intArrayOf(1, 3), (1..4 step 2).stream().toArray()) assertArrayEquals(intArrayOf(1, 3), (1..3 step 2).stream().toArray()) + @Suppress("EmptyRange") // It's supposed to be empty. assertArrayEquals(intArrayOf(), (1..0).stream().toArray()) assertArrayEquals(intArrayOf(1, 0), (1 downTo 0).stream().toArray()) assertArrayEquals(intArrayOf(3, 1), (3 downTo 0 step 2).stream().toArray()) diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/CustomVaultQueryTest.kt b/docs/source/example-code/src/test/kotlin/net/corda/docs/CustomVaultQueryTest.kt index 847675db13..1ec43e7271 100644 --- a/docs/source/example-code/src/test/kotlin/net/corda/docs/CustomVaultQueryTest.kt +++ b/docs/source/example-code/src/test/kotlin/net/corda/docs/CustomVaultQueryTest.kt @@ -2,6 +2,7 @@ package net.corda.docs import net.corda.core.contracts.Amount import net.corda.core.identity.Party +import net.corda.core.internal.packageName import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow import net.corda.finance.* @@ -26,15 +27,12 @@ class CustomVaultQueryTest { @Before fun setup() { - mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance.contracts.asset")) + mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance.contracts.asset", CashSchemaV1::class.packageName)) mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name) nodeA = mockNet.createPartyNode() nodeB = mockNet.createPartyNode() - nodeA.internals.registerInitiatedFlow(TopupIssuerFlow.TopupIssuer::class.java) nodeA.internals.installCordaService(CustomVaultQuery.Service::class.java) - nodeA.internals.registerCustomSchemas(setOf(CashSchemaV1)) - nodeB.internals.registerCustomSchemas(setOf(CashSchemaV1)) notary = nodeA.services.getDefaultNotary() } diff --git a/docs/source/example-code/src/test/kotlin/net/corda/docs/FxTransactionBuildTutorialTest.kt b/docs/source/example-code/src/test/kotlin/net/corda/docs/FxTransactionBuildTutorialTest.kt index 97ddbc598c..7a5193c0b0 100644 --- a/docs/source/example-code/src/test/kotlin/net/corda/docs/FxTransactionBuildTutorialTest.kt +++ b/docs/source/example-code/src/test/kotlin/net/corda/docs/FxTransactionBuildTutorialTest.kt @@ -1,6 +1,7 @@ package net.corda.docs import net.corda.core.identity.Party +import net.corda.core.internal.packageName import net.corda.core.toFuture import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow @@ -24,12 +25,10 @@ class FxTransactionBuildTutorialTest { @Before fun setup() { - mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance.contracts.asset")) + mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance.contracts.asset", CashSchemaV1::class.packageName)) mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name) nodeA = mockNet.createPartyNode() nodeB = mockNet.createPartyNode() - nodeA.internals.registerCustomSchemas(setOf(CashSchemaV1)) - nodeB.internals.registerCustomSchemas(setOf(CashSchemaV1)) nodeB.internals.registerInitiatedFlow(ForeignExchangeRemoteFlow::class.java) notary = nodeA.services.getDefaultNotary() } diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt index bf4138379d..5fd6b46f21 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt @@ -55,8 +55,7 @@ class AttachmentsClassLoaderTests : TestDependencyInjectionBase() { class DummyServiceHub : MockServices() { override val cordappProvider: CordappProviderImpl - = CordappProviderImpl(CordappLoader.createDevMode(listOf(ISOLATED_CONTRACTS_JAR_PATH))).start(attachments) - + = CordappProviderImpl(CordappLoader.createDevMode(listOf(ISOLATED_CONTRACTS_JAR_PATH)), attachments) private val cordapp get() = cordappProvider.cordapps.first() val attachmentId get() = cordappProvider.getCordappAttachmentId(cordapp)!! val appContext get() = cordappProvider.getAppContext(cordapp) diff --git a/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt index 3ea5527202..9d4abec634 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/AttachmentLoadingTests.kt @@ -37,7 +37,7 @@ import kotlin.test.assertFailsWith class AttachmentLoadingTests : TestDependencyInjectionBase() { private class Services : MockServices() { - private val provider = CordappProviderImpl(CordappLoader.createDevMode(listOf(isolatedJAR))).start(attachments) + private val provider = CordappProviderImpl(CordappLoader.createDevMode(listOf(isolatedJAR)), attachments) private val cordapp get() = provider.cordapps.first() val attachmentId get() = provider.getCordappAttachmentId(cordapp)!! val appContext get() = provider.getAppContext(cordapp) 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 9a7e5cbbeb..16829873aa 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -7,7 +7,6 @@ import net.corda.confidential.SwapIdentitiesFlow import net.corda.confidential.SwapIdentitiesHandler import net.corda.core.CordaException import net.corda.core.concurrent.CordaFuture -import net.corda.core.cordapp.CordappProvider import net.corda.core.flows.* import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party @@ -26,7 +25,6 @@ import net.corda.core.node.ServiceHub import net.corda.core.node.StateLoader import net.corda.core.node.services.* import net.corda.core.node.services.NetworkMapCache.MapChange -import net.corda.core.schemas.MappedSchema import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken @@ -37,6 +35,7 @@ import net.corda.node.VersionInfo import net.corda.node.internal.classloading.requireAnnotation import net.corda.node.internal.cordapp.CordappLoader import net.corda.node.internal.cordapp.CordappProviderImpl +import net.corda.node.internal.cordapp.CordappProviderInternal import net.corda.node.services.ContractUpgradeHandler import net.corda.node.services.FinalityHandler import net.corda.node.services.NotaryChangeHandler @@ -148,7 +147,6 @@ abstract class AbstractNode(config: NodeConfiguration, protected lateinit var network: MessagingService protected val runOnStop = ArrayList<() -> Any?>() protected lateinit var database: CordaPersistence - lateinit var cordappProvider: CordappProviderImpl protected val _nodeReadyFuture = openFuture() /** Completes once the node has successfully registered with the network map service * or has loaded network map data from local database */ @@ -161,7 +159,7 @@ abstract class AbstractNode(config: NodeConfiguration, } open val serializationWhitelists: List by lazy { - cordappProvider.cordapps.flatMap { it.serializationWhitelists } + cordappLoader.cordapps.flatMap { it.serializationWhitelists } } /** Set to non-null once [start] has been successfully called. */ @@ -185,11 +183,12 @@ abstract class AbstractNode(config: NodeConfiguration, validateKeystore() } + private fun makeSchemaService() = NodeSchemaService(cordappLoader) open fun generateNodeInfo() { check(started == null) { "Node has already been started" } initCertificate() log.info("Generating nodeInfo ...") - val schemaService = NodeSchemaService() + val schemaService = makeSchemaService() initialiseDatabasePersistence(schemaService) { makeServices(schemaService) saveOwnNodeInfo() @@ -200,7 +199,7 @@ abstract class AbstractNode(config: NodeConfiguration, check(started == null) { "Node has already been started" } initCertificate() log.info("Node starting up ...") - val schemaService = NodeSchemaService() + val schemaService = makeSchemaService() // Do all of this in a database transaction so anything that might need a connection has one. val startedImpl = initialiseDatabasePersistence(schemaService) { val tokenizableServices = makeServices(schemaService) @@ -231,8 +230,7 @@ abstract class AbstractNode(config: NodeConfiguration, installCordaServices() registerCordappFlows() - _services.rpcFlows += cordappProvider.cordapps.flatMap { it.rpcFlows } - registerCustomSchemas(cordappProvider.cordapps.flatMap { it.customSchemas }.toSet()) + _services.rpcFlows += cordappLoader.cordapps.flatMap { it.rpcFlows } FlowLogicRefFactoryImpl.classloader = cordappLoader.appClassLoader runOnStop += network::stop @@ -254,7 +252,7 @@ abstract class AbstractNode(config: NodeConfiguration, private class ServiceInstantiationException(cause: Throwable?) : CordaException("Service Instantiation Error", cause) private fun installCordaServices() { - val loadedServices = cordappProvider.cordapps.flatMap { it.services } + val loadedServices = cordappLoader.cordapps.flatMap { it.services } filterServicesToInstall(loadedServices).forEach { try { installCordaService(it) @@ -374,7 +372,7 @@ abstract class AbstractNode(config: NodeConfiguration, } private fun registerCordappFlows() { - cordappProvider.cordapps.flatMap { it.initiatedFlows } + cordappLoader.cordapps.flatMap { it.initiatedFlows } .forEach { try { registerInitiatedFlowInternal(it, track = false) @@ -471,11 +469,11 @@ abstract class AbstractNode(config: NodeConfiguration, */ private fun makeServices(schemaService: SchemaService): MutableList { checkpointStorage = DBCheckpointStorage() - cordappProvider = CordappProviderImpl(cordappLoader) val transactionStorage = makeTransactionStorage() - _services = ServiceHubInternalImpl(schemaService, transactionStorage, StateLoaderImpl(transactionStorage)) - attachments = NodeAttachmentService(services.monitoringService.metrics) - cordappProvider.start(attachments) + val metrics = MetricRegistry() + attachments = NodeAttachmentService(metrics) + val cordappProvider = CordappProviderImpl(cordappLoader, attachments) + _services = ServiceHubInternalImpl(schemaService, transactionStorage, StateLoaderImpl(transactionStorage), MonitoringService(metrics), cordappProvider) legalIdentity = obtainIdentity(notaryConfig = null) network = makeMessagingService(legalIdentity) info = makeInfo(legalIdentity) @@ -541,7 +539,7 @@ abstract class AbstractNode(config: NodeConfiguration, protected open fun initialiseDatabasePersistence(schemaService: SchemaService, insideTransaction: () -> T): T { val props = configuration.dataSourceProperties if (props.isNotEmpty()) { - this.database = configureDatabase(props, configuration.database, schemaService, { _services.identityService }) + this.database = configureDatabase(props, configuration.database, { _services.identityService }, schemaService) // Now log the vendor string as this will also cause a connection to be tested eagerly. database.transaction { log.info("Connected to ${database.dataSource.connection.metaData.databaseProductName} database.") @@ -764,12 +762,13 @@ abstract class AbstractNode(config: NodeConfiguration, private inner class ServiceHubInternalImpl( override val schemaService: SchemaService, override val validatedTransactions: WritableTransactionStorage, - private val stateLoader: StateLoader + private val stateLoader: StateLoader, + override val monitoringService: MonitoringService, + override val cordappProvider: CordappProviderInternal ) : SingletonSerializeAsToken(), ServiceHubInternal, StateLoader by stateLoader { override val rpcFlows = ArrayList>>() override val stateMachineRecordedTransactionMapping = DBTransactionMappingStorage() override val auditService = DummyAuditService() - override val monitoringService = MonitoringService(MetricRegistry()) override val transactionVerifierService by lazy { makeTransactionVerifierService() } override val networkMapCache by lazy { PersistentNetworkMapCache(this) } override val vaultService by lazy { NodeVaultService(platformClock, keyManagementService, stateLoader, this@AbstractNode.database.hibernateConfig) } @@ -794,8 +793,6 @@ abstract class AbstractNode(config: NodeConfiguration, override val myInfo: NodeInfo get() = info override val database: CordaPersistence get() = this@AbstractNode.database override val configuration: NodeConfiguration get() = this@AbstractNode.configuration - override val cordappProvider: CordappProvider = this@AbstractNode.cordappProvider - override fun cordaService(type: Class): T { require(type.isAnnotationPresent(CordaService::class.java)) { "${type.name} is not a Corda service" } return cordappServices.getInstance(type) ?: throw IllegalArgumentException("Corda service ${type.name} does not exist") @@ -817,9 +814,4 @@ abstract class AbstractNode(config: NodeConfiguration, override fun jdbcSession(): Connection = database.createSession() } - - fun registerCustomSchemas(schemas: Set) { - database.hibernateConfig.schemaService.registerCustomSchemas(schemas) - } - } diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index 7257eea773..e76f226adc 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -62,7 +62,7 @@ import kotlin.system.exitProcess * * @param configuration This is typically loaded from a TypeSafe HOCON configuration file. */ -open class Node(override val configuration: FullNodeConfiguration, +open class Node(configuration: FullNodeConfiguration, versionInfo: VersionInfo, val initialiseSerialization: Boolean = true, cordappLoader: CordappLoader = makeCordappLoader(configuration) @@ -99,6 +99,7 @@ open class Node(override val configuration: FullNodeConfiguration, } override val log: Logger get() = logger + override val configuration get() = super.configuration as FullNodeConfiguration // Necessary to avoid init order NPE. override val networkMapAddress: NetworkMapAddress? get() = configuration.networkMapService?.address?.let(::NetworkMapAddress) override fun makeTransactionVerifierService() = (network as NodeMessagingClient).verifierService diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt index 67a06aa2e9..1776b64271 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt @@ -95,7 +95,7 @@ open class NodeStartup(val args: Array) { return } val startedNode = node.start() - Node.printBasicNodeInfo("Loaded CorDapps", startedNode.internals.cordappProvider.cordapps.joinToString { it.name }) + Node.printBasicNodeInfo("Loaded CorDapps", startedNode.services.cordappProvider.cordapps.joinToString { it.name }) startedNode.internals.nodeReadyFuture.thenMatch({ val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0 val name = startedNode.info.legalIdentitiesAndCerts.first().name.organisation diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappLoader.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappLoader.kt index c481bfcc36..5154c592b1 100644 --- a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappLoader.kt +++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappLoader.kt @@ -38,10 +38,10 @@ import kotlin.streams.toList * * @property cordappJarPaths The classpath of cordapp JARs */ -class CordappLoader private constructor(private val cordappJarPaths: List) { +class CordappLoader private constructor(private val cordappJarPaths: List) { val cordapps: List by lazy { loadCordapps() + coreCordapp } - internal val appClassLoader: ClassLoader = URLClassLoader(cordappJarPaths.toTypedArray(), javaClass.classLoader) + internal val appClassLoader: ClassLoader = URLClassLoader(cordappJarPaths.stream().map { it.url }.toTypedArray(), javaClass.classLoader) init { if (cordappJarPaths.isEmpty()) { @@ -97,20 +97,22 @@ class CordappLoader private constructor(private val cordappJarPaths: List) * @param scanJars Uses the JAR URLs provided for classpath scanning and Cordapp detection */ @VisibleForTesting - fun createDevMode(scanJars: List) = CordappLoader(scanJars) + fun createDevMode(scanJars: List) = CordappLoader(scanJars.map { RestrictedURL(it, null) }) private fun getCordappsPath(baseDir: Path): Path = baseDir / CORDAPPS_DIR_NAME - private fun createScanPackage(scanPackage: String): List { + private fun createScanPackage(scanPackage: String): List { val resource = scanPackage.replace('.', '/') return this::class.java.classLoader.getResources(resource) .asSequence() .map { path -> if (path.protocol == "jar") { - (path.openConnection() as JarURLConnection).jarFileURL.toURI() + // When running tests from gradle this may be a corda module jar, so restrict to scanPackage: + RestrictedURL((path.openConnection() as JarURLConnection).jarFileURL, scanPackage) } else { - createDevCordappJar(scanPackage, path, resource) - }.toURL() + // No need to restrict as createDevCordappJar has already done that: + RestrictedURL(createDevCordappJar(scanPackage, path, resource).toURL(), null) + } } .toList() } @@ -143,12 +145,12 @@ class CordappLoader private constructor(private val cordappJarPaths: List) return generatedCordapps[path]!! } - private fun getCordappsInDirectory(cordappsDir: Path): List { + private fun getCordappsInDirectory(cordappsDir: Path): List { return if (!cordappsDir.exists()) { - emptyList() + emptyList() } else { cordappsDir.list { - it.filter { it.isRegularFile() && it.toString().endsWith(".jar") }.map { it.toUri().toURL() }.toList() + it.filter { it.isRegularFile() && it.toString().endsWith(".jar") }.map { RestrictedURL(it.toUri().toURL(), null) }.toList() } } } @@ -187,15 +189,15 @@ class CordappLoader private constructor(private val cordappJarPaths: List) findServices(scanResult), findPlugins(it), findCustomSchemas(scanResult), - it) + it.url) } } - private fun findServices(scanResult: ScanResult): List> { + private fun findServices(scanResult: RestrictedScanResult): List> { return scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class) } - private fun findInitiatedFlows(scanResult: ScanResult): List>> { + private fun findInitiatedFlows(scanResult: RestrictedScanResult): List>> { return scanResult.getClassesWithAnnotation(FlowLogic::class, InitiatedBy::class) // First group by the initiating flow class in case there are multiple mappings .groupBy { it.requireAnnotation().value.java } @@ -214,35 +216,35 @@ class CordappLoader private constructor(private val cordappJarPaths: List) return Modifier.isPublic(modifiers) && !isLocalClass && !isAnonymousClass && (!isMemberClass || Modifier.isStatic(modifiers)) } - private fun findRPCFlows(scanResult: ScanResult): List>> { + private fun findRPCFlows(scanResult: RestrictedScanResult): List>> { return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByRPC::class).filter { it.isUserInvokable() } } - private fun findServiceFlows(scanResult: ScanResult): List>> { + private fun findServiceFlows(scanResult: RestrictedScanResult): List>> { return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByService::class) } - private fun findSchedulableFlows(scanResult: ScanResult): List>> { + private fun findSchedulableFlows(scanResult: RestrictedScanResult): List>> { return scanResult.getClassesWithAnnotation(FlowLogic::class, SchedulableFlow::class) } - private fun findContractClassNames(scanResult: ScanResult): List { - return (scanResult.getNamesOfClassesImplementing(Contract::class.java) + scanResult.getNamesOfClassesImplementing(UpgradedContract::class.java)).distinct() + private fun findContractClassNames(scanResult: RestrictedScanResult): List { + return (scanResult.getNamesOfClassesImplementing(Contract::class) + scanResult.getNamesOfClassesImplementing(UpgradedContract::class)).distinct() } - private fun findPlugins(cordappJarPath: URL): List { - return ServiceLoader.load(SerializationWhitelist::class.java, URLClassLoader(arrayOf(cordappJarPath), appClassLoader)).toList().filter { - cordappJarPath == it.javaClass.protectionDomain.codeSource.location + private fun findPlugins(cordappJarPath: RestrictedURL): List { + return ServiceLoader.load(SerializationWhitelist::class.java, URLClassLoader(arrayOf(cordappJarPath.url), appClassLoader)).toList().filter { + it.javaClass.protectionDomain.codeSource.location == cordappJarPath.url && it.javaClass.name.startsWith(cordappJarPath.qualifiedNamePrefix) } + DefaultWhitelist // Always add the DefaultWhitelist to the whitelist for an app. } - private fun findCustomSchemas(scanResult: ScanResult): Set { + private fun findCustomSchemas(scanResult: RestrictedScanResult): Set { return scanResult.getClassesWithSuperclass(MappedSchema::class).toSet() } - private fun scanCordapp(cordappJarPath: URL): ScanResult { + private fun scanCordapp(cordappJarPath: RestrictedURL): RestrictedScanResult { logger.info("Scanning CorDapp in $cordappJarPath") - return FastClasspathScanner().addClassLoader(appClassLoader).overrideClasspath(cordappJarPath).scan() + return RestrictedScanResult(FastClasspathScanner().addClassLoader(appClassLoader).overrideClasspath(cordappJarPath.url).scan(), cordappJarPath.qualifiedNamePrefix) } private class FlowTypeHierarchyComparator(val initiatingFlow: Class>) : Comparator>> { @@ -269,16 +271,30 @@ class CordappLoader private constructor(private val cordappJarPaths: List) } } - private fun ScanResult.getClassesWithSuperclass(type: KClass): List { - return getNamesOfSubclassesOf(type.java) - .mapNotNull { loadClass(it, type) } - .filterNot { Modifier.isAbstract(it.modifiers) } - .map { it.kotlin.objectOrNewInstance() } + /** @param rootPackageName only this package and subpackages may be extracted from [url], or null to allow all packages. */ + private class RestrictedURL(val url: URL, rootPackageName: String?) { + val qualifiedNamePrefix = rootPackageName?.let { it + '.' } ?: "" } - private fun ScanResult.getClassesWithAnnotation(type: KClass, annotation: KClass): List> { - return getNamesOfClassesWithAnnotation(annotation.java) - .mapNotNull { loadClass(it, type) } - .filterNot { Modifier.isAbstract(it.modifiers) } + private inner class RestrictedScanResult(private val scanResult: ScanResult, private val qualifiedNamePrefix: String) { + fun getNamesOfClassesImplementing(type: KClass<*>): List { + return scanResult.getNamesOfClassesImplementing(type.java) + .filter { it.startsWith(qualifiedNamePrefix) } + } + + fun getClassesWithSuperclass(type: KClass): List { + return scanResult.getNamesOfSubclassesOf(type.java) + .filter { it.startsWith(qualifiedNamePrefix) } + .mapNotNull { loadClass(it, type) } + .filterNot { Modifier.isAbstract(it.modifiers) } + .map { it.kotlin.objectOrNewInstance() } + } + + fun getClassesWithAnnotation(type: KClass, annotation: KClass): List> { + return scanResult.getNamesOfClassesWithAnnotation(annotation.java) + .filter { it.startsWith(qualifiedNamePrefix) } + .mapNotNull { loadClass(it, type) } + .filterNot { Modifier.isAbstract(it.modifiers) } + } } } diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderImpl.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderImpl.kt index 967c332fd3..ba305283f2 100644 --- a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderImpl.kt @@ -6,15 +6,14 @@ import net.corda.core.crypto.SecureHash import net.corda.core.node.services.AttachmentStorage import net.corda.core.cordapp.Cordapp import net.corda.core.cordapp.CordappContext -import net.corda.core.cordapp.CordappProvider import net.corda.core.node.services.AttachmentId import net.corda.core.serialization.SingletonSerializeAsToken -import java.net.URLClassLoader +import java.net.URL /** * Cordapp provider and store. For querying CorDapps for their attachment and vice versa. */ -open class CordappProviderImpl(private val cordappLoader: CordappLoader) : SingletonSerializeAsToken(), CordappProvider { +open class CordappProviderImpl(private val cordappLoader: CordappLoader, attachmentStorage: AttachmentStorage) : SingletonSerializeAsToken(), CordappProviderInternal { override fun getAppContext(): CordappContext { // TODO: Use better supported APIs in Java 9 Exception().stackTrace.forEach { stackFrame -> @@ -34,28 +33,19 @@ open class CordappProviderImpl(private val cordappLoader: CordappLoader) : Singl /** * Current known CorDapps loaded on this node */ - val cordapps get() = cordappLoader.cordapps - private lateinit var cordappAttachments: HashBiMap - - /** - * Should only be called once from the initialisation routine of the node or tests - */ - fun start(attachmentStorage: AttachmentStorage): CordappProviderImpl { - cordappAttachments = HashBiMap.create(loadContractsIntoAttachmentStore(attachmentStorage)) - return this - } - + override val cordapps get() = cordappLoader.cordapps + private val cordappAttachments = HashBiMap.create(loadContractsIntoAttachmentStore(attachmentStorage)) /** * Gets the attachment ID of this CorDapp. Only CorDapps with contracts have an attachment ID * * @param cordapp The cordapp to get the attachment ID * @return An attachment ID if it exists, otherwise nothing */ - fun getCordappAttachmentId(cordapp: Cordapp): SecureHash? = cordappAttachments.inverse().get(cordapp) + fun getCordappAttachmentId(cordapp: Cordapp): SecureHash? = cordappAttachments.inverse().get(cordapp.jarPath) - private fun loadContractsIntoAttachmentStore(attachmentStorage: AttachmentStorage): Map { - val cordappsWithAttachments = cordapps.filter { !it.contractClassNames.isEmpty() } - val attachmentIds = cordappsWithAttachments.map { it.jarPath.openStream().use { attachmentStorage.importAttachment(it) } } + private fun loadContractsIntoAttachmentStore(attachmentStorage: AttachmentStorage): Map { + val cordappsWithAttachments = cordapps.filter { !it.contractClassNames.isEmpty() }.map { it.jarPath } + val attachmentIds = cordappsWithAttachments.map { it.openStream().use { attachmentStorage.importAttachment(it) } } return attachmentIds.zip(cordappsWithAttachments).toMap() } diff --git a/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderInternal.kt b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderInternal.kt new file mode 100644 index 0000000000..a29d8bab25 --- /dev/null +++ b/node/src/main/kotlin/net/corda/node/internal/cordapp/CordappProviderInternal.kt @@ -0,0 +1,8 @@ +package net.corda.node.internal.cordapp + +import net.corda.core.cordapp.Cordapp +import net.corda.core.cordapp.CordappProvider + +interface CordappProviderInternal : CordappProvider { + val cordapps: List +} diff --git a/node/src/main/kotlin/net/corda/node/services/api/SchemaService.kt b/node/src/main/kotlin/net/corda/node/services/api/SchemaService.kt index 7428a2e90a..4a4d815708 100644 --- a/node/src/main/kotlin/net/corda/node/services/api/SchemaService.kt +++ b/node/src/main/kotlin/net/corda/node/services/api/SchemaService.kt @@ -30,11 +30,5 @@ interface SchemaService { * or via custom logic in this service. */ fun generateMappedObject(state: ContractState, schema: MappedSchema): PersistentState - - /** - * Registration mechanism to add custom contract schemas that extend the [MappedSchema] class. - */ - fun registerCustomSchemas(customSchemas: Set) - } //DOCEND SchemaService 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 65bd38d843..5fdb7993a0 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 @@ -21,6 +21,7 @@ import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.loggerFor import net.corda.node.internal.InitiatedFlowFactory +import net.corda.node.internal.cordapp.CordappProviderInternal import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.messaging.MessagingService import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl @@ -89,7 +90,7 @@ interface ServiceHubInternal : ServiceHub { val networkService: MessagingService val database: CordaPersistence val configuration: NodeConfiguration - + override val cordappProvider: CordappProviderInternal override fun recordTransactions(notifyVault: Boolean, txs: Iterable) { require(txs.any()) { "No transactions passed in for recording" } val recordedTransactions = txs.filter { validatedTransactions.addTransaction(it) } diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/HibernateConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/persistence/HibernateConfiguration.kt index bf6efb6c8c..8fb0023b3d 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/HibernateConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/HibernateConfiguration.kt @@ -33,25 +33,13 @@ class HibernateConfiguration(val schemaService: SchemaService, private val datab private val sessionFactories = ConcurrentHashMap, SessionFactory>() private val transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel") ?: "") - - init { - logger.info("Init HibernateConfiguration for schemas: ${schemaService.schemaOptions.keys}") - sessionFactoryForRegisteredSchemas() + val sessionFactoryForRegisteredSchemas = schemaService.schemaOptions.keys.let { + logger.info("Init HibernateConfiguration for schemas: $it") + sessionFactoryForSchemas(it) } - fun sessionFactoryForRegisteredSchemas(): SessionFactory { - return sessionFactoryForSchemas(*schemaService.schemaOptions.keys.toTypedArray()) - } - - fun sessionFactoryForSchema(schema: MappedSchema): SessionFactory { - return sessionFactoryForSchemas(schema) - } - - //vararg to set conversions left to preserve method signature for now - fun sessionFactoryForSchemas(vararg schemas: MappedSchema): SessionFactory { - val schemaSet: Set = schemas.toSet() - return sessionFactories.computeIfAbsent(schemaSet, { makeSessionFactoryForSchemas(schemaSet) }) - } + /** @param key must be immutable, not just read-only. */ + fun sessionFactoryForSchemas(key: Set) = sessionFactories.computeIfAbsent(key, { makeSessionFactoryForSchemas(key) }) private fun makeSessionFactoryForSchemas(schemas: Set): SessionFactory { logger.info("Creating session factory for schemas: $schemas") diff --git a/node/src/main/kotlin/net/corda/node/services/schema/HibernateObserver.kt b/node/src/main/kotlin/net/corda/node/services/schema/HibernateObserver.kt index 9afc740949..45a3334ef1 100644 --- a/node/src/main/kotlin/net/corda/node/services/schema/HibernateObserver.kt +++ b/node/src/main/kotlin/net/corda/node/services/schema/HibernateObserver.kt @@ -38,7 +38,7 @@ class HibernateObserver(vaultUpdates: Observable>, v } fun persistStateWithSchema(state: ContractState, stateRef: StateRef, schema: MappedSchema) { - val sessionFactory = config.sessionFactoryForSchema(schema) + val sessionFactory = config.sessionFactoryForSchemas(setOf(schema)) val session = sessionFactory.withOptions(). connection(DatabaseTransactionManager.current().connection). flushMode(FlushMode.MANUAL). diff --git a/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt b/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt index 0599616644..8436f9459b 100644 --- a/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt +++ b/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt @@ -9,6 +9,7 @@ import net.corda.core.schemas.NodeInfoSchemaV1 import net.corda.core.schemas.PersistentState import net.corda.core.schemas.QueryableState import net.corda.core.serialization.SingletonSerializeAsToken +import net.corda.node.internal.cordapp.CordappLoader import net.corda.node.services.api.SchemaService import net.corda.node.services.events.NodeSchedulerService import net.corda.node.services.identity.PersistentIdentityService @@ -27,13 +28,13 @@ import net.corda.node.services.vault.VaultSchemaV1 /** * Most basic implementation of [SchemaService]. - * + * @param cordappLoader if not null, custom schemas will be extracted from its cordapps. * TODO: support loading schema options from node configuration. * TODO: support configuring what schemas are to be selected for persistence. * TODO: support plugins for schema version upgrading or custom mapping not supported by original [QueryableState]. * TODO: create whitelisted tables when a CorDapp is first installed */ -class NodeSchemaService(customSchemas: Set = emptySet()) : SchemaService, SingletonSerializeAsToken() { +class NodeSchemaService(cordappLoader: CordappLoader?) : SchemaService, SingletonSerializeAsToken() { // Entities for compulsory services object NodeServices @@ -67,9 +68,12 @@ class NodeSchemaService(customSchemas: Set = emptySet()) : SchemaS Pair(NodeInfoSchemaV1, SchemaService.SchemaOptions()), Pair(NodeServicesV1, SchemaService.SchemaOptions())) - override var schemaOptions: Map = requiredSchemas.plus(customSchemas.map { mappedSchema -> - Pair(mappedSchema, SchemaService.SchemaOptions()) - }) + override val schemaOptions: Map = if (cordappLoader == null) { + requiredSchemas + } else { + val customSchemas = cordappLoader.cordapps.flatMap { it.customSchemas }.toSet() + requiredSchemas.plus(customSchemas.map { mappedSchema -> Pair(mappedSchema, SchemaService.SchemaOptions()) }) + } // Currently returns all schemas supported by the state, with no filtering or enrichment. override fun selectSchemas(state: ContractState): Iterable { @@ -92,10 +96,4 @@ class NodeSchemaService(customSchemas: Set = emptySet()) : SchemaS return VaultSchemaV1.VaultFungibleStates(state.owner, state.amount.quantity, state.amount.token.issuer.party, state.amount.token.issuer.reference, state.participants) return (state as QueryableState).generateMappedObject(schema) } - - override fun registerCustomSchemas(_customSchemas: Set) { - schemaOptions = schemaOptions.plus(_customSchemas.map { mappedSchema -> - Pair(mappedSchema, SchemaService.SchemaOptions()) - }) - } } diff --git a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt index 864da2bd50..d5a189b0ee 100644 --- a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt +++ b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt @@ -59,7 +59,7 @@ private fun CriteriaBuilder.executeUpdate(session: Session, configure: Root<*>.( * TODO: keep an audit trail with time stamps of previously unconsumed states "as of" a particular point in time. * TODO: have transaction storage do some caching. */ -class NodeVaultService(private val clock: Clock, private val keyManagementService: KeyManagementService, private val stateLoader: StateLoader, private val hibernateConfig: HibernateConfiguration) : SingletonSerializeAsToken(), VaultServiceInternal { +class NodeVaultService(private val clock: Clock, private val keyManagementService: KeyManagementService, private val stateLoader: StateLoader, hibernateConfig: HibernateConfiguration) : SingletonSerializeAsToken(), VaultServiceInternal { private companion object { val log = loggerFor() @@ -377,9 +377,8 @@ class NodeVaultService(private val clock: Clock, private val keyManagementServic return keysToCheck.any { it in myKeys } } - private var sessionFactory = hibernateConfig.sessionFactoryForRegisteredSchemas() - private var criteriaBuilder = sessionFactory.criteriaBuilder - + private val sessionFactory = hibernateConfig.sessionFactoryForRegisteredSchemas + private val criteriaBuilder = sessionFactory.criteriaBuilder /** * Maintain a list of contract state interfaces to concrete types stored in the vault * for usage in generic queries of type queryBy or queryBy> @@ -406,11 +405,6 @@ class NodeVaultService(private val clock: Clock, private val keyManagementServic @Throws(VaultQueryException::class) override fun _queryBy(criteria: QueryCriteria, paging: PageSpecification, sorting: Sort, contractStateType: Class): Vault.Page { log.info("Vault Query for contract type: $contractStateType, criteria: $criteria, pagination: $paging, sorting: $sorting") - - // refresh to include any schemas registered after initial VQ service initialisation - sessionFactory = hibernateConfig.sessionFactoryForRegisteredSchemas() - criteriaBuilder = sessionFactory.criteriaBuilder - // calculate total results where a page specification has been defined var totalStates = -1L if (!paging.isDefault) { diff --git a/node/src/main/kotlin/net/corda/node/utilities/CordaPersistence.kt b/node/src/main/kotlin/net/corda/node/utilities/CordaPersistence.kt index 0bf9885945..b8fc4f333d 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/CordaPersistence.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/CordaPersistence.kt @@ -6,8 +6,6 @@ import net.corda.core.node.services.IdentityService import net.corda.node.services.api.SchemaService import net.corda.node.services.persistence.HibernateConfiguration import net.corda.node.services.schema.NodeSchemaService -import org.hibernate.SessionFactory - import rx.Observable import rx.Subscriber import rx.subjects.UnicastSubject @@ -32,12 +30,7 @@ class CordaPersistence(var dataSource: HikariDataSource, private val schemaServi HibernateConfiguration(schemaService, databaseProperties, createIdentityService) } } - - val entityManagerFactory: SessionFactory by lazy { - transaction { - hibernateConfig.sessionFactoryForRegisteredSchemas() - } - } + val entityManagerFactory get() = hibernateConfig.sessionFactoryForRegisteredSchemas companion object { fun connect(dataSource: HikariDataSource, schemaService: SchemaService, createIdentityService: () -> IdentityService, databaseProperties: Properties): CordaPersistence { @@ -103,7 +96,7 @@ class CordaPersistence(var dataSource: HikariDataSource, private val schemaServi } } -fun configureDatabase(dataSourceProperties: Properties, databaseProperties: Properties?, schemaService: SchemaService = NodeSchemaService(), createIdentityService: () -> IdentityService): CordaPersistence { +fun configureDatabase(dataSourceProperties: Properties, databaseProperties: Properties?, createIdentityService: () -> IdentityService, schemaService: SchemaService = NodeSchemaService(null)): CordaPersistence { val config = HikariConfig(dataSourceProperties) val dataSource = HikariDataSource(config) val persistence = CordaPersistence.connect(dataSource, schemaService, createIdentityService, databaseProperties ?: Properties()) diff --git a/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java b/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java index 0568b45a3e..2ad7697d20 100644 --- a/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java +++ b/node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java @@ -8,7 +8,6 @@ import net.corda.core.messaging.*; import net.corda.core.node.services.*; import net.corda.core.node.services.vault.*; import net.corda.core.node.services.vault.QueryCriteria.*; -import net.corda.core.schemas.*; import net.corda.core.utilities.*; import net.corda.finance.contracts.*; import net.corda.finance.contracts.asset.*; @@ -43,14 +42,13 @@ public class VaultQueryJavaTests extends TestDependencyInjectionBase { @Before public void setUp() { - List cordappPackages = Arrays.asList("net.corda.testing.contracts", "net.corda.finance.contracts.asset"); + List cordappPackages = Arrays.asList("net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1.class.getPackage().getName()); ArrayList keys = new ArrayList<>(); keys.add(getMEGA_CORP_KEY()); keys.add(getDUMMY_NOTARY_KEY()); - Set requiredSchemas = Collections.singleton(CashSchemaV1.INSTANCE); IdentityService identitySvc = makeTestIdentityService(); @SuppressWarnings("unchecked") - Pair databaseAndServices = makeTestDatabaseAndMockServices(requiredSchemas, keys, () -> identitySvc, cordappPackages); + Pair databaseAndServices = makeTestDatabaseAndMockServices(keys, () -> identitySvc, cordappPackages); issuerServices = new MockServices(cordappPackages, getDUMMY_CASH_ISSUER_KEY(), getBOC_KEY()); database = databaseAndServices.getFirst(); services = databaseAndServices.getSecond(); diff --git a/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt b/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt index 3d4005d6fc..54117732cf 100644 --- a/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt +++ b/node/src/test/kotlin/net/corda/node/InteractiveShellTest.kt @@ -26,7 +26,7 @@ import kotlin.test.assertEquals class InteractiveShellTest { @Before fun setup() { - InteractiveShell.database = configureDatabase(MockServices.makeTestDataSourceProperties(), MockServices.makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) + InteractiveShell.database = configureDatabase(MockServices.makeTestDataSourceProperties(), MockServices.makeTestDatabaseProperties(), ::makeTestIdentityService) } @After diff --git a/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt b/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt index 877037c387..9f7833f928 100644 --- a/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt +++ b/node/src/test/kotlin/net/corda/node/internal/cordapp/CordappProviderImplTests.kt @@ -1,5 +1,6 @@ package net.corda.node.internal.cordapp +import com.nhaarman.mockito_kotlin.mock import net.corda.core.node.services.AttachmentStorage import net.corda.testing.node.MockAttachmentStorage import org.junit.Assert @@ -22,9 +23,7 @@ class CordappProviderImplTests { @Test fun `isolated jar is loaded into the attachment store`() { val loader = CordappLoader.createDevMode(listOf(isolatedJAR)) - val provider = CordappProviderImpl(loader) - - provider.start(attachmentStore) + val provider = CordappProviderImpl(loader, attachmentStore) val maybeAttachmentId = provider.getCordappAttachmentId(provider.cordapps.first()) Assert.assertNotNull(maybeAttachmentId) @@ -34,17 +33,14 @@ class CordappProviderImplTests { @Test fun `empty jar is not loaded into the attachment store`() { val loader = CordappLoader.createDevMode(listOf(emptyJAR)) - val provider = CordappProviderImpl(loader) - - provider.start(attachmentStore) - + val provider = CordappProviderImpl(loader, attachmentStore) Assert.assertNull(provider.getCordappAttachmentId(provider.cordapps.first())) } @Test fun `test that we find a cordapp class that is loaded into the store`() { val loader = CordappLoader.createDevMode(listOf(isolatedJAR)) - val provider = CordappProviderImpl(loader) + val provider = CordappProviderImpl(loader, mock()) val className = "net.corda.finance.contracts.isolated.AnotherDummyContract" val expected = provider.cordapps.first() @@ -57,10 +53,8 @@ class CordappProviderImplTests { @Test fun `test that we find an attachment for a cordapp contrat class`() { val loader = CordappLoader.createDevMode(listOf(isolatedJAR)) - val provider = CordappProviderImpl(loader) + val provider = CordappProviderImpl(loader, attachmentStore) val className = "net.corda.finance.contracts.isolated.AnotherDummyContract" - - provider.start(attachmentStore) val expected = provider.getAppContext(provider.cordapps.first()).attachmentId val actual = provider.getContractAttachmentID(className) 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 d5c966d31c..d54bfa8754 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 @@ -78,7 +78,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { calls = 0 val dataSourceProps = makeTestDataSourceProperties() val databaseProperties = makeTestDatabaseProperties() - database = configureDatabase(dataSourceProps, databaseProperties, createIdentityService = ::makeTestIdentityService) + database = configureDatabase(dataSourceProps, databaseProperties, ::makeTestIdentityService) val identityService = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) val kms = MockKeyManagementService(identityService, ALICE_KEY) @@ -97,7 +97,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { network = mockMessagingService), TestReference { override val vaultService: VaultServiceInternal = NodeVaultService(testClock, kms, stateLoader, database.hibernateConfig) override val testReference = this@NodeSchedulerServiceTest - override val cordappProvider = CordappProviderImpl(CordappLoader.createWithTestPackages(listOf("net.corda.testing.contracts"))).start(attachments) + override val cordappProvider = CordappProviderImpl(CordappLoader.createWithTestPackages(listOf("net.corda.testing.contracts")), attachments) } smmExecutor = AffinityExecutor.ServiceAffinityExecutor("test", 1) scheduler = NodeSchedulerService(services, schedulerGatedExecutor, serverThread = smmExecutor) diff --git a/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt b/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt index 6a1adee86a..418322b589 100644 --- a/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/messaging/ArtemisMessagingTests.kt @@ -71,7 +71,7 @@ class ArtemisMessagingTests : TestDependencyInjectionBase() { baseDirectory = baseDirectory, myLegalName = ALICE.name) LogHelper.setLevel(PersistentUniquenessProvider::class) - database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) + database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService) networkMapRegistrationFuture = doneFuture(Unit) networkMapCache = PersistentNetworkMapCache(serviceHub = object : MockServiceHubInternal(database, config) {}) } diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt index aaa8e49db1..f71f266388 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBCheckpointStorageTests.kt @@ -33,7 +33,7 @@ class DBCheckpointStorageTests : TestDependencyInjectionBase() { @Before fun setUp() { LogHelper.setLevel(PersistentUniquenessProvider::class) - database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) + database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService) newCheckpointStorage() } diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt index 3a3148c0db..2b9ff96f1c 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt @@ -38,7 +38,7 @@ class DBTransactionStorageTests : TestDependencyInjectionBase() { fun setUp() { LogHelper.setLevel(PersistentUniquenessProvider::class) val dataSourceProps = makeTestDataSourceProperties() - database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), NodeSchemaService(), ::makeTestIdentityService) + database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), ::makeTestIdentityService) database.transaction { services = object : MockServices(BOB_KEY) { diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt index f0a381c411..0e1cdc1047 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt @@ -9,6 +9,7 @@ import net.corda.core.utilities.toBase58String import net.corda.core.node.services.Vault import net.corda.core.node.services.VaultService import net.corda.core.schemas.CommonSchemaV1 +import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.PersistentStateRef import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.deserialize @@ -25,7 +26,6 @@ import net.corda.finance.schemas.SampleCashSchemaV2 import net.corda.finance.schemas.SampleCashSchemaV3 import net.corda.finance.utils.sumCash import net.corda.node.services.schema.HibernateObserver -import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.vault.VaultSchemaV1 import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.configureDatabase @@ -77,7 +77,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() { issuerServices = MockServices(cordappPackages, DUMMY_CASH_ISSUER_KEY, BOB_KEY, BOC_KEY) val dataSourceProps = makeTestDataSourceProperties() val defaultDatabaseProperties = makeTestDatabaseProperties() - database = configureDatabase(dataSourceProps, defaultDatabaseProperties, NodeSchemaService(), ::makeTestIdentityService) + database = configureDatabase(dataSourceProps, defaultDatabaseProperties, ::makeTestIdentityService) database.transaction { hibernateConfig = database.hibernateConfig services = object : MockServices(cordappPackages, BOB_KEY, BOC_KEY, DUMMY_NOTARY_KEY) { @@ -95,13 +95,13 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() { hibernatePersister = services.hibernatePersister } setUpDb() - - val customSchemas = setOf(VaultSchemaV1, CashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3) - sessionFactory = hibernateConfig.sessionFactoryForSchemas(*customSchemas.toTypedArray()) + sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, CashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3) entityManager = sessionFactory.createEntityManager() criteriaBuilder = sessionFactory.criteriaBuilder } + private fun sessionFactoryForSchemas(vararg schemas: MappedSchema) = hibernateConfig.sessionFactoryForSchemas(schemas.toSet()) + @After fun cleanUp() { database.close() @@ -536,8 +536,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() { services.fillWithSomeTestDeals(listOf("123", "456", "789")) services.fillWithSomeTestLinearStates(2) } - - val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1) + val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1) val criteriaBuilder = sessionFactory.criteriaBuilder val entityManager = sessionFactory.createEntityManager() @@ -568,8 +567,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() { services.fillWithSomeTestDeals(listOf("123", "456", "789")) services.fillWithSomeTestLinearStates(2) } - - val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2) + val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2) val criteriaBuilder = sessionFactory.criteriaBuilder val entityManager = sessionFactory.createEntityManager() @@ -635,8 +633,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() { hibernatePersister.persistStateWithSchema(dummyFungibleState, it.ref, SampleCashSchemaV3) } } - - val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, CommonSchemaV1, SampleCashSchemaV3) + val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, CommonSchemaV1, SampleCashSchemaV3) val criteriaBuilder = sessionFactory.criteriaBuilder val entityManager = sessionFactory.createEntityManager() @@ -764,8 +761,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() { services.fillWithSomeTestLinearStates(2, externalId = "222") services.fillWithSomeTestLinearStates(3, externalId = "333") } - - val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2) + val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2) val criteriaBuilder = sessionFactory.criteriaBuilder val entityManager = sessionFactory.createEntityManager() @@ -817,8 +813,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() { services.fillWithSomeTestLinearStates(2, externalId = "222") services.fillWithSomeTestLinearStates(3, externalId = "333") } - - val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1) + val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1) val criteriaBuilder = sessionFactory.criteriaBuilder val entityManager = sessionFactory.createEntityManager() diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentStorageTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentStorageTest.kt index d3ee944069..a8a352cbf1 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentStorageTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentStorageTest.kt @@ -40,7 +40,7 @@ class NodeAttachmentStorageTest { LogHelper.setLevel(PersistentUniquenessProvider::class) val dataSourceProperties = makeTestDataSourceProperties() - database = configureDatabase(dataSourceProperties, makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) + database = configureDatabase(dataSourceProperties, makeTestDatabaseProperties(), ::makeTestIdentityService) fs = Jimfs.newFileSystem(Configuration.unix()) } diff --git a/node/src/test/kotlin/net/corda/node/services/schema/HibernateObserverTests.kt b/node/src/test/kotlin/net/corda/node/services/schema/HibernateObserverTests.kt index 44fc3cb47b..33e8bcdad4 100644 --- a/node/src/test/kotlin/net/corda/node/services/schema/HibernateObserverTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/schema/HibernateObserverTests.kt @@ -57,8 +57,6 @@ class HibernateObserverTests { val testSchema = TestSchema val rawUpdatesPublisher = PublishSubject.create>() val schemaService = object : SchemaService { - override fun registerCustomSchemas(customSchemas: Set) {} - override val schemaOptions: Map = emptyMap() override fun selectSchemas(state: ContractState): Iterable = setOf(testSchema) @@ -70,7 +68,7 @@ class HibernateObserverTests { return parent } } - val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), schemaService, createIdentityService = ::makeTestIdentityService) + val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService, schemaService) @Suppress("UNUSED_VARIABLE") val observer = HibernateObserver(rawUpdatesPublisher, database.hibernateConfig) database.transaction { diff --git a/node/src/test/kotlin/net/corda/node/services/schema/NodeSchemaServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/schema/NodeSchemaServiceTest.kt index 73bb252af5..be168e8b98 100644 --- a/node/src/test/kotlin/net/corda/node/services/schema/NodeSchemaServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/schema/NodeSchemaServiceTest.kt @@ -3,11 +3,13 @@ package net.corda.node.services.schema import co.paralleluniverse.fibers.Suspendable import net.corda.core.flows.FlowLogic import net.corda.core.flows.StartableByRPC +import net.corda.core.internal.packageName import net.corda.core.messaging.startFlow import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.PersistentState import net.corda.core.utilities.getOrThrow import net.corda.node.services.api.ServiceHubInternal +import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.driver import net.corda.testing.node.MockNetwork import net.corda.testing.schemas.DummyLinearStateSchemaV1 @@ -15,6 +17,7 @@ import org.hibernate.annotations.Cascade import org.hibernate.annotations.CascadeType import org.junit.Test import javax.persistence.* +import kotlin.test.assertEquals import kotlin.test.assertTrue class NodeSchemaServiceTest { @@ -23,11 +26,9 @@ class NodeSchemaServiceTest { */ @Test fun `registering custom schemas for testing with MockNode`() { - val mockNet = MockNetwork() + val mockNet = MockNetwork(cordappPackages = listOf(DummyLinearStateSchemaV1::class.packageName)) val mockNode = mockNet.createNode() mockNet.runNetwork() - - mockNode.internals.registerCustomSchemas(setOf(DummyLinearStateSchemaV1)) val schemaService = mockNode.services.schemaService assertTrue(schemaService.schemaOptions.containsKey(DummyLinearStateSchemaV1)) @@ -50,6 +51,16 @@ class NodeSchemaServiceTest { } } + @Test + fun `custom schemas are loaded eagerly`() { + val expected = setOf("PARENTS", "CHILDREN") + assertEquals>(expected, driver { + (startNode(startInSameProcess = true).getOrThrow() as NodeHandle.InProcess).node.database.transaction { + session.createNativeQuery("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES").list() + } + }.toMutableSet().apply { retainAll(expected) }) + } + @StartableByRPC class MappedSchemasFlow : FlowLogic>() { @Suspendable diff --git a/node/src/test/kotlin/net/corda/node/services/transactions/DistributedImmutableMapTests.kt b/node/src/test/kotlin/net/corda/node/services/transactions/DistributedImmutableMapTests.kt index bd4c3358f3..ce79064a79 100644 --- a/node/src/test/kotlin/net/corda/node/services/transactions/DistributedImmutableMapTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/transactions/DistributedImmutableMapTests.kt @@ -86,7 +86,7 @@ class DistributedImmutableMapTests : TestDependencyInjectionBase() { private fun createReplica(myAddress: NetworkHostAndPort, clusterAddress: NetworkHostAndPort? = null): CompletableFuture { val storage = Storage.builder().withStorageLevel(StorageLevel.MEMORY).build() val address = Address(myAddress.host, myAddress.port) - val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties("serverNameTablePrefix", "PORT_${myAddress.port}_"), createIdentityService = ::makeTestIdentityService) + val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties("serverNameTablePrefix", "PORT_${myAddress.port}_"), ::makeTestIdentityService) databases.add(database) val stateMachineFactory = { DistributedImmutableMap(database, RaftUniquenessProvider.Companion::createMap) } diff --git a/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt b/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt index 491931ab2a..088a14e18f 100644 --- a/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/transactions/PersistentUniquenessProviderTests.kt @@ -23,7 +23,7 @@ class PersistentUniquenessProviderTests : TestDependencyInjectionBase() { @Before fun setUp() { LogHelper.setLevel(PersistentUniquenessProvider::class) - database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) + database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService) } @After diff --git a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt index 4740ac776d..46802e8a7f 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/NodeVaultServiceTest.kt @@ -9,6 +9,7 @@ import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party +import net.corda.core.internal.packageName import net.corda.core.node.services.* import net.corda.core.node.services.vault.QueryCriteria import net.corda.core.node.services.vault.QueryCriteria.* @@ -46,7 +47,7 @@ import kotlin.test.assertTrue class NodeVaultServiceTest : TestDependencyInjectionBase() { companion object { - private val cordappPackages = listOf("net.corda.finance.contracts.asset") + private val cordappPackages = listOf("net.corda.finance.contracts.asset", CashSchemaV1::class.packageName) } lateinit var services: MockServices @@ -58,7 +59,6 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() { fun setUp() { LogHelper.setLevel(NodeVaultService::class) val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(BOC_KEY, DUMMY_CASH_ISSUER_KEY), - customSchemas = setOf(CashSchemaV1), cordappPackages = cordappPackages) database = databaseAndServices.first services = databaseAndServices.second diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt index 56d6e90992..8d34babb97 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt @@ -6,6 +6,7 @@ import net.corda.core.crypto.entropyToKeyPair import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate +import net.corda.core.internal.packageName import net.corda.core.node.services.* import net.corda.core.node.services.vault.* import net.corda.core.node.services.vault.QueryCriteria.* @@ -45,10 +46,9 @@ import java.time.temporal.ChronoUnit import java.util.* class VaultQueryTests : TestDependencyInjectionBase() { - companion object { - private val cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts") - } - + private val cordappPackages = setOf( + "net.corda.testing.contracts", "net.corda.finance.contracts", + CashSchemaV1::class.packageName, CommercialPaperSchemaV1::class.packageName, DummyLinearStateSchemaV1::class.packageName).toMutableList() private lateinit var services: MockServices private lateinit var notaryServices: MockServices private val vaultService: VaultService get() = services.vaultService @@ -67,7 +67,6 @@ class VaultQueryTests : TestDependencyInjectionBase() { identitySvc.verifyAndRegisterIdentity(BOC_IDENTITY) val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(MEGA_CORP_KEY, DUMMY_NOTARY_KEY), createIdentityService = { identitySvc }, - customSchemas = setOf(CashSchemaV1, CommercialPaperSchemaV1, DummyLinearStateSchemaV1), cordappPackages = cordappPackages) database = databaseAndServices.first services = databaseAndServices.second @@ -85,8 +84,7 @@ class VaultQueryTests : TestDependencyInjectionBase() { @Ignore @Test fun createPersistentTestDb() { - val database = configureDatabase(makePersistentDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = { identitySvc }) - + val database = configureDatabase(makePersistentDataSourceProperties(), makeTestDatabaseProperties(), { identitySvc }) setUpDb(database, 5000) database.close() @@ -1753,6 +1751,9 @@ class VaultQueryTests : TestDependencyInjectionBase() { @Test fun `query attempting to use unregistered schema`() { + tearDown() + cordappPackages -= SampleCashSchemaV3::class.packageName + setUp() database.transaction { services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt index a42e13d55c..feb6530062 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultWithCashTest.kt @@ -4,6 +4,7 @@ import net.corda.core.contracts.ContractState import net.corda.core.contracts.LinearState import net.corda.core.contracts.UniqueIdentifier import net.corda.core.identity.AnonymousParty +import net.corda.core.internal.packageName import net.corda.core.node.services.Vault import net.corda.core.node.services.VaultService import net.corda.core.node.services.queryBy @@ -35,7 +36,7 @@ import kotlin.test.assertEquals class VaultWithCashTest : TestDependencyInjectionBase() { companion object { - private val cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts.asset") + private val cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1::class.packageName) } lateinit var services: MockServices @@ -48,7 +49,6 @@ class VaultWithCashTest : TestDependencyInjectionBase() { fun setUp() { LogHelper.setLevel(VaultWithCashTest::class) val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(DUMMY_CASH_ISSUER_KEY, DUMMY_NOTARY_KEY), - customSchemas = setOf(CashSchemaV1), cordappPackages = cordappPackages) database = databaseAndServices.first services = databaseAndServices.second diff --git a/node/src/test/kotlin/net/corda/node/utilities/ObservablesTests.kt b/node/src/test/kotlin/net/corda/node/utilities/ObservablesTests.kt index ffac359f49..e7b9ca1623 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/ObservablesTests.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/ObservablesTests.kt @@ -21,7 +21,7 @@ class ObservablesTests { val toBeClosed = mutableListOf() fun createDatabase(): CordaPersistence { - val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) + val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService) toBeClosed += database return database } diff --git a/samples/irs-demo/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt b/samples/irs-demo/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt index 4e9d129c26..d43192cdf8 100644 --- a/samples/irs-demo/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt +++ b/samples/irs-demo/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt @@ -62,7 +62,7 @@ class NodeInterestRatesTest : TestDependencyInjectionBase() { @Before fun setUp() { - database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) + database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService) database.transaction { oracle = createMockCordaService(services, NodeInterestRates::Oracle) oracle.knownFixes = TEST_DATA diff --git a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt index 90a3ca2d8b..b9abcd6538 100644 --- a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt +++ b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt @@ -12,7 +12,6 @@ import net.corda.node.internal.StartedNode import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.statemachine.StateMachineManager import net.corda.nodeapi.internal.ServiceInfo -import net.corda.nodeapi.internal.ServiceType import net.corda.testing.* import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.MockNetwork @@ -270,9 +269,3 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, mockNet.stopNodes() } } - -/** - * Helper function for verifying that a service info contains the given type of advertised service. For non-simulation cases - * this is a configuration matter rather than implementation. - */ -fun Iterable.containsType(type: ServiceType) = any { it.type == type } \ No newline at end of file diff --git a/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt b/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt index 6fb3556c25..61580c8632 100644 --- a/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt +++ b/samples/trader-demo/src/integration-test/kotlin/net/corda/traderdemo/TraderDemoTest.kt @@ -1,6 +1,7 @@ package net.corda.traderdemo import net.corda.client.rpc.CordaRPCClient +import net.corda.core.internal.packageName import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.millis import net.corda.finance.DOLLARS @@ -20,7 +21,9 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.Test import java.util.concurrent.Executors -class TraderDemoTest : NodeBasedTest(listOf("net.corda.finance.contracts.asset", "net.corda.finance.contracts")) { +class TraderDemoTest : NodeBasedTest(listOf( + "net.corda.finance.contracts.asset", "net.corda.finance.contracts", + CashSchemaV1::class.packageName, CommercialPaperSchemaV1::class.packageName)) { @Test fun `runs trader demo`() { val demoUser = User("demo", "demo", setOf(startFlowPermission())) @@ -35,9 +38,6 @@ class TraderDemoTest : NodeBasedTest(listOf("net.corda.finance.contracts.asset", val (nodeA, nodeB, bankNode) = listOf(nodeAFuture, nodeBFuture, bankNodeFuture, notaryFuture).map { it.getOrThrow() } nodeA.internals.registerInitiatedFlow(BuyerFlow::class.java) - nodeA.internals.registerCustomSchemas(setOf(CashSchemaV1)) - nodeB.internals.registerCustomSchemas(setOf(CashSchemaV1, CommercialPaperSchemaV1)) - val (nodeARpc, nodeBRpc) = listOf(nodeA, nodeB).map { val client = CordaRPCClient(it.internals.configuration.rpcAddress!!) client.start(demoUser.username, demoUser.password).proxy diff --git a/testing/node-driver/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt b/testing/node-driver/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt index c4ca2077cf..1188e1571e 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt @@ -1,7 +1,6 @@ package net.corda.node.testing import com.codahale.metrics.MetricRegistry -import net.corda.core.cordapp.CordappProvider import net.corda.core.flows.FlowInitiator import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party @@ -13,11 +12,11 @@ import net.corda.node.internal.InitiatedFlowFactory import net.corda.node.internal.StateLoaderImpl import net.corda.node.internal.cordapp.CordappLoader import net.corda.node.internal.cordapp.CordappProviderImpl +import net.corda.node.internal.cordapp.CordappProviderInternal import net.corda.node.serialization.NodeClock import net.corda.node.services.api.* import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.messaging.MessagingService -import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.statemachine.FlowStateMachineImpl import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.services.transactions.InMemoryTransactionVerifierService @@ -46,10 +45,9 @@ open class MockServiceHubInternal( val mapCache: NetworkMapCacheInternal? = null, val scheduler: SchedulerService? = null, val overrideClock: Clock? = NodeClock(), - val schemas: SchemaService? = NodeSchemaService(), val customContractUpgradeService: ContractUpgradeService? = null, val customTransactionVerifierService: TransactionVerifierService? = InMemoryTransactionVerifierService(2), - override val cordappProvider: CordappProvider = CordappProviderImpl(CordappLoader.createDefault(Paths.get("."))).start(attachments), + override val cordappProvider: CordappProviderInternal = CordappProviderImpl(CordappLoader.createDefault(Paths.get(".")), attachments), protected val stateLoader: StateLoaderImpl = StateLoaderImpl(validatedTransactions) ) : ServiceHubInternal, StateLoader by stateLoader { override val transactionVerifierService: TransactionVerifierService @@ -75,8 +73,7 @@ open class MockServiceHubInternal( override val monitoringService: MonitoringService = MonitoringService(MetricRegistry()) override val rpcFlows: List>> get() = throw UnsupportedOperationException() - override val schemaService: SchemaService - get() = schemas ?: throw UnsupportedOperationException() + override val schemaService get() = throw UnsupportedOperationException() override val auditService: AuditService = DummyAuditService() lateinit var smm: StateMachineManager diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt index 47fd8589a3..fcd5689800 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -14,7 +14,6 @@ import net.corda.core.node.NodeInfo import net.corda.core.node.ServiceHub import net.corda.core.node.StateLoader import net.corda.core.node.services.* -import net.corda.core.schemas.MappedSchema import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.SignedTransaction @@ -51,7 +50,7 @@ import java.util.* * building chains of transactions and verifying them. It isn't sufficient for testing flows however. */ open class MockServices( - cordappPackages: List, + cordappLoader: CordappLoader, override val validatedTransactions: WritableTransactionStorage, protected val stateLoader: StateLoaderImpl = StateLoaderImpl(validatedTransactions), vararg val keys: KeyPair @@ -101,24 +100,22 @@ open class MockServices( /** * Makes database and mock services appropriate for unit tests. - * - * @param customSchemas a set of schemas being used by [NodeSchemaService] - * @param keys a lis of [KeyPair] instances to be used by [MockServices]. Defualts to [MEGA_CORP_KEY] + * @param keys a list of [KeyPair] instances to be used by [MockServices]. Defualts to [MEGA_CORP_KEY] * @param createIdentityService a lambda function returning an instance of [IdentityService]. Defauts to [InMemoryIdentityService]. * * @return a pair where the first element is the instance of [CordaPersistence] and the second is [MockServices]. */ @JvmStatic - fun makeTestDatabaseAndMockServices(customSchemas: Set = emptySet(), - keys: List = listOf(MEGA_CORP_KEY), + fun makeTestDatabaseAndMockServices(keys: List = listOf(MEGA_CORP_KEY), createIdentityService: () -> IdentityService = { makeTestIdentityService() }, cordappPackages: List = emptyList()): Pair { + val cordappLoader = CordappLoader.createWithTestPackages(cordappPackages) val dataSourceProps = makeTestDataSourceProperties() val databaseProperties = makeTestDatabaseProperties() val identityServiceRef: IdentityService by lazy { createIdentityService() } - val database = configureDatabase(dataSourceProps, databaseProperties, NodeSchemaService(customSchemas), { identityServiceRef }) + val database = configureDatabase(dataSourceProps, databaseProperties, { identityServiceRef }, NodeSchemaService(cordappLoader)) val mockService = database.transaction { - object : MockServices(cordappPackages, *(keys.toTypedArray())) { + object : MockServices(cordappLoader, *(keys.toTypedArray())) { override val identityService: IdentityService = database.transaction { identityServiceRef } override val vaultService = makeVaultService(database.hibernateConfig) @@ -137,7 +134,8 @@ open class MockServices( } } - constructor(cordappPackages: List, vararg keys: KeyPair) : this(cordappPackages, MockTransactionStorage(), keys = *keys) + private constructor(cordappLoader: CordappLoader, vararg keys: KeyPair) : this(cordappLoader, MockTransactionStorage(), keys = *keys) + constructor(cordappPackages: List, vararg keys: KeyPair) : this(CordappLoader.createWithTestPackages(cordappPackages), keys = *keys) constructor(vararg keys: KeyPair) : this(emptyList(), *keys) constructor() : this(generateKeyPair()) @@ -167,11 +165,11 @@ open class MockServices( return NodeInfo(emptyList(), listOf(identity), 1, serial = 1L) } override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2) - val mockCordappProvider = MockCordappProvider(CordappLoader.createWithTestPackages(cordappPackages)).start(attachments) as MockCordappProvider + val mockCordappProvider = MockCordappProvider(cordappLoader, attachments) override val cordappProvider: CordappProvider get() = mockCordappProvider lateinit var hibernatePersister: HibernateObserver - fun makeVaultService(hibernateConfig: HibernateConfiguration = HibernateConfiguration(NodeSchemaService(), makeTestDatabaseProperties(), { identityService })): VaultServiceInternal { + fun makeVaultService(hibernateConfig: HibernateConfiguration): VaultServiceInternal { val vaultService = NodeVaultService(Clock.systemUTC(), keyManagementService, stateLoader, hibernateConfig) hibernatePersister = HibernateObserver(vaultService.rawUpdates, hibernateConfig) return vaultService diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/SimpleNode.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/SimpleNode.kt index cfb1e3a29d..3b7bf9130e 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/SimpleNode.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/SimpleNode.kt @@ -37,7 +37,7 @@ class SimpleNode(val config: NodeConfiguration, val address: NetworkHostAndPort val monitoringService = MonitoringService(MetricRegistry()) val identity: KeyPair = generateKeyPair() val identityService: IdentityService = InMemoryIdentityService(trustRoot = trustRoot) - val database: CordaPersistence = configureDatabase(config.dataSourceProperties, config.database, NodeSchemaService(), { InMemoryIdentityService(trustRoot = trustRoot) }) + val database: CordaPersistence = configureDatabase(config.dataSourceProperties, config.database, { InMemoryIdentityService(trustRoot = trustRoot) }) val keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity)) val executor = ServiceAffinityExecutor(config.myLegalName.organisation, 1) // TODO: We should have a dummy service hub rather than change behaviour in tests diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/LogHelper.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/LogHelper.kt index ad2e488e91..1fab8508fc 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/LogHelper.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/LogHelper.kt @@ -1,5 +1,6 @@ package net.corda.testing +import net.corda.core.internal.packageName import org.apache.logging.log4j.Level import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.core.LoggerContext @@ -25,7 +26,7 @@ object LogHelper { } } - fun setLevel(vararg classes: KClass<*>) = setLevel(*classes.map { "+" + it.java.`package`.name }.toTypedArray()) + fun setLevel(vararg classes: KClass<*>) = setLevel(*classes.map { "+" + it.packageName }.toTypedArray()) /** Removes custom configuration for the specified logger names */ fun reset(vararg names: String) { @@ -35,7 +36,7 @@ object LogHelper { loggerContext.updateLoggers(config) } - fun reset(vararg classes: KClass<*>) = reset(*classes.map { it.java.`package`.name }.toTypedArray()) + fun reset(vararg classes: KClass<*>) = reset(*classes.map { it.packageName }.toTypedArray()) /** Updates logging level for the specified Log4j logger name */ private fun setLevel(name: String, level: Level) { diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/node/MockCordappProvider.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/node/MockCordappProvider.kt index dae72192a6..5c8736335e 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/node/MockCordappProvider.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/node/MockCordappProvider.kt @@ -4,12 +4,13 @@ import net.corda.core.contracts.ContractClassName import net.corda.core.cordapp.Cordapp import net.corda.core.internal.cordapp.CordappImpl import net.corda.core.node.services.AttachmentId +import net.corda.core.node.services.AttachmentStorage import net.corda.node.internal.cordapp.CordappLoader import net.corda.node.internal.cordapp.CordappProviderImpl import java.nio.file.Paths import java.util.* -class MockCordappProvider(cordappLoader: CordappLoader) : CordappProviderImpl(cordappLoader) { +class MockCordappProvider(cordappLoader: CordappLoader, attachmentStorage: AttachmentStorage) : CordappProviderImpl(cordappLoader, attachmentStorage) { val cordappRegistry = mutableListOf>() fun addMockCordapp(contractClassName: ContractClassName, attachments: MockAttachmentStorage) {