CORDA-2942: Allow exception from CordaService creation to propagate (#5884)

* CORDA-2942: Allow exception from `CordaService` creation to propagate

It will ultimately be thrown from Node's `start()` method terminating the node start-up sequence.

* CORDA-2942: Be lenient when retrievign the name of the Notary

Some tests setup such that they do nto have Notary running.
This commit is contained in:
Viktor Kolomeyko 2020-01-24 10:20:08 +00:00 committed by Matthew Nesbit
parent 1380779a9c
commit 42a2ed98e2
4 changed files with 7 additions and 8 deletions

View File

@ -1906,7 +1906,6 @@
<ID>MaxLineLength:CordaRPCOps.kt$sorting: Sort = Sort(emptySet())</ID> <ID>MaxLineLength:CordaRPCOps.kt$sorting: Sort = Sort(emptySet())</ID>
<ID>MaxLineLength:CordaRPCOpsImplTest.kt$CordaRPCOpsImplTest$assertThatCode { rpc.startFlow(::SoftLock, cash.ref, Duration.ofSeconds(1)).returnValue.getOrThrow() }.doesNotThrowAnyException()</ID> <ID>MaxLineLength:CordaRPCOpsImplTest.kt$CordaRPCOpsImplTest$assertThatCode { rpc.startFlow(::SoftLock, cash.ref, Duration.ofSeconds(1)).returnValue.getOrThrow() }.doesNotThrowAnyException()</ID>
<ID>MaxLineLength:CordaRPCOpsImplTest.kt$CordaRPCOpsImplTest$val cash = rpc.startFlow(::CashIssueFlow, 10.DOLLARS, issuerRef, notary).returnValue.getOrThrow().stx.tx.outRefsOfType&lt;Cash.State&gt;().single()</ID> <ID>MaxLineLength:CordaRPCOpsImplTest.kt$CordaRPCOpsImplTest$val cash = rpc.startFlow(::CashIssueFlow, 10.DOLLARS, issuerRef, notary).returnValue.getOrThrow().stx.tx.outRefsOfType&lt;Cash.State&gt;().single()</ID>
<ID>MaxLineLength:CordaSSHAuthInfo.kt$CordaSSHAuthInfo : AuthInfo</ID>
<ID>MaxLineLength:CordaServiceTest.kt$CordaServiceTest$mockNet = MockNetwork(MockNetworkParameters(threadPerNode = true, cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, enclosedCordapp())))</ID> <ID>MaxLineLength:CordaServiceTest.kt$CordaServiceTest$mockNet = MockNetwork(MockNetworkParameters(threadPerNode = true, cordappsForAllNodes = listOf(FINANCE_CONTRACTS_CORDAPP, enclosedCordapp())))</ID>
<ID>MaxLineLength:CordaServiceTest.kt$CordaServiceTest.CordaServiceThatRequiresThreadContextClassLoader$assertNotNull(Thread.currentThread().contextClassLoader, "thread context classloader should not be null during service initialisation")</ID> <ID>MaxLineLength:CordaServiceTest.kt$CordaServiceTest.CordaServiceThatRequiresThreadContextClassLoader$assertNotNull(Thread.currentThread().contextClassLoader, "thread context classloader should not be null during service initialisation")</ID>
<ID>MaxLineLength:CordaUtils.kt$ private fun owns(packageName: String, fullClassName: String): Boolean</ID> <ID>MaxLineLength:CordaUtils.kt$ private fun owns(packageName: String, fullClassName: String): Boolean</ID>
@ -3889,6 +3888,7 @@
<ID>SpreadOperator:WithContracts.kt$WithContracts$(owner, magicNumber, *others)</ID> <ID>SpreadOperator:WithContracts.kt$WithContracts$(owner, magicNumber, *others)</ID>
<ID>SpreadOperator:X509Utilities.kt$X509Utilities$(*certificates)</ID> <ID>SpreadOperator:X509Utilities.kt$X509Utilities$(*certificates)</ID>
<ID>ThrowsCount:AMQPTypeIdentifierParser.kt$AMQPTypeIdentifierParser$// Make sure our inputs aren't designed to blow things up. private fun validate(typeString: String)</ID> <ID>ThrowsCount:AMQPTypeIdentifierParser.kt$AMQPTypeIdentifierParser$// Make sure our inputs aren't designed to blow things up. private fun validate(typeString: String)</ID>
<ID>ThrowsCount:AbstractNode.kt$AbstractNode$private fun installCordaServices()</ID>
<ID>ThrowsCount:AbstractNode.kt$fun CordaPersistence.startHikariPool(hikariProperties: Properties, databaseConfig: DatabaseConfig, schemas: Set&lt;MappedSchema&gt;, metricRegistry: MetricRegistry? = null, cordappLoader: CordappLoader? = null, currentDir: Path? = null, ourName: CordaX500Name)</ID> <ID>ThrowsCount:AbstractNode.kt$fun CordaPersistence.startHikariPool(hikariProperties: Properties, databaseConfig: DatabaseConfig, schemas: Set&lt;MappedSchema&gt;, metricRegistry: MetricRegistry? = null, cordappLoader: CordappLoader? = null, currentDir: Path? = null, ourName: CordaX500Name)</ID>
<ID>ThrowsCount:ArtemisMessagingServer.kt$ArtemisMessagingServer$// TODO: Maybe wrap [IOException] on a key store load error so that it's clearly splitting key store loading from // Artemis IO errors @Throws(IOException::class, AddressBindingException::class, KeyStoreException::class) private fun configureAndStartServer()</ID> <ID>ThrowsCount:ArtemisMessagingServer.kt$ArtemisMessagingServer$// TODO: Maybe wrap [IOException] on a key store load error so that it's clearly splitting key store loading from // Artemis IO errors @Throws(IOException::class, AddressBindingException::class, KeyStoreException::class) private fun configureAndStartServer()</ID>
<ID>ThrowsCount:BrokerJaasLoginModule.kt$BaseBrokerJaasLoginModule$@Suppress("DEPRECATION") // should use java.security.cert.X509Certificate protected fun getUsernamePasswordAndCerts(): Triple&lt;String, String, Array&lt;javax.security.cert.X509Certificate&gt;?&gt;</ID> <ID>ThrowsCount:BrokerJaasLoginModule.kt$BaseBrokerJaasLoginModule$@Suppress("DEPRECATION") // should use java.security.cert.X509Certificate protected fun getUsernamePasswordAndCerts(): Triple&lt;String, String, Array&lt;javax.security.cert.X509Certificate&gt;?&gt;</ID>
@ -4406,9 +4406,6 @@
<ID>WildcardImport:CertificateRevocationListNodeTests.kt$import net.corda.nodeapi.internal.crypto.*</ID> <ID>WildcardImport:CertificateRevocationListNodeTests.kt$import net.corda.nodeapi.internal.crypto.*</ID>
<ID>WildcardImport:CertificateRevocationListNodeTests.kt$import org.bouncycastle.asn1.x509.*</ID> <ID>WildcardImport:CertificateRevocationListNodeTests.kt$import org.bouncycastle.asn1.x509.*</ID>
<ID>WildcardImport:CertificatesUtils.kt$import net.corda.nodeapi.internal.crypto.*</ID> <ID>WildcardImport:CertificatesUtils.kt$import net.corda.nodeapi.internal.crypto.*</ID>
<ID>WildcardImport:CheckpointDumperImpl.kt$import com.fasterxml.jackson.databind.*</ID>
<ID>WildcardImport:CheckpointDumperImpl.kt$import net.corda.core.internal.*</ID>
<ID>WildcardImport:CheckpointDumperImpl.kt$import net.corda.node.services.statemachine.*</ID>
<ID>WildcardImport:CheckpointSerializationAPI.kt$import net.corda.core.serialization.*</ID> <ID>WildcardImport:CheckpointSerializationAPI.kt$import net.corda.core.serialization.*</ID>
<ID>WildcardImport:ClassCarpenter.kt$import org.objectweb.asm.Opcodes.*</ID> <ID>WildcardImport:ClassCarpenter.kt$import org.objectweb.asm.Opcodes.*</ID>
<ID>WildcardImport:ClassCarpenterTestUtils.kt$import net.corda.serialization.internal.amqp.*</ID> <ID>WildcardImport:ClassCarpenterTestUtils.kt$import net.corda.serialization.internal.amqp.*</ID>
@ -4561,7 +4558,6 @@
<ID>WildcardImport:FlowFrameworkTests.kt$import net.corda.core.flows.*</ID> <ID>WildcardImport:FlowFrameworkTests.kt$import net.corda.core.flows.*</ID>
<ID>WildcardImport:FlowFrameworkTests.kt$import net.corda.testing.node.internal.*</ID> <ID>WildcardImport:FlowFrameworkTests.kt$import net.corda.testing.node.internal.*</ID>
<ID>WildcardImport:FlowFrameworkTripartyTests.kt$import net.corda.testing.node.internal.*</ID> <ID>WildcardImport:FlowFrameworkTripartyTests.kt$import net.corda.testing.node.internal.*</ID>
<ID>WildcardImport:FlowLogic.kt$import net.corda.core.internal.*</ID>
<ID>WildcardImport:FlowLogicRefFactoryImpl.kt$import net.corda.core.flows.*</ID> <ID>WildcardImport:FlowLogicRefFactoryImpl.kt$import net.corda.core.flows.*</ID>
<ID>WildcardImport:FlowMatchers.kt$import net.corda.testing.internal.matchers.*</ID> <ID>WildcardImport:FlowMatchers.kt$import net.corda.testing.internal.matchers.*</ID>
<ID>WildcardImport:FlowOverrideTests.kt$import net.corda.core.flows.*</ID> <ID>WildcardImport:FlowOverrideTests.kt$import net.corda.core.flows.*</ID>

View File

@ -8,7 +8,8 @@ API: Service Classes
==================== ====================
Service classes are long-lived instances that can trigger or be triggered by flows from within a node. A Service class is limited to a Service classes are long-lived instances that can trigger or be triggered by flows from within a node. A Service class is limited to a
single instance per node. During startup, the node handles the creation of the service. single instance per node. During startup, the node handles the creation of the service. If there is problem when instantiating service
the node will report in the log what the problem was and terminate.
Services allow related, reusable, functions to be separated into their own class where their functionality is Services allow related, reusable, functions to be separated into their own class where their functionality is
grouped together. These functions can then be called from other services or flows. grouped together. These functions can then be called from other services or flows.

View File

@ -80,7 +80,7 @@ class CordaServiceIssueOnceAtStartupTests {
// Without the "secret" property service upon instantiation will be subscribed to lifecycle events which would be unwanted. // Without the "secret" property service upon instantiation will be subscribed to lifecycle events which would be unwanted.
// Also do not do this for Notary // Also do not do this for Notary
val myName = services.myInfo.legalIdentities.single().name val myName = services.myInfo.legalIdentities.single().name
val notaryName = services.networkMapCache.notaryIdentities.single().name val notaryName = services.networkMapCache.notaryIdentities.firstOrNull()?.name
if(java.lang.Boolean.getBoolean(armedPropName) && myName != notaryName) { if(java.lang.Boolean.getBoolean(armedPropName) && myName != notaryName) {
services.register(observer = MyServiceLifecycleObserver()) services.register(observer = MyServiceLifecycleObserver())
} else { } else {

View File

@ -757,7 +757,6 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
// This sets the Cordapp classloader on the contextClassLoader of the current thread, prior to initializing services // This sets the Cordapp classloader on the contextClassLoader of the current thread, prior to initializing services
// Needed because of bug CORDA-2653 - some Corda services can utilise third-party libraries that require access to // Needed because of bug CORDA-2653 - some Corda services can utilise third-party libraries that require access to
// the Thread context class loader // the Thread context class loader
val oldContextClassLoader: ClassLoader? = Thread.currentThread().contextClassLoader val oldContextClassLoader: ClassLoader? = Thread.currentThread().contextClassLoader
try { try {
Thread.currentThread().contextClassLoader = cordappLoader.appClassLoader Thread.currentThread().contextClassLoader = cordappLoader.appClassLoader
@ -768,14 +767,17 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
} catch (e: NoSuchMethodException) { } catch (e: NoSuchMethodException) {
log.error("${it.name}, as a Corda service, must have a constructor with a single parameter of type " + log.error("${it.name}, as a Corda service, must have a constructor with a single parameter of type " +
ServiceHub::class.java.name) ServiceHub::class.java.name)
throw e
} catch (e: ServiceInstantiationException) { } catch (e: ServiceInstantiationException) {
if (e.cause != null) { if (e.cause != null) {
log.error("Corda service ${it.name} failed to instantiate. Reason was: ${e.cause?.rootMessage}", e.cause) log.error("Corda service ${it.name} failed to instantiate. Reason was: ${e.cause?.rootMessage}", e.cause)
} else { } else {
log.error("Corda service ${it.name} failed to instantiate", e) log.error("Corda service ${it.name} failed to instantiate", e)
} }
throw e
} catch (e: Exception) { } catch (e: Exception) {
log.error("Unable to install Corda service ${it.name}", e) log.error("Unable to install Corda service ${it.name}", e)
throw e
} }
} }
} finally { } finally {