docs: public static boolean parseProviderEndpoints(String providerEndpoints,
        List<ProviderEndPoint> listOfEndPoints, boolean whenDefaultingUseSecurePort)
        throws IncorrectCallException {
  
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.entry(tc, "parseProviderEndpoints", new Object[]{ providerEndpoints, listOfEndPoints, whenDefaultingUseSecurePort });
  
      // Indicate whether the user specified their own endpoints,
      // or whether we made them up on their behalf.
      boolean hasUserDefinedEndPoints = false;
  
      if (providerEndpoints != null && providerEndpoints.trim().equals("")) {
        providerEndpoints = null;
      }
  
      // If there are any endpoints defined by the client.
      if (providerEndpoints != null) {
  
        // Split the full string based on the comma separator. We know that
        // the elements on the triplets (including IPv4/v6 IP addresses) do
        // not contain commas.
        // NB. IPv6 is RFC 2373)
        StringTokenizer st = new StringTokenizer(providerEndpoints,",");
  
        // Look at each of the elements in turn.
        while (st.hasMoreElements()) {
  
          // Prepare some variables to receive the parsed data.
          String host  = null;
          String port  = null;
          String chain = null;
  
          String str = st.nextToken();
          if (str != null) {
  
            // The user has given us some explicit endpoint information.
            hasUserDefinedEndPoints = true;
  
            // To hold the position of the opening brace if one exists.
            int openBracePos = 0;
  
            // Check for IPv6 bracing [ ... ]
            if ((openBracePos = str.indexOf("[")) != -1) {
              // We have found an IPv6 opening brace.
  
              // To hold the position of the closing brace if one exists.
              int closeBracePos = 0;
  
              if ((closeBracePos = str.indexOf("]")) != -1) {
                // Found the closing brace as well.
                host = str.substring(openBracePos+1, closeBracePos);
  
                // Remove the parsed data from the string.
                str = str.substring(closeBracePos+1);
  
              } else {
                // No closing brace to match the opening brace.
                throw new IncorrectCallException(str);
              } // if closing brace.
  
            } else {
              // No opening brace.
              // Check for an orphaned closing brace to be on the safe side.
              if (str.indexOf("]") != -1) {
                throw new IncorrectCallException(str);
              }
  
            } // if opening brace.
  
            // Take out any whitespace that might cause confusion.
            if (str.indexOf(" ") != -1)
            {
              // Doing a quick check for contains will avoid running the
              // regex on the following line in cases where there are no
              // spaces.
              str = str.replaceAll(" ", "");
            }
  
  
            // Tokenize the remaining information (some will have been removed above if there
            // was an IPv6 address) using the : character. Use the true flag so that we get
            // given the separators too.
            StringTokenizer st2 = new StringTokenizer(str, ":", true);
  
            // We are going to use this counter to determine which item of information
            // we are looking for.
            int elementSearch = 1;
  
            // If the host was in IPv6 form we will already have set it here, and the
            // str string will look like a ":port:chain" format. This missing host
            // is handled successfully by the block below anyway.
  
            while (st2.hasMoreTokens())
            {
              String next = st2.nextToken();
  
              // If we find a separator character then we start looking at the
              // next item (host/port etc)
              if (":".equals(next))
              {
                elementSearch++;
              } else
              {
  
                switch(elementSearch)
                {
                  case 1: // host
                    host = next;
                    break;
  
                  case 2: // port
                    port = next;
                    break;
  
                  case 3: // chain
                    // Allow for synonyms of the chain names to be used
                    chain = resolveSynonymousChainName(next);
                    break;
  
                  default: // bad formatting - ignore it!
                    break;
  
                }//switch
  
              }//if
  
            }//while
  
            // Default any missing values
            if (host == null || host.trim().equals("")) {
              host = PROVIDER_ENDPOINTS_LOCALHOST;
            }
  
            boolean usingDefaultPort = false;
  
            if (port == null || port.trim().equals("")) {
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(tc, "No port was specified");
  
              if (chain != null) {
                // A non-empty chain was specified. We should use this information to override
                // the defaulting of the port number if we recognise the chain name. This has
                // higher precedence than whether a password was specified because the user
                // gave us direct instructions.
                if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(tc, "A non-empty chain was specified");
                if (BOOTSTRAP_TRANSPORT_CHAIN_BASIC.equals(chain)) {
                  whenDefaultingUseSecurePort = false;
                } else if (BOOTSTRAP_TRANSPORT_CHAIN_SECURE.equals(chain)) {
                  whenDefaultingUseSecurePort = true;
                }
  
              } // if override port based on chain
  
              if (whenDefaultingUseSecurePort) {
                port = PROVIDER_ENDPOINTS_PORT_SECURE;
                if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(tc, "Password specified so defaulting to " + port);
              } else {
                port = PROVIDER_ENDPOINTS_PORT_BASIC;
                if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(tc, "No password specified so defaulting to " + port);
              } // if isPasswordSpecified
              usingDefaultPort = true;
            } // if port
  
            if (chain == null || chain.trim().equals("")) {
                chain = BOOTSTRAP_TRANSPORT_CHAIN_BASIC;
                if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(tc, "No chain specified so defaulting to " + chain);
            } // if chain
  
            ProviderEndPoint newEP = new ProviderEndPoint(host, new Integer(port), chain);
            if (!listOfEndPoints.contains(newEP)) {
              listOfEndPoints.add(newEP);
            }
  
          } // if element not null
  
        } // while more elements
  
      } // if providerEndpoints
  
      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(tc, listOfEndPoints.toString());
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.exit(tc, "parseProviderEndpoints", Boolean.valueOf(hasUserDefinedEndPoints));
      return hasUserDefinedEndPoints;
  
    }