Skip to content

Commit

Permalink
GEODE-5861: change jdbc connector to use jndi binding (apache#2650)
Browse files Browse the repository at this point in the history
The jdbc connector now uses the existing "jndi-binding" xml/gfsh instead of adding "jdbc-connection" xml/gfsh. All the old "jdbc-connection" commands have been removed.

The create jndi-binding command has been changed in the following ways:
* the driver-class-name gfsh parameter is now optional.
* --url can be used as a replacement for --connnection-url
* the --type now defaults to SIMPLE (it used to not have a default).
* the --type=POOLED now defaults to creating a Hikari pool and an SPI exists to customize the class 
that implements the pool.

New External APIS:
  DataSourceFactoryTest: this is the SPI users can implement for the POOLED type.

Co-authored-by: @BenjaminPerryRoss
  • Loading branch information
dschneider-pivotal authored Oct 24, 2018
1 parent 1c55639 commit 404c64d
Show file tree
Hide file tree
Showing 90 changed files with 788 additions and 4,258 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -709,10 +709,15 @@ javadoc/org/apache/geode/compression/package-tree.html
javadoc/org/apache/geode/connectors/jdbc/JdbcAsyncWriter.html
javadoc/org/apache/geode/connectors/jdbc/JdbcConnectorException.html
javadoc/org/apache/geode/connectors/jdbc/JdbcLoader.html
javadoc/org/apache/geode/connectors/jdbc/JdbcPooledDataSourceFactory.html
javadoc/org/apache/geode/connectors/jdbc/JdbcWriter.html
javadoc/org/apache/geode/connectors/jdbc/package-frame.html
javadoc/org/apache/geode/connectors/jdbc/package-summary.html
javadoc/org/apache/geode/connectors/jdbc/package-tree.html
javadoc/org/apache/geode/datasource/PooledDataSourceFactory.html
javadoc/org/apache/geode/datasource/package-frame.html
javadoc/org/apache/geode/datasource/package-summary.html
javadoc/org/apache/geode/datasource/package-tree.html
javadoc/org/apache/geode/distributed/AbstractLauncher.ServiceState.html
javadoc/org/apache/geode/distributed/AbstractLauncher.Status.html
javadoc/org/apache/geode/distributed/AbstractLauncher.html
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geode.connectors.jdbc;

import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
import org.apache.geode.internal.jndi.JNDIInvoker;
import org.apache.geode.management.internal.configuration.domain.Configuration;
import org.apache.geode.management.internal.configuration.utils.XmlUtils;
import org.apache.geode.test.dunit.rules.ClusterStartupRule;
import org.apache.geode.test.dunit.rules.MemberVM;
import org.apache.geode.test.junit.categories.JDBCConnectorTest;
import org.apache.geode.test.junit.rules.GfshCommandRule;
import org.apache.geode.test.junit.rules.VMProvider;

@Category({JDBCConnectorTest.class})
public class CreatePooledJndiBindingDUnitTest {

private MemberVM locator, server1, server2;

@Rule
public ClusterStartupRule cluster = new ClusterStartupRule();

@Rule
public GfshCommandRule gfsh = new GfshCommandRule();


@Before
public void before() throws Exception {
locator = cluster.startLocatorVM(0);
server1 = cluster.startServerVM(1, "group1", locator.getPort());
server2 = cluster.startServerVM(2, "group1", locator.getPort());

gfsh.connectAndVerify(locator);
}

@Test
public void testCreateJndiBinding() throws Exception {
// assert that is no datasource
VMProvider.invokeInEveryMember(
() -> assertThat(JNDIInvoker.getNoOfAvailableDataSources()).isEqualTo(0));

// create the binding
gfsh.executeAndAssertThat(
"create jndi-binding --name=jndi1 --username=myuser --password=mypass --type=POOLED --connection-url=\"jdbc:derby:newDB;create=true\" --conn-pooled-datasource-class=org.apache.geode.internal.jta.CacheJTAPooledDataSourceFactory")
.statusIsSuccess().tableHasColumnOnlyWithValues("Member", "server-1", "server-2");

// verify cluster config is updated
locator.invoke(() -> {
InternalConfigurationPersistenceService ccService =
ClusterStartupRule.getLocator().getConfigurationPersistenceService();
Configuration configuration = ccService.getConfiguration("cluster");
String xmlContent = configuration.getCacheXmlContent();

Document document = XmlUtils.createDocumentFromXml(xmlContent);
NodeList jndiBindings = document.getElementsByTagName("jndi-binding");

assertThat(jndiBindings.getLength()).isEqualTo(1);
assertThat(xmlContent).contains("user-name=\"myuser\"");
assertThat(xmlContent).contains("password=\"mypass\"");

boolean found = false;
for (int i = 0; i < jndiBindings.getLength(); i++) {
Element eachBinding = (Element) jndiBindings.item(i);
if (eachBinding.getAttribute("jndi-name").equals("jndi1")) {
found = true;
break;
}
}
assertThat(found).isTrue();
});

// verify datasource exists
VMProvider.invokeInEveryMember(
() -> assertThat(JNDIInvoker.getNoOfAvailableDataSources()).isEqualTo(1), server1, server2);

// bounce server1
server1.stop(false);
server1 = cluster.startServerVM(1, locator.getPort());

// verify it has recreated the datasource from cluster config
server1.invoke(() -> {
assertThat(JNDIInvoker.getNoOfAvailableDataSources()).isEqualTo(1);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,10 @@
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionFactory;
import org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
import org.apache.geode.connectors.jdbc.internal.RegionMappingExistsException;
import org.apache.geode.connectors.jdbc.internal.SqlHandler;
import org.apache.geode.connectors.jdbc.internal.TableMetaDataManager;
import org.apache.geode.connectors.jdbc.internal.TestConfigService;
import org.apache.geode.connectors.jdbc.internal.TestableConnectionManager;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.pdx.PdxInstance;

Expand All @@ -54,6 +52,8 @@ public abstract class JdbcAsyncWriterIntegrationTest {
private PdxInstance pdxEmployee2;
private Employee employee1;
private Employee employee2;
private final TestDataSourceFactory testDataSourceFactory =
new TestDataSourceFactory(getConnectionUrl());

@Before
public void setup() throws Exception {
Expand All @@ -79,15 +79,17 @@ public void tearDown() throws Exception {
}

private void closeDB() throws Exception {
if (statement == null) {
if (statement == null && connection != null) {
statement = connection.createStatement();
}
statement.execute("Drop table " + REGION_TABLE_NAME);
statement.close();

if (statement != null) {
statement.execute("Drop table " + REGION_TABLE_NAME);
statement.close();
}
if (connection != null) {
connection.close();
}
testDataSourceFactory.close();
}

public abstract Connection getConnection() throws SQLException;
Expand Down Expand Up @@ -220,7 +222,7 @@ private void assertRecordMatchesEmployee(ResultSet resultSet, String key, Employ
}

private Region<String, PdxInstance> createRegionWithJDBCAsyncWriter(String regionName)
throws ConnectionConfigExistsException, RegionMappingExistsException {
throws RegionMappingExistsException {
jdbcWriter = new JdbcAsyncWriter(createSqlHandler(), cache);
cache.createAsyncEventQueueFactory().setBatchSize(1).setBatchTimeInterval(1)
.create("jdbcAsyncQueue", jdbcWriter);
Expand All @@ -238,9 +240,10 @@ private void validateTableRowCount(int expected) throws Exception {
}

private SqlHandler createSqlHandler()
throws ConnectionConfigExistsException, RegionMappingExistsException {
return new SqlHandler(new TestableConnectionManager(), new TableMetaDataManager(),
TestConfigService.getTestConfigService(getConnectionUrl()));
throws RegionMappingExistsException {
return new SqlHandler(new TableMetaDataManager(),
TestConfigService.getTestConfigService(getConnectionUrl()),
testDataSourceFactory);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public void throwsExceptionWhenNoConnectionExists() throws Exception {
Region<Object, Object> region = ClusterStartupRule.getCache().getRegion(REGION_NAME);
assertThatThrownBy(() -> region.put("key1", pdxEmployee1))
.isExactlyInstanceOf(JdbcConnectorException.class).hasMessage(
"JDBC connection with name TestConnection not found. Create the connection with the gfsh command 'create jdbc-connection'");
"JDBC connection with name TestConnection not found. Create the connection with the gfsh command 'create jndi-binding'");
});
}

Expand Down Expand Up @@ -607,7 +607,7 @@ private void createClientRegion(ClientVM client) {

private void createJdbcConnection() {
final String commandStr =
"create jdbc-connection --name=" + CONNECTION_NAME + " --url=" + connectionUrl;
"create jndi-binding --type=POOLED --name=" + CONNECTION_NAME + " --url=" + connectionUrl;
gfsh.executeAndAssertThat(commandStr).statusIsSuccess();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,10 @@
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionFactory;
import org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
import org.apache.geode.connectors.jdbc.internal.RegionMappingExistsException;
import org.apache.geode.connectors.jdbc.internal.SqlHandler;
import org.apache.geode.connectors.jdbc.internal.TableMetaDataManager;
import org.apache.geode.connectors.jdbc.internal.TestConfigService;
import org.apache.geode.connectors.jdbc.internal.TestableConnectionManager;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.util.BlobHelper;
import org.apache.geode.pdx.PdxInstance;
Expand All @@ -58,6 +56,9 @@ public abstract class JdbcLoaderIntegrationTest {
@Rule
public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();

private final TestDataSourceFactory testDataSourceFactory =
new TestDataSourceFactory(getConnectionUrl());

@Before
public void setUp() throws Exception {
System.setProperty(AutoSerializableManager.NO_HARDCODED_EXCLUDES_PARAM, "true");
Expand Down Expand Up @@ -98,6 +99,7 @@ private void closeDB() throws Exception {
if (connection != null) {
connection.close();
}
testDataSourceFactory.close();
}

@Test
Expand Down Expand Up @@ -175,15 +177,16 @@ public void verifySimpleMiss() throws Exception {
}

private SqlHandler createSqlHandler(String pdxClassName, boolean primaryKeyInValue)
throws ConnectionConfigExistsException, RegionMappingExistsException {
return new SqlHandler(new TestableConnectionManager(), new TableMetaDataManager(),
throws RegionMappingExistsException {
return new SqlHandler(new TableMetaDataManager(),
TestConfigService.getTestConfigService((InternalCache) cache, pdxClassName,
primaryKeyInValue, getConnectionUrl()));
primaryKeyInValue, getConnectionUrl()),
testDataSourceFactory);
}

private <K, V> Region<K, V> createRegionWithJDBCLoader(String regionName, String pdxClassName,
boolean primaryKeyInValue)
throws ConnectionConfigExistsException, RegionMappingExistsException {
throws RegionMappingExistsException {
JdbcLoader<K, V> jdbcLoader =
new JdbcLoader<>(createSqlHandler(pdxClassName, primaryKeyInValue), cache);
RegionFactory<K, V> regionFactory = cache.createRegionFactory(REPLICATE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,10 @@
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionFactory;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
import org.apache.geode.connectors.jdbc.internal.RegionMappingExistsException;
import org.apache.geode.connectors.jdbc.internal.SqlHandler;
import org.apache.geode.connectors.jdbc.internal.TableMetaDataManager;
import org.apache.geode.connectors.jdbc.internal.TestConfigService;
import org.apache.geode.connectors.jdbc.internal.TestableConnectionManager;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.pdx.PdxInstance;

Expand All @@ -55,6 +53,8 @@ public abstract class JdbcWriterIntegrationTest {
private PdxInstance pdx2;
private Employee employee1;
private Employee employee2;
private final TestDataSourceFactory testDataSourceFactory =
new TestDataSourceFactory(getConnectionUrl());

@Before
public void setUp() throws Exception {
Expand Down Expand Up @@ -86,14 +86,18 @@ public void tearDown() throws Exception {

private void closeDB() throws Exception {
if (statement == null) {
statement = connection.createStatement();
if (connection != null) {
statement = connection.createStatement();
}
}
if (statement != null) {
statement.execute("Drop table " + REGION_TABLE_NAME);
statement.close();
}
statement.execute("Drop table " + REGION_TABLE_NAME);
statement.close();

if (connection != null) {
connection.close();
}
testDataSourceFactory.close();
}

@Test
Expand Down Expand Up @@ -206,7 +210,7 @@ public void canInsertBecomeUpdate() throws Exception {
}

private Region<String, PdxInstance> createRegionWithJDBCSynchronousWriter(String regionName)
throws ConnectionConfigExistsException, RegionMappingExistsException {
throws RegionMappingExistsException {
jdbcWriter = new JdbcWriter(createSqlHandler(), cache);

RegionFactory<String, PdxInstance> regionFactory =
Expand All @@ -223,9 +227,10 @@ private void validateTableRowCount(int expected) throws Exception {
}

private SqlHandler createSqlHandler()
throws ConnectionConfigExistsException, RegionMappingExistsException {
return new SqlHandler(new TestableConnectionManager(), new TableMetaDataManager(),
TestConfigService.getTestConfigService(getConnectionUrl()));
throws RegionMappingExistsException {
return new SqlHandler(new TableMetaDataManager(),
TestConfigService.getTestConfigService(getConnectionUrl()),
testDataSourceFactory);
}

private void assertRecordMatchesEmployee(ResultSet resultSet, String key, Employee employee)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geode.connectors.jdbc;

import javax.sql.DataSource;

import com.zaxxer.hikari.HikariDataSource;

import org.apache.geode.connectors.jdbc.internal.SqlHandler.DataSourceFactory;

public class TestDataSourceFactory implements DataSourceFactory {
private final String url;
private HikariDataSource dataSource;

public TestDataSourceFactory(String url) {
this.url = url;
}

@Override
public DataSource getDataSource(String dataSourceName) {
if (dataSource == null) {
dataSource = new HikariDataSource();
dataSource.setJdbcUrl(url);
}
return dataSource;
}

public void close() {
if (dataSource != null) {
dataSource.close();
}
}
}
Loading

0 comments on commit 404c64d

Please sign in to comment.