Broadleaf Microservices
  • v1.0.0-latest-prod

Data Tracking Release Notes for 2.0.7-GA

  • The 2.x versions are Spring Boot 3 compatible.

Spring Boot Upgrade

  • As of Broadleaf Release Train 2.3.0-GA, support for Spring Boot 3.3 & 3.5 for all common libraries has been added.

Introduce Support for Optimized Catalog Hierarchy Propagation

When changes to a catalog-discriminated entity (ex: Product) are deployed to production, there is a 'propagation' process executed to cascade update any downstream catalog overrides with the changes within (unless the downstream record has already overridden the changed fields).

This is an expensive operation, and in projects with large numbers of child catalogs and child catalog overrides, this can become a performance hotspot.

With this release, we are introducing optional support for a different propagation design that can more efficiently propagate over large quantities of override records.

Please see Optimized Hierarchy Propagation documentation for more details.

  • Introduce a completely new alternative set of components called HierarchyPropagationHandler. Unlike PropagationHandler, which focuses on propagating a single record at a time (and relies on DefaultPropagationManager to do the work of recursing through the hierarchy), these implementations are capable of completing the full end-to-end propagation process for the entire hierarchy all on their own. This API contract enables much more powerful handler implementations that can batch propagate through entire ancestries much more quickly than the current flow.

  • Support for HierarchyPropagationHandler components is disabled by default. However, if enabled, DefaultPropagationManager will find the first such component which can handle the flow and delegate to it if available. If no HierarchyPropagationHandler is available, propagation falls back to the existing standard propagation flow.

  • Introduce a SimpleDeleteHierarchyPropagationHandler which delegates to a new method in JpaTrackableRepository to batch update entities as archived

  • Introduce a new SimpleCreateHierarchyPropagationHandler which short-circuits create propagation as a no-op

  • Introduce a new PerFieldUpdateHierarchyPropagationHandler which propagates changes for each field individually, delegating to FieldUpdatePropagator components to do so. By default, the only such propagator is SimpleFieldUpdatePropagator, which leverages new methods on JpaTrackableRepository to detect if a field is a simple field (can be easily compared and set in a single UPDATE statement) and execute an update statement to propagate changes on that field if it’s simple. If SimpleFieldUpdatePropagator is insufficient for a particular client’s needs, a new FieldUpdatePropagator can easily be registered with higher precedence to handle the specific field on the specific entity.

  • To support the simple field update propagation, JpaTrackableRepository was updated to now inject the NativeSqlStrategyManager to allow delegation to NativeSqlStrategy beans.

  • Defined new NativeSqlStrategy beans to implement the native SQL generation for the interesting fields. These are supported by new HibernateColumnResolverUtility for column mapping detection, as well as new methods in EntityUtils to detect entity field definition information, including any converter that might be being used for the field.

Bug Fixes

  • Updated JpaTrackableRepository.findByContextIdAndCatalog to detect if the current entity is sandbox-discriminated, and if so, add filters to ensure only production and non-sandbox-archived records are returned.

    • This fixes a bug with the default catalog propagation logic, which used this method to locate instances to propagate changes to. Without these additional filters, the result of the query was not deterministic and could result in propagation being applied to the wrong instance.

  • Fixed an issue where the incorrect tracking level causes the creation of a redundant notification state for the ChangeSummaryProducer#TYPE and an event with a null author and sandbox

    • NOTE: The method com.broadleafcommerce.data.tracking.core.mapping.TrackableDomainMapperMemberSupport.buildTracking is overloaded, and a new parameter is added. This may cause a breaking change if the method is overridden. The old method will no longer be called by the com.broadleafcommerce.data.tracking.core.transition.VendorSandboxPropagationHandler. If you have any customizations, please make sure to update them.

  • Added a cache invalidator to clear application cache to fix an issue where products from an unassigned and deleted catalog can still be searched and accessed on a storefront

  • Fixed an issue where methods in DefaultTrackablePolicyUtils that use Assert.notNull to check when catalogs are archived would throw an error instead of gracefully handling the policy validation failure

  • Fixed an issue where 'Undo Overrides' could be requested on an inherited entity and directly mutate the instance in the parent catalog

    • DefaultTrackableDomainMapperMemberSupport.handleDelete has been updated to reject 'clear override' requests if the target entity is not directly located in the catalog defined in the context request

Miscellaneous

  • Introduced a mechanism to allow the NotificationState for SingleIndexRequest messages to be built, even if SuppressNotificationContext is enabled

    • Previously, when SuppressNotificationContext was active for SingleIndexRequest during a CRUD flow, SingleIndexRequestNotificationStateMapperMember would always cease to build the NotificationState for it. This is still the default behavior, but now, there is a new SingleIndexRequestNotificationStateBuildContext ThreadLocal that can be activated to force the NotificationState to still be built in those flows. Using this will mean that on a CRUD operation, the NotificationState will still be built, but the first 'eager' send attempt of that message will not happen until the retry handler picks it up later.

    • Example of usage

      return SingleIndexRequestNotificationStateBuildContext.doWithForceBuildEnabled(() -> {
          return SuppressNotificationContext.exec(() -> {
              // invoke CRUD method that engages the mapping + persistence flows
              return replace(id, businessInstance, context);
          }, SingleIndexRequestProducer.TYPE);
      });
  • Updated various methods in CrudEntityHelper to be protected instead of private, improving extensibility of the class

  • Updated SortPositionRequest in accordance with Jackson library upgrade to enable seamless JSON deserialization

  • Enhanced performance of standard recursive catalog propagation flow

    • Introduced a net new PropagationCandidateFinderRepositoryFragment interface with a new bulk findByContextIdAndCatalogIn method.

    • Updated JpaTrackableRepository to implement that interface, and updated JpaTrackableRepositoryFactory to explicitly expose that interface on the final repository proxy instance

    • Updated DefaultPropagationManager to utilize the new batch query instead of querying for override records one child catalog at a time

      Note
      Please see Propagation Manager Properties for configuration options on the batch size.
  • Updated DefaultPropagationHandler to gate the emission of PERSISTENCE notifications on a new property. The default is still enabled for backward compatibility, but this feature now allows clients to disable that process for less noise and improved performance.

    Note
    Please see Default Propagation Handler Properties for configuration options.
  • Introduced new overrideCatalogLevel and creatingApplicationId fields to ContextState, and updated ContextStateBuilder to initialize them

    • overrideCatalogLevel is not serialized in API responses by default, but serves as a mechanism for internal service components to know the level of the catalog in overrideCatalogId, if set

    • creatingApplicationId is serialized in API responses and is also available for internal service components to know which application owns the entity (if the entity is in an application-owned catalog)