From c474c04503004f2b2f4c37e23ab4b6250b911651 Mon Sep 17 00:00:00 2001 From: Tudor Malene Date: Thu, 7 Jun 2018 14:05:28 +0100 Subject: [PATCH] ENT-1837 better error message on db failure (#3318) --- .../internal/persistence/CordaPersistence.kt | 4 +++- .../net/corda/node/internal/AbstractNode.kt | 23 +++++++++++++++---- .../net/corda/node/internal/NodeStartup.kt | 4 ++++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/CordaPersistence.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/CordaPersistence.kt index 850436efa6..48087de79b 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/CordaPersistence.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/CordaPersistence.kt @@ -264,4 +264,6 @@ private fun Throwable.hasSQLExceptionCause(): Boolean = null -> false is SQLException -> true else -> cause?.hasSQLExceptionCause() ?: false - } \ No newline at end of file + } + +class CouldNotCreateDataSourceException(override val message: String?, override val cause: Throwable? = null) : Exception() \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 1cebff87fc..bfe1856851 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -3,6 +3,7 @@ package net.corda.node.internal import com.codahale.metrics.MetricRegistry import com.google.common.collect.MutableClassToInstanceMap import com.google.common.util.concurrent.MoreExecutors +import com.zaxxer.hikari.pool.HikariPool import net.corda.confidential.SwapIdentitiesFlow import net.corda.confidential.SwapIdentitiesHandler import net.corda.core.CordaException @@ -70,6 +71,7 @@ import net.corda.nodeapi.internal.NodeInfoAndSigned import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.persistence.CordaPersistence +import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException import net.corda.nodeapi.internal.persistence.DatabaseConfig import net.corda.nodeapi.internal.persistence.HibernateConfiguration import net.corda.nodeapi.internal.storeLegalIdentity @@ -219,7 +221,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, networkMapCache.clearNetworkMapCache() } } - + open fun start(): StartedNode { check(started == null) { "Node has already been started" } if (configuration.devMode) { @@ -1001,6 +1003,11 @@ class ConfigurationException(message: String) : CordaException(message) */ internal class NetworkMapCacheEmptyException : Exception() +/** + * Creates the connection pool to the database. + * + *@throws [CouldNotCreateDataSourceException] + */ fun configureDatabase(hikariProperties: Properties, databaseConfig: DatabaseConfig, wellKnownPartyFromX500Name: (CordaX500Name) -> Party?, @@ -1011,7 +1018,15 @@ fun configureDatabase(hikariProperties: Properties, // so we end up providing both descriptor and converter. We should re-examine this in later versions to see if // either Hibernate can be convinced to stop warning, use the descriptor by default, or something else. JavaTypeDescriptorRegistry.INSTANCE.addDescriptor(AbstractPartyDescriptor(wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous)) - val dataSource = DataSourceFactory.createDataSource(hikariProperties) - val attributeConverters = listOf(AbstractPartyToX500NameAsStringConverter(wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous)) - return CordaPersistence(dataSource, databaseConfig, schemaService.schemaOptions.keys, attributeConverters) + try { + val dataSource = DataSourceFactory.createDataSource(hikariProperties) + val attributeConverters = listOf(AbstractPartyToX500NameAsStringConverter(wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous)) + return CordaPersistence(dataSource, databaseConfig, schemaService.schemaOptions.keys, attributeConverters) + } catch (ex: Exception) { + when { + ex is HikariPool.PoolInitializationException -> throw CouldNotCreateDataSourceException("Could not connect to the database. Please check your JDBC connection URL, or the connectivity to the database.") + ex.cause is ClassNotFoundException -> throw CouldNotCreateDataSourceException("Could not find the database driver class. Please add it to the 'drivers' folders. See: https://docs.corda.net/corda-configuration-file.html") + else -> throw CouldNotCreateDataSourceException("Could not create the DataSource: ${ex.message}", ex) + } + } } diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt index 6da2426aed..1c0dd7bf77 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt @@ -27,6 +27,7 @@ import net.corda.node.utilities.registration.HTTPNetworkRegistrationService import net.corda.node.utilities.registration.NodeRegistrationHelper import net.corda.nodeapi.internal.addShutdownHook import net.corda.nodeapi.internal.config.UnknownConfigurationKeysException +import net.corda.nodeapi.internal.persistence.CouldNotCreateDataSourceException import net.corda.tools.shell.InteractiveShell import org.fusesource.jansi.Ansi import org.fusesource.jansi.AnsiConsole @@ -128,6 +129,9 @@ open class NodeStartup(val args: Array) { try { cmdlineOptions.baseDirectory.createDirectories() startNode(conf, versionInfo, startTime, cmdlineOptions) + } catch (e: CouldNotCreateDataSourceException) { + logger.error(e.message, e.cause) + return false } catch (e: CheckpointIncompatibleException) { logger.error(e.message) return false