CORDA-676 Eager cordapp schemas (#1839)

* Retire customSchemas.
* Key cordapp-to-hash map by url as native equality too strict.
This commit is contained in:
Andrzej Cichocki 2017-10-16 11:35:29 +01:00 committed by GitHub
parent d3d87c2497
commit 38cf4a489e
46 changed files with 197 additions and 236 deletions

View File

@ -32,7 +32,7 @@ import static net.corda.testing.TestConstants.getALICE;
public class CordaRPCJavaClientTest extends NodeBasedTest { public class CordaRPCJavaClientTest extends NodeBasedTest {
public CordaRPCJavaClientTest() { public CordaRPCJavaClientTest() {
super(Collections.singletonList("net.corda.finance.contracts")); super(Arrays.asList("net.corda.finance.contracts", CashSchemaV1.class.getPackage().getName()));
} }
private List<String> perms = Arrays.asList(startFlowPermission(CashPaymentFlow.class), startFlowPermission(CashIssueFlow.class)); private List<String> perms = Arrays.asList(startFlowPermission(CashPaymentFlow.class), startFlowPermission(CashIssueFlow.class));
@ -53,7 +53,6 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
public void setUp() throws ExecutionException, InterruptedException { public void setUp() throws ExecutionException, InterruptedException {
CordaFuture<StartedNode<Node>> nodeFuture = startNotaryNode(getALICE().getName(), singletonList(rpcUser), true); CordaFuture<StartedNode<Node>> nodeFuture = startNotaryNode(getALICE().getName(), singletonList(rpcUser), true);
node = nodeFuture.get(); node = nodeFuture.get();
node.getInternals().registerCustomSchemas(Collections.singleton(CashSchemaV1.INSTANCE));
client = new CordaRPCClient(requireNonNull(node.getInternals().getConfiguration().getRpcAddress())); client = new CordaRPCClient(requireNonNull(node.getInternals().getConfiguration().getRpcAddress()));
} }

View File

@ -2,6 +2,7 @@ package net.corda.client.rpc
import net.corda.core.crypto.random63BitValue import net.corda.core.crypto.random63BitValue
import net.corda.core.flows.FlowInitiator import net.corda.core.flows.FlowInitiator
import net.corda.core.internal.packageName
import net.corda.core.messaging.FlowProgressHandle import net.corda.core.messaging.FlowProgressHandle
import net.corda.core.messaging.StateMachineUpdate import net.corda.core.messaging.StateMachineUpdate
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
@ -32,7 +33,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertTrue 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( private val rpcUser = User("user1", "test", permissions = setOf(
startFlowPermission<CashIssueFlow>(), startFlowPermission<CashIssueFlow>(),
startFlowPermission<CashPaymentFlow>() startFlowPermission<CashPaymentFlow>()
@ -48,7 +49,6 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts"))
@Before @Before
fun setUp() { fun setUp() {
node = startNotaryNode(ALICE.name, rpcUsers = listOf(rpcUser)).getOrThrow() node = startNotaryNode(ALICE.name, rpcUsers = listOf(rpcUser)).getOrThrow()
node.internals.registerCustomSchemas(setOf(CashSchemaV1))
client = CordaRPCClient(node.internals.configuration.rpcAddress!!) client = CordaRPCClient(node.internals.configuration.rpcAddress!!)
} }

View File

@ -300,3 +300,6 @@ fun TransactionBuilder.toWireTransaction(services: ServicesForResolution, serial
* @suppress * @suppress
*/ */
fun TransactionBuilder.toLedgerTransaction(services: ServiceHub, serializationContext: SerializationContext) = toLedgerTransactionWithContext(services, serializationContext) 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

View File

@ -61,6 +61,7 @@ class InternalUtilsTest {
assertArrayEquals(intArrayOf(1, 2, 3, 4), (1 until 5).stream().toArray()) 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..4 step 2).stream().toArray())
assertArrayEquals(intArrayOf(1, 3), (1..3 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).stream().toArray())
assertArrayEquals(intArrayOf(1, 0), (1 downTo 0).stream().toArray()) assertArrayEquals(intArrayOf(1, 0), (1 downTo 0).stream().toArray())
assertArrayEquals(intArrayOf(3, 1), (3 downTo 0 step 2).stream().toArray()) assertArrayEquals(intArrayOf(3, 1), (3 downTo 0 step 2).stream().toArray())

View File

@ -2,6 +2,7 @@ package net.corda.docs
import net.corda.core.contracts.Amount import net.corda.core.contracts.Amount
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.packageName
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.finance.* import net.corda.finance.*
@ -26,15 +27,12 @@ class CustomVaultQueryTest {
@Before @Before
fun setup() { 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) mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
nodeA = mockNet.createPartyNode() nodeA = mockNet.createPartyNode()
nodeB = mockNet.createPartyNode() nodeB = mockNet.createPartyNode()
nodeA.internals.registerInitiatedFlow(TopupIssuerFlow.TopupIssuer::class.java) nodeA.internals.registerInitiatedFlow(TopupIssuerFlow.TopupIssuer::class.java)
nodeA.internals.installCordaService(CustomVaultQuery.Service::class.java) nodeA.internals.installCordaService(CustomVaultQuery.Service::class.java)
nodeA.internals.registerCustomSchemas(setOf(CashSchemaV1))
nodeB.internals.registerCustomSchemas(setOf(CashSchemaV1))
notary = nodeA.services.getDefaultNotary() notary = nodeA.services.getDefaultNotary()
} }

View File

@ -1,6 +1,7 @@
package net.corda.docs package net.corda.docs
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.packageName
import net.corda.core.toFuture import net.corda.core.toFuture
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
@ -24,12 +25,10 @@ class FxTransactionBuildTutorialTest {
@Before @Before
fun setup() { 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) mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
nodeA = mockNet.createPartyNode() nodeA = mockNet.createPartyNode()
nodeB = mockNet.createPartyNode() nodeB = mockNet.createPartyNode()
nodeA.internals.registerCustomSchemas(setOf(CashSchemaV1))
nodeB.internals.registerCustomSchemas(setOf(CashSchemaV1))
nodeB.internals.registerInitiatedFlow(ForeignExchangeRemoteFlow::class.java) nodeB.internals.registerInitiatedFlow(ForeignExchangeRemoteFlow::class.java)
notary = nodeA.services.getDefaultNotary() notary = nodeA.services.getDefaultNotary()
} }

View File

@ -55,8 +55,7 @@ class AttachmentsClassLoaderTests : TestDependencyInjectionBase() {
class DummyServiceHub : MockServices() { class DummyServiceHub : MockServices() {
override val cordappProvider: CordappProviderImpl 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() private val cordapp get() = cordappProvider.cordapps.first()
val attachmentId get() = cordappProvider.getCordappAttachmentId(cordapp)!! val attachmentId get() = cordappProvider.getCordappAttachmentId(cordapp)!!
val appContext get() = cordappProvider.getAppContext(cordapp) val appContext get() = cordappProvider.getAppContext(cordapp)

View File

@ -37,7 +37,7 @@ import kotlin.test.assertFailsWith
class AttachmentLoadingTests : TestDependencyInjectionBase() { class AttachmentLoadingTests : TestDependencyInjectionBase() {
private class Services : MockServices() { 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() private val cordapp get() = provider.cordapps.first()
val attachmentId get() = provider.getCordappAttachmentId(cordapp)!! val attachmentId get() = provider.getCordappAttachmentId(cordapp)!!
val appContext get() = provider.getAppContext(cordapp) val appContext get() = provider.getAppContext(cordapp)

View File

@ -7,7 +7,6 @@ import net.corda.confidential.SwapIdentitiesFlow
import net.corda.confidential.SwapIdentitiesHandler import net.corda.confidential.SwapIdentitiesHandler
import net.corda.core.CordaException import net.corda.core.CordaException
import net.corda.core.concurrent.CordaFuture import net.corda.core.concurrent.CordaFuture
import net.corda.core.cordapp.CordappProvider
import net.corda.core.flows.* import net.corda.core.flows.*
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party 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.StateLoader
import net.corda.core.node.services.* import net.corda.core.node.services.*
import net.corda.core.node.services.NetworkMapCache.MapChange 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.SerializationWhitelist
import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsToken
import net.corda.core.serialization.SingletonSerializeAsToken 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.classloading.requireAnnotation
import net.corda.node.internal.cordapp.CordappLoader import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.internal.cordapp.CordappProviderImpl 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.ContractUpgradeHandler
import net.corda.node.services.FinalityHandler import net.corda.node.services.FinalityHandler
import net.corda.node.services.NotaryChangeHandler import net.corda.node.services.NotaryChangeHandler
@ -148,7 +147,6 @@ abstract class AbstractNode(config: NodeConfiguration,
protected lateinit var network: MessagingService protected lateinit var network: MessagingService
protected val runOnStop = ArrayList<() -> Any?>() protected val runOnStop = ArrayList<() -> Any?>()
protected lateinit var database: CordaPersistence protected lateinit var database: CordaPersistence
lateinit var cordappProvider: CordappProviderImpl
protected val _nodeReadyFuture = openFuture<Unit>() protected val _nodeReadyFuture = openFuture<Unit>()
/** Completes once the node has successfully registered with the network map service /** Completes once the node has successfully registered with the network map service
* or has loaded network map data from local database */ * or has loaded network map data from local database */
@ -161,7 +159,7 @@ abstract class AbstractNode(config: NodeConfiguration,
} }
open val serializationWhitelists: List<SerializationWhitelist> by lazy { open val serializationWhitelists: List<SerializationWhitelist> by lazy {
cordappProvider.cordapps.flatMap { it.serializationWhitelists } cordappLoader.cordapps.flatMap { it.serializationWhitelists }
} }
/** Set to non-null once [start] has been successfully called. */ /** Set to non-null once [start] has been successfully called. */
@ -185,11 +183,12 @@ abstract class AbstractNode(config: NodeConfiguration,
validateKeystore() validateKeystore()
} }
private fun makeSchemaService() = NodeSchemaService(cordappLoader)
open fun generateNodeInfo() { open fun generateNodeInfo() {
check(started == null) { "Node has already been started" } check(started == null) { "Node has already been started" }
initCertificate() initCertificate()
log.info("Generating nodeInfo ...") log.info("Generating nodeInfo ...")
val schemaService = NodeSchemaService() val schemaService = makeSchemaService()
initialiseDatabasePersistence(schemaService) { initialiseDatabasePersistence(schemaService) {
makeServices(schemaService) makeServices(schemaService)
saveOwnNodeInfo() saveOwnNodeInfo()
@ -200,7 +199,7 @@ abstract class AbstractNode(config: NodeConfiguration,
check(started == null) { "Node has already been started" } check(started == null) { "Node has already been started" }
initCertificate() initCertificate()
log.info("Node starting up ...") 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. // Do all of this in a database transaction so anything that might need a connection has one.
val startedImpl = initialiseDatabasePersistence(schemaService) { val startedImpl = initialiseDatabasePersistence(schemaService) {
val tokenizableServices = makeServices(schemaService) val tokenizableServices = makeServices(schemaService)
@ -231,8 +230,7 @@ abstract class AbstractNode(config: NodeConfiguration,
installCordaServices() installCordaServices()
registerCordappFlows() registerCordappFlows()
_services.rpcFlows += cordappProvider.cordapps.flatMap { it.rpcFlows } _services.rpcFlows += cordappLoader.cordapps.flatMap { it.rpcFlows }
registerCustomSchemas(cordappProvider.cordapps.flatMap { it.customSchemas }.toSet())
FlowLogicRefFactoryImpl.classloader = cordappLoader.appClassLoader FlowLogicRefFactoryImpl.classloader = cordappLoader.appClassLoader
runOnStop += network::stop runOnStop += network::stop
@ -254,7 +252,7 @@ abstract class AbstractNode(config: NodeConfiguration,
private class ServiceInstantiationException(cause: Throwable?) : CordaException("Service Instantiation Error", cause) private class ServiceInstantiationException(cause: Throwable?) : CordaException("Service Instantiation Error", cause)
private fun installCordaServices() { private fun installCordaServices() {
val loadedServices = cordappProvider.cordapps.flatMap { it.services } val loadedServices = cordappLoader.cordapps.flatMap { it.services }
filterServicesToInstall(loadedServices).forEach { filterServicesToInstall(loadedServices).forEach {
try { try {
installCordaService(it) installCordaService(it)
@ -374,7 +372,7 @@ abstract class AbstractNode(config: NodeConfiguration,
} }
private fun registerCordappFlows() { private fun registerCordappFlows() {
cordappProvider.cordapps.flatMap { it.initiatedFlows } cordappLoader.cordapps.flatMap { it.initiatedFlows }
.forEach { .forEach {
try { try {
registerInitiatedFlowInternal(it, track = false) registerInitiatedFlowInternal(it, track = false)
@ -471,11 +469,11 @@ abstract class AbstractNode(config: NodeConfiguration,
*/ */
private fun makeServices(schemaService: SchemaService): MutableList<Any> { private fun makeServices(schemaService: SchemaService): MutableList<Any> {
checkpointStorage = DBCheckpointStorage() checkpointStorage = DBCheckpointStorage()
cordappProvider = CordappProviderImpl(cordappLoader)
val transactionStorage = makeTransactionStorage() val transactionStorage = makeTransactionStorage()
_services = ServiceHubInternalImpl(schemaService, transactionStorage, StateLoaderImpl(transactionStorage)) val metrics = MetricRegistry()
attachments = NodeAttachmentService(services.monitoringService.metrics) attachments = NodeAttachmentService(metrics)
cordappProvider.start(attachments) val cordappProvider = CordappProviderImpl(cordappLoader, attachments)
_services = ServiceHubInternalImpl(schemaService, transactionStorage, StateLoaderImpl(transactionStorage), MonitoringService(metrics), cordappProvider)
legalIdentity = obtainIdentity(notaryConfig = null) legalIdentity = obtainIdentity(notaryConfig = null)
network = makeMessagingService(legalIdentity) network = makeMessagingService(legalIdentity)
info = makeInfo(legalIdentity) info = makeInfo(legalIdentity)
@ -541,7 +539,7 @@ abstract class AbstractNode(config: NodeConfiguration,
protected open fun <T> initialiseDatabasePersistence(schemaService: SchemaService, insideTransaction: () -> T): T { protected open fun <T> initialiseDatabasePersistence(schemaService: SchemaService, insideTransaction: () -> T): T {
val props = configuration.dataSourceProperties val props = configuration.dataSourceProperties
if (props.isNotEmpty()) { 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. // Now log the vendor string as this will also cause a connection to be tested eagerly.
database.transaction { database.transaction {
log.info("Connected to ${database.dataSource.connection.metaData.databaseProductName} database.") log.info("Connected to ${database.dataSource.connection.metaData.databaseProductName} database.")
@ -764,12 +762,13 @@ abstract class AbstractNode(config: NodeConfiguration,
private inner class ServiceHubInternalImpl( private inner class ServiceHubInternalImpl(
override val schemaService: SchemaService, override val schemaService: SchemaService,
override val validatedTransactions: WritableTransactionStorage, 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 { ) : SingletonSerializeAsToken(), ServiceHubInternal, StateLoader by stateLoader {
override val rpcFlows = ArrayList<Class<out FlowLogic<*>>>() override val rpcFlows = ArrayList<Class<out FlowLogic<*>>>()
override val stateMachineRecordedTransactionMapping = DBTransactionMappingStorage() override val stateMachineRecordedTransactionMapping = DBTransactionMappingStorage()
override val auditService = DummyAuditService() override val auditService = DummyAuditService()
override val monitoringService = MonitoringService(MetricRegistry())
override val transactionVerifierService by lazy { makeTransactionVerifierService() } override val transactionVerifierService by lazy { makeTransactionVerifierService() }
override val networkMapCache by lazy { PersistentNetworkMapCache(this) } override val networkMapCache by lazy { PersistentNetworkMapCache(this) }
override val vaultService by lazy { NodeVaultService(platformClock, keyManagementService, stateLoader, this@AbstractNode.database.hibernateConfig) } 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 myInfo: NodeInfo get() = info
override val database: CordaPersistence get() = this@AbstractNode.database override val database: CordaPersistence get() = this@AbstractNode.database
override val configuration: NodeConfiguration get() = this@AbstractNode.configuration override val configuration: NodeConfiguration get() = this@AbstractNode.configuration
override val cordappProvider: CordappProvider = this@AbstractNode.cordappProvider
override fun <T : SerializeAsToken> cordaService(type: Class<T>): T { override fun <T : SerializeAsToken> cordaService(type: Class<T>): T {
require(type.isAnnotationPresent(CordaService::class.java)) { "${type.name} is not a Corda service" } 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") 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() override fun jdbcSession(): Connection = database.createSession()
} }
fun registerCustomSchemas(schemas: Set<MappedSchema>) {
database.hibernateConfig.schemaService.registerCustomSchemas(schemas)
}
} }

View File

@ -62,7 +62,7 @@ import kotlin.system.exitProcess
* *
* @param configuration This is typically loaded from a TypeSafe HOCON configuration file. * @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, versionInfo: VersionInfo,
val initialiseSerialization: Boolean = true, val initialiseSerialization: Boolean = true,
cordappLoader: CordappLoader = makeCordappLoader(configuration) cordappLoader: CordappLoader = makeCordappLoader(configuration)
@ -99,6 +99,7 @@ open class Node(override val configuration: FullNodeConfiguration,
} }
override val log: Logger get() = logger 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 val networkMapAddress: NetworkMapAddress? get() = configuration.networkMapService?.address?.let(::NetworkMapAddress)
override fun makeTransactionVerifierService() = (network as NodeMessagingClient).verifierService override fun makeTransactionVerifierService() = (network as NodeMessagingClient).verifierService

View File

@ -95,7 +95,7 @@ open class NodeStartup(val args: Array<String>) {
return return
} }
val startedNode = node.start() 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({ startedNode.internals.nodeReadyFuture.thenMatch({
val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0 val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0
val name = startedNode.info.legalIdentitiesAndCerts.first().name.organisation val name = startedNode.info.legalIdentitiesAndCerts.first().name.organisation

View File

@ -38,10 +38,10 @@ import kotlin.streams.toList
* *
* @property cordappJarPaths The classpath of cordapp JARs * @property cordappJarPaths The classpath of cordapp JARs
*/ */
class CordappLoader private constructor(private val cordappJarPaths: List<URL>) { class CordappLoader private constructor(private val cordappJarPaths: List<RestrictedURL>) {
val cordapps: List<Cordapp> by lazy { loadCordapps() + coreCordapp } val cordapps: List<Cordapp> 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 { init {
if (cordappJarPaths.isEmpty()) { if (cordappJarPaths.isEmpty()) {
@ -97,20 +97,22 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
* @param scanJars Uses the JAR URLs provided for classpath scanning and Cordapp detection * @param scanJars Uses the JAR URLs provided for classpath scanning and Cordapp detection
*/ */
@VisibleForTesting @VisibleForTesting
fun createDevMode(scanJars: List<URL>) = CordappLoader(scanJars) fun createDevMode(scanJars: List<URL>) = CordappLoader(scanJars.map { RestrictedURL(it, null) })
private fun getCordappsPath(baseDir: Path): Path = baseDir / CORDAPPS_DIR_NAME private fun getCordappsPath(baseDir: Path): Path = baseDir / CORDAPPS_DIR_NAME
private fun createScanPackage(scanPackage: String): List<URL> { private fun createScanPackage(scanPackage: String): List<RestrictedURL> {
val resource = scanPackage.replace('.', '/') val resource = scanPackage.replace('.', '/')
return this::class.java.classLoader.getResources(resource) return this::class.java.classLoader.getResources(resource)
.asSequence() .asSequence()
.map { path -> .map { path ->
if (path.protocol == "jar") { 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 { } else {
createDevCordappJar(scanPackage, path, resource) // No need to restrict as createDevCordappJar has already done that:
}.toURL() RestrictedURL(createDevCordappJar(scanPackage, path, resource).toURL(), null)
}
} }
.toList() .toList()
} }
@ -143,12 +145,12 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
return generatedCordapps[path]!! return generatedCordapps[path]!!
} }
private fun getCordappsInDirectory(cordappsDir: Path): List<URL> { private fun getCordappsInDirectory(cordappsDir: Path): List<RestrictedURL> {
return if (!cordappsDir.exists()) { return if (!cordappsDir.exists()) {
emptyList<URL>() emptyList()
} else { } else {
cordappsDir.list { 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<URL>)
findServices(scanResult), findServices(scanResult),
findPlugins(it), findPlugins(it),
findCustomSchemas(scanResult), findCustomSchemas(scanResult),
it) it.url)
} }
} }
private fun findServices(scanResult: ScanResult): List<Class<out SerializeAsToken>> { private fun findServices(scanResult: RestrictedScanResult): List<Class<out SerializeAsToken>> {
return scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class) return scanResult.getClassesWithAnnotation(SerializeAsToken::class, CordaService::class)
} }
private fun findInitiatedFlows(scanResult: ScanResult): List<Class<out FlowLogic<*>>> { private fun findInitiatedFlows(scanResult: RestrictedScanResult): List<Class<out FlowLogic<*>>> {
return scanResult.getClassesWithAnnotation(FlowLogic::class, InitiatedBy::class) return scanResult.getClassesWithAnnotation(FlowLogic::class, InitiatedBy::class)
// First group by the initiating flow class in case there are multiple mappings // First group by the initiating flow class in case there are multiple mappings
.groupBy { it.requireAnnotation<InitiatedBy>().value.java } .groupBy { it.requireAnnotation<InitiatedBy>().value.java }
@ -214,35 +216,35 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
return Modifier.isPublic(modifiers) && !isLocalClass && !isAnonymousClass && (!isMemberClass || Modifier.isStatic(modifiers)) return Modifier.isPublic(modifiers) && !isLocalClass && !isAnonymousClass && (!isMemberClass || Modifier.isStatic(modifiers))
} }
private fun findRPCFlows(scanResult: ScanResult): List<Class<out FlowLogic<*>>> { private fun findRPCFlows(scanResult: RestrictedScanResult): List<Class<out FlowLogic<*>>> {
return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByRPC::class).filter { it.isUserInvokable() } return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByRPC::class).filter { it.isUserInvokable() }
} }
private fun findServiceFlows(scanResult: ScanResult): List<Class<out FlowLogic<*>>> { private fun findServiceFlows(scanResult: RestrictedScanResult): List<Class<out FlowLogic<*>>> {
return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByService::class) return scanResult.getClassesWithAnnotation(FlowLogic::class, StartableByService::class)
} }
private fun findSchedulableFlows(scanResult: ScanResult): List<Class<out FlowLogic<*>>> { private fun findSchedulableFlows(scanResult: RestrictedScanResult): List<Class<out FlowLogic<*>>> {
return scanResult.getClassesWithAnnotation(FlowLogic::class, SchedulableFlow::class) return scanResult.getClassesWithAnnotation(FlowLogic::class, SchedulableFlow::class)
} }
private fun findContractClassNames(scanResult: ScanResult): List<String> { private fun findContractClassNames(scanResult: RestrictedScanResult): List<String> {
return (scanResult.getNamesOfClassesImplementing(Contract::class.java) + scanResult.getNamesOfClassesImplementing(UpgradedContract::class.java)).distinct() return (scanResult.getNamesOfClassesImplementing(Contract::class) + scanResult.getNamesOfClassesImplementing(UpgradedContract::class)).distinct()
} }
private fun findPlugins(cordappJarPath: URL): List<SerializationWhitelist> { private fun findPlugins(cordappJarPath: RestrictedURL): List<SerializationWhitelist> {
return ServiceLoader.load(SerializationWhitelist::class.java, URLClassLoader(arrayOf(cordappJarPath), appClassLoader)).toList().filter { return ServiceLoader.load(SerializationWhitelist::class.java, URLClassLoader(arrayOf(cordappJarPath.url), appClassLoader)).toList().filter {
cordappJarPath == it.javaClass.protectionDomain.codeSource.location it.javaClass.protectionDomain.codeSource.location == cordappJarPath.url && it.javaClass.name.startsWith(cordappJarPath.qualifiedNamePrefix)
} + DefaultWhitelist // Always add the DefaultWhitelist to the whitelist for an app. } + DefaultWhitelist // Always add the DefaultWhitelist to the whitelist for an app.
} }
private fun findCustomSchemas(scanResult: ScanResult): Set<MappedSchema> { private fun findCustomSchemas(scanResult: RestrictedScanResult): Set<MappedSchema> {
return scanResult.getClassesWithSuperclass(MappedSchema::class).toSet() return scanResult.getClassesWithSuperclass(MappedSchema::class).toSet()
} }
private fun scanCordapp(cordappJarPath: URL): ScanResult { private fun scanCordapp(cordappJarPath: RestrictedURL): RestrictedScanResult {
logger.info("Scanning CorDapp in $cordappJarPath") 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<out FlowLogic<*>>) : Comparator<Class<out FlowLogic<*>>> { private class FlowTypeHierarchyComparator(val initiatingFlow: Class<out FlowLogic<*>>) : Comparator<Class<out FlowLogic<*>>> {
@ -269,16 +271,30 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
} }
} }
private fun <T : Any> ScanResult.getClassesWithSuperclass(type: KClass<T>): List<T> { /** @param rootPackageName only this package and subpackages may be extracted from [url], or null to allow all packages. */
return getNamesOfSubclassesOf(type.java) private class RestrictedURL(val url: URL, rootPackageName: String?) {
.mapNotNull { loadClass(it, type) } val qualifiedNamePrefix = rootPackageName?.let { it + '.' } ?: ""
.filterNot { Modifier.isAbstract(it.modifiers) }
.map { it.kotlin.objectOrNewInstance() }
} }
private fun <T : Any> ScanResult.getClassesWithAnnotation(type: KClass<T>, annotation: KClass<out Annotation>): List<Class<out T>> { private inner class RestrictedScanResult(private val scanResult: ScanResult, private val qualifiedNamePrefix: String) {
return getNamesOfClassesWithAnnotation(annotation.java) fun getNamesOfClassesImplementing(type: KClass<*>): List<String> {
.mapNotNull { loadClass(it, type) } return scanResult.getNamesOfClassesImplementing(type.java)
.filterNot { Modifier.isAbstract(it.modifiers) } .filter { it.startsWith(qualifiedNamePrefix) }
}
fun <T : Any> getClassesWithSuperclass(type: KClass<T>): List<T> {
return scanResult.getNamesOfSubclassesOf(type.java)
.filter { it.startsWith(qualifiedNamePrefix) }
.mapNotNull { loadClass(it, type) }
.filterNot { Modifier.isAbstract(it.modifiers) }
.map { it.kotlin.objectOrNewInstance() }
}
fun <T : Any> getClassesWithAnnotation(type: KClass<T>, annotation: KClass<out Annotation>): List<Class<out T>> {
return scanResult.getNamesOfClassesWithAnnotation(annotation.java)
.filter { it.startsWith(qualifiedNamePrefix) }
.mapNotNull { loadClass(it, type) }
.filterNot { Modifier.isAbstract(it.modifiers) }
}
} }
} }

View File

@ -6,15 +6,14 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.node.services.AttachmentStorage import net.corda.core.node.services.AttachmentStorage
import net.corda.core.cordapp.Cordapp import net.corda.core.cordapp.Cordapp
import net.corda.core.cordapp.CordappContext import net.corda.core.cordapp.CordappContext
import net.corda.core.cordapp.CordappProvider
import net.corda.core.node.services.AttachmentId import net.corda.core.node.services.AttachmentId
import net.corda.core.serialization.SingletonSerializeAsToken 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. * 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 { override fun getAppContext(): CordappContext {
// TODO: Use better supported APIs in Java 9 // TODO: Use better supported APIs in Java 9
Exception().stackTrace.forEach { stackFrame -> Exception().stackTrace.forEach { stackFrame ->
@ -34,28 +33,19 @@ open class CordappProviderImpl(private val cordappLoader: CordappLoader) : Singl
/** /**
* Current known CorDapps loaded on this node * Current known CorDapps loaded on this node
*/ */
val cordapps get() = cordappLoader.cordapps override val cordapps get() = cordappLoader.cordapps
private lateinit var cordappAttachments: HashBiMap<SecureHash, Cordapp> private val cordappAttachments = HashBiMap.create(loadContractsIntoAttachmentStore(attachmentStorage))
/**
* 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
}
/** /**
* Gets the attachment ID of this CorDapp. Only CorDapps with contracts have an attachment ID * Gets the attachment ID of this CorDapp. Only CorDapps with contracts have an attachment ID
* *
* @param cordapp The cordapp to get the attachment ID * @param cordapp The cordapp to get the attachment ID
* @return An attachment ID if it exists, otherwise nothing * @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<SecureHash, Cordapp> { private fun loadContractsIntoAttachmentStore(attachmentStorage: AttachmentStorage): Map<SecureHash, URL> {
val cordappsWithAttachments = cordapps.filter { !it.contractClassNames.isEmpty() } val cordappsWithAttachments = cordapps.filter { !it.contractClassNames.isEmpty() }.map { it.jarPath }
val attachmentIds = cordappsWithAttachments.map { it.jarPath.openStream().use { attachmentStorage.importAttachment(it) } } val attachmentIds = cordappsWithAttachments.map { it.openStream().use { attachmentStorage.importAttachment(it) } }
return attachmentIds.zip(cordappsWithAttachments).toMap() return attachmentIds.zip(cordappsWithAttachments).toMap()
} }

View File

@ -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<Cordapp>
}

View File

@ -30,11 +30,5 @@ interface SchemaService {
* or via custom logic in this service. * or via custom logic in this service.
*/ */
fun generateMappedObject(state: ContractState, schema: MappedSchema): PersistentState fun generateMappedObject(state: ContractState, schema: MappedSchema): PersistentState
/**
* Registration mechanism to add custom contract schemas that extend the [MappedSchema] class.
*/
fun registerCustomSchemas(customSchemas: Set<MappedSchema>)
} }
//DOCEND SchemaService //DOCEND SchemaService

View File

@ -21,6 +21,7 @@ import net.corda.core.serialization.CordaSerializable
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.node.internal.InitiatedFlowFactory 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.config.NodeConfiguration
import net.corda.node.services.messaging.MessagingService import net.corda.node.services.messaging.MessagingService
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
@ -89,7 +90,7 @@ interface ServiceHubInternal : ServiceHub {
val networkService: MessagingService val networkService: MessagingService
val database: CordaPersistence val database: CordaPersistence
val configuration: NodeConfiguration val configuration: NodeConfiguration
override val cordappProvider: CordappProviderInternal
override fun recordTransactions(notifyVault: Boolean, txs: Iterable<SignedTransaction>) { override fun recordTransactions(notifyVault: Boolean, txs: Iterable<SignedTransaction>) {
require(txs.any()) { "No transactions passed in for recording" } require(txs.any()) { "No transactions passed in for recording" }
val recordedTransactions = txs.filter { validatedTransactions.addTransaction(it) } val recordedTransactions = txs.filter { validatedTransactions.addTransaction(it) }

View File

@ -33,25 +33,13 @@ class HibernateConfiguration(val schemaService: SchemaService, private val datab
private val sessionFactories = ConcurrentHashMap<Set<MappedSchema>, SessionFactory>() private val sessionFactories = ConcurrentHashMap<Set<MappedSchema>, SessionFactory>()
private val transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel") ?: "") private val transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel") ?: "")
val sessionFactoryForRegisteredSchemas = schemaService.schemaOptions.keys.let {
init { logger.info("Init HibernateConfiguration for schemas: $it")
logger.info("Init HibernateConfiguration for schemas: ${schemaService.schemaOptions.keys}") sessionFactoryForSchemas(it)
sessionFactoryForRegisteredSchemas()
} }
fun sessionFactoryForRegisteredSchemas(): SessionFactory { /** @param key must be immutable, not just read-only. */
return sessionFactoryForSchemas(*schemaService.schemaOptions.keys.toTypedArray()) fun sessionFactoryForSchemas(key: Set<MappedSchema>) = sessionFactories.computeIfAbsent(key, { makeSessionFactoryForSchemas(key) })
}
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<MappedSchema> = schemas.toSet()
return sessionFactories.computeIfAbsent(schemaSet, { makeSessionFactoryForSchemas(schemaSet) })
}
private fun makeSessionFactoryForSchemas(schemas: Set<MappedSchema>): SessionFactory { private fun makeSessionFactoryForSchemas(schemas: Set<MappedSchema>): SessionFactory {
logger.info("Creating session factory for schemas: $schemas") logger.info("Creating session factory for schemas: $schemas")

View File

@ -38,7 +38,7 @@ class HibernateObserver(vaultUpdates: Observable<Vault.Update<ContractState>>, v
} }
fun persistStateWithSchema(state: ContractState, stateRef: StateRef, schema: MappedSchema) { fun persistStateWithSchema(state: ContractState, stateRef: StateRef, schema: MappedSchema) {
val sessionFactory = config.sessionFactoryForSchema(schema) val sessionFactory = config.sessionFactoryForSchemas(setOf(schema))
val session = sessionFactory.withOptions(). val session = sessionFactory.withOptions().
connection(DatabaseTransactionManager.current().connection). connection(DatabaseTransactionManager.current().connection).
flushMode(FlushMode.MANUAL). flushMode(FlushMode.MANUAL).

View File

@ -9,6 +9,7 @@ import net.corda.core.schemas.NodeInfoSchemaV1
import net.corda.core.schemas.PersistentState import net.corda.core.schemas.PersistentState
import net.corda.core.schemas.QueryableState import net.corda.core.schemas.QueryableState
import net.corda.core.serialization.SingletonSerializeAsToken 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.api.SchemaService
import net.corda.node.services.events.NodeSchedulerService import net.corda.node.services.events.NodeSchedulerService
import net.corda.node.services.identity.PersistentIdentityService import net.corda.node.services.identity.PersistentIdentityService
@ -27,13 +28,13 @@ import net.corda.node.services.vault.VaultSchemaV1
/** /**
* Most basic implementation of [SchemaService]. * 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 loading schema options from node configuration.
* TODO: support configuring what schemas are to be selected for persistence. * 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: support plugins for schema version upgrading or custom mapping not supported by original [QueryableState].
* TODO: create whitelisted tables when a CorDapp is first installed * TODO: create whitelisted tables when a CorDapp is first installed
*/ */
class NodeSchemaService(customSchemas: Set<MappedSchema> = emptySet()) : SchemaService, SingletonSerializeAsToken() { class NodeSchemaService(cordappLoader: CordappLoader?) : SchemaService, SingletonSerializeAsToken() {
// Entities for compulsory services // Entities for compulsory services
object NodeServices object NodeServices
@ -67,9 +68,12 @@ class NodeSchemaService(customSchemas: Set<MappedSchema> = emptySet()) : SchemaS
Pair(NodeInfoSchemaV1, SchemaService.SchemaOptions()), Pair(NodeInfoSchemaV1, SchemaService.SchemaOptions()),
Pair(NodeServicesV1, SchemaService.SchemaOptions())) Pair(NodeServicesV1, SchemaService.SchemaOptions()))
override var schemaOptions: Map<MappedSchema, SchemaService.SchemaOptions> = requiredSchemas.plus(customSchemas.map { mappedSchema -> override val schemaOptions: Map<MappedSchema, SchemaService.SchemaOptions> = if (cordappLoader == null) {
Pair(mappedSchema, SchemaService.SchemaOptions()) 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. // Currently returns all schemas supported by the state, with no filtering or enrichment.
override fun selectSchemas(state: ContractState): Iterable<MappedSchema> { override fun selectSchemas(state: ContractState): Iterable<MappedSchema> {
@ -92,10 +96,4 @@ class NodeSchemaService(customSchemas: Set<MappedSchema> = emptySet()) : SchemaS
return VaultSchemaV1.VaultFungibleStates(state.owner, state.amount.quantity, state.amount.token.issuer.party, state.amount.token.issuer.reference, state.participants) 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) return (state as QueryableState).generateMappedObject(schema)
} }
override fun registerCustomSchemas(_customSchemas: Set<MappedSchema>) {
schemaOptions = schemaOptions.plus(_customSchemas.map { mappedSchema ->
Pair(mappedSchema, SchemaService.SchemaOptions())
})
}
} }

View File

@ -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: 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. * 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 { private companion object {
val log = loggerFor<NodeVaultService>() val log = loggerFor<NodeVaultService>()
@ -377,9 +377,8 @@ class NodeVaultService(private val clock: Clock, private val keyManagementServic
return keysToCheck.any { it in myKeys } return keysToCheck.any { it in myKeys }
} }
private var sessionFactory = hibernateConfig.sessionFactoryForRegisteredSchemas() private val sessionFactory = hibernateConfig.sessionFactoryForRegisteredSchemas
private var criteriaBuilder = sessionFactory.criteriaBuilder private val criteriaBuilder = sessionFactory.criteriaBuilder
/** /**
* Maintain a list of contract state interfaces to concrete types stored in the vault * Maintain a list of contract state interfaces to concrete types stored in the vault
* for usage in generic queries of type queryBy<LinearState> or queryBy<FungibleState<*>> * for usage in generic queries of type queryBy<LinearState> or queryBy<FungibleState<*>>
@ -406,11 +405,6 @@ class NodeVaultService(private val clock: Clock, private val keyManagementServic
@Throws(VaultQueryException::class) @Throws(VaultQueryException::class)
override fun <T : ContractState> _queryBy(criteria: QueryCriteria, paging: PageSpecification, sorting: Sort, contractStateType: Class<out T>): Vault.Page<T> { override fun <T : ContractState> _queryBy(criteria: QueryCriteria, paging: PageSpecification, sorting: Sort, contractStateType: Class<out T>): Vault.Page<T> {
log.info("Vault Query for contract type: $contractStateType, criteria: $criteria, pagination: $paging, sorting: $sorting") 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 // calculate total results where a page specification has been defined
var totalStates = -1L var totalStates = -1L
if (!paging.isDefault) { if (!paging.isDefault) {

View File

@ -6,8 +6,6 @@ import net.corda.core.node.services.IdentityService
import net.corda.node.services.api.SchemaService import net.corda.node.services.api.SchemaService
import net.corda.node.services.persistence.HibernateConfiguration import net.corda.node.services.persistence.HibernateConfiguration
import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.schema.NodeSchemaService
import org.hibernate.SessionFactory
import rx.Observable import rx.Observable
import rx.Subscriber import rx.Subscriber
import rx.subjects.UnicastSubject import rx.subjects.UnicastSubject
@ -32,12 +30,7 @@ class CordaPersistence(var dataSource: HikariDataSource, private val schemaServi
HibernateConfiguration(schemaService, databaseProperties, createIdentityService) HibernateConfiguration(schemaService, databaseProperties, createIdentityService)
} }
} }
val entityManagerFactory get() = hibernateConfig.sessionFactoryForRegisteredSchemas
val entityManagerFactory: SessionFactory by lazy {
transaction {
hibernateConfig.sessionFactoryForRegisteredSchemas()
}
}
companion object { companion object {
fun connect(dataSource: HikariDataSource, schemaService: SchemaService, createIdentityService: () -> IdentityService, databaseProperties: Properties): CordaPersistence { 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 config = HikariConfig(dataSourceProperties)
val dataSource = HikariDataSource(config) val dataSource = HikariDataSource(config)
val persistence = CordaPersistence.connect(dataSource, schemaService, createIdentityService, databaseProperties ?: Properties()) val persistence = CordaPersistence.connect(dataSource, schemaService, createIdentityService, databaseProperties ?: Properties())

View File

@ -8,7 +8,6 @@ import net.corda.core.messaging.*;
import net.corda.core.node.services.*; import net.corda.core.node.services.*;
import net.corda.core.node.services.vault.*; import net.corda.core.node.services.vault.*;
import net.corda.core.node.services.vault.QueryCriteria.*; import net.corda.core.node.services.vault.QueryCriteria.*;
import net.corda.core.schemas.*;
import net.corda.core.utilities.*; import net.corda.core.utilities.*;
import net.corda.finance.contracts.*; import net.corda.finance.contracts.*;
import net.corda.finance.contracts.asset.*; import net.corda.finance.contracts.asset.*;
@ -43,14 +42,13 @@ public class VaultQueryJavaTests extends TestDependencyInjectionBase {
@Before @Before
public void setUp() { public void setUp() {
List<String> cordappPackages = Arrays.asList("net.corda.testing.contracts", "net.corda.finance.contracts.asset"); List<String> cordappPackages = Arrays.asList("net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1.class.getPackage().getName());
ArrayList<KeyPair> keys = new ArrayList<>(); ArrayList<KeyPair> keys = new ArrayList<>();
keys.add(getMEGA_CORP_KEY()); keys.add(getMEGA_CORP_KEY());
keys.add(getDUMMY_NOTARY_KEY()); keys.add(getDUMMY_NOTARY_KEY());
Set<MappedSchema> requiredSchemas = Collections.singleton(CashSchemaV1.INSTANCE);
IdentityService identitySvc = makeTestIdentityService(); IdentityService identitySvc = makeTestIdentityService();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Pair<CordaPersistence, MockServices> databaseAndServices = makeTestDatabaseAndMockServices(requiredSchemas, keys, () -> identitySvc, cordappPackages); Pair<CordaPersistence, MockServices> databaseAndServices = makeTestDatabaseAndMockServices(keys, () -> identitySvc, cordappPackages);
issuerServices = new MockServices(cordappPackages, getDUMMY_CASH_ISSUER_KEY(), getBOC_KEY()); issuerServices = new MockServices(cordappPackages, getDUMMY_CASH_ISSUER_KEY(), getBOC_KEY());
database = databaseAndServices.getFirst(); database = databaseAndServices.getFirst();
services = databaseAndServices.getSecond(); services = databaseAndServices.getSecond();

View File

@ -26,7 +26,7 @@ import kotlin.test.assertEquals
class InteractiveShellTest { class InteractiveShellTest {
@Before @Before
fun setup() { fun setup() {
InteractiveShell.database = configureDatabase(MockServices.makeTestDataSourceProperties(), MockServices.makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) InteractiveShell.database = configureDatabase(MockServices.makeTestDataSourceProperties(), MockServices.makeTestDatabaseProperties(), ::makeTestIdentityService)
} }
@After @After

View File

@ -1,5 +1,6 @@
package net.corda.node.internal.cordapp package net.corda.node.internal.cordapp
import com.nhaarman.mockito_kotlin.mock
import net.corda.core.node.services.AttachmentStorage import net.corda.core.node.services.AttachmentStorage
import net.corda.testing.node.MockAttachmentStorage import net.corda.testing.node.MockAttachmentStorage
import org.junit.Assert import org.junit.Assert
@ -22,9 +23,7 @@ class CordappProviderImplTests {
@Test @Test
fun `isolated jar is loaded into the attachment store`() { fun `isolated jar is loaded into the attachment store`() {
val loader = CordappLoader.createDevMode(listOf(isolatedJAR)) val loader = CordappLoader.createDevMode(listOf(isolatedJAR))
val provider = CordappProviderImpl(loader) val provider = CordappProviderImpl(loader, attachmentStore)
provider.start(attachmentStore)
val maybeAttachmentId = provider.getCordappAttachmentId(provider.cordapps.first()) val maybeAttachmentId = provider.getCordappAttachmentId(provider.cordapps.first())
Assert.assertNotNull(maybeAttachmentId) Assert.assertNotNull(maybeAttachmentId)
@ -34,17 +33,14 @@ class CordappProviderImplTests {
@Test @Test
fun `empty jar is not loaded into the attachment store`() { fun `empty jar is not loaded into the attachment store`() {
val loader = CordappLoader.createDevMode(listOf(emptyJAR)) val loader = CordappLoader.createDevMode(listOf(emptyJAR))
val provider = CordappProviderImpl(loader) val provider = CordappProviderImpl(loader, attachmentStore)
provider.start(attachmentStore)
Assert.assertNull(provider.getCordappAttachmentId(provider.cordapps.first())) Assert.assertNull(provider.getCordappAttachmentId(provider.cordapps.first()))
} }
@Test @Test
fun `test that we find a cordapp class that is loaded into the store`() { fun `test that we find a cordapp class that is loaded into the store`() {
val loader = CordappLoader.createDevMode(listOf(isolatedJAR)) val loader = CordappLoader.createDevMode(listOf(isolatedJAR))
val provider = CordappProviderImpl(loader) val provider = CordappProviderImpl(loader, mock())
val className = "net.corda.finance.contracts.isolated.AnotherDummyContract" val className = "net.corda.finance.contracts.isolated.AnotherDummyContract"
val expected = provider.cordapps.first() val expected = provider.cordapps.first()
@ -57,10 +53,8 @@ class CordappProviderImplTests {
@Test @Test
fun `test that we find an attachment for a cordapp contrat class`() { fun `test that we find an attachment for a cordapp contrat class`() {
val loader = CordappLoader.createDevMode(listOf(isolatedJAR)) val loader = CordappLoader.createDevMode(listOf(isolatedJAR))
val provider = CordappProviderImpl(loader) val provider = CordappProviderImpl(loader, attachmentStore)
val className = "net.corda.finance.contracts.isolated.AnotherDummyContract" val className = "net.corda.finance.contracts.isolated.AnotherDummyContract"
provider.start(attachmentStore)
val expected = provider.getAppContext(provider.cordapps.first()).attachmentId val expected = provider.getAppContext(provider.cordapps.first()).attachmentId
val actual = provider.getContractAttachmentID(className) val actual = provider.getContractAttachmentID(className)

View File

@ -78,7 +78,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
calls = 0 calls = 0
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
val databaseProperties = makeTestDatabaseProperties() val databaseProperties = makeTestDatabaseProperties()
database = configureDatabase(dataSourceProps, databaseProperties, createIdentityService = ::makeTestIdentityService) database = configureDatabase(dataSourceProps, databaseProperties, ::makeTestIdentityService)
val identityService = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT) val identityService = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
val kms = MockKeyManagementService(identityService, ALICE_KEY) val kms = MockKeyManagementService(identityService, ALICE_KEY)
@ -97,7 +97,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
network = mockMessagingService), TestReference { network = mockMessagingService), TestReference {
override val vaultService: VaultServiceInternal = NodeVaultService(testClock, kms, stateLoader, database.hibernateConfig) override val vaultService: VaultServiceInternal = NodeVaultService(testClock, kms, stateLoader, database.hibernateConfig)
override val testReference = this@NodeSchedulerServiceTest 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) smmExecutor = AffinityExecutor.ServiceAffinityExecutor("test", 1)
scheduler = NodeSchedulerService(services, schedulerGatedExecutor, serverThread = smmExecutor) scheduler = NodeSchedulerService(services, schedulerGatedExecutor, serverThread = smmExecutor)

View File

@ -71,7 +71,7 @@ class ArtemisMessagingTests : TestDependencyInjectionBase() {
baseDirectory = baseDirectory, baseDirectory = baseDirectory,
myLegalName = ALICE.name) myLegalName = ALICE.name)
LogHelper.setLevel(PersistentUniquenessProvider::class) LogHelper.setLevel(PersistentUniquenessProvider::class)
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService)
networkMapRegistrationFuture = doneFuture(Unit) networkMapRegistrationFuture = doneFuture(Unit)
networkMapCache = PersistentNetworkMapCache(serviceHub = object : MockServiceHubInternal(database, config) {}) networkMapCache = PersistentNetworkMapCache(serviceHub = object : MockServiceHubInternal(database, config) {})
} }

View File

@ -33,7 +33,7 @@ class DBCheckpointStorageTests : TestDependencyInjectionBase() {
@Before @Before
fun setUp() { fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class) LogHelper.setLevel(PersistentUniquenessProvider::class)
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService)
newCheckpointStorage() newCheckpointStorage()
} }

View File

@ -38,7 +38,7 @@ class DBTransactionStorageTests : TestDependencyInjectionBase() {
fun setUp() { fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class) LogHelper.setLevel(PersistentUniquenessProvider::class)
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), NodeSchemaService(), ::makeTestIdentityService) database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), ::makeTestIdentityService)
database.transaction { database.transaction {
services = object : MockServices(BOB_KEY) { services = object : MockServices(BOB_KEY) {

View File

@ -9,6 +9,7 @@ import net.corda.core.utilities.toBase58String
import net.corda.core.node.services.Vault import net.corda.core.node.services.Vault
import net.corda.core.node.services.VaultService import net.corda.core.node.services.VaultService
import net.corda.core.schemas.CommonSchemaV1 import net.corda.core.schemas.CommonSchemaV1
import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentStateRef import net.corda.core.schemas.PersistentStateRef
import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.deserialize 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.schemas.SampleCashSchemaV3
import net.corda.finance.utils.sumCash import net.corda.finance.utils.sumCash
import net.corda.node.services.schema.HibernateObserver 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.services.vault.VaultSchemaV1
import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
@ -77,7 +77,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
issuerServices = MockServices(cordappPackages, DUMMY_CASH_ISSUER_KEY, BOB_KEY, BOC_KEY) issuerServices = MockServices(cordappPackages, DUMMY_CASH_ISSUER_KEY, BOB_KEY, BOC_KEY)
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
val defaultDatabaseProperties = makeTestDatabaseProperties() val defaultDatabaseProperties = makeTestDatabaseProperties()
database = configureDatabase(dataSourceProps, defaultDatabaseProperties, NodeSchemaService(), ::makeTestIdentityService) database = configureDatabase(dataSourceProps, defaultDatabaseProperties, ::makeTestIdentityService)
database.transaction { database.transaction {
hibernateConfig = database.hibernateConfig hibernateConfig = database.hibernateConfig
services = object : MockServices(cordappPackages, BOB_KEY, BOC_KEY, DUMMY_NOTARY_KEY) { services = object : MockServices(cordappPackages, BOB_KEY, BOC_KEY, DUMMY_NOTARY_KEY) {
@ -95,13 +95,13 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
hibernatePersister = services.hibernatePersister hibernatePersister = services.hibernatePersister
} }
setUpDb() setUpDb()
sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, CashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3)
val customSchemas = setOf(VaultSchemaV1, CashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3)
sessionFactory = hibernateConfig.sessionFactoryForSchemas(*customSchemas.toTypedArray())
entityManager = sessionFactory.createEntityManager() entityManager = sessionFactory.createEntityManager()
criteriaBuilder = sessionFactory.criteriaBuilder criteriaBuilder = sessionFactory.criteriaBuilder
} }
private fun sessionFactoryForSchemas(vararg schemas: MappedSchema) = hibernateConfig.sessionFactoryForSchemas(schemas.toSet())
@After @After
fun cleanUp() { fun cleanUp() {
database.close() database.close()
@ -536,8 +536,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
services.fillWithSomeTestDeals(listOf("123", "456", "789")) services.fillWithSomeTestDeals(listOf("123", "456", "789"))
services.fillWithSomeTestLinearStates(2) services.fillWithSomeTestLinearStates(2)
} }
val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1)
val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1)
val criteriaBuilder = sessionFactory.criteriaBuilder val criteriaBuilder = sessionFactory.criteriaBuilder
val entityManager = sessionFactory.createEntityManager() val entityManager = sessionFactory.createEntityManager()
@ -568,8 +567,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
services.fillWithSomeTestDeals(listOf("123", "456", "789")) services.fillWithSomeTestDeals(listOf("123", "456", "789"))
services.fillWithSomeTestLinearStates(2) services.fillWithSomeTestLinearStates(2)
} }
val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2)
val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2)
val criteriaBuilder = sessionFactory.criteriaBuilder val criteriaBuilder = sessionFactory.criteriaBuilder
val entityManager = sessionFactory.createEntityManager() val entityManager = sessionFactory.createEntityManager()
@ -635,8 +633,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
hibernatePersister.persistStateWithSchema(dummyFungibleState, it.ref, SampleCashSchemaV3) hibernatePersister.persistStateWithSchema(dummyFungibleState, it.ref, SampleCashSchemaV3)
} }
} }
val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, CommonSchemaV1, SampleCashSchemaV3)
val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, CommonSchemaV1, SampleCashSchemaV3)
val criteriaBuilder = sessionFactory.criteriaBuilder val criteriaBuilder = sessionFactory.criteriaBuilder
val entityManager = sessionFactory.createEntityManager() val entityManager = sessionFactory.createEntityManager()
@ -764,8 +761,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
services.fillWithSomeTestLinearStates(2, externalId = "222") services.fillWithSomeTestLinearStates(2, externalId = "222")
services.fillWithSomeTestLinearStates(3, externalId = "333") services.fillWithSomeTestLinearStates(3, externalId = "333")
} }
val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2)
val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV2)
val criteriaBuilder = sessionFactory.criteriaBuilder val criteriaBuilder = sessionFactory.criteriaBuilder
val entityManager = sessionFactory.createEntityManager() val entityManager = sessionFactory.createEntityManager()
@ -817,8 +813,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
services.fillWithSomeTestLinearStates(2, externalId = "222") services.fillWithSomeTestLinearStates(2, externalId = "222")
services.fillWithSomeTestLinearStates(3, externalId = "333") services.fillWithSomeTestLinearStates(3, externalId = "333")
} }
val sessionFactory = sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1)
val sessionFactory = hibernateConfig.sessionFactoryForSchemas(VaultSchemaV1, DummyLinearStateSchemaV1)
val criteriaBuilder = sessionFactory.criteriaBuilder val criteriaBuilder = sessionFactory.criteriaBuilder
val entityManager = sessionFactory.createEntityManager() val entityManager = sessionFactory.createEntityManager()

View File

@ -40,7 +40,7 @@ class NodeAttachmentStorageTest {
LogHelper.setLevel(PersistentUniquenessProvider::class) LogHelper.setLevel(PersistentUniquenessProvider::class)
val dataSourceProperties = makeTestDataSourceProperties() val dataSourceProperties = makeTestDataSourceProperties()
database = configureDatabase(dataSourceProperties, makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) database = configureDatabase(dataSourceProperties, makeTestDatabaseProperties(), ::makeTestIdentityService)
fs = Jimfs.newFileSystem(Configuration.unix()) fs = Jimfs.newFileSystem(Configuration.unix())
} }

View File

@ -57,8 +57,6 @@ class HibernateObserverTests {
val testSchema = TestSchema val testSchema = TestSchema
val rawUpdatesPublisher = PublishSubject.create<Vault.Update<ContractState>>() val rawUpdatesPublisher = PublishSubject.create<Vault.Update<ContractState>>()
val schemaService = object : SchemaService { val schemaService = object : SchemaService {
override fun registerCustomSchemas(customSchemas: Set<MappedSchema>) {}
override val schemaOptions: Map<MappedSchema, SchemaService.SchemaOptions> = emptyMap() override val schemaOptions: Map<MappedSchema, SchemaService.SchemaOptions> = emptyMap()
override fun selectSchemas(state: ContractState): Iterable<MappedSchema> = setOf(testSchema) override fun selectSchemas(state: ContractState): Iterable<MappedSchema> = setOf(testSchema)
@ -70,7 +68,7 @@ class HibernateObserverTests {
return parent return parent
} }
} }
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), schemaService, createIdentityService = ::makeTestIdentityService) val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService, schemaService)
@Suppress("UNUSED_VARIABLE") @Suppress("UNUSED_VARIABLE")
val observer = HibernateObserver(rawUpdatesPublisher, database.hibernateConfig) val observer = HibernateObserver(rawUpdatesPublisher, database.hibernateConfig)
database.transaction { database.transaction {

View File

@ -3,11 +3,13 @@ package net.corda.node.services.schema
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StartableByRPC
import net.corda.core.internal.packageName
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState import net.corda.core.schemas.PersistentState
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.node.services.api.ServiceHubInternal import net.corda.node.services.api.ServiceHubInternal
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver import net.corda.testing.driver.driver
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.schemas.DummyLinearStateSchemaV1 import net.corda.testing.schemas.DummyLinearStateSchemaV1
@ -15,6 +17,7 @@ import org.hibernate.annotations.Cascade
import org.hibernate.annotations.CascadeType import org.hibernate.annotations.CascadeType
import org.junit.Test import org.junit.Test
import javax.persistence.* import javax.persistence.*
import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
class NodeSchemaServiceTest { class NodeSchemaServiceTest {
@ -23,11 +26,9 @@ class NodeSchemaServiceTest {
*/ */
@Test @Test
fun `registering custom schemas for testing with MockNode`() { fun `registering custom schemas for testing with MockNode`() {
val mockNet = MockNetwork() val mockNet = MockNetwork(cordappPackages = listOf(DummyLinearStateSchemaV1::class.packageName))
val mockNode = mockNet.createNode() val mockNode = mockNet.createNode()
mockNet.runNetwork() mockNet.runNetwork()
mockNode.internals.registerCustomSchemas(setOf(DummyLinearStateSchemaV1))
val schemaService = mockNode.services.schemaService val schemaService = mockNode.services.schemaService
assertTrue(schemaService.schemaOptions.containsKey(DummyLinearStateSchemaV1)) assertTrue(schemaService.schemaOptions.containsKey(DummyLinearStateSchemaV1))
@ -50,6 +51,16 @@ class NodeSchemaServiceTest {
} }
} }
@Test
fun `custom schemas are loaded eagerly`() {
val expected = setOf("PARENTS", "CHILDREN")
assertEquals<Set<*>>(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 @StartableByRPC
class MappedSchemasFlow : FlowLogic<List<String>>() { class MappedSchemasFlow : FlowLogic<List<String>>() {
@Suspendable @Suspendable

View File

@ -86,7 +86,7 @@ class DistributedImmutableMapTests : TestDependencyInjectionBase() {
private fun createReplica(myAddress: NetworkHostAndPort, clusterAddress: NetworkHostAndPort? = null): CompletableFuture<Member> { private fun createReplica(myAddress: NetworkHostAndPort, clusterAddress: NetworkHostAndPort? = null): CompletableFuture<Member> {
val storage = Storage.builder().withStorageLevel(StorageLevel.MEMORY).build() val storage = Storage.builder().withStorageLevel(StorageLevel.MEMORY).build()
val address = Address(myAddress.host, myAddress.port) 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) databases.add(database)
val stateMachineFactory = { DistributedImmutableMap(database, RaftUniquenessProvider.Companion::createMap) } val stateMachineFactory = { DistributedImmutableMap(database, RaftUniquenessProvider.Companion::createMap) }

View File

@ -23,7 +23,7 @@ class PersistentUniquenessProviderTests : TestDependencyInjectionBase() {
@Before @Before
fun setUp() { fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class) LogHelper.setLevel(PersistentUniquenessProvider::class)
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService)
} }
@After @After

View File

@ -9,6 +9,7 @@ import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.packageName
import net.corda.core.node.services.* import net.corda.core.node.services.*
import net.corda.core.node.services.vault.QueryCriteria import net.corda.core.node.services.vault.QueryCriteria
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() { class NodeVaultServiceTest : TestDependencyInjectionBase() {
companion object { 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 lateinit var services: MockServices
@ -58,7 +59,6 @@ class NodeVaultServiceTest : TestDependencyInjectionBase() {
fun setUp() { fun setUp() {
LogHelper.setLevel(NodeVaultService::class) LogHelper.setLevel(NodeVaultService::class)
val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(BOC_KEY, DUMMY_CASH_ISSUER_KEY), val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(BOC_KEY, DUMMY_CASH_ISSUER_KEY),
customSchemas = setOf(CashSchemaV1),
cordappPackages = cordappPackages) cordappPackages = cordappPackages)
database = databaseAndServices.first database = databaseAndServices.first
services = databaseAndServices.second services = databaseAndServices.second

View File

@ -6,6 +6,7 @@ import net.corda.core.crypto.entropyToKeyPair
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.packageName
import net.corda.core.node.services.* import net.corda.core.node.services.*
import net.corda.core.node.services.vault.* import net.corda.core.node.services.vault.*
import net.corda.core.node.services.vault.QueryCriteria.* import net.corda.core.node.services.vault.QueryCriteria.*
@ -45,10 +46,9 @@ import java.time.temporal.ChronoUnit
import java.util.* import java.util.*
class VaultQueryTests : TestDependencyInjectionBase() { class VaultQueryTests : TestDependencyInjectionBase() {
companion object { private val cordappPackages = setOf(
private val cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts") "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 services: MockServices
private lateinit var notaryServices: MockServices private lateinit var notaryServices: MockServices
private val vaultService: VaultService get() = services.vaultService private val vaultService: VaultService get() = services.vaultService
@ -67,7 +67,6 @@ class VaultQueryTests : TestDependencyInjectionBase() {
identitySvc.verifyAndRegisterIdentity(BOC_IDENTITY) identitySvc.verifyAndRegisterIdentity(BOC_IDENTITY)
val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(MEGA_CORP_KEY, DUMMY_NOTARY_KEY), val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(MEGA_CORP_KEY, DUMMY_NOTARY_KEY),
createIdentityService = { identitySvc }, createIdentityService = { identitySvc },
customSchemas = setOf(CashSchemaV1, CommercialPaperSchemaV1, DummyLinearStateSchemaV1),
cordappPackages = cordappPackages) cordappPackages = cordappPackages)
database = databaseAndServices.first database = databaseAndServices.first
services = databaseAndServices.second services = databaseAndServices.second
@ -85,8 +84,7 @@ class VaultQueryTests : TestDependencyInjectionBase() {
@Ignore @Ignore
@Test @Test
fun createPersistentTestDb() { fun createPersistentTestDb() {
val database = configureDatabase(makePersistentDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = { identitySvc }) val database = configureDatabase(makePersistentDataSourceProperties(), makeTestDatabaseProperties(), { identitySvc })
setUpDb(database, 5000) setUpDb(database, 5000)
database.close() database.close()
@ -1753,6 +1751,9 @@ class VaultQueryTests : TestDependencyInjectionBase() {
@Test @Test
fun `query attempting to use unregistered schema`() { fun `query attempting to use unregistered schema`() {
tearDown()
cordappPackages -= SampleCashSchemaV3::class.packageName
setUp()
database.transaction { database.transaction {
services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.DOLLARS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L))
services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L)) services.fillWithSomeTestCash(100.POUNDS, notaryServices, DUMMY_NOTARY, 1, 1, Random(0L))

View File

@ -4,6 +4,7 @@ import net.corda.core.contracts.ContractState
import net.corda.core.contracts.LinearState import net.corda.core.contracts.LinearState
import net.corda.core.contracts.UniqueIdentifier import net.corda.core.contracts.UniqueIdentifier
import net.corda.core.identity.AnonymousParty 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.Vault
import net.corda.core.node.services.VaultService import net.corda.core.node.services.VaultService
import net.corda.core.node.services.queryBy import net.corda.core.node.services.queryBy
@ -35,7 +36,7 @@ import kotlin.test.assertEquals
class VaultWithCashTest : TestDependencyInjectionBase() { class VaultWithCashTest : TestDependencyInjectionBase() {
companion object { 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 lateinit var services: MockServices
@ -48,7 +49,6 @@ class VaultWithCashTest : TestDependencyInjectionBase() {
fun setUp() { fun setUp() {
LogHelper.setLevel(VaultWithCashTest::class) LogHelper.setLevel(VaultWithCashTest::class)
val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(DUMMY_CASH_ISSUER_KEY, DUMMY_NOTARY_KEY), val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(DUMMY_CASH_ISSUER_KEY, DUMMY_NOTARY_KEY),
customSchemas = setOf(CashSchemaV1),
cordappPackages = cordappPackages) cordappPackages = cordappPackages)
database = databaseAndServices.first database = databaseAndServices.first
services = databaseAndServices.second services = databaseAndServices.second

View File

@ -21,7 +21,7 @@ class ObservablesTests {
val toBeClosed = mutableListOf<Closeable>() val toBeClosed = mutableListOf<Closeable>()
fun createDatabase(): CordaPersistence { fun createDatabase(): CordaPersistence {
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService)
toBeClosed += database toBeClosed += database
return database return database
} }

View File

@ -62,7 +62,7 @@ class NodeInterestRatesTest : TestDependencyInjectionBase() {
@Before @Before
fun setUp() { fun setUp() {
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), createIdentityService = ::makeTestIdentityService) database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), ::makeTestIdentityService)
database.transaction { database.transaction {
oracle = createMockCordaService(services, NodeInterestRates::Oracle) oracle = createMockCordaService(services, NodeInterestRates::Oracle)
oracle.knownFixes = TEST_DATA oracle.knownFixes = TEST_DATA

View File

@ -12,7 +12,6 @@ import net.corda.node.internal.StartedNode
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.services.statemachine.StateMachineManager
import net.corda.nodeapi.internal.ServiceInfo import net.corda.nodeapi.internal.ServiceInfo
import net.corda.nodeapi.internal.ServiceType
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
@ -270,9 +269,3 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
mockNet.stopNodes() 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<ServiceInfo>.containsType(type: ServiceType) = any { it.type == type }

View File

@ -1,6 +1,7 @@
package net.corda.traderdemo package net.corda.traderdemo
import net.corda.client.rpc.CordaRPCClient import net.corda.client.rpc.CordaRPCClient
import net.corda.core.internal.packageName
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.millis import net.corda.core.utilities.millis
import net.corda.finance.DOLLARS import net.corda.finance.DOLLARS
@ -20,7 +21,9 @@ import org.assertj.core.api.Assertions.assertThat
import org.junit.Test import org.junit.Test
import java.util.concurrent.Executors 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 @Test
fun `runs trader demo`() { fun `runs trader demo`() {
val demoUser = User("demo", "demo", setOf(startFlowPermission<SellerFlow>())) val demoUser = User("demo", "demo", setOf(startFlowPermission<SellerFlow>()))
@ -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() } val (nodeA, nodeB, bankNode) = listOf(nodeAFuture, nodeBFuture, bankNodeFuture, notaryFuture).map { it.getOrThrow() }
nodeA.internals.registerInitiatedFlow(BuyerFlow::class.java) 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 (nodeARpc, nodeBRpc) = listOf(nodeA, nodeB).map {
val client = CordaRPCClient(it.internals.configuration.rpcAddress!!) val client = CordaRPCClient(it.internals.configuration.rpcAddress!!)
client.start(demoUser.username, demoUser.password).proxy client.start(demoUser.username, demoUser.password).proxy

View File

@ -1,7 +1,6 @@
package net.corda.node.testing package net.corda.node.testing
import com.codahale.metrics.MetricRegistry import com.codahale.metrics.MetricRegistry
import net.corda.core.cordapp.CordappProvider
import net.corda.core.flows.FlowInitiator import net.corda.core.flows.FlowInitiator
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.Party 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.StateLoaderImpl
import net.corda.node.internal.cordapp.CordappLoader import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.internal.cordapp.CordappProviderImpl import net.corda.node.internal.cordapp.CordappProviderImpl
import net.corda.node.internal.cordapp.CordappProviderInternal
import net.corda.node.serialization.NodeClock import net.corda.node.serialization.NodeClock
import net.corda.node.services.api.* import net.corda.node.services.api.*
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.messaging.MessagingService 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.FlowStateMachineImpl
import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.transactions.InMemoryTransactionVerifierService import net.corda.node.services.transactions.InMemoryTransactionVerifierService
@ -46,10 +45,9 @@ open class MockServiceHubInternal(
val mapCache: NetworkMapCacheInternal? = null, val mapCache: NetworkMapCacheInternal? = null,
val scheduler: SchedulerService? = null, val scheduler: SchedulerService? = null,
val overrideClock: Clock? = NodeClock(), val overrideClock: Clock? = NodeClock(),
val schemas: SchemaService? = NodeSchemaService(),
val customContractUpgradeService: ContractUpgradeService? = null, val customContractUpgradeService: ContractUpgradeService? = null,
val customTransactionVerifierService: TransactionVerifierService? = InMemoryTransactionVerifierService(2), 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) protected val stateLoader: StateLoaderImpl = StateLoaderImpl(validatedTransactions)
) : ServiceHubInternal, StateLoader by stateLoader { ) : ServiceHubInternal, StateLoader by stateLoader {
override val transactionVerifierService: TransactionVerifierService override val transactionVerifierService: TransactionVerifierService
@ -75,8 +73,7 @@ open class MockServiceHubInternal(
override val monitoringService: MonitoringService = MonitoringService(MetricRegistry()) override val monitoringService: MonitoringService = MonitoringService(MetricRegistry())
override val rpcFlows: List<Class<out FlowLogic<*>>> override val rpcFlows: List<Class<out FlowLogic<*>>>
get() = throw UnsupportedOperationException() get() = throw UnsupportedOperationException()
override val schemaService: SchemaService override val schemaService get() = throw UnsupportedOperationException()
get() = schemas ?: throw UnsupportedOperationException()
override val auditService: AuditService = DummyAuditService() override val auditService: AuditService = DummyAuditService()
lateinit var smm: StateMachineManager lateinit var smm: StateMachineManager

View File

@ -14,7 +14,6 @@ import net.corda.core.node.NodeInfo
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
import net.corda.core.node.StateLoader import net.corda.core.node.StateLoader
import net.corda.core.node.services.* import net.corda.core.node.services.*
import net.corda.core.schemas.MappedSchema
import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsToken
import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.transactions.SignedTransaction 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. * building chains of transactions and verifying them. It isn't sufficient for testing flows however.
*/ */
open class MockServices( open class MockServices(
cordappPackages: List<String>, cordappLoader: CordappLoader,
override val validatedTransactions: WritableTransactionStorage, override val validatedTransactions: WritableTransactionStorage,
protected val stateLoader: StateLoaderImpl = StateLoaderImpl(validatedTransactions), protected val stateLoader: StateLoaderImpl = StateLoaderImpl(validatedTransactions),
vararg val keys: KeyPair vararg val keys: KeyPair
@ -101,24 +100,22 @@ open class MockServices(
/** /**
* Makes database and mock services appropriate for unit tests. * Makes database and mock services appropriate for unit tests.
* * @param keys a list of [KeyPair] instances to be used by [MockServices]. Defualts to [MEGA_CORP_KEY]
* @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 createIdentityService a lambda function returning an instance of [IdentityService]. Defauts to [InMemoryIdentityService]. * @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]. * @return a pair where the first element is the instance of [CordaPersistence] and the second is [MockServices].
*/ */
@JvmStatic @JvmStatic
fun makeTestDatabaseAndMockServices(customSchemas: Set<MappedSchema> = emptySet(), fun makeTestDatabaseAndMockServices(keys: List<KeyPair> = listOf(MEGA_CORP_KEY),
keys: List<KeyPair> = listOf(MEGA_CORP_KEY),
createIdentityService: () -> IdentityService = { makeTestIdentityService() }, createIdentityService: () -> IdentityService = { makeTestIdentityService() },
cordappPackages: List<String> = emptyList()): Pair<CordaPersistence, MockServices> { cordappPackages: List<String> = emptyList()): Pair<CordaPersistence, MockServices> {
val cordappLoader = CordappLoader.createWithTestPackages(cordappPackages)
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
val databaseProperties = makeTestDatabaseProperties() val databaseProperties = makeTestDatabaseProperties()
val identityServiceRef: IdentityService by lazy { createIdentityService() } 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 { val mockService = database.transaction {
object : MockServices(cordappPackages, *(keys.toTypedArray())) { object : MockServices(cordappLoader, *(keys.toTypedArray())) {
override val identityService: IdentityService = database.transaction { identityServiceRef } override val identityService: IdentityService = database.transaction { identityServiceRef }
override val vaultService = makeVaultService(database.hibernateConfig) override val vaultService = makeVaultService(database.hibernateConfig)
@ -137,7 +134,8 @@ open class MockServices(
} }
} }
constructor(cordappPackages: List<String>, vararg keys: KeyPair) : this(cordappPackages, MockTransactionStorage(), keys = *keys) private constructor(cordappLoader: CordappLoader, vararg keys: KeyPair) : this(cordappLoader, MockTransactionStorage(), keys = *keys)
constructor(cordappPackages: List<String>, vararg keys: KeyPair) : this(CordappLoader.createWithTestPackages(cordappPackages), keys = *keys)
constructor(vararg keys: KeyPair) : this(emptyList(), *keys) constructor(vararg keys: KeyPair) : this(emptyList(), *keys)
constructor() : this(generateKeyPair()) constructor() : this(generateKeyPair())
@ -167,11 +165,11 @@ open class MockServices(
return NodeInfo(emptyList(), listOf(identity), 1, serial = 1L) return NodeInfo(emptyList(), listOf(identity), 1, serial = 1L)
} }
override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2) 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 override val cordappProvider: CordappProvider get() = mockCordappProvider
lateinit var hibernatePersister: HibernateObserver 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) val vaultService = NodeVaultService(Clock.systemUTC(), keyManagementService, stateLoader, hibernateConfig)
hibernatePersister = HibernateObserver(vaultService.rawUpdates, hibernateConfig) hibernatePersister = HibernateObserver(vaultService.rawUpdates, hibernateConfig)
return vaultService return vaultService

View File

@ -37,7 +37,7 @@ class SimpleNode(val config: NodeConfiguration, val address: NetworkHostAndPort
val monitoringService = MonitoringService(MetricRegistry()) val monitoringService = MonitoringService(MetricRegistry())
val identity: KeyPair = generateKeyPair() val identity: KeyPair = generateKeyPair()
val identityService: IdentityService = InMemoryIdentityService(trustRoot = trustRoot) 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 keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity))
val executor = ServiceAffinityExecutor(config.myLegalName.organisation, 1) val executor = ServiceAffinityExecutor(config.myLegalName.organisation, 1)
// TODO: We should have a dummy service hub rather than change behaviour in tests // TODO: We should have a dummy service hub rather than change behaviour in tests

View File

@ -1,5 +1,6 @@
package net.corda.testing package net.corda.testing
import net.corda.core.internal.packageName
import org.apache.logging.log4j.Level import org.apache.logging.log4j.Level
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.core.LoggerContext 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 */ /** Removes custom configuration for the specified logger names */
fun reset(vararg names: String) { fun reset(vararg names: String) {
@ -35,7 +36,7 @@ object LogHelper {
loggerContext.updateLoggers(config) 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 */ /** Updates logging level for the specified Log4j logger name */
private fun setLevel(name: String, level: Level) { private fun setLevel(name: String, level: Level) {

View File

@ -4,12 +4,13 @@ import net.corda.core.contracts.ContractClassName
import net.corda.core.cordapp.Cordapp import net.corda.core.cordapp.Cordapp
import net.corda.core.internal.cordapp.CordappImpl import net.corda.core.internal.cordapp.CordappImpl
import net.corda.core.node.services.AttachmentId 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.CordappLoader
import net.corda.node.internal.cordapp.CordappProviderImpl import net.corda.node.internal.cordapp.CordappProviderImpl
import java.nio.file.Paths import java.nio.file.Paths
import java.util.* import java.util.*
class MockCordappProvider(cordappLoader: CordappLoader) : CordappProviderImpl(cordappLoader) { class MockCordappProvider(cordappLoader: CordappLoader, attachmentStorage: AttachmentStorage) : CordappProviderImpl(cordappLoader, attachmentStorage) {
val cordappRegistry = mutableListOf<Pair<Cordapp, AttachmentId>>() val cordappRegistry = mutableListOf<Pair<Cordapp, AttachmentId>>()
fun addMockCordapp(contractClassName: ContractClassName, attachments: MockAttachmentStorage) { fun addMockCordapp(contractClassName: ContractClassName, attachments: MockAttachmentStorage) {