Ignoring artifacts when running re-aug to isolate the current and new stores
Closes #20974
This commit is contained in:
parent
8cc04a6724
commit
bde57ca839
7 changed files with 79 additions and 51 deletions
|
@ -30,47 +30,41 @@ import org.keycloak.models.map.storage.jpa.hibernate.listeners.JpaAutoFlushListe
|
||||||
import org.keycloak.models.map.storage.jpa.hibernate.listeners.JpaEntityVersionListener;
|
import org.keycloak.models.map.storage.jpa.hibernate.listeners.JpaEntityVersionListener;
|
||||||
import org.keycloak.models.map.storage.jpa.hibernate.listeners.JpaOptimisticLockingListener;
|
import org.keycloak.models.map.storage.jpa.hibernate.listeners.JpaOptimisticLockingListener;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adding listeners to Hibernate's entity manager for the JPA Map store.
|
* Adding listeners to Hibernate's entity manager for the JPA Map store.
|
||||||
*/
|
*/
|
||||||
public class EventListenerIntegrator implements Integrator {
|
public class EventListenerIntegrator implements Integrator {
|
||||||
|
|
||||||
public static String JPA_MAP_STORAGE_ENABLED = "kc.jpa-map-storage-enabled";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactoryImplementor,
|
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactoryImplementor,
|
||||||
SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {
|
SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {
|
||||||
if (Objects.equals(sessionFactoryImplementor.getProperties().get(JPA_MAP_STORAGE_ENABLED), Boolean.TRUE.toString())) {
|
final EventListenerRegistry eventListenerRegistry =
|
||||||
final EventListenerRegistry eventListenerRegistry =
|
sessionFactoryServiceRegistry.getService(EventListenerRegistry.class);
|
||||||
sessionFactoryServiceRegistry.getService(EventListenerRegistry.class);
|
|
||||||
|
|
||||||
if (metadata.getDatabase().getDialect() instanceof CockroachDialect) {
|
if (metadata.getDatabase().getDialect() instanceof CockroachDialect) {
|
||||||
// CockroachDB will always use serializable transactions, therefore no optimistic locking is necessary
|
// CockroachDB will always use serializable transactions, therefore no optimistic locking is necessary
|
||||||
metadata.getEntityBindings().forEach(persistentClass -> {
|
metadata.getEntityBindings().forEach(persistentClass -> {
|
||||||
if (persistentClass instanceof RootClass) {
|
if (persistentClass instanceof RootClass) {
|
||||||
RootClass root = (RootClass) persistentClass;
|
RootClass root = (RootClass) persistentClass;
|
||||||
root.setOptimisticLockStyle(OptimisticLockStyle.NONE);
|
root.setOptimisticLockStyle(OptimisticLockStyle.NONE);
|
||||||
root.setVersion(null);
|
root.setVersion(null);
|
||||||
root.setDeclaredVersion(null);
|
root.setDeclaredVersion(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// If the version column should be updated with an incrementing number on each change in the future,
|
// If the version column should be updated with an incrementing number on each change in the future,
|
||||||
// implement a listener similar to JpaOptimisticLockingListener to increment it.
|
// implement a listener similar to JpaOptimisticLockingListener to increment it.
|
||||||
} else {
|
} else {
|
||||||
eventListenerRegistry.appendListeners(EventType.PRE_INSERT, JpaOptimisticLockingListener.INSTANCE);
|
eventListenerRegistry.appendListeners(EventType.PRE_INSERT, JpaOptimisticLockingListener.INSTANCE);
|
||||||
eventListenerRegistry.appendListeners(EventType.PRE_UPDATE, JpaOptimisticLockingListener.INSTANCE);
|
eventListenerRegistry.appendListeners(EventType.PRE_UPDATE, JpaOptimisticLockingListener.INSTANCE);
|
||||||
eventListenerRegistry.appendListeners(EventType.PRE_DELETE, JpaOptimisticLockingListener.INSTANCE);
|
eventListenerRegistry.appendListeners(EventType.PRE_DELETE, JpaOptimisticLockingListener.INSTANCE);
|
||||||
}
|
|
||||||
|
|
||||||
eventListenerRegistry.appendListeners(EventType.PRE_INSERT, JpaEntityVersionListener.INSTANCE);
|
|
||||||
eventListenerRegistry.appendListeners(EventType.PRE_UPDATE, JpaEntityVersionListener.INSTANCE);
|
|
||||||
eventListenerRegistry.appendListeners(EventType.PRE_DELETE, JpaEntityVersionListener.INSTANCE);
|
|
||||||
|
|
||||||
// replace auto-flush listener
|
|
||||||
eventListenerRegistry.setListeners(EventType.AUTO_FLUSH, JpaAutoFlushListener.INSTANCE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eventListenerRegistry.appendListeners(EventType.PRE_INSERT, JpaEntityVersionListener.INSTANCE);
|
||||||
|
eventListenerRegistry.appendListeners(EventType.PRE_UPDATE, JpaEntityVersionListener.INSTANCE);
|
||||||
|
eventListenerRegistry.appendListeners(EventType.PRE_DELETE, JpaEntityVersionListener.INSTANCE);
|
||||||
|
|
||||||
|
// replace auto-flush listener
|
||||||
|
eventListenerRegistry.setListeners(EventType.AUTO_FLUSH, JpaAutoFlushListener.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -420,9 +420,6 @@ public class JpaMapStorageProviderFactory implements
|
||||||
logger.warnf("Database %s used without lockTimeout option configured. This can result in deadlock where one connection waits for a pessimistic write lock forever.", databaseShortName);
|
logger.warnf("Database %s used without lockTimeout option configured. This can result in deadlock where one connection waits for a pessimistic write lock forever.", databaseShortName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass on the property to 'EventListenerIntegrator' to activate the necessary event listeners for JPA map storage
|
|
||||||
properties.put(EventListenerIntegrator.JPA_MAP_STORAGE_ENABLED, Boolean.TRUE.toString());
|
|
||||||
|
|
||||||
logger.trace("Creating EntityManagerFactory");
|
logger.trace("Creating EntityManagerFactory");
|
||||||
ParsedPersistenceXmlDescriptor descriptor = PersistenceXmlParser.locateIndividualPersistenceUnit(
|
ParsedPersistenceXmlDescriptor descriptor = PersistenceXmlParser.locateIndividualPersistenceUnit(
|
||||||
JpaMapStorageProviderFactory.class.getClassLoader()
|
JpaMapStorageProviderFactory.class.getClassLoader()
|
||||||
|
|
|
@ -5,5 +5,6 @@ public class ClassLoaderOptions {
|
||||||
public static final Option<String> IGNORE_ARTIFACTS = new OptionBuilder<>("class-loader-ignore-artifacts", String.class)
|
public static final Option<String> IGNORE_ARTIFACTS = new OptionBuilder<>("class-loader-ignore-artifacts", String.class)
|
||||||
.category(OptionCategory.GENERAL)
|
.category(OptionCategory.GENERAL)
|
||||||
.hidden()
|
.hidden()
|
||||||
|
.buildTime(true)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,6 @@ import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
@ -129,7 +128,6 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
@ -166,7 +164,7 @@ class KeycloakProcessor {
|
||||||
private static final Map<String, Function<ScriptProviderMetadata, ProviderFactory>> DEPLOYEABLE_SCRIPT_PROVIDERS = new HashMap<>();
|
private static final Map<String, Function<ScriptProviderMetadata, ProviderFactory>> DEPLOYEABLE_SCRIPT_PROVIDERS = new HashMap<>();
|
||||||
private static final String KEYCLOAK_SCRIPTS_JSON_PATH = "META-INF/keycloak-scripts.json";
|
private static final String KEYCLOAK_SCRIPTS_JSON_PATH = "META-INF/keycloak-scripts.json";
|
||||||
|
|
||||||
private static final List<Class<? extends ProviderFactory>> IGNORED_PROVIDER_FACTORY = Arrays.asList(
|
private static final List<Class<? extends ProviderFactory>> IGNORED_PROVIDER_FACTORY = List.of(
|
||||||
JBossJtaTransactionManagerLookup.class,
|
JBossJtaTransactionManagerLookup.class,
|
||||||
DefaultJpaConnectionProviderFactory.class,
|
DefaultJpaConnectionProviderFactory.class,
|
||||||
DefaultLiquibaseConnectionProvider.class,
|
DefaultLiquibaseConnectionProvider.class,
|
||||||
|
@ -319,12 +317,6 @@ class KeycloakProcessor {
|
||||||
final Optional<String> lockTimeoutConfigValue = getOptionalValue("spi-map-storage-jpa-lock-timeout");
|
final Optional<String> lockTimeoutConfigValue = getOptionalValue("spi-map-storage-jpa-lock-timeout");
|
||||||
lockTimeoutConfigValue.ifPresent(v -> unitProperties.setProperty(AvailableSettings.JAKARTA_LOCK_TIMEOUT, v));
|
lockTimeoutConfigValue.ifPresent(v -> unitProperties.setProperty(AvailableSettings.JAKARTA_LOCK_TIMEOUT, v));
|
||||||
|
|
||||||
final ConfigValue storage = getKcConfigValue(StorageOptions.STORAGE.getKey());
|
|
||||||
if (storage != null && Objects.equals(storage.getValue(), StorageOptions.StorageType.jpa.name())) {
|
|
||||||
// if JPA map storage is enabled, pass on the property to 'EventListenerIntegrator' to activate the necessary event listeners for JPA map storage
|
|
||||||
unitProperties.setProperty(EventListenerIntegrator.JPA_MAP_STORAGE_ENABLED, Boolean.TRUE.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
unitProperties.setProperty(AvailableSettings.QUERY_STARTUP_CHECKING, Boolean.FALSE.toString());
|
unitProperties.setProperty(AvailableSettings.QUERY_STARTUP_CHECKING, Boolean.FALSE.toString());
|
||||||
|
|
||||||
String dbKind = defaultDataSource.getDbKind();
|
String dbKind = defaultDataSource.getDbKind();
|
||||||
|
|
|
@ -22,14 +22,19 @@ import static org.keycloak.quarkus.runtime.Environment.isDevMode;
|
||||||
import static org.keycloak.quarkus.runtime.cli.Picocli.println;
|
import static org.keycloak.quarkus.runtime.cli.Picocli.println;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.getAllCliArgs;
|
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.getAllCliArgs;
|
||||||
|
|
||||||
|
import org.keycloak.config.ClassLoaderOptions;
|
||||||
import org.keycloak.config.OptionCategory;
|
import org.keycloak.config.OptionCategory;
|
||||||
import org.keycloak.quarkus.runtime.Environment;
|
import org.keycloak.quarkus.runtime.Environment;
|
||||||
import org.keycloak.quarkus.runtime.Messages;
|
import org.keycloak.quarkus.runtime.Messages;
|
||||||
|
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||||
|
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
|
||||||
|
|
||||||
import io.quarkus.bootstrap.runner.QuarkusEntryPoint;
|
import io.quarkus.bootstrap.runner.QuarkusEntryPoint;
|
||||||
import io.quarkus.bootstrap.runner.RunnerClassLoader;
|
import io.quarkus.bootstrap.runner.RunnerClassLoader;
|
||||||
|
|
||||||
import io.quarkus.runtime.configuration.ProfileManager;
|
import io.quarkus.runtime.configuration.ProfileManager;
|
||||||
|
import io.smallrye.config.ConfigValue;
|
||||||
|
import org.keycloak.utils.StringUtil;
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
import picocli.CommandLine.Command;
|
import picocli.CommandLine.Command;
|
||||||
|
|
||||||
|
@ -71,6 +76,9 @@ public final class Build extends AbstractCommand implements Runnable {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
beforeReaugmentationOnWindows();
|
beforeReaugmentationOnWindows();
|
||||||
|
|
||||||
|
configureBuildClassLoader();
|
||||||
|
|
||||||
QuarkusEntryPoint.main();
|
QuarkusEntryPoint.main();
|
||||||
|
|
||||||
if (!isDevMode()) {
|
if (!isDevMode()) {
|
||||||
|
@ -84,6 +92,16 @@ public final class Build extends AbstractCommand implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void configureBuildClassLoader() {
|
||||||
|
ConfigValue ignoredArtifacts = Configuration.getCurrentBuiltTimeProperty(
|
||||||
|
MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX + ClassLoaderOptions.IGNORE_ARTIFACTS.getKey());
|
||||||
|
|
||||||
|
if (ignoredArtifacts != null && StringUtil.isNotBlank(ignoredArtifacts.getValue())) {
|
||||||
|
// ignored artifacts must be set prior to starting re-augmentation
|
||||||
|
System.setProperty("quarkus.class-loading.removed-artifacts", ignoredArtifacts.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean includeBuildTime() {
|
public boolean includeBuildTime() {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -4,12 +4,19 @@ import static org.keycloak.quarkus.runtime.Environment.getCurrentOrCreateFeature
|
||||||
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
|
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
|
||||||
|
|
||||||
import io.smallrye.config.ConfigSourceInterceptorContext;
|
import io.smallrye.config.ConfigSourceInterceptorContext;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.keycloak.common.Profile;
|
import org.keycloak.common.Profile;
|
||||||
import org.keycloak.common.Profile.Feature;
|
import org.keycloak.common.Profile.Feature;
|
||||||
import org.keycloak.config.ClassLoaderOptions;
|
import org.keycloak.config.ClassLoaderOptions;
|
||||||
|
import org.keycloak.config.StorageOptions;
|
||||||
import org.keycloak.quarkus.runtime.Environment;
|
import org.keycloak.quarkus.runtime.Environment;
|
||||||
|
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||||
|
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
|
||||||
|
|
||||||
final class ClassLoaderPropertyMappers {
|
final class ClassLoaderPropertyMappers {
|
||||||
|
|
||||||
|
@ -27,14 +34,27 @@ final class ClassLoaderPropertyMappers {
|
||||||
private static Optional<String> resolveIgnoredArtifacts(Optional<String> value, ConfigSourceInterceptorContext context) {
|
private static Optional<String> resolveIgnoredArtifacts(Optional<String> value, ConfigSourceInterceptorContext context) {
|
||||||
if (Environment.isRebuildCheck() || Environment.isRebuild()) {
|
if (Environment.isRebuildCheck() || Environment.isRebuild()) {
|
||||||
Profile profile = getCurrentOrCreateFeatureProfile();
|
Profile profile = getCurrentOrCreateFeatureProfile();
|
||||||
|
Set<String> ignoredArtifacts = new HashSet<>();
|
||||||
|
|
||||||
if (profile.getFeatures().get(Feature.FIPS)) {
|
if (profile.getFeatures().get(Feature.FIPS)) {
|
||||||
return Optional.of(
|
ignoredArtifacts.addAll(List.of(
|
||||||
"org.bouncycastle:bcprov-jdk15on,org.bouncycastle:bcpkix-jdk15on,org.bouncycastle:bcutil-jdk15on,org.keycloak:keycloak-crypto-default");
|
"org.bouncycastle:bcprov-jdk15on", "org.bouncycastle:bcpkix-jdk15on", "org.bouncycastle:bcutil-jdk15on", "org.keycloak:keycloak-crypto-default"));
|
||||||
|
} else {
|
||||||
|
ignoredArtifacts.addAll(List.of(
|
||||||
|
"org.keycloak:keycloak-crypto-fips1402", "org.bouncycastle:bc-fips", "org.bouncycastle:bctls-fips", "org.bouncycastle:bcpkix-fips"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Optional.of(
|
Optional<String> storage = Configuration.getOptionalValue(
|
||||||
"org.keycloak:keycloak-crypto-fips1402,org.bouncycastle:bc-fips,org.bouncycastle:bctls-fips,org.bouncycastle:bcpkix-fips");
|
MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX + StorageOptions.STORAGE.getKey());
|
||||||
|
|
||||||
|
if (storage.isEmpty()) {
|
||||||
|
ignoredArtifacts.add("org.keycloak:keycloak-model-map-jpa");
|
||||||
|
ignoredArtifacts.add("org.keycloak:keycloak-model-map-hot-rod");
|
||||||
|
ignoredArtifacts.add("org.keycloak:keycloak-model-map");
|
||||||
|
ignoredArtifacts.add("org.keycloak:keycloak-model-map-file");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.of(String.join(",", ignoredArtifacts));
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
|
|
@ -17,17 +17,19 @@
|
||||||
|
|
||||||
package org.keycloak.quarkus.runtime.storage.database.jpa;
|
package org.keycloak.quarkus.runtime.storage.database.jpa;
|
||||||
|
|
||||||
|
import static org.keycloak.config.StorageOptions.STORAGE;
|
||||||
|
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import jakarta.enterprise.inject.Instance;
|
import jakarta.enterprise.inject.Instance;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.EntityManagerFactory;
|
import jakarta.persistence.EntityManagerFactory;
|
||||||
import org.hibernate.internal.SessionFactoryImpl;
|
import org.hibernate.internal.SessionFactoryImpl;
|
||||||
import org.hibernate.internal.SessionImpl;
|
import org.keycloak.config.StorageOptions.StorageType;
|
||||||
import org.keycloak.config.StorageOptions;
|
|
||||||
import org.keycloak.models.map.storage.jpa.JpaMapStorageProviderFactory;
|
import org.keycloak.models.map.storage.jpa.JpaMapStorageProviderFactory;
|
||||||
|
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||||
|
|
||||||
import io.quarkus.arc.Arc;
|
import io.quarkus.arc.Arc;
|
||||||
import io.quarkus.hibernate.orm.PersistenceUnit;
|
import io.quarkus.hibernate.orm.PersistenceUnit;
|
||||||
|
@ -36,7 +38,7 @@ public class QuarkusJpaMapStorageProviderFactory extends JpaMapStorageProviderFa
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return StorageOptions.StorageType.jpa.getProvider();
|
return StorageType.jpa.getProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -81,4 +83,8 @@ public class QuarkusJpaMapStorageProviderFactory extends JpaMapStorageProviderFa
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSupported() {
|
||||||
|
return StorageType.jpa.name().equals(Configuration.getOptionalValue(NS_KEYCLOAK_PREFIX + STORAGE.getKey()).orElse(null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue