private Set<String> getServicesForPlatform(long manifestPlatformId) {
   List<CmsRfcRelation> rfcRelations =
       cmRfcMrgProcessor.getFromCIRelationsNaked(
           manifestPlatformId, MANIFEST_REQUIRES, null, null);
   return rfcRelations
       .stream()
       .filter(this::needServices)
       .flatMap(this::getServices)
       .collect(toSet());
 }
  @Override
  public long updateEnvClouds(long envId, List<CmsCIRelation> cloudRels, String userId) {
    // for now we will handle just new clouds
    List<CmsCIRelation> existingCloudRels =
        cmProcessor.getFromCIRelationsNaked(envId, BASE_CONSUMES, ACCOUNT_CLOUD);
    Set<Long> existingCloudIds = new HashSet<Long>();
    for (CmsCIRelation rel : existingCloudRels) {
      existingCloudIds.add(rel.getToCiId());
    }

    boolean needUpdate = false;
    for (CmsCIRelation requestRel : cloudRels) {
      if (!existingCloudIds.contains(requestRel.getToCiId())) {
        // this is new cloud lets add env->cloud rel
        cmProcessor.createRelation(requestRel);
        needUpdate = true;
      } else {
        cmProcessor.updateRelation(requestRel);
        existingCloudIds.remove(requestRel.getToCiId());
      }
    }
    if (!existingCloudIds.isEmpty()) {
      // looks like we need to delete some clouds
      // first lets see if we have any open releases
      processCloudDeletions(envId, existingCloudIds);
    }

    if (needUpdate) {
      CmsCI env = getEnv(envId);
      String nsPath = env.getNsPath() + "/" + env.getCiName() + "/manifest";
      List<CmsRfcRelation> compOfRels =
          cmRfcMrgProcessor.getFromCIRelations(
              envId, MANIFEST_COMPOSED_OF, MANIFEST_PLATFORM, "dj");
      for (CmsRfcRelation compOfRel : compOfRels) {
        CmsRfcCI platform = compOfRel.getToRfcCi();
        String platNs = platform.getNsPath();
        manifestRfcProcessor.processClouds(env, platform, platNs, nsPath, userId, null, null, null);
        Set<String> missingSrvs = cloudUtil.getMissingServices(platform.getCiId());
        if (missingSrvs.size() > 0) {
          logger.info(
              ">>>>> Not all services available for platform: "
                  + platform.getCiName()
                  + ", the missing services: "
                  + missingSrvs.toString());
          manifestRfcProcessor.disablePlatform(platform.getCiId(), userId);
        }
        logger.info("Done working on platform " + platform.getCiName());
      }
      return populateParentRelease(env, nsPath);
    } else {
      return 0;
    }
  }
  private long checkPlatformPackCompliance(
      List<CmsCIRelation> designPlatRels, CmsCI env, String nsPath, String userId) {

    List<CmsCIRelation> manifestPlatRels =
        cmProcessor.getFromCIRelations(
            env.getCiId(), MANIFEST_COMPOSED_OF, null, MANIFEST_PLATFORM);

    Map<String, String> manifestPlatPacks = new HashMap<String, String>(manifestPlatRels.size());
    for (CmsCIRelation manifestRel : manifestPlatRels) {
      CmsCI plat = manifestRel.getToCi();
      String key = plat.getCiName() + ":" + plat.getAttribute("major_version").getDjValue();
      String value =
          plat.getAttribute("source").getDjValue()
              + ":"
              + plat.getAttribute("pack").getDjValue()
              + ":"
              + plat.getAttribute("version").getDjValue();
      manifestPlatPacks.put(key, value);
    }

    long newReleaseId = 0;

    for (CmsCIRelation designRel : designPlatRels) {
      CmsCI dPlat = designRel.getToCi();
      String key = dPlat.getCiName() + ":" + dPlat.getAttribute("major_version").getDjValue();
      String value =
          dPlat.getAttribute("source").getDjValue()
              + ":"
              + dPlat.getAttribute("pack").getDjValue()
              + ":"
              + dPlat.getAttribute("version").getDjValue();
      if (manifestPlatPacks.containsKey(key) && !value.equals(manifestPlatPacks.get(key))) {
        String platNsPath =
            nsPath
                + "/"
                + dPlat.getCiName()
                + "/"
                + dPlat.getAttribute("major_version").getDfValue();
        List<CmsRfcCI> mPlats =
            cmRfcMrgProcessor.getDfDjCi(platNsPath, MANIFEST_PLATFORM, dPlat.getCiName(), "dj");
        if (mPlats.size() > 0) {
          newReleaseId = manifestRfcProcessor.deleteManifestPlatform(mPlats.get(0), userId);
        }
      }
    }
    return newReleaseId;
  }
 /**
  * This checks the cloud is configured with all services which are required for deployment of
  * platform .
  *
  * @param manifestPlatformId the id of platform for which services need to be found
  * @throws TransistorException if missing services are found.
  */
 public void check4missingServices(long manifestPlatformId) {
   // get all required components of platforms
   List<CmsRfcRelation> requiredRelations =
       cmRfcMrgProcessor.getFromCIRelationsNaked(
           manifestPlatformId, MANIFEST_REQUIRES, null, null);
   Set<String> requiredServices =
       requiredRelations
           .stream()
           .filter(this::needServices)
           .flatMap(this::getServices)
           .collect(toSet());
   Map<String, TreeSet<String>> cloudsMissingServices =
       getMissingCloudServices(manifestPlatformId, requiredServices);
   if (!cloudsMissingServices.isEmpty()) {
     // <{c1=[s1]}> mess
     String message =
         String.format(
             "All services <%s> required for platform (%s) are not configured for clouds.Please contact your org. admin .",
             cloudsMissingServices.toString(),
             withoutManifest(requiredRelations.get(0).getNsPath()));
     throw new TransistorException(TRANSISTOR_MISSING_CLOUD_SERVICES, message);
   }
 }
  private Map<String, TreeSet<String>> getMissingCloudServices(
      long manifestPlatCiId, Set<String> requiredServices) {
    Map<String, TreeSet<String>> missingCloud2Services = new TreeMap<>();
    // get clouds
    List<CmsRfcRelation> cloudRelations =
        cmRfcMrgProcessor.getFromCIRelations(
            manifestPlatCiId, BASE_CONSUMES, ACCOUNT_CLOUD_CLASS, "dj");
    // get services for all clouds
    cloudRelations.forEach(
        rel -> {
          Set<String> cloudServices =
              cmProcessor
                  .getFromCIRelationsNaked(rel.getToCiId(), BASE_PROVIDES, null)
                  .stream()
                  .filter(this::isService)
                  .map(cmsCIRelation -> cmsCIRelation.getAttribute("service").getDjValue())
                  .collect(Collectors.toSet());
          String cloud = rel.getToRfcCi().getCiName();

          // check if service is configured
          requiredServices
              .stream()
              .filter(s -> !cloudServices.contains(s))
              .forEach(
                  s -> missingCloud2Services.computeIfAbsent(cloud, k -> new TreeSet<>()).add(s));
          logger.debug(
              "cloud: "
                  + cloud
                  + " required services:: "
                  + requiredServices.toString()
                  + " missingServices "
                  + missingCloud2Services.keySet());
        });

    return missingCloud2Services;
  }
  /**
   * @param manifestPlatformRfcs
   * @param userId
   */
  private void processPlatformRfcs(ManifestRfcContainer manifestPlatformRfcs, String userId) {

    long t1 = System.currentTimeMillis();
    /** *** Handle root RFC and relations ***** */
    CmsRfcCI rootRfc = null;
    if (manifestPlatformRfcs.getRootRfcRelTouple().getRfcCI() != null) {
      rootRfc =
          rfcProcessor.createAndfetchRfcCINoCheck(
              manifestPlatformRfcs.getRootRfcRelTouple().getRfcCI(), userId);
      if (rootRfc.getCiState() == null) {
        rootRfc.setCiState("default");
      }
    } else {
      rootRfc = manifestPlatformRfcs.getManifestPlatformRfc();
    }

    for (CmsRfcRelation toRfcRelation :
        manifestPlatformRfcs.getRootRfcRelTouple().getToRfcRelation()) {
      toRfcRelation.setToCiId(rootRfc.getCiId());
      rfcProcessor.createRfcRelationNoCheck(toRfcRelation, userId);
    }

    for (CmsRfcRelation fromRfcRelation :
        manifestPlatformRfcs.getRootRfcRelTouple().getFromRfcRelation()) {
      fromRfcRelation.setFromCiId(rootRfc.getCiId());
      rfcProcessor.createRfcRelationNoCheck(fromRfcRelation, userId);
    }

    /** Handle DependsOn and other pack relations ** */
    for (ManifestRfcRelationTriplet rfcRelTriplet : manifestPlatformRfcs.getRfcRelTripletList()) {

      CmsRfcRelation rfcRelation = rfcRelTriplet.getRfcRelation();
      if (rfcRelation.getRfcAction() == null) {
        rfcRelation.setRfcAction("add");
      }

      CmsRfcCI toRfcCI = rfcRelTriplet.getToRfcCI();
      if (toRfcCI != null) {
        if (toRfcCI.getRfcAction() == null) {
          toRfcCI.setRfcAction("add");
        }
        manifestRfcProcessor.setCiId(toRfcCI);
        if (toRfcCI.getRfcId() == 0 && toRfcCI.getCiId() == 0) {
          toRfcCI = rfcProcessor.createAndfetchRfcCINoCheck(toRfcCI, userId);
        }
        rfcRelation.setToCiId(toRfcCI.getCiId());
      }

      CmsRfcCI fromRfcCI = rfcRelTriplet.getFromRfcCI();
      if (fromRfcCI != null) {
        if (fromRfcCI.getRfcAction() == null) {
          fromRfcCI.setRfcAction("add");
        }
        manifestRfcProcessor.setCiId(fromRfcCI);
        if (fromRfcCI.getRfcId() == 0 && fromRfcCI.getCiId() == 0) {
          fromRfcCI = rfcProcessor.createAndfetchRfcCINoCheck(fromRfcCI, userId);
        }
        rfcRelation.setFromCiId(fromRfcCI.getCiId());
      }

      if ("manifest.Entrypoint".equals(rfcRelation.getRelationName())) {
        rfcRelation.setFromCiId(rootRfc.getCiId());
      }

      manifestRfcProcessor.setCiRelationId(rfcRelation);
      rfcProcessor.createRfcRelationNoCheck(rfcRelation, userId);
    }

    /** Handle Requires relations ** */
    for (ManifestRootRfcContainer rfcRelTouple : manifestPlatformRfcs.getRfcRelToupleList()) {
      CmsRfcCI newRfc;
      if (rfcRelTouple.getRfcCI().getRfcId() == 0) {
        newRfc = rfcProcessor.createAndfetchRfcCINoCheck(rfcRelTouple.getRfcCI(), userId);
      } else {
        newRfc = rfcRelTouple.getRfcCI();
      }
      for (CmsRfcRelation rfcRel : rfcRelTouple.getToRfcRelation()) {
        if (rfcRel.getRfcAction() == null) {
          rfcRel.setRfcAction("add");
        }

        if ("manifest.Requires".equals(rfcRel.getRelationName()) && rfcRel.getFromCiId() == 0) {
          rfcRel.setFromCiId(rootRfc.getCiId());
        }
        rfcRel.setToCiId(newRfc.getCiId());
        rfcProcessor.createRfcRelationNoCheck(rfcRel, userId);
      }
      for (CmsRfcRelation rfcRel : rfcRelTouple.getFromRfcRelation()) {
        if (rfcRel.getRfcAction() == null) {
          rfcRel.setRfcAction("add");
        }

        if (rfcRel.getToCiId() == 0) {
          rfcRel.setToCiId(rootRfc.getCiId());
        }
        rfcRel.setFromCiId(newRfc.getCiId());
        rfcProcessor.createRfcRelationNoCheck(rfcRel, userId);
      }
    }

    for (CmsRfcCI rfc : manifestPlatformRfcs.getRfcList()) {
      rfcProcessor.createRfcCINoCheck(rfc, userId);
    }

    for (CmsRfcRelation rfcRelation : manifestPlatformRfcs.getRfcRelationList()) {
      if (rfcRelation.getFromCiId() == 0) {
        if ("base.Consumes".equals(rfcRelation.getRelationName())) {
          rfcRelation.setFromCiId(rootRfc.getCiId());
        } else {
          rfcRelation.setFromCiId(rootRfc.getCiId());
        }
      }
      if (rfcRelation.getRfcAction() == null) {
        rfcRelation.setRfcAction("add");
      }

      rfcProcessor.createRfcRelationNoCheck(rfcRelation, userId);
    }

    for (Long delCiId : manifestPlatformRfcs.getDeleteCiIdList()) {
      cmRfcMrgProcessor.requestCiDeleteCascadeNoRelsRfcs(delCiId, userId, 0);
    }

    for (CmsRfcRelation delRelation : manifestPlatformRfcs.getRfcDeleteRelationList()) {
      cmRfcMrgProcessor.requestRelationDelete(delRelation.getCiRelationId(), userId);
    }
    long t2 = System.currentTimeMillis();
    logger.info(
        " processPlatformRfcs  "
            + manifestPlatformRfcs.getManifestPlatformRfc().getNsPath()
            + " completed in  "
            + (t2 - t1));
  }