Skip to content

Commit

Permalink
Merge pull request #126 from AxonFramework/add-sample
Browse files Browse the repository at this point in the history
Added an AMQP sample to show how to use the extension
  • Loading branch information
lfgcampos committed Sep 20, 2021
2 parents 0344444 + 1b2749d commit c40d22b
Show file tree
Hide file tree
Showing 16 changed files with 780 additions and 3 deletions.
29 changes: 29 additions & 0 deletions amqp-axon-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# AMQP Axon Springboot Example

This is an example SpringBoot application using Axon's AMQP extension. It uses an In-Memory Event Store and RabbitMQ as the Message Bus.

## How to run

### Preparation

You will need `docker` and `docker-compose` to run this example.

Please run:

```bash
docker compose -f ./amqp-axon-example/docker-compose.yaml up -d
```

This will start RabbitMQ with default values.

Now build the application by running:

```bash
mvn clean package -f ./amqp-axon-example
```

### Running example application

You can start the application by running `java -jar ./amqp-axon-example/target/amqp-axon-example.jar`.

You can access the `rabbitmq` UI on [http://localhost:15672/](http://localhost:15672/) (using the default `guest`/`guest`credentials) where you can see the queues, bindings and exchanges used by Axon and inspect the messages on them.
9 changes: 9 additions & 0 deletions amqp-axon-example/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: '3.7'

services:

rabbitmq:
image: rabbitmq:management
ports:
- "5672:5672"
- "15672:15672"
164 changes: 164 additions & 0 deletions amqp-axon-example/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2010-2021. Axon Framework
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>axon-amqp-parent</artifactId>
<groupId>org.axonframework.extensions.amqp</groupId>
<version>4.6.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>amqp-axon-example</artifactId>
<version>4.6.0-SNAPSHOT</version>

<name>Axon Framework AMQP Extension - Spring Boot Example</name>
<description>Example module for the AMQP Extension of Axon Framework</description>

<properties>
<kotlin.version>1.5.30</kotlin.version>
<kotlin-logging-jvm.version>2.0.10</kotlin-logging-jvm.version>
<spring.boot.version>2.5.4</spring.boot.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.axonframework</groupId>
<artifactId>axon-spring-boot-starter</artifactId>
<version>${axon.version}</version>
<exclusions>
<exclusion>
<groupId>org.axonframework</groupId>
<artifactId>axon-server-connector</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.axonframework.extensions.amqp</groupId>
<artifactId>axon-amqp-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>io.github.microutils</groupId>
<artifactId>kotlin-logging-jvm</artifactId>
<version>${kotlin-logging-jvm.version}</version>
<exclusions>
<exclusion>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<configuration>
<finalName>${project.artifactId}</finalName>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<configuration>
<jvmTarget>1.8</jvmTarget>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>spring</plugin>
<plugin>no-arg</plugin>
<plugin>all-open</plugin>
</compilerPlugins>
</configuration>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2010-2021. Axon Framework
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.axonframework.extension.amqp.example

import org.springframework.amqp.core.Binding
import org.springframework.amqp.core.BindingBuilder
import org.springframework.amqp.core.Queue
import org.springframework.amqp.core.TopicExchange
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import org.springframework.scheduling.annotation.EnableScheduling


/**
* Starting point.
*/
fun main(args: Array<String>) {
runApplication<AMQPAxonExampleApplication>(*args)
}

/**
* Main application class.
*/
@SpringBootApplication
@EnableScheduling
class AMQPAxonExampleApplication {

@Bean
fun eventsExchange(): TopicExchange {
return TopicExchange(TOPIC_EXCHANGE_NAME)
}

@Bean
fun eventsQueue(): Queue {
return Queue(QUEUE_NAME, true)
}

@Bean
fun eventsBinding(queue: Queue, exchange: TopicExchange): Binding {
return BindingBuilder.bind(queue)
.to(exchange)
.with("#")
}

companion object {

const val TOPIC_EXCHANGE_NAME = "exchange"

const val QUEUE_NAME = "queue"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2010-2021. Axon Framework
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.axonframework.extension.amqp.example

import com.rabbitmq.client.Channel
import org.axonframework.eventhandling.tokenstore.TokenStore
import org.axonframework.eventhandling.tokenstore.inmemory.InMemoryTokenStore
import org.axonframework.eventsourcing.eventstore.EventStorageEngine
import org.axonframework.eventsourcing.eventstore.inmemory.InMemoryEventStorageEngine
import org.axonframework.extension.amqp.example.AMQPAxonExampleApplication.Companion.QUEUE_NAME
import org.axonframework.extensions.amqp.eventhandling.AMQPMessageConverter
import org.axonframework.extensions.amqp.eventhandling.spring.SpringAMQPMessageSource
import org.springframework.amqp.core.Message
import org.springframework.amqp.rabbit.annotation.RabbitListener
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class AxonConfig {

/**
* The SpringAMQPMessageSource allows event processors to read messages from a queue instead of the event store or
* event bus. It acts as an adapter between Spring AMQP and the SubscribableMessageSource needed by these processors.
*
* @param messageConverter Converter to/from AMQP Messages to/from Axon Messages.
*/
@Bean
fun amqpMessageSource(messageConverter: AMQPMessageConverter): SpringAMQPMessageSource {
return object : SpringAMQPMessageSource(messageConverter) {
@RabbitListener(queues = [QUEUE_NAME])
override fun onMessage(message: Message, channel: Channel) {
println("amqp event $message received")
super.onMessage(message, channel)
}
}
}

/**
* Creates an InMemoryEventStorageEngine.
* NOT PRODUCTION READY
*/
@Bean
fun storageEngine(): EventStorageEngine = InMemoryEventStorageEngine()

/**
* Creates an InMemoryTokenStore.
* NOT PRODUCTION READY
*/
@Bean
fun tokenStore(): TokenStore = InMemoryTokenStore()

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2010-2021. Axon Framework
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.axonframework.extension.amqp.example.api

import org.axonframework.modelling.command.TargetAggregateIdentifier

/**
* Create account.
*/
data class CreateBankAccountCommand(
@TargetAggregateIdentifier
val bankAccountId: String,
val overdraftLimit: Long
)

/**
* Deposit money.
*/
data class DepositMoneyCommand(
@TargetAggregateIdentifier
val bankAccountId: String,
val amountOfMoney: Long
)

/**
* Withdraw money.
*/
data class WithdrawMoneyCommand(
@TargetAggregateIdentifier
val bankAccountId: String,
val amountOfMoney: Long
)

/**
* Return money if transfer is not possible.
*/
data class ReturnMoneyOfFailedBankTransferCommand(
@TargetAggregateIdentifier
val bankAccountId: String,
val amount: Long
)

0 comments on commit c40d22b

Please sign in to comment.