/*
* HA-JDBC: High-Availability JDBC
* Copyright (C) 2012 Paul Ferraro
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.hajdbc.xml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
import java.io.StringReader;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Map;
import javax.sql.DataSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import net.sf.hajdbc.Database;
import net.sf.hajdbc.DatabaseBuilder;
import net.sf.hajdbc.DatabaseClusterConfiguration;
import net.sf.hajdbc.DatabaseClusterConfigurationBuilder;
import net.sf.hajdbc.Locality;
import net.sf.hajdbc.MockDataSource;
import net.sf.hajdbc.MockDriver;
import net.sf.hajdbc.SynchronizationStrategy;
import net.sf.hajdbc.balancer.load.LoadBalancerFactory;
import net.sf.hajdbc.cache.eager.EagerDatabaseMetaDataCacheFactory;
import net.sf.hajdbc.dialect.StandardDialectFactory;
import net.sf.hajdbc.durability.coarse.CoarseDurabilityFactory;
import net.sf.hajdbc.sql.DataSourceDatabase;
import net.sf.hajdbc.sql.DataSourceDatabaseClusterConfigurationBuilder;
import net.sf.hajdbc.sql.DriverDatabase;
import net.sf.hajdbc.sql.DriverDatabaseClusterConfigurationBuilder;
import net.sf.hajdbc.sql.TransactionModeEnum;
import net.sf.hajdbc.state.StateManagerFactory;
import net.sf.hajdbc.state.sql.SQLStateManagerFactory;
import net.sf.hajdbc.sync.DifferentialSynchronizationStrategy;
import org.junit.Test;
public class XMLDatabaseClusterConfigurationFactoryTest
{
@Test
public void createDriverBasedConfiguration() throws SQLException
{
Driver driver = new MockDriver(mock(Connection.class));
DriverManager.registerDriver(driver);
try
{
String url1 = "jdbc:mock:db1";
Map.Entry<String, String> property1 = new SimpleImmutableEntry<>("name", "value1");
String url2 = "jdbc:mock:db2";
Map.Entry<String, String> property2 = new SimpleImmutableEntry<>("name", "value2");
DatabaseClusterConfiguration<Driver, DriverDatabase> configuration = createConfiguration(new DriverDatabaseClusterConfigurationBuilder(), url1, url2, property1, property2);
DriverDatabase db1 = configuration.getDatabaseMap().get("db1");
assertSame(driver, db1.getConnectionSource());
assertEquals(url1, db1.getLocation());
assertEquals("value1", db1.getProperties().getProperty("name"));
DriverDatabase db2 = configuration.getDatabaseMap().get("db2");
assertSame(driver, db2.getConnectionSource());
assertEquals(url2, db2.getLocation());
assertEquals("value2", db2.getProperties().getProperty("name"));
}
finally
{
DriverManager.deregisterDriver(driver);
}
}
@Test
public void createDataSourceBasedConfiguration() throws SQLException
{
String location = MockDataSource.class.getName();
Map.Entry<String, String> property1 = new SimpleImmutableEntry<>("name", "db1");
Map.Entry<String, String> property2 = new SimpleImmutableEntry<>("name", "db2");
DatabaseClusterConfiguration<DataSource, DataSourceDatabase> configuration = createConfiguration(new DataSourceDatabaseClusterConfigurationBuilder(), location, location, property1, property2);
DataSourceDatabase db1 = configuration.getDatabaseMap().get("db1");
assertTrue(db1.getConnectionSource().getClass().getName(), db1.getConnectionSource() instanceof MockDataSource);
assertEquals("db1", ((MockDataSource) db1.getConnectionSource()).getName());
DataSourceDatabase db2 = configuration.getDatabaseMap().get("db2");
assertTrue(db2.getConnectionSource().getClass().getName(), db2.getConnectionSource() instanceof MockDataSource);
assertEquals("db2", ((MockDataSource) db2.getConnectionSource()).getName());
}
private static <Z, D extends Database<Z>, B extends DatabaseBuilder<Z, D>> DatabaseClusterConfiguration<Z, D> createConfiguration(DatabaseClusterConfigurationBuilder<Z, D, B> configurationBuilder, String location1, String location2, Map.Entry<String, String> property1, Map.Entry<String, String> property2) throws SQLException
{
StringBuilder builder = new StringBuilder();
builder.append("<?xml version=\"1.0\"?>");
builder.append("<ha-jdbc xmlns=\"").append(Namespace.CURRENT_VERSION.getURI()).append("\">");
builder.append("\t<sync id=\"diff\"><property name=\"fetchSize\">100</property><property name=\"maxBatchSize\">100</property></sync>");
builder.append("\t<state id=\"sql\"><property name=\"urlPattern\">jdbc:h2:{0}</property><property name=\"minIdle\">1</property></state>");
builder.append("\t<cluster default-sync=\"diff\">");
builder.append(String.format("\t\t<database id=\"db1\" location=\"%s\">", location1));
builder.append(String.format("\t\t\t<property name=\"%s\">%s</property>", property1.getKey(), property1.getValue()));
builder.append(String.format("\t\t</database>", location1));
builder.append(String.format("\t\t<database id=\"db2\" location=\"%s\">", location2));
builder.append(String.format("\t\t\t<property name=\"%s\">%s</property>", property2.getKey(), property2.getValue()));
builder.append(String.format("\t\t</database>", location1));
builder.append("\t</cluster>");
builder.append("</ha-jdbc>");
String xml = builder.toString();
XMLStreamFactory streamFactory = mock(XMLStreamFactory.class);
XMLDatabaseClusterConfigurationFactory<Z, D> factory = new XMLDatabaseClusterConfigurationFactory<>(streamFactory);
when(streamFactory.createSource()).thenReturn(new StreamSource(new StringReader(xml)));
DatabaseClusterConfiguration<Z, D> configuration = factory.createConfiguration(configurationBuilder);
assertNull(configuration.getDispatcherFactory());
Map<String, SynchronizationStrategy> syncStrategies = configuration.getSynchronizationStrategyMap();
assertNotNull(syncStrategies);
assertEquals(1, syncStrategies.size());
SynchronizationStrategy syncStrategy = syncStrategies.get("diff");
assertNotNull(syncStrategy);
assertTrue(syncStrategy instanceof DifferentialSynchronizationStrategy);
DifferentialSynchronizationStrategy diffStrategy = (DifferentialSynchronizationStrategy) syncStrategy;
assertEquals(100, diffStrategy.getFetchSize());
assertEquals(100, diffStrategy.getMaxBatchSize());
assertNull(diffStrategy.getVersionPattern());
StateManagerFactory stateManagerFactory = configuration.getStateManagerFactory();
assertTrue(stateManagerFactory instanceof SQLStateManagerFactory);
SQLStateManagerFactory sqlStateManagerFactory = (SQLStateManagerFactory) stateManagerFactory;
assertEquals("jdbc:h2:{0}", sqlStateManagerFactory.getUrlPattern());
assertNull(sqlStateManagerFactory.getUser());
assertNull(sqlStateManagerFactory.getPassword());
assertEquals(LoadBalancerFactory.class, configuration.getBalancerFactory().getClass());
assertEquals(EagerDatabaseMetaDataCacheFactory.class, configuration.getDatabaseMetaDataCacheFactory().getClass());
assertEquals("diff", configuration.getDefaultSynchronizationStrategy());
assertEquals(StandardDialectFactory.class, configuration.getDialectFactory().getClass());
assertEquals(CoarseDurabilityFactory.class, configuration.getDurabilityFactory().getClass());
assertSame(TransactionModeEnum.SERIAL, configuration.getTransactionMode());
assertNotNull(configuration.getExecutorProvider());
assertNull(configuration.getAutoActivationExpression());
assertNull(configuration.getFailureDetectionExpression());
assertFalse(configuration.isCurrentDateEvaluationEnabled());
assertFalse(configuration.isCurrentTimeEvaluationEnabled());
assertFalse(configuration.isCurrentTimestampEvaluationEnabled());
assertFalse(configuration.isIdentityColumnDetectionEnabled());
assertFalse(configuration.isRandEvaluationEnabled());
assertFalse(configuration.isSequenceDetectionEnabled());
Map<String, D> databases = configuration.getDatabaseMap();
assertNotNull(databases);
assertEquals(2, databases.size());
D db1 = databases.get("db1");
assertNotNull(db1);
assertEquals("db1", db1.getId());
assertEquals(1, db1.getWeight());
assertSame(Locality.REMOTE, db1.getLocality());
D db2 = databases.get("db2");
assertNotNull(db2);
assertEquals("db2", db2.getId());
assertEquals(1, db2.getWeight());
assertSame(Locality.REMOTE, db2.getLocality());
reset(streamFactory);
StringWriter writer = new StringWriter();
when(streamFactory.createResult()).thenReturn(new StreamResult(writer));
factory.export(configuration);
System.out.println(writer.toString());
return configuration;
}
}