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

jinmeiliao pushed a commit to branch support/1.15
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/support/1.15 by this push:
     new 7bc982dcb5 GEODE-10318: do not add duplicate entries in the locators 
list (#7703)
7bc982dcb5 is described below

commit 7bc982dcb5c70950a020f797e836db01307768b3
Author: Jinmei Liao <[email protected]>
AuthorDate: Mon May 23 09:37:58 2022 -0700

    GEODE-10318: do not add duplicate entries in the locators list (#7703)
    
    * move locator parsing to api package
    
    (cherry picked from commit 7e052cde43208ec0ea62374a95472807d60f444a)
---
 .../internal/LocatorIntegrationTest.java           |  61 +++++++++
 .../distributed/internal/InternalLocator.java      | 147 +++++++++++++--------
 .../distributed/internal/InternalLocatorTest.java  |  53 ++++++++
 ...st.java => LocatorConfigurationParserTest.java} |   6 +-
 .../gms/membership/GMSJoinLeaveJUnitTest.java      |   4 +-
 .../membership/api/LocatorConfigurationParser.java | 142 ++++++++++++++++++++
 .../internal/membership/gms/GMSUtil.java           | 117 +---------------
 .../membership/gms/locator/GMSLocator.java         |   4 +-
 .../membership/gms/membership/GMSJoinLeave.java    |   4 +-
 9 files changed, 360 insertions(+), 178 deletions(-)

diff --git 
a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/LocatorIntegrationTest.java
 
b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/LocatorIntegrationTest.java
new file mode 100644
index 0000000000..2edaafd1d2
--- /dev/null
+++ 
b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/LocatorIntegrationTest.java
@@ -0,0 +1,61 @@
+/*
+ *
+ * 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.distributed.internal;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.net.UnknownHostException;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.internal.AvailablePortHelper;
+import org.apache.geode.internal.inet.LocalHostUtil;
+import org.apache.geode.test.junit.rules.LocatorStarterRule;
+
+public class LocatorIntegrationTest {
+  @Rule
+  public LocatorStarterRule locator = new LocatorStarterRule();
+
+  @Test
+  public void locatorConfigurationShouldNotBeModifiedIfExists() throws 
UnknownHostException {
+    int port = AvailablePortHelper.getRandomAvailableTCPPort();
+    locator.withPort(port);
+    String hostAddress = LocalHostUtil.getLocalHost().getHostAddress();
+    String originalLocators = hostAddress + "[" + port + "]";
+    locator.withProperty("locators", originalLocators);
+    locator.startLocator();
+
+    String locators = locator.getLocator().getConfig().getLocators();
+    assertThat(locators).isEqualTo(originalLocators);
+  }
+
+  @Test
+  public void locatorConfigurationWillBeModifiedToIncludeItselfWithHostName()
+      throws UnknownHostException {
+    int port = AvailablePortHelper.getRandomAvailableTCPPort();
+    locator.withPort(port);
+    locator.startLocator();
+
+    String locators = locator.getLocator().getConfig().getLocators();
+    String hostAddress = LocalHostUtil.getLocalHost().getCanonicalHostName();
+    assertThat(locators).isEqualTo(hostAddress + "[" + port + "]");
+  }
+
+
+}
diff --git 
a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
 
b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
index 201d3cbc70..68b2ce1f8b 100644
--- 
a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
+++ 
b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
@@ -24,6 +24,7 @@ import static 
org.apache.geode.util.internal.GeodeGlossary.GEMFIRE_PREFIX;
 
 import java.io.File;
 import java.io.IOException;
+import java.net.InetAddress;
 import java.net.URI;
 import java.net.UnknownHostException;
 import java.nio.file.Path;
@@ -31,6 +32,7 @@ import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
@@ -64,6 +66,7 @@ import org.apache.geode.distributed.Locator;
 import 
org.apache.geode.distributed.internal.InternalDistributedSystem.ConnectListener;
 import 
org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.distributed.internal.membership.adapter.ServiceConfig;
+import 
org.apache.geode.distributed.internal.membership.api.LocatorConfigurationParser;
 import org.apache.geode.distributed.internal.membership.api.MemberIdentifier;
 import org.apache.geode.distributed.internal.membership.api.MembershipConfig;
 import 
org.apache.geode.distributed.internal.membership.api.MembershipConfigurationException;
@@ -71,6 +74,7 @@ import 
org.apache.geode.distributed.internal.membership.api.MembershipLocator;
 import 
org.apache.geode.distributed.internal.membership.api.MembershipLocatorBuilder;
 import org.apache.geode.distributed.internal.membership.api.QuorumChecker;
 import org.apache.geode.distributed.internal.tcpserver.HostAddress;
+import org.apache.geode.distributed.internal.tcpserver.HostAndPort;
 import org.apache.geode.distributed.internal.tcpserver.InfoRequest;
 import org.apache.geode.distributed.internal.tcpserver.TcpHandler;
 import org.apache.geode.distributed.internal.tcpserver.TcpServer;
@@ -707,71 +711,102 @@ public class InternalLocator extends Locator implements 
ConnectListener, LogConf
       // LOG: changed from config to info
       logger.info("Using existing distributed system: {}", existing);
       startCache(existing);
-    } else {
+      return;
+    }
 
-      StringBuilder sb = new StringBuilder(100);
-      if (hostAddress != null && 
!StringUtils.isEmpty(hostAddress.getHostName())) {
-        sb.append(hostAddress.getHostName());
-      } else {
-        sb.append(LocalHostUtil.getLocalHost().getCanonicalHostName());
-      }
-      sb.append('[').append(getPort()).append(']');
-      String thisLocator = sb.toString();
-
-      if (peerLocator) {
-        // append this locator to the locators list from the config properties
-        boolean setLocatorsProp = false;
-        String locatorsConfigValue = distributionConfig.getLocators();
-        if (StringUtils.isNotBlank(locatorsConfigValue)) {
-          if (!locatorsConfigValue.contains(thisLocator)) {
-            locatorsConfigValue = locatorsConfigValue + ',' + thisLocator;
-            setLocatorsProp = true;
-          }
-        } else {
-          locatorsConfigValue = thisLocator;
-          setLocatorsProp = true;
-        }
-        if (setLocatorsProp) {
-          Properties updateEnv = new Properties();
-          updateEnv.setProperty(LOCATORS, locatorsConfigValue);
-          distributionConfig.setApiProps(updateEnv);
-          String locatorsPropertyName = GEMFIRE_PREFIX + LOCATORS;
-          if (System.getProperty(locatorsPropertyName) != null) {
-            System.setProperty(locatorsPropertyName, locatorsConfigValue);
-          }
-        }
-        // No longer default mcast-port to zero.
+    HostAddress thisLocator = getHostAddress(hostAddress);
+    if (peerLocator) {
+      String existingLocators = distributionConfig.getLocators();
+      String newLocators = addLocatorIfMissing(existingLocators, thisLocator, 
getPort());
+      if (!newLocators.equals(existingLocators)) {
+        setLocatorProperties(newLocators);
       }
+    }
 
-      Properties distributedSystemProperties = new Properties();
-      // LogWriterAppender is now shared via that class
-      // using a DistributionConfig earlier in this method
-      distributedSystemProperties.put(DistributionConfig.DS_CONFIG_NAME, 
distributionConfig);
-
-      logger.info("Starting distributed system");
-
-      internalDistributedSystem =
-          InternalDistributedSystem
-              .connectInternal(distributedSystemProperties, null,
-                  new InternalDistributedSystemMetricsService.Builder(),
-                  membershipLocator);
-
-      if (peerLocator) {
-        // We've created a peer location message handler - it needs to be 
connected to
-        // the membership service in order to get membership view notifications
-        membershipLocator
-            .setMembership(internalDistributedSystem.getDM()
-                .getDistribution().getMembership());
-      }
+    Properties distributedSystemProperties = new Properties();
+    // LogWriterAppender is now shared via that class
+    // using a DistributionConfig earlier in this method
+    distributedSystemProperties.put(DistributionConfig.DS_CONFIG_NAME, 
distributionConfig);
+
+    logger.info("Starting distributed system");
+
+    internalDistributedSystem =
+        InternalDistributedSystem
+            .connectInternal(distributedSystemProperties, null,
+                new InternalDistributedSystemMetricsService.Builder(),
+                membershipLocator);
+
+    if (peerLocator) {
+      // We've created a peer location message handler - it needs to be 
connected to
+      // the membership service in order to get membership view notifications
+      membershipLocator
+          .setMembership(internalDistributedSystem.getDM()
+              .getDistribution().getMembership());
+    }
+
+    internalDistributedSystem.addDisconnectListener(sys -> stop(false, false, 
false));
+
+    startCache(internalDistributedSystem);
 
-      internalDistributedSystem.addDisconnectListener(sys -> stop(false, 
false, false));
+    logger.info("Locator started on {}[{}]", thisLocator, getPort());
 
-      startCache(internalDistributedSystem);
+  }
+
+  HostAddress getHostAddress(HostAddress hostAddress) throws 
UnknownHostException {
+    HostAddress thisLocator;
+    if (hostAddress != null && 
!StringUtils.isEmpty(hostAddress.getHostName())) {
+      thisLocator = hostAddress;
+    } else {
+      thisLocator = new HostAddress(LocalHostUtil.getLocalHost());
+    }
+    return thisLocator;
+  }
+
+  /**
+   * add this locator to the locators list if not already in, note the 
locator's
+   * hostname is used, but if it resoves to be the same as what's already in 
the
+   * list, what's specified by the user is preserved
+   *
+   * @param existingLocators the existing configured locators
+   * @param thisLocator this locator's address
+   * @param port this locator's port
+   * @return the comma separated list of locators with this locator added
+   *         if this locator is not already in the list
+   */
+  String addLocatorIfMissing(String existingLocators, HostAddress thisLocator, 
int port)
+      throws IOException {
+    String thisLocatorHostnameAndPort = String.format("%s[%d]", 
thisLocator.getHostName(), port);
+    if (StringUtils.isBlank(existingLocators)) {
+      return thisLocatorHostnameAndPort;
+    }
+
+    List<HostAndPort> hostAndPorts;
+    try {
+      hostAndPorts = 
LocatorConfigurationParser.parseLocators(existingLocators, (InetAddress) null);
+    } catch (MembershipConfigurationException e) {
+      throw new IOException(e.getMessage(), e);
+    }
 
-      logger.info("Locator started on {}", thisLocator);
+    if (hostAndPorts.stream().anyMatch(
+        (hp) -> thisLocator.getAddress().equals(hp.getAddress())
+            && port == hp.getPort())) {
+      return existingLocators;
     }
+    // if not found in existing locators
+    return existingLocators + "," + thisLocatorHostnameAndPort;
   }
 
+  private void setLocatorProperties(String locatorsConfigValue) {
+    Properties updateEnv = new Properties();
+    updateEnv.setProperty(LOCATORS, locatorsConfigValue);
+    distributionConfig.setApiProps(updateEnv);
+    String locatorsPropertyName = GEMFIRE_PREFIX + LOCATORS;
+    if (System.getProperty(locatorsPropertyName) != null) {
+      System.setProperty(locatorsPropertyName, locatorsConfigValue);
+    }
+  }
+
+
   private void startCache(DistributedSystem system) throws IOException {
     InternalCache internalCache = GemFireCacheImpl.getInstance();
     if (internalCache == null) {
diff --git 
a/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalLocatorTest.java
 
b/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalLocatorTest.java
index fd678c805e..d7b59d20ea 100644
--- 
a/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalLocatorTest.java
+++ 
b/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalLocatorTest.java
@@ -15,6 +15,7 @@
 
 package org.apache.geode.distributed.internal;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doThrow;
@@ -33,9 +34,11 @@ import org.junit.Test;
 
 import org.apache.geode.cache.RegionShortcut;
 import org.apache.geode.cache.internal.HttpService;
+import org.apache.geode.distributed.internal.tcpserver.HostAddress;
 import org.apache.geode.internal.AvailablePortHelper;
 import org.apache.geode.internal.cache.InternalCacheForClientAccess;
 import org.apache.geode.internal.cache.InternalRegionFactory;
+import org.apache.geode.internal.inet.LocalHostUtil;
 import org.apache.geode.internal.security.SecurableCommunicationChannel;
 import org.apache.geode.logging.internal.LoggingSession;
 import org.apache.geode.management.internal.AgentUtil;
@@ -67,6 +70,8 @@ public class InternalLocatorTest {
     when(distributionConfig.getSecurableCommunicationChannels())
         .thenReturn(new SecurableCommunicationChannel[] {});
     
when(distributionConfig.getSecurityAuthTokenEnabledComponents()).thenReturn(new 
String[] {});
+    when(distributionConfig.getSSLProtocols()).thenReturn("any");
+    when(distributionConfig.getClusterSSLProtocols()).thenReturn("any");
     
when(cache.createInternalRegionFactory(RegionShortcut.REPLICATE)).thenReturn(regionFactory);
     when(cache.getOptionalService(HttpService.class))
         .thenReturn(Optional.of(httpService));
@@ -133,4 +138,52 @@ public class InternalLocatorTest {
     verify(httpService, never()).addWebApplication(eq("/management"), any(), 
any());
   }
 
+  @Test
+  public void getHostAddress() throws Exception {
+    // use localhost if no bindAddress
+    HostAddress locator = internalLocator.getHostAddress(null);
+    assertThat(locator.getAddress()).isEqualTo(LocalHostUtil.getLocalHost());
+
+    // use bindAddress name
+    HostAddress bindAddress = new HostAddress("test");
+    locator = internalLocator.getHostAddress(bindAddress);
+    assertThat(locator).isEqualTo(bindAddress);
+  }
+
+  @Test
+  public void addLocatorToBlankConfig() throws Exception {
+    String localHostname = LocalHostUtil.getCanonicalLocalHostName();
+    HostAddress localhost = new HostAddress(LocalHostUtil.getLocalHost());
+    String locator = internalLocator.addLocatorIfMissing(null, localhost, 
1234);
+    assertThat(locator).isEqualTo(localHostname + "[1234]");
+  }
+
+  @Test
+  public void configurePeerLocatorWithNoMatchLocatorList() throws Exception {
+    String localHostname = LocalHostUtil.getCanonicalLocalHostName();
+    HostAddress localhost = new HostAddress(LocalHostUtil.getLocalHost());
+    String existing = "10.10.10.10[12345]";
+    String locator = internalLocator.addLocatorIfMissing(existing, localhost, 
1234);
+    assertThat(locator).isEqualTo(existing + "," + localHostname + "[1234]");
+  }
+
+  @Test
+  public void configurePeerLocatorWithMatchingLocatorList() throws Exception {
+    HostAddress localhost = new HostAddress(LocalHostUtil.getLocalHost());
+    String localAddress = LocalHostUtil.getLocalHost().getHostAddress();
+    String existing = localAddress + "[12345]";
+    String locator = internalLocator.addLocatorIfMissing(existing, localhost, 
12345);
+    // what's returned is what's specified in the original configuration
+    assertThat(locator).isEqualTo(existing);
+  }
+
+  @Test
+  public void configurePeerLocatorWithMatchingAddressButNoMatchingPort() 
throws Exception {
+    HostAddress localhost = new HostAddress(LocalHostUtil.getLocalHost());
+    String localAddress = LocalHostUtil.getLocalHost().getHostAddress();
+    String existing = localAddress + "[11110]";
+    String locator = internalLocator.addLocatorIfMissing(existing, localhost, 
12345);
+    // what's returned is what's specified in the original configuration
+    assertThat(locator).isEqualTo(existing + "," + localhost.getHostName() + 
"[12345]");
+  }
 }
diff --git 
a/geode-membership/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/GMSUtilTest.java
 
b/geode-membership/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/LocatorConfigurationParserTest.java
similarity index 97%
rename from 
geode-membership/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/GMSUtilTest.java
rename to 
geode-membership/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/LocatorConfigurationParserTest.java
index d927c21ac2..90fa55caa6 100644
--- 
a/geode-membership/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/GMSUtilTest.java
+++ 
b/geode-membership/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/LocatorConfigurationParserTest.java
@@ -1,4 +1,5 @@
 /*
+ *
  * 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
@@ -11,11 +12,12 @@
  * 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.distributed.internal.membership.gms;
 
-import static 
org.apache.geode.distributed.internal.membership.gms.GMSUtil.parseLocators;
+import static 
org.apache.geode.distributed.internal.membership.api.LocatorConfigurationParser.parseLocators;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
@@ -31,7 +33,7 @@ import 
org.apache.geode.distributed.internal.tcpserver.HostAndPort;
 import org.apache.geode.test.junit.runners.GeodeParamsRunner;
 
 @RunWith(GeodeParamsRunner.class)
-public class GMSUtilTest {
+public class LocatorConfigurationParserTest {
 
   static final int PORT = 1234; // any old port--no need to have anything 
actually bound here
 
diff --git 
a/geode-membership/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeaveJUnitTest.java
 
b/geode-membership/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeaveJUnitTest.java
index 55318cd3af..94fe9cb0fb 100644
--- 
a/geode-membership/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeaveJUnitTest.java
+++ 
b/geode-membership/src/integrationTest/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeaveJUnitTest.java
@@ -57,6 +57,7 @@ import org.mockito.internal.verification.Times;
 import org.mockito.verification.Timeout;
 
 import org.apache.geode.distributed.internal.membership.api.Authenticator;
+import 
org.apache.geode.distributed.internal.membership.api.LocatorConfigurationParser;
 import org.apache.geode.distributed.internal.membership.api.MemberDataBuilder;
 import org.apache.geode.distributed.internal.membership.api.MemberIdentifier;
 import 
org.apache.geode.distributed.internal.membership.api.MemberIdentifierFactoryImpl;
@@ -64,7 +65,6 @@ import 
org.apache.geode.distributed.internal.membership.api.MemberStartupExcepti
 import org.apache.geode.distributed.internal.membership.api.MembershipConfig;
 import 
org.apache.geode.distributed.internal.membership.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
-import org.apache.geode.distributed.internal.membership.gms.GMSUtil;
 import 
org.apache.geode.distributed.internal.membership.gms.MemberIdentifierImpl;
 import org.apache.geode.distributed.internal.membership.gms.Services;
 import org.apache.geode.distributed.internal.membership.gms.Services.Stopper;
@@ -443,7 +443,7 @@ public class GMSJoinLeaveJUnitTest {
 
   @Test
   public void multipleLocatorsWithSameAddressAreCanonicalized() throws 
Exception {
-    List<HostAndPort> locators = GMSUtil.parseLocators(
+    List<HostAndPort> locators = LocatorConfigurationParser.parseLocators(
         "localhost[1234],localhost[1234],localhost[1234]", (InetAddress) null);
     assertThat(locators.size()).isEqualTo(1);
   }
diff --git 
a/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/api/LocatorConfigurationParser.java
 
b/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/api/LocatorConfigurationParser.java
new file mode 100644
index 0000000000..609d0a5698
--- /dev/null
+++ 
b/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/api/LocatorConfigurationParser.java
@@ -0,0 +1,142 @@
+/*
+ *
+ * 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.distributed.internal.membership.api;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.apache.geode.distributed.internal.tcpserver.HostAndPort;
+import org.apache.geode.internal.inet.LocalHostUtil;
+
+public class LocatorConfigurationParser {
+  /**
+   * parse locators & check that the resulting address is compatible with the 
given address
+   *
+   * @param locatorsString a DistributionConfig "locators" string
+   * @param bindAddress optional address to check for loopback compatibility
+   * @return addresses of locators
+   */
+  public static List<HostAndPort> parseLocators(String locatorsString, String 
bindAddress)
+      throws MembershipConfigurationException {
+    InetAddress addr = null;
+
+    try {
+      if (bindAddress == null || bindAddress.trim().length() == 0) {
+        addr = LocalHostUtil.getLocalHost();
+      } else {
+        addr = InetAddress.getByName(bindAddress);
+      }
+    } catch (UnknownHostException e) {
+      // ignore
+    }
+    return parseLocators(locatorsString, addr);
+  }
+
+  /**
+   * parse locators & check that the resulting address is compatible with the 
given address
+   *
+   * @param locatorsString a DistributionConfig "locators" string
+   * @param bindAddress optional address to check for loopback compatibility
+   * @return addresses of locators
+   */
+  public static List<HostAndPort> parseLocators(String locatorsString, 
InetAddress bindAddress)
+      throws MembershipConfigurationException {
+    List<HostAndPort> result = new ArrayList<>(2);
+    Set<InetSocketAddress> inetAddresses = new HashSet<>();
+    final boolean isLoopback = ((bindAddress != null) && 
bindAddress.isLoopbackAddress());
+
+    StringTokenizer parts = new StringTokenizer(locatorsString, ",");
+    while (parts.hasMoreTokens()) {
+      String str = parts.nextToken();
+
+      HostAndPort hostAndPort = parseLocator(str);
+      String host = hostAndPort.getHostName();
+      final InetSocketAddress isa = new InetSocketAddress(host, 
hostAndPort.getPort());
+
+      if (isLoopback) {
+        final InetAddress locatorAddress = isa.getAddress();
+        if (locatorAddress == null) {
+          throw new MembershipConfigurationException("This process is 
attempting to use a locator" +
+              " at an unknown address or FQDN: " + host);
+        }
+
+        if (!locatorAddress.isLoopbackAddress()) {
+          throw new MembershipConfigurationException(
+              "This process is attempting to join with a loopback address (" + 
bindAddress
+                  + ") using a locator that does not have a local address (" + 
isa
+                  + ").  On Unix this usually means that /etc/hosts is 
misconfigured.");
+        }
+      }
+      if (!inetAddresses.contains(isa)) {
+        inetAddresses.add(isa);
+        result.add(hostAndPort);
+      }
+    }
+
+    return result;
+  }
+
+  public static HostAndPort parseLocator(String locatorHostAndPort)
+      throws MembershipConfigurationException {
+    final int portSpecificationStart = locatorHostAndPort.indexOf('[');
+
+    if (portSpecificationStart == -1) {
+      throw createBadPortException(locatorHostAndPort);
+    }
+
+    String host = locatorHostAndPort.substring(0, portSpecificationStart);
+
+    int idx = host.lastIndexOf('@');
+    if (idx < 0) {
+      idx = host.lastIndexOf(':');
+    }
+    String start = host.substring(0, idx > -1 ? idx : host.length());
+    if (start.indexOf(':') >= 0) { // a single numeric ipv6 address
+      idx = host.lastIndexOf('@');
+    }
+    if (idx >= 0) {
+      host = host.substring(idx + 1);
+    }
+
+    int startIdx = portSpecificationStart + 1;
+    int endIdx = locatorHostAndPort.indexOf(']');
+
+    if (endIdx == -1) {
+      throw createBadPortException(locatorHostAndPort);
+    }
+
+    final int port;
+    try {
+      port = Integer.parseInt(locatorHostAndPort.substring(startIdx, endIdx));
+    } catch (NumberFormatException e) {
+      throw createBadPortException(locatorHostAndPort);
+    }
+    return new HostAndPort(host, port);
+  }
+
+  private static MembershipConfigurationException createBadPortException(final 
String str) {
+    return new MembershipConfigurationException("This process is attempting to 
use a locator" +
+        " with a malformed port specification: " + str);
+  }
+}
diff --git 
a/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSUtil.java
 
b/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSUtil.java
index f9e60e43b8..bea1f32ff2 100644
--- 
a/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSUtil.java
+++ 
b/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/GMSUtil.java
@@ -1,4 +1,5 @@
 /*
+ *
  * 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
@@ -11,15 +12,13 @@
  * 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.distributed.internal.membership.gms;
 
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -27,9 +26,6 @@ import java.util.Set;
 import java.util.StringTokenizer;
 
 import org.apache.geode.distributed.internal.membership.api.MemberIdentifier;
-import 
org.apache.geode.distributed.internal.membership.api.MembershipConfigurationException;
-import org.apache.geode.distributed.internal.tcpserver.HostAndPort;
-import org.apache.geode.internal.inet.LocalHostUtil;
 import org.apache.geode.internal.serialization.DeserializationContext;
 import org.apache.geode.internal.serialization.SerializationContext;
 import org.apache.geode.internal.serialization.StaticSerialization;
@@ -39,29 +35,6 @@ import 
org.apache.geode.internal.serialization.StaticSerialization;
  */
 public class GMSUtil {
 
-  /**
-   * parse locators & check that the resulting address is compatible with the 
given address
-   *
-   * @param locatorsString a DistributionConfig "locators" string
-   * @param bindAddress optional address to check for loopback compatibility
-   * @return addresses of locators
-   */
-  public static List<HostAndPort> parseLocators(String locatorsString, String 
bindAddress)
-      throws MembershipConfigurationException {
-    InetAddress addr = null;
-
-    try {
-      if (bindAddress == null || bindAddress.trim().length() == 0) {
-        addr = LocalHostUtil.getLocalHost();
-      } else {
-        addr = InetAddress.getByName(bindAddress);
-      }
-    } catch (UnknownHostException e) {
-      // ignore
-    }
-    return parseLocators(locatorsString, addr);
-  }
-
   public static <ID extends MemberIdentifier> Set<ID> 
readHashSetOfMemberIDs(DataInput in,
       DeserializationContext context)
       throws IOException, ClassNotFoundException {
@@ -77,92 +50,8 @@ public class GMSUtil {
   }
 
   /**
-   * parse locators & check that the resulting address is compatible with the 
given address
-   *
-   * @param locatorsString a DistributionConfig "locators" string
-   * @param bindAddress optional address to check for loopback compatibility
-   * @return addresses of locators
+   * Parses comma-separated-roles/groups into array of groups (strings).
    */
-  public static List<HostAndPort> parseLocators(String locatorsString, 
InetAddress bindAddress)
-      throws MembershipConfigurationException {
-    List<HostAndPort> result = new ArrayList<>(2);
-    Set<InetSocketAddress> inetAddresses = new HashSet<>();
-    String host;
-    final boolean isLoopback = ((bindAddress != null) && 
bindAddress.isLoopbackAddress());
-
-    StringTokenizer parts = new StringTokenizer(locatorsString, ",");
-    while (parts.hasMoreTokens()) {
-      String str = parts.nextToken();
-
-      final int portSpecificationStart = str.indexOf('[');
-
-      if (portSpecificationStart == -1) {
-        throw createBadPortException(str);
-      }
-
-      host = str.substring(0, portSpecificationStart);
-
-      int idx = host.lastIndexOf('@');
-      if (idx < 0) {
-        idx = host.lastIndexOf(':');
-      }
-      String start = host.substring(0, idx > -1 ? idx : host.length());
-      if (start.indexOf(':') >= 0) { // a single numeric ipv6 address
-        idx = host.lastIndexOf('@');
-      }
-      if (idx >= 0) {
-        host = host.substring(idx + 1);
-      }
-
-      int startIdx = portSpecificationStart + 1;
-      int endIdx = str.indexOf(']');
-
-      if (endIdx == -1) {
-        throw createBadPortException(str);
-      }
-
-      final int port;
-
-      try {
-        port = Integer.parseInt(str.substring(startIdx, endIdx));
-      } catch (NumberFormatException e) {
-        throw createBadPortException(str);
-      }
-
-      final InetSocketAddress isa = new InetSocketAddress(host, port);
-
-      if (isLoopback) {
-        final InetAddress locatorAddress = isa.getAddress();
-
-        if (locatorAddress == null) {
-          throw new MembershipConfigurationException("This process is 
attempting to use a locator" +
-              " at an unknown address or FQDN: " + host);
-        }
-
-        if (!locatorAddress.isLoopbackAddress()) {
-          throw new MembershipConfigurationException(
-              "This process is attempting to join with a loopback address (" + 
bindAddress
-                  + ") using a locator that does not have a local address (" + 
isa
-                  + ").  On Unix this usually means that /etc/hosts is 
misconfigured.");
-        }
-      }
-
-      HostAndPort hostAndPort = new HostAndPort(host, port);
-      if (!inetAddresses.contains(isa)) {
-        inetAddresses.add(isa);
-        result.add(hostAndPort);
-      }
-    }
-
-    return result;
-  }
-
-  private static MembershipConfigurationException createBadPortException(final 
String str) {
-    return new MembershipConfigurationException("This process is attempting to 
use a locator" +
-        " with a malformed port specification: " + str);
-  }
-
-  /** Parses comma-separated-roles/groups into array of groups (strings). */
   public static String[] parseGroups(String csvRoles, String csvGroups) {
     List<String> groups = new ArrayList<>();
     parseCsv(groups, csvRoles);
diff --git 
a/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocator.java
 
b/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocator.java
index 821891a1ca..cd5b18955b 100644
--- 
a/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocator.java
+++ 
b/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/locator/GMSLocator.java
@@ -36,11 +36,11 @@ import java.util.concurrent.ConcurrentHashMap;
 import org.apache.logging.log4j.Logger;
 
 import org.apache.geode.annotations.VisibleForTesting;
+import 
org.apache.geode.distributed.internal.membership.api.LocatorConfigurationParser;
 import org.apache.geode.distributed.internal.membership.api.MemberIdentifier;
 import 
org.apache.geode.distributed.internal.membership.api.MembershipConfigurationException;
 import 
org.apache.geode.distributed.internal.membership.api.MembershipLocatorStatistics;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
-import org.apache.geode.distributed.internal.membership.gms.GMSUtil;
 import org.apache.geode.distributed.internal.membership.gms.Services;
 import org.apache.geode.distributed.internal.membership.gms.interfaces.Locator;
 import 
org.apache.geode.distributed.internal.membership.gms.messenger.GMSMemberWrapper;
@@ -121,7 +121,7 @@ public class GMSLocator<ID extends MemberIdentifier> 
implements Locator<ID>, Tcp
     if (this.locatorString == null || this.locatorString.isEmpty()) {
       locators = new ArrayList<>(0);
     } else {
-      locators = GMSUtil.parseLocators(locatorString,
+      locators = LocatorConfigurationParser.parseLocators(locatorString,
           bindAddress == null ? null : bindAddress.getAddress());
     }
     this.locatorStats = locatorStats;
diff --git 
a/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave.java
 
b/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave.java
index 31879f815d..48e5ed1447 100644
--- 
a/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave.java
+++ 
b/geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave.java
@@ -41,13 +41,13 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.Logger;
 
 import org.apache.geode.annotations.VisibleForTesting;
+import 
org.apache.geode.distributed.internal.membership.api.LocatorConfigurationParser;
 import org.apache.geode.distributed.internal.membership.api.MemberIdentifier;
 import 
org.apache.geode.distributed.internal.membership.api.MemberStartupException;
 import 
org.apache.geode.distributed.internal.membership.api.MembershipClosedException;
 import org.apache.geode.distributed.internal.membership.api.MembershipConfig;
 import 
org.apache.geode.distributed.internal.membership.api.MembershipConfigurationException;
 import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView;
-import org.apache.geode.distributed.internal.membership.gms.GMSUtil;
 import org.apache.geode.distributed.internal.membership.gms.Services;
 import 
org.apache.geode.distributed.internal.membership.gms.interfaces.JoinLeave;
 import 
org.apache.geode.distributed.internal.membership.gms.locator.FindCoordinatorRequest;
@@ -1912,7 +1912,7 @@ public class GMSJoinLeave<ID extends MemberIdentifier> 
implements JoinLeave<ID>
         config.isNetworkPartitionDetectionEnabled();
 
     String bindAddr = config.getBindAddress();
-    locators = GMSUtil.parseLocators(config.getLocators(), bindAddr);
+    locators = LocatorConfigurationParser.parseLocators(config.getLocators(), 
bindAddr);
     if (logger.isDebugEnabled()) {
       logger.debug("Parsed locators are {}", locators);
     }

Reply via email to