private ProductInstance createProductInstance(
      ProductRelease productRelease, VM vm, String vdc, List<Attribute> attributes)
      throws InvalidEntityException, AlreadyExistsEntityException {

    ProductInstance instance = new ProductInstance();

    Product product = null;
    try {
      product = productDao.load(productRelease.getProduct().getName());
    } catch (EntityNotFoundException e) {
      product =
          new Product(
              productRelease.getProduct().getName(), productRelease.getProduct().getDescription());
    }
    product.setAttributes(attributes);

    productRelease.setProduct(product);

    instance.setProductRelease(productRelease);
    instance.setVm(vm);
    instance.setVdc(vdc);
    instance.setStatus(Status.UNINSTALLED);
    instance.setName(
        vm.getFqn()
            + "_"
            + productRelease.getProduct().getName()
            + "_"
            + productRelease.getVersion());

    instance = productInstanceDao.create(instance);
    return instance;
  }
  /**
   * Tell Chef the previously assigned recipes are ready to be installed.
   *
   * @param osInstance
   * @throws
   * @throws ShellCommandException
   */
  public void isRecipeExecuted(VM vm, String process, String recipe, String token)
      throws NodeExecutionException {
    boolean isExecuted = false;
    int time = 5000;
    Date fechaAhora = new Date();
    while (!isExecuted) {
      log.info("MAX_TIME: " + MAX_TIME + " and time: " + time);
      try {
        if (time > MAX_TIME) {
          String errorMesg =
              "Recipe " + process + " coub not be executed in " + vm.getChefClientName();
          log.info(errorMesg);
          // unassignRecipes(vm, recipe, token);
          throw new NodeExecutionException(errorMesg);
        }

        Thread.sleep(time);

        ChefNode node = chefNodeDao.loadNodeFromHostname(vm.getHostname(), token);

        long last_recipeexecution_timestamp = getLastRecipeExecutionTimeStamp(node);
        log.info(
            "last_recipeexecution_timestamp:"
                + last_recipeexecution_timestamp
                + "fechaAhora:"
                + fechaAhora.getTime());
        if (last_recipeexecution_timestamp > fechaAhora.getTime()) {
          // if (isRecipeExecutedOK(process, node))
          isExecuted = true;
          /*else{
              String message =" Recipe Execution failed";
              unassignRecipes(vm, recipe);
              throw new NodeExecutionException( new ChefRecipeExecutionException(message));
          }*/
        }
        time += time;
      } catch (EntityNotFoundException e) {
        throw new NodeExecutionException(e);
      } catch (CanNotCallChefException e) {
        throw new NodeExecutionException(e);
      } catch (InterruptedException ie) {
        throw new NodeExecutionException(ie);
      } /*catch (InstallatorException ie2){
            throw new NodeExecutionException(ie2);
        }*/
    }
  }
 public ProductInstance load(VM vm, ProductRelease productRelease, String vdc)
     throws EntityNotFoundException {
   ProductInstance instance =
       productInstanceDao.load(
           vm.getFqn()
               + "_"
               + productRelease.getProduct().getName()
               + "_"
               + productRelease.getVersion());
   if (!instance.getVdc().equals(vdc)) {
     throw new EntityNotFoundException(ProductInstance.class, "vdc", vdc);
   }
   return instance;
 }
  public void callService(
      ProductInstance productInstance,
      VM vm,
      List<Attribute> attributes,
      String action,
      String token)
      throws InstallatorException, NodeExecutionException {

    String process = productInstance.getProductRelease().getProduct().getName();

    String recipe = "";

    if ("install".equals(action)) {
      recipe = recipeNamingGenerator.getInstallRecipe(productInstance);
    } else if ("uninstall".equals(action)) {
      recipe = recipeNamingGenerator.getUninstallRecipe(productInstance);
    } else if ("configure".equals(action)) {
      recipe = recipeNamingGenerator.getConfigureRecipe(productInstance);
    } else if ("deployArtifact".equals(action)) {
      recipe = recipeNamingGenerator.getDeployArtifactRecipe(productInstance);
    } else if ("undeployArtifact".equals(action)) {
      recipe = recipeNamingGenerator.getUnDeployArtifactRecipe(productInstance);
    } else {
      throw new InstallatorException("Missing Action");
    }

    configureNode(vm, attributes, process, recipe, token);
    try {
      log.info("Updating node with recipe " + recipe + " in " + vm.getIp());
      if (isSdcClientInstalled()) {
        executeRecipes(vm);
        // unassignRecipes(vm, recipe);
      } else {
        isRecipeExecuted(vm, process, recipe, token);
        //  unassignRecipes(vm, recipe);
        // eliminate the attribute

      }
    } catch (NodeExecutionException e) {
      // even if execution fails want to unassign the recipe
      throw new NodeExecutionException(e.getMessage());
    }
  }
  @Override
  public void validateInstalatorData(VM vm, String token)
      throws InvalidInstallProductRequestException, NodeExecutionException {
    if (isSdcClientInstalled()) {
      if (!vm.canWorkWithChef()) {
        sdcClientUtils.checkIfSdcNodeIsReady(vm.getIp());
        sdcClientUtils.setNodeCommands(vm);

        vm = ip2vm.getVm(vm.getIp(), vm.getFqn(), vm.getOsType());
        // Configure the node with the corresponding node commands
      }
    } else {
      if (!vm.canWorkWithInstallatorServer()) {
        String message =
            "The VM does not include the node hostname required to Install " + "software";
        throw new InvalidInstallProductRequestException(message);
      }
      isNodeRegistered(vm.getHostname(), token);
    }
  }
  @Override
  public ProductInstance install(
      VM vm, String vdc, ProductRelease productRelease, List<Attribute> attributes)
      throws NodeExecutionException, AlreadyInstalledException,
          InvalidInstallProductRequestException, EntityNotFoundException {

    // if (INSTALATOR_CHEF.equals(product.getMapMetadata().get("installator"))) {
    //
    // }else{
    //
    // }

    // Check that there is not another product installed
    ProductInstance instance = null;
    try {

      instance =
          productInstanceDao.load(
              vm.getFqn()
                  + "_"
                  + productRelease.getProduct().getName()
                  + "_"
                  + productRelease.getVersion());

      System.out.println("intance:" + instance.getStatus());

      if (instance.getStatus().equals(Status.INSTALLED)) {
        throw new AlreadyInstalledException(instance);
      } else if (!(instance.getStatus().equals(Status.UNINSTALLED))
          && !(instance.getStatus().equals(Status.ERROR)))
        throw new InvalidInstallProductRequestException(
            "Product "
                + productRelease.getProduct().getName()
                + " "
                + productRelease.getVersion()
                + " cannot be installed in the VM "
                + vm.getFqn()
                + " strage status:  "
                + instance.getStatus());
    } catch (EntityNotFoundException e) {
      try {
        instance = createProductInstance(productRelease, vm, vdc, attributes);
      } catch (Exception e2) {
        throw new InvalidInstallProductRequestException(
            "Product "
                + productRelease.getProduct().getName()
                + " "
                + productRelease.getVersion()
                + " cannot be installed in the VM "
                + vm.getFqn()
                + " error in creating the isntance:  "
                + e2.getMessage());
      }
    }

    Status previousStatus = null;

    try {
      // makes the validations
      // instance = getProductToInstall(product, vm, vdc, attributes);
      previousStatus = instance.getStatus();
      // now we have the productInstance so can validate the operation
      validator.validateInstall(instance);

      instance.setStatus(Status.INSTALLING);
      instance.setVm(vm);
      // Id for the ProductInstance
      instance = productInstanceDao.update(instance);

      Product product = productDao.load(productRelease.getProduct().getName());

      if (INSTALATOR_CHEF.equals(product.getMapMetadata().get("installator"))) {
        chefInstallator.validateInstalatorData(vm);
        chefInstallator.callService(instance, vm, attributes, INSTALL);
      } else {
        if (INSTALATOR_PUPPET.equals(product.getMapMetadata().get("installator"))) {
          puppetInstallator.validateInstalatorData(vm);
          puppetInstallator.callService(vm, vdc, productRelease, INSTALL);
        } else {
          chefInstallator.validateInstalatorData(vm);
          chefInstallator.callService(instance, vm, attributes, INSTALL);
        }
      }

      instance.setStatus(Status.INSTALLED);
      return productInstanceDao.update(instance);

    } catch (InstallatorException sce) {
      restoreInstance(previousStatus, instance);
      throw new SdcRuntimeException(sce);
    } catch (RuntimeException e) {
      // by default restore the previous state when a runtime is thrown
      restoreInstance(previousStatus, instance);
      throw new SdcRuntimeException(e);
    }
  }