Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.blazebit.persistence.impl.CriteriaBuilderFactoryImpl Maven / Gradle / Ivy
/*
* Copyright 2014 - 2023 Blazebit.
*
* 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 com.blazebit.persistence.impl;
import com.blazebit.persistence.CriteriaBuilder;
import com.blazebit.persistence.CriteriaBuilderFactory;
import com.blazebit.persistence.DeleteCriteriaBuilder;
import com.blazebit.persistence.InsertCriteriaBuilder;
import com.blazebit.persistence.LeafOngoingFinalSetOperationCriteriaBuilder;
import com.blazebit.persistence.StartOngoingSetOperationCriteriaBuilder;
import com.blazebit.persistence.UpdateCriteriaBuilder;
import com.blazebit.persistence.parser.FunctionKind;
import com.blazebit.persistence.parser.expression.ExpressionCache;
import com.blazebit.persistence.parser.expression.ExpressionFactory;
import com.blazebit.persistence.parser.expression.ExpressionFactoryImpl;
import com.blazebit.persistence.parser.expression.MacroConfiguration;
import com.blazebit.persistence.parser.expression.SimpleCachingExpressionFactory;
import com.blazebit.persistence.parser.expression.SubqueryExpressionFactory;
import com.blazebit.persistence.spi.ConfigurationSource;
import com.blazebit.persistence.spi.DbmsDialect;
import com.blazebit.persistence.spi.EntityManagerFactoryIntegrator;
import com.blazebit.persistence.spi.ExtendedQuerySupport;
import com.blazebit.persistence.spi.JpaProvider;
import com.blazebit.persistence.spi.JpaProviderFactory;
import com.blazebit.persistence.spi.JpqlFunction;
import com.blazebit.persistence.spi.JpqlFunctionGroup;
import com.blazebit.persistence.spi.JpqlFunctionKind;
import com.blazebit.persistence.spi.PackageOpener;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.metamodel.Metamodel;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author Christian Beikov
* @since 1.0.0
*/
public class CriteriaBuilderFactoryImpl implements CriteriaBuilderFactory {
private final PackageOpener packageOpener;
private final EntityManagerFactory entityManagerFactory;
private final EntityMetamodelImpl metamodel;
private final AssociationParameterTransformerFactory transientEntityParameterTransformerFactory;
private final ExtendedQuerySupport extendedQuerySupport;
private final Map functions;
private final Map, String> namedTypes;
private final ExpressionCache expressionCache;
private final ExpressionFactory expressionFactory;
private final ExpressionFactory subqueryExpressionFactory;
private final QueryConfiguration queryConfiguration;
private final MacroConfiguration macroConfiguration;
private final String configuredDbms;
private final DbmsDialect configuredDbmsDialect;
private final Map configuredRegisteredFunctions;
private final Map registeredFunctionNames;
private final JpaProviderFactory configuredJpaProviderFactory;
private final JpaProvider jpaProvider;
public CriteriaBuilderFactoryImpl(CriteriaBuilderConfigurationImpl config, EntityManagerFactory entityManagerFactory) {
List integrators = config.getEntityManagerIntegrators();
if (integrators.size() < 1) {
throw new IllegalArgumentException("No EntityManagerFactoryIntegrator was found on the classpath! Please check if an integration for your JPA provider is visible on the classpath!");
}
if (integrators.size() > 1) {
throw new IllegalArgumentException("Multiple EntityManagerFactoryIntegrator were found on the classpath! Please remove the wrong integrations from the classpath!");
}
EntityManagerFactoryIntegrator integrator = integrators.get(0);
EntityManagerFactory emf = integrator.registerFunctions(entityManagerFactory, config.getFunctions());
Map registeredFunctions = new HashMap<>(integrator.getRegisteredFunctions(emf));
String dbms = integrator.getDbms(emf);
Map dbmsDialects = config.getDbmsDialects();
DbmsDialect dialect = dbmsDialects.get(dbms);
// Use the default dialect
if (dialect == null) {
dialect = dbmsDialects.get(null);
}
this.packageOpener = config.getPackageOpener();
this.configuredDbms = dbms;
this.configuredDbmsDialect = dialect;
this.configuredRegisteredFunctions = registeredFunctions;
this.configuredJpaProviderFactory = integrator.getJpaProviderFactory(emf);
this.queryConfiguration = new ImmutableQueryConfiguration((Map) (Map) config.getProperties());
final boolean compatibleMode = queryConfiguration.isCompatibleModeEnabled();
final boolean optimize = queryConfiguration.isExpressionOptimizationEnabled();
this.entityManagerFactory = entityManagerFactory;
this.metamodel = new EntityMetamodelImpl(entityManagerFactory, configuredJpaProviderFactory);
this.jpaProvider = new CachingJpaProvider(metamodel);
this.transientEntityParameterTransformerFactory = new TransientEntityAssociationParameterTransformerFactory(metamodel, new AssociationToIdParameterTransformer(jpaProvider));
this.extendedQuerySupport = config.getExtendedQuerySupport();
this.functions = resolveFunctions(config.getFunctions(), configuredRegisteredFunctions);
this.registeredFunctionNames = caseInsensitiveFunctions(configuredRegisteredFunctions);
this.namedTypes = resolveNamedTypes(config.getNamedTypes());
ExpressionFactory originalExpressionFactory = new ExpressionFactoryImpl(functions, metamodel.getEntityTypes(), metamodel.getEnumTypes(), metamodel.getEnumTypesForLiterals(), !compatibleMode, optimize);
this.expressionCache = createCache(queryConfiguration.getExpressionCacheClass());
ExpressionFactory cachingExpressionFactory = new SimpleCachingExpressionFactory(originalExpressionFactory, expressionCache);
ExpressionFactory cachingSubqueryExpressionFactory = new SimpleCachingExpressionFactory(new SubqueryExpressionFactory(functions, metamodel.getEntityTypes(), metamodel.getEnumTypes(), metamodel.getEnumTypesForLiterals(), !compatibleMode, optimize, originalExpressionFactory));
this.macroConfiguration = MacroConfiguration.of(JpqlMacroAdapter.createMacros(config.getMacros(), cachingExpressionFactory));
JpqlMacroStorage macroStorage = new JpqlMacroStorage(null, macroConfiguration);
this.expressionFactory = new JpqlMacroAwareExpressionFactory(cachingExpressionFactory, macroStorage);
this.subqueryExpressionFactory = new JpqlMacroAwareExpressionFactory(cachingSubqueryExpressionFactory, macroStorage);
}
private ExpressionCache createCache(String className) {
try {
return (ExpressionCache) Class.forName(className).newInstance();
} catch (Exception ex) {
throw new IllegalArgumentException("Could not instantiate expression cache: " + className, ex);
}
}
private static Map resolveFunctions(Map functions, Map configuredFunctions) {
Map map = new HashMap<>();
for (Map.Entry entry : functions.entrySet()) {
map.put(entry.getKey().toLowerCase(), getKind(entry.getValue().getKind()));
}
// add standard JPQL aggregate functions
map.put("sum", FunctionKind.AGGREGATE);
map.put("min", FunctionKind.AGGREGATE);
map.put("max", FunctionKind.AGGREGATE);
map.put("avg", FunctionKind.AGGREGATE);
map.put("count", FunctionKind.AGGREGATE);
for (Map.Entry entry : configuredFunctions.entrySet()) {
if (!map.containsKey(entry.getKey())) {
map.put(entry.getKey(), FunctionKind.DETERMINISTIC);
}
}
return map;
}
private static FunctionKind getKind(JpqlFunctionKind kind) {
switch (kind) {
case WINDOW:
return FunctionKind.WINDOW;
case VOLATILE:
return FunctionKind.VOLATILE;
case AGGREGATE:
return FunctionKind.AGGREGATE;
case ORDERED_SET_AGGREGATE:
return FunctionKind.ORDERED_SET_AGGREGATE;
case DETERMINISTIC:
return FunctionKind.DETERMINISTIC;
default:
throw new IllegalArgumentException("Illegal function kind: " + kind);
}
}
private static Map caseInsensitiveFunctions(Map registeredFunctions) {
Map registeredFunctionsNames = new HashMap<>(registeredFunctions.size());
for (Map.Entry registeredFunctionEntry : registeredFunctions.entrySet()) {
registeredFunctionsNames.put(registeredFunctionEntry.getKey().toLowerCase(), registeredFunctionEntry.getKey());
}
return registeredFunctionsNames;
}
private static Map, String> resolveNamedTypes(Map> namedTypes) {
Map, String> types = new HashMap, String>(namedTypes.size());
for (Map.Entry> entry : namedTypes.entrySet()) {
types.put(entry.getValue(), entry.getKey());
}
return Collections.unmodifiableMap(types);
}
public JpaProvider getJpaProvider() {
return jpaProvider;
}
public QueryConfiguration getQueryConfiguration() {
return queryConfiguration;
}
public EntityMetamodelImpl getMetamodel() {
return metamodel;
}
public AssociationParameterTransformerFactory getTransientEntityParameterTransformerFactory() {
return transientEntityParameterTransformerFactory;
}
public MacroConfiguration getMacroConfiguration() {
return macroConfiguration;
}
public ExtendedQuerySupport getExtendedQuerySupport() {
return extendedQuerySupport;
}
public Map getFunctions() {
return functions;
}
public Map, String> getNamedTypes() {
return namedTypes;
}
public ExpressionCache getExpressionCache() {
return expressionCache;
}
public ExpressionFactory getExpressionFactory() {
return expressionFactory;
}
public ExpressionFactory getSubqueryExpressionFactory() {
return subqueryExpressionFactory;
}
@Override
public Map getRegisteredFunctions() {
return Collections.unmodifiableMap(configuredRegisteredFunctions);
}
@Override
public Map getProperties() {
return queryConfiguration.getProperties();
}
@Override
public String getProperty(String propertyName) {
return queryConfiguration.getProperty(propertyName);
}
public MainQuery createMainQuery(EntityManager entityManager) {
return MainQuery.create(this, entityManager, configuredDbms, configuredDbmsDialect, configuredRegisteredFunctions, registeredFunctionNames);
}
@Override
@SuppressWarnings("unchecked")
public StartOngoingSetOperationCriteriaBuilder> startSet(EntityManager entityManager, Class resultClass) {
MainQuery mainQuery = createMainQuery(entityManager);
FinalSetOperationCriteriaBuilderImpl parentFinalSetOperationBuilder = new FinalSetOperationCriteriaBuilderImpl(mainQuery, null, true, resultClass, null, false, null);
OngoingFinalSetOperationCriteriaBuilderImpl subFinalSetOperationBuilder = new OngoingFinalSetOperationCriteriaBuilderImpl(mainQuery, null, false, resultClass, null, true, parentFinalSetOperationBuilder.getSubListener());
LeafOngoingSetOperationCriteriaBuilderImpl leafCb = new LeafOngoingSetOperationCriteriaBuilderImpl(mainQuery, null, false, resultClass, parentFinalSetOperationBuilder.getSubListener(), parentFinalSetOperationBuilder);
StartOngoingSetOperationCriteriaBuilderImpl> cb = new StartOngoingSetOperationCriteriaBuilderImpl>(mainQuery, null, false, resultClass, subFinalSetOperationBuilder.getSubListener(), subFinalSetOperationBuilder, leafCb);
// TODO: This is such an ugly hack, but I don't know how else to fix this generics issue for now
subFinalSetOperationBuilder.setEndSetResult((T) leafCb);
subFinalSetOperationBuilder.setOperationManager.setStartQueryBuilder(cb);
parentFinalSetOperationBuilder.setOperationManager.setStartQueryBuilder(subFinalSetOperationBuilder);
subFinalSetOperationBuilder.getSubListener().onBuilderStarted(cb);
parentFinalSetOperationBuilder.getSubListener().onBuilderStarted(leafCb);
return cb;
}
@Override
public CriteriaBuilder create(EntityManager entityManager, Class resultClass) {
return create(entityManager, resultClass, null);
}
@Override
public CriteriaBuilder create(EntityManager entityManager, Class resultClass, String alias) {
MainQuery mainQuery = createMainQuery(entityManager);
CriteriaBuilderImpl cb = new CriteriaBuilderImpl(mainQuery, true, resultClass, alias);
return cb;
}
@Override
public DeleteCriteriaBuilder delete(EntityManager entityManager, Class deleteClass) {
return delete(entityManager, deleteClass, null);
}
@Override
public DeleteCriteriaBuilder delete(EntityManager entityManager, Class deleteClass, String alias) {
MainQuery mainQuery = createMainQuery(entityManager);
DeleteCriteriaBuilderImpl cb = new DeleteCriteriaBuilderImpl(mainQuery, deleteClass, alias);
return cb;
}
@Override
public DeleteCriteriaBuilder deleteCollection(EntityManager entityManager, Class deleteOwnerClass, String collectionName) {
return deleteCollection(entityManager, deleteOwnerClass, null, collectionName);
}
@Override
public DeleteCriteriaBuilder deleteCollection(EntityManager entityManager, Class deleteOwnerClass, String alias, String collectionName) {
MainQuery mainQuery = createMainQuery(entityManager);
DeleteCollectionCriteriaBuilderImpl cb = new DeleteCollectionCriteriaBuilderImpl(mainQuery, deleteOwnerClass, alias, collectionName);
return cb;
}
@Override
public UpdateCriteriaBuilder update(EntityManager entityManager, Class updateClass) {
return update(entityManager, updateClass, null);
}
@Override
public UpdateCriteriaBuilder update(EntityManager entityManager, Class updateClass, String alias) {
MainQuery mainQuery = createMainQuery(entityManager);
UpdateCriteriaBuilderImpl cb = new UpdateCriteriaBuilderImpl(mainQuery, updateClass, alias);
return cb;
}
@Override
public UpdateCriteriaBuilder updateCollection(EntityManager entityManager, Class updateOwnerClass, String collectionName) {
return updateCollection(entityManager, updateOwnerClass, null, collectionName);
}
@Override
public UpdateCriteriaBuilder updateCollection(EntityManager entityManager, Class updateOwnerClass, String alias, String collectionName) {
MainQuery mainQuery = createMainQuery(entityManager);
UpdateCollectionCriteriaBuilderImpl cb = new UpdateCollectionCriteriaBuilderImpl(mainQuery, updateOwnerClass, alias, collectionName);
return cb;
}
@Override
public InsertCriteriaBuilder insert(EntityManager entityManager, Class insertClass) {
MainQuery mainQuery = createMainQuery(entityManager);
InsertCriteriaBuilderImpl cb = new InsertCriteriaBuilderImpl(mainQuery, insertClass);
return cb;
}
@Override
public InsertCriteriaBuilder insertCollection(EntityManager entityManager, Class insertOwnerClass, String collectionName) {
MainQuery mainQuery = createMainQuery(entityManager);
InsertCollectionCriteriaBuilderImpl cb = new InsertCollectionCriteriaBuilderImpl(mainQuery, insertOwnerClass, collectionName);
return cb;
}
@Override
@SuppressWarnings("unchecked")
public T getService(Class serviceClass) {
if (SubqueryExpressionFactory.class.equals(serviceClass)) {
return (T) subqueryExpressionFactory;
} else if (ConfigurationSource.class.equals(serviceClass)) {
return (T) this;
} else if (ExpressionFactory.class.isAssignableFrom(serviceClass)) {
return (T) expressionFactory;
} else if (DbmsDialect.class.equals(serviceClass)) {
return (T) configuredDbmsDialect;
} else if (ExtendedQuerySupport.class.equals(serviceClass)) {
return (T) extendedQuerySupport;
} else if (JpaProviderFactory.class.equals(serviceClass)) {
return (T) configuredJpaProviderFactory;
} else if (JpaProvider.class.equals(serviceClass)) {
return (T) jpaProvider;
} else if (ExpressionCache.class.equals(serviceClass)) {
return (T) expressionCache;
} else if (Metamodel.class.isAssignableFrom(serviceClass)) {
return (T) metamodel;
} else if (EntityManagerFactory.class.equals(serviceClass)) {
return (T) entityManagerFactory;
} else if (PackageOpener.class.equals(serviceClass)) {
if (CallerChecker.isCallerTrusted()) {
return (T) packageOpener;
}
}
return null;
}
}