[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.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.ExecutionTime;
|
||||
import io.quarkus.deployment.annotations.Record;
|
||||
import io.quarkus.deployment.builditem.FeatureBuildItem;
|
||||
import io.quarkus.hibernate.orm.deployment.PersistenceUnitDescriptorBuildItem;
|
||||
import org.keycloak.runtime.KeycloakRecorder;
|
||||
|
||||
class KeycloakProcessor {
|
||||
|
||||
|
@ -24,9 +27,17 @@ class KeycloakProcessor {
|
|||
@Record(ExecutionTime.STATIC_INIT)
|
||||
@BuildStep
|
||||
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();
|
||||
unit.setTransactionType(PersistenceUnitTransactionType.JTA);
|
||||
unit.getProperties().setProperty(AvailableSettings.DIALECT,
|
||||
KeycloakRecorder.CONFIG.getRawValue("quarkus.datasource.dialect"));
|
||||
unit.getProperties().setProperty(AvailableSettings.DIALECT, DelegatingDialect.class.getName());
|
||||
}
|
||||
|
||||
@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>
|
||||
|
||||
<properties>
|
||||
<quarkus.version>1.4.2.Final</quarkus.version>
|
||||
<resteasy.version>4.4.2.Final</resteasy.version>
|
||||
<quarkus.version>999-SNAPSHOT</quarkus.version>
|
||||
<resteasy.version>4.5.3.Final</resteasy.version>
|
||||
<jackson.version>2.10.2</jackson.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>
|
||||
|
||||
<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.servicelocator.DefaultPackageScanClassResolver;
|
||||
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 {
|
||||
|
||||
|
|
|
@ -75,52 +75,50 @@ public class QuarkusLiquibaseConnectionProvider implements LiquibaseConnectionPr
|
|||
protected void baseLiquibaseInitialization(KeycloakSession session) {
|
||||
resourceAccessor = new ClassLoaderResourceAccessor(getClass().getClassLoader());
|
||||
FastServiceLocator locator = (FastServiceLocator) ServiceLocator.getInstance();
|
||||
|
||||
JpaConnectionProviderFactory jpaConnectionProvider = (JpaConnectionProviderFactory) session
|
||||
.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
|
||||
try (Connection connection = jpaConnectionProvider.getConnection()) {
|
||||
Database database = DatabaseFactory.getInstance()
|
||||
.findCorrectDatabaseImplementation(new JdbcConnection(connection));
|
||||
DatabaseFactory.getInstance().clearRegistry();
|
||||
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());
|
||||
if (database.getDatabaseProductName().equals(MySQLDatabase.PRODUCT_NAME)) {
|
||||
// Adding CustomVarcharType for MySQL 8 and newer
|
||||
DataTypeFactory.getInstance().register(MySQL8VarcharType.class);
|
||||
} else if (database.getDatabaseProductName().equals(MariaDBDatabase.PRODUCT_NAME)) {
|
||||
locator.register(new UpdatedMariaDBDatabase());
|
||||
// Adding CustomVarcharType for MySQL 8 and newer
|
||||
DataTypeFactory.getInstance().register(MySQL8VarcharType.class);
|
||||
} else {
|
||||
locator.register(database);
|
||||
}
|
||||
|
||||
// disables XML validation
|
||||
for (ChangeLogParser parser : ChangeLogParserFactory.getInstance().getParsers()) {
|
||||
if (parser instanceof XMLChangeLogSAXParser) {
|
||||
Method getSaxParserFactory = null;
|
||||
try {
|
||||
getSaxParserFactory = XMLChangeLogSAXParser.class.getDeclaredMethod("getSaxParserFactory");
|
||||
getSaxParserFactory.setAccessible(true);
|
||||
SAXParserFactory saxParserFactory = (SAXParserFactory) getSaxParserFactory.invoke(parser);
|
||||
saxParserFactory.setValidating(false);
|
||||
saxParserFactory.setSchema(null);
|
||||
} catch (Exception e) {
|
||||
logger.warnf("Failed to disable liquibase XML validations");
|
||||
} finally {
|
||||
if (getSaxParserFactory != null) {
|
||||
getSaxParserFactory.setAccessible(false);
|
||||
}
|
||||
DatabaseFactory.getInstance().clearRegistry();
|
||||
locator.register(database);
|
||||
} catch (Exception cause) {
|
||||
throw new RuntimeException("Failed to configure Liquibase database", cause);
|
||||
}
|
||||
|
||||
// disables XML validation
|
||||
for (ChangeLogParser parser : ChangeLogParserFactory.getInstance().getParsers()) {
|
||||
if (parser instanceof XMLChangeLogSAXParser) {
|
||||
Method getSaxParserFactory = null;
|
||||
try {
|
||||
getSaxParserFactory = XMLChangeLogSAXParser.class.getDeclaredMethod("getSaxParserFactory");
|
||||
getSaxParserFactory.setAccessible(true);
|
||||
SAXParserFactory saxParserFactory = (SAXParserFactory) getSaxParserFactory.invoke(parser);
|
||||
saxParserFactory.setValidating(false);
|
||||
saxParserFactory.setSchema(null);
|
||||
} catch (Exception e) {
|
||||
logger.warnf("Failed to disable liquibase XML validations");
|
||||
} finally {
|
||||
if (getSaxParserFactory != null) {
|
||||
getSaxParserFactory.setAccessible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception cause) {
|
||||
throw new RuntimeException("Failed to configure Liquibase database", cause);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,10 @@ package org.keycloak.runtime;
|
|||
import java.util.List;
|
||||
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.KeycloakLogger;
|
||||
|
||||
|
@ -21,6 +25,10 @@ public class KeycloakRecorder {
|
|||
CONFIG = (SmallRyeConfig) SmallRyeConfigProviderResolver.instance().getConfig();
|
||||
}
|
||||
|
||||
public static String getDatabaseDialect() {
|
||||
return CONFIG.getRawValue("quarkus.datasource.dialect");
|
||||
}
|
||||
|
||||
public void configureLiquibase(Map<String, List<String>> services) {
|
||||
LogFactory.setInstance(new LogFactory() {
|
||||
KeycloakLogger logger = new KeycloakLogger();
|
||||
|
@ -37,4 +45,16 @@ public class KeycloakRecorder {
|
|||
});
|
||||
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