// Path: tsharding-client/src/main/java/com/mogujie/trade/db/DataSourceLookup.java
// public class DataSourceLookup implements Closeable {
// 
//     private final Map<String, ReadWriteSplittingDataSource> dataSources;
// 
//     public DataSourceLookup(Map<String, ReadWriteSplittingDataSource> dataSources) {
//         this.dataSources = Collections.unmodifiableMap(dataSources);
//     }
// 
//     /**
//      * @param name
//      * @return
//      */
//     public ReadWriteSplittingDataSource get(String name) {
//         return this.dataSources.get(name);
//     }
// 
//     public Map<String, ReadWriteSplittingDataSource> getMapping() {
//         return this.dataSources;
//     }
// 
//     @Override
//     public void close() throws IOException {
//         for (ReadWriteSplittingDataSource dataSource : dataSources.values()) {
//             dataSource.close();
//         }
//     }
// }
// 
// Path: tsharding-client/src/main/java/com/mogujie/trade/db/ReadWriteSplittingDataSource.java
// public class ReadWriteSplittingDataSource extends AbstractDataSource implements DataSource, Closeable {
// 
//     private final String name;
// 
//     private final DataSource masterDataSource;
// 
//     private final DataSource slaveDataSource;
// 
//     public ReadWriteSplittingDataSource(String name, DataSource masterDataSource, DataSource slaveDataSource) {
//         this.name = name;
//         this.masterDataSource = masterDataSource;
//         this.slaveDataSource = slaveDataSource;
//         Assert.isTrue(masterDataSource != slaveDataSource || masterDataSource != null,
//                 "masterDataSource and slaveDataSource can't be both null!");
//     }
// 
//     @Override
//     public Connection getConnection() throws SQLException {
//         return this.determineTargetDataSource().getConnection();
//     }
// 
//     public DataSource getSlaveDataSource() {
//         return slaveDataSource;
//     }
// 
//     private DataSource determineTargetDataSource() {
//         if (slaveDataSource == null) {
//             return masterDataSource;
//         }
// 
//         if (this.isInTransaction()) {
//             return masterDataSource;
//         }
// 
//         return ReadWriteSplittingContext.isMaster() ? masterDataSource : slaveDataSource;
//     }
// 
//     private boolean isInTransaction() {
//         return RoutingDataSourceTransactionContext.getCurTransactionDataSource() != null;
//     }
// 
//     @Override
//     public Connection getConnection(String username, String password) throws SQLException {
//         return this.determineTargetDataSource().getConnection(username, password);
//     }
// 
//     public String getName() {
//         return this.name;
//     }
// 
//     @Override
//     public String toString() {
//         StringBuilder builder = new StringBuilder();
//         builder.append("ReadWriteSplittingDataSource [");
//         if (name != null) {
//             builder.append("name=").append(name).append(", ");
//         }
//         if (masterDataSource != null) {
//             builder.append("masterDataSource=").append(masterDataSource).append(", ");
//         }
//         if (slaveDataSource != null) {
//             builder.append("slaveDataSource=").append(slaveDataSource);
//         }
//         builder.append("]");
//         return builder.toString();
//     }
// 
//     @Override
//     public void close() throws IOException {
//         if (this.masterDataSource != null) {
//             if (masterDataSource instanceof AutoCloseable) {
//                 try {
//                     ((AutoCloseable) masterDataSource).close();
//                 } catch (Exception ignore) {
//                 }
//             }
//         }
// 
//         if (this.slaveDataSource != null) {
//             if (slaveDataSource instanceof AutoCloseable) {
//                 try {
//                     ((AutoCloseable) slaveDataSource).close();
//                 } catch (Exception ignore) {
//                 }
//             }
//         }
//     }
// 
// }


import com.mogujie.trade.db.DataSourceLookup;
import com.mogujie.trade.db.ReadWriteSplittingDataSource;
import com.mogujie.trade.tsharding.route.orm.base.*;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        this.dataSourceLookup = beanFactory.getBean(DataSourceLookup.class);

        try {
            this.initSqlSessionFactories(beanFactory);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        ClassPathScanHandler scanner = new ClassPathScanHandler();
        Set<Class<?>> mapperClasses = new HashSet<>();
        for (String mapperPackage : this.mapperPacakages) {
            Set<Class<?>> classes = scanner.getPackageAllClasses(mapperPackage.trim(), false);
            mapperClasses.addAll(classes);
        }
        for (Class<?> clazz : mapperClasses) {
            if (isMapper(clazz)) {
                Object mapper = this.newMapper(clazz);
                beanFactory.registerSingleton(Character.toLowerCase(clazz.getSimpleName().charAt(0))
                        + clazz.getSimpleName().substring(1), mapper);
            }
        }

    }

    private void initSqlSessionFactories(ConfigurableListableBeanFactory beanFactory) throws Exception {
        Map<String, SqlSessionFactory> sqlSessionFactories = new HashMap<>(this.dataSourceLookup.getMapping().size());

// Path: tsharding-client/src/main/java/com/mogujie/trade/db/DataSourceLookup.java
// public class DataSourceLookup implements Closeable {
// 
//     private final Map<String, ReadWriteSplittingDataSource> dataSources;
// 
//     public DataSourceLookup(Map<String, ReadWriteSplittingDataSource> dataSources) {
//         this.dataSources = Collections.unmodifiableMap(dataSources);
//     }
// 
//     /**
//      * @param name
//      * @return
//      */
//     public ReadWriteSplittingDataSource get(String name) {
//         return this.dataSources.get(name);
//     }
// 
//     public Map<String, ReadWriteSplittingDataSource> getMapping() {
//         return this.dataSources;
//     }
// 
//     @Override
//     public void close() throws IOException {
//         for (ReadWriteSplittingDataSource dataSource : dataSources.values()) {
//             dataSource.close();
//         }
//     }
// }
// 
// Path: tsharding-client/src/main/java/com/mogujie/trade/db/ReadWriteSplittingDataSource.java
// public class ReadWriteSplittingDataSource extends AbstractDataSource implements DataSource, Closeable {
// 
//     private final String name;
// 
//     private final DataSource masterDataSource;
// 
//     private final DataSource slaveDataSource;
// 
//     public ReadWriteSplittingDataSource(String name, DataSource masterDataSource, DataSource slaveDataSource) {
//         this.name = name;
//         this.masterDataSource = masterDataSource;
//         this.slaveDataSource = slaveDataSource;
//         Assert.isTrue(masterDataSource != slaveDataSource || masterDataSource != null,
//                 "masterDataSource and slaveDataSource can't be both null!");
//     }
// 
//     @Override
//     public Connection getConnection() throws SQLException {
//         return this.determineTargetDataSource().getConnection();
//     }
// 
//     public DataSource getSlaveDataSource() {
//         return slaveDataSource;
//     }
// 
//     private DataSource determineTargetDataSource() {
//         if (slaveDataSource == null) {
//             return masterDataSource;
//         }
// 
//         if (this.isInTransaction()) {
//             return masterDataSource;
//         }
// 
//         return ReadWriteSplittingContext.isMaster() ? masterDataSource : slaveDataSource;
//     }
// 
//     private boolean isInTransaction() {
//         return RoutingDataSourceTransactionContext.getCurTransactionDataSource() != null;
//     }
// 
//     @Override
//     public Connection getConnection(String username, String password) throws SQLException {
//         return this.determineTargetDataSource().getConnection(username, password);
//     }
// 
//     public String getName() {
//         return this.name;
//     }
// 
//     @Override
//     public String toString() {
//         StringBuilder builder = new StringBuilder();
//         builder.append("ReadWriteSplittingDataSource [");
//         if (name != null) {
//             builder.append("name=").append(name).append(", ");
//         }
//         if (masterDataSource != null) {
//             builder.append("masterDataSource=").append(masterDataSource).append(", ");
//         }
//         if (slaveDataSource != null) {
//             builder.append("slaveDataSource=").append(slaveDataSource);
//         }
//         builder.append("]");
//         return builder.toString();
//     }
// 
//     @Override
//     public void close() throws IOException {
//         if (this.masterDataSource != null) {
//             if (masterDataSource instanceof AutoCloseable) {
//                 try {
//                     ((AutoCloseable) masterDataSource).close();
//                 } catch (Exception ignore) {
//                 }
//             }
//         }
// 
//         if (this.slaveDataSource != null) {
//             if (slaveDataSource instanceof AutoCloseable) {
//                 try {
//                     ((AutoCloseable) slaveDataSource).close();
//                 } catch (Exception ignore) {
//                 }
//             }
//         }
//     }
// 
// }


// Path: tsharding-client/src/main/java/com/mogujie/trade/tsharding/route/orm/MapperScannerWithSharding.java
import com.mogujie.trade.db.DataSourceLookup;
import com.mogujie.trade.db.ReadWriteSplittingDataSource;
import com.mogujie.trade.tsharding.route.orm.base.*;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        this.dataSourceLookup = beanFactory.getBean(DataSourceLookup.class);

        try {
            this.initSqlSessionFactories(beanFactory);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        ClassPathScanHandler scanner = new ClassPathScanHandler();
        Set<Class<?>> mapperClasses = new HashSet<>();
        for (String mapperPackage : this.mapperPacakages) {
            Set<Class<?>> classes = scanner.getPackageAllClasses(mapperPackage.trim(), false);
            mapperClasses.addAll(classes);
        }
        for (Class<?> clazz : mapperClasses) {
            if (isMapper(clazz)) {
                Object mapper = this.newMapper(clazz);
                beanFactory.registerSingleton(Character.toLowerCase(clazz.getSimpleName().charAt(0))
                        + clazz.getSimpleName().substring(1), mapper);
            }
        }

    }

    private void initSqlSessionFactories(ConfigurableListableBeanFactory beanFactory) throws Exception {
        Map<String, SqlSessionFactory> sqlSessionFactories = new HashMap<>(this.dataSourceLookup.getMapping().size());

        ReadWriteSplittingDataSource defaultDataSource = null;