private Map<String, Map<String, Collection<String>>> getRequiredPropertiesByService(Blueprint blueprint) {

    Map<String, Map<String, Collection<String>>> requiredPropertiesForServiceByType = new HashMap<>();

    for (String bpService : blueprint.getServices()) {
      LOGGER.debug("Collecting required properties for the service: {}", bpService);

      Collection<Stack.ConfigProperty> requiredConfigsForService = blueprint.getStack().getRequiredConfigurationProperties(bpService);
      Map<String, Collection<String>> requiredPropertiesByConfigType = new HashMap<>();

      for (Stack.ConfigProperty configProperty : requiredConfigsForService) {

        if (configProperty.getPropertyTypes() != null && configProperty.getPropertyTypes().contains(PropertyInfo.PropertyType.PASSWORD)) {
          LOGGER.debug("Skipping required property validation for password type: {}", configProperty.getName());
          // skip password types
          continue;
        }

        // add / get  service related required propeByType map
        if (requiredPropertiesForServiceByType.containsKey(bpService)) {
          requiredPropertiesByConfigType = requiredPropertiesForServiceByType.get(bpService);
        } else {
          LOGGER.debug("Adding required properties entry for service: {}", bpService);
          requiredPropertiesForServiceByType.put(bpService, requiredPropertiesByConfigType);
        }

        // add collection of required properties
        Collection<String> requiredPropsForType = new HashSet<>();
        if (requiredPropertiesByConfigType.containsKey(configProperty.getType())) {
          requiredPropsForType = requiredPropertiesByConfigType.get(configProperty.getType());
        } else {
          LOGGER.debug("Adding required properties entry for configuration type: {}", configProperty.getType());
          requiredPropertiesByConfigType.put(configProperty.getType(), requiredPropsForType);
        }

        requiredPropsForType.add(configProperty.getName());
        LOGGER.debug("Added required property for service; {}, configuration type: {}, property: {}", bpService,
          configProperty.getType(), configProperty.getName());
      }
    }

    LOGGER.info("Identified required properties for blueprint services: {}", requiredPropertiesForServiceByType);
    return requiredPropertiesForServiceByType;

  }
Collects required properties for services in the blueprint. Configuration properties are returned by configuration type.
service -> configType -> properties

@param blueprint the blueprint from the cluster topology
@return a map with configuration types mapped to collections of required property names
ambari-server/src/main/java/org/apache/ambari/server/topology/validators/RequiredConfigPropertiesValidator.java