public Set<String> getMissingDependencies(Cluster cluster, AmbariMetaInfo metaInfo)
      throws AmbariException {
    Set<String> missingDependencies = Sets.newTreeSet();

    String stackPackagesJson = cluster.getClusterProperty(
        ConfigHelper.CLUSTER_ENV_STACK_PACKAGES_PROPERTY, null);

    // quick exit
    if (StringUtils.isEmpty(stackPackagesJson)) {
      return missingDependencies;
    }

    // create a GSON builder which can deserialize the stack_packages.json
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(UpgradeDependencies.class, new UpgradeDependencyDeserializer());
    Gson gson = gsonBuilder.create();
    Type type = new TypeToken<Map<String, StackPackage>>(){}.getType();

    // a mapping of stack name to stack-select/conf-select/upgade-deps
    final Map<String, StackPackage> stackPackages;

    try {
      stackPackages = gson.fromJson(stackPackagesJson, type);
    } catch( Exception exception ) {
      LOG.warn("Unable to deserialize the stack packages JSON, assuming no service dependencies",
          exception);

      return missingDependencies;
    }

    StackId stackId = new StackId(release.stackId);
    StackPackage stackPackage = stackPackages.get(stackId.getStackName());
    if (null == stackPackage || null == stackPackage.upgradeDependencies) {
      return missingDependencies;
    }

    Map<String, List<String>> dependencies = stackPackage.upgradeDependencies.dependencies;

    if (null == dependencies || dependencies.isEmpty()) {
      return missingDependencies;
    }

    // the installed services in the cluster
    Map<String,Service> installedServices = cluster.getServices();

    ClusterVersionSummary clusterVersionSummary = getClusterSummary(cluster, metaInfo);
    Set<String> servicesInUpgrade = clusterVersionSummary.getAvailableServiceNames();
    Set<String> servicesInRepository = getAvailableServiceNames();

    for (String serviceInUpgrade : servicesInUpgrade) {
      List<String> servicesRequired = dependencies.get(serviceInUpgrade);
      if (null == servicesRequired) {
        continue;
      }

      for (String serviceRequired : servicesRequired) {
        if (!servicesInRepository.contains(serviceRequired) && installedServices.containsKey(serviceRequired)) {
          missingDependencies.add(serviceRequired);
        }
      }
    }

    // now that we have built the list of missing dependencies based solely on
    // the services participating in the upgrade, recursively see if any of
    // those services have dependencies as well
    missingDependencies = getRecursiveDependencies(missingDependencies, dependencies,
        servicesInUpgrade, installedServices.keySet());

    return missingDependencies;
  }
Gets information about services which cannot be upgraded because the
repository does not contain required dependencies. This method will look at
the {@code cluster-env/stack_packages} structure to see if there are any
dependencies listed in the {@code upgrade-dependencies} key.

@param cluster
         the cluster (not {@code null}).
@param metaInfo
         the metainfo instance
@return a mapping of service name to its missing service dependencies, or
        an empty map if there are none (never {@code null}).
@throws AmbariException
ambari-server/src/main/java/org/apache/ambari/server/state/repository/VersionDefinitionXml.java