Register custom functions FunctionContributor

Closes #16336

---
Quarkus3 branch sync no. 6 (17.2.2023)
Resolved conflicts:
keycloak/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/JpaMapStorage.java - Modified
keycloak/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/JpaMapStorageCockroachdb.java - Modified
keycloak/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/JpaMapStorageProviderFactory.java - Modified
---
Quarkus3 branch sync no. 3 (27.1.2023)
Resolved conflicts:
keycloak/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/JpaMapStorage.java - Modified
keycloak/testsuite/model/src/test/java/org/keycloak/testsuite/model/parameters/JpaMapStorageCockroachdb.java - Modified
This commit is contained in:
vramik 2023-01-17 13:45:36 +01:00 committed by Václav Muzikář
parent 33e2bcd94f
commit 60e6fb9dae
8 changed files with 93 additions and 46 deletions

View file

@ -410,7 +410,7 @@ public class JpaMapStorageProviderFactory implements
properties.put("hibernate.format_sql", config.getBoolean("formatSql", true));
properties.put("hibernate.dialect", config.get("driverDialect"));
// metadata contributor to register the json type
properties.put("hibernate.metadata_builder_contributor", "org.keycloak.models.map.storage.jpa.hibernate.jsonb.JsonbMetadataBuilderContributor");
properties.put("hibernate.metadata_builder_contributor", "org.keycloak.models.map.storage.jpa.hibernate.contributor.JsonbMetadataBuilderContributor");
properties.put("jakarta.persistence.validation.mode", ValidationMode.NONE.name());
Long lockTimeout = config.getLong("lockTimeout", DEFAULT_LOCK_TIMEOUT);
if (lockTimeout >= 0) {

View file

@ -0,0 +1,71 @@
/*
* Copyright 2023 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.hibernate.contributor;
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.boot.model.FunctionContributor;
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeReference;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
import org.jboss.logging.Logger;
import org.keycloak.models.map.storage.jpa.hibernate.jsonb.JsonbType;
/**
* A {@link FunctionContributor} to register custom functions.
*/
public class JpaMapFunctionContributor implements FunctionContributor {
private final Logger LOG = Logger.getLogger(JpaMapFunctionContributor.class);
@Override
public void contributeFunctions(FunctionContributions fc) {
fc.getFunctionRegistry().registerPattern("->>", "?1->>?2", getBasicType(fc, StandardBasicTypes.STRING));
fc.getFunctionRegistry().registerPattern("->", "?1->?2", getJsonbBasicType(fc));
fc.getFunctionRegistry().registerPattern("@>", "?1@>?2::jsonb", getBasicType(fc, StandardBasicTypes.BOOLEAN));
contributeDbSpecificFunctions(fc);
}
private BasicType getJsonbBasicType(FunctionContributions fc) {
return fc.getTypeConfiguration().getBasicTypeRegistry().resolve(JsonbType.class, SqlTypes.JSON);
}
private BasicType getBasicType(FunctionContributions fc, BasicTypeReference<?> btr) {
return fc.getTypeConfiguration().getBasicTypeRegistry().resolve(btr);
}
// Since Hibernate 6.2.0 dialect should be accessible via FunctionContributions.getDialect(): https://github.com/hibernate/hibernate-orm/pull/5964/
private Dialect getDialect(FunctionContributions fc) {
return fc.getTypeConfiguration().getMetadataBuildingContext().getMetadataCollector().getDatabase().getDialect();
}
private void contributeDbSpecificFunctions(FunctionContributions fc) {
Dialect dialect = getDialect(fc);
if (dialect instanceof PostgreSQLDialect) {
fc.getFunctionRegistry().registerPattern("kc_hash", "sha256(?1::bytea)", getBasicType(fc, StandardBasicTypes.BINARY));
} else if (dialect instanceof CockroachDialect) {
fc.getFunctionRegistry().registerPattern("kc_hash", "sha256(?1)", getBasicType(fc, StandardBasicTypes.STRING));
} else {
LOG.warnf("Dialect %s not recognized.", dialect);
}
}
}

View file

@ -14,26 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.map.storage.jpa.hibernate.jsonb;
package org.keycloak.models.map.storage.jpa.hibernate.contributor;
import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.spi.MetadataBuilderContributor;
import org.hibernate.query.sqm.function.FunctionKind;
import org.hibernate.query.sqm.function.PatternBasedSqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.keycloak.models.map.storage.jpa.hibernate.jsonb.JsonbType;
/**
* A {@link MetadataBuilderContributor} to register JSONB types/functions.
* A {@link MetadataBuilderContributor} to register JSONB type.
*/
public class JsonbMetadataBuilderContributor implements MetadataBuilderContributor {
@Override
public void contribute(MetadataBuilder metadataBuilder) {
metadataBuilder.applyBasicType(JsonbType.INSTANCE);
metadataBuilder.applySqlFunction("->>", new PatternBasedSqmFunctionDescriptor(
new PatternRenderer("?1->>?2"), StandardArgumentsValidators.exactly(2), null, null, "->>",
FunctionKind.NORMAL, null
));
}
}

View file

@ -1,32 +0,0 @@
/*
* Copyright 2021 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.hibernate.dialect;
import org.hibernate.dialect.PostgreSQL95Dialect;
//import org.hibernate.dialect.function.SQLFunctionTemplate;
import org.hibernate.type.StandardBasicTypes;
import org.keycloak.models.map.storage.jpa.hibernate.jsonb.JsonbType;
public class JsonbPostgreSQL95Dialect extends PostgreSQL95Dialect {
public JsonbPostgreSQL95Dialect() {
super();
// registerFunction("->", new SQLFunctionTemplate(JsonbType.INSTANCE, "?1->?2"));
// registerFunction("->>", new SQLFunctionTemplate(StandardBasicTypes.STRING, "?1->>?2"));
// registerFunction("@>", new SQLFunctionTemplate(StandardBasicTypes.BOOLEAN, "?1@>?2::jsonb"));
// registerFunction("kc_hash", new SQLFunctionTemplate(StandardBasicTypes.BINARY, "sha256(?1::bytea)"));
}
}

View file

@ -0,0 +1,18 @@
#
# Copyright 2023 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.
#
org.keycloak.models.map.storage.jpa.hibernate.contributor.JpaMapFunctionContributor

View file

@ -174,7 +174,6 @@
"user": "${keycloak.map.storage.connectionsJpa.user:}",
"password": "${keycloak.map.storage.connectionsJpa.password:}",
"driver": "org.postgresql.Driver",
"driverDialect": "org.keycloak.models.map.storage.jpa.hibernate.dialect.JsonbPostgreSQL95Dialect",
"showSql": "${keycloak.map.storage.connectionsJpa,showSql:false}"
},
"file": {

View file

@ -100,7 +100,6 @@ public class JpaMapStorage extends KeycloakModelParameters {
.config("user", POSTGRES_DB_USER)
.config("password", POSTGRES_DB_PASSWORD)
.config("driver", "org.postgresql.Driver")
.config("driverDialect", "org.keycloak.models.map.storage.jpa.hibernate.dialect.JsonbPostgreSQL95Dialect")
.config("lockTimeout", "${" + LOCK_TIMEOUT_SYSTEM_PROPERTY + ":}");
cf.spi(AuthenticationSessionSpi.PROVIDER_ID).provider(MapRootAuthenticationSessionProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)

View file

@ -98,7 +98,6 @@ public class JpaMapStorageCockroachdb extends KeycloakModelParameters {
.config("user", COCKROACHDB_DB_USER)
.config("password", COCKROACHDB_DB_PASSWORD)
.config("driver", "org.postgresql.Driver")
.config("driverDialect", "org.keycloak.models.map.storage.jpa.hibernate.dialect.JsonbPostgreSQL95Dialect")
.config("lockTimeout", "${" + LOCK_TIMEOUT_SYSTEM_PROPERTY + ":}");
cf.spi(AuthenticationSessionSpi.PROVIDER_ID).provider(MapRootAuthenticationSessionProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, JpaMapStorageProviderFactory.PROVIDER_ID)