Make the event listeners specific to the persistence unit

Closes #13219
This commit is contained in:
Alexander Schwartz 2023-02-15 14:41:59 +01:00 committed by Václav Muzikář
parent 3be2775f9e
commit febe134d5b
3 changed files with 20 additions and 12 deletions

View file

@ -23,24 +23,23 @@ import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.keycloak.common.Profile;
import org.keycloak.models.map.storage.jpa.hibernate.listeners.JpaAutoFlushListener;
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.
* This used to be a JPA map storage specific configuration via the Hibernate option <code>hibernate.integrator_provider</code>
* which worked in an Undertow setup but not in a Quarkus setup.
* As this will be called for both the legacy store and the new JPA Map store, it first checks if the JPA Map store has been enabled.
* A follow-up issue to track this is here: <a href="https://github.com/keycloak/keycloak/issues/13219">#13219</a>
*/
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 (Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE)) {
if (Objects.equals(sessionFactoryImplementor.getProperties().get(JPA_MAP_STORAGE_ENABLED), Boolean.TRUE.toString())) {
final EventListenerRegistry eventListenerRegistry =
sessionFactoryServiceRegistry.getService(EventListenerRegistry.class);

View file

@ -414,6 +414,9 @@ 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()

View file

@ -22,6 +22,7 @@ import static org.keycloak.quarkus.runtime.KeycloakRecorder.DEFAULT_METRICS_ENDP
import static org.keycloak.quarkus.runtime.Providers.getProviderManager;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfig;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getPropertyNames;
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_QUARKUS;
import static org.keycloak.quarkus.runtime.configuration.QuarkusPropertiesConfigSource.QUARKUS_PROPERTY_ENABLED;
import static org.keycloak.quarkus.runtime.storage.legacy.database.LegacyJpaConnectionProviderFactory.QUERY_PROPERTY_PREFIX;
@ -95,12 +96,11 @@ import org.jboss.resteasy.spi.ResteasyDeployment;
import org.keycloak.Config;
import org.keycloak.common.crypto.FipsMode;
import org.keycloak.common.profile.PropertiesFileProfileConfigResolver;
import org.keycloak.common.profile.PropertiesProfileConfigResolver;
import org.keycloak.config.SecurityOptions;
import org.keycloak.config.StorageOptions;
import org.keycloak.config.TransactionOptions;
import org.keycloak.connections.jpa.JpaConnectionProvider;
import org.keycloak.connections.jpa.JpaConnectionSpi;
import org.keycloak.models.map.storage.jpa.EventListenerIntegrator;
import org.keycloak.models.map.storage.jpa.JpaMapStorageProviderFactory;
import org.keycloak.protocol.saml.mappers.DeployedScriptSAMLProtocolMapper;
import org.keycloak.quarkus.runtime.QuarkusProfileConfigResolver;
@ -280,7 +280,7 @@ class KeycloakProcessor {
@BuildStep(onlyIf = IsJpaStoreEnabled.class)
void produceDefaultPersistenceUnit(BuildProducer<PersistenceXmlDescriptorBuildItem> producer) {
String storage = Configuration.getRawValue(
MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.concat(StorageOptions.STORAGE.getKey()));
NS_KEYCLOAK_PREFIX.concat(StorageOptions.STORAGE.getKey()));
ParsedPersistenceXmlDescriptor descriptor;
if (storage == null) {
@ -327,6 +327,12 @@ class KeycloakProcessor {
unitProperties.setProperty(AvailableSettings.JPA_LOCK_TIMEOUT, lockTimeoutConfigValue.getValue());
}
ConfigValue storage = getConfig().getConfigValue(NS_KEYCLOAK_PREFIX.concat(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();
@ -632,7 +638,7 @@ class KeycloakProcessor {
@Record(ExecutionTime.STATIC_INIT)
void setCryptoProvider(KeycloakRecorder recorder) {
FipsMode fipsMode = Configuration.getOptionalValue(
MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX + SecurityOptions.FIPS_MODE.getKey()).map(
NS_KEYCLOAK_PREFIX + SecurityOptions.FIPS_MODE.getKey()).map(
FipsMode::valueOf).orElse(FipsMode.disabled);
recorder.setCryptoProvider(fipsMode);
@ -829,11 +835,11 @@ class KeycloakProcessor {
}
private boolean isMetricsEnabled() {
return Configuration.getOptionalBooleanValue(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.concat("metrics-enabled")).orElse(false);
return Configuration.getOptionalBooleanValue(NS_KEYCLOAK_PREFIX.concat("metrics-enabled")).orElse(false);
}
private boolean isHealthEnabled() {
return Configuration.getOptionalBooleanValue(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.concat("health-enabled")).orElse(false);
return Configuration.getOptionalBooleanValue(NS_KEYCLOAK_PREFIX.concat("health-enabled")).orElse(false);
}
static JdbcDataSourceBuildItem getDefaultDataSource(List<JdbcDataSourceBuildItem> jdbcDataSources) {