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.JpaOptimisticLockingListener;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Adding listeners to Hibernate's entity manager for the JPA Map store.
|
||||
*/
|
||||
public class EventListenerIntegrator implements Integrator {
|
||||
|
||||
public static String JPA_MAP_STORAGE_ENABLED = "kc.jpa-map-storage-enabled";
|
||||
|
||||
@Override
|
||||
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactoryImplementor,
|
||||
SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {
|
||||
if (Objects.equals(sessionFactoryImplementor.getProperties().get(JPA_MAP_STORAGE_ENABLED), Boolean.TRUE.toString())) {
|
||||
final EventListenerRegistry eventListenerRegistry =
|
||||
sessionFactoryServiceRegistry.getService(EventListenerRegistry.class);
|
||||
final EventListenerRegistry eventListenerRegistry =
|
||||
sessionFactoryServiceRegistry.getService(EventListenerRegistry.class);
|
||||
|
||||
if (metadata.getDatabase().getDialect() instanceof CockroachDialect) {
|
||||
// CockroachDB will always use serializable transactions, therefore no optimistic locking is necessary
|
||||
metadata.getEntityBindings().forEach(persistentClass -> {
|
||||
if (persistentClass instanceof RootClass) {
|
||||
RootClass root = (RootClass) persistentClass;
|
||||
root.setOptimisticLockStyle(OptimisticLockStyle.NONE);
|
||||
root.setVersion(null);
|
||||
root.setDeclaredVersion(null);
|
||||
}
|
||||
});
|
||||
// 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.
|
||||
} else {
|
||||
eventListenerRegistry.appendListeners(EventType.PRE_INSERT, JpaOptimisticLockingListener.INSTANCE);
|
||||
eventListenerRegistry.appendListeners(EventType.PRE_UPDATE, 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);
|
||||
if (metadata.getDatabase().getDialect() instanceof CockroachDialect) {
|
||||
// CockroachDB will always use serializable transactions, therefore no optimistic locking is necessary
|
||||
metadata.getEntityBindings().forEach(persistentClass -> {
|
||||
if (persistentClass instanceof RootClass) {
|
||||
RootClass root = (RootClass) persistentClass;
|
||||
root.setOptimisticLockStyle(OptimisticLockStyle.NONE);
|
||||
root.setVersion(null);
|
||||
root.setDeclaredVersion(null);
|
||||
}
|
||||
});
|
||||
// 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.
|
||||
} else {
|
||||
eventListenerRegistry.appendListeners(EventType.PRE_INSERT, JpaOptimisticLockingListener.INSTANCE);
|
||||
eventListenerRegistry.appendListeners(EventType.PRE_UPDATE, 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);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
// 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");
|
||||
ParsedPersistenceXmlDescriptor descriptor = PersistenceXmlParser.locateIndividualPersistenceUnit(
|
||||
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)
|
||||
.category(OptionCategory.GENERAL)
|
||||
.hidden()
|
||||
.buildTime(true)
|
||||
.build();
|
||||
}
|
||||
|
|
|
@ -121,7 +121,6 @@ import java.io.InputStream;
|
|||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
|
@ -129,7 +128,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
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 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,
|
||||
DefaultJpaConnectionProviderFactory.class,
|
||||
DefaultLiquibaseConnectionProvider.class,
|
||||
|
@ -319,12 +317,6 @@ class KeycloakProcessor {
|
|||
final Optional<String> lockTimeoutConfigValue = getOptionalValue("spi-map-storage-jpa-lock-timeout");
|
||||
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());
|
||||
|
||||
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.configuration.ConfigArgsConfigSource.getAllCliArgs;
|
||||
|
||||
import org.keycloak.config.ClassLoaderOptions;
|
||||
import org.keycloak.config.OptionCategory;
|
||||
import org.keycloak.quarkus.runtime.Environment;
|
||||
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.RunnerClassLoader;
|
||||
|
||||
import io.quarkus.runtime.configuration.ProfileManager;
|
||||
import io.smallrye.config.ConfigValue;
|
||||
import org.keycloak.utils.StringUtil;
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
|
@ -71,6 +76,9 @@ public final class Build extends AbstractCommand implements Runnable {
|
|||
|
||||
try {
|
||||
beforeReaugmentationOnWindows();
|
||||
|
||||
configureBuildClassLoader();
|
||||
|
||||
QuarkusEntryPoint.main();
|
||||
|
||||
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
|
||||
public boolean includeBuildTime() {
|
||||
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 io.smallrye.config.ConfigSourceInterceptorContext;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.Profile.Feature;
|
||||
import org.keycloak.config.ClassLoaderOptions;
|
||||
import org.keycloak.config.StorageOptions;
|
||||
import org.keycloak.quarkus.runtime.Environment;
|
||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
|
||||
|
||||
final class ClassLoaderPropertyMappers {
|
||||
|
||||
|
@ -27,14 +34,27 @@ final class ClassLoaderPropertyMappers {
|
|||
private static Optional<String> resolveIgnoredArtifacts(Optional<String> value, ConfigSourceInterceptorContext context) {
|
||||
if (Environment.isRebuildCheck() || Environment.isRebuild()) {
|
||||
Profile profile = getCurrentOrCreateFeatureProfile();
|
||||
Set<String> ignoredArtifacts = new HashSet<>();
|
||||
|
||||
if (profile.getFeatures().get(Feature.FIPS)) {
|
||||
return Optional.of(
|
||||
"org.bouncycastle:bcprov-jdk15on,org.bouncycastle:bcpkix-jdk15on,org.bouncycastle:bcutil-jdk15on,org.keycloak:keycloak-crypto-default");
|
||||
ignoredArtifacts.addAll(List.of(
|
||||
"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(
|
||||
"org.keycloak:keycloak-crypto-fips1402,org.bouncycastle:bc-fips,org.bouncycastle:bctls-fips,org.bouncycastle:bcpkix-fips");
|
||||
Optional<String> storage = Configuration.getOptionalValue(
|
||||
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;
|
||||
|
|
|
@ -17,17 +17,19 @@
|
|||
|
||||
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.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
import jakarta.enterprise.inject.Instance;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import org.hibernate.internal.SessionFactoryImpl;
|
||||
import org.hibernate.internal.SessionImpl;
|
||||
import org.keycloak.config.StorageOptions;
|
||||
import org.keycloak.config.StorageOptions.StorageType;
|
||||
import org.keycloak.models.map.storage.jpa.JpaMapStorageProviderFactory;
|
||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||
|
||||
import io.quarkus.arc.Arc;
|
||||
import io.quarkus.hibernate.orm.PersistenceUnit;
|
||||
|
@ -36,7 +38,7 @@ public class QuarkusJpaMapStorageProviderFactory extends JpaMapStorageProviderFa
|
|||
|
||||
@Override
|
||||
public String getId() {
|
||||
return StorageOptions.StorageType.jpa.getProvider();
|
||||
return StorageType.jpa.getProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -81,4 +83,8 @@ public class QuarkusJpaMapStorageProviderFactory extends JpaMapStorageProviderFa
|
|||
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