This is an automated email from the ASF dual-hosted git repository. zhouxj pushed a commit to branch feature/GEODE-6770 in repository https://gitbox.apache.org/repos/asf/geode.git
commit 98d37be738002badceeda566392c3d892a0ce9e7 Author: zhouxh <[email protected]> AuthorDate: Wed May 22 10:19:58 2019 -0700 GEODE-6770: add optional deregister driver class when destroy data source. Co-authored-by: Benjamin Ross <[email protected]> Co-authored-by: Donal Evans <[email protected]> Co-authored-by: Xiaojian Zhou <[email protected]> --- .../internal/cli/DestroyDataSourceCommand.java | 54 ++++++++- .../internal/cli/DestroyDataSourceCommandTest.java | 132 +++++++++++++++++++++ .../geode/internal/util/DriverJarUtilTest.java | 1 - 3 files changed, 183 insertions(+), 4 deletions(-) diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommand.java index 2b1be87..0188710 100644 --- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommand.java +++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommand.java @@ -14,6 +14,7 @@ */ package org.apache.geode.connectors.jdbc.internal.cli; +import java.sql.SQLException; import java.util.List; import java.util.Set; @@ -28,12 +29,14 @@ import org.apache.geode.cache.configuration.RegionConfig; import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping; import org.apache.geode.distributed.DistributedMember; import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService; +import org.apache.geode.internal.util.DriverJarUtil; import org.apache.geode.management.cli.CliMetaData; import org.apache.geode.management.cli.SingleGfshCommand; import org.apache.geode.management.internal.cli.commands.CreateJndiBindingCommand; import org.apache.geode.management.internal.cli.functions.CliFunctionResult; import org.apache.geode.management.internal.cli.functions.DestroyJndiBindingFunction; import org.apache.geode.management.internal.cli.i18n.CliStrings; +import org.apache.geode.management.internal.cli.result.model.InfoResultModel; import org.apache.geode.management.internal.cli.result.model.ResultModel; import org.apache.geode.management.internal.exceptions.EntityNotFoundException; import org.apache.geode.management.internal.security.ResourceOperation; @@ -49,6 +52,10 @@ public class DestroyDataSourceCommand extends SingleGfshCommand { "Skip the destroy operation when the specified data source does " + "not exist. Without this option, an error results from the specification " + "of a data source that does not exist."; + static final String DEREGISTER_DRIVER = "deregister-driver"; + static final String DEREGISTER_DRIVER_HELP = + "Indicates whether or not the driver class associated" + + "with the target data source should be deregistered during the destroy process."; @CliCommand(value = DESTROY_DATA_SOURCE, help = DESTROY_DATA_SOURCE_HELP) @CliMetaData(relatedTopic = CliStrings.TOPIC_GEODE_REGION) @@ -57,11 +64,15 @@ public class DestroyDataSourceCommand extends SingleGfshCommand { public ResultModel destroyDataSource( @CliOption(key = DATA_SOURCE_NAME, mandatory = true, help = DATA_SOURCE_NAME_HELP) String dataSourceName, + @CliOption(key = DEREGISTER_DRIVER, + help = DEREGISTER_DRIVER_HELP, specifiedDefaultValue = "true", + unspecifiedDefaultValue = "false") boolean deregisterDriver, @CliOption(key = CliStrings.IFEXISTS, help = IFEXISTS_HELP, specifiedDefaultValue = "true", unspecifiedDefaultValue = "false") boolean ifExists) { InternalConfigurationPersistenceService service = (InternalConfigurationPersistenceService) getConfigurationPersistenceService(); + String driverClassName = null; if (service != null) { List<JndiBindingsType.JndiBinding> bindings = service.getCacheConfig("cluster").getJndiBindings(); @@ -86,6 +97,9 @@ public class DestroyDataSourceCommand extends SingleGfshCommand { dataSourceName, ex.getMessage())); } + if (deregisterDriver) { + driverClassName = binding.getJdbcDriverClass(); + } } Set<DistributedMember> targetMembers = findMembers(null, null); @@ -109,14 +123,27 @@ public class DestroyDataSourceCommand extends SingleGfshCommand { } ResultModel result = ResultModel.createMemberStatusResult(dataSourceDestroyResult); + InfoResultModel infoModel = result.addInfo(); + String deregisterResult = deregisterDriver(deregisterDriver, driverClassName, dataSourceName); + if (deregisterResult != null) { + infoModel.addLine(deregisterResult); + } result.setConfigObject(dataSourceName); return result; } else { if (service != null) { - ResultModel result = - ResultModel - .createInfo("No members found, data source removed from cluster configuration."); + // ResultModel result = + // ResultModel + // .createInfo("No members found, data source removed from cluster configuration."); + ResultModel result = new ResultModel(); + InfoResultModel infoModel = result.addInfo(); + infoModel.addLine("No members found, data source removed from cluster configuration."); + String deregisterResult = + deregisterDriver(deregisterDriver, driverClassName, dataSourceName); + if (deregisterResult != null) { + infoModel.addLine(deregisterResult); + } result.setConfigObject(dataSourceName); return result; } else { @@ -149,6 +176,27 @@ public class DestroyDataSourceCommand extends SingleGfshCommand { || CreateJndiBindingCommand.DATASOURCE_TYPE.POOLED.getType().equals(binding.getType()); } + private String deregisterDriver(boolean deregisterDriver, String driverClassName, + String dataSourceName) { + if (deregisterDriver && driverClassName != null) { + DriverJarUtil util = createDriverJarUtil(); + try { + util.deregisterDriver(driverClassName); + } catch (SQLException ex) { + return "Warning: deregistering \"" + driverClassName + "\" while destroying data source \"" + + dataSourceName + "\" failed with exception: " + ex.getMessage(); + } + } else if (deregisterDriver && driverClassName == null) { + return "Warning: deregistering \"" + driverClassName + "\" while destroying data source \"" + + dataSourceName + "\" failed: No driver class name found"; + } + return null; + } + + DriverJarUtil createDriverJarUtil() { + return new DriverJarUtil(); + } + @Override public boolean updateConfigForGroup(String group, CacheConfig config, Object element) { CacheElement.removeElement(config.getJndiBindings(), (String) element); diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommandTest.java index 4388e91..823b946 100644 --- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommandTest.java +++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommandTest.java @@ -20,12 +20,14 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNotNull; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -47,6 +49,7 @@ import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping; import org.apache.geode.distributed.DistributedMember; import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService; import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.util.DriverJarUtil; import org.apache.geode.management.internal.cli.commands.CreateJndiBindingCommand; import org.apache.geode.management.internal.cli.functions.CliFunctionResult; import org.apache.geode.management.internal.cli.functions.DestroyJndiBindingFunction; @@ -364,4 +367,133 @@ public class DestroyDataSourceCommandTest { assertThat(destroyingDataSource).isEqualTo(true); assertThat(targetMembers.getValue()).isEqualTo(members); } + + @Test + public void destroyDataSourceWithDeregisterDriverSucceedsWithWarning() { + List<JndiBindingsType.JndiBinding> bindings = new ArrayList<>(); + JndiBindingsType.JndiBinding jndiBinding = new JndiBindingsType.JndiBinding(); + jndiBinding.setJndiName("name"); + jndiBinding.setType(CreateJndiBindingCommand.DATASOURCE_TYPE.SIMPLE.getType()); + bindings.add(jndiBinding); + doReturn(bindings).when(cacheConfig).getJndiBindings(); + + Set<DistributedMember> members = new HashSet<>(); + members.add(mock(DistributedMember.class)); + + CliFunctionResult result = + new CliFunctionResult("server1", true, "Data source \"name\" destroyed on \"server1\""); + List<CliFunctionResult> results = new ArrayList<>(); + results.add(result); + + doReturn(members).when(command).findMembers(any(), any()); + doReturn(results).when(command).executeAndGetFunctionResult(any(), any(), any()); + + gfsh.executeAndAssertThat(command, COMMAND + " --name=name --deregister-driver") + .statusIsSuccess() + .tableHasColumnOnlyWithValues("Member", "server1") + .tableHasColumnOnlyWithValues("Status", "OK") + .tableHasColumnOnlyWithValues("Message", "Data source \"name\" destroyed on \"server1\""); + + assertThat(cacheConfig.getJndiBindings().isEmpty()).isTrue(); + verify(command).updateConfigForGroup(eq("cluster"), eq(cacheConfig), any()); + + ArgumentCaptor<DestroyJndiBindingFunction> function = + ArgumentCaptor.forClass(DestroyJndiBindingFunction.class); + ArgumentCaptor<Object[]> arguments = ArgumentCaptor.forClass(Object[].class); + + ArgumentCaptor<Set<DistributedMember>> targetMembers = ArgumentCaptor.forClass(Set.class); + verify(command, times(1)).executeAndGetFunctionResult(function.capture(), arguments.capture(), + targetMembers.capture()); + + String jndiName = (String) arguments.getValue()[0]; + boolean destroyingDataSource = (boolean) arguments.getValue()[1]; + + assertThat(function.getValue()).isInstanceOf(DestroyJndiBindingFunction.class); + assertThat(jndiName).isEqualTo("name"); + assertThat(destroyingDataSource).isEqualTo(true); + assertThat(targetMembers.getValue()).isEqualTo(members); + } + + @Test + public void destroyDataSourceThrowsSQLExceptpionWithRegisterDriverAndBadDriverClassName() + throws SQLException { + DriverJarUtil util = mock(DriverJarUtil.class); + doReturn(util).when(command).createDriverJarUtil(); + + String exceptionMessage = "Command failed as expected."; + + doThrow(new SQLException(exceptionMessage)).when(util).deregisterDriver(any()); + + List<JndiBindingsType.JndiBinding> bindings = new ArrayList<>(); + JndiBindingsType.JndiBinding jndiBinding = new JndiBindingsType.JndiBinding(); + jndiBinding.setJndiName("name"); + jndiBinding.setJdbcDriverClass("badDriverClassName"); + jndiBinding.setType(CreateJndiBindingCommand.DATASOURCE_TYPE.SIMPLE.getType()); + bindings.add(jndiBinding); + doReturn(bindings).when(cacheConfig).getJndiBindings(); + + Set<DistributedMember> members = new HashSet<>(); + members.add(mock(DistributedMember.class)); + + CliFunctionResult result = + new CliFunctionResult("server1", true, "Data source \"name\" destroyed on \"server1\""); + List<CliFunctionResult> results = new ArrayList<>(); + results.add(result); + + doReturn(members).when(command).findMembers(any(), any()); + doReturn(results).when(command).executeAndGetFunctionResult(any(), any(), any()); + + gfsh.executeAndAssertThat(command, COMMAND + " --name=name --deregister-driver") + .containsOutput(exceptionMessage); + } + + @Test + public void destroyDataSourceWithDeregisterDriverSucceedsWithoutWarnings() { + DriverJarUtil util = mock(DriverJarUtil.class); + + List<JndiBindingsType.JndiBinding> bindings = new ArrayList<>(); + JndiBindingsType.JndiBinding jndiBinding = new JndiBindingsType.JndiBinding(); + jndiBinding.setJndiName("name"); + jndiBinding.setJdbcDriverClass("driverClassName"); + jndiBinding.setType(CreateJndiBindingCommand.DATASOURCE_TYPE.SIMPLE.getType()); + bindings.add(jndiBinding); + doReturn(bindings).when(cacheConfig).getJndiBindings(); + + Set<DistributedMember> members = new HashSet<>(); + members.add(mock(DistributedMember.class)); + + CliFunctionResult result = + new CliFunctionResult("server1", true, "Data source \"name\" destroyed on \"server1\""); + List<CliFunctionResult> results = new ArrayList<>(); + results.add(result); + + doReturn(members).when(command).findMembers(any(), any()); + doReturn(results).when(command).executeAndGetFunctionResult(any(), any(), any()); + + gfsh.executeAndAssertThat(command, COMMAND + " --name=name --deregister-driver") + .statusIsSuccess() + .tableHasColumnOnlyWithValues("Member", "server1") + .tableHasColumnOnlyWithValues("Status", "OK") + .tableHasColumnOnlyWithValues("Message", "Data source \"name\" destroyed on \"server1\"") + .doesNotContainOutput("Warning:"); + + assertThat(cacheConfig.getJndiBindings().isEmpty()).isTrue(); + verify(command).updateConfigForGroup(eq("cluster"), eq(cacheConfig), any()); + + ArgumentCaptor<DestroyJndiBindingFunction> function = + ArgumentCaptor.forClass(DestroyJndiBindingFunction.class); + ArgumentCaptor<Object[]> arguments = ArgumentCaptor.forClass(Object[].class); + + ArgumentCaptor<Set<DistributedMember>> targetMembers = ArgumentCaptor.forClass(Set.class); + verify(command, times(1)).executeAndGetFunctionResult(function.capture(), arguments.capture(), + targetMembers.capture()); + + String jndiName = (String) arguments.getValue()[0]; + boolean destroyingDataSource = (boolean) arguments.getValue()[1]; + + assertThat(function.getValue()).isInstanceOf(DestroyJndiBindingFunction.class); + assertThat(jndiName).isEqualTo("name"); + assertThat(destroyingDataSource).isEqualTo(true); + assertThat(targetMembers.getValue()).isEqualTo(members); + } } diff --git a/geode-core/src/test/java/org/apache/geode/internal/util/DriverJarUtilTest.java b/geode-core/src/test/java/org/apache/geode/internal/util/DriverJarUtilTest.java index 8a93b96..de8102a 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/util/DriverJarUtilTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/util/DriverJarUtilTest.java @@ -63,5 +63,4 @@ public class DriverJarUtilTest { util.deregisterDriver(driverName); verify(util).deregisterDriverWithDriverManager(any()); } - }
