use of org.candlepin.model.dto.ProductData in project candlepin by candlepin.
the class EntitlerTest method testCreatedDevPoolAttributes.
@Test
public void testCreatedDevPoolAttributes() {
Owner owner = TestUtil.createOwner("o");
List<ProductData> devProdDTOs = new ArrayList<>();
Product p1 = TestUtil.createProduct("dev-product", "Dev Product");
p1.setAttribute(Product.Attributes.SUPPORT_LEVEL, "Premium");
p1.setAttribute("expires_after", "47");
Product p2 = TestUtil.createProduct("provided-product1", "Provided Product 1");
Product p3 = TestUtil.createProduct("provided-product2", "Provided Product 2");
devProdDTOs.add(p1.toDTO());
devProdDTOs.add(p2.toDTO());
devProdDTOs.add(p3.toDTO());
Consumer devSystem = TestUtil.createConsumer(owner);
devSystem.setFact("dev_sku", p1.getId());
devSystem.addInstalledProduct(new ConsumerInstalledProduct(p2));
devSystem.addInstalledProduct(new ConsumerInstalledProduct(p3));
when(productAdapter.getProductsByIds(eq(owner), any(List.class))).thenReturn(devProdDTOs);
this.mockProducts(owner, p1, p2, p3);
this.mockProductImport(owner, p1, p2, p3);
this.mockContentImport(owner, Collections.<String, Content>emptyMap());
Pool created = entitler.assembleDevPool(devSystem, owner, devSystem.getFact("dev_sku"));
Calendar cal = Calendar.getInstance();
cal.setTime(created.getStartDate());
cal.add(Calendar.DAY_OF_YEAR, 47);
assertEquals(created.getEndDate(), cal.getTime());
assertEquals("true", created.getAttributeValue(Pool.Attributes.DEVELOPMENT_POOL));
assertEquals(devSystem.getUuid(), created.getAttributeValue(Pool.Attributes.REQUIRES_CONSUMER));
assertEquals(p1.getId(), created.getProductId());
assertEquals(2, created.getProvidedProducts().size());
assertEquals("Premium", created.getProduct().getAttributeValue(Product.Attributes.SUPPORT_LEVEL));
assertEquals(1L, created.getQuantity().longValue());
}
use of org.candlepin.model.dto.ProductData in project candlepin by candlepin.
the class EntitlementImporter method associateProvidedProducts.
/*
* Transfer associations to provided and derived provided products over to the
* subscription.
*
* WARNING: This is a bit tricky due to backward compatibility issues. Prior to
* candlepin 2.0, pools serialized a collection of disjoint provided product info,
* an object with just a product ID and name, not directly linked to anything in the db.
*
* In candlepin 2.0 we have referential integrity and links to full product objects,
* but we need to maintain both API and import compatibility with old manifests and
* servers that may import new manifests.
*
* To do this, we serialize the providedProductDtos and derivedProvidedProductDtos
* collections on pool which keeps the API/manifest JSON identical to what it was
* before. On import we load into these transient collections, and here we transfer
* to the actual persisted location.
*/
public void associateProvidedProducts(Map<String, ProductDTO> productsById, Entitlement entitlement, Subscription subscription) throws SyncDataFormatException {
// Associate main provided products:
Set<ProductData> providedProducts = new HashSet<>();
entitlement.getPool().populateAllTransientProvidedProducts(productCurator);
for (ProvidedProduct providedProduct : entitlement.getPool().getProvidedProductDtos()) {
ProductDTO productDTO = this.findProduct(productsById, providedProduct.getProductId());
providedProducts.add(this.translator.translate(productDTO, ProductData.class));
}
subscription.setProvidedProducts(providedProducts);
// Associate derived provided products:
Set<ProductData> derivedProvidedProducts = new HashSet<>();
for (ProvidedProduct pp : entitlement.getPool().getDerivedProvidedProductDtos()) {
ProductDTO productDTO = this.findProduct(productsById, pp.getProductId());
derivedProvidedProducts.add(this.translator.translate(productDTO, ProductData.class));
}
subscription.setDerivedProvidedProducts(derivedProvidedProducts);
log.debug("Subscription has {} provided products.", derivedProvidedProducts.size());
log.debug("Subscription has {} derived provided products.", derivedProvidedProducts.size());
}
use of org.candlepin.model.dto.ProductData in project candlepin by candlepin.
the class PoolRulesTest method createVirtLimitSubWithDerivedProducts.
private Subscription createVirtLimitSubWithDerivedProducts(String productId, String derivedProductId, int quantity, int virtLimit) {
Product product = TestUtil.createProduct(productId, productId);
product.setAttribute(Product.Attributes.VIRT_LIMIT, Integer.toString(virtLimit));
when(ownerProdCuratorMock.getProductById(owner, product.getId())).thenReturn(product);
Product derivedProd = TestUtil.createProduct(derivedProductId, derivedProductId);
// We'll look for this to make sure it makes it to correct pools:
derivedProd.setAttribute(DERIVED_ATTR, "nobodycares");
when(ownerProdCuratorMock.getProductById(owner, derivedProd.getId())).thenReturn(derivedProd);
// Create some provided products:
Product provided1 = TestUtil.createProduct();
when(ownerProdCuratorMock.getProductById(owner, provided1.getId())).thenReturn(provided1);
Product provided2 = TestUtil.createProduct();
when(ownerProdCuratorMock.getProductById(owner, provided2.getId())).thenReturn(provided2);
// Create some derived provided products:
Product derivedProvided1 = TestUtil.createProduct();
when(ownerProdCuratorMock.getProductById(owner, derivedProvided1.getId())).thenReturn(derivedProvided1);
Product derivedProvided2 = TestUtil.createProduct();
when(ownerProdCuratorMock.getProductById(owner, derivedProvided2.getId())).thenReturn(derivedProvided2);
Subscription s = TestUtil.createSubscription(owner, product);
s.setQuantity(new Long(quantity));
s.setDerivedProduct(derivedProd.toDTO());
Set<ProductData> derivedProds = new HashSet<>();
derivedProds.add(derivedProvided1.toDTO());
derivedProds.add(derivedProvided2.toDTO());
s.setDerivedProvidedProducts(derivedProds);
return s;
}
use of org.candlepin.model.dto.ProductData in project candlepin by candlepin.
the class ContentManager method importContent.
/**
* Creates or updates content from the given content DTOs, omitting product updates for the
* provided Red Hat product IDs.
* <p></p>
* The content DTOs provided in the given map should be mapped by the content's Red Hat ID. If
* the mappings are incorrect or inconsistent, the result of this method is undefined.
*
* @param owner
* The owner for which to import the given content
*
* @param contentData
* A mapping of Red Hat content ID to content DTOs to import
*
* @param importedProductIds
* A set of Red Hat product IDs specifying products which are being imported and should not be
* updated as part of this import operation
*
* @return
* A mapping of Red Hat content ID to content entities representing the imported content
*/
@SuppressWarnings("checkstyle:methodlength")
@Transactional
@Traceable
public ImportResult<Content> importContent(@TraceableParam("owner") Owner owner, Map<String, ContentData> contentData, Set<String> importedProductIds) {
if (owner == null) {
throw new IllegalArgumentException("owner is null");
}
ImportResult<Content> importResult = new ImportResult<>();
if (contentData == null || contentData.isEmpty()) {
// Nothing to import
return importResult;
}
Map<String, Content> skippedContent = importResult.getSkippedEntities();
Map<String, Content> createdContent = importResult.getCreatedEntities();
Map<String, Content> updatedContent = importResult.getUpdatedEntities();
Map<String, Integer> contentVersions = new HashMap<>();
Map<String, Content> sourceContent = new HashMap<>();
Map<String, List<Content>> existingVersions = new HashMap<>();
List<OwnerContent> ownerContentBuffer = new LinkedList<>();
// - Divide imported products into sets of updates and creates
log.debug("Fetching existing content for update...");
for (Content content : this.ownerContentCurator.getContentByIds(owner, contentData.keySet())) {
ContentData update = contentData.get(content.getId());
if (!this.isChangedBy(content, update)) {
// This content won't be changing, so we'll just pretend it's not being imported at all
skippedContent.put(content.getId(), content);
continue;
}
// Content is coming from an upstream source; lock it so only upstream can make
// further changes to it. If we ever use this method for anything other than
// imports, we'll need to stop doing this.
sourceContent.put(content.getId(), content);
content = this.applyContentChanges((Content) content.clone(), update);
updatedContent.put(content.getId(), content);
contentVersions.put(content.getId(), content.getEntityVersion());
}
log.debug("Validating new content...");
for (ContentData update : contentData.values()) {
if (!skippedContent.containsKey(update.getId()) && !updatedContent.containsKey(update.getId())) {
// Ensure content is minimally populated
if (update.getId() == null || update.getType() == null || update.getLabel() == null || update.getName() == null || update.getVendor() == null) {
throw new IllegalStateException("Content data is incomplete: " + update);
}
Content content = this.applyContentChanges(new Content(update.getId()), update);
createdContent.put(content.getId(), content);
contentVersions.put(content.getId(), content.getEntityVersion());
}
}
log.debug("Checking for existing content versions...");
for (Content alt : this.ownerContentCurator.getContentByVersions(owner, contentVersions)) {
List<Content> alternates = existingVersions.get(alt.getId());
if (alternates == null) {
alternates = new LinkedList<>();
existingVersions.put(alt.getId(), alternates);
}
alternates.add(alt);
}
contentVersions.clear();
contentVersions = null;
// We're about to start modifying the maps, so we need to clone the created set before we
// start adding the update forks to it.
Map<String, Content> stagedEntities = new HashMap<>(createdContent);
// Process the created group...
// Check our created set for existing versions:
// - If there's an existing version, we'll remove the staged entity from the creation
// set, and stage an owner-content mapping for the existing version
// - Otherwise, we'll stage the new entity for persistence by leaving it in the created
// set, and stage an owner-content mapping to the new entity
Iterator<Content> iterator = stagedEntities.values().iterator();
createdContentLoop: while (iterator.hasNext()) {
Content created = iterator.next();
List<Content> alternates = existingVersions.get(created.getId());
if (alternates != null) {
for (Content alt : alternates) {
if (created.equals(alt)) {
ownerContentBuffer.add(new OwnerContent(owner, alt));
createdContent.put(alt.getId(), alt);
iterator.remove();
continue createdContentLoop;
}
}
}
ownerContentBuffer.add(new OwnerContent(owner, created));
}
// - Otherwise, we need to stage the updated entity for persistence
updatedContentLoop: for (Map.Entry<String, Content> entry : updatedContent.entrySet()) {
Content updated = entry.getValue();
List<Content> alternates = existingVersions.get(updated.getId());
if (alternates != null) {
for (Content alt : alternates) {
if (!updated.getUuid().equals(alt.getUuid()) && updated.equals(alt)) {
updated = alt;
entry.setValue(alt);
continue updatedContentLoop;
}
}
}
// We need to stage the updated entity for persistence. We'll reuse the now-empty
// createdContent map for this.
updated.setUuid(null);
stagedEntities.put(updated.getId(), updated);
}
// Persist our staged entities
// We probably don't want to evict the content yet, as they'll appear as unmanaged if
// they're used later. However, the join objects can be evicted safely since they're only
// really used here.
log.debug("Persisting content changes...");
this.contentCurator.saveAll(stagedEntities.values(), true, false);
this.ownerContentCurator.saveAll(ownerContentBuffer, true, true);
// Fetch collection of products affected by this import that aren't being imported themselves
log.debug("Updating non-imported, affected products...");
List<Product> affectedProducts = this.productCurator.getProductsByContent(owner, sourceContent.keySet(), importedProductIds).list();
if (affectedProducts != null && !affectedProducts.isEmpty()) {
// Get the collection of content those products use
Map<String, Content> affectedProductsContent = new HashMap<>();
for (Content content : this.contentCurator.getContentByProducts(affectedProducts)) {
affectedProductsContent.put(content.getId(), content);
}
// Update the content map so it references the updated content
affectedProductsContent.putAll(updatedContent);
Map<String, ProductData> affectedProductData = new HashMap<>();
Map<String, ContentData> contentDTOCache = new HashMap<>();
for (Product product : affectedProducts) {
ProductData pdto = product.toDTO();
for (ProductContent pcdata : product.getProductContent()) {
Content content = pcdata.getContent();
Content updated = updatedContent.get(content.getId());
if (updated != null) {
ContentData cdto = contentDTOCache.get(content.getId());
if (cdto == null) {
cdto = content.toDTO();
contentDTOCache.put(cdto.getId(), cdto);
}
pdto.addContent(cdto, pcdata.isEnabled());
}
}
affectedProductData.put(pdto.getId(), pdto);
}
// Perform a micro-import for these products using the content map we just built
this.productManager.importProducts(owner, affectedProductData, affectedProductsContent);
}
// Perform bulk reference update
Map<String, String> contentUuidMap = new HashMap<>();
for (Content update : updatedContent.values()) {
Content source = sourceContent.get(update.getId());
contentUuidMap.put(source.getUuid(), update.getUuid());
}
this.ownerContentCurator.updateOwnerContentReferences(owner, contentUuidMap);
// Return
return importResult;
}
use of org.candlepin.model.dto.ProductData in project candlepin by candlepin.
the class ContentManager method removeContentByUuids.
/**
* Removes all content with the provided UUIDs from the given owner.
*
* @param owner
* The owner from which to remove content
*
* @param contentUuids
* A collection of UUIDs representing the content to remove
*
* @param regenerateEntitlementCerts
* Whether or not changes made to the content should trigger the regeneration of entitlement
* certificates for affected consumers
*
* @throws IllegalArgumentException
* if owner is null
*/
public void removeContentByUuids(Owner owner, Collection<String> contentUuids, boolean regenerateEntitlementCerts) {
if (owner == null) {
throw new IllegalArgumentException("owner is null");
}
if (contentUuids != null && !contentUuids.isEmpty()) {
log.debug("Deleting content with UUIDs: {}", contentUuids);
List<Product> affectedProducts = this.productCurator.getProductsByContentUuids(owner, contentUuids).list();
if (!affectedProducts.isEmpty()) {
log.debug("Updating {} affected products", affectedProducts.size());
if (!(contentUuids instanceof Set)) {
// Convert this to a set so our filtering lookups aren't painfully slow
contentUuids = new HashSet<>(contentUuids);
}
// Get the collection of content those products use, throwing out the ones we'll be
// removing shortly
Map<String, Content> affectedProductsContent = new HashMap<>();
for (Content content : this.contentCurator.getContentByProducts(affectedProducts)) {
if (!contentUuids.contains(content.getUuid())) {
affectedProductsContent.put(content.getId(), content);
}
}
// Convert our affectedProducts into DTOs (hoping Hibernate uses its entity cache
// instead of pulling down the content list for each product...)
Map<String, ProductData> affectedProductData = new HashMap<>();
for (Product product : affectedProducts) {
ProductData pdto = product.toDTO();
Iterator<ProductContentData> pcd = pdto.getProductContent().iterator();
while (pcd.hasNext()) {
ContentData cdto = pcd.next().getContent();
if (!affectedProductsContent.containsKey(cdto.getId())) {
pcd.remove();
}
}
affectedProductData.put(pdto.getId(), pdto);
}
// Perform a micro-import for these products using the content map we just built
log.debug("Performing micro-import for products: {}", affectedProductData);
this.productManager.importProducts(owner, affectedProductData, affectedProductsContent);
if (regenerateEntitlementCerts) {
this.entitlementCertGenerator.regenerateCertificatesOf(Arrays.asList(owner), affectedProducts, true);
}
}
// Remove content references
this.ownerContentCurator.removeOwnerContentReferences(owner, contentUuids);
}
}
Aggregations