Compare commits
9 Commits
master
...
feature/sm
| Author | SHA1 | Date |
|---|---|---|
|
|
8b9643b60a | |
|
|
d0c7ca03fb | |
|
|
18248a2773 | |
|
|
4a32a1c09d | |
|
|
6865e3fdb8 | |
|
|
0e381ff70c | |
|
|
5770faf7db | |
|
|
6b16393ccb | |
|
|
301c952ef9 |
|
|
@ -0,0 +1,9 @@
|
|||
package ru.touchin.common.spring.annotations
|
||||
|
||||
import org.springframework.context.annotation.Import
|
||||
import ru.touchin.common.spring.processors.RequiredByBeanDefinitionPostProcessor
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS)
|
||||
@Import(RequiredByBeanDefinitionPostProcessor::class)
|
||||
annotation class RequiredBy(vararg val value: String)
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package ru.touchin.common.spring.processors
|
||||
|
||||
import org.springframework.beans.BeansException
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
|
||||
import org.springframework.stereotype.Component
|
||||
import ru.touchin.common.spring.annotations.RequiredBy
|
||||
|
||||
@Component
|
||||
class RequiredByBeanDefinitionPostProcessor : BeanDefinitionRegistryPostProcessor {
|
||||
|
||||
@Throws(BeansException::class)
|
||||
override fun postProcessBeanDefinitionRegistry(registry: BeanDefinitionRegistry) {
|
||||
for (beanName in registry.beanDefinitionNames) {
|
||||
val beanClassName = registry.getBeanDefinition(beanName).beanClassName?:continue
|
||||
|
||||
getDependantBeanNames(beanClassName).forEach { dependantBeanName ->
|
||||
registry.getBeanDefinition(dependantBeanName).setDependsOn(beanName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(BeansException::class)
|
||||
override fun postProcessBeanFactory(beanFactory: ConfigurableListableBeanFactory) {
|
||||
}
|
||||
|
||||
private fun getDependantBeanNames(beanClassName: String): List<String> {
|
||||
val beanClass = Class.forName(beanClassName)
|
||||
var dependantBeans = emptyList<String>()
|
||||
|
||||
if (beanClass.isAnnotationPresent(RequiredBy::class.java)) {
|
||||
dependantBeans = beanClass.getAnnotation(RequiredBy::class.java).value.toList()
|
||||
}
|
||||
|
||||
return dependantBeans
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
|||
|
|
@ -58,3 +58,4 @@ include("s3-storage")
|
|||
include("server-info-spring-web")
|
||||
include("geoip-core")
|
||||
include("user-agent")
|
||||
include("smart-migration")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
plugins {
|
||||
id("kotlin")
|
||||
id("kotlin-spring")
|
||||
id("maven-publish")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
implementation("org.springframework.boot:spring-boot")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
implementation project(":common-spring")
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
@file:Suppress("unused")
|
||||
package ru.touchin.smartmigration
|
||||
|
||||
import org.springframework.stereotype.Component
|
||||
import ru.touchin.common.spring.annotations.RequiredBy
|
||||
import ru.touchin.smartmigration.logic.DataSourceSQL
|
||||
import ru.touchin.smartmigration.logic.factory.DataSourceSqlFactoryImpl
|
||||
import java.sql.Date
|
||||
import java.text.SimpleDateFormat
|
||||
import javax.annotation.PostConstruct
|
||||
import javax.sql.DataSource
|
||||
|
||||
private val SQL_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
|
||||
|
||||
private val CURRENT_TIME_SQL: String
|
||||
get() = SQL_DATE_FORMAT.format(Date(System.currentTimeMillis()))
|
||||
|
||||
@Component
|
||||
@RequiredBy("liquibase")
|
||||
class BeforeLiquibase(
|
||||
private val dataSource: DataSource
|
||||
) {
|
||||
|
||||
val dataSourceSql: DataSourceSQL = DataSourceSqlFactoryImpl()
|
||||
.getDataSourceSql(dataSource.connection.metaData.databaseProductName)
|
||||
|
||||
@PostConstruct
|
||||
fun doAction() {
|
||||
val buildNumber = System.getenv("BUILD_NUMBER")
|
||||
?: return
|
||||
|
||||
checkMigrationTable()
|
||||
|
||||
if (checkBuildMigrationExecuted(buildNumber)) {
|
||||
System.setProperty("spring.liquibase.enabled", "false")
|
||||
} else {
|
||||
insertMigration(buildNumber)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkBuildMigrationExecuted(buildNumber: String): Boolean {
|
||||
return dataSourceSql.getMigrationCheckSQL(buildNumber).let {
|
||||
dataSource.connection.createStatement().executeQuery(it).next()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkMigrationTable() {
|
||||
dataSourceSql.getTableCheckSQL().let {
|
||||
dataSource.connection.createStatement().execute(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun insertMigration(buildNumber: String) {
|
||||
dataSourceSql.getInsertMigrationSQL(buildNumber, CURRENT_TIME_SQL).let {
|
||||
dataSource.connection.createStatement().execute(it)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package ru.touchin.smartmigration
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("ru.touchin.smartmigration")
|
||||
open class SmartMigrationConfig
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package ru.touchin.smartmigration.annotation
|
||||
|
||||
import org.springframework.context.annotation.Import
|
||||
import ru.touchin.smartmigration.SmartMigrationConfig
|
||||
|
||||
@Import(SmartMigrationConfig::class)
|
||||
annotation class EnableSmartMigration
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package ru.touchin.smartmigration.logic
|
||||
|
||||
interface DataSourceSQL {
|
||||
|
||||
fun getTableCheckSQL(): String
|
||||
|
||||
fun getMigrationCheckSQL(buildNumber: String): String
|
||||
|
||||
fun getInsertMigrationSQL(buildNumber: String, formattedTime: String): String
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package ru.touchin.smartmigration.logic
|
||||
|
||||
import org.intellij.lang.annotations.Language
|
||||
|
||||
private const val MIGRATION_TABLE_NAME = "SMART_MIGRATION"
|
||||
|
||||
class PostgresDataSourceImpl: DataSourceSQL {
|
||||
|
||||
@Language("SQL")
|
||||
override fun getTableCheckSQL(): String {
|
||||
return """
|
||||
CREATE TABLE IF NOT EXISTS smart_migration (
|
||||
ID BIGSERIAL PRIMARY KEY,
|
||||
BUILD_NUMBER VARCHAR(255) NOT NULL,
|
||||
DATE timestamp NOT NULL
|
||||
);
|
||||
"""
|
||||
}
|
||||
|
||||
@Language("SQL")
|
||||
override fun getMigrationCheckSQL(buildNumber: String): String {
|
||||
return "SELECT * FROM $MIGRATION_TABLE_NAME WHERE BUILD_NUMBER = '$buildNumber'"
|
||||
}
|
||||
|
||||
@Language("SQL")
|
||||
override fun getInsertMigrationSQL(buildNumber: String, formattedTime: String): String {
|
||||
return """
|
||||
INSERT INTO $MIGRATION_TABLE_NAME (BUILD_NUMBER, DATE)
|
||||
VALUES ('$buildNumber', '$formattedTime');
|
||||
"""
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package ru.touchin.smartmigration.logic
|
||||
|
||||
import org.intellij.lang.annotations.Language
|
||||
|
||||
private const val MIGRATION_TABLE_NAME = "SMART_MIGRATION"
|
||||
|
||||
class SqlDatasourceImpl:DataSourceSQL {
|
||||
|
||||
@Language("TSQL")
|
||||
override fun getTableCheckSQL(): String {
|
||||
return """
|
||||
IF NOT EXISTS (
|
||||
SELECT * FROM sysobjects WHERE name = '$MIGRATION_TABLE_NAME' and xtype='U'
|
||||
)
|
||||
CREATE TABLE SMART_MIGRATION (
|
||||
ID BIGINT PRIMARY KEY IDENTITY ,
|
||||
BUILD_NUMBER VARCHAR(255) NOT NULL,
|
||||
DATE DATETIME NOT NULL
|
||||
);
|
||||
"""
|
||||
}
|
||||
|
||||
@Language("TSQL")
|
||||
override fun getMigrationCheckSQL(buildNumber: String): String {
|
||||
return "SELECT * FROM $MIGRATION_TABLE_NAME WHERE BUILD_NUMBER = '$buildNumber'"
|
||||
}
|
||||
|
||||
@Language("TSQL")
|
||||
override fun getInsertMigrationSQL(buildNumber: String, formattedTime: String): String {
|
||||
return """
|
||||
INSERT INTO $MIGRATION_TABLE_NAME (BUILD_NUMBER, DATE)
|
||||
VALUES ('$buildNumber', '$formattedTime');
|
||||
"""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package ru.touchin.smartmigration.logic.factory
|
||||
|
||||
import ru.touchin.smartmigration.logic.DataSourceSQL
|
||||
|
||||
interface DataSourceSqlFactory {
|
||||
|
||||
fun getDataSourceSql(driverName: String): DataSourceSQL
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package ru.touchin.smartmigration.logic.factory
|
||||
|
||||
import ru.touchin.smartmigration.logic.DataSourceSQL
|
||||
import ru.touchin.smartmigration.logic.PostgresDataSourceImpl
|
||||
import ru.touchin.smartmigration.logic.SqlDatasourceImpl
|
||||
|
||||
class DataSourceSqlFactoryImpl: DataSourceSqlFactory {
|
||||
|
||||
override fun getDataSourceSql(driverName: String): DataSourceSQL {
|
||||
return when(driverName){
|
||||
"Microsoft SQL Server" -> SqlDatasourceImpl()
|
||||
"PostgresSQL" -> PostgresDataSourceImpl()
|
||||
else -> {
|
||||
PostgresDataSourceImpl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue