/**
  * Create a SagaMethodMessageHandler for the given <code>methodHandler</code>. The
  * SagaMethodMessageHandler add information specific to the behavior of Sagas, such as the
  * association value and creation policy.
  *
  * @param methodHandler The handler for incoming events
  * @return a SagaMethodMessageHandler for the handler
  */
 public static SagaMethodMessageHandler getInstance(MethodMessageHandler methodHandler) {
   Method handlerMethod = methodHandler.getMethod();
   SagaEventHandler handlerAnnotation = handlerMethod.getAnnotation(SagaEventHandler.class);
   String associationPropertyName = handlerAnnotation.associationProperty();
   Method associationProperty;
   try {
     associationProperty =
         methodHandler.getPayloadType().getMethod(methodForProperty(associationPropertyName));
   } catch (NoSuchMethodException e) {
     throw new AxonConfigurationException(
         format(
             "SagaEventHandler %s.%s defines a property %s that is not "
                 + "defined on the Event it declares to handle (%s)",
             methodHandler.getMethod().getDeclaringClass().getName(),
             methodHandler.getMethodName(),
             associationPropertyName,
             methodHandler.getPayloadType().getName()),
         e);
   }
   String associationKey =
       handlerAnnotation.keyName().isEmpty()
           ? associationPropertyName
           : handlerAnnotation.keyName();
   StartSaga startAnnotation = handlerMethod.getAnnotation(StartSaga.class);
   SagaCreationPolicy sagaCreationPolicy;
   if (startAnnotation == null) {
     sagaCreationPolicy = SagaCreationPolicy.NONE;
   } else if (startAnnotation.forceNew()) {
     sagaCreationPolicy = SagaCreationPolicy.ALWAYS;
   } else {
     sagaCreationPolicy = SagaCreationPolicy.IF_NONE_FOUND;
   }
   return new SagaMethodMessageHandler(
       sagaCreationPolicy, methodHandler, associationKey, associationProperty);
 }
  @PostConstruct
  @SuppressWarnings({"unchecked"})
  @Override
  public synchronized void subscribe() {
    for (final MethodMessageHandler commandHandler : inspector.getHandlers()) {
      CommandHandler<Object> handler =
          new CommandHandler<Object>() {
            @Override
            public Object handle(CommandMessage<Object> command, UnitOfWork unitOfWork)
                throws Throwable {
              T aggregate = loadAggregate(command);
              try {
                return commandHandler.invoke(aggregate, command);
              } catch (InvocationTargetException e) {
                throw e.getCause();
              }
            }
          };
      commandBus.subscribe(commandHandler.getPayloadType(), handler);
      registeredCommandHandlers.put(commandHandler.getPayloadType(), handler);
    }

    for (final ConstructorCommandMessageHandler<T> handler : inspector.getConstructorHandlers()) {
      commandBus.subscribe(
          handler.getPayloadType(), new AnnotatedConstructorCommandHandler(handler));
    }
  }
 @Override
 public int compareTo(SagaMethodMessageHandler o) {
   if (this.handlerMethod == null && o.handlerMethod == null) {
     return 0;
   } else if (this.handlerMethod == null) {
     return -1;
   } else if (o.handlerMethod == null) {
     return 1;
   }
   return handlerMethod.compareTo(o.handlerMethod);
 }
  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    SagaMethodMessageHandler that = (SagaMethodMessageHandler) o;

    return !(handlerMethod != null
        ? !handlerMethod.equals(that.handlerMethod)
        : that.handlerMethod != null);
  }
 @Override
 public int hashCode() {
   return handlerMethod != null ? handlerMethod.hashCode() : 0;
 }
 /**
  * Indicates whether this Handler is suitable for the given <code>message</code>.
  *
  * @param message The message to inspect
  * @return <code>true</code> if this handler can handle the message, otherwise <code>false</code>.
  */
 public boolean matches(EventMessage message) {
   return handlerMethod != null && handlerMethod.matches(message);
 }
 /**
  * Indicates whether the handler of the target event indicates an ending event handler (i.e. is
  * annotated with {@link EndSaga}).
  *
  * @param event The event to investigate the handler for
  * @return <code>true</code> if handling the given <code>event</code> should end the lifecycle of
  *     the Saga, <code>false</code> otherwise.
  */
 public boolean isEndingEvent(EventMessage event) {
   MethodMessageHandler handler = invoker.findHandlerMethod(event);
   return handler != null && handler.getMethod().isAnnotationPresent(EndSaga.class);
 }