/**
   * {@inheritDoc}
   *
   * @throws EntityNotFoundException
   */
  @UseCase(traceTo = "UC_001.4", status = "implemented")
  @Override
  public ProductInstance upgrade(ProductInstance productInstance, ProductRelease productRelease)
      throws NotTransitableException, NodeExecutionException, FSMViolationException,
          InstallatorException, EntityNotFoundException {
    Status previousStatus = productInstance.getStatus();
    try {
      validator.validateUpdate(productInstance, productRelease);
      // update the status
      productInstance.setStatus(Status.UPGRADING);
      productInstance = productInstanceDao.update(productInstance);
      productInstance.setProductRelease(productRelease);

      VM vm = productInstance.getVm();
      Product product = productDao.load(productInstance.getName());

      if (INSTALATOR_PUPPET.equals(product.getMapMetadata().get("installator"))) {
        throw new InstallatorException("Product not upgradeable in Puppet");
      } else {
        chefInstallator.upgrade(productInstance, vm);
      }

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

    } catch (RuntimeException e) { // by runtime restore the previous state
      // restore the status
      restoreInstance(previousStatus, productInstance);
      throw new SdcRuntimeException(e);
    }
  }
  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 void uninstall(ProductInstance productInstance)
      throws NodeExecutionException, FSMViolationException, EntityNotFoundException {
    Status previousStatus = productInstance.getStatus();
    try {
      validator.validateUninstall(productInstance);
      productInstance.setStatus(Status.UNINSTALLING);
      productInstance = productInstanceDao.update(productInstance);

      Product product = productDao.load(productInstance.getProductRelease().getProduct().getName());

      if (INSTALATOR_PUPPET.equals(product.getMapMetadata().get("installator"))) {
        puppetInstallator.callService(
            productInstance.getVm(),
            productInstance.getVdc(),
            productInstance.getProductRelease(),
            UNINSTALL);
      } else {
        chefInstallator.callService(productInstance, UNINSTALL);
      }

      productInstance.setStatus(Status.UNINSTALLED);
      productInstanceDao.update(productInstance);
    } catch (InstallatorException e) {
      restoreInstance(previousStatus, productInstance);
      throw new SdcRuntimeException(e);
    } catch (RuntimeException e) {
      // by default restore the previous state when a runtime is thrown
      restoreInstance(previousStatus, productInstance);
      throw new SdcRuntimeException(e);
    }
  }
 private boolean checkProduct(Product product) {
   PaasManagerUser credentials = this.getCredentials();
   if (product.getMapMetadata().get(TENANT_METADATA) != null
       && product.getMapMetadata().get(TENANT_METADATA).equals(credentials.getTenantId())) {
     return true;
   }
   return false;
 }
  @Test
  public void testInsert() throws Exception {
    Product product = new Product();
    product.setName(PRODUCT_NAME);
    product.setDescription("description");

    Product createdProduct = productResource.insert(product);
    assertEquals(createdProduct.getName(), PRODUCT_NAME);
  }
  public Product insert(Product product)
      throws AlreadyExistsEntityException, InvalidEntityException {

    Product productOut;
    try {
      productOut = productDao.load(product.getName());
      LOGGER.log(Level.INFO, "Product " + productOut.getName() + " LOADED");
    } catch (EntityNotFoundException e) {

      List<Metadata> metadatas = new ArrayList<Metadata>();
      metadatas.add(new Metadata("image", "df44f62d-9d66-4dc5-b084-2d6c7bc4cfe4")); // centos6.3_sdc
      metadatas.add(new Metadata("cookbook_url", ""));
      metadatas.add(new Metadata("cloud", "yes"));
      metadatas.add(new Metadata("installator", "chef"));
      metadatas.add(new Metadata("open_ports", "80 22"));

      List<Metadata> defaultmetadatas = new ArrayList<Metadata>();
      defaultmetadatas.add(new Metadata("image", "df44f62d-9d66-4dc5-b084-2d6c7bc4cfe4"));
      defaultmetadatas.add(new Metadata("cookbook_url", ""));
      defaultmetadatas.add(new Metadata("cloud", "yes"));
      defaultmetadatas.add(new Metadata("installator", "chef"));
      defaultmetadatas.add(new Metadata("open_ports", "80 22"));

      for (Metadata external_metadata : product.getMetadatas()) {
        boolean defaultmetadata = false;
        for (Metadata default_metadata : defaultmetadatas) {
          if (external_metadata.getKey().equals(default_metadata.getKey())) {
            metadatas
                .get(metadatas.indexOf(default_metadata))
                .setValue(external_metadata.getValue());
            defaultmetadata = true;
          }
        }
        if (!defaultmetadata) {
          metadatas.add(external_metadata);
        }
      }
      product.setMetadatas(metadatas);
      productOut = productDao.create(product);
    }
    return productOut;
  }
  @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());
  }