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

io.microsphere.spring.test.jdbc.embedded.EmbeddedDataBaseBeanDefinitionRegistrar Maven / Gradle / Ivy

There is a newer version: 0.0.3
Show newest version
package io.microsphere.spring.test.jdbc.embedded;

import ch.vorburger.exec.ManagedProcessException;
import ch.vorburger.mariadb4j.DB;
import ch.vorburger.mariadb4j.DBConfigurationBuilder;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.StringReader;
import java.lang.annotation.Annotation;
import java.util.Properties;
import java.util.StringJoiner;

import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;
import static org.springframework.core.annotation.AnnotationAttributes.fromMap;

/**
 * Embedded database {@link ImportBeanDefinitionRegistrar}
 *
 * @author Mercy
 * @see EnableEmbeddedDatabase
 * @since 1.0.0
 */
class EmbeddedDataBaseBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    private static final Class ANNOTATION_TYPE = EnableEmbeddedDatabase.class;

    private static final String INTERNAL_USE_PROPERTY_NAME_PREFIX = "_";

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes attributes = fromMap(metadata.getAnnotationAttributes(ANNOTATION_TYPE.getName()));
        registerBeanDefinitions(attributes, registry);
    }

    void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
        EmbeddedDatabaseType type = attributes.getEnum("type");

        switch (type) {
            case SQLITE:
                processSQLite(attributes, registry);
                break;
            case MARIADB:
                processMariaDB(attributes, registry);
                break;
        }
    }

    private void processSQLite(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
        registerSQLiteDataSourceBeanDefinition(attributes, registry);
    }

    private void processMariaDB(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
        int port = attributes.getNumber("port");
        Properties properties = resolveProperties(attributes, registry);
        startEmbeddedMariaDB4j(port, properties);
        registerMariaDBDataSourceBeanDefinition(port, attributes, registry);
    }

    private void registerSQLiteDataSourceBeanDefinition(AnnotationAttributes attributes,
                                                        BeanDefinitionRegistry registry) {
        registerDataSourceBeanDefinition("jdbc:sqlite::memory:", attributes, registry);
    }

    private void startEmbeddedMariaDB4j(int port, Properties properties) {
        DBConfigurationBuilder configBuilder = DBConfigurationBuilder.newBuilder();
        configBuilder.setPort(port);
        String sqlSource = properties.getProperty("_sql.source");
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        DB db = null;
        try {
            db = DB.newEmbeddedDB(configBuilder.build());
            db.start();
            if (StringUtils.hasText(sqlSource)) {
                Resource resource = resourceLoader.getResource(sqlSource);
                db.source(resource.getInputStream());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void registerMariaDBDataSourceBeanDefinition(int port,
                                                         AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
        String jdbcURL = "jdbc:mariadb://127.0.0.1:" + port;
        registerDataSourceBeanDefinition(jdbcURL, attributes, registry);
    }

    private void registerDataSourceBeanDefinition(String jdbcURL,
                                                  AnnotationAttributes attributes,
                                                  BeanDefinitionRegistry registry) {
        String beanName = attributes.getString("dataSource");
        boolean primary = attributes.getBoolean("primary");
        Properties properties = resolveProperties(attributes, registry);

        BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(DriverManagerDataSource.class);
        beanDefinitionBuilder.addConstructorArgValue(jdbcURL);
        beanDefinitionBuilder.addConstructorArgValue(properties);
        if (registry.containsBeanDefinition(beanName)) {
            throw new BeanCreationException("The duplicated BeanDefinition with name : " + beanName);
        }
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        beanDefinition.setPrimary(primary);
        registry.registerBeanDefinition(beanName, beanDefinition);
    }

    private Properties resolveProperties(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
        ConfigurableBeanFactory beanFactory = null;
        if (registry instanceof ConfigurableBeanFactory) {
            beanFactory = (ConfigurableBeanFactory) registry;
        }
        String[] values = attributes.getStringArray("properties");
        if (values.length == 0) {
            return null;
        }
        StringJoiner stringJoiner = new StringJoiner(System.lineSeparator());
        for (String value : values) {
            // TODO
            // Resolve the placeholders
            // If value starts with "_", ignored
//            if (value.startsWith(INTERNAL_USE_PROPERTY_NAME_PREFIX)) {
//                continue;
//            }
            String resolvedValue = beanFactory == null ? value :
                    beanFactory.resolveEmbeddedValue(value);
            stringJoiner.add(resolvedValue);
        }
        Properties properties = new Properties();
        try {
            properties.load(new StringReader(stringJoiner.toString()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return properties;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy