Initial Database Migration

This commit is contained in:
Isaac Parenteau
2019-10-06 20:07:47 -05:00
parent 38dbc5bbf5
commit af8e8fa52a
20 changed files with 1567 additions and 113 deletions

View File

@@ -0,0 +1,156 @@
/**
*
* Project: Eight Track, File: EightTrackBeanConfiguration.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.database.config;
import java.util.HashSet;
import java.util.Properties;
import javax.sql.DataSource;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.configuration.FluentConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration(value="net.locusworks.discord.eighttrack.database.config.EightTrackBeanConfiguration")
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = {"net.locusworks.discord.eighttrack.database.repos"},
entityManagerFactoryRef = "eighttrackEntityManagerFactory",
transactionManagerRef = "eighttrackTransactionManager"
)
public class EightTrackBeanConfiguration {
public static final String PERSISTENCE_UNIT = "eighttrack_pu";
public static final HashSet<String> cacheNames = new HashSet<>();
private static final String[] PACKAGES_TO_SCAN = {
"net.locusworks.discord.eighttrack.database.entities"
};
private static final Properties hibernateProperties;
static {
hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.connection.zeroDateTimeBehavior", "convertToNull");
hibernateProperties.setProperty("hibernate.dbcp.maxActive", "50");
hibernateProperties.setProperty("hibernate.dbcp.maxIdle", "10");
hibernateProperties.setProperty("hibernate.dbcp.maxWait", "5000");
hibernateProperties.setProperty("hibernate.jdbc.batch_size property", "50");
hibernateProperties.setProperty("hibernate.connection.charSet", "utf8");
hibernateProperties.setProperty("hibernate.connection.characterEncoding", "utf8");
hibernateProperties.setProperty("hibernate.connection.useUnicode", "true");
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
}
@Autowired
private DataSource dataSource;
@Autowired
private DataSource flywayDataSource;
/**
* Create the entity manager factory bean used in the database connection
* @return entityManagerFactoryBean
*/
@Primary
@Bean
@DependsOn("flyway")
public LocalContainerEntityManagerFactoryBean eighttrackEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource);
lef.setJpaVendorAdapter(eighttrackJpaVendorAdapter());
lef.setPackagesToScan(PACKAGES_TO_SCAN);
lef.setJpaProperties(hibernateProperties);
lef.setPersistenceUnitName(PERSISTENCE_UNIT);
return lef;
}
/**
* Create the session factory bean
* @return sessionFactoryBean
*/
@Bean
public LocalSessionFactoryBean pseduobotSessionFactory() {
LocalSessionFactoryBean sessionBean = new LocalSessionFactoryBean();
sessionBean.setDataSource(dataSource);
sessionBean.setPackagesToScan(PACKAGES_TO_SCAN);
sessionBean.setHibernateProperties(hibernateProperties);
return sessionBean;
}
/**
* Create the JPA Vendor adaptor bean that is used in the entity manager factory
* @return jpaVendorAdaptor
*/
@Primary
@Bean
public JpaVendorAdapter eighttrackJpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(false);
hibernateJpaVendorAdapter.setGenerateDdl(false);
hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);
return hibernateJpaVendorAdapter;
}
/**
* Create the transaction manager bean
* @return transactionManager
*/
@Primary
@Bean
public PlatformTransactionManager eighttrackTransactionManager() {
JpaTransactionManager manager = new JpaTransactionManager();
manager.setEntityManagerFactory(eighttrackEntityManagerFactory().getObject());
return new JpaTransactionManager();
}
@Bean(name="flyway", initMethod="migrate")
public Flyway flyway() {
FluentConfiguration fc = Flyway.configure();
fc.schemas("eighttrack");
fc.table("_flyway_migration");
fc.locations("database/migration");
fc.outOfOrder(false);
fc.dataSource(flywayDataSource);
return fc.load();
}
}

View File

@@ -0,0 +1,162 @@
/**
*
* Project: Eight Track, File: EightTrackDataSource.java
*
* Copyright 2019 Locusworks LLC.
* All rights reserved. Federal copyright law prohibits unauthorized reproduction by
* any means and imposes fines up to $25,000 for violation. No part of this material
* may be reproduced, transmitted, transcribed, stored in a retrieval system, copied,
* modified, duplicated, adapted or translated into another program language in any
* form or by any means, electronic, mechanical, photocopying, recording, or
* otherwise, without the prior written permission from Locusworks. Locusworks
* affirms that Eight-Track(R) software and data is subject to United States
* Government Purpose Rights. Contact Locusworks, 1313 Lawnview Drive
* Forney TX 75126, (802) 488-0438, for commercial licensing opportunities.
*
* IN NO EVENT SHALL LOCUSWORKS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF LOCUSWORKS HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. NO RESPONSIBILITY IS ASSUMED BY
* LOCUSWORKS FOR ITS USE, OR FOR ANY INFRINGEMENTS OF PATENTS OR OTHER RIGHTS OF
* THIRD PARTIES RESULTING FROM ITS USE. LOCUSWORKS SPECIFICALLY DISCLAIMS ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND
* ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
* IS". LOCUSWORKS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS.
*/
package net.locusworks.discord.eighttrack.database.config;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TimeZone;
import java.util.stream.Collectors;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.ConnectionFactory;
import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.dbcp2.PoolingDataSource;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.AbandonedConfig;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.mariadb.jdbc.MariaDbDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import net.locusworks.discord.eighttrack.services.ConfigurationService;
@Primary
@Component
public class EightTrackDataSource {
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String JNDI_STRING = "jdbc:mysql://%s:%d%s";
private static Map<String, String> mysqlProperties;
static {
mysqlProperties = new LinkedHashMap<>();
mysqlProperties.put("rewriteBatchedStatements", "true");
mysqlProperties.put("zeroDateTimeBehavior", "CONVERT_TO_NULL");
mysqlProperties.put("useSSL", "false");
mysqlProperties.put("serverTimezone", TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT));
}
private Logger logger = LoggerFactory.getLogger(EightTrackDataSource.class);
@Autowired
private ConfigurationService confService;
/**
* Create the data source bean
* @return the data source bean
* @throws Exception
*/
@Bean
public DataSource dataSource() throws Exception {
return getDataSource(false);
}
@Bean
public DataSource flywayDataSource() throws Exception {
logger.debug("Logging in with flyway for migrations");
String user = confService.getDatabaseRootUsername();
String passwd = confService.getDatabaseRootPassword();
String url = String.format("jdbc:mariadb://%s:%d?user=%s&password=%s",
confService.getDatabaseHost(), confService.getDatabasePort(),
user, passwd);
MariaDbDataSource mariadbDS = new MariaDbDataSource(url);
return mariadbDS;
}
private DataSource getDataSource(Boolean isFlyway) throws Exception {
logger.debug("Gettind datasource");
Class.forName(DRIVER).getDeclaredConstructor().newInstance();
String user = confService.getDatabaseUsername();
String passwd = confService.getDatabasePassword();
Properties props = new Properties();
props.setProperty("user", user);
props.setProperty("password", passwd);
List<String> params = mysqlProperties
.entrySet()
.stream()
.map(prop -> String.format("%s=%s", prop.getKey(), prop.getValue()))
.collect(Collectors.toList());
String host = confService.getDatabaseHost();
int port = confService.getDatabasePort();
String url = String.format(JNDI_STRING, host, port, "/eighttrack");
url = String.format("%s?%s", url, StringUtils.join(params, "&"));
logger.debug("Database connection string: %s", url);
ConnectionFactory cf = new DriverManagerConnectionFactory(url, props);
//Create the poolable connection factory
PoolableConnectionFactory pcf = new PoolableConnectionFactory(cf, null);
pcf.setValidationQuery("SELECT 1");
pcf.setDefaultAutoCommit(true);
GenericObjectPoolConfig<PoolableConnection> poolConfig = new GenericObjectPoolConfig<>();
poolConfig.setMinIdle(10);
poolConfig.setMaxTotal(100);
AbandonedConfig abandonConfig = new AbandonedConfig();
abandonConfig.setRemoveAbandonedTimeout(60);
abandonConfig.setLogAbandoned(false);
abandonConfig.setRemoveAbandonedOnBorrow(true);
abandonConfig.setRemoveAbandonedOnMaintenance(true);
//Create the pool of connections
GenericObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(pcf, poolConfig);
connectionPool.setTestOnBorrow(true);
connectionPool.setTestWhileIdle(true);
connectionPool.setTimeBetweenEvictionRunsMillis(10000);
connectionPool.setMinEvictableIdleTimeMillis(1000);
connectionPool.setAbandonedConfig(abandonConfig);
pcf.setPool(connectionPool);
//Pooling data source itself
PoolingDataSource<PoolableConnection> dataSource = new PoolingDataSource<>(connectionPool);
return dataSource;
}
}