private static Map<ProvisionStep, List<Predicate>> createComponentPredicates(
    ProvisionAction serviceAction,
    Map<String, Set<String>> hostsByComponent,
    Map<String, Map<ProvisionAction, Set<String>>> customActionByComponent
  ) {
    Map<ProvisionStep, List<Predicate>> componentPredicatesByStep = new EnumMap<>(ProvisionStep.class);

    for (Map.Entry<String, Set<String>> componentEntry : hostsByComponent.entrySet()) {
      String componentName = componentEntry.getKey();
      Set<String> allHosts = componentEntry.getValue();
      Map<ProvisionAction, Set<String>> hostsByAction = customActionByComponent.getOrDefault(componentName, ImmutableMap.of());

      if (!hostsByAction.isEmpty()) {
        Set<String> customActionHosts = new HashSet<>();
        for (Map.Entry<ProvisionAction, Set<String>> e : hostsByAction.entrySet()) {
          ProvisionAction componentAction = e.getKey();
          Set<String> hosts = e.getValue();

          Predicate componentPredicate = predicateForComponentHosts(componentName, hosts);
          classifyItem(componentAction, componentPredicate, componentPredicatesByStep);

          customActionHosts.addAll(hosts);
        }

        // apply service-level action to any hosts for which no explicit action was specified
        Set<String> leftoverHosts = ImmutableSet.copyOf(Sets.difference(allHosts, customActionHosts));
        if (!leftoverHosts.isEmpty()) {
          Predicate componentPredicate = predicateForComponentHosts(componentName, leftoverHosts);
          classifyItem(serviceAction, componentPredicate, componentPredicatesByStep);
        }
      } else {
        Predicate componentPredicate = componentNameIs(componentName);
        classifyItem(serviceAction, componentPredicate, componentPredicatesByStep);
      }
    }
    return componentPredicatesByStep;
  }
Creates predicates for each component with custom action (one that does not match its parent service's action).

@param serviceAction service-level action
@param hostsByComponent component -> hosts map (all hosts, including ones for which no custom action was specified)
@param customActionByComponent component -> action -> hosts mapping;
  only contains components whose action does not match the upper-level (service or request) action
@return step -> component predicates map
ambari-server/src/main/java/org/apache/ambari/server/topology/addservice/ProvisionActionPredicateBuilder.java