Class HierarchicalStateManager

java.lang.Object
org.axonframework.modelling.HierarchicalStateManager
All Implemented Interfaces:
DescribableComponent, StateManager

public class HierarchicalStateManager extends Object implements StateManager
StateManager that can load an entity from two delegates, giving preference to the child delegate and then the parent. This is useful to encapsulate a set of repositories that are only relevant in a specific context, such as a specific Module.

Any registrations of Repository will be done on the child StateManager.

Since:
5.0.0
Author:
Mitchell Herrijgers
  • Method Details

    • create

      public static HierarchicalStateManager create(StateManager parent, StateManager child)
      Creates a new hierarchical StateManager that delegates to the given parent and child managers, giving preference to the child manager.
      Parameters:
      parent - The parent StateManager to delegate if the child StateManager cannot load the entity.
      child - The child StateManager to try first.
      Returns:
      A new hierarchical StateManager that delegates to the given managers.
    • register

      public <I, T> StateManager register(Repository<I,T> repository)
      Description copied from interface: StateManager
      Registers an Repository for use with this StateManager. The combination of Repository.entityType() and Repository.idType() must be unique for all registered repositories.
      Specified by:
      register in interface StateManager
      Type Parameters:
      I - the type of id
      T - the type of the entity
      Parameters:
      repository - the Repository to use for loading state
      Returns:
      this StateManager for fluent interfacing
    • loadManagedEntity

      public <I, T> CompletableFuture<ManagedEntity<I,T>> loadManagedEntity(Class<T> type, I id, ProcessingContext context)
      Retrieves a ManagedEntity of the given type and id. The CompletableFuture will resolve to a ManagedEntity, or complete exceptionally if it could not be resolved.

      Delegates directly to StateManager#loadManagedEntity(Class, Object, ProcessingContext) of the child, falling back to the parent when the child completes exceptionally with a MissingRepositoryException. Delegating the load itself, rather than first locating a Repository through repository(Class, Class) and invoking it here, ensures each delegate applies its own resolution semantics for type. SimpleStateManager, for instance, resolves a Repository registered for a supertype when asked for a subtype, whereas repository(Class, Class) only matches the exact registered type. Re-implementing that resolution here would either duplicate or diverge from the delegate's own behavior; calling loadManagedEntity avoids that entirely, and still composes correctly when the delegate is itself a HierarchicalStateManager.

      Delegates such as SimpleStateManager complete their CompletableFuture exceptionally rather than throwing MissingRepositoryException synchronously, so the parent fallback is expressed with CompletableFuture.exceptionallyCompose(java.util.function.Function) rather than a try/catch. The child call is nonetheless wrapped in FutureUtils.runFailing(java.util.function.Supplier) so a delegate that still throws MissingRepositoryException synchronously also triggers the fallback. Any other exception is propagated to the caller unchanged. Only MissingRepositoryException triggers the fallback; a LoadedEntityNotOfExpectedTypeException, for instance, does not, since by the time it surfaces the child's loadOrCreate may already have attached state to the ProcessingContext, making a retry against the parent unsound.

      Specified by:
      loadManagedEntity in interface StateManager
      Type Parameters:
      I - the type of the identifier of the entity
      T - the type of the entity
      Parameters:
      type - the type of state to retrieve
      id - the id of the state to retrieve
      context - the context to load the entity in
      Returns:
      a CompletableFuture which resolves to the entity instance, or completes exceptionally with a MissingRepositoryException when this StateManager does not control the Repository to load the ManagedEntity from
    • registeredEntities

      public Set<Class<?>> registeredEntities()
      Description copied from interface: StateManager
      The types of entities that are registered with this StateManager.
      Specified by:
      registeredEntities in interface StateManager
      Returns:
      the types of entities that are registered with this StateManager
    • registeredIdsFor

      public Set<Class<?>> registeredIdsFor(Class<?> entityType)
      Description copied from interface: StateManager
      The types of identifiers that are registered with this StateManager for the given entityType.
      Specified by:
      registeredIdsFor in interface StateManager
      Parameters:
      entityType - the type of the entity
      Returns:
      the types of identifiers that are registered with this StateManager for the given entityType
    • repository

      public <I, T> @Nullable Repository<I,T> repository(Class<T> entityType, Class<I> idType)
      Description copied from interface: StateManager
      Returns the Repository for the given type.

      Returns null if no repository is registered for the given type and id.

      Unlike StateManager.loadManagedEntity(Class, Object, ProcessingContext), which resolves a Repository registered for a supertype when asked for a subtype, this method only matches an exactly registered (entityType, idType) pair. Hence, there is no supertype or subtype resolution.

      Specified by:
      repository in interface StateManager
      Type Parameters:
      I - the type of the identifier of the entity
      T - the type of the entity
      Parameters:
      entityType - the type of the entity
      idType - the type of the identifier of the entity
      Returns:
      the Repository for the given idType and entityType
    • getParent

      public StateManager getParent()
      Returns the parent StateManager of this HierarchicalStateManager.
      Returns:
      The parent StateManager of this HierarchicalStateManager.
    • getChild

      public StateManager getChild()
      Returns the child StateManager of this HierarchicalStateManager.
      Returns:
      The child StateManager of this HierarchicalStateManager.
    • describeTo

      public void describeTo(ComponentDescriptor descriptor)
      Description copied from interface: DescribableComponent
      Describe the properties of this DescribableComponent with the given descriptor.

      Components should call the appropriate describeProperty methods on the descriptor to register their properties. The descriptor is responsible for determining how these properties are formatted and structured in the final output.

      Best Practices: As a general rule, all relevant fields of a DescribableComponent implementation should be described in this method. However, developers have discretion to include only the fields that make sense in the context. Not every field may be meaningful for description purposes, especially internal implementation details. Furthermore, components might want to expose different information based on their current state. The final decision on what properties to include lies with the person implementing the describeTo method, who should focus on providing information that is useful for understanding the component's configuration and state.

      Example implementation:

       public void describeTo(ComponentDescriptor descriptor) {
           descriptor.describeProperty("name", this.name);
           descriptor.describeProperty("enabled", this.enabled);
           descriptor.describeProperty("configuration", this.configuration); // A nested component
           descriptor.describeProperty("handlers", this.eventHandlers);      // A collection
       }
       
      Specified by:
      describeTo in interface DescribableComponent
      Parameters:
      descriptor - The component descriptor to describe this DescribableComponentn its properties in.