Search in sources :

Example 1 with ProductContentDTO

use of org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO in project candlepin by candlepin.

the class ContentManager method updateContent.

/**
 * Updates the specified content instance, creating a new version of the content as necessary.
 * The content instance returned by this method is not guaranteed to be the same instance passed
 * in. As such, once this method has been called, callers should only use the instance output by
 * this method.
 *
 * @param owner
 *  The owner for which to update the content
 *
 * @param regenerateEntitlementCerts
 *  Whether or not changes made to the content should trigger the regeneration of entitlement
 *  certificates for affected consumers
 *
 * @throws IllegalStateException
 *  if the given content update references a content that does not exist for the specified owner
 *
 * @throws IllegalArgumentException
 *  if either the provided content entity or owner are null
 *
 * @return
 *  the updated content entity, or a new content entity
 */
@Transactional
public Content updateContent(ContentDTO update, Owner owner, boolean regenerateEntitlementCerts) {
    if (update == null) {
        throw new IllegalArgumentException("update is null");
    }
    if (update.getId() == null) {
        throw new IllegalArgumentException("update is incomplete");
    }
    if (owner == null) {
        throw new IllegalArgumentException("owner is null");
    }
    // Resolve the entity to ensure we're working with the merged entity, and to ensure it's
    // already been created.
    // TODO: FIXME:
    // There's a bug here where if changes are applied to an entity's collections, and then
    // this method is called, the check below will cause the changes to be persisted.
    // This needs to be re-written to use DTOs as the primary source of entity creation, rather
    // than a bolted-on utility method.
    // If we never edit the entity directly, however, this is safe.
    Content entity = this.ownerContentCurator.getContentById(owner, update.getId());
    if (entity == null) {
        // If we're doing an exclusive update, this should be an error condition
        throw new IllegalStateException("Content has not yet been created");
    }
    // TODO: Remove this shim and stop using DTOs in this class
    if (!this.isChangedBy(entity, update)) {
        return entity;
    }
    log.debug("Applying content update for org: {}, {}", entity, owner);
    Content updated = this.applyContentChanges((Content) entity.clone(), update);
    List<Content> alternateVersions = this.ownerContentCurator.getContentByVersions(owner, Collections.<String, Integer>singletonMap(updated.getId(), updated.getEntityVersion())).list();
    log.debug("Checking {} alternate content versions", alternateVersions.size());
    for (Content alt : alternateVersions) {
        if (alt.equals(updated)) {
            log.debug("Converging product with existing: {} => {}", updated, alt);
            // Make sure every product using the old version/entity are updated to use the new one
            List<Product> affectedProducts = this.productCurator.getProductsByContent(owner, Arrays.asList(updated.getId())).list();
            this.ownerContentCurator.updateOwnerContentReferences(owner, Collections.<String, String>singletonMap(entity.getUuid(), alt.getUuid()));
            log.debug("Updating {} affected products", affectedProducts.size());
            ContentDTO cdto = this.modelTranslator.translate(alt, ContentDTO.class);
            // TODO: Should we bulk this up like we do in importContent? Probably.
            for (Product product : affectedProducts) {
                log.debug("Updating affected product: {}", product);
                ProductDTO pdto = this.modelTranslator.translate(product, ProductDTO.class);
                ProductContentDTO pcdto = pdto.getProductContent(cdto.getId());
                if (pcdto != null) {
                    pdto.addContent(cdto, pcdto.isEnabled());
                    // Impl note: This should also take care of our entitlement cert regeneration
                    this.productManager.updateProduct(pdto, owner, regenerateEntitlementCerts);
                }
            }
            return alt;
        }
    }
    // Temporarily (?) disabled. If we ever move to clustered caching (rather than per-instance
    // caching, this branch should be re-enabled.
    /*
        // No alternate versions with which to converge. Check if we can do an in-place update instead
        if (this.ownerContentCurator.getOwnerCount(updated) < 2) {
            log.debug("Applying in-place update to content: {}", updated);

            updated = this.contentCurator.merge(this.applyContentChanges(entity, update, owner));

            if (regenerateEntitlementCerts) {
                // Every owner with a pool using any of the affected products needs an update.
                List<Product> affectedProducts = this.productCurator
                    .getProductsByContent(Arrays.asList(updated.getUuid()))
                    .list();

                this.entitlementCertGenerator.regenerateCertificatesOf(
                    Arrays.asList(owner), affectedProducts, true
                );
            }

            return updated;
        }
        */
    log.debug("Forking content and applying update: {}", updated);
    // Get products that currently use this content...
    List<Product> affectedProducts = this.productCurator.getProductsByContent(owner, Arrays.asList(updated.getId())).list();
    // Clear the UUID so Hibernate doesn't think our copy is a detached entity
    updated.setUuid(null);
    updated = this.contentCurator.create(updated);
    this.ownerContentCurator.updateOwnerContentReferences(owner, Collections.<String, String>singletonMap(entity.getUuid(), updated.getUuid()));
    // Impl note:
    // This block is a consequence of products and contents not being strongly related.
    log.debug("Updating {} affected products", affectedProducts.size());
    ContentDTO cdto = this.modelTranslator.translate(updated, ContentDTO.class);
    // TODO: Should we bulk this up like we do in importContent? Probably.
    for (Product product : affectedProducts) {
        log.debug("Updating affected product: {}", product);
        ProductDTO pdto = this.modelTranslator.translate(product, ProductDTO.class);
        ProductContentDTO pcdto = pdto.getProductContent(cdto.getId());
        if (pcdto != null) {
            pdto.addContent(cdto, pcdto.isEnabled());
            // Impl note: This should also take care of our entitlement cert regeneration
            this.productManager.updateProduct(pdto, owner, regenerateEntitlementCerts);
        }
    }
    return updated;
}
Also used : ProductContentDTO(org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO) ContentDTO(org.candlepin.dto.api.v1.ContentDTO) ProductContent(org.candlepin.model.ProductContent) Content(org.candlepin.model.Content) OwnerContent(org.candlepin.model.OwnerContent) Product(org.candlepin.model.Product) ProductContentDTO(org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO) ProductDTO(org.candlepin.dto.api.v1.ProductDTO) Transactional(com.google.inject.persist.Transactional)

Example 2 with ProductContentDTO

use of org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO in project candlepin by candlepin.

the class ProductManager method applyProductChanges.

/**
 * Applies the changes from the given DTO to the specified entity
 *
 * @param entity
 *  The entity to modify
 *
 * @param update
 *  The DTO containing the modifications to apply
 *
 * @param content
 *  A mapping of Red Hat content ID to content entities to use for content resolution
 *
 * @throws IllegalArgumentException
 *  if entity, update or owner is null
 *
 * @return
 *  The updated product entity
 */
private Product applyProductChanges(Product entity, ProductDTO update, Map<String, Content> contentMap) {
    if (entity == null) {
        throw new IllegalArgumentException("entity is null");
    }
    if (update == null) {
        throw new IllegalArgumentException("update is null");
    }
    if (contentMap == null) {
        throw new IllegalArgumentException("contentMap is null");
    }
    if (update.getName() != null) {
        entity.setName(update.getName());
    }
    if (update.getMultiplier() != null) {
        entity.setMultiplier(update.getMultiplier());
    }
    if (update.getAttributes() != null) {
        entity.setAttributes(update.getAttributes());
    }
    if (update.getProductContent() != null) {
        Collection<ProductContent> productContent = new LinkedList<>();
        // Sort the existing ProductContent so we aren't iterating on it several times.
        // TODO: Remove this if/when product content is stored as a map on products.
        Map<String, ProductContent> existingLinks = new HashMap<>();
        for (ProductContent pc : entity.getProductContent()) {
            existingLinks.put(pc.getContent().getId(), pc);
        }
        // Actually process our list of content...
        for (ProductContentDTO pcd : update.getProductContent()) {
            if (pcd == null) {
                throw new IllegalStateException("Product data contains a null product-content mapping: " + update);
            }
            ContentDTO cdto = pcd.getContent();
            if (cdto == null || cdto.getId() == null) {
                // adding it to our link object. This is very bad.
                throw new IllegalStateException("Product data contains an incomplete product-content " + "mapping: " + update);
            }
            ProductContent existingLink = existingLinks.get(cdto.getId());
            Content content = contentMap.get(cdto.getId());
            if (content == null) {
                // Content doesn't exist yet -- it should have been created already
                throw new IllegalStateException("product references content which does not exist: " + cdto);
            }
            if (existingLink == null) {
                existingLink = new ProductContent(entity, content, pcd.isEnabled() != null ? pcd.isEnabled() : false);
            } else {
                existingLink.setContent(content);
                if (pcd.isEnabled() != null) {
                    existingLink.setEnabled(pcd.isEnabled());
                }
            }
            productContent.add(existingLink);
        }
        entity.setProductContent(productContent);
    }
    if (update.getDependentProductIds() != null) {
        entity.setDependentProductIds(update.getDependentProductIds());
    }
    if (update.isLocked() != null) {
        entity.setLocked(update.isLocked());
    }
    return entity;
}
Also used : ProductContentDTO(org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO) ContentDTO(org.candlepin.dto.api.v1.ContentDTO) HashMap(java.util.HashMap) ProductContent(org.candlepin.model.ProductContent) Content(org.candlepin.model.Content) ProductContentDTO(org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO) ProductContent(org.candlepin.model.ProductContent) LinkedList(java.util.LinkedList)

Example 3 with ProductContentDTO

use of org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO in project candlepin by candlepin.

the class ProductDTOTranslatorTest method initSourceObject.

@Override
protected ProductDTO initSourceObject() {
    ProductDTO source = new ProductDTO();
    Map<String, String> attributes = new HashMap<>();
    attributes.put("attrib_1", "attrib_value_1");
    attributes.put("attrib_2", "attrib_value_2");
    attributes.put("attrib_3", "attrib_value_3");
    Collection<String> depProdIds = new LinkedList<>();
    depProdIds.add("dep_prod_1");
    depProdIds.add("dep_prod_2");
    depProdIds.add("dep_prod_3");
    source.setUuid("test_uuid");
    source.setId("test_id");
    source.setName("test_name");
    source.setMultiplier(10L);
    source.setAttributes(attributes);
    source.setDependentProductIds(depProdIds);
    for (int i = 0; i < 3; ++i) {
        ContentDTO contentDTO = new ContentDTO();
        contentDTO.setId("content-dto-" + i);
        contentDTO.setUuid(contentDTO.getId() + "_uuid");
        ProductContentDTO pcDTO = new ProductContentDTO(contentDTO, true);
        source.addProductContent(pcDTO);
    }
    return source;
}
Also used : ProductContentDTO(org.candlepin.dto.manifest.v1.ProductDTO.ProductContentDTO) ContentDTO(org.candlepin.dto.manifest.v1.ContentDTO) HashMap(java.util.HashMap) ProductContentDTO(org.candlepin.dto.manifest.v1.ProductDTO.ProductContentDTO) ProductDTO(org.candlepin.dto.manifest.v1.ProductDTO) LinkedList(java.util.LinkedList)

Example 4 with ProductContentDTO

use of org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO in project candlepin by candlepin.

the class ProductDTOTranslatorTest method verifyOutput.

@Override
protected void verifyOutput(ProductDTO source, ProductData dto, boolean childrenGenerated) {
    if (source != null) {
        assertEquals(source.getUuid(), dto.getUuid());
        assertEquals(source.getId(), dto.getId());
        assertEquals(source.getName(), dto.getName());
        assertEquals(source.getMultiplier(), dto.getMultiplier());
        assertEquals(source.getAttributes(), dto.getAttributes());
        assertEquals(source.getDependentProductIds(), dto.getDependentProductIds());
        assertNotNull(dto.getProductContent());
        if (childrenGenerated) {
            for (ProductContentDTO pcdto : source.getProductContent()) {
                for (ProductContentData pcdata : dto.getProductContent()) {
                    ContentDTO cdto = pcdto.getContent();
                    ContentData cdata = pcdata.getContent();
                    assertNotNull(cdata);
                    assertNotNull(cdata.getUuid());
                    if (cdata.getUuid().equals(cdto.getUuid())) {
                        assertEquals(pcdto.isEnabled(), pcdata.isEnabled());
                        // Pass the content off to the ContentTranslatorTest to verify it
                        this.contentDTOTranslatorTest.verifyOutput(cdto, cdata, true);
                    }
                }
            }
        } else {
            assertTrue(dto.getProductContent().isEmpty());
        }
    } else {
        assertNull(dto);
    }
}
Also used : ProductContentDTO(org.candlepin.dto.manifest.v1.ProductDTO.ProductContentDTO) ContentDTO(org.candlepin.dto.manifest.v1.ContentDTO) ContentData(org.candlepin.model.dto.ContentData) ProductContentData(org.candlepin.model.dto.ProductContentData) ProductContentDTO(org.candlepin.dto.manifest.v1.ProductDTO.ProductContentDTO) ProductContentData(org.candlepin.model.dto.ProductContentData)

Example 5 with ProductContentDTO

use of org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO in project candlepin by candlepin.

the class ProductDataTranslatorTest method verifyOutput.

@Override
protected void verifyOutput(ProductData source, ProductDTO dto, boolean childrenGenerated) {
    if (source != null) {
        assertEquals(source.getUuid(), dto.getUuid());
        assertEquals(source.getId(), dto.getId());
        assertEquals(source.getName(), dto.getName());
        assertEquals(source.getMultiplier(), dto.getMultiplier());
        assertEquals(source.getAttributes(), dto.getAttributes());
        assertEquals(source.getDependentProductIds(), dto.getDependentProductIds());
        assertEquals(source.isLocked(), dto.isLocked());
        assertEquals(source.getHref(), dto.getHref());
        if (childrenGenerated) {
            assertNotNull(dto.getProductContent());
            for (ProductContentData pc : source.getProductContent()) {
                for (ProductContentDTO pcdto : dto.getProductContent()) {
                    ContentData content = pc.getContent();
                    ContentDTO cdto = pcdto.getContent();
                    assertNotNull(cdto);
                    assertNotNull(cdto.getUuid());
                    if (cdto.getUuid().equals(content.getUuid())) {
                        assertEquals(pc.isEnabled(), pcdto.isEnabled());
                        // Pass the content off to the ContentTranslatorTest to verify it
                        this.contentDataTranslatorTest.verifyOutput(content, cdto, childrenGenerated);
                    }
                }
            }
        } else {
            assertNull(dto.getProductContent());
        }
    } else {
        assertNull(dto);
    }
}
Also used : ProductContentDTO(org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO) ContentDTO(org.candlepin.dto.api.v1.ContentDTO) ContentData(org.candlepin.model.dto.ContentData) ProductContentData(org.candlepin.model.dto.ProductContentData) ProductContentDTO(org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO) ProductContentData(org.candlepin.model.dto.ProductContentData)

Aggregations

ProductContentDTO (org.candlepin.dto.api.v1.ProductDTO.ProductContentDTO)7 Content (org.candlepin.model.Content)6 ProductContent (org.candlepin.model.ProductContent)5 ContentDTO (org.candlepin.dto.api.v1.ContentDTO)4 HashMap (java.util.HashMap)2 LinkedList (java.util.LinkedList)2 ContentDTO (org.candlepin.dto.manifest.v1.ContentDTO)2 ProductContentDTO (org.candlepin.dto.manifest.v1.ProductDTO.ProductContentDTO)2 Product (org.candlepin.model.Product)2 ContentData (org.candlepin.model.dto.ContentData)2 ProductContentData (org.candlepin.model.dto.ProductContentData)2 Transactional (com.google.inject.persist.Transactional)1 Collection (java.util.Collection)1 Comparator (java.util.Comparator)1 ProductDTO (org.candlepin.dto.api.v1.ProductDTO)1 ProductDTO (org.candlepin.dto.manifest.v1.ProductDTO)1 OwnerContent (org.candlepin.model.OwnerContent)1