| @@ -1,94 +0,0 @@ | |||
| package com.ffii.fpsms.modules.common.demo | |||
| import org.slf4j.LoggerFactory | |||
| import org.springframework.beans.factory.annotation.Value | |||
| import org.springframework.boot.ApplicationArguments | |||
| import org.springframework.boot.ApplicationRunner | |||
| import org.springframework.context.annotation.Profile | |||
| import org.springframework.core.annotation.Order | |||
| import org.springframework.core.io.ClassPathResource | |||
| import org.springframework.jdbc.core.JdbcTemplate | |||
| import org.springframework.stereotype.Component | |||
| import java.nio.charset.StandardCharsets | |||
| import java.sql.Connection | |||
| import javax.sql.DataSource | |||
| /** | |||
| * Extra fictional rows so demo screens and report downloads have something to show. | |||
| * Runs only after the base sandbox exists, and only against fpsms_demo. | |||
| */ | |||
| @Component | |||
| @Profile("db-demo") | |||
| @Order(2) | |||
| class DemoCoverageSeeder( | |||
| @Value("\${spring.datasource.jdbc-url}") private val jdbcUrl: String, | |||
| private val dataSource: DataSource, | |||
| private val jdbcTemplate: JdbcTemplate, | |||
| ) : ApplicationRunner { | |||
| private val log = LoggerFactory.getLogger(DemoCoverageSeeder::class.java) | |||
| override fun run(args: ApplicationArguments) { | |||
| val configuredName = databaseName(jdbcUrl) | |||
| val connectedName = dataSource.connection.use { it.catalog } | |||
| if (configuredName != DEMO_DATABASE || !DEMO_DATABASE.equals(connectedName, ignoreCase = true)) { | |||
| throw IllegalStateException( | |||
| "Demo coverage refused to start. Configured database is '$configuredName', connected database is '$connectedName'.", | |||
| ) | |||
| } | |||
| val already = jdbcTemplate.queryForObject( | |||
| "SELECT COUNT(*) FROM settings WHERE name = ?", | |||
| Int::class.java, | |||
| MARKER, | |||
| ) ?: 0 | |||
| if (already > 0) { | |||
| log.info("Demo coverage data already present.") | |||
| return | |||
| } | |||
| val script = ClassPathResource(SCRIPT).inputStream.use { it.readBytes().toString(StandardCharsets.UTF_8) } | |||
| dataSource.connection.use { connection -> | |||
| connection.autoCommit = false | |||
| try { | |||
| executeScript(connection, script) | |||
| connection.commit() | |||
| } catch (ex: Exception) { | |||
| connection.rollback() | |||
| throw IllegalStateException("Demo coverage data failed to load.", ex) | |||
| } | |||
| } | |||
| log.info("Demo coverage data loaded.") | |||
| } | |||
| private fun executeScript(connection: Connection, script: String) { | |||
| val statement = StringBuilder() | |||
| connection.createStatement().use { jdbc -> | |||
| for (rawLine in script.lineSequence()) { | |||
| val line = rawLine.trim() | |||
| if (line.isEmpty() || line.startsWith("--")) continue | |||
| statement.append(rawLine).append('\n') | |||
| if (line.endsWith(";")) { | |||
| val sql = statement.toString().trim().removeSuffix(";").trim() | |||
| statement.clear() | |||
| if (sql.isNotEmpty()) jdbc.execute(sql) | |||
| } | |||
| } | |||
| } | |||
| val tail = statement.toString().trim().removeSuffix(";").trim() | |||
| if (tail.isNotEmpty()) { | |||
| connection.createStatement().use { it.execute(tail) } | |||
| } | |||
| } | |||
| private fun databaseName(jdbcUrl: String): String? { | |||
| val path = jdbcUrl.substringBefore('?').substringAfter("://") | |||
| val slash = path.indexOf('/') | |||
| if (slash < 0 || slash == path.lastIndex) return null | |||
| return path.substring(slash + 1).trim().ifEmpty { null } | |||
| } | |||
| companion object { | |||
| private const val DEMO_DATABASE = "fpsms_demo" | |||
| private const val MARKER = "DEMO.coverage.v1" | |||
| private const val SCRIPT = "demo/demo-coverage.sql" | |||
| } | |||
| } | |||