Class ProductCharacteristicManagementUtility<P extends Product>

java.lang.Object
com.broadleafcommerce.catalog.service.product.util.ProductCharacteristicManagementUtility<P>
Type Parameters:
P - the type of Product this utility is for.

public class ProductCharacteristicManagementUtility<P extends Product> extends Object
Utility component for managing product characteristics. This class provides a centralized and reusable way to handle the complexities of creating, updating, and managing product characteristics, especially in relation to business types and inheritance.

It is designed to be used by services that need to manage product characteristics as part of their business logic.

  • Constructor Details

  • Method Details

    • manageProductCharacteristics

      public ProductCharacteristicManagementResult manageProductCharacteristics(ProductCharacteristicManagementRequest request, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo context)
      Manages the characteristics for a batch of products. This method orchestrates the process of identifying which characteristics are new, which are updated, and which are unchanged, and then persists those changes.
      Parameters:
      request - a ProductCharacteristicManagementRequest containing the products and their requested characteristics
      context - the context information for the request
      Returns:
      a ProductCharacteristicManagementResult containing the latest state of the product characteristics for all processed products
    • hydrateBusinessTypes

      protected Map<String,BusinessType> hydrateBusinessTypes(ProductCharacteristicManagementRequest request, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo context)
      Hydrates the business types for the products in the request.
      Parameters:
      request - the management request
      context - the context info
      Returns:
      a map of business types by their type key
    • getExistingCharacteristics

      protected Map<String,List<ProductCharacteristic>> getExistingCharacteristics(Set<String> productIds, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo context)
      Retrieves the existing product characteristics for the given product IDs.
      Parameters:
      productIds - the set of product IDs
      context - the context info
      Returns:
      a map of existing characteristics grouped by product ID
    • getProdCharsByIdByProductId

      protected Map<String,Map<String,ProductCharacteristic>> getProdCharsByIdByProductId(Map<String,List<ProductCharacteristic>> existingCharacteristicsByProdId)
      Organizes existing product characteristics into a nested map structure for efficient lookup.
      Parameters:
      existingCharacteristicsByProdId - A map where keys are product IDs and values are lists of ProductCharacteristics associated with that product.
      Returns:
      A nested map where the outer key is the product ID, and the inner map's key is the product characteristic ID, with the ProductCharacteristic as the value. This facilitates quick access to a specific characteristic of a specific product.
    • identifyCharacteristicsToCreate

      protected List<ProductCharacteristic> identifyCharacteristicsToCreate(ProductCharacteristicManagementRequest request, Map<String,List<ProductCharacteristic>> existingCharacteristicsByProdId, Map<String,BusinessType> businessTypesByKey, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo context)
      Identifies the product characteristics that need to be created.
      Parameters:
      request - the management request
      existingCharacteristicsByProdId - the map of existing characteristics
      businessTypesByKey - the map of business types
      context - the context info
      Returns:
      a list of characteristics to create
    • identifyCharacteristicsToUpdate

      protected List<com.broadleafcommerce.data.tracking.core.service.Update<ProductCharacteristic>> identifyCharacteristicsToUpdate(ProductCharacteristicManagementRequest request, Map<String,List<ProductCharacteristic>> existingCharacteristicsByProdId, Map<String,BusinessType> businessTypesByKey, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo context)
      Identifies the product characteristics that need to be updated.
      Parameters:
      request - the management request
      existingCharacteristicsByProdId - the map of existing characteristics
      businessTypesByKey - the map of business types
      context - the context info
      Returns:
      a list of updates for characteristics
    • persistCharacteristicChanges

      protected void persistCharacteristicChanges(List<ProductCharacteristic> toCreate, List<com.broadleafcommerce.data.tracking.core.service.Update<ProductCharacteristic>> toUpdate, Map<String,Map<String,ProductCharacteristic>> prodCharsByIdByProductId, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo context)
      Persists the created and updated characteristics.
      Parameters:
      toCreate - the list of characteristics to create
      toUpdate - the list of characteristics to update
      prodCharsByIdByProductId - the map to store the persisted characteristics
      context - the context info
    • buildResult

      protected ProductCharacteristicManagementResult buildResult(Map<String,Map<String,ProductCharacteristic>> prodCharsByIdByProductId)
      Builds the final result from the persisted characteristics.
      Parameters:
      prodCharsByIdByProductId - the map of persisted characteristics
      Returns:
      the product characteristic management result
    • mapLatestCharacteristicsStateOntoResponse

      public void mapLatestCharacteristicsStateOntoResponse(com.broadleafcommerce.data.tracking.core.service.BulkPersistenceResponse<P> response, ProductCharacteristicManagementResult latestState)
      Maps the latest characteristic state onto a bulk persistence response. This ensures that the product instances in the response reflect the most up-to-date characteristic values.
      Parameters:
      response - the bulk persistence response
      latestState - the result from the characteristic management process
    • mapLatestCharacteristicsStateOntoResponse

      public void mapLatestCharacteristicsStateOntoResponse(P response, ProductCharacteristicManagementResult latestState)
      Maps the latest characteristic state onto a single product response.
      Parameters:
      response - the product response
      latestState - the result from the characteristic management process
    • mapLatestCharacteristicsStateOntoResponse

      public void mapLatestCharacteristicsStateOntoResponse(List<P> response, ProductCharacteristicManagementResult latestState)
      Maps the latest characteristic state onto a list of product responses.
      Parameters:
      response - the list of product responses
      latestState - the result from the characteristic management process
    • forceInitializeProductIdValueOnProdChars

      protected void forceInitializeProductIdValueOnProdChars(@Nullable Map<String,List<ProductCharacteristic>> requestedCharacteristicsByProductId)
      The API caller may or may not have set ProductCharacteristic.getProductId() on the API payload (and almost certainly not if this is a create operation). We force-set the value here to match the ID of the product the characteristics were provided under. This guarantees the API caller neither has to supply the value, nor can they accidentally affect characteristics of unintended unrelated products by supplying an invalid product ID.
      Parameters:
      requestedCharacteristicsByProductId - the caller provided characteristics values mapped by product id
    • isNewCharacteristic

      protected boolean isNewCharacteristic(ProductCharacteristic pc, Map<String,List<ProductCharacteristic>> existingCharacteristicsByProdId)
      Checks if the characteristic is considered new.

      A characteristic is new if it has a null ID, or if it has an ID but that ID is not found in the existing characteristics for the product.

      Parameters:
      pc - the characteristic to check
      existingCharacteristicsByProdId - the map of existing characteristics by product ID
      Returns:
      true if new, false otherwise
    • isExistingCharacteristic

      protected boolean isExistingCharacteristic(ProductCharacteristic pc, Map<String,List<ProductCharacteristic>> existingCharacteristicsByProdId)
      Checks if the characteristic already exists.

      A characteristic exists if it has a non-null ID and that ID is found in the existing characteristics for the product.

      Parameters:
      pc - the characteristic to check
      existingCharacteristicsByProdId - the map of existing characteristics by product ID
      Returns:
      true if existing, false otherwise
    • matchesParentBusinessType

      protected boolean matchesParentBusinessType(ProductCharacteristic pc, @Nullable BusinessType bt)
      Checks if the given ProductCharacteristic exactly matches the characteristic value defined on the parent BusinessType.
      Parameters:
      pc - the incoming product characteristic
      bt - the parent business type
      Returns:
      true if the provided product characteristic details match their counterparts in the parent business type
    • shouldUpdateCharacteristic

      protected boolean shouldUpdateCharacteristic(ProductCharacteristic pc, Map<String,List<ProductCharacteristic>> existingCharacteristics, Map<String,BusinessType> businessTypesByKey, Map<String,P> productsById)
      Checks if the value of a ProductCharacteristic has changed compared to the existing characteristics.

      This method looks up the existing characteristic in the provided map using the product ID and characteristic ID. If found, it delegates to areCharacteristicValuesDifferent(ProductCharacteristic, ProductCharacteristic, Map, Map) to compare values.

      If the characteristic is not found in the existing map (but has an ID), this returns true to ensure an update is attempted.

      Parameters:
      pc - the incoming product characteristic to check
      existingCharacteristics - a map of existing characteristics grouped by product ID
      Returns:
      true if the value has changed or the characteristic is not found, false otherwise
    • areCharacteristicValuesDifferent

      protected boolean areCharacteristicValuesDifferent(ProductCharacteristic pc, ProductCharacteristic existingProductCharacteristic, Map<String,BusinessType> businessTypesByKey, Map<String,P> productsById)
      Compares the values of an incoming ProductCharacteristic with an existing one to determine if they are different.

      For non-enum field types, this filters the existing values to only include active ones before comparing.

      Parameters:
      pc - the incoming product characteristic
      existingProductCharacteristic - the existing product characteristic from the database
      Returns:
      true if the values are different, false otherwise
    • matchExistingCharacteristicByFieldNameAndSetId

      protected ProductCharacteristic matchExistingCharacteristicByFieldNameAndSetId(ProductCharacteristic pc, Map<String,List<ProductCharacteristic>> existingCharacteristics)
      Matches an incoming product characteristic to an existing one based on field name.

      If a match is found in the provided map of existing characteristics (keyed by product ID), the ID of the incoming characteristic is updated to match the existing one. This ensures that updates happen instead of deletes.

      Parameters:
      pc - the incoming product characteristic to match
      existingCharacteristics - a map of existing characteristics grouped by product ID
    • setOverrideChangeContainer

      protected ProductCharacteristic setOverrideChangeContainer(ProductCharacteristic pc, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo context)
      Sets the override change container on the ProductCharacteristic to ensure it is tracked under the product's change container context.

      If a change container is present on the context request, it is copied to preserve context (like catalog and route key).

      This sets the container ID to the product ID from the characteristic, and sets the container name and sub-container name to "PRODUCT" and "PRODUCT_CHARACTERISTIC" respectively. This ensures that changes to the characteristic are grouped with the product.

      Parameters:
      pc - the product characteristic to update
      context - context information containing the request context
      Returns:
      the product characteristic with the override change container set
    • copyChangeContainer

      protected com.broadleafcommerce.data.tracking.core.filtering.domain.ChangeContainer copyChangeContainer(com.broadleafcommerce.data.tracking.core.filtering.domain.ChangeContainer changeContainer)
      Creates a copy of the given ChangeContainer. This is used to ensure that each characteristic has its own change container instance, preventing unintended side effects.
      Parameters:
      changeContainer - the change container to copy
      Returns:
      a new instance of ChangeContainer with the same properties as the original
    • getTypeFactory

      protected com.broadleafcommerce.common.extension.TypeFactory getTypeFactory()
    • getProductCharacteristicService

      protected ProductCharacteristicService<ProductCharacteristic> getProductCharacteristicService()
    • getBusinessTypeService

      protected BusinessTypeService<BusinessType> getBusinessTypeService()