diff --git a/pom.xml b/pom.xml
index 19595b5..8cb767e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
org.activestack
syncengine
- 1.1.58-SNAPSHOT
+ 1.1.59-SNAPSHOT
3.2.4.RELEASE
@@ -335,6 +335,21 @@
logback-ext-loggly
0.1.2
+
+
+
+ com.zaxxer
+ HikariCP
+ 2.4.1
+
+
+
+
+ com.h2database
+ h2
+ 1.3.167
+ test
+
diff --git a/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java b/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java
index 8576242..4e0192a 100644
--- a/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java
+++ b/src/main/java/com/percero/agents/sync/jobs/UpdateTableConnectionFactory.java
@@ -1,51 +1,12 @@
package com.percero.agents.sync.jobs;
-import com.mchange.v2.c3p0.ComboPooledDataSource;
-import org.apache.log4j.Logger;
-
-import java.beans.PropertyVetoException;
-import java.sql.Connection;
-import java.sql.SQLException;
+import com.percero.datasource.BaseConnectionFactory;
/**
* Created by jonnysamps on 9/2/15.
*/
-//@Component
-public class UpdateTableConnectionFactory {
-
- private static Logger logger = Logger.getLogger(UpdateTableConnectionFactory.class);
-
- private String driverClassName;
- public void setDriverClassName(String val){
- this.driverClassName = val;
- }
- public String getDriverClassName(){
- return driverClassName;
- }
+public class UpdateTableConnectionFactory extends BaseConnectionFactory {
- private String username;
- public void setUsername(String val){
- this.username = val;
- }
- public String getUsername(){
- return username;
- }
-
- private String password;
- public void setPassword(String val){
- this.password = val;
- }
- public String getPassword(){
- return password;
- }
-
- private String jdbcUrl;
- public void setJdbcUrl(String val){
- this.jdbcUrl = val;
- }
- public String getJdbcUrl(){
- return jdbcUrl;
- }
private String[] tableNames;
public void setTableNames(String[] val) {
@@ -117,42 +78,4 @@ public int getWeight(){
return this.weight;
}
- private ComboPooledDataSource cpds;
-
- public void init() throws PropertyVetoException{
- try {
- cpds = new ComboPooledDataSource();
- cpds.setDriverClass(driverClassName); //loads the jdbc driver
- cpds.setJdbcUrl(jdbcUrl);
- cpds.setUser(username);
- cpds.setPassword(password);
-
- // the settings below are optional -- c3p0 can work with defaults
- cpds.setMinPoolSize(10);
- cpds.setAcquireIncrement(5);
- cpds.setMaxPoolSize(this.weight);
- cpds.setTestConnectionOnCheckout(true);
-
- }catch(PropertyVetoException pve){
- logger.error(pve.getMessage(), pve);
- throw pve;
- }
- }
-
- public Connection getConnection() throws SQLException{
- try{
- if (cpds == null) {
- init();
- }
- return cpds.getConnection();
- }
- catch(PropertyVetoException e){
- logger.error(e.getMessage(), e);
- throw new SQLException(e);
- }
- catch(SQLException e){
- logger.error(e.getMessage(), e);
- throw e;
- }
- }
}
diff --git a/src/main/java/com/percero/datasource/BaseConnectionFactory.java b/src/main/java/com/percero/datasource/BaseConnectionFactory.java
new file mode 100644
index 0000000..440725e
--- /dev/null
+++ b/src/main/java/com/percero/datasource/BaseConnectionFactory.java
@@ -0,0 +1,227 @@
+package com.percero.datasource;
+
+import java.beans.PropertyVetoException;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+import org.apache.log4j.Logger;
+import org.springframework.util.StringUtils;
+
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+
+public class BaseConnectionFactory implements IConnectionFactory {
+
+ private static Logger logger = Logger.getLogger(BaseConnectionFactory.class);
+
+ public static final String HIKARI_CONNECTION_POOL = "hikari";
+ public static final String C3P0_CONNECTION_POOL = "c3p0";
+
+ private String name;
+ private String preferredConnectionPool = HIKARI_CONNECTION_POOL;
+ private Integer acquireIncrement = 4;
+ private Integer minPoolSize = 4;
+ private Integer maxPoolSize = 52;
+ private Integer maxIdleTime = 60 * 30; // 30 Minutes
+ private String testQuery = "SELECT 1 FROM dual";
+ private Integer fetchSize = 100;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getPreferredConnectionPool() {
+ return preferredConnectionPool;
+ }
+
+ public void setPreferredConnectionPool(String preferredConnectionPool) {
+ this.preferredConnectionPool = preferredConnectionPool;
+ }
+
+ public Integer getAcquireIncrement() {
+ return acquireIncrement;
+ }
+
+ public void setAcquireIncrement(Integer acquireIncrement) {
+ this.acquireIncrement = acquireIncrement;
+ }
+
+ public Integer getMinPoolSize() {
+ return minPoolSize;
+ }
+
+ public void setMinPoolSize(Integer minPoolSize) {
+ this.minPoolSize = minPoolSize;
+ }
+
+ public Integer getMaxPoolSize() {
+ return maxPoolSize;
+ }
+
+ public void setMaxPoolSize(Integer maxPoolSize) {
+ this.maxPoolSize = maxPoolSize;
+ }
+
+ public Integer getMaxIdleTime() {
+ return maxIdleTime;
+ }
+
+ public void setMaxIdleTime(Integer maxIdleTime) {
+ this.maxIdleTime = maxIdleTime;
+ }
+
+ public String getTestQuery() {
+ return testQuery;
+ }
+
+ public void setTestQuery(String testQuery) {
+ this.testQuery = testQuery;
+ }
+
+ public Integer getFetchSize() {
+ // Default to 100;
+ if (fetchSize == null || fetchSize <= 0) {
+ return 100;
+ }
+ return fetchSize;
+ }
+
+ public void setFetchSize(Integer fetchSize) {
+ this.fetchSize = fetchSize;
+ }
+
+ private String driverClassName;
+ public void setDriverClassName(String val){
+ this.driverClassName = val;
+ }
+ public String getDriverClassName(){
+ return driverClassName;
+ }
+
+ private String username;
+ public void setUsername(String val){
+ this.username = val;
+ }
+ public String getUsername(){
+ return username;
+ }
+
+ private String password;
+ public void setPassword(String val){
+ this.password = val;
+ }
+ public String getPassword(){
+ return password;
+ }
+
+ private String jdbcUrl;
+ public void setJdbcUrl(String val){
+ this.jdbcUrl = val;
+ }
+ public String getJdbcUrl(){
+ return jdbcUrl;
+ }
+
+ private DataSource ds;
+ public DataSource getDataSource() {
+ return ds;
+ }
+
+ public void init() throws PropertyVetoException{
+ try {
+ if (C3P0_CONNECTION_POOL.equalsIgnoreCase(preferredConnectionPool)) {
+ ComboPooledDataSource cpds = new ComboPooledDataSource();
+ cpds.setDriverClass(driverClassName); // loads the jdbc driver
+ cpds.setJdbcUrl(jdbcUrl);
+ cpds.setUser(username);
+ cpds.setPassword(password);
+
+ // the settings below are optional -- c3p0 can work with
+ // defaults
+ if (minPoolSize != null) {
+ cpds.setMinPoolSize(minPoolSize);
+ }
+ if (acquireIncrement != null) {
+ cpds.setAcquireIncrement(acquireIncrement);
+ }
+ if (maxPoolSize != null) {
+ cpds.setMaxPoolSize(maxPoolSize);
+ }
+ if (maxIdleTime != null) {
+ cpds.setMaxIdleTime(maxIdleTime);
+ cpds.setIdleConnectionTestPeriod(maxIdleTime);
+ }
+ cpds.setNumHelperThreads(30);
+ cpds.setTestConnectionOnCheckout(true);
+ if (StringUtils.hasText(testQuery)) {
+ cpds.setPreferredTestQuery(testQuery);
+ }
+
+ ds = cpds;
+ } else {
+ // Default to Hikari Connection Pool.
+ HikariConfig config = new HikariConfig();
+ config.setDriverClassName(driverClassName);
+ config.setJdbcUrl(jdbcUrl);
+ config.setUsername(username);
+ config.setPassword(password);
+ config.addDataSourceProperty("cachePrepStmts", "true");
+ config.addDataSourceProperty("prepStmtCacheSize", "250");
+ config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
+
+ if (StringUtils.hasText(name)) {
+ config.setPoolName(name);
+ }
+ if (minPoolSize != null) {
+ config.setMinimumIdle(minPoolSize);
+ }
+ // if (acquireIncrement != null) {
+ // config.setAcquireIncrement(acquireIncrement);
+ // }
+ if (maxPoolSize != null) {
+ config.setMaximumPoolSize(maxPoolSize);
+ }
+ if (maxIdleTime != null) {
+ config.setIdleTimeout(maxIdleTime * 1000); // Convert to
+ // milliseconds
+ }
+ // config.setNumHelperThreads(30);
+ // config.setTestConnectionOnCheckout(true);
+ if (StringUtils.hasText(testQuery)) {
+ config.setConnectionTestQuery(testQuery);
+ }
+
+ ds = new HikariDataSource(config);
+ }
+
+ }catch(PropertyVetoException pve){
+ logger.error(pve.getMessage(), pve);
+ throw pve;
+ }
+ }
+
+ public Connection getConnection() throws SQLException{
+ try{
+ if (ds == null) {
+ init();
+ }
+ return getDataSource().getConnection();
+ }
+ catch(PropertyVetoException e){
+ logger.error(e.getMessage(), e);
+ throw new SQLException(e);
+ }
+ catch(SQLException e){
+ logger.error(e.getMessage(), e);
+ throw e;
+ }
+ }
+
+}
diff --git a/src/main/java/com/percero/datasource/IConnectionFactory.java b/src/main/java/com/percero/datasource/IConnectionFactory.java
new file mode 100644
index 0000000..62d71bd
--- /dev/null
+++ b/src/main/java/com/percero/datasource/IConnectionFactory.java
@@ -0,0 +1,13 @@
+package com.percero.datasource;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+public interface IConnectionFactory {
+
+ String getName();
+ void setName(String name);
+ Connection getConnection() throws SQLException;
+
+ Integer getFetchSize();
+}
diff --git a/src/test/java/com/percero/datasource/TestBaseConnectionFactory.java b/src/test/java/com/percero/datasource/TestBaseConnectionFactory.java
new file mode 100644
index 0000000..5bf0beb
--- /dev/null
+++ b/src/test/java/com/percero/datasource/TestBaseConnectionFactory.java
@@ -0,0 +1,161 @@
+package com.percero.datasource;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.beans.PropertyVetoException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import com.esotericsoftware.yamlbeans.YamlException;
+import com.esotericsoftware.yamlbeans.YamlReader;
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+import com.zaxxer.hikari.HikariDataSource;
+
+public class TestBaseConnectionFactory {
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ BaseConnectionFactory bcf = null;
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ bcf = null;
+ }
+
+ @Test
+ public void testInit() {
+ BaseConnectionFactory bcf = new BaseConnectionFactory();
+ bcf.setJdbcUrl("jdbc:h2:~/test");
+ bcf.setDriverClassName("org.h2.Driver");
+ bcf.setName("TESTS");
+ bcf.setUsername("sa");
+ bcf.setPassword("");
+
+ String testQuery = "SELECT 1 FROM dual";
+ bcf.setTestQuery(testQuery);
+ bcf.setMaxIdleTime(1000);
+
+ try {
+ // Validate data source type.
+ bcf.init();
+ assertTrue(bcf.getDataSource() instanceof HikariDataSource);
+ HikariDataSource hds = (HikariDataSource) bcf.getDataSource();
+ assertEquals(bcf.getDriverClassName(), hds.getDriverClassName());
+ assertEquals(bcf.getJdbcUrl(), hds.getJdbcUrl());
+ assertEquals(bcf.getUsername(), hds.getUsername());
+ assertEquals(bcf.getPassword(), hds.getPassword());
+ assertEquals(bcf.getName(), hds.getPoolName());
+ assertEquals(bcf.getMinPoolSize().intValue(), hds.getMinimumIdle());
+ assertEquals(bcf.getMaxPoolSize().longValue(), hds.getMaximumPoolSize());
+ assertEquals(bcf.getMaxIdleTime().longValue() * 1000, hds.getIdleTimeout());
+ assertEquals(testQuery, hds.getConnectionTestQuery());
+
+ assertEquals("true", hds.getDataSourceProperties().getProperty("cachePrepStmts"));
+ assertEquals("250", hds.getDataSourceProperties().getProperty("prepStmtCacheSize"));
+ assertEquals("2048", hds.getDataSourceProperties().getProperty("prepStmtCacheSqlLimit"));
+
+ // C3PO.
+ bcf.setPreferredConnectionPool(BaseConnectionFactory.C3P0_CONNECTION_POOL);
+ bcf.init();
+ assertTrue(bcf.getDataSource() instanceof ComboPooledDataSource);
+ ComboPooledDataSource cpds = (ComboPooledDataSource) bcf.getDataSource();
+ assertEquals(bcf.getDriverClassName(), cpds.getDriverClass());
+ assertEquals(bcf.getJdbcUrl(), cpds.getJdbcUrl());
+ assertEquals(bcf.getUsername(), cpds.getUser());
+ assertEquals(bcf.getPassword(), cpds.getPassword());
+ assertEquals(bcf.getMinPoolSize().intValue(), cpds.getMinPoolSize());
+ assertEquals(bcf.getAcquireIncrement().intValue(), cpds.getAcquireIncrement());
+ assertEquals(bcf.getMaxPoolSize().intValue(), cpds.getMaxPoolSize());
+ assertEquals(bcf.getMaxIdleTime().intValue(), cpds.getMaxIdleTime());
+ assertEquals(bcf.getMaxIdleTime().intValue(), cpds.getIdleConnectionTestPeriod());
+ assertEquals(30, cpds.getNumHelperThreads());
+ assertEquals(testQuery, cpds.getPreferredTestQuery());
+
+ // Hikari.
+ bcf.setPreferredConnectionPool(BaseConnectionFactory.HIKARI_CONNECTION_POOL);
+ bcf.init();
+ assertTrue(bcf.getDataSource() instanceof HikariDataSource);
+ } catch (PropertyVetoException e) {
+ // TODO Auto-generated catch block
+ fail("Error with property: " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testGetConnection() {
+
+ DataSource mockDataSource = Mockito.mock(DataSource.class);
+ Connection connection = Mockito.mock(Connection.class);
+
+ try {
+ Mockito.when(mockDataSource.getConnection()).thenReturn(connection);
+ } catch (SQLException e) {
+ fail("Failed to Mock DataSource.getConnection(): " + e.getMessage());
+ }
+
+ bcf = Mockito.mock(BaseConnectionFactory.class);
+ Mockito.when(bcf.getDataSource()).thenReturn(mockDataSource);
+
+ try {
+ Mockito.when(bcf.getConnection()).thenCallRealMethod();
+ assertSame(connection, bcf.getConnection());
+ } catch (SQLException e) {
+ fail("Failed to get Connection from DataSource: " + e.getMessage());
+ }
+ }
+
+ @Test
+ public void testYmlImport() {
+ try {
+ URL ymlUrl = TestBaseConnectionFactory.class.getClassLoader().getResource("baseconnectionfactories.yml");
+ if (ymlUrl == null) {
+ fail("No configuration file found: baseconnectionFactories.yml");
+ }
+ File configFile = new File(ymlUrl.getFile());
+ YamlReader reader = new YamlReader(new FileReader(configFile));
+
+ BaseConnectionFactory connectionFactory = reader.read(BaseConnectionFactory.class);
+ assertNotNull(connectionFactory);
+ assertEquals("org.h2.Driver", connectionFactory.getDriverClassName());
+ assertEquals("jdbc:h2:~/test", connectionFactory.getJdbcUrl());
+ assertEquals("sa", connectionFactory.getUsername());
+ assertEquals("pass", connectionFactory.getPassword());
+ assertEquals("TEST", connectionFactory.getName());
+ assertEquals(new Integer(5), connectionFactory.getMinPoolSize());
+ assertEquals(new Integer(25), connectionFactory.getMaxPoolSize());
+ assertEquals(new Integer(1000), connectionFactory.getMaxIdleTime());
+ assertEquals("SELECT 1 FROM dual", connectionFactory.getTestQuery());
+ }
+ catch (FileNotFoundException e) {
+ fail("Error processing config file baseconnectionfactories.yml: " + e.getMessage());
+ } catch (YamlException e) {
+ fail("YAML Error processing config file baseconnectionfactories.yml: " + e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/com/percero/datasource/TestUpdateTablesConnectionFactory.java b/src/test/java/com/percero/datasource/TestUpdateTablesConnectionFactory.java
new file mode 100644
index 0000000..2a225b5
--- /dev/null
+++ b/src/test/java/com/percero/datasource/TestUpdateTablesConnectionFactory.java
@@ -0,0 +1,94 @@
+package com.percero.datasource;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.net.URL;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.esotericsoftware.yamlbeans.YamlException;
+import com.esotericsoftware.yamlbeans.YamlReader;
+import com.percero.agents.sync.jobs.UpdateTableConnectionFactory;
+
+public class TestUpdateTablesConnectionFactory {
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testYmlImport() {
+ try {
+ URL ymlUrl = TestUpdateTablesConnectionFactory.class.getClassLoader().getResource("updatetablesconnectionfactories.yml");
+ if (ymlUrl == null) {
+ fail("No configuration file found: updatetablesconnectionfactories.yml");
+ }
+ File configFile = new File(ymlUrl.getFile());
+ YamlReader reader = new YamlReader(new FileReader(configFile));
+
+ // First UpdateTableConnectionFactory
+ UpdateTableConnectionFactory connectionFactory = reader.read(UpdateTableConnectionFactory.class);
+ assertNotNull(connectionFactory);
+ assertEquals("org.h2.Driver", connectionFactory.getDriverClassName());
+ assertEquals("jdbc:h2:~/test", connectionFactory.getJdbcUrl());
+ assertEquals("sa", connectionFactory.getUsername());
+ assertEquals("pass", connectionFactory.getPassword());
+ assertEquals("TEST", connectionFactory.getName());
+ assertEquals(new Integer(5), connectionFactory.getMinPoolSize());
+ assertEquals(new Integer(25), connectionFactory.getMaxPoolSize());
+ assertEquals(new Integer(1000), connectionFactory.getMaxIdleTime());
+ assertEquals("SELECT 1 FROM dual", connectionFactory.getTestQuery());
+
+ assertEquals(50, connectionFactory.getWeight());
+ assertEquals("UPDATE_TABLE_LOCK_BATCH", connectionFactory.getStoredProcedureName());
+ assertEquals("My Stored Proc", connectionFactory.getStoredProcedureDefinition());
+
+ assertNotNull(connectionFactory.getTableNames());
+ assertEquals(2, connectionFactory.getTableNames().length);
+ assertEquals("update_table_1", connectionFactory.getTableNames()[0]);
+ assertEquals("update_table_2", connectionFactory.getTableNames()[1]);
+
+ // Second UpdateTableConnectionFactory
+ connectionFactory = reader.read(UpdateTableConnectionFactory.class);
+ assertNotNull(connectionFactory);
+ assertEquals("org.h2.Driver", connectionFactory.getDriverClassName());
+ assertEquals("jdbc:h2:~/test", connectionFactory.getJdbcUrl());
+ assertEquals("sa", connectionFactory.getUsername());
+ assertEquals("pass", connectionFactory.getPassword());
+
+ assertEquals(55, connectionFactory.getWeight());
+ assertEquals("UPDATE_TABLE_LOCK_BATCH", connectionFactory.getStoredProcedureName());
+ assertEquals("My Stored Proc", connectionFactory.getStoredProcedureDefinition());
+
+ assertNotNull(connectionFactory.getTableNames());
+ assertEquals(1, connectionFactory.getTableNames().length);
+ assertEquals("update_table_1", connectionFactory.getTableNames()[0]);
+ }
+ catch (FileNotFoundException e) {
+ fail("Error processing config file updatetablesconnectionfactories.yml: " + e.getMessage());
+ } catch (YamlException e) {
+ fail("YAML Error processing config file updatetablesconnectionfactories.yml: " + e.getMessage());
+ }
+ }
+}
diff --git a/src/test/resources/baseconnectionfactories.yml b/src/test/resources/baseconnectionfactories.yml
new file mode 100644
index 0000000..ea4edfa
--- /dev/null
+++ b/src/test/resources/baseconnectionfactories.yml
@@ -0,0 +1,11 @@
+# ---
+name: TEST
+preferredConnectionPool: hikari
+driverClassName: org.h2.Driver
+jdbcUrl: jdbc:h2:~/test
+username: sa
+password: pass
+testQuery: SELECT 1 FROM dual
+maxIdleTime: 1000
+minPoolSize: 5
+maxPoolSize: 25
\ No newline at end of file
diff --git a/src/test/resources/updatetablesconnectionfactories.yml b/src/test/resources/updatetablesconnectionfactories.yml
new file mode 100644
index 0000000..6a5ec88
--- /dev/null
+++ b/src/test/resources/updatetablesconnectionfactories.yml
@@ -0,0 +1,27 @@
+# ---
+name: TEST
+preferredConnectionPool: hikari
+driverClassName: org.h2.Driver
+jdbcUrl: jdbc:h2:~/test
+username: sa
+password: pass
+testQuery: SELECT 1 FROM dual
+maxIdleTime: 1000
+minPoolSize: 5
+maxPoolSize: 25
+tableNames:
+ - update_table_1
+ - update_table_2
+weight: 50
+storedProcedureName: UPDATE_TABLE_LOCK_BATCH
+storedProcedureDefinition: My Stored Proc
+---
+driverClassName: org.h2.Driver
+jdbcUrl: jdbc:h2:~/test
+username: sa
+password: pass
+tableNames:
+ - update_table_1
+weight: 55
+storedProcedureName: UPDATE_TABLE_LOCK_BATCH
+storedProcedureDefinition: My Stored Proc