use of org.candlepin.model.ProductContent 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.ProductContent in project candlepin by candlepin.
the class X509Util method filterContentByContentArch.
/*
* remove content sets that do not match the consumers arch
*/
public Set<ProductContent> filterContentByContentArch(Set<ProductContent> pcSet, Consumer consumer, Product product) {
Set<ProductContent> filtered = new HashSet<>();
String consumerArch = consumer.getFact(ARCH_FACT);
if (consumerArch == null) {
log.debug("consumer: " + consumer.getId() + " has no " + ARCH_FACT + " attribute.");
log.debug("Not filtering by arch");
return pcSet;
}
for (ProductContent pc : pcSet) {
boolean canUse = true;
Set<String> contentArches = Arch.parseArches(pc.getContent().getArches());
Set<String> productArches = Arch.parseArches(product.getAttributeValue(Product.Attributes.ARCHITECTURE));
// inheriting the arches from the product
if (contentArches.isEmpty()) {
// and if so inherit it.
if (!productArches.isEmpty()) {
contentArches.addAll(productArches);
} else {
// No Product arches either, log it, but do
// not filter out this content
log.debug("No arch attributes found for content or product");
}
}
for (String contentArch : contentArches) {
if (Arch.contentForConsumer(contentArch, consumerArch)) {
canUse = true;
break;
} else {
canUse = false;
}
}
// Content or on Product)
if (canUse) {
filtered.add(pc);
}
}
return filtered;
}
use of org.candlepin.model.ProductContent in project candlepin by candlepin.
the class ProductTranslatorTest method verifyOutput.
@Override
protected void verifyOutput(Product 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());
assertNotNull(dto.getProductContent());
if (childrenGenerated) {
for (ProductContent pc : source.getProductContent()) {
for (ProductContentDTO pcdto : dto.getProductContent()) {
Content 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.contentTranslatorTest.verifyOutput(content, cdto, childrenGenerated);
}
}
}
} else {
assertTrue(dto.getProductContent().isEmpty());
}
} else {
assertNull(dto);
}
}
use of org.candlepin.model.ProductContent in project candlepin by candlepin.
the class ProductManagerTest method testUpdateProductContentOnSharedProduct.
// Move this to ContentManagerTest
@Test
public void testUpdateProductContentOnSharedProduct() {
Owner owner1 = this.createOwner("test-owner-1", "Test Owner 1");
Owner owner2 = this.createOwner("test-owner-2", "Test Owner 2");
Product product = this.createProduct("p1", "prod1", owner1);
Content content = this.createContent("c1", "content1", owner1);
this.ownerProductCurator.mapProductToOwners(product, owner1, owner2);
product.setProductContent(Arrays.asList(new ProductContent(product, content, true)));
this.productCurator.merge(product);
ProductDTO pdto = this.modelTranslator.translate(product, ProductDTO.class);
pdto.getProductContent(content.getId()).setEnabled(false);
Product output = this.productManager.updateProduct(pdto, owner1, false);
assertNotEquals(product, output);
assertTrue(product.hasContent(content.getId()));
assertTrue(output.hasContent(content.getId()));
assertTrue(product.getProductContent().iterator().next().isEnabled());
assertFalse(output.getProductContent().iterator().next().isEnabled());
assertFalse(this.ownerProductCurator.isProductMappedToOwner(product, owner1));
assertTrue(this.ownerProductCurator.isProductMappedToOwner(product, owner2));
assertTrue(this.ownerProductCurator.isProductMappedToOwner(output, owner1));
assertFalse(this.ownerProductCurator.isProductMappedToOwner(output, owner2));
verifyZeroInteractions(this.mockEntCertGenerator);
}
use of org.candlepin.model.ProductContent in project candlepin by candlepin.
the class X509ExtensionUtil method contentExtensions.
public Set<X509ExtensionWrapper> contentExtensions(Collection<ProductContent> productContentList, String contentPrefix, Map<String, EnvironmentContent> promotedContent, Consumer consumer, Product skuProduct) {
Set<ProductContent> productContent = new HashSet<>(productContentList);
Set<X509ExtensionWrapper> toReturn = new LinkedHashSet<>();
boolean enableEnvironmentFiltering = config.getBoolean(ConfigProperties.ENV_CONTENT_FILTERING);
List<String> skuDisabled = skuProduct.getSkuDisabledContentIds();
List<String> skuEnabled = skuProduct.getSkuEnabledContentIds();
// informative error message to the user.
for (ProductContent pc : productContent) {
// augment the content path with the prefix if it is passed in
String contentPath = this.createFullContentPath(contentPrefix, pc);
// skip it. see rhbz#997970
if (!OIDUtil.CF_REPO_TYPE.containsKey(pc.getContent().getType())) {
log.warn("No content type OID found for {} with content type: {}", pc.getContent(), pc.getContent().getType());
continue;
}
String contentOid = OIDUtil.REDHAT_OID + "." + OIDUtil.TOPLEVEL_NAMESPACES.get(OIDUtil.CHANNEL_FAMILY_NAMESPACE_KEY) + "." + pc.getContent().getId().toString() + "." + OIDUtil.CF_REPO_TYPE.get(pc.getContent().getType());
toReturn.add(new X509ExtensionWrapper(contentOid, false, pc.getContent().getType()));
toReturn.add(new X509ExtensionWrapper(contentOid + "." + OIDUtil.CHANNEL_FAMILY_OIDS.get(OIDUtil.CF_NAME_KEY), false, pc.getContent().getName()));
toReturn.add(new X509ExtensionWrapper(contentOid + "." + OIDUtil.CHANNEL_FAMILY_OIDS.get(OIDUtil.CF_LABEL_KEY), false, pc.getContent().getLabel()));
toReturn.add(new X509ExtensionWrapper(contentOid + "." + OIDUtil.CHANNEL_FAMILY_OIDS.get(OIDUtil.CF_VENDOR_ID_KEY), false, pc.getContent().getVendor()));
toReturn.add(new X509ExtensionWrapper(contentOid + "." + OIDUtil.CHANNEL_FAMILY_OIDS.get(OIDUtil.CF_DOWNLOAD_URL_KEY), false, contentPath));
toReturn.add(new X509ExtensionWrapper(contentOid + "." + OIDUtil.CHANNEL_FAMILY_OIDS.get(OIDUtil.CF_GPG_URL_KEY), false, pc.getContent().getGpgUrl()));
Boolean enabled = pc.isEnabled();
log.debug("default enabled flag = " + enabled);
// sku level content enable override. if on both lists, active wins.
if (skuDisabled.contains(pc.getContent().getId())) {
enabled = false;
}
if (skuEnabled.contains(pc.getContent().getId())) {
enabled = true;
}
// content:
if (enableEnvironmentFiltering && consumer.getEnvironmentId() != null) {
// we know content has been promoted at this point:
Boolean enabledOverride = promotedContent.get(pc.getContent().getId()).getEnabled();
if (enabledOverride != null) {
log.debug("overriding enabled flag: {}", enabledOverride);
enabled = enabledOverride;
}
}
toReturn.add(new X509ExtensionWrapper(contentOid + "." + OIDUtil.CHANNEL_FAMILY_OIDS.get(OIDUtil.CF_ENABLED), false, (enabled) ? "1" : "0"));
// Include metadata expiry if specified on the content:
if (pc.getContent().getMetadataExpire() != null) {
toReturn.add(new X509ExtensionWrapper(contentOid + "." + OIDUtil.CHANNEL_FAMILY_OIDS.get(OIDUtil.CF_METADATA_EXPIRE), false, pc.getContent().getMetadataExpire().toString()));
}
// Include required tags if specified on the content set:
String requiredTags = pc.getContent().getRequiredTags();
if ((requiredTags != null) && !requiredTags.equals("")) {
toReturn.add(new X509ExtensionWrapper(contentOid + "." + OIDUtil.CHANNEL_FAMILY_OIDS.get(OIDUtil.CF_REQUIRED_TAGS), false, requiredTags));
}
}
return toReturn;
}
Aggregations