Annotation Type EnableJpaTrackableFlow


  • @Repeatable(EnableJpaTrackableFlows.class)
    @Target(TYPE)
    @Retention(RUNTIME)
    @Documented
    @Inherited
    @Import({JpaTrackableProjectionFactoryBeanRegistrar.class,com.broadleafcommerce.data.tracking.jpa.filtering.auto.JpaTrackableRepositoriesRegistrar.class,com.broadleafcommerce.data.tracking.jpa.filtering.auto.JpaTrackableServicesRegistrar.class,com.broadleafcommerce.data.tracking.jpa.filtering.auto.JpaTrackableApiRegistrar.class})
    public @interface EnableJpaTrackableFlow
    This annotation facilitates auto generation of boilerplate Trackable lifecycle components based on new persistence domain. In many cases, default CRUD behavior is all that's required for a new persistence domain class, and overall implementation simplicity will benefit from not having to implement multiple support components with common behavior. This annotations helps with that by engaging auto-generation of JpaTrackableRepository, RsqlCrudEntityService, and ProjectionReferencedApi components that comprise the main plumbing for interacting with a domain class via the admin. Note, metadata configuration and possibly permission configuration (i.e. auth service) are still required to complete a full admin experience.

    This process benefits from full autoconfiguration behavior. This means that you may explicitly declare one or all of these components (presumably with custom behavior), and the system will back off and not auto-generate those one or more components.

    Note that auto-generation of projections for a persistence domain class is outside the scope of influence of this annotation. Auto-generation of projections is handled automatically by the system and does not require an annotation to drive that behavior. However, aspects of how projections are generated can be customized, or suppressed. See ProjectionManager, AutoConfigureProjectionMapping, and ExplicitProjectionFieldConfiguration for more information on auto-generated projections.

    The basic use case would resemble the following in code when introducing a new persistence domain class as an addition to the Broadleaf catalog service. The configuration:
         @Configuration
         @EnableJpaTrackableFlow(entityClass = JpaWidget.class, routeKey = CATALOG_ROUTE_KEY, permissionRoots = "CATALOG", rootPath = "/widgets", projectionName = "Widget")
         @JpaEntityScan(basePackages = "com.mycompany.catalog.domain", routePackage = CATALOG_ROUTE_PACKAGE)
         public class MyConfig {
              ...
         }
     
    And, the persistence domain class:
         package com.mycompany.catalog.domain;
         
         ...
         
         @Entity
         @Table(name = "WIDGET")
         @Data
         @EqualsAndHashCode(exclude = "id")
         @EntityListeners(TrackingListener.class)
         public class JpaWidget implements Serializable, CatalogTrackable<CatalogJpaTracking> {
    
              private static final long serialVersionUID = 1L;
    
              @Id
              @GeneratedValue(generator = "blcid")
              @GenericGenerator(name = "blcid", strategy = "blcid")
              @Type(type = "com.broadleafcommerce.data.tracking.jpa.hibernate.ULidType")
              @Column(name = "ID", nullable = false)
              private String id;
    
              @Column(name = "CONTEXT_ID")
              @Convert(converter = UlidConverter.class)
              @FilterAndSortAlias("id")
              private String contextId;
    
              @Embedded
              private CatalogJpaTracking tracking;
    
              @Column(name = "NAME")
              private String name;
    
              @Column(name = "DESCRIPTION", length = JpaConstants.MEDIUM_TEXT_LENGTH)
              private String description;
    
         }
     
    Note, in the case above, the system would skip auto-generation of the projection class if the "Widget" class implemented BusinessTypeAware and ModelMapperMappable, which allows for more custom mapping from the persistence domain.

    Custom component registration is straightforward and allows for further refinement of behavior at one or more points in the CRUD lifecycle. Take, for example, the registration of a new BaseRsqlCrudEntityService component. The configuration:
         @Configuration
         @EnableJpaTrackableFlow(entityClass = JpaWidget.class, routeKey = CATALOG_ROUTE_KEY, permissionRoots = "CATALOG", rootPath = "/widgets", projectionName = "Widget")
         @JpaEntityScan(basePackages = "com.mycompany.catalog.domain", routePackage = CATALOG_ROUTE_PACKAGE)
         public class MyConfig {
              ...
              @Bean
              public MyProjectionService projectionService(TrackableRepository<JpaWidget> repository,
                         RsqlCrudEntityHelper helper) {
                  return new MyProjectionService(repository, helper);
              }
         }
     
    And, the custom service class:
         public class MyProjectionService extends BaseRsqlCrudEntityService<Projection<JpaWidget>> {
    
              public MyProjectionService(TrackableRepository<JpaWidget> repository,RsqlCrudEntityHelper helper) {
                  super(repository, helper);
              }
    
              @Override
              public Projection<Widget> update(String id, Projection<JpaWidget> projection, ContextInfo context) {
                  projection.expose().setName("override");
                  return super.update(id, businessInstance, context);
              }
          }
     
    The key revelation here is that the auto-generated components are typed against your auto-generated projection (or your explicit projection if you're implementing BusinessTypeAware and ModelMapperMappable). This takes the form of Projection<T> where 'T' is the persistence domain class. If you need to retrieve or manipulate the values in the projection, you may call Projection.expose() and exercise the API of 'T' against the Projection instance.
    Author:
    Jeff Fischer
    • Required Element Summary

      Required Elements 
      Modifier and Type Required Element Description
      Class<?> entityClass
      The JPA entity class from which to derive service lifecycle components.
      String[] permissionRoots
      List of one or more permissions required to access the API.
      String rootPath
      The root path to use for request pattern matching for the service API.
      String routeKey
      When data routing is enabled for composite services (default is true), the data route key for which the generated trackable flows should subscribe must be included.
    • Optional Element Summary

      Optional Elements 
      Modifier and Type Optional Element Description
      String projectionName
      Represents the simple class name that will be generated for the auto created projection.
    • Field Detail

      • ROUTE_KEY_NONE

        static final String ROUTE_KEY_NONE
    • Element Detail

      • entityClass

        Class<?> entityClass
        The JPA entity class from which to derive service lifecycle components. This includes dynamic Projection creation (optional), BaseTrackableRepository creation, BaseRsqlCrudEntityService creation, and RestController implementation creation.
        Returns:
        The JPA entity class from which to derive service lifecycle components.
      • routeKey

        String routeKey
        When data routing is enabled for composite services (default is true), the data route key for which the generated trackable flows should subscribe must be included. This relates to JpaDataRoute.routeKey() and is required when adding new domain to an existing composite service. If data routing is disabled, set this parameter to ROUTE_KEY_NONE.
        Returns:
        The identifying key for the data route to use in a composite service.
      • permissionRoots

        String[] permissionRoots
        List of one or more permissions required to access the API. It is assumed the permission(s) are already appropriately registered with the security infrastructure and available for recognition during policy enforcement. See Policy.permissionRoots() for more information. If more granular control over permissions per service API method is required, consider implementing a custom controller marked with the ProjectionReferencedApi interface in order to make this auto generation flow back off. At that point, in the custom controller, you are free to annotate each request method with different policy requirements.
        Returns:
        List of one or more permissions required to access the API.
      • rootPath

        String rootPath
        The root path to use for request pattern matching for the service API. The root path will be built upon to create the various CRUD endpoints for management of the domain. The path should begin with a forward slash (e.g. /widgets).
        Returns:
        The root path to use for request pattern matching for the service API.
      • projectionName

        String projectionName
        Represents the simple class name that will be generated for the auto created projection. The package to which this generated class belongs is harvested from the entityClass(). This class name is used in some admin UI elements, so for the best experience, it's recommended to set a value here. The projection name must be different than the simple name of entityClass(). Note, if entityClass() implements BusinessTypeAware, then you would leave this value blank.
        Returns:
        The simple class name for the generated projection class.
        Default:
        ""