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

org.babyfish.jimmer.spring.JSpringSqlClient Maven / Gradle / Ivy

There is a newer version: 0.9.19
Show newest version
package org.babyfish.jimmer.spring;

import org.babyfish.jimmer.spring.cfg.JimmerProperties;
import org.babyfish.jimmer.spring.cfg.support.SpringConnectionManager;
import org.babyfish.jimmer.spring.cfg.support.SpringLogicalDeletedValueGeneratorProvider;
import org.babyfish.jimmer.spring.cfg.support.SpringTransientResolverProvider;
import org.babyfish.jimmer.spring.cfg.support.SpringUserIdGeneratorProvider;
import org.babyfish.jimmer.spring.dialect.DialectDetector;
import org.babyfish.jimmer.spring.meta.SpringMetaStringResolver;
import org.babyfish.jimmer.spring.util.ApplicationContextUtils;
import org.babyfish.jimmer.sql.DraftInterceptor;
import org.babyfish.jimmer.sql.DraftPreProcessor;
import org.babyfish.jimmer.sql.JSqlClient;
import org.babyfish.jimmer.sql.cache.CacheAbandonedCallback;
import org.babyfish.jimmer.sql.cache.CacheFactory;
import org.babyfish.jimmer.sql.cache.CacheOperator;
import org.babyfish.jimmer.sql.di.*;
import org.babyfish.jimmer.sql.dialect.DefaultDialect;
import org.babyfish.jimmer.sql.dialect.Dialect;
import org.babyfish.jimmer.sql.event.TriggerType;
import org.babyfish.jimmer.sql.event.Triggers;
import org.babyfish.jimmer.sql.filter.Filter;
import org.babyfish.jimmer.sql.kt.cfg.KCustomizer;
import org.babyfish.jimmer.sql.kt.cfg.KCustomizerKt;
import org.babyfish.jimmer.sql.kt.cfg.KInitializer;
import org.babyfish.jimmer.sql.kt.cfg.KInitializerKt;
import org.babyfish.jimmer.sql.kt.filter.KFilter;
import org.babyfish.jimmer.sql.kt.filter.impl.JavaFiltersKt;
import org.babyfish.jimmer.sql.meta.DatabaseNamingStrategy;
import org.babyfish.jimmer.sql.meta.MetaStringResolver;
import org.babyfish.jimmer.sql.runtime.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.EmbeddedValueResolver;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ConfigurableApplicationContext;

import javax.sql.DataSource;
import java.util.Collection;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static org.babyfish.jimmer.impl.util.ObjectUtil.firstNonNullOf;
import static org.babyfish.jimmer.impl.util.ObjectUtil.optionalFirstNonNullOf;

class JSpringSqlClient extends JLazyInitializationSqlClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(JSpringSqlClient.class);

    private final ApplicationContext ctx;

    private final DataSource dataSource;

    private final Consumer block;

    private final boolean isKotlin;

    public JSpringSqlClient(
            ApplicationContext ctx,
            DataSource dataSource,
            Consumer block,
            boolean isKotlin
    ) {
        this.ctx = Objects.requireNonNull(ctx, "ctx cannot be null");
        this.dataSource = dataSource;
        this.block = block;
        this.isKotlin = isKotlin;
    }

    @Override
    protected JSqlClient.Builder createBuilder() {

        boolean isCfgKotlin = "kotlin".equals(getRequiredBean(JimmerProperties.class).getLanguage());
        if (isCfgKotlin != isKotlin) {
            throw new IllegalStateException(
                    "Cannot create sql client for \"" +
                    (isKotlin ? "kotlin" : "java") +
                    "\" because \"jimmer.language\" in \"application.properties/application.yml\" is \"" +
                    (isCfgKotlin ? "kotlin" : "java") +
                    "\""
            );
        }

        JimmerProperties properties = getRequiredBean(JimmerProperties.class);
        UserIdGeneratorProvider userIdGeneratorProvider = getOptionalBean(UserIdGeneratorProvider.class);
        LogicalDeletedValueGeneratorProvider logicalDeletedValueGeneratorProvider = getOptionalBean(LogicalDeletedValueGeneratorProvider.class);
        TransientResolverProvider transientResolverProvider = getOptionalBean(TransientResolverProvider.class);
        AopProxyProvider aopProxyProvider = getOptionalBean(AopProxyProvider.class);
        EntityManager entityManager = getOptionalBean(EntityManager.class);
        DatabaseNamingStrategy databaseNamingStrategy = getOptionalBean(DatabaseNamingStrategy.class);
        MetaStringResolver metaStringResolver = getOptionalBean(MetaStringResolver.class);
        Dialect dialect = getOptionalBean(Dialect.class);
        Executor executor = getOptionalBean(Executor.class);
        SqlFormatter sqlFormatter = getOptionalBean(SqlFormatter.class);
        CacheFactory cacheFactory = getOptionalBean(CacheFactory.class);
        CacheOperator cacheOperator = getOptionalBean(CacheOperator.class);
        MicroServiceExchange exchange = getOptionalBean(MicroServiceExchange.class);
        Collection callbacks = getObjects(CacheAbandonedCallback.class);
        Collection> providers = getObjects(ScalarProvider.class);
        Collection> processors = getObjects(DraftPreProcessor.class);
        Collection> interceptors = getObjects(DraftInterceptor.class);
        Collection> exceptionTranslators = getObjects(ExceptionTranslator.class);

        JSqlClient.Builder builder = JSqlClient.newBuilder();
        if (userIdGeneratorProvider != null) {
            builder.setUserIdGeneratorProvider(userIdGeneratorProvider);
        } else {
            builder.setUserIdGeneratorProvider(new SpringUserIdGeneratorProvider(ctx));
        }
        if (logicalDeletedValueGeneratorProvider != null) {
            builder.setLogicalDeletedValueGeneratorProvider(logicalDeletedValueGeneratorProvider);
        } else {
            builder.setLogicalDeletedValueGeneratorProvider(new SpringLogicalDeletedValueGeneratorProvider(ctx));
        }
        if (transientResolverProvider != null) {
            builder.setTransientResolverProvider(transientResolverProvider);
        } else {
            builder.setTransientResolverProvider(new SpringTransientResolverProvider(ctx));
        }
        if (aopProxyProvider != null) {
            builder.setAopProxyProvider(aopProxyProvider);
        } else {
            builder.setAopProxyProvider(AopUtils::getTargetClass);
        }
        if (entityManager != null) {
            builder.setEntityManager(entityManager);
        }
        if (databaseNamingStrategy != null) {
            builder.setDatabaseNamingStrategy(databaseNamingStrategy);
        }
        if (metaStringResolver != null) {
            builder.setMetaStringResolver(metaStringResolver);
        } else if (ctx instanceof ConfigurableApplicationContext) {
            ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) ctx).getBeanFactory();
            builder.setMetaStringResolver(new SpringMetaStringResolver(new EmbeddedValueResolver(beanFactory)));
        }

        builder.setTriggerType(properties.getTriggerType());
        builder.setDefaultDissociateActionCheckable(properties.isDefaultDissociationActionCheckable());
        builder.setIdOnlyTargetCheckingLevel(properties.getIdOnlyTargetCheckingLevel());
        builder.setDefaultEnumStrategy(properties.getDefaultEnumStrategy());
        builder.setDefaultBatchSize(properties.getDefaultBatchSize());
        builder.setDefaultListBatchSize(properties.getDefaultListBatchSize());
        builder.setInListPaddingEnabled(properties.isInListPaddingEnabled());
        builder.setExpandedInListPaddingEnabled(properties.isExpandedInListPaddingEnabled());
        builder.setOffsetOptimizingThreshold(properties.getOffsetOptimizingThreshold());
        builder.setDefaultLockMode(properties.getDefaultLockMode());
        builder.setForeignKeyEnabledByDefault(properties.isForeignKeyEnabledByDefault());
        builder.setMaxCommandJoinCount(properties.getMaxCommandJoinDepth());
        builder.setTargetTransferable(properties.isTargetTransferable());
        builder.setExecutorContextPrefixes(properties.getExecutorContextPrefixes());
        if (properties.isShowSql()) {
            builder.setExecutor(Executor.log(executor));
        } else {
            builder.setExecutor(executor);
        }
        if (sqlFormatter != null) {
            builder.setSqlFormatter(sqlFormatter);
        } else if (properties.isPrettySql()) {
            if (properties.isInlineSqlVariables()) {
                builder.setSqlFormatter(SqlFormatter.INLINE_PRETTY);
            } else {
                builder.setSqlFormatter(SqlFormatter.PRETTY);
            }
        }
        builder
                .setDatabaseValidationMode(properties.getDatabaseValidation().getMode())
                .setDatabaseValidationCatalog(properties.getDatabaseValidation().getCatalog())
                .setDatabaseValidationSchema(properties.getDatabaseValidation().getSchema())
                .setCacheFactory(cacheFactory)
                .setCacheOperator(cacheOperator)
                .addCacheAbandonedCallbacks(callbacks);

        for (ScalarProvider provider : providers) {
            builder.addScalarProvider(provider);
        }

        builder.addDraftPreProcessors(processors);
        builder.addDraftInterceptors(interceptors);
        builder.addExceptionTranslators(exceptionTranslators);
        initializeByLanguage(builder);
        builder.addInitializers(new SpringEventInitializer(ctx));

        builder.setMicroServiceName(properties.getMicroServiceName());
        if (!properties.getMicroServiceName().isEmpty()) {
            builder.setMicroServiceExchange(exchange);
        }

        if (block != null) {
            block.accept(builder);
        }

        ConnectionManager connectionManager = firstNonNullOf(
                () -> ((JSqlClientImplementor.Builder) builder).getConnectionManager(),
                () -> getOptionalBean(ConnectionManager.class),
                () -> dataSource == null ? null : new SpringConnectionManager(dataSource),
                () -> new SpringConnectionManager(getRequiredBean(DataSource.class))
        );

        builder.setConnectionManager(connectionManager);

        if (((JSqlClientImplementor.Builder) builder).getDialect().getClass() == DefaultDialect.class) {
            builder.setDialect(
                    optionalFirstNonNullOf(
                            () -> dialect,
                            properties::getDialect,
                            () -> connectionManager.execute(DialectDetector::detectDialect)
                    )
            );
        }

        return builder;
    }

    private void initializeByLanguage(JSqlClient.Builder builder) {

        Collection> javaFilters = getObjects(Filter.class);
        Collection javaCustomizers = getObjects(Customizer.class);
        Collection javaInitializers = getObjects(Initializer.class);
        Collection> kotlinFilters = getObjects(KFilter.class);
        Collection kotlinCustomizers = getObjects(KCustomizer.class);
        Collection kotlinInitializers = getObjects(KInitializer.class);

        if (isKotlin) {
            if (!javaFilters.isEmpty()) {
                LOGGER.warn(
                        "Jimmer is working in kotlin mode, but some java filters " +
                        "has been found in spring context, they will be ignored"
                );
            }
            if (!javaCustomizers.isEmpty()) {
                LOGGER.warn(
                        "Jimmer is working in kotlin mode, but some java customizers " +
                        "has been found in spring context, they will be ignored"
                );
            }
            if (!javaInitializers.isEmpty()) {
                LOGGER.warn(
                        "Jimmer is working in kotlin mode, but some java initializers " +
                        "has been found in spring context, they will be ignored"
                );
            }
            builder.addFilters(
                    kotlinFilters
                            .stream()
                            .map(JavaFiltersKt::toJavaFilter)
                            .collect(Collectors.toList())
            );
            builder.addCustomizers(
                    kotlinCustomizers
                            .stream()
                            .map(KCustomizerKt::toJavaCustomizer)
                            .collect(Collectors.toList())
            );
            builder.addInitializers(
                    kotlinInitializers
                            .stream()
                            .map(KInitializerKt::toJavaInitializer)
                            .collect(Collectors.toList())
            );
        } else {
            if (!kotlinFilters.isEmpty()) {
                LOGGER.warn(
                        "Jimmer is working in java mode, but some kotlin filters " +
                        "has been found in spring context, they will be ignored"
                );
            }
            if (!kotlinCustomizers.isEmpty()) {
                LOGGER.warn(
                        "Jimmer is working in java mode, but some kotlin customizers " +
                        "has been found in spring context, they will be ignored"
                );
            }
            if (!kotlinInitializers.isEmpty()) {
                LOGGER.warn(
                        "Jimmer is working in kotlin mode, but some kotlin initializers " +
                        "has been found in spring context, they will be ignored"
                );
            }
            builder.addFilters(javaFilters);
            builder.addCustomizers(javaCustomizers);
            builder.addInitializers(javaInitializers);
        }
    }

    private  T getRequiredBean(Class type) {
        return ctx.getBean(type);
    }

    private  T getOptionalBean(Class type) {
        try {
            return ctx.getBean(type);
        } catch (NoSuchBeanDefinitionException ex) {
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    private  Collection getObjects(Class beanType) {
        return (Collection) ApplicationContextUtils.getBeansOfType(ctx, beanType);
    }

    private static class SpringEventInitializer implements Initializer {

        private final ApplicationEventPublisher publisher;

        private SpringEventInitializer(ApplicationEventPublisher publisher) {
            this.publisher = publisher;
        }

        @Override
        public void initialize(JSqlClient sqlClient) throws Exception {
            Triggers[] triggersArr = ((JSqlClientImplementor) sqlClient).getTriggerType() == TriggerType.BOTH ?
                    new Triggers[]{sqlClient.getTriggers(), sqlClient.getTriggers(true)} :
                    new Triggers[]{sqlClient.getTriggers()};
            for (Triggers triggers : triggersArr) {
                triggers.addEntityListener(publisher::publishEvent);
                triggers.addAssociationListener(publisher::publishEvent);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy