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

com.cvent.dropwizard.mybatis.sessionbuilder.DefaultSqlSessionFactoryProvider Maven / Gradle / Ivy

Go to download

An open source bridge layer so that you can use mybatis with dropwizard + other useful utility methods often used within an enterprise.

There is a newer version: 4.0.4
Show newest version
package com.cvent.dropwizard.mybatis.sessionbuilder;

import com.cvent.dropwizard.mybatis.MyBatisFactory;
import com.cvent.dropwizard.mybatis.datasource.ConfigurableLazyDataSourceFactory;
import com.cvent.pangaea.MultiEnvAware;
import io.dropwizard.db.ManagedDataSource;
import io.dropwizard.setup.Environment;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.session.SqlSessionFactory;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * This is the base SqlSessionFactoryProvider class to manage SQL session initialization for all environments specified
 * in the configuration on startup. It also manages new session creation during runtime for new environments not
 * available in the existing session factories collection.
 *
 * @author Brent Ryan, Nikhil Bhagwat, zhuang
 */
public final class DefaultSqlSessionFactoryProvider implements SqlSessionFactoryProvider {

    private final MultiEnvAware sessionFactories;
    private final MultiEnvAware dataSourceFactories;
    private final Environment dropwizardEnvironment;
    private final String applicationName;
    private final List> typeHandlers;
    private final List> sqlMappers;
    private final Map, Class> typeClassToTypeHandlerClassMap;
    private final Map> typeToAliasClassMap;
    private final ObjectFactory objectFactory;
    private final Map mybatisConfigurationSettings;

    /**
     * Create a new provider instance
     * 
     * @param dropwizardEnvironment The dropwizard environment object
     * @param applicationName       The application name
     * @param dataSourceFactories   The MultiEnvAware datasource list used to create session factories from
     * @param typeHandlers          The list of type handlers to configure with each session factory
     * @param sqlMappers            The list of sql mappers to configure with each session factory
     */
    private DefaultSqlSessionFactoryProvider(Environment dropwizardEnvironment,
                                             String applicationName,
                                             MultiEnvAware dataSourceFactories,
                                             List> typeHandlers,
                                             List> sqlMappers,
                                             Map, Class> typeClassToTypeHandlerClassMap,
                                             Map> typeToAliasClassMap,
                                             ObjectFactory objectFactory,
                                             Map mybatisConfigurationSettingsMap) {
        this.dropwizardEnvironment = dropwizardEnvironment;
        this.applicationName = applicationName;
        this.dataSourceFactories = dataSourceFactories;
        this.typeHandlers = typeHandlers;
        this.sqlMappers = sqlMappers;
        this.typeClassToTypeHandlerClassMap = typeClassToTypeHandlerClassMap;
        this.typeToAliasClassMap = typeToAliasClassMap;
        this.objectFactory = objectFactory;
        this.mybatisConfigurationSettings = mybatisConfigurationSettingsMap;
        sessionFactories = dataSourceFactories.convert((env, dataSource) -> buildSessionFactory(dataSource, env));
    }

    /**
     * A simple builder allowing us to customize the underlying session factory provider
     */
    public static class Builder {

        private final List> typeHandlers = new ArrayList<>();
        private final List> sqlMappers = new ArrayList<>();
        private final Map, Class> typeClassToTypeHandlerClassMap = new HashMap<>();
        private final Map> typeToAliasClassMap = new HashMap<>();
        private final MultiEnvAware dataSourceFactories;
        private final Environment dropwizardEnvironment;
        private final String applicationName;
        private ObjectFactory objectFactory;
        private final Map mybatisConfigurationSettingsMap = new HashMap<>();

        /**
         * A new Builder
         * 
         * @param dropwizardEnvironment The dropwizard environment object
         * @param applicationName The application name
         * @param dataSourceFactories The MultiEnvAware datasource list used to create session factories from
         */
        public Builder(Environment dropwizardEnvironment, String applicationName,
                MultiEnvAware dataSourceFactories) {
            this.dropwizardEnvironment = dropwizardEnvironment;
            this.applicationName = applicationName;
            this.dataSourceFactories = dataSourceFactories;
        }

        /**
         * Register a new type handler to be used with this sql session provider
         * 
         * @param typeHandler
         * @return 
         */
        public Builder register(Class typeHandler) {
            typeHandlers.add(typeHandler);
            return this;
        }

        /**
         * Register a new type and type handler association to be used with this sql session provider
         *
         * @param javaTypeClass
         * @param typeHandlerClass
         * @return
         */
        public Builder register(Class javaTypeClass, Class typeHandlerClass) {
            typeClassToTypeHandlerClassMap.put(javaTypeClass, typeHandlerClass);
            return this;
        }

        /**
         * Register a new alias to be used with this sql session provider
         *
         * @param alias
         * @param value
         * @return
         */
        public Builder registerAlias(String alias, Class value) {
            typeToAliasClassMap.put(alias, value);
            return this;
        }

        /**
         * Register a new sql mapper to be used with this sql session provider
         *
         * @param sqlMapper
         * @return 
         */
        public Builder addMapper(Class sqlMapper) {
            sqlMappers.add(sqlMapper);
            return this;
        }

        /**
         * Add an object factory to the builder
         * 
         * @param factory
         * @return 
         */
        public Builder objectFactory(ObjectFactory factory) {
            this.objectFactory = factory;
            return this;
        }

        /**
         * Add a new MyBatis Configuration Setting.
         * @param configName
         * @param configSettingObject
         * @return
         */
        public Builder addConfigurationSettings(String configName, Object configSettingObject) {
            this.mybatisConfigurationSettingsMap.put(configName, configSettingObject);
            return this;
        }

        /**
         * Create a new SqlSessionFactoryProvider based on the attributes that have been added to this builder
         * 
         * @return a new instance of SqlSessionFactoryProvider
         */
        public SqlSessionFactoryProvider build() {
            return new DefaultSqlSessionFactoryProvider(dropwizardEnvironment,
                    applicationName,
                    dataSourceFactories,
                    typeHandlers,
                    sqlMappers,
                    typeClassToTypeHandlerClassMap,
                    typeToAliasClassMap,
                    objectFactory,
                    mybatisConfigurationSettingsMap);
        }

    }

    /**
     * Build a new sql session factory.  This method is NOT threadsafe so this internal class must take care to
     * synchronize on sessionFactories.
     * 
     * @param dataSource        The datasource to use for constructing the session factory from
     * @param environmentName   The environment name to use
     * @return  A new SqlSessionFactory
     */
    private SqlSessionFactory buildSessionFactory(ConfigurableLazyDataSourceFactory dataSource,
            String environmentName) {
        String dataSourceName = String.format("%s-%s-sql", applicationName, environmentName);

        ManagedDataSource ds = dataSource.build(dropwizardEnvironment.metrics(), dataSourceName);
        SqlSessionFactory sessionFactory = new MyBatisFactory()
                .build(dropwizardEnvironment, dataSource, ds, dataSourceName);

        for (Map.Entry, Class> typeClassToTypeHandlerClassEntry :
                typeClassToTypeHandlerClassMap.entrySet()) {
            sessionFactory.getConfiguration().getTypeHandlerRegistry().register(
                    typeClassToTypeHandlerClassEntry.getKey(),
                    typeClassToTypeHandlerClassEntry.getValue());
        }

        for (Map.Entry> typeToAliasClassEntry :
                typeToAliasClassMap.entrySet()) {
            sessionFactory.getConfiguration().getTypeAliasRegistry().registerAlias(
                    typeToAliasClassEntry.getKey(),
                    typeToAliasClassEntry.getValue());
        }

        for (Class typeHandler : typeHandlers) {
            sessionFactory.getConfiguration().getTypeHandlerRegistry().register(typeHandler);
        }

        for (Class sqlMapper : sqlMappers) {
            sessionFactory.getConfiguration().addMapper(sqlMapper);
        }

        if (objectFactory != null) {
            sessionFactory.getConfiguration().setObjectFactory(objectFactory);
        }

        mybatisConfigurationSettings.forEach((settingName, configSettingObject) -> {
            try {
                Field field = sessionFactory.getConfiguration().getClass().getDeclaredField(settingName);
                field.setAccessible(true);
                field.set(sessionFactory.getConfiguration(), configSettingObject);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        });

        //Only add to it after it's be initialized.  This is used mainly for "templates"
        if (sessionFactories != null) {
            sessionFactories.put(environmentName, sessionFactory);
        }

        return sessionFactory;
    }

    /**
     * Get SQL session by environment name, create a new session if requested environment is not found
     *
     * @param environmentName
     * @return SqlSessionFactory
     */
    @Override
    public SqlSessionFactory getSqlSessionFactory(String environmentName) {
        if (StringUtils.isBlank(environmentName) || sessionFactories.containsKey(environmentName)) {
            return sessionFactories.get(environmentName);
        }

        //implement double check locking so that we're protected against multiple threads trying to get a session
        //factory while avoiding the possibility of duplication session factories and not hurting performance for 99% of
        //the calls.
        synchronized (this) {
            if (StringUtils.isBlank(environmentName) || sessionFactories.containsKey(environmentName)) {
                return sessionFactories.get(environmentName);
            } else {
                return buildSessionFactory(dataSourceFactories.get(environmentName), environmentName);
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy