Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added an AMQP sample to show how to use the extension #126

Merged
merged 4 commits into from
Sep 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
lfgcampos marked this conversation as resolved.
Show resolved Hide resolved
```

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"?>
lfgcampos marked this conversation as resolved.
Show resolved Hide resolved
<!--
~ 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>
lfgcampos marked this conversation as resolved.
Show resolved Hide resolved
<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
)