Class AnnotatedSaga<T>

java.lang.Object
org.axonframework.modelling.saga.AnnotatedSaga<T>
All Implemented Interfaces:
DescribableComponent, MessageHandler, EventHandler, EventHandlingComponent, ReplayStatusChangedHandler, ResetHandler, Saga<T>, SagaLifecycle

public class AnnotatedSaga<T> extends Object implements Saga<T>, SagaLifecycle
Implementation of the interface that allows for a POJO instance with annotated message handlers to act as a Saga. The POJO instance can access SagaLifecycle operations, such as associateWith and end, by declaring a SagaLifecycle-typed parameter on its @SagaEventHandler method. This AnnotatedSaga instance registers itself as the active SagaLifecycle on the ProcessingContext for the duration of a single event handler invocation, so the parameter always resolves to this instance.

A @SagaEventHandler method must complete on the thread that invoked it. Returning a result that is not done yet fails handling with a SagaExecutionException, because the Saga is stored in the invoking thread's transaction and work continuing on another thread would fall outside it. Axon Framework 4 had no way to express an asynchronous handler at all, so nothing that worked there is refused here.

While a handler method runs, this Saga is the current Scope, as it was in Axon Framework 4. Code reached from the handler on the same thread, such as a DeadlineManager, can therefore describe the Saga through Scope.describeCurrentScope() and reach the handler's ProcessingContext through ContextAwareScope.currentProcessingContext(), without being handed either of them.

Since:
3.0
Author:
Allard Buijze
  • Constructor Details

    • AnnotatedSaga

      public AnnotatedSaga(String sagaId, Set<AssociationValue> associationValues, T annotatedSaga, SagaModel<T> metaModel, MessageHandlerInterceptorMemberChain<T> chainedInterceptor)
      Creates an AnnotatedSaga instance to wrap the given annotatedSaga, identifier with the given sagaId and associated with the given associationValues. The metaModel provides the description of the structure of the Saga.
      Parameters:
      sagaId - The identifier of this Saga instance
      associationValues - The current associations of this Saga
      annotatedSaga - The object instance representing the Saga
      metaModel - The model describing Saga structure
      chainedInterceptor - The interceptor to be used for this Saga
  • Method Details

    • getSagaIdentifier

      public String getSagaIdentifier()
      Description copied from interface: Saga
      Returns the unique identifier of this saga.
      Specified by:
      getSagaIdentifier in interface Saga<T>
      Returns:
      the unique identifier of this saga
    • getAssociationValues

      public AssociationValues getAssociationValues()
      Description copied from interface: Saga
      Returns a view on the Association Values for this saga instance. The returned instance is mutable.
      Specified by:
      getAssociationValues in interface Saga<T>
      Returns:
      a view on the Association Values for this saga instance
    • invoke

      public <R> R invoke(Function<T,R> invocation)
      Description copied from interface: Saga
      Execute the given invocation against the root object of this Saga instance.
      Specified by:
      invoke in interface Saga<T>
      Type Parameters:
      R - The type of return value expected
      Parameters:
      invocation - the function to invoke. The root object of the Saga is input to the function, the result is the result of the execution.
      Returns:
      The result of the invocation on the Saga.
    • execute

      public void execute(Consumer<T> invocation)
      Description copied from interface: Saga
      Execute the given invocation against the root object of this Saga instance.
      Specified by:
      execute in interface Saga<T>
      Parameters:
      invocation - the function to invoke. The root object of the Saga is input to the function.
    • isActive

      public boolean isActive()
      Description copied from interface: Saga
      Indicates whether or not this saga is active. A Saga is active when its life cycle has not been ended.
      Specified by:
      isActive in interface Saga<T>
      Returns:
      true if this saga is active, false otherwise.
    • supportedEvents

      public Set<QualifiedName> supportedEvents()
      Description copied from interface: EventHandlingComponent
      All supported events, referenced through a QualifiedName.
      Specified by:
      supportedEvents in interface EventHandlingComponent
      Returns:
      All supported events, referenced through a QualifiedName.
    • canHandle

      public boolean canHandle(EventMessage event, ProcessingContext context)
      Description copied from interface: Saga
      Indicates whether this saga instance takes the given event, which is the case when it is active and holds the AssociationValue that one of its handlers for this event resolves from it.

      This answers a different question than EventHandlingComponent.supports(org.axonframework.messaging.core.QualifiedName), which reports the events the saga type declares handlers for. Two saga instances of the same type therefore disagree here whenever they are associated with different values, and the component managing them needs that answer: a Saga that declines the event has not taken it, so a SagaCreationPolicy.IF_NONE_FOUND policy must still start a new instance. The returned MessageStream cannot express it, since a Saga that declines and a Saga that handled the event without producing anything both yield an empty stream.

      In Axon Framework 4 this method was inherited from MessageHandler, which Axon Framework 5 reduced to a marker interface, so the declaration lives here instead.

      Specified by:
      canHandle in interface Saga<T>
      Parameters:
      event - the event to check this saga instance against
      context - the ProcessingContext in which the event is being processed
      Returns:
      true when this saga instance takes the given event, false otherwise
    • handle

      public MessageStream.Empty<Message> handle(EventMessage event, ProcessingContext context)
      Description copied from interface: EventHandler
      Handles the given event within the given context.

      The result of handling is an empty stream.

      Specified by:
      handle in interface EventHandler
      Parameters:
      event - The event to handle.
      context - The context to the given event is handled in.
      Returns:
      An empty stream containing nothing.
    • root

      public T root()
      Returns the (annotated) Saga instance.
      Returns:
      the Saga instance
    • associateWith

      public void associateWith(AssociationValue associationValue)
      Description copied from interface: SagaLifecycle
      Registers the given associationValue with the current Saga. When the saga is committed, it can be found using the registered property. If the saga already has the given association, nothing happens.
      Specified by:
      associateWith in interface SagaLifecycle
      Parameters:
      associationValue - the association to associate this saga with
    • removeAssociationWith

      public void removeAssociationWith(AssociationValue associationValue)
      Description copied from interface: SagaLifecycle
      Removes the given associationValue from the current Saga. When the saga is committed, it can no longer be found using the given association value. If the given saga wasn't associated with the given value, nothing happens.
      Specified by:
      removeAssociationWith in interface SagaLifecycle
      Parameters:
      associationValue - the association value to remove from this saga
    • end

      public void end()
      Description copied from interface: SagaLifecycle
      Marks the saga as ended. Ended sagas may be cleaned up by the repository when they are committed.
      Specified by:
      end in interface SagaLifecycle
    • associationValues

      public Set<AssociationValue> associationValues()
      Description copied from interface: SagaLifecycle
      Retrieves the AssociationValues that have been associated with the current Saga so far. This includes the uncommitted ones, so adding or removing an AssociationValue through SagaLifecycle.associateWith(AssociationValue) or any other method will have an immediate effect.
      Specified by:
      associationValues in interface SagaLifecycle
      Returns:
      the AssociationValues that have been associated with the Saga so far
    • 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.