Details
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProvider.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProvider.java
index 5874084..7c48499 100644
--- a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProvider.java
@@ -48,32 +48,35 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
private CustomLockService lockService;
private Connection dbConnection;
+ private boolean initialized = false;
private int maxAttempts = DEFAULT_MAX_ATTEMPTS;
public LiquibaseDBLockProvider(LiquibaseDBLockProviderFactory factory, KeycloakSession session) {
this.factory = factory;
this.session = session;
- init();
}
- private void init() {
- LiquibaseConnectionProvider liquibaseProvider = session.getProvider(LiquibaseConnectionProvider.class);
- JpaConnectionProviderFactory jpaProviderFactory = (JpaConnectionProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class);
+ private void lazyInit() {
+ if (!initialized) {
+ LiquibaseConnectionProvider liquibaseProvider = session.getProvider(LiquibaseConnectionProvider.class);
+ JpaConnectionProviderFactory jpaProviderFactory = (JpaConnectionProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class);
- this.dbConnection = jpaProviderFactory.getConnection();
- String defaultSchema = jpaProviderFactory.getSchema();
+ this.dbConnection = jpaProviderFactory.getConnection();
+ String defaultSchema = jpaProviderFactory.getSchema();
- try {
- Liquibase liquibase = liquibaseProvider.getLiquibase(dbConnection, defaultSchema);
+ try {
+ Liquibase liquibase = liquibaseProvider.getLiquibase(dbConnection, defaultSchema);
- this.lockService = new CustomLockService();
- lockService.setChangeLogLockWaitTime(factory.getLockWaitTimeoutMillis());
- lockService.setDatabase(liquibase.getDatabase());
- } catch (LiquibaseException exception) {
- safeRollbackConnection();
- safeCloseConnection();
- throw new IllegalStateException(exception);
+ this.lockService = new CustomLockService();
+ lockService.setChangeLogLockWaitTime(factory.getLockWaitTimeoutMillis());
+ lockService.setDatabase(liquibase.getDatabase());
+ initialized = true;
+ } catch (LiquibaseException exception) {
+ safeRollbackConnection();
+ safeCloseConnection();
+ throw new IllegalStateException(exception);
+ }
}
}
@@ -82,12 +85,15 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
safeCloseConnection();
this.dbConnection = null;
this.lockService = null;
- init();
+ initialized = false;
+ lazyInit();
}
@Override
public void waitForLock() {
+ lazyInit();
+
while (maxAttempts > 0) {
try {
lockService.waitForLock();
@@ -110,6 +116,8 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
@Override
public void releaseLock() {
+ lazyInit();
+
lockService.releaseLock();
lockService.reset();
factory.setHasLock(false);
@@ -128,6 +136,8 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
@Override
public void destroyLockInfo() {
+ lazyInit();
+
try {
this.lockService.destroy();
dbConnection.commit();
@@ -154,7 +164,7 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
}
private void safeCloseConnection() {
- // Close after creating EntityManagerFactory to prevent in-mem databases from closing
+ // Close to prevent in-mem databases from closing
if (dbConnection != null) {
try {
dbConnection.close();
diff --git a/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml b/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml
index 2d0117e..6b9ab90 100644
--- a/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml
+++ b/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml
@@ -32,4 +32,6 @@
<include file="META-INF/jpa-changelog-1.9.0.xml"/>
<include file="META-INF/db2-jpa-changelog-1.9.1.xml"/>
<include file="META-INF/jpa-changelog-1.9.2.xml"/>
+
+ <include file="META-INF/jpa-changelog-authz-master.xml"/>
</databaseChangeLog>
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index 818d571..0385281 100644
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -27,6 +27,7 @@ import org.keycloak.migration.MigrationModelManager;
import org.keycloak.models.*;
import org.keycloak.models.dblock.DBLockProvider;
import org.keycloak.models.dblock.DBLockManager;
+import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.PostMigrationEvent;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.RealmRepresentation;
@@ -91,53 +92,28 @@ public class KeycloakApplication extends Application {
singletons.add(new ObjectMapperResolver(Boolean.parseBoolean(System.getProperty("keycloak.jsonPrettyPrint", "false"))));
- ExportImportManager exportImportManager;
-
- DBLockManager dbLockManager = new DBLockManager(sessionFactory.create());
- dbLockManager.checkForcedUnlock();
- DBLockProvider dbLock = dbLockManager.getDBLock();
- dbLock.waitForLock();
- try {
- migrateModel();
-
- KeycloakSession session = sessionFactory.create();
- try {
- session.getTransaction().begin();
+ ExportImportManager[] exportImportManager = new ExportImportManager[1];
- ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
- exportImportManager = new ExportImportManager(session);
+ KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
- boolean createMasterRealm = applianceBootstrap.isNewInstall();
- if (exportImportManager.isRunImport() && exportImportManager.isImportMasterIncluded()) {
- createMasterRealm = false;
- }
-
- if (createMasterRealm) {
- applianceBootstrap.createMasterRealm(contextPath);
- }
- session.getTransaction().commit();
- } catch (RuntimeException re) {
- if (session.getTransaction().isActive()) {
- session.getTransaction().rollback();
+ @Override
+ public void run(KeycloakSession lockSession) {
+ DBLockManager dbLockManager = new DBLockManager(lockSession);
+ dbLockManager.checkForcedUnlock();
+ DBLockProvider dbLock = dbLockManager.getDBLock();
+ dbLock.waitForLock();
+ try {
+ exportImportManager[0] = migrateAndBootstrap();
+ } finally {
+ dbLock.releaseLock();
}
- throw re;
- } finally {
- session.close();
}
- if (exportImportManager.isRunImport()) {
- exportImportManager.runImport();
- } else {
- importRealms();
- }
+ });
- importAddUser();
- } finally {
- dbLock.releaseLock();
- }
- if (exportImportManager.isRunExport()) {
- exportImportManager.runExport();
+ if (exportImportManager[0].isRunExport()) {
+ exportImportManager[0].runExport();
}
boolean bootstrapAdminUser = false;
@@ -158,6 +134,49 @@ public class KeycloakApplication extends Application {
setupScheduledTasks(sessionFactory);
}
+
+ // Migrate model, bootstrap master realm, import realms and create admin user. This is done with acquired dbLock
+ protected ExportImportManager migrateAndBootstrap() {
+ ExportImportManager exportImportManager;
+ migrateModel();
+
+ KeycloakSession session = sessionFactory.create();
+ try {
+ session.getTransaction().begin();
+
+ ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
+ exportImportManager = new ExportImportManager(session);
+
+ boolean createMasterRealm = applianceBootstrap.isNewInstall();
+ if (exportImportManager.isRunImport() && exportImportManager.isImportMasterIncluded()) {
+ createMasterRealm = false;
+ }
+
+ if (createMasterRealm) {
+ applianceBootstrap.createMasterRealm(contextPath);
+ }
+ session.getTransaction().commit();
+ } catch (RuntimeException re) {
+ if (session.getTransaction().isActive()) {
+ session.getTransaction().rollback();
+ }
+ throw re;
+ } finally {
+ session.close();
+ }
+
+ if (exportImportManager.isRunImport()) {
+ exportImportManager.runImport();
+ } else {
+ importRealms();
+ }
+
+ importAddUser();
+
+ return exportImportManager;
+ }
+
+
protected void migrateModel() {
KeycloakSession session = sessionFactory.create();
try {
diff --git a/testsuite/integration/src/test/resources/log4j.properties b/testsuite/integration/src/test/resources/log4j.properties
index f093692..c2bc22c 100755
--- a/testsuite/integration/src/test/resources/log4j.properties
+++ b/testsuite/integration/src/test/resources/log4j.properties
@@ -49,7 +49,7 @@ log4j.logger.org.keycloak.connections.jpa.updater.liquibase=${keycloak.liquibase
# Enable to view database updates
# log4j.logger.org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider=debug
-# log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug
+log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=${keycloak.liquibase.logging.level}
# log4j.logger.org.keycloak.migration.MigrationModelManager=debug
# Enable to view hibernate statistics