This is an automated email from the ASF dual-hosted git repository.

lgallinat pushed a commit to branch feature/GEODE-4017
in repository https://gitbox.apache.org/repos/asf/geode.git

commit a27b7ca6026238af91c5b7b9aadd777a2fd4e881
Author: Lynn Gallinat <lgalli...@pivotal.io>
AuthorDate: Thu Dec 7 17:43:07 2017 -0800

    GEODE-4017 Add alter connection command
---
 .../jdbc/internal/ConnectionConfigBuilder.java     |  12 +-
 ...java => ConnectionConfigNotFoundException.java} |  26 +--
 .../jdbc/internal/ConnectionConfiguration.java     |  11 +-
 .../internal/InternalJdbcConnectorService.java     |   3 +
 .../jdbc/internal/JdbcConnectorService.java        |  13 ++
 .../jdbc/internal/cli/AlterConnectionCommand.java  | 139 +++++++++++++
 .../jdbc/internal/cli/AlterConnectionFunction.java | 116 +++++++++++
 .../org.springframework.shell.core.CommandMarker   |   3 +-
 .../jdbc/internal/JdbcConnectorServiceTest.java    |  11 ++
 .../cli/AlterConnectionCommandDUnitTest.java       | 132 +++++++++++++
 .../cli/AlterConnectionCommandIntegrationTest.java |  79 ++++++++
 .../internal/cli/AlterConnectionFunctionTest.java  | 220 +++++++++++++++++++++
 .../internal/cli/CreateConnectionFunctionTest.java |   4 +
 13 files changed, 745 insertions(+), 24 deletions(-)

diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfigBuilder.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfigBuilder.java
index c03034b..480517f 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfigBuilder.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfigBuilder.java
@@ -48,10 +48,14 @@ public class ConnectionConfigBuilder {
   }
 
   public ConnectionConfigBuilder withParameters(String[] params) {
-    for (String param : params) {
-      String[] keyValuePair = param.split(PARAMS_DELIMITER);
-      if (keyValuePair.length == 2) {
-        parameters.put(keyValuePair[0], keyValuePair[1]);
+    if (params == null) {
+      parameters = null;
+    } else {
+      for (String param : params) {
+        String[] keyValuePair = param.split(PARAMS_DELIMITER);
+        if (keyValuePair.length == 2) {
+          parameters.put(keyValuePair[0], keyValuePair[1]);
+        }
       }
     }
     return this;
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/InternalJdbcConnectorService.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfigNotFoundException.java
similarity index 56%
copy from 
geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/InternalJdbcConnectorService.java
copy to 
geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfigNotFoundException.java
index c242255..0c74d3b 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/InternalJdbcConnectorService.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfigNotFoundException.java
@@ -14,24 +14,18 @@
  */
 package org.apache.geode.connectors.jdbc.internal;
 
-import java.util.Set;
+public class ConnectionConfigNotFoundException extends Exception {
 
-import org.apache.geode.cache.Cache;
-import org.apache.geode.internal.cache.CacheService;
-import org.apache.geode.internal.cache.extension.Extension;
+  public ConnectionConfigNotFoundException() {
+    super();
+  }
 
-public interface InternalJdbcConnectorService extends Extension<Cache>, 
CacheService {
+  public ConnectionConfigNotFoundException(String message) {
+    super(message);
+  }
 
-  void createConnectionConfig(ConnectionConfiguration config)
-      throws ConnectionConfigExistsException;
+  public ConnectionConfigNotFoundException(String message, Throwable cause) {
+    super(message, cause);
+  }
 
-  void destroyConnectionConfig(String connectionName);
-
-  ConnectionConfiguration getConnectionConfig(String connectionName);
-
-  Set<ConnectionConfiguration> getConnectionConfigs();
-
-  void addOrUpdateRegionMapping(RegionMapping mapping);
-
-  RegionMapping getMappingForRegion(String regionName);
 }
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfiguration.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfiguration.java
index 72b4aa8..0254817 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfiguration.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfiguration.java
@@ -36,8 +36,7 @@ public class ConnectionConfiguration implements Serializable {
     this.url = url;
     this.user = user;
     this.password = password;
-    this.parameters =
-        parameters == null ? new HashMap<>() : 
Collections.unmodifiableMap(parameters);
+    this.parameters = parameters == null ? null : 
Collections.unmodifiableMap(parameters);
   }
 
   public String getName() {
@@ -56,10 +55,16 @@ public class ConnectionConfiguration implements 
Serializable {
     return password;
   }
 
+  public Map<String, String> getParameters() {
+    return parameters;
+  }
+
   public Properties getConnectionProperties() {
     Properties properties = new Properties();
 
-    properties.putAll(parameters);
+    if (parameters != null) {
+      properties.putAll(parameters);
+    }
     if (user != null) {
       properties.put(USER, user);
     }
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/InternalJdbcConnectorService.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/InternalJdbcConnectorService.java
index c242255..8241c66 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/InternalJdbcConnectorService.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/InternalJdbcConnectorService.java
@@ -25,6 +25,9 @@ public interface InternalJdbcConnectorService extends 
Extension<Cache>, CacheSer
   void createConnectionConfig(ConnectionConfiguration config)
       throws ConnectionConfigExistsException;
 
+  void replaceConnectionConfig(ConnectionConfiguration config)
+      throws ConnectionConfigNotFoundException;
+
   void destroyConnectionConfig(String connectionName);
 
   ConnectionConfiguration getConnectionConfig(String connectionName);
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorService.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorService.java
index 8192c75..b6b2f07 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorService.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorService.java
@@ -46,6 +46,19 @@ public class JdbcConnectorService implements 
InternalJdbcConnectorService {
   }
 
   @Override
+  public void replaceConnectionConfig(ConnectionConfiguration alteredConfig)
+      throws ConnectionConfigNotFoundException {
+    registerAsExtension();
+    ConnectionConfiguration existingConfig = 
connectionsByName.get(alteredConfig.getName());
+    if (existingConfig == null) {
+      throw new ConnectionConfigNotFoundException(
+          "ConnectionConfiguration " + alteredConfig.getName() + " was not 
found");
+    }
+
+    connectionsByName.put(existingConfig.getName(), alteredConfig);
+  }
+
+  @Override
   public void destroyConnectionConfig(String connectionName) {
     registerAsExtension();
     connectionsByName.remove(connectionName);
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommand.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommand.java
new file mode 100644
index 0000000..bace38d
--- /dev/null
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommand.java
@@ -0,0 +1,139 @@
+/*
+ * 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.internal.cli;
+
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfigBuilder;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.commands.GfshCommand;
+import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.cli.result.TabularResultData;
+import org.apache.geode.management.internal.configuration.domain.XmlEntity;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class AlterConnectionCommand implements GfshCommand {
+  static final String ALTER_JDBC_CONNECTION = "alter jdbc-connection";
+  static final String ALTER_JDBC_CONNECTION__HELP =
+      "Alter properties for an existing jdbc connection.";
+
+  static final String ALTER_CONNECTION__NAME = "name";
+  static final String ALTER_CONNECTION__NAME__HELP = "Name of the connection 
to be altered.";
+  static final String ALTER_CONNECTION__URL = "url";
+  static final String ALTER_CONNECTION__URL__HELP = "New URL location for the 
database.";
+  static final String ALTER_CONNECTION__USER = "user";
+  static final String ALTER_CONNECTION__USER__HELP =
+      "New user name to use when connecting to database.";
+  static final String ALTER_CONNECTION__PASSWORD = "password";
+  static final String ALTER_CONNECTION__PASSWORD__HELP =
+      "New password to use when connecting to database.";
+  static final String ALTER_CONNECTION__PARAMS = "params";
+  static final String ALTER_CONNECTION__PARAMS__HELP =
+      "New additional parameters to use when connecting to the database. This 
replaces all previously existing parameters.";
+
+  private static final String ERROR_PREFIX = "ERROR: ";
+
+  @CliCommand(value = ALTER_JDBC_CONNECTION, help = 
ALTER_JDBC_CONNECTION__HELP)
+  @CliMetaData(relatedTopic = CliStrings.DEFAULT_TOPIC_GEODE)
+  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+      operation = ResourcePermission.Operation.MANAGE)
+  public Result alterConnection(
+      @CliOption(key = ALTER_CONNECTION__NAME, mandatory = true,
+          help = ALTER_CONNECTION__NAME__HELP) String name,
+      @CliOption(key = ALTER_CONNECTION__URL, specifiedDefaultValue = "",
+          help = ALTER_CONNECTION__URL__HELP) String url,
+      @CliOption(key = ALTER_CONNECTION__USER, specifiedDefaultValue = "",
+          help = ALTER_CONNECTION__USER__HELP) String user,
+      @CliOption(key = ALTER_CONNECTION__PASSWORD, specifiedDefaultValue = "",
+          help = ALTER_CONNECTION__PASSWORD__HELP) String password,
+      @CliOption(key = ALTER_CONNECTION__PARAMS, specifiedDefaultValue = "",
+          help = ALTER_CONNECTION__PARAMS__HELP) String[] params) {
+    // input
+    Set<DistributedMember> targetMembers = getMembers(null, null);
+    ConnectionConfiguration configuration = getArguments(name, url, user, 
password, params);
+
+    // action
+    ResultCollector<CliFunctionResult, List<CliFunctionResult>> 
resultCollector =
+        execute(new AlterConnectionFunction(), configuration, targetMembers);
+
+    // output
+    TabularResultData tabularResultData = 
ResultBuilder.createTabularResultData();
+    XmlEntity xmlEntity = fillTabularResultData(resultCollector, 
tabularResultData);
+    Result result = ResultBuilder.buildResult(tabularResultData);
+    updateClusterConfiguration(result, xmlEntity);
+    return result;
+  }
+
+  ResultCollector<CliFunctionResult, List<CliFunctionResult>> execute(
+      AlterConnectionFunction function, ConnectionConfiguration configuration,
+      Set<DistributedMember> targetMembers) {
+    return (ResultCollector<CliFunctionResult, List<CliFunctionResult>>) 
executeFunction(function,
+        configuration, targetMembers);
+  }
+
+  private ConnectionConfiguration getArguments(String name, String url, String 
user,
+      String password, String[] params) {
+    ConnectionConfigBuilder builder = new 
ConnectionConfigBuilder().withName(name).withUrl(url)
+        .withUser(user).withPassword(password).withParameters(params);
+    return builder.build();
+  }
+
+  private XmlEntity fillTabularResultData(
+      ResultCollector<CliFunctionResult, List<CliFunctionResult>> 
resultCollector,
+      TabularResultData tabularResultData) {
+    XmlEntity xmlEntity = null;
+
+    for (CliFunctionResult oneResult : resultCollector.getResult()) {
+      if (oneResult.isSuccessful()) {
+        xmlEntity = addSuccessToResults(tabularResultData, oneResult);
+      } else {
+        addErrorToResults(tabularResultData, oneResult);
+      }
+    }
+
+    return xmlEntity;
+  }
+
+  private XmlEntity addSuccessToResults(TabularResultData tabularResultData,
+      CliFunctionResult oneResult) {
+    tabularResultData.accumulate("Member", oneResult.getMemberIdOrName());
+    tabularResultData.accumulate("Status", oneResult.getMessage());
+    return oneResult.getXmlEntity();
+  }
+
+  private void addErrorToResults(TabularResultData tabularResultData, 
CliFunctionResult oneResult) {
+    tabularResultData.accumulate("Member", oneResult.getMemberIdOrName());
+    tabularResultData.accumulate("Status", ERROR_PREFIX + 
oneResult.getMessage());
+    tabularResultData.setStatus(Result.Status.ERROR);
+  }
+
+  private void updateClusterConfiguration(final Result result, final XmlEntity 
xmlEntity) {
+    if (xmlEntity != null) {
+      persistClusterConfiguration(result,
+          () -> getSharedConfiguration().addXmlEntity(xmlEntity, null));
+    }
+  }
+}
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionFunction.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionFunction.java
new file mode 100644
index 0000000..c6316a2
--- /dev/null
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionFunction.java
@@ -0,0 +1,116 @@
+/*
+ * 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.internal.cli;
+
+import java.util.Map;
+
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionContext;
+import 
org.apache.geode.connectors.jdbc.internal.ConnectionConfigNotFoundException;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
+import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
+import org.apache.geode.internal.InternalEntity;
+import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
+import org.apache.geode.management.internal.configuration.domain.XmlEntity;
+
+public class AlterConnectionFunction implements 
Function<ConnectionConfiguration>, InternalEntity {
+
+  private static final String ID = AlterConnectionFunction.class.getName();
+
+  private final FunctionContextArgumentProvider argumentProvider;
+  private final ExceptionHandler exceptionHandler;
+
+  AlterConnectionFunction() {
+    this(new FunctionContextArgumentProvider(), new ExceptionHandler());
+  }
+
+  private AlterConnectionFunction(FunctionContextArgumentProvider 
argumentProvider,
+      ExceptionHandler exceptionHandler) {
+    this.argumentProvider = argumentProvider;
+    this.exceptionHandler = exceptionHandler;
+  }
+
+  @Override
+  public boolean isHA() {
+    return false;
+  }
+
+  @Override
+  public String getId() {
+    return ID;
+  }
+
+  @Override
+  public void execute(FunctionContext<ConnectionConfiguration> context) {
+    try {
+      // input
+      ConnectionConfiguration connectionConfig = context.getArguments();
+      InternalJdbcConnectorService service = 
argumentProvider.getJdbcConnectorService(context);
+      ConnectionConfiguration existingConfig =
+          service.getConnectionConfig(connectionConfig.getName());
+      if (existingConfig == null) {
+        throw new ConnectionConfigNotFoundException(
+            "ConnectionConfiguration " + connectionConfig.getName() + " was 
not found");
+      }
+
+      // action
+      ConnectionConfiguration alteredConfig =
+          alterConnectionConfig(connectionConfig, existingConfig);
+      service.replaceConnectionConfig(alteredConfig);
+
+      // output
+      String member = argumentProvider.getMember(context);
+      XmlEntity xmlEntity = argumentProvider.createXmlEntity(context);
+      CliFunctionResult result = 
createSuccessResult(connectionConfig.getName(), member, xmlEntity);
+      context.getResultSender().lastResult(result);
+
+    } catch (Exception e) {
+      exceptionHandler.handleException(context, e);
+    }
+  }
+
+  /**
+   * Creates the named connection configuration
+   */
+  ConnectionConfiguration alterConnectionConfig(ConnectionConfiguration 
connectionConfig,
+      ConnectionConfiguration existingConfig) throws 
ConnectionConfigNotFoundException {
+    String url = getValue(connectionConfig.getUrl(), existingConfig.getUrl());
+    String user = getValue(connectionConfig.getUser(), 
existingConfig.getUser());
+    String password = getValue(connectionConfig.getPassword(), 
existingConfig.getPassword());
+
+    Map<String, String> parameters = connectionConfig.getParameters();
+    if (parameters == null) {
+      parameters = existingConfig.getParameters();
+    }
+    ConnectionConfiguration alteredConfig =
+        new ConnectionConfiguration(existingConfig.getName(), url, user, 
password, parameters);
+    return alteredConfig;
+  }
+
+  private String getValue(String newValue, String existingValue) {
+    // if newValue is null use the value already in the config
+    // if newValue is the empty string, then "unset" it by returning null
+    if (newValue == null) {
+      return existingValue;
+    }
+    return newValue.isEmpty() ? null : newValue;
+  }
+
+  private CliFunctionResult createSuccessResult(String connectionName, String 
member,
+      XmlEntity xmlEntity) {
+    String message = "Altered JDBC connection " + connectionName + " on " + 
member;
+    return new CliFunctionResult(member, xmlEntity, message);
+  }
+}
diff --git 
a/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
 
b/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
index 60e3207..b9e2a72 100644
--- 
a/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
+++ 
b/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
@@ -14,7 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Lucene Extensions command
+# JDBC Connector Extension commands
 org.apache.geode.connectors.jdbc.internal.cli.CreateConnectionCommand
 org.apache.geode.connectors.jdbc.internal.cli.DestroyConnectionCommand
 org.apache.geode.connectors.jdbc.internal.cli.ListConnectionCommand
+org.apache.geode.connectors.jdbc.internal.cli.AlterConnectionCommand
\ No newline at end of file
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorServiceTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorServiceTest.java
index 0a85da9..85f719f 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorServiceTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorServiceTest.java
@@ -16,9 +16,13 @@ package org.apache.geode.connectors.jdbc.internal;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.entry;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
@@ -35,6 +39,7 @@ public class JdbcConnectorServiceTest {
 
   private ConnectionConfiguration config;
   private ConnectionConfiguration config2;
+  private ConnectionConfiguration configToAlter;
   private RegionMapping mapping;
 
   private JdbcConnectorService service;
@@ -45,6 +50,11 @@ public class JdbcConnectorServiceTest {
     config = mock(ConnectionConfiguration.class);
     mapping = mock(RegionMapping.class);
     config2 = mock(ConnectionConfiguration.class);
+    Map<String, String> parameters = new HashMap<>();
+    parameters.put("key1", "value1");
+    parameters.put("key2", "value2");
+    configToAlter = new ConnectionConfiguration(TEST_CONFIG_NAME, 
"originalUrl", "originalUser",
+        "originalPassword", parameters);
 
     when(cache.getExtensionPoint()).thenReturn(mock(ExtensionPoint.class));
     when(config.getName()).thenReturn(TEST_CONFIG_NAME);
@@ -102,4 +112,5 @@ public class JdbcConnectorServiceTest {
     assertThatThrownBy(() -> service.createConnectionConfig(config2))
         
.isInstanceOf(ConnectionConfigExistsException.class).hasMessageContaining(TEST_CONFIG_NAME);
   }
+
 }
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommandDUnitTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommandDUnitTest.java
new file mode 100644
index 0000000..836029c
--- /dev/null
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommandDUnitTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.internal.cli;
+
+import static 
org.apache.geode.connectors.jdbc.internal.cli.AlterConnectionCommand.ALTER_CONNECTION__NAME;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.AlterConnectionCommand.ALTER_CONNECTION__PARAMS;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.AlterConnectionCommand.ALTER_CONNECTION__PASSWORD;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.AlterConnectionCommand.ALTER_CONNECTION__URL;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.AlterConnectionCommand.ALTER_CONNECTION__USER;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.AlterConnectionCommand.ALTER_JDBC_CONNECTION;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.CreateConnectionCommand.CREATE_CONNECTION;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.CreateConnectionCommand.CREATE_CONNECTION__NAME;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.CreateConnectionCommand.CREATE_CONNECTION__PARAMS;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.CreateConnectionCommand.CREATE_CONNECTION__PASSWORD;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.CreateConnectionCommand.CREATE_CONNECTION__URL;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.CreateConnectionCommand.CREATE_CONNECTION__USER;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
+import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
+import org.apache.geode.distributed.internal.InternalLocator;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+import org.apache.geode.test.junit.rules.serializable.SerializableTestName;
+
+public class AlterConnectionCommandDUnitTest {
+
+  @Rule
+  public transient GfshCommandRule gfsh = new GfshCommandRule();
+
+  @Rule
+  public LocatorServerStartupRule startupRule = new LocatorServerStartupRule();
+
+  @Rule
+  public SerializableTestName testName = new SerializableTestName();
+
+  private MemberVM locator;
+  private MemberVM server;
+
+  @Before
+  public void before() throws Exception {
+    locator = startupRule.startLocatorVM(0);
+    server = startupRule.startServerVM(1, locator.getPort());
+
+    gfsh.connectAndVerify(locator);
+
+    CommandStringBuilder csb = new CommandStringBuilder(CREATE_CONNECTION);
+    csb.addOption(CREATE_CONNECTION__NAME, "name");
+    csb.addOption(CREATE_CONNECTION__URL, "url");
+    csb.addOption(CREATE_CONNECTION__USER, "username");
+    csb.addOption(CREATE_CONNECTION__PASSWORD, "secret");
+    csb.addOption(CREATE_CONNECTION__PARAMS, "param1:value1,param2:value2");
+
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
+  }
+
+  @Test
+  public void altersConnectionWithNewValues() throws Exception {
+    CommandStringBuilder csb = new CommandStringBuilder(ALTER_JDBC_CONNECTION);
+    csb.addOption(ALTER_CONNECTION__NAME, "name");
+    csb.addOption(ALTER_CONNECTION__URL, "newUrl");
+    csb.addOption(ALTER_CONNECTION__USER, "newUsername");
+    csb.addOption(ALTER_CONNECTION__PASSWORD, "newPassword");
+    csb.addOption(ALTER_CONNECTION__PARAMS, "Key1:Value1,Key22:Value22");
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
+
+
+    locator.invoke(() -> {
+      String xml = 
InternalLocator.getLocator().getSharedConfiguration().getConfiguration("cluster")
+          .getCacheXmlContent();
+      assertThat(xml).isNotNull().contains("jdbc:connector-service");
+    });
+
+    server.invoke(() -> {
+      InternalCache cache = LocatorServerStartupRule.getCache();
+      ConnectionConfiguration config =
+          
cache.getService(InternalJdbcConnectorService.class).getConnectionConfig("name");
+      assertThat(config.getUrl()).isEqualTo("newUrl");
+      assertThat(config.getUser()).isEqualTo("newUsername");
+      assertThat(config.getPassword()).isEqualTo("newPassword");
+      assertThat(config.getConnectionProperties()).containsEntry("Key1", 
"Value1")
+          .containsEntry("Key22", "Value22");
+    });
+  }
+
+  @Test
+  public void altersConnectionByRemovingValues() {
+    CommandStringBuilder csb = new CommandStringBuilder(ALTER_JDBC_CONNECTION);
+    csb.addOption(ALTER_CONNECTION__NAME, "name");
+    csb.addOption(ALTER_CONNECTION__URL, "");
+    csb.addOption(ALTER_CONNECTION__USER, "");
+    csb.addOption(ALTER_CONNECTION__PASSWORD, "");
+    csb.addOption(ALTER_CONNECTION__PARAMS, "");
+
+    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
+
+    locator.invoke(() -> {
+      String xml = 
InternalLocator.getLocator().getSharedConfiguration().getConfiguration("cluster")
+          .getCacheXmlContent();
+      assertThat(xml).isNotNull().contains("jdbc:connector-service");
+    });
+
+    server.invoke(() -> {
+      InternalCache cache = LocatorServerStartupRule.getCache();
+      ConnectionConfiguration config =
+          
cache.getService(InternalJdbcConnectorService.class).getConnectionConfig("name");
+      assertThat(config.getUrl()).isNull();
+      assertThat(config.getUser()).isNull();
+      assertThat(config.getPassword()).isNull();
+      assertThat(config.getConnectionProperties()).hasSize(0);
+    });
+  }
+}
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommandIntegrationTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommandIntegrationTest.java
new file mode 100644
index 0000000..bc00618
--- /dev/null
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommandIntegrationTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.internal.cli;
+
+import static 
org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
+import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.cli.Result;
+
+public class AlterConnectionCommandIntegrationTest {
+
+  private InternalCache cache;
+  private AlterConnectionCommand alterConnectionCommand;
+
+  private String name;
+
+  @Before
+  public void setup() throws Exception {
+    name = "name";
+    String url = "url";
+    String user = "user";
+    String password = "password";
+    String[] params = new String[] {"param1:value1", "param2:value2"};
+
+    cache = (InternalCache) new 
CacheFactory().set(ENABLE_CLUSTER_CONFIGURATION, "true").create();
+    (new CreateConnectionCommand()).createConnection(name, url, user, 
password, params);
+
+    alterConnectionCommand = new AlterConnectionCommand();
+  }
+
+  @After
+  public void tearDown() {
+    cache.close();
+  }
+
+  @Test
+  public void altersConnectionConfigurationInService() throws Exception {
+    String[] newParams = new String[] {"key1:value1", "key2:value2"};
+    Result result =
+        alterConnectionCommand.alterConnection(name, "newUrl", "newUser", 
"newPassword", newParams);
+
+    assertThat(result.getStatus()).isSameAs(Result.Status.OK);
+
+    InternalJdbcConnectorService service = 
cache.getService(InternalJdbcConnectorService.class);
+    ConnectionConfiguration connectionConfig = 
service.getConnectionConfig(name);
+
+    assertThat(connectionConfig).isNotNull();
+    assertThat(connectionConfig.getName()).isEqualTo(name);
+    assertThat(connectionConfig.getUrl()).isEqualTo("newUrl");
+    assertThat(connectionConfig.getUser()).isEqualTo("newUser");
+    assertThat(connectionConfig.getPassword()).isEqualTo("newPassword");
+    
assertThat(connectionConfig.getConnectionProperties()).containsEntry("key1", 
"value1")
+        .containsEntry("key2", "value2");
+  }
+
+}
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionFunctionTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionFunctionTest.java
new file mode 100644
index 0000000..4b4aa06
--- /dev/null
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionFunctionTest.java
@@ -0,0 +1,220 @@
+/*
+ * 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.internal.cli;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang.SerializationUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.cache.execute.ResultSender;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfigBuilder;
+import 
org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
+import 
org.apache.geode.connectors.jdbc.internal.ConnectionConfigNotFoundException;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
+import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.distributed.DistributedSystem;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
+
+public class AlterConnectionFunctionTest {
+
+  private static final String CONNECTION_NAME = "theConnection";
+
+  private ConnectionConfiguration connectionConfig;
+  private ConnectionConfiguration existingConfig;
+  private ConnectionConfiguration configToAlter;
+  private FunctionContext<ConnectionConfiguration> context;
+  private ResultSender<Object> resultSender;
+  private InternalJdbcConnectorService service;
+
+  private AlterConnectionFunction function;
+
+  @Before
+  public void setUp() throws Exception {
+    context = mock(FunctionContext.class);
+    resultSender = mock(ResultSender.class);
+    InternalCache cache = mock(InternalCache.class);
+    DistributedSystem system = mock(DistributedSystem.class);
+    DistributedMember distributedMember = mock(DistributedMember.class);
+    service = mock(InternalJdbcConnectorService.class);
+
+    connectionConfig = new 
ConnectionConfigBuilder().withName(CONNECTION_NAME).build();
+    existingConfig = new 
ConnectionConfigBuilder().withName(CONNECTION_NAME).build();
+    Map<String, String> parameters = new HashMap<>();
+    parameters.put("key1", "value1");
+    parameters.put("key2", "value2");
+    configToAlter = new ConnectionConfiguration(CONNECTION_NAME, 
"originalUrl", "originalUser",
+        "originalPassword", parameters);
+
+    when(context.getResultSender()).thenReturn(resultSender);
+    when(context.getCache()).thenReturn(cache);
+    when(cache.getDistributedSystem()).thenReturn(system);
+    when(system.getDistributedMember()).thenReturn(distributedMember);
+    when(context.getArguments()).thenReturn(connectionConfig);
+    
when(cache.getService(eq(InternalJdbcConnectorService.class))).thenReturn(service);
+
+    function = new AlterConnectionFunction();
+  }
+
+  @Test
+  public void isHAReturnsFalse() throws Exception {
+    assertThat(function.isHA()).isFalse();
+  }
+
+  @Test
+  public void getIdReturnsNameOfClass() throws Exception {
+    assertThat(function.getId()).isEqualTo(function.getClass().getName());
+  }
+
+  @Test
+  public void serializes() throws Exception {
+    Serializable original = function;
+
+    Object copy = SerializationUtils.clone(original);
+
+    
assertThat(copy).isNotSameAs(original).isInstanceOf(AlterConnectionFunction.class);
+  }
+
+  @Test
+  public void alterConnectionConfigThrowsConnectionNotFound() throws Exception 
{
+    AlterConnectionFunction alterFunction = 
mock(AlterConnectionFunction.class);
+    doThrow(ConnectionConfigNotFoundException.class).when(alterFunction)
+        .alterConnectionConfig(any(), any());
+
+    assertThatThrownBy(() -> 
alterFunction.alterConnectionConfig(connectionConfig, existingConfig))
+        .isInstanceOf(ConnectionConfigNotFoundException.class);
+  }
+
+  @Test
+  public void executeInvokesReplaceOnService() throws Exception {
+    
when(service.getConnectionConfig(CONNECTION_NAME)).thenReturn(existingConfig);
+    function.execute(context);
+
+    verify(service, times(1)).replaceConnectionConfig(any());
+  }
+
+  @Test
+  public void executeReportsErrorIfConnectionConfigNotFound() throws Exception 
{
+    doThrow(ConnectionConfigNotFoundException.class).when(service)
+        .replaceConnectionConfig(eq(connectionConfig));
+
+    function.execute(context);
+
+    ArgumentCaptor<CliFunctionResult> argument = 
ArgumentCaptor.forClass(CliFunctionResult.class);
+    verify(resultSender, times(1)).lastResult(argument.capture());
+    
assertThat(argument.getValue().getErrorMessage()).contains(CONNECTION_NAME);
+  }
+
+  @Test
+  public void alterConnectionConfigUrl() throws Exception {
+    ConnectionConfiguration newConfigValues =
+        new ConnectionConfiguration(CONNECTION_NAME, "newUrl", null, null, 
null);
+
+    ConnectionConfiguration alteredConfig =
+        function.alterConnectionConfig(newConfigValues, configToAlter);
+
+    assertThat(alteredConfig.getName()).isEqualTo(CONNECTION_NAME);
+    assertThat(alteredConfig.getUrl()).isEqualTo("newUrl");
+    assertThat(alteredConfig.getUser()).isEqualTo("originalUser");
+    assertThat(alteredConfig.getPassword()).isEqualTo("originalPassword");
+    Map<String, String> parameters = alteredConfig.getParameters();
+    assertThat(parameters).containsOnly(entry("key1", "value1"), entry("key2", 
"value2"));
+  }
+
+  @Test
+  public void alterConnectionConfigUser() throws Exception {
+    ConnectionConfiguration newConfigValues =
+        new ConnectionConfiguration(CONNECTION_NAME, null, "newUser", null, 
null);
+
+    ConnectionConfiguration alteredConfig =
+        function.alterConnectionConfig(newConfigValues, configToAlter);
+
+    assertThat(alteredConfig.getName()).isEqualTo(CONNECTION_NAME);
+    assertThat(alteredConfig.getUrl()).isEqualTo("originalUrl");
+    assertThat(alteredConfig.getUser()).isEqualTo("newUser");
+    assertThat(alteredConfig.getPassword()).isEqualTo("originalPassword");
+    assertThat(alteredConfig.getParameters()).containsOnly(entry("key1", 
"value1"),
+        entry("key2", "value2"));
+  }
+
+  @Test
+  public void alterConnectionConfigPassword() throws Exception {
+    ConnectionConfiguration newConfigValues =
+        new ConnectionConfiguration(CONNECTION_NAME, null, null, 
"newPassword", null);
+
+    ConnectionConfiguration alteredConfig =
+        function.alterConnectionConfig(newConfigValues, configToAlter);
+
+    assertThat(alteredConfig.getName()).isEqualTo(CONNECTION_NAME);
+    assertThat(alteredConfig.getUrl()).isEqualTo("originalUrl");
+    assertThat(alteredConfig.getUser()).isEqualTo("originalUser");
+    assertThat(alteredConfig.getPassword()).isEqualTo("newPassword");
+    assertThat(alteredConfig.getParameters()).containsOnly(entry("key1", 
"value1"),
+        entry("key2", "value2"));
+  }
+
+  @Test
+  public void alterConnectionConfigParameters() throws Exception {
+    Map<String, String> newParameters = new HashMap<>();
+    newParameters.put("key1", "anotherValue1");
+    newParameters.put("key8", "value8");
+    ConnectionConfiguration newConfigValues =
+        new ConnectionConfiguration(CONNECTION_NAME, null, null, null, 
newParameters);
+
+    ConnectionConfiguration alteredConfig =
+        function.alterConnectionConfig(newConfigValues, configToAlter);
+
+    assertThat(alteredConfig.getName()).isEqualTo(CONNECTION_NAME);
+    assertThat(alteredConfig.getUrl()).isEqualTo("originalUrl");
+    assertThat(alteredConfig.getUser()).isEqualTo("originalUser");
+    assertThat(alteredConfig.getPassword()).isEqualTo("originalPassword");
+    assertThat(alteredConfig.getParameters()).containsOnly(entry("key1", 
"anotherValue1"),
+        entry("key8", "value8"));
+  }
+
+  @Test
+  public void alterConnectionConfigWithNothingToAlter() throws Exception {
+    ConnectionConfiguration newConfigValues =
+        new ConnectionConfiguration(CONNECTION_NAME, null, null, null, null);
+
+    ConnectionConfiguration alteredConfig =
+        function.alterConnectionConfig(newConfigValues, configToAlter);
+
+    assertThat(alteredConfig.getName()).isEqualTo(CONNECTION_NAME);
+    assertThat(alteredConfig.getUrl()).isEqualTo("originalUrl");
+    assertThat(alteredConfig.getUser()).isEqualTo("originalUser");
+    assertThat(alteredConfig.getPassword()).isEqualTo("originalPassword");
+    assertThat(alteredConfig.getParameters()).containsOnly(entry("key1", 
"value1"),
+        entry("key2", "value2"));
+  }
+}
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunctionTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunctionTest.java
index 882a8d0..228d58b 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunctionTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunctionTest.java
@@ -16,6 +16,7 @@ package org.apache.geode.connectors.jdbc.internal.cli;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.entry;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
@@ -24,6 +25,8 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.commons.lang.SerializationUtils;
 import org.junit.Before;
@@ -133,4 +136,5 @@ public class CreateConnectionFunctionTest {
     assertThat(argument.getValue().getErrorMessage())
         .contains(ConnectionConfigExistsException.class.getName());
   }
+
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@geode.apache.org" <commits@geode.apache.org>.

Reply via email to