private void getContainerTemplates(final State currentState, Collection<String> documentLinks) {

    OperationJoin.create(
            documentLinks.stream().map(documentLink -> Operation.createGet(this, documentLink)))
        .setCompletion(
            (ops, exs) -> {
              if (null != exs && !exs.isEmpty()) {
                failTask(exs);
                return;
              }

              try {
                Set<String> containerTemplateServiceLinks =
                    ops.values()
                        .stream()
                        .map(
                            operation ->
                                operation.getBody(ContainerService.State.class)
                                    .containerTemplateServiceLink)
                        .collect(Collectors.toSet());
                loadNamesFromTemplates(currentState, containerTemplateServiceLinks);
              } catch (Throwable t) {
                failTask(t);
              }
            })
        .sendWith(this);
  }
  private void processStartedStage(
      final State currentState, final VmService.State vmState, final HostService.State hostState) {
    Operation imageGetOperation =
        HostUtils.getCloudStoreHelper(this).createGet(vmState.imageServiceLink);
    Operation vmFlavorGetOperation =
        HostUtils.getCloudStoreHelper(this).createGet(vmState.vmFlavorServiceLink);
    Operation diskFlavorGetOperation =
        HostUtils.getCloudStoreHelper(this).createGet(vmState.diskFlavorServiceLink);
    Operation projectGetOperation =
        HostUtils.getCloudStoreHelper(this).createGet(vmState.projectServiceLink);

    OperationJoin.create(
            Arrays.asList(
                imageGetOperation,
                projectGetOperation,
                vmFlavorGetOperation,
                diskFlavorGetOperation))
        .setCompletion(
            (ops, exs) -> {
              if (null != exs && !exs.isEmpty()) {
                failTask(exs);
                return;
              }

              try {
                ImageService.State imageState =
                    ops.get(imageGetOperation.getId()).getBody(ImageService.State.class);
                ProjectService.State projectState =
                    ops.get(projectGetOperation.getId()).getBody(ProjectService.State.class);
                FlavorService.State vmFlavorState =
                    ops.get(vmFlavorGetOperation.getId()).getBody(FlavorService.State.class);

                FlavorService.State diskFlavorState =
                    ops.get(diskFlavorGetOperation.getId()).getBody(FlavorService.State.class);

                processStartedStage(
                    currentState,
                    vmState,
                    hostState,
                    imageState,
                    projectState,
                    vmFlavorState,
                    diskFlavorState);

              } catch (Throwable t) {
                failTask(t);
              }
            })
        .sendWith(this);
  }
  private Runnable createImportTask(ImportOvfRequest req, Operation patch) {
    return () -> {
      URI ovfUri;

      HttpClient client = OvfRetriever.newInsecureClient();
      OvfRetriever retriever = new OvfRetriever(client);
      OvfParser parser = new OvfParser();

      Document doc;
      try {
        ovfUri = retriever.downloadIfOva(req.ovfUri);
        doc = parser.retrieveDescriptor(ovfUri);
      } catch (Exception e) {
        patch.fail(e);
        return;
      }

      CustomProperties.of(req.template).put(OvfParser.PROP_OVF_URI, ovfUri);

      if (!Objects.equals(ovfUri, req.ovfUri)) {
        // this is an ova archive, store original OVA uri
        CustomProperties.of(req.template).put(OvfParser.PROP_OVF_ARCHIVE_URI, req.ovfUri);
      }

      List<ComputeDescription> ovfDescriptions = parser.parse(doc, req.template);
      Stream<Operation> opStream =
          ovfDescriptions
              .stream()
              .map(
                  desc ->
                      Operation.createPost(getHost(), ComputeDescriptionService.FACTORY_LINK)
                          .setBodyNoCloning(desc));

      OperationJoin join =
          OperationJoin.create()
              .setOperations(opStream)
              .setCompletion(
                  (os, es) -> {
                    if (es != null && !es.isEmpty()) {
                      patch.fail(es.values().iterator().next());
                    } else {
                      patch.complete();
                    }
                  });

      join.sendWith(this);
    };
  }
  private void clearTransactions(
      Operation patch, String transactionId, Collection<Operation> clearTransactionRequests) {
    OperationJoin.create(clearTransactionRequests)
        .setCompletion(
            (ops, exs) -> {
              if (exs != null) {
                patch.fail(
                    new IllegalStateException(
                        String.format(
                            "Transaction %s failed to clear from some services", transactionId)));
                return;
              }

              patch.complete();
            })
        .sendWith(this);
  }
  /**
   * This method retrieves the names of the containers from the set of container templates and
   * generates the vm metadata.
   *
   * @param currentState Supplies the current state object.
   * @param templateLinks Supplies a set of container template links.
   */
  private void loadNamesFromTemplates(final State currentState, Set<String> templateLinks) {

    if (templateLinks.isEmpty()) {
      throw new DcpRuntimeException("Template links set is empty");
    }

    OperationJoin.create(
            templateLinks.stream().map(templateLink -> Operation.createGet(this, templateLink)))
        .setCompletion(
            (ops, exs) -> {
              if (null != exs && !exs.isEmpty()) {
                failTask(exs);
                return;
              }

              try {
                Map<String, String> metadata = new HashMap<>();
                ops.values()
                    .stream()
                    .forEach(
                        getOperation -> {
                          ContainerTemplateService.State containerTemplateState =
                              getOperation.getBody(ContainerTemplateService.State.class);
                          if (containerTemplateState.portBindings != null) {
                            for (Integer port : containerTemplateState.portBindings.keySet()) {
                              metadata.put(
                                  CONTAINERS_METADATA_PREFIX + port.toString(),
                                  containerTemplateState.name);
                            }
                          }
                        });

                getVmId(currentState, metadata);
              } catch (Throwable t) {
                failTask(t);
              }
            })
        .sendWith(this);
  }
  private void deleteServicesAndClearTransactions(
      Operation patch,
      String transactionId,
      Collection<Operation> deleteRequests,
      Collection<Operation> clearTransactionRequests) {
    OperationJoin.create(deleteRequests)
        .setCompletion(
            (ops, exs) -> {
              if (exs != null) {
                patch.fail(
                    new IllegalStateException(
                        String.format(
                            "Transaction %s failed to delete some services", transactionId)));
                return;
              }

              if (clearTransactionRequests != null && !clearTransactionRequests.isEmpty()) {
                clearTransactions(patch, transactionId, clearTransactionRequests);
              } else {
                patch.complete();
              }
            })
        .sendWith(this);
  }