parent
30b41d02b4
commit
b959e5c32a
3 changed files with 101 additions and 18 deletions
|
@ -18,14 +18,17 @@
|
||||||
package org.keycloak.models.map.storage.jpa.liquibase.connection;
|
package org.keycloak.models.map.storage.jpa.liquibase.connection;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import liquibase.Liquibase;
|
import liquibase.Liquibase;
|
||||||
|
import liquibase.Scope;
|
||||||
import liquibase.database.Database;
|
import liquibase.database.Database;
|
||||||
import liquibase.database.DatabaseFactory;
|
import liquibase.database.DatabaseFactory;
|
||||||
import liquibase.database.jvm.JdbcConnection;
|
|
||||||
import liquibase.exception.LiquibaseException;
|
import liquibase.exception.LiquibaseException;
|
||||||
import liquibase.resource.ClassLoaderResourceAccessor;
|
import liquibase.resource.ClassLoaderResourceAccessor;
|
||||||
import liquibase.resource.ResourceAccessor;
|
import liquibase.resource.ResourceAccessor;
|
||||||
|
import liquibase.ui.LoggerUIService;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
|
||||||
|
@ -56,7 +59,9 @@ public class DefaultLiquibaseConnectionProvider implements MapLiquibaseConnectio
|
||||||
public Liquibase getLiquibaseForCustomUpdate(final Connection connection, final String defaultSchema, final String changelogLocation,
|
public Liquibase getLiquibaseForCustomUpdate(final Connection connection, final String defaultSchema, final String changelogLocation,
|
||||||
final ClassLoader classloader, final String changelogTableName) throws LiquibaseException {
|
final ClassLoader classloader, final String changelogTableName) throws LiquibaseException {
|
||||||
|
|
||||||
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
|
String scopeId = enterLiquibaseScope();
|
||||||
|
try {
|
||||||
|
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnectionFromPool(connection));
|
||||||
if (defaultSchema != null) {
|
if (defaultSchema != null) {
|
||||||
database.setDefaultSchemaName(defaultSchema);
|
database.setDefaultSchemaName(defaultSchema);
|
||||||
}
|
}
|
||||||
|
@ -64,6 +69,40 @@ public class DefaultLiquibaseConnectionProvider implements MapLiquibaseConnectio
|
||||||
database.setDatabaseChangeLogTableName(changelogTableName);
|
database.setDatabaseChangeLogTableName(changelogTableName);
|
||||||
|
|
||||||
logger.debugf("Using changelog file %s and changelogTableName %s", changelogLocation, database.getDatabaseChangeLogTableName());
|
logger.debugf("Using changelog file %s and changelogTableName %s", changelogLocation, database.getDatabaseChangeLogTableName());
|
||||||
return new Liquibase(changelogLocation, resourceAccessor, database);
|
|
||||||
|
return new Liquibase(changelogLocation, resourceAccessor, database) {
|
||||||
|
@Override
|
||||||
|
public void close() throws LiquibaseException {
|
||||||
|
super.close();
|
||||||
|
exitLiquibaseScope(scopeId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (LiquibaseException | RuntimeException ex) {
|
||||||
|
// When this trows an exception, close the scope here.
|
||||||
|
// If it returns the Liquibase object, the scope will be closed once the Liquibase object is being closed.
|
||||||
|
exitLiquibaseScope(scopeId);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exitLiquibaseScope(String scopeId) {
|
||||||
|
try {
|
||||||
|
Scope.exit(scopeId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to exist scope: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String enterLiquibaseScope() {
|
||||||
|
String scopeId;
|
||||||
|
final Map<String, Object> scopeValues = new HashMap<>();
|
||||||
|
// Setting the LoggerUIService here prevents Liquibase from logging each change set to the console using java.util.Logging in the Quarkus setup
|
||||||
|
scopeValues.put(Scope.Attr.ui.name(), new LoggerUIService());
|
||||||
|
try {
|
||||||
|
scopeId = Scope.enter(scopeValues);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to initialize Liquibase: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return scopeId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.models.map.storage.jpa.liquibase.connection;
|
||||||
|
|
||||||
|
import liquibase.database.jvm.JdbcConnection;
|
||||||
|
import liquibase.exception.DatabaseException;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for JDBC connections retrieved from a connection pool.
|
||||||
|
* Such a connection would not be closed, but used within the current transaction context.
|
||||||
|
*
|
||||||
|
* @author Alexander Schwartz
|
||||||
|
*/
|
||||||
|
public class JdbcConnectionFromPool extends JdbcConnection {
|
||||||
|
public JdbcConnectionFromPool(Connection connection) {
|
||||||
|
super(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws DatabaseException {
|
||||||
|
rollback();
|
||||||
|
// do not close the connection here, as connection will be returned to the pool or continued to be used in this session
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ package org.keycloak.models.map.storage.jpa.liquibase.updater;
|
||||||
import liquibase.database.Database;
|
import liquibase.database.Database;
|
||||||
import liquibase.database.DatabaseFactory;
|
import liquibase.database.DatabaseFactory;
|
||||||
import liquibase.database.core.CockroachDatabase;
|
import liquibase.database.core.CockroachDatabase;
|
||||||
import liquibase.database.jvm.JdbcConnection;
|
import org.keycloak.models.map.storage.jpa.liquibase.connection.JdbcConnectionFromPool;
|
||||||
import org.keycloak.models.map.storage.jpa.liquibase.connection.MapLiquibaseConnectionProvider;
|
import org.keycloak.models.map.storage.jpa.liquibase.connection.MapLiquibaseConnectionProvider;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
|
@ -88,8 +88,8 @@ public class MapJpaLiquibaseUpdaterProvider implements MapJpaUpdaterProvider {
|
||||||
ThreadLocalSessionContext.setCurrentSession(session);
|
ThreadLocalSessionContext.setCurrentSession(session);
|
||||||
|
|
||||||
Writer exportWriter = null;
|
Writer exportWriter = null;
|
||||||
try {
|
try (Liquibase liquibase = getLiquibase(modelType, connection, defaultSchema)) {
|
||||||
Liquibase liquibase = getLiquibase(modelType, connection, defaultSchema);
|
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
exportWriter = new FileWriter(file);
|
exportWriter = new FileWriter(file);
|
||||||
}
|
}
|
||||||
|
@ -146,8 +146,7 @@ public class MapJpaLiquibaseUpdaterProvider implements MapJpaUpdaterProvider {
|
||||||
logger.debug("Validating if database is updated");
|
logger.debug("Validating if database is updated");
|
||||||
ThreadLocalSessionContext.setCurrentSession(session);
|
ThreadLocalSessionContext.setCurrentSession(session);
|
||||||
|
|
||||||
try {
|
try (Liquibase liquibase = getLiquibase(modelType, connection, defaultSchema)) {
|
||||||
Liquibase liquibase = getLiquibase(modelType, connection, defaultSchema);
|
|
||||||
|
|
||||||
Status status = validateChangeSet(liquibase, liquibase.getChangeLogFile());
|
Status status = validateChangeSet(liquibase, liquibase.getChangeLogFile());
|
||||||
if (status != Status.VALID) {
|
if (status != Status.VALID) {
|
||||||
|
@ -198,10 +197,14 @@ public class MapJpaLiquibaseUpdaterProvider implements MapJpaUpdaterProvider {
|
||||||
if (modelName.equals("auth-events") || modelName.equals("admin-events"))
|
if (modelName.equals("auth-events") || modelName.equals("admin-events"))
|
||||||
modelName = "events";
|
modelName = "events";
|
||||||
|
|
||||||
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
|
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnectionFromPool(connection));
|
||||||
// if database is cockroachdb, use the aggregate changelog (see GHI #11230).
|
try {
|
||||||
|
// if the database is cockroachdb, use the aggregate changelog (see GHI #11230).
|
||||||
String changelog = database instanceof CockroachDatabase ? "META-INF/jpa-aggregate-changelog.xml" : "META-INF/jpa-" + modelName + "-changelog.xml";
|
String changelog = database instanceof CockroachDatabase ? "META-INF/jpa-aggregate-changelog.xml" : "META-INF/jpa-" + modelName + "-changelog.xml";
|
||||||
return liquibaseProvider.getLiquibaseForCustomUpdate(connection, defaultSchema, changelog, this.getClass().getClassLoader(), "databasechangelog");
|
return liquibaseProvider.getLiquibaseForCustomUpdate(connection, defaultSchema, changelog, this.getClass().getClassLoader(), "databasechangelog");
|
||||||
|
} finally {
|
||||||
|
database.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in a new issue