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;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import liquibase.Liquibase;
|
||||
import liquibase.Scope;
|
||||
import liquibase.database.Database;
|
||||
import liquibase.database.DatabaseFactory;
|
||||
import liquibase.database.jvm.JdbcConnection;
|
||||
import liquibase.exception.LiquibaseException;
|
||||
import liquibase.resource.ClassLoaderResourceAccessor;
|
||||
import liquibase.resource.ResourceAccessor;
|
||||
import liquibase.ui.LoggerUIService;
|
||||
import org.jboss.logging.Logger;
|
||||
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,
|
||||
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) {
|
||||
database.setDefaultSchemaName(defaultSchema);
|
||||
}
|
||||
|
@ -64,6 +69,40 @@ public class DefaultLiquibaseConnectionProvider implements MapLiquibaseConnectio
|
|||
database.setDatabaseChangeLogTableName(changelogTableName);
|
||||
|
||||
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.DatabaseFactory;
|
||||
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 java.io.File;
|
||||
import java.io.FileWriter;
|
||||
|
@ -88,8 +88,8 @@ public class MapJpaLiquibaseUpdaterProvider implements MapJpaUpdaterProvider {
|
|||
ThreadLocalSessionContext.setCurrentSession(session);
|
||||
|
||||
Writer exportWriter = null;
|
||||
try {
|
||||
Liquibase liquibase = getLiquibase(modelType, connection, defaultSchema);
|
||||
try (Liquibase liquibase = getLiquibase(modelType, connection, defaultSchema)) {
|
||||
|
||||
if (file != null) {
|
||||
exportWriter = new FileWriter(file);
|
||||
}
|
||||
|
@ -146,8 +146,7 @@ public class MapJpaLiquibaseUpdaterProvider implements MapJpaUpdaterProvider {
|
|||
logger.debug("Validating if database is updated");
|
||||
ThreadLocalSessionContext.setCurrentSession(session);
|
||||
|
||||
try {
|
||||
Liquibase liquibase = getLiquibase(modelType, connection, defaultSchema);
|
||||
try (Liquibase liquibase = getLiquibase(modelType, connection, defaultSchema)) {
|
||||
|
||||
Status status = validateChangeSet(liquibase, liquibase.getChangeLogFile());
|
||||
if (status != Status.VALID) {
|
||||
|
@ -198,10 +197,14 @@ public class MapJpaLiquibaseUpdaterProvider implements MapJpaUpdaterProvider {
|
|||
if (modelName.equals("auth-events") || modelName.equals("admin-events"))
|
||||
modelName = "events";
|
||||
|
||||
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
|
||||
// if database is cockroachdb, use the aggregate changelog (see GHI #11230).
|
||||
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnectionFromPool(connection));
|
||||
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";
|
||||
return liquibaseProvider.getLiquibaseForCustomUpdate(connection, defaultSchema, changelog, this.getClass().getClassLoader(), "databasechangelog");
|
||||
} finally {
|
||||
database.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue