/**
  * Computes the Chronos job's state based on current success and error count.
  *
  * @param job the {@link Job}.
  * @return the {@link JobState}.
  */
 public static JobState getLastState(Job job) {
   // State = Fresh (success + error = 0), Success (success > 0), Failure (error > 0)
   // NOTE that Chronos increments the error only after all the retries has failed (x retries -> +1
   // error)
   if (job.getSuccessCount() > 0) {
     return JobState.SUCCESS;
   } else {
     if (job.getErrorCount() > 0) {
       return JobState.FAILURE;
     } else {
       return JobState.FRESH;
     }
   }
 }
  protected Job createJob(
      Map<String, NodeTemplate> nodes,
      String deploymentId,
      String nodeName,
      NodeTemplate nodeTemplate,
      Map<String, Resource> resources) {
    try {
      Job chronosJob = new Job();
      // Init job infos

      // Get the generated UUID for the node (in DB resource ?)
      // FIXME This is just for prototyping... Otherwise is madness!!
      Resource resourceJob = resources.get(nodeName);

      chronosJob.setName(resourceJob.getId());

      // TODO Validation
      chronosJob.setRetries(
          Integer.parseInt(
              (String)
                  toscaService.getNodePropertyValueByName(nodeTemplate, "retries").getValue()));

      chronosJob.setCommand(
          (String) toscaService.getNodePropertyValueByName(nodeTemplate, "command").getValue());

      // TODO Enable epsilon setting in TOSCA tplt ?
      chronosJob.setEpsilon("PT10S");

      ListPropertyValue inputUris =
          (ListPropertyValue) toscaService.getNodePropertyValueByName(nodeTemplate, "uris");
      if (inputUris != null && !inputUris.getValue().isEmpty()) {
        // Convert List<Object> to List<String>
        chronosJob.setUris(
            inputUris
                .getValue()
                .stream()
                .map(e -> ((PropertyValue<?>) e).getValue().toString())
                .collect(Collectors.toList()));
      }

      List<EnvironmentVariable> envs = new ArrayList<>();
      ComplexPropertyValue inputEnvVars =
          ((ComplexPropertyValue)
              toscaService.getNodePropertyValueByName(nodeTemplate, "environment_variables"));
      if (inputEnvVars != null) {
        for (Map.Entry<String, Object> var : inputEnvVars.getValue().entrySet()) {
          EnvironmentVariable envVar = new EnvironmentVariable();
          envVar.setName(var.getKey());
          envVar.setValue(((PropertyValue<?>) var.getValue()).getValue().toString());
          envs.add(envVar);
        }
        chronosJob.setEnvironmentVariables(envs);
      }

      // Docker image
      // TODO Remove hard-coded?
      String supportedType = "tosca.artifacts.Deployment.Image.Container.Docker";
      DeploymentArtifact image;
      // <image> artifact available
      if (nodeTemplate.getArtifacts() == null
          || (image = nodeTemplate.getArtifacts().get("image")) == null) {
        throw new IllegalArgumentException(
            String.format(
                "<image> artifact not found in node <%s> of type <%s>",
                nodeName, nodeTemplate.getType()));
      }

      // <image> artifact type check
      if (!image.getArtifactType().equals(supportedType)) {
        throw new IllegalArgumentException(
            String.format(
                "Unsupported artifact type for <image> artifact in node <%s> of type <%s>. "
                    + "Given <%s>, supported <%s>",
                nodeName,
                nodeTemplate.getType(),
                nodeTemplate.getArtifacts().get("image").getArtifactType(),
                supportedType));
      }

      // Requirements

      // Get Docker host dependency
      String dockerCapabilityName = "host";
      Map<String, NodeTemplate> dockerRelationships =
          toscaService.getAssociatedNodesByCapability(nodes, nodeTemplate, dockerCapabilityName);
      Double dockerNumCpus = null;
      Double dockerMemSize = null;
      if (!dockerRelationships.isEmpty()) {
        /*
         * WARNING: The TOSCA validation should already check the limits (currently Alien4Cloud does
         * not...)
         */
        NodeTemplate dockerNode = dockerRelationships.values().iterator().next();
        Capability dockerCapability = dockerNode.getCapabilities().get(dockerCapabilityName);
        dockerNumCpus =
            Double.parseDouble(
                (String)
                    toscaService
                        .getCapabilityPropertyValueByName(dockerCapability, "num_cpus")
                        .getValue());

        // Converting Memory Size (as TOSCA scalar-unit.size)
        SizeType tmp = new SizeType();
        String memSizeRaw =
            (String)
                toscaService
                    .getCapabilityPropertyValueByName(dockerCapability, "mem_size")
                    .getValue();
        dockerMemSize = tmp.parse(memSizeRaw).convert("MB"); // Chronos wants MB
      }

      Container container = new Container();
      container.setType("DOCKER");

      // Run the container in Privileged Mode
      Parameters param = new Parameters();
      param.setKey("privileged");
      param.setValue("true");
      Collection<Parameters> parameters = new ArrayList<Parameters>();
      parameters.add(param);
      container.setParameters(parameters);

      // FIXME ForcePullImage must be parametrizable by tosca template
      container.setForcePullImage(true);
      ////////////////////////////////////////////////////////////////

      container.setImage(
          (String)
              ((PropertyValue<?>) nodeTemplate.getArtifacts().get("image").getFile()).getValue());
      if (dockerNumCpus != null) {
        chronosJob.setCpus(dockerNumCpus);
      }
      if (dockerMemSize != null) {
        chronosJob.setMem(dockerMemSize);
      }

      chronosJob.setContainer(container);

      return chronosJob;
    } catch (Exception ex) {
      throw new RuntimeException(
          String.format(
              "Failed to parse node <%s> of type <%s>: %s",
              nodeName, nodeTemplate.getType(), ex.getMessage()),
          ex);
    }
  }
 @Override
 public String toString() {
   return "IndigoJob [toscaNodeName=" + toscaNodeName + ", chronosJob=" + chronosJob.getName();
 }