private static Map<String, KerberosServiceDescriptor> processServices(Map<String, KerberosServiceDescriptor> previousStackServices,
                                                                        Map<String, KerberosServiceDescriptor> newStackServices,
                                                                        Map<String, KerberosServiceDescriptor> userServices) {
    if ((userServices == null) || userServices.isEmpty() || ((previousStackServices == null) && (newStackServices == null))) {
      return userServices;
    }

    Map<String, KerberosServiceDescriptor> updatedServices = new TreeMap<>();

    if (previousStackServices == null) {
      previousStackServices = Collections.emptyMap();
    }

    if (newStackServices == null) {
      newStackServices = Collections.emptyMap();
    }

    for (Map.Entry<String, KerberosServiceDescriptor> entry : userServices.entrySet()) {
      String name = entry.getKey();
      KerberosServiceDescriptor userValue = entry.getValue();

      if (userValue != null) {
        if (newStackServices.containsKey(name)) {
          KerberosServiceDescriptor oldValue = previousStackServices.get(name);
          KerberosServiceDescriptor newValue = newStackServices.get(name);

          LOG.debug("Processing service {} for modifications", name);
          updatedServices.put(name, processService(oldValue, newValue, userValue));
        } else if (previousStackServices.containsKey(name)) {
          LOG.debug("Removing service {} from user-specified Kerberos Descriptor", name);
          // Nothing to do here, just don't add it to the updated configurations map...
        } else {
          LOG.debug("Leaving service {} in user-specified Kerberos Descriptor unchanged since it was user-defined.", name);
          updatedServices.put(name, userValue);
        }
      }
    }

    // Note: there is no need to add service definitions that do not exist since they will get
    // added dynamically when merged with the stack default value.

    return updatedServices;
  }
Processes the service-level Kerberos descriptors to add, remove, or update data in the user-specified
Kerberos descriptor.

@param previousStackServices a map of {@link KerberosServiceDescriptor}s from the previous stack version's Kerberos descriptor
@param newStackServices      a map of {@link KerberosServiceDescriptor}s from the new stack version's Kerberos descriptor
@param userServices          a map of {@link KerberosServiceDescriptor}s from the user-supplied Kerberos descriptor
@return a map of updated {@link KerberosServiceDescriptor}s
ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorUpdateHelper.java