[KEYCLOAK-14264] - Temporary multi-database support
This commit is contained in:
parent
8c7b69fc9e
commit
cc776204f0
6 changed files with 1086 additions and 35 deletions
|
@ -6,13 +6,16 @@ import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
|
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
|
||||||
import org.keycloak.runtime.KeycloakRecorder;
|
import org.keycloak.connections.jpa.DelegatingDialect;
|
||||||
|
|
||||||
|
import io.quarkus.arc.deployment.BeanContainerListenerBuildItem;
|
||||||
|
import io.quarkus.deployment.annotations.BuildProducer;
|
||||||
import io.quarkus.deployment.annotations.BuildStep;
|
import io.quarkus.deployment.annotations.BuildStep;
|
||||||
import io.quarkus.deployment.annotations.ExecutionTime;
|
import io.quarkus.deployment.annotations.ExecutionTime;
|
||||||
import io.quarkus.deployment.annotations.Record;
|
import io.quarkus.deployment.annotations.Record;
|
||||||
import io.quarkus.deployment.builditem.FeatureBuildItem;
|
import io.quarkus.deployment.builditem.FeatureBuildItem;
|
||||||
import io.quarkus.hibernate.orm.deployment.PersistenceUnitDescriptorBuildItem;
|
import io.quarkus.hibernate.orm.deployment.PersistenceUnitDescriptorBuildItem;
|
||||||
|
import org.keycloak.runtime.KeycloakRecorder;
|
||||||
|
|
||||||
class KeycloakProcessor {
|
class KeycloakProcessor {
|
||||||
|
|
||||||
|
@ -24,9 +27,17 @@ class KeycloakProcessor {
|
||||||
@Record(ExecutionTime.STATIC_INIT)
|
@Record(ExecutionTime.STATIC_INIT)
|
||||||
@BuildStep
|
@BuildStep
|
||||||
void configureHibernate(KeycloakRecorder recorder, List<PersistenceUnitDescriptorBuildItem> descriptors) {
|
void configureHibernate(KeycloakRecorder recorder, List<PersistenceUnitDescriptorBuildItem> descriptors) {
|
||||||
|
// TODO: ORM extension is going to provide build items that we can rely on to create our own PU instead of relying
|
||||||
|
// on the parsed descriptor and assume that the order that build steps are executed is always the same (although dialect
|
||||||
|
// is only created during runtime)
|
||||||
ParsedPersistenceXmlDescriptor unit = descriptors.get(0).getDescriptor();
|
ParsedPersistenceXmlDescriptor unit = descriptors.get(0).getDescriptor();
|
||||||
unit.setTransactionType(PersistenceUnitTransactionType.JTA);
|
unit.setTransactionType(PersistenceUnitTransactionType.JTA);
|
||||||
unit.getProperties().setProperty(AvailableSettings.DIALECT,
|
unit.getProperties().setProperty(AvailableSettings.DIALECT, DelegatingDialect.class.getName());
|
||||||
KeycloakRecorder.CONFIG.getRawValue("quarkus.datasource.dialect"));
|
}
|
||||||
|
|
||||||
|
@Record(ExecutionTime.STATIC_INIT)
|
||||||
|
@BuildStep
|
||||||
|
void configureDataSource(KeycloakRecorder recorder, BuildProducer<BeanContainerListenerBuildItem> container) {
|
||||||
|
container.produce(new BeanContainerListenerBuildItem(recorder.configureDataSource()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,11 @@
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<quarkus.version>1.4.2.Final</quarkus.version>
|
<quarkus.version>999-SNAPSHOT</quarkus.version>
|
||||||
<resteasy.version>4.4.2.Final</resteasy.version>
|
<resteasy.version>4.5.3.Final</resteasy.version>
|
||||||
<jackson.version>2.10.2</jackson.version>
|
<jackson.version>2.10.2</jackson.version>
|
||||||
<jackson.databind.version>${jackson.version}</jackson.databind.version>
|
<jackson.databind.version>${jackson.version}</jackson.databind.version>
|
||||||
<hibernate.version>5.4.14.Final</hibernate.version>
|
<hibernate.version>5.4.16.Final</hibernate.version>
|
||||||
<snakeyaml.version>1.20</snakeyaml.version>
|
<snakeyaml.version>1.20</snakeyaml.version>
|
||||||
|
|
||||||
<surefire-plugin.version>2.22.0</surefire-plugin.version>
|
<surefire-plugin.version>2.22.0</surefire-plugin.version>
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,6 +13,9 @@ import liquibase.database.Database;
|
||||||
import liquibase.logging.Logger;
|
import liquibase.logging.Logger;
|
||||||
import liquibase.servicelocator.DefaultPackageScanClassResolver;
|
import liquibase.servicelocator.DefaultPackageScanClassResolver;
|
||||||
import liquibase.servicelocator.ServiceLocator;
|
import liquibase.servicelocator.ServiceLocator;
|
||||||
|
import org.keycloak.connections.jpa.updater.liquibase.PostgresPlusDatabase;
|
||||||
|
import org.keycloak.connections.jpa.updater.liquibase.UpdatedMariaDBDatabase;
|
||||||
|
import org.keycloak.connections.jpa.updater.liquibase.UpdatedMySqlDatabase;
|
||||||
|
|
||||||
public class FastServiceLocator extends ServiceLocator {
|
public class FastServiceLocator extends ServiceLocator {
|
||||||
|
|
||||||
|
|
|
@ -75,29 +75,30 @@ public class QuarkusLiquibaseConnectionProvider implements LiquibaseConnectionPr
|
||||||
protected void baseLiquibaseInitialization(KeycloakSession session) {
|
protected void baseLiquibaseInitialization(KeycloakSession session) {
|
||||||
resourceAccessor = new ClassLoaderResourceAccessor(getClass().getClassLoader());
|
resourceAccessor = new ClassLoaderResourceAccessor(getClass().getClassLoader());
|
||||||
FastServiceLocator locator = (FastServiceLocator) ServiceLocator.getInstance();
|
FastServiceLocator locator = (FastServiceLocator) ServiceLocator.getInstance();
|
||||||
|
|
||||||
JpaConnectionProviderFactory jpaConnectionProvider = (JpaConnectionProviderFactory) session
|
JpaConnectionProviderFactory jpaConnectionProvider = (JpaConnectionProviderFactory) session
|
||||||
.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class);
|
.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class);
|
||||||
|
|
||||||
|
// register our custom databases
|
||||||
|
locator.register(new PostgresPlusDatabase());
|
||||||
|
locator.register(new UpdatedMySqlDatabase());
|
||||||
|
locator.register(new UpdatedMariaDBDatabase());
|
||||||
|
|
||||||
// registers only the database we are using
|
// registers only the database we are using
|
||||||
try (Connection connection = jpaConnectionProvider.getConnection()) {
|
try (Connection connection = jpaConnectionProvider.getConnection()) {
|
||||||
Database database = DatabaseFactory.getInstance()
|
Database database = DatabaseFactory.getInstance()
|
||||||
.findCorrectDatabaseImplementation(new JdbcConnection(connection));
|
.findCorrectDatabaseImplementation(new JdbcConnection(connection));
|
||||||
DatabaseFactory.getInstance().clearRegistry();
|
if (database.getDatabaseProductName().equals(MySQLDatabase.PRODUCT_NAME)) {
|
||||||
if (database.getDatabaseProductName().equals(PostgresDatabase.PRODUCT_NAME)) {
|
|
||||||
// Adding PostgresPlus support to liquibase
|
|
||||||
locator.register(new PostgresPlusDatabase());
|
|
||||||
} else if (database.getDatabaseProductName().equals(MySQLDatabase.PRODUCT_NAME)) {
|
|
||||||
// Adding newer version of MySQL/MariaDB support to liquibase
|
|
||||||
locator.register(new UpdatedMySqlDatabase());
|
|
||||||
// Adding CustomVarcharType for MySQL 8 and newer
|
// Adding CustomVarcharType for MySQL 8 and newer
|
||||||
DataTypeFactory.getInstance().register(MySQL8VarcharType.class);
|
DataTypeFactory.getInstance().register(MySQL8VarcharType.class);
|
||||||
} else if (database.getDatabaseProductName().equals(MariaDBDatabase.PRODUCT_NAME)) {
|
} else if (database.getDatabaseProductName().equals(MariaDBDatabase.PRODUCT_NAME)) {
|
||||||
locator.register(new UpdatedMariaDBDatabase());
|
|
||||||
// Adding CustomVarcharType for MySQL 8 and newer
|
// Adding CustomVarcharType for MySQL 8 and newer
|
||||||
DataTypeFactory.getInstance().register(MySQL8VarcharType.class);
|
DataTypeFactory.getInstance().register(MySQL8VarcharType.class);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
DatabaseFactory.getInstance().clearRegistry();
|
||||||
locator.register(database);
|
locator.register(database);
|
||||||
|
} catch (Exception cause) {
|
||||||
|
throw new RuntimeException("Failed to configure Liquibase database", cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
// disables XML validation
|
// disables XML validation
|
||||||
|
@ -119,9 +120,6 @@ public class QuarkusLiquibaseConnectionProvider implements LiquibaseConnectionPr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception cause) {
|
|
||||||
throw new RuntimeException("Failed to configure Liquibase database", cause);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -3,6 +3,10 @@ package org.keycloak.runtime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.quarkus.agroal.runtime.DataSourceSupport;
|
||||||
|
import io.quarkus.arc.runtime.BeanContainer;
|
||||||
|
import io.quarkus.arc.runtime.BeanContainerListener;
|
||||||
|
import io.quarkus.datasource.common.runtime.DataSourceUtil;
|
||||||
import org.keycloak.connections.liquibase.FastServiceLocator;
|
import org.keycloak.connections.liquibase.FastServiceLocator;
|
||||||
import org.keycloak.connections.liquibase.KeycloakLogger;
|
import org.keycloak.connections.liquibase.KeycloakLogger;
|
||||||
|
|
||||||
|
@ -21,6 +25,10 @@ public class KeycloakRecorder {
|
||||||
CONFIG = (SmallRyeConfig) SmallRyeConfigProviderResolver.instance().getConfig();
|
CONFIG = (SmallRyeConfig) SmallRyeConfigProviderResolver.instance().getConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getDatabaseDialect() {
|
||||||
|
return CONFIG.getRawValue("quarkus.datasource.dialect");
|
||||||
|
}
|
||||||
|
|
||||||
public void configureLiquibase(Map<String, List<String>> services) {
|
public void configureLiquibase(Map<String, List<String>> services) {
|
||||||
LogFactory.setInstance(new LogFactory() {
|
LogFactory.setInstance(new LogFactory() {
|
||||||
KeycloakLogger logger = new KeycloakLogger();
|
KeycloakLogger logger = new KeycloakLogger();
|
||||||
|
@ -37,4 +45,16 @@ public class KeycloakRecorder {
|
||||||
});
|
});
|
||||||
ServiceLocator.setInstance(new FastServiceLocator(services));
|
ServiceLocator.setInstance(new FastServiceLocator(services));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BeanContainerListener configureDataSource() {
|
||||||
|
return new BeanContainerListener() {
|
||||||
|
@Override
|
||||||
|
public void created(BeanContainer container) {
|
||||||
|
String driver = CONFIG.getRawValue("quarkus.datasource.driver");
|
||||||
|
DataSourceSupport instance = container.instance(DataSourceSupport.class);
|
||||||
|
DataSourceSupport.Entry entry = instance.entries.get(DataSourceUtil.DEFAULT_DATASOURCE_NAME);
|
||||||
|
entry.resolvedDriverClass = driver;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue