Class ProductCharacteristicsConsolidationContributor
- All Implemented Interfaces:
ProductConsolidationContributor
ProductCharacteristics into ConsolidatedProducts.
This contributor is responsible for fetching and consolidating product characteristics for a
given set of products. It uses the ProductHydrationService to hydrate the characteristics
for the products.
- Since:
- Catalog Services 2.3.0, Release Train 2.3.0
- Author:
- Jon Fleschler (jfleschler)
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classPOJO used internally byProductCharacteristicsConsolidationContributorto collect and pass pre-fetched data. -
Field Summary
Fields inherited from class com.broadleafcommerce.catalog.service.product.consolidation.ContextualProductConsolidationContributor
IGNORE_ARCHIVED_FILTER, typeFactory -
Constructor Summary
ConstructorsConstructorDescriptionProductCharacteristicsConsolidationContributor(com.broadleafcommerce.common.extension.TypeFactory typeFactory, ProductCharacteristicService<ProductCharacteristic> productCharacteristicService, CharacteristicService<Characteristic> characteristicService, CharacteristicHydrationService characteristicHydrationService, BusinessTypeService<BusinessType> businessTypeService, ProductHydrationService productHydrationService, ConsolidationBusinessTypeHydrationUtil consolidationBusinessTypeHydrationUtil) -
Method Summary
Modifier and TypeMethodDescriptionprotected voidapplyHydrationToProduct(ConsolidatedProduct product, ProductCharacteristicsConsolidationContributor.ProductCharacteristicsConsolidationData prodCharsConsolidationData, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines) protected Map<String,List<ProductCharacteristic>> collectMostDerivedProductCharacteristicsByProductId(com.broadleafcommerce.data.tracking.core.filtering.business.domain.ContextState productContext, List<ProductCharacteristic> allUnnarrowedProdChars, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines) This method tries to mimic whatProductCharacteristicService.readAllByProductContextIdIn(Collection, ContextInfo)normally provides to the characteristic hydration flow, which would be all the 'most derived' representations of theProductCharacteristicinstances belonging to a particular context.protected Map<String,List<ProductCharacteristic>> collectProductCharacteristicsFromInheritanceLineByProductId(com.broadleafcommerce.data.tracking.core.filtering.business.domain.ContextState productContext, List<ProductCharacteristic> allUnnarrowedProdChars, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines) This method tries to mimic whatProductCharacteristicService.readAllByProductContextIdAndInheritanceLine(Collection, ContextInfo)normally provides to the characteristic hydration flow.voidconsolidateProducts(Set<String> productIds, List<ConsolidatedProduct> products, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines, com.broadleafcommerce.data.tracking.core.context.ContextInfo context) This method is largely mimicking the structure ofContextualProductConsolidationContributor.consolidateProducts(Set, List, InheritanceLines, ContextInfo), but adapted slightly to tailor to this domain's use-case.protected List<ConsolidatedProduct>consolidateRelations(List<ConsolidatedProduct> products, ProductCharacteristicsConsolidationContributor.ProductCharacteristicsConsolidationData prodCharsConsolidationData, Function<ProductCharacteristic, String> idGetter, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines) Loosely modeled after the baseContextualProductConsolidationContributor.consolidateRelations(List, List, BiConsumer, Function, InheritanceLines)method.protected ConsolidatedProductcreateOverrideProductForContext(com.broadleafcommerce.data.tracking.core.filtering.business.domain.ContextState unmatchedContextState, List<ProductCharacteristic> relations, ConsolidatedProduct implicitProduct, BiConsumer<ConsolidatedProduct, List<ProductCharacteristic>> setRelation, Function<ProductCharacteristic, String> idGetter, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines) Overrides the base method to only generate the clone override and not actually set anything, since we want to do that in a later step.protected ProductCharacteristicextractBaseCharacteristicIdsFromProdChars(Map<String, List<ProductCharacteristic>> prodCharsByProdId) protected List<ProductCharacteristic>gatherProductCharacteristicsWithUnmatchedContexts(List<ConsolidatedProduct> productsWithSameId, List<ProductCharacteristic> prodCharsToCheckUnmatchedContextFor) protected BusinessTypeService<BusinessType>protected CharacteristicHydrationServiceprotected CharacteristicService<Characteristic>protected ConsolidationBusinessTypeHydrationUtilprotected StringgetMostSpecificCatalogIdNullSafe(com.broadleafcommerce.data.tracking.core.filtering.business.domain.ContextState contextState) protected List<ProductCharacteristic>getObjectsToConsolidate(Set<String> productIds, List<ConsolidatedProduct> products, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines, com.broadleafcommerce.data.tracking.core.context.ContextInfo context) The base class requires us to implement this abstract method, but we've overriddenconsolidateProducts(Set, List, InheritanceLines, ContextInfo)to callgetProdCharsAndRelatedDataToConsolidate(Set, List, InheritanceLines, ContextInfo)instead, and thus we will do nothing in this method but throw an exception.getProdCharsAndRelatedDataToConsolidate(@NonNull Set<String> productIds, @NonNull List<ConsolidatedProduct> products, @NonNull com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines, @NonNull com.broadleafcommerce.data.tracking.core.context.ContextInfo context) protected ProductHydrationServiceprotected IntegergetSandboxLevelNullSafe(com.broadleafcommerce.data.tracking.core.filtering.business.domain.ContextState contextState) protected Function<ProductCharacteristic,String> idGetter()Defines the function which retrieves the contextId of the domain object in order to recognize it in different contexts.protected Function<ProductCharacteristic,String> Defines the function which retrieves the Product ID from the domain object to consolidate, in order to group it with the appropriate product for processing.protected List<ProductCharacteristic>Refines the raw ancestry of product characteristics to ensure it only contains exactly one record per catalog level, and that all returned records belong to the same logicalContext IDfor any givenfieldName.protected BiConsumer<ConsolidatedProduct,List<ProductCharacteristic>> setter()Defines the function which should be used to set the domain objects on the consolidated product.booleanshouldConsolidate(Set<String> productIds, List<ConsolidatedProduct> products, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines, com.broadleafcommerce.data.tracking.core.context.ContextInfo context) Determines whether this contributor should be executed based on the given parameters and context.Methods inherited from class com.broadleafcommerce.catalog.service.product.consolidation.ContextualProductConsolidationContributor
buildIgnoreArchivedFilter, consolidateRelations, contextCompositeKey, contextCompositeKey, contextStatesMatch, createUnmodifiedOverrideProductForContext, deepCopy, findImplicitMatches, findImplicitMatchVisibleCandidates, generateNewOverriddenProducts, getCloneMapper, getInheritanceLevel, getMostSpecificCatalogId, getObjectDeepCopyUtility, getProductConsolidationRequest, getRsqlParser, getTypeFactory, ignoreArchived, isInheriting, setListValue, setObjectDeepCopyUtility, setSingleValue
-
Constructor Details
-
ProductCharacteristicsConsolidationContributor
public ProductCharacteristicsConsolidationContributor(com.broadleafcommerce.common.extension.TypeFactory typeFactory, ProductCharacteristicService<ProductCharacteristic> productCharacteristicService, CharacteristicService<Characteristic> characteristicService, CharacteristicHydrationService characteristicHydrationService, BusinessTypeService<BusinessType> businessTypeService, ProductHydrationService productHydrationService, ConsolidationBusinessTypeHydrationUtil consolidationBusinessTypeHydrationUtil)
-
-
Method Details
-
shouldConsolidate
public boolean shouldConsolidate(Set<String> productIds, List<ConsolidatedProduct> products, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines, com.broadleafcommerce.data.tracking.core.context.ContextInfo context) Description copied from interface:ProductConsolidationContributorDetermines whether this contributor should be executed based on the given parameters and context.Returns true by default.
- Parameters:
productIds- the IDs of the products to consolidateproducts- the product in all explicit context statesinheritanceLines- the catalog inheritance lines top-down from all of the productscontext- context information surrounding sandboxing/multitenant state
-
consolidateProducts
public void consolidateProducts(Set<String> productIds, List<ConsolidatedProduct> products, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines, com.broadleafcommerce.data.tracking.core.context.ContextInfo context) This method is largely mimicking the structure ofContextualProductConsolidationContributor.consolidateProducts(Set, List, InheritanceLines, ContextInfo), but adapted slightly to tailor to this domain's use-case.- Specified by:
consolidateProductsin interfaceProductConsolidationContributor- Overrides:
consolidateProductsin classContextualProductConsolidationContributor<ProductCharacteristic>- Parameters:
productIds- the IDs of the products to consolidateproducts- the product in all explicit context statesinheritanceLines- the catalog inheritance lines top-down from all of the productscontext- context information surrounding sandboxing/multitenant state
-
getObjectsToConsolidate
protected List<ProductCharacteristic> getObjectsToConsolidate(Set<String> productIds, List<ConsolidatedProduct> products, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines, com.broadleafcommerce.data.tracking.core.context.ContextInfo context) The base class requires us to implement this abstract method, but we've overriddenconsolidateProducts(Set, List, InheritanceLines, ContextInfo)to callgetProdCharsAndRelatedDataToConsolidate(Set, List, InheritanceLines, ContextInfo)instead, and thus we will do nothing in this method but throw an exception.- Specified by:
getObjectsToConsolidatein classContextualProductConsolidationContributor<ProductCharacteristic>- Parameters:
productIds- the IDs of the products to consolidateproducts- the products in all explicit context statesinheritanceLines- the catalog inheritance lines top-down from all of the productscontext- context information surrounding sandboxing/multitenant state- Returns:
- N/A
-
getProdCharsAndRelatedDataToConsolidate
protected ProductCharacteristicsConsolidationContributor.ProductCharacteristicsConsolidationData getProdCharsAndRelatedDataToConsolidate(@NonNull @NonNull Set<String> productIds, @NonNull @NonNull List<ConsolidatedProduct> products, @NonNull @NonNull com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines, @NonNull @NonNull com.broadleafcommerce.data.tracking.core.context.ContextInfo context) -
extractBaseCharacteristicIdsFromProdChars
-
consolidateRelations
protected List<ConsolidatedProduct> consolidateRelations(List<ConsolidatedProduct> products, ProductCharacteristicsConsolidationContributor.ProductCharacteristicsConsolidationData prodCharsConsolidationData, Function<ProductCharacteristic, String> idGetter, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines) Loosely modeled after the baseContextualProductConsolidationContributor.consolidateRelations(List, List, BiConsumer, Function, InheritanceLines)method.- Parameters:
products- the product in all explicit context statesprodCharsConsolidationData- the prefetched consolidation dataidGetter- the operator to get the ID from the related domaininheritanceLines- the catalog inheritance lines top-down from all of the products- Returns:
- newly generated products which didn't match an existing product context
-
gatherProductCharacteristicsWithUnmatchedContexts
protected List<ProductCharacteristic> gatherProductCharacteristicsWithUnmatchedContexts(List<ConsolidatedProduct> productsWithSameId, List<ProductCharacteristic> prodCharsToCheckUnmatchedContextFor) -
createOverrideProductForContext
protected ConsolidatedProduct createOverrideProductForContext(com.broadleafcommerce.data.tracking.core.filtering.business.domain.ContextState unmatchedContextState, List<ProductCharacteristic> relations, ConsolidatedProduct implicitProduct, BiConsumer<ConsolidatedProduct, List<ProductCharacteristic>> setRelation, Function<ProductCharacteristic, String> idGetter, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines) Overrides the base method to only generate the clone override and not actually set anything, since we want to do that in a later step.- Overrides:
createOverrideProductForContextin classContextualProductConsolidationContributor<ProductCharacteristic>- Parameters:
unmatchedContextState- the context state to create an override product forrelations- the related domain in all explicit context statesimplicitProduct- the implicitly resolved product for the relation's contextsetRelation- the operator to set the related domain value on the productidGetter- the operator to get the ID from the related domaininheritanceLines- the catalog inheritance lines top-down from all of the products- Returns:
- just the clone override generated product, without invoking any characteristic hydration on it
-
applyHydrationToProduct
protected void applyHydrationToProduct(ConsolidatedProduct product, ProductCharacteristicsConsolidationContributor.ProductCharacteristicsConsolidationData prodCharsConsolidationData, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines) -
collectMostDerivedProductCharacteristicsByProductId
protected Map<String,List<ProductCharacteristic>> collectMostDerivedProductCharacteristicsByProductId(com.broadleafcommerce.data.tracking.core.filtering.business.domain.ContextState productContext, List<ProductCharacteristic> allUnnarrowedProdChars, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines) This method tries to mimic whatProductCharacteristicService.readAllByProductContextIdIn(Collection, ContextInfo)normally provides to the characteristic hydration flow, which would be all the 'most derived' representations of theProductCharacteristicinstances belonging to a particular context. In this case we find the 'most derived' representations visible from the context matching a given product representation.- Parameters:
productContext- context state of the product for which we are gathering characteristicsallUnnarrowedProdChars- all unnarrowed product characteristics that were found in the DB for this productinheritanceLines- catalog inheritance lines that can be used to determine parent/child relationships- Returns:
- a value that can be used in
ResolvedProductReferences.getProductCharacteristicsByProductId()
-
collectProductCharacteristicsFromInheritanceLineByProductId
protected Map<String,List<ProductCharacteristic>> collectProductCharacteristicsFromInheritanceLineByProductId(com.broadleafcommerce.data.tracking.core.filtering.business.domain.ContextState productContext, List<ProductCharacteristic> allUnnarrowedProdChars, com.broadleafcommerce.data.tracking.core.tenant.domain.InheritanceLines inheritanceLines) This method tries to mimic what
ProductCharacteristicService.readAllByProductContextIdAndInheritanceLine(Collection, ContextInfo)normally provides to the characteristic hydration flow. That method doesn't work in an ignore-narrowing context (and we already have fetched everything in memory anyway), so we have to replicate its filtration semantics here in memory for the context matching a given product representation.Note that the semantics of only considering ancestor catalog records that are
TrackingLevel.PRODUCTIONis meaningful for two reasons. First, it makes the logic consistent with how catalog overrides traditionally work for other fields, as noted inCustomizedProductCharacteristicRepository.findAllByProductContextIdAndInheritanceLine(Collection, ContextInfo). Second, by only including production records from ancestors, we avoid a hairy problem in this reindexing flow about generating a huge number of additional 'override product' instances. For example, if value narrowing could come be influenced by ancestor catalog sandbox records, it would mean that if there was a production level record in childCatalog, and there was also a sandbox change in parentCatalog, we would need to generate both a production and sandbox representation of the childCatalog record for prod and non-prod contexts. And this would unwind further for every context permutation on every characteristic on each product. We avoid this issue altogether thanks to the production inheritance limitation.Note: This method must stay in sync with the logic in
JpaCustomizedProductCharacteristicRepository.refineProductCharacteristicAncestries(List).- Parameters:
productContext- context state of the product for which we are gathering characteristicsallUnnarrowedProdChars- all unnarrowed product characteristics that were found in the DB for this productinheritanceLines- catalog inheritance lines that can be used to determine parent/child relationships- Returns:
- a value that can be used in
ResolvedProductReferences.getProductCharacteristicsFromInheritanceLineByProductId()
-
refineProductCharacteristicAncestries
protected List<ProductCharacteristic> refineProductCharacteristicAncestries(List<ProductCharacteristic> candidates) Refines the raw ancestry of product characteristics to ensure it only contains exactly one record per catalog level, and that all returned records belong to the same logical
Context IDfor any givenfieldName.See the Javadocs of
ProductCharacteristicService.deduplicateProductCharacteristicsByFieldName(List)for an explanation of the edge case regarding inadvertent ancestry mixing for the same logical field name that this method is addressing.This method applies a 3-step reduction algorithm:
- Identify the "Winning" Product Characteristic Context ID: Group by
(productId, fieldName)and find the record with the maximumtracking.catalog.level(deepest catalog). If tied, pick the minimumtracking.level(Sandbox wins over Prod). We know that we only care about bringing in the ancestry for the product characteristic context ID that represents the 'most derived' record visible in the context for a given field name. - Purge Orphan Lineages (Whitelist): Filter the raw records to keep only those whose Context ID matches the "Winning" Context ID for their respective field.
- Resolve Sandbox States Per Catalog: Within this refined, single-ID ancestry line,
group by
catalogIdand reduce down to a single record by picking the one with the minimumtracking.level. This guarantees Sandbox overrides win against Production baselines within the same catalog tier.
Note: This method must stay in sync with the logic in
JpaCustomizedProductCharacteristicRepository.refineProductCharacteristicAncestries(List).- Parameters:
candidates- the list of product characteristics to process- Returns:
- a list of product characteristics where only the instance with the lowest tracking level per catalog and field name is preserved, belonging to a refined ancestry
- Identify the "Winning" Product Characteristic Context ID: Group by
-
getCatalogLevel
-
getMostSpecificCatalogIdNullSafe
@Nullable protected String getMostSpecificCatalogIdNullSafe(@Nullable com.broadleafcommerce.data.tracking.core.filtering.business.domain.ContextState contextState) -
getSandboxLevelNullSafe
@Nullable protected Integer getSandboxLevelNullSafe(@Nullable com.broadleafcommerce.data.tracking.core.filtering.business.domain.ContextState contextState) -
deepCloneProductCharacteristic
-
productIdGetter
Description copied from class:ContextualProductConsolidationContributorDefines the function which retrieves the Product ID from the domain object to consolidate, in order to group it with the appropriate product for processing.- Specified by:
productIdGetterin classContextualProductConsolidationContributor<ProductCharacteristic>- Returns:
- function to retrieve Product ID of the domain object
-
setter
Description copied from class:ContextualProductConsolidationContributorDefines the function which should be used to set the domain objects on the consolidated product.- Specified by:
setterin classContextualProductConsolidationContributor<ProductCharacteristic>- Returns:
- function to set domain objects on the consolidated product
-
idGetter
Description copied from class:ContextualProductConsolidationContributorDefines the function which retrieves the contextId of the domain object in order to recognize it in different contexts.- Specified by:
idGetterin classContextualProductConsolidationContributor<ProductCharacteristic>- Returns:
- function to retrieve contextId of the domain object
-
getProductCharacteristicService
-
getCharacteristicService
-
getCharacteristicHydrationService
-
getBusinessTypeService
-
getProductHydrationService
-
getConsolidationBusinessTypeHydrationUtil
-