/axon-gateway-extension

Extension to Axon Framework providing additional gateways.

Primary LanguageKotlinApache License 2.0Apache-2.0

Axon Framework - Gateways Extension

stable Maven Central Codacy Badge

Note: This extension is still in an experimental stage.

Getting started

Dependencies for the Spring Boot Starter

Maven

<dependency>
  <groupId>io.holixon.axon.gateway</groupId>
  <artifactId>axon-gateway-springboot-starter</artifactId>
  <version>${axon-gateway-extension.version}</version>
</dependency>

Usage

Revision-Aware Query Gateway

Imagine, you are sending a command, and you want to query for the result of its effect in the projection. A Revision-Aware Gateway is capable of retrieving for a certain (minimal) revision of the projection. In order to do so, you need to pass the revision along with your command, packaged in metadata by using the helper method:

commandGateway.send<Void>(
  GenericCommandMessage.asCommandMessage<UpdateApprovalRequestCommand>(
    CreateApprovalRequestCommand(
      requestId = requestId,
      subject = value.subject,
      currency = value.currency,
      amount = value.amount
    )
  ).withMetaData(RevisionValue(revision).toMetaData())
)

Now you can query for a certain revision, if the result contains the revision information inside the payload (the query result implements Revisionable).

queryGateway.query(
  GenericCommandMessage
    .asCommandMessage<ApprovalRequestQuery>(ApprovalRequestQuery(requestId.trim()))
    .withMetaData(RevisionQueryParameters(revision).toMetaData()),
  ResponseTypes.instanceOf(ApprovalRequestQueryResult::class.java)
).join()

As alternative, you can query for a certain revision, if the query method returns QueryResponseMessage<T> and carries metadata inside the message metadata field.

queryGateway.query(
  GenericCommandMessage
    .asCommandMessage<ApprovalRequestQuery>(ApprovalRequestQuery(requestId.trim()))
    .withMetaData(RevisionQueryParameters(revision).toMetaData()),
  QueryResponseMessageType.queryResponseMessageType<ApprovalRequest>()
).join()

The query gateway will detect the revision metadata in the query and wait until the specified response with specified revision has arrived in the projection. In order not to wait forever, you can either pass the timeout with the query or setup default timeout using the application properties.

In order to maintain revisions in your projection, make sure your event get the revision information from the command and the projection stores it. Currently, the revision must be transported inside the query result, by implementing the Revisionable interface or by returning QueryResponseMessage<T> from your handler method.

If you have any questions how to use the extension, please have a look on example project.

Dispatch-aware Axon Server command bus

By default, the Axon Server Connector will register all command handlers it finds by AutoConfiguration both on "Local" and "Remote" segments of the command bus. In order to have more flexibility on that, for example by hiding some CommandHandlers from registration, you might want to have a possibility to exclude CommandHandler registration on a remote command bus. By doing so, the locally dispatched commands should still get delivered to command handlers by using the local segment of the command bus.

The Dispatch-aware command bus is designed exactly for the purpose above. In order to use it, you will need the Axon Server Connector to be configured to use Axon Server (axon.axonserver.enabled must not be set to false). In addition, you need to enable the following property:

axon-gateway:
  command:
    dispatch-aware:
      enabled: true

Now you need to specify a CommandDispatchStrategy. You can do this manually, by providing a bean factory for this, a component implementing this interface or by using the predefined components using properties to configure predicates for command names excluded from remote registration. For doing so, specify the following properties in your application.yml

axon-gateway:
  command:
    dispatch-aware:
      enabled: true
      strategy:
        exclude-command-names:
          - io.holixon.axon.gateway.example.UpdateApprovalRequestCommand
          - io.holixon.axon.gateway.example.OtherCommand
        exclude-command-packages:
          - example.matching.all.commands.in.this.package.and.sub.packages

Please check the implementations of CommandDispatchStrategy for more details.

Jackson for query serialization

If you are using this extension with Jackson serialization, it is required that the query response type is serializable by Jackson. For this purpose, we provide a small Jackson module which needs to be included and registered in your project.

To do so, please add the following dependency to your classpath:

Maven

<dependency>
  <groupId>io.holixon.axon.gateway</groupId>
  <artifactId>axon-gateway-jackson-module</artifactId>
  <version>${axon-gateway-extension.version}</version>
</dependency>

and register it in your Jackson ObjectMapper:

@Bean
fun objectMapper(): ObjectMapper = jacksonObjectMapper()
    .registerModule(AxonGatewayJacksonModule())

Building the extension

If you want to build the extension locally, you need to check it out from GiHub and run the following command:

./mvnw clean install

Building example project

The project includes an example module demonstrating usage of the extension. If you want to skip the example build, please run the following command line:

./mvnw clean install -DskipExamples

To start example please run the AxonGatewayExampleApplication. By supplying the Spring profile inmem you can run it without the Axon Server. If you run it with Axon Server, make use of example/docker-compose.yml to start one using Docker.

To play with example, navigate to http://localhost:8079/swagger-ui/index.html with your browser and send some REST requests.