Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

Commit

Permalink
Merge branch 'release/0.0.6'
Browse files Browse the repository at this point in the history
  • Loading branch information
zambrovski committed Nov 3, 2023
2 parents e50d702 + dc9ee49 commit 9957a86
Show file tree
Hide file tree
Showing 59 changed files with 821 additions and 319 deletions.
14 changes: 14 additions & 0 deletions .github/release-notes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
changelog:
sections:
- title: ":rocket: Enhancements & Features"
labels: [ "Type: enhancement", "Type: documentation", "Type: example" ]
- title: ":bug: Bug Fixes"
labels: [ "Type: bug" ]
- title: ":hammer_and_wrench: Chore"
labels: [ "Type: dependencies" ]
issues:
exclude:
labels: [ "Type: question" ]
contributors:
exclude:
names: [ "dependabot[bot]" ]
8 changes: 4 additions & 4 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
key: ${{ runner.os }}-pip-${{ hashFiles('./docs/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
Expand Down Expand Up @@ -61,13 +61,13 @@ jobs:
# This is for a tagged version
- name: Create a new version of documentation and push to GH pages.
if: startsWith(github.ref, 'refs/tags/')
run: mike deploy ${{ steps.get_tag_name.outputs.TAG_NAME }} stable --push --rebase
run: mike deploy ${{ steps.get_tag_name.outputs.TAG_NAME }} stable --push -u

- name: Make stable to default.
if: startsWith(github.ref, 'refs/tags/')
run: mike set-default stable --push --rebase
run: mike set-default stable --push

# This is for develop
- name: Deploy latest develop snapshot docs to GH pages.
if: github.ref == 'refs/heads/develop'
run: mike deploy snapshot --push --rebase
run: mike deploy snapshot --push -u
33 changes: 33 additions & 0 deletions .github/workflows/release-notes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Trigger the workflow on milestone events
on:
milestone:
types: [closed]
name: Milestone Closure
jobs:
create-release-notes:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Create Release Notes Markdown
uses: docker://decathlon/release-notes-generator-action:3.1.5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
OUTPUT_FOLDER: temp_release_notes
USE_MILESTONE_TITLE: "true"
- name: Get the name of the created Release Notes file and extract Version
run: |
RELEASE_NOTES_FILE=$(ls temp_release_notes/*.md | head -n 1)
echo "RELEASE_NOTES_FILE=$RELEASE_NOTES_FILE" >> $GITHUB_ENV
VERSION=$(echo ${{ github.event.milestone.title }} | cut -d' ' -f2)
echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: Create a Draft Release Notes on GitHub
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ env.VERSION }}
release_name: ${{ env.VERSION }}
body_path: ${{ env.RELEASE_NOTES_FILE }}
draft: true
37 changes: 18 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
# axon-avro-serializer

[![incubating](https://img.shields.io/badge/lifecycle-INCUBATING-orange.svg)](https://github.com/holisticon#open-source-lifecycle)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/e5518754d4fd4eea80ef02a95be59486)](https://app.codacy.com/gh/holixon/axon-avro-serializer?utm_source=github.com&utm_medium=referral&utm_content=holixon/axon-avro-serializer&utm_campaign=Badge_Grade_Settings)
[![Build Status](https://github.com/holixon/axon-avro-serializer/workflows/Development%20branches/badge.svg)](https://github.com/holixon/axon-avro-serializer/actions)
[![sponsored](https://img.shields.io/badge/sponsoredBy-Holisticon-RED.svg)](https://holisticon.de/)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.holixon.axon.avro/axon-avro-serializer/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.holixon.axon.avro/axon-avro-serializer)
[![codecov](https://codecov.io/gh/holixon/axon-avro-serializer/branch/develop/graph/badge.svg?token=ZKDNW1QJ1Y)](https://codecov.io/gh/holixon/axon-avro-serializer)

__DISCLAIMER__: early draft, heavy development, *everything* might still change
This extension to the [Axon Framework](https://docs.axoniq.io/reference-guide/) aims to provide support for serialization of Axon events
with the [Apache Avro](https://avro.apache.org/docs/current/) data format.

This extension to the [Axon Framework](https://docs.axoniq.io/reference-guide/) aims to provide support for serialization of Axon messages (commands, events, queries) with the [Apache Avro](https://avro.apache.org/docs/current/) data format.
Avro is a schema-based data format that can be serialized to JSON or byte sequence, which is useful to minimize the disk space needed for
your Axon event store and bandwidth used for transport. Messages can be validated against a schema version and Avro supports schema
evolution by automatically determining [compatibility modes](https://docs.confluent.io/platform/current/schema-registry/avro.html) between
different revisions.

Avro is a schema-based data format that can be serialized to JSON or byte sequence, which is useful to minimize
the disk space needed for your Axon event store and bandwidth used for transport.
Messages can be validated against a schema version and avro supports schema evolution by automatically determining
[compatibility modes](https://docs.confluent.io/platform/current/schema-registry/avro.html) between different revisions.
Please check our [official documentation](https://www.holixon.io/axon-avro-serializer/snapshot/) for more details.

see on [component overview](file:/notes/README.md)

## Links
## Developers

* [Avro Registry Adapter](https://github.com/holixon/avro-registry-adapter) - used to abstract from concrete schema registry
* <https://hub.docker.com/r/axoniq/axonserver>
* [Jan Galinski](https://github.com/jangalinski)
* [Simon Zambrovski](https://github.com/zambrovski)

## Notes
## License

* <https://github.com/sksamuel/avro4k>
* <https://www.baeldung.com/java-apache-avro>
* <https://avro.apache.org/docs/current/gettingstartedjava.html>
* <http://bigdatums.net/2016/01/20/simple-apache-avro-example-using-java/>
* <http://www.soutier.de/blog/2017/03/07/daten-modellieren-avro/>
This library is developed under

### great
[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://www.holunda.io/camunda-bpm-taskpool/license)

## Sponsors and Customers

[![sponsored](https://img.shields.io/badge/sponsoredBy-Holisticon-red.svg)](https://holisticon.de/)

* <https://blog.cloudera.com/robust-message-serialization-in-apache-kafka-using-apache-avro-part-1/>
* <https://github.com/cloudera/kafka-examples>
22 changes: 6 additions & 16 deletions docs/assets/css/extra.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,13 @@
*/
/* Customize logo size */
.md-header__button.md-logo img, .md-header__button.md-logo svg {
height: 100%;
width: 100%;
}

/* Disable title text*/
.md-header__title .md-ellipsis {
position: absolute !important;
width: 1px !important;
height: 1px !important;
padding: 0 !important;
margin: -1px !important; /* Fix for https://github.com/twbs/bootstrap/issues/25686 */
overflow: hidden !important;
clip: rect(0, 0, 0, 0) !important;
white-space: nowrap !important;
border: 0 !important;
height: 600%;
width: 60%;
}

[data-md-color-scheme="default"] {
/*
Polyflow color scheme
Polyflow colors
*/
--monochrome-80: #3e3e3e;
--background-white: #ffffff;
Expand All @@ -42,6 +29,9 @@
--royal: #0d0f7e;


/*
Default colors adjustments
*/
--md-primary-fg-color: var(--accent-4-100);
--md-accent-fg-color: var(--pumpkin-orange);
--md-footer-bg-color: var(--accent-4-100);
Expand Down
File renamed without changes.
File renamed without changes
10 changes: 10 additions & 0 deletions docs/concepts/event-generation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
In order to work with the Axon Framework, we need to have Java (or Kotlin) classes representing the events defined in the schema to be
available. This class is generated from the schema using Avro generator. In order to do so, the build environment must have access to the
schema (registry) and use a build system plugin (Maven or Gradle) to generate java/kt source files Please see example in
the [reference guide](../reference/index.md#event-generation) for more details.

!!! note
The class FQN will suffice to identity the published schema, but for the Axon default upcasters to work, a `@Revision` annotation
on the class file is needed. For this purpose, a special SchemaBasedRevisionResolver is implemented and configured in the Avro serializer.


19 changes: 19 additions & 0 deletions docs/concepts/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Apache Avro is a data serialization system based on **schemas**, defined in JSON. A schema is required to write data and to read data. In
particular, this means that Apache Avro is using a so-called schema-first approach. First, a schema is created and distributed, then it is
used to serialize the message and used again to deserialize the message back.

In general, the presence of the schema is sufficient to read and write data, but for statically-typed languages like Java or Kotlin, it is
common to generate static classes using Avro Code Generator.

Avro is flexible in where to get this schema from, so we defined
a [Schema Registry API](https://github.com/holixon/avro-registry-adapter/blob/develop/extension/api/src/main/kotlin/AvroSchemaRegistry.kt)
to de-couple the user from the implementation of the schema registry. This allowed us to define multiple interchangeable implementation of
the [registry adapters](../reference/registry-adapters.md).

The following figure demonstrates this approach:

![Overview](../assets/img/axon-serializer.png)




46 changes: 46 additions & 0 deletions docs/concepts/schema-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
Based on the business requirements for the events of the bounded context, an Avro Schema definition is created. It describes all properties
of the event and is defined using JSON.

Most Important:

* event namespace (in which context is this event relevant? could be context's name prefixed by the domain,
example: `example.bankaccount.event`)
* event name (describing what happened in a simple past tense. Meaningful in context, example: `BankAccountCreated`)
* event revision (when we later modify the event content, which is the revision we relate to, example: `1`)
* event reference identifier (business aggregate identifier this event relates to, example: `bankAccountId`)

The schema can be identified by the URL of `namespace.name`, which will later also be the FQN of the generated classes, used for handling
the event instances.

!!! important
We consider that the namespace of the business context and the name of an event should not change over time when they are
modelled properly in advance. So it might be a good option not to force a typical java-package pattern on them, which would require renaming
when refactorings are done.

The revision should be defined as a metadata of the schema, not a property inside.

Here is an example:

```json
{
"type": "record",
"namespace": "example.bankaccount.event",
"name": "BankAccountCreatedEvent",
"fields": [
{
"name": "bankAccountId",
"type": "string"
},
{
"name": "initialBalance",
"type": "int"
}
],
"revision": "1"
}

```

For more details, please consult the [Avro Specification](https://avro.apache.org/docs/current/spec.html#schemas).


5 changes: 5 additions & 0 deletions docs/concepts/schema-publication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Once we are happy with our [schema design](schema-design.md), we publish it to a schema registry.

* This extension is not enforcing usage of a particular registry but instead provide
flexible [registry adapters](../reference/registry-adapters.md).
* The registry must be available at build and runtime because we need it for code generation and runtime validation/migration.
24 changes: 24 additions & 0 deletions docs/concepts/schema-registry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
**Schema registry** is a central concept introduced to decouple storage and management of schemas from the usage of schemas for
serialization and deserialization. In order to decouple from concrete implementation, we defined an API to work with registries in the
sister project [Avro Registry Adapter](https://github.com/holixon/avro-registry-adapter). There are several registry adapters available,
which can be used in your implementation. Currently, they are:

* In-Memory registry for a transient registry
* Apicurio Registry Adapter to connect to [apicur.io Registry](https://www.apicur.io/registry/)

The following registries will be available shortly:

* JPA registry for storing schemas in RDBMS
* Confluent registry adapter to work with [Confluent Schema Registry](https://docs.confluent.io/platform/current/schema-registry/index.html)

Using one of those adapters you can reuse the existing registry. Every registry adapter needs its specific configuration to operate
properly. In the [Registry Adapters](../reference/registry-adapters.md) section, the examples of configuration is provided. For more
details, please consult the documentation of the [Avro Registry Adapter](https://github.com/holixon/avro-registry-adapter) project.

## Registry Performance

Since the Schema registry is required for any serialization and deserialization process, performance of the schema resolution is vital. To
address this requirement, we provide a mechanism of a **Composite Registry**, effectively building a chain of registries. It might be a good
idea to have an in-memory registry as the main registry used in the application, backed by a remote schema registry connected via selected
registry adapter.

11 changes: 11 additions & 0 deletions docs/concepts/upcasting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Upcasting is the process of matching the structure of the event intermediate representation of an event to the target type of the event. It
is required if the structure of the event of the writer side is not matching the structure of the event of the reader side. In general, we
speak about event evolution, which is described in the context of Avro with the concept of Schema Evolution. Luckily, Avro provides a
foundation of detection of schema changes and allows for a classification of those changes - some of those changes are non-breaking and some
are breaking. The task for the upcaster is to overcome the breaking changes.

In order to upcast a Avro-serialized message, the intermediate representation is constructed. Since it is not easily possible to upcast
binary data directly, we provide a converter of binary data into
a [Generic Record format](https://avro.apache.org/docs/1.7.6/api/java/org/apache/avro/generic/GenericRecord.html) which is essentially
a `Map<String, Object>` structure. An upcaster may modify this map to match the target event type. In addition, it needs to change the
schema information (schema namespace, name, revision) of the `Generic Record` to match the reader schema.
27 changes: 27 additions & 0 deletions docs/developer-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Design decisions

We decided to create a sister project [Avro Registry Adapter](https://github.com/holixon/avro-registry-adapter) which eases the work with
Apache Avro and defines the API and implementations for [Schema Registry](concepts/schema-registry.md). In doing so, we provide a maximum
independence of the serialization process from the used registry.

The extension itself is implemented in Kotlin only, since we need to work with JVM and Axon Framework and Kotlin is more fun.

The extension is usable from Kotlin and Java, although the API might have advantages when using Kotlin.

## References

There are some resources on the Internet, which might be helpful to understand the design decisions and implementation. Here is a short
collection of links:

### Notes

* <https://github.com/sksamuel/avro4k>
* <https://www.baeldung.com/java-apache-avro>
* <https://avro.apache.org/docs/current/gettingstartedjava.html>
* <http://bigdatums.net/2016/01/20/simple-apache-avro-example-using-java/>
* <http://www.soutier.de/blog/2017/03/07/daten-modellieren-avro/>

### Great to read

* <https://blog.cloudera.com/robust-message-serialization-in-apache-kafka-using-apache-avro-part-1/>
* <https://github.com/cloudera/kafka-examples>
32 changes: 32 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Put the serializer library and one of the [registry adapters](reference/registry-adapters.md) on the class path of you project:

```xml

<dependency>
<groupId>io.holixon.axon.avro</groupId>
<artifactId>axon-avro-serializer-spring</artifactId>
<version>${axon-avro-serializer.version}</version>
</dependency>
```

```xml

<dependency>
<groupId>io.holixon.avro</groupId>
<artifactId>avro-registry-adapter-apicurio</artifactId>
<version>${avro-registry.version}</version>
</dependency>
```

Activate the used registry adapter and the serializer in your configuration:

```kotlin
@EnableAxonAvroSerializer
class MyConfiguration {

@Bean
fun avroSchemaRegistry(): AvroSchemaRegistry {
return ...
}
}
```
26 changes: 26 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## Why should I use it?

We believe that serialization of events for messaging and storage purpose is done best
using [Apache Avro](https://avro.apache.org/docs/current/) data serialization system. For this purpose we designed and implemented an **Avro
Serializer** for [Axon Framework](https://docs.axoniq.io/reference-guide/) **to foster** usage of Apache Avro as
a [serialization format for events](https://docs.axoniq.io/reference-guide/axon-framework/events/event-serialization), instead of XML or
JSON.

### Why?

* Avro is schema based
* Avro Schema allows detection of incompatibilities during Schema Evolution
* Avro supports binary encoding which saves space

## Interested?

You can get more details if you start understanding [Concepts](concepts/index.md). For further details, please check
our [reference guide](reference/index.md). We also provide
some [Examples](https://github.com/holixon/axon-avro-serializer/tree/develop/examples) demonstrating the usage of the extension in a simple
Axon Bank Scenario.

[![Slack](https://img.shields.io/badge/slack-@holixon/avroserializer-green.svg?logo=slack")](https://holixon.slack.com/messages/avro-serializer/)
[![Github Issues](https://img.shields.io/github/issues/holixon/axon-avro-serializer)](https://github.com/holixon/axon-avro-serializer/issues)



Loading

0 comments on commit 9957a86

Please sign in to comment.