@Override
    public String updateForClusterCreate(String propertyName,
                                         String origValue,
                                         Map<String, Map<String, String>> properties,
                                         ClusterTopology topology) {

      if (origValue == null) {
        LOG.info("Property {} is null, skipping search for host group placeholder", propertyName);
        return null;
      }

      HostGroups hostGroups = new HostGroups(topology, propertyName);

      //todo: getHostStrings (?)

      // replaces all %HOSTGROUP::name% references to host names in the value string one by one. The value string can contain
      // only one (typical) or multiple %HOSTGROUP references. If the same host group is referenced multiple times,
      // another host will be picked each time.
      // Assuming you have the following hostgroups and hosts:
      // - hostgroup1: [group1_host]
      // - hostgroup2: [group2_host]
      // - hostgroup3: [group3_host1, group3_host2, group3_host3]
      // the following replacements will be made:
      // - %HOSTGROUP::group1%:8080 --> grop1_host:8080
      // - %HOSTGROUP::group1%:8080,%HOSTGROUP::group2%:8080 --> group1_host:8080,group2_host:8080
      // - %HOSTGROUP::group3%:8080,%HOSTGROUP::group3%:8080,%HOSTGROUP::group3%:8080 -->
      //      group3_host1:8080,group3_host2:8080,group3_host3:8080 (maybe in different order)
      LinkedList<Pair<Pair<Integer, Integer>, String>> replacements = new LinkedList<>();
      for (Matcher m = HostGroup.HOSTGROUP_REGEX.matcher(origValue); m.find(); ) {
        String replacement = hostGroups.getHost(m.group(1));
        int from = m.start();
        int to = m.end();
        replacements.add(Pair.of(Pair.of(from, to), replacement));
      }
      StringBuilder newValue = new StringBuilder(origValue);
      // replace in descending order so indices remain valid
      for (Iterator<Pair<Pair<Integer, Integer>, String>> it = replacements.descendingIterator(); it.hasNext(); ) {
        Pair<Pair<Integer, Integer>, String> replacement = it.next();
        int from = replacement.getLeft().getLeft();
        int to = replacement.getLeft().getRight();
        String replacementValue = replacement.getRight();
        newValue.replace(from, to, replacementValue);
      }
      return newValue.toString();
    }
@return the default updater to apply on user defined (blueprint + cluster template, not stack defaults) properties
configuration properties that do not have a registered updater
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/BlueprintConfigurationProcessor.java