All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.blazebit.persistence.impl.CriteriaBuilderFactoryImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014 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 java.util.*;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import com.blazebit.persistence.CriteriaBuilder;
import com.blazebit.persistence.CriteriaBuilderFactory;
import com.blazebit.persistence.DeleteCriteriaBuilder;
import com.blazebit.persistence.InsertCriteriaBuilder;
import com.blazebit.persistence.LeafOngoingSetOperationCriteriaBuilder;
import com.blazebit.persistence.StartOngoingSetOperationCriteriaBuilder;
import com.blazebit.persistence.UpdateCriteriaBuilder;
import com.blazebit.persistence.impl.expression.*;
import com.blazebit.persistence.impl.util.PropertyUtils;
import com.blazebit.persistence.spi.*;

/**
 *
 * @author Christian Beikov
 * @since 1.0
 */
public class CriteriaBuilderFactoryImpl implements CriteriaBuilderFactory {

    private final boolean compatibleMode;
    private final boolean optimize;

    private final EntityMetamodel metamodel;
    private final List queryTransformers;
    private final ExtendedQuerySupport extendedQuerySupport;
    private final Map dbmsDialects;
    private final Set aggregateFunctions;
    private final Map, String> treatFunctions;
    private final ExpressionCache expressionCache;
    private final ExpressionFactory expressionFactory;
    private final ExpressionFactory subqueryExpressionFactory;
    private final Map properties;

    private final MacroConfiguration macroConfiguration;
    private final String configuredDbms;
    private final DbmsDialect configuredDbmsDialect;
    private final Set configuredRegisteredFunctions;
    private final JpaProviderFactory configuredJpaProviderFactory;

    public CriteriaBuilderFactoryImpl(CriteriaBuilderConfigurationImpl config, EntityManagerFactory entityManagerFactory) {
        this.compatibleMode = Boolean.valueOf(config.getProperty(ConfigurationProperties.COMPATIBLE_MODE));
        this.optimize = PropertyUtils.getAsBooleanProperty(config.getProperties(), ConfigurationProperties.EXPRESSION_OPTIMIZATION, true);

        this.metamodel = new EntityMetamodel(entityManagerFactory.getMetamodel());
        this.queryTransformers = new ArrayList(config.getQueryTransformers());
        this.extendedQuerySupport = config.getExtendedQuerySupport();
        this.dbmsDialects = new HashMap(config.getDbmsDialects());
        this.aggregateFunctions = resolveAggregateFunctions(config.getFunctions());
        this.treatFunctions = resolveTreatTypes(config.getTreatTypes());

        ExpressionFactory originalExpressionFactory = new ExpressionFactoryImpl(aggregateFunctions, !compatibleMode, optimize);
        this.expressionCache = createCache(config.getProperty(ConfigurationProperties.EXPRESSION_CACHE_CLASS));
        ExpressionFactory cachingExpressionFactory = new SimpleCachingExpressionFactory(originalExpressionFactory, expressionCache);
        ExpressionFactory cachingSubqueryExpressionFactory = new SimpleCachingExpressionFactory(new SubqueryExpressionFactory(aggregateFunctions, !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);
        this.properties = copyProperties(config.getProperties());
        
        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());
        Set registeredFunctions = new HashSet(integrator.getRegisteredFunctions(emf));
        String dbms = integrator.getDbms(emf);
        DbmsDialect dialect = dbmsDialects.get(dbms);
        
        // Use the default dialect
        if (dialect == null) {
            dialect = dbmsDialects.get(null);
        }

        this.configuredDbms = dbms;
        this.configuredDbmsDialect = dialect;
        this.configuredRegisteredFunctions = registeredFunctions;
        this.configuredJpaProviderFactory = integrator.getJpaProviderFactory(emf);
    }

    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 Set resolveAggregateFunctions(Map functions) {
        Set aggregateFunctions = new HashSet();
        for (Map.Entry entry : functions.entrySet()) {
            if (entry.getValue().isAggregate()) {
                aggregateFunctions.add(entry.getKey().toLowerCase());
            }
        }
        return aggregateFunctions;
    }

    private static Map, String> resolveTreatTypes(Map> treatTypes) {
        Map, String> types = new HashMap, String>(treatTypes.size());
        for (Map.Entry> entry : treatTypes.entrySet()) {
            types.put(entry.getValue(), "TREAT_" + entry.getKey().toUpperCase());
        }
        return Collections.unmodifiableMap(types);
    }

    public JpaProvider createJpaProvider(EntityManager em) {
        return configuredJpaProviderFactory.createJpaProvider(em);
    }

    public boolean isCompatibleMode() {
        return compatibleMode;
    }

    public boolean isOptimize() {
        return optimize;
    }

    public EntityMetamodel getMetamodel() {
        return metamodel;
    }

    public MacroConfiguration getMacroConfiguration() {
        return macroConfiguration;
    }

    public List getQueryTransformers() {
        return queryTransformers;
    }

    public ExtendedQuerySupport getExtendedQuerySupport() {
        return extendedQuerySupport;
    }

    public Set getAggregateFunctions() {
        return aggregateFunctions;
    }

    public Map, String> getTreatFunctions() {
        return treatFunctions;
    }

    public ExpressionCache getExpressionCache() {
        return expressionCache;
    }

    public ExpressionFactory getExpressionFactory() {
        return expressionFactory;
    }

    public ExpressionFactory getSubqueryExpressionFactory() {
        return subqueryExpressionFactory;
    }

    @Override
    public Map getProperties() {
        return properties;
    }

    @Override
	public String getProperty(String propertyName) {
		return properties.get(propertyName);
	}
    
    private MainQuery createMainQuery(EntityManager entityManager) {
        return MainQuery.create(this, entityManager, configuredDbms, configuredDbmsDialect, configuredRegisteredFunctions);
    }

    @Override
    @SuppressWarnings("unchecked")
    public  StartOngoingSetOperationCriteriaBuilder> startSet(EntityManager entityManager, Class resultClass) {
        MainQuery mainQuery = createMainQuery(entityManager);
        FinalSetOperationCriteriaBuilderImpl parentFinalSetOperationBuilder = new FinalSetOperationCriteriaBuilderImpl(mainQuery, true, resultClass, null, false, null);
        OngoingFinalSetOperationCriteriaBuilderImpl subFinalSetOperationBuilder = new OngoingFinalSetOperationCriteriaBuilderImpl(mainQuery, false, resultClass, null, true, parentFinalSetOperationBuilder.getSubListener());
        
        LeafOngoingSetOperationCriteriaBuilderImpl leafCb = new LeafOngoingSetOperationCriteriaBuilderImpl(mainQuery, false, resultClass, parentFinalSetOperationBuilder.getSubListener(), parentFinalSetOperationBuilder);
        OngoingSetOperationCriteriaBuilderImpl> cb = new OngoingSetOperationCriteriaBuilderImpl>(mainQuery, 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  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  InsertCriteriaBuilder insert(EntityManager entityManager, Class insertClass) {
        MainQuery mainQuery = createMainQuery(entityManager);
        InsertCriteriaBuilderImpl cb = new InsertCriteriaBuilderImpl(mainQuery, insertClass);
        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 (ExpressionCache.class.equals(serviceClass)) {
            return (T) expressionCache;
        }

        return null;
    }

    private Map copyProperties(Properties properties) {
        Map newProperties = new HashMap();

        for (Map.Entry entry : properties.entrySet()) {
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            newProperties.put(key, value);
        }

        return newProperties;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy