/**
   * Insert the ProductRelease in SDC.
   *
   * @param productReleaseDto
   * @throws AlreadyExistsProductReleaseException
   * @throws InvalidProductReleaseException
   * @return proudctRelease
   */
  public ProductRelease insert(String pName, ProductReleaseDto productReleaseDto)
      throws AlreadyExistsProductReleaseException, InvalidProductReleaseException {

    try {
      generalValidator.validateName(pName);
    } catch (InvalidNameException e) {
      throw new InvalidProductReleaseException(e.getMessage());
    }
    productReleaseDto.setProductName(pName);

    log.info(
        "Inserting a new product release in the software catalogue "
            + productReleaseDto.getProductName()
            + " "
            + productReleaseDto.getVersion()
            + " "
            + productReleaseDto.getProductDescription());
    Product product =
        new Product(productReleaseDto.getProductName(), productReleaseDto.getProductDescription());

    ProductRelease productRelease =
        new ProductRelease(
            productReleaseDto.getVersion(),
            productReleaseDto.getReleaseNotes(),
            product,
            productReleaseDto.getSupportedOS(),
            productReleaseDto.getTransitableReleases());

    log.info(productRelease.toString());
    return productReleaseManager.insert(productRelease);
  }
 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;
 }
  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;
  }
  @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);
    }
  }
  /**
   * {@inheritDoc}
   *
   * @throws InstallatorException
   */
  @Override
  public ProductInstance configure(ProductInstance productInstance, List<Attribute> configuration)
      throws NodeExecutionException, FSMViolationException, InstallatorException {
    System.out.println(
        "Configuring product instance " + productInstance.getName() + " " + configuration);
    Status previousStatus = productInstance.getStatus();
    try {
      validator.validateConfigure(productInstance);
      productInstance.setStatus(Status.CONFIGURING);
      productInstance = productInstanceDao.update(productInstance);

      System.out.println("Get VM");
      VM vm = productInstance.getVm();

      System.out.println(
          "Load product " + productInstance.getProductRelease().getProduct().getName());
      Product product = productDao.load(productInstance.getProductRelease().getProduct().getName());

      if (configuration != null) {
        for (int j = 0; j < configuration.size(); j++) {
          Attribute attribute = configuration.get(j);
          product.addAttribute(attribute);
        }
      }
      System.out.println(
          "Update product " + productInstance.getProductRelease().getProduct().getName());
      productDao.update(product);

      ProductRelease productRelease = productInstance.getProductRelease();
      productRelease.setProduct(product);

      if (INSTALATOR_PUPPET.equals(product.getMapMetadata().get("installator"))) {
        throw new InstallatorException("Product not configurable in Puppet");
      } else {
        chefInstallator.callService(
            productInstance, productInstance.getVm(), configuration, CONFIGURE);
      }

      /*
       * String recipe = recipeNamingGenerator .getInstallRecipe(productInstance); callChef(
       * productInstance.getProductRelease().getProduct().getName(), recipe, productInstance.getVm(),
       * configuration); String restoreRecipe = recipeNamingGenerator .getRestoreRecipe(productInstance);
       * callChef(restoreRecipe, vm);
       */

      productInstance.setProductRelease(productRelease);
      productInstance.setStatus(Status.INSTALLED);
      return productInstanceDao.update(productInstance);

    } catch (InstallatorException e) {
      restoreInstance(previousStatus, productInstance);
      throw new SdcRuntimeException(e);
    } catch (RuntimeException e) { // by runtime restore the previous state
      // restore the status
      restoreInstance(previousStatus, productInstance);
      throw new SdcRuntimeException(e);
    } catch (NodeExecutionException e) {
      restoreInstance(Status.ERROR, productInstance);
      throw e;
    } catch (EntityNotFoundException e) {
      throw new SdcRuntimeException(e);
    }
  }
  /**
   * Update the ProductRelease (productReleaseDto, cookbooks, installable).
   *
   * @param multipart
   * @throws ProductReleaseNotFoundException
   * @throws InvalidProductReleaseException
   * @throws InvalidProductReleaseException
   * @throws InvalidMultiPartRequestException
   * @return productRelease
   * @throws InvalidProductReleaseUpdateRequestException
   */
  public ProductRelease update(MultiPart multiPart)
      throws ProductReleaseNotFoundException, InvalidProductReleaseException,
          InvalidMultiPartRequestException, InvalidProductReleaseUpdateRequestException {

    ProductReleaseDto productReleaseDto =
        multiPart.getBodyParts().get(0).getEntityAs(ProductReleaseDto.class);
    log.log(
        Level.INFO,
        "ProductRelease "
            + productReleaseDto.getProductName()
            + " version "
            + productReleaseDto.getVersion());

    // TODO Validar el Objeto ProductReleaseDto en las validaciones
    Product product = new Product();
    ProductRelease productRelease = new ProductRelease();

    product.setName(productReleaseDto.getProductName());

    if (productReleaseDto.getProductDescription() != null) {
      product.setDescription(productReleaseDto.getProductDescription());
    }

    /*
     * if (productReleaseDto.getPrivateAttributes() != null) { for (int i =
     * 0; productReleaseDto.getPrivateAttributes().size() < 1; i++) {
     * product
     * .addAttribute(productReleaseDto.getPrivateAttributes().get(i)); } }
     */

    productRelease.setProduct(product);

    if (productReleaseDto.getVersion() != null) {
      productRelease.setVersion(productReleaseDto.getVersion());
    }

    // ReleaseNotes
    if (productReleaseDto.getReleaseNotes() != null) {
      productRelease.setReleaseNotes(productReleaseDto.getReleaseNotes());
    }

    // PrivateAttributes
    /*
     * if (productReleaseDto.getPrivateAttributes() != null) {
     * productRelease
     * .setPrivateAttributes(productReleaseDto.getPrivateAttributes()); }
     */

    // SupportedOS
    if (productReleaseDto.getSupportedOS() != null) {
      productRelease.setSupportedOOSS(productReleaseDto.getSupportedOS());
    }

    // TransitableRelease
    if (productReleaseDto.getTransitableReleases() != null) {
      productRelease.setTransitableReleases(productReleaseDto.getTransitableReleases());
    }

    ReleaseDto releaseDto =
        new ReleaseDto(
            productReleaseDto.getProductName(), productReleaseDto.getVersion(), "product");

    validator.validateUpdate(releaseDto, multiPart);

    File cookbook = null;
    File installable = null;

    try {
      cookbook =
          File.createTempFile(
              "cookbook-" + releaseDto.getName() + "-" + releaseDto.getVersion() + ".tar", ".tmp");
      cookbook =
          getFileFromBodyPartEntity(
              (BodyPartEntity) multiPart.getBodyParts().get(1).getEntity(), cookbook);
    } catch (IOException e) {
      throw new SdcRuntimeException(e);
    }

    try {
      installable =
          File.createTempFile(
              "installable-" + releaseDto.getName() + "-" + releaseDto.getVersion() + ".tar",
              ".tmp");

      installable =
          getFileFromBodyPartEntity(
              (BodyPartEntity) multiPart.getBodyParts().get(2).getEntity(), installable);
    } catch (IOException e) {
      throw new SdcRuntimeException(e);
    }

    return productReleaseManager.update(
        productRelease, cookbook, installable, getCredentials().getToken());
  }