49 Commits

Author SHA1 Message Date
Michael Schnell
eeca95221f Moved license file 2021-10-23 14:54:34 +02:00
Michael Schnell
e0aca86722 Added license information 2021-10-23 14:52:43 +02:00
Michael Schnell
2b9a8da5ae Update README.md 2021-09-19 18:34:02 +02:00
Michael Schnell
cefabe2603 Fixed doc 2021-09-19 11:57:58 +02:00
Michael Schnell
01605ec586 Enhanced title for search engines 2021-09-18 13:51:10 +02:00
Michael Schnell
35e852475c Added build link 2021-09-17 17:35:56 +02:00
Michael Schnell
628669e2dd Added build badge 2021-09-17 17:34:11 +02:00
Michael Schnell
6bab4790af Cleanup Sonar issues, added Github build and formatted source 2021-09-17 17:22:05 +02:00
Michael Schnell
a3fe604856 Fixed wrong level 2021-09-17 16:43:41 +02:00
Michael Schnell
73f10da831 Shortend howto 2021-09-17 16:41:56 +02:00
Michael Schnell
773e23c859 Removed Developer VM as it is outdated and shortened howto 2021-09-17 16:31:11 +02:00
Michael Schnell
e33e149023 Do not use "report-unupported-elements-at-runtime".
See https://github.com/oracle/graal/issues/1725#issuecomment-547570158
2021-09-17 16:09:38 +02:00
Michael Schnell
c05fbf3068 Fixed too old eventstore version 2021-09-17 16:07:43 +02:00
Michael Schnell
52810588c3 Fixed doc 2021-09-05 09:29:49 +02:00
Michael Schnell
95602b8715 Added missing version 2021-09-05 09:29:36 +02:00
Michael Schnell
7a1210abb3 Updated Maven Wrapper 2021-09-05 09:29:24 +02:00
Michael Schnell
5a614a7d72 Fixed problems with native image creation 2021-09-04 17:33:45 +02:00
Michael Schnell
eb394c118f Updated to latest Quarkus version 2021-09-04 17:33:23 +02:00
Michael Schnell
d2e03295a2 Added missing engine 2021-09-04 15:57:29 +02:00
Michael Schnell
0689587fcd Added framwork hints 2021-09-04 15:56:28 +02:00
Michael Schnell
ca526e872e Updated current Quarkus / Spring Boot versions 2021-09-04 15:53:45 +02:00
Michael Schnell
0bd7433cc8 spring.http.converters changed to spring.mvc.converters
See https://docs.across.dev/across-site/production/migration/platform-5-0-to-5-1.html#_deprecated_spring_boot_properties
2021-09-04 15:52:59 +02:00
Michael Schnell
05705386de Fixed naming 2021-09-04 15:49:32 +02:00
Michael Schnell
e88922b3cd Changed badge 2020-12-20 13:54:52 +01:00
Michael Schnell
2dd2969901 Started migration to Java 11 2020-12-20 13:53:47 +01:00
Michael Schnell
074873012e Merge pull request #9 from fuinorg/dependabot/maven/aggregates/junit-junit-4.13.1
Bump junit from 4.12 to 4.13.1 in /aggregates
2020-12-20 07:41:15 +01:00
Michael Schnell
3d591d003c Merge pull request #8 from fuinorg/dependabot/maven/shared/junit-junit-4.13.1
Bump junit from 4.12 to 4.13.1 in /shared
2020-12-20 07:41:03 +01:00
dependabot[bot]
c9f21adeaf Bump junit from 4.12 to 4.13.1 in /aggregates
Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-13 18:32:14 +00:00
dependabot[bot]
cc65808dac Bump junit from 4.12 to 4.13.1 in /shared
Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-13 18:28:13 +00:00
Michael Schnell
64e95e8dc8 Create ES projection based on even type names. 2020-03-21 11:57:50 +01:00
Michael Schnell
b4114a97eb Create ES projection with hash based on event types. 2020-03-21 11:48:51 +01:00
Michael Schnell
7459eb3244 Switched to new iteration and Quarkus 1.2.0.Final 2020-02-02 19:57:32 +01:00
Michael Schnell
32565f7efd Use variables for log statements 2020-01-10 09:43:05 +01:00
Michael Schnell
89241fb66a Fixed transaction border 2020-01-10 09:41:56 +01:00
Michael Schnell
1abd8f7441 Merge pull request #5 from fuinorg/dependabot/maven/java-se-cdi/org.hibernate.validator-hibernate-validator-6.1.0.Final
Bump hibernate-validator from 6.0.10.Final to 6.1.0.Final in /java-se-cdi
2020-01-10 09:32:27 +01:00
Michael Schnell
a3f31864c4 Merge pull request #6 from fuinorg/dependabot/maven/shared/org.hibernate.validator-hibernate-validator-6.1.0.Final
Bump hibernate-validator from 6.0.10.Final to 6.1.0.Final in /shared
2020-01-10 09:32:16 +01:00
Michael Schnell
63ae4af2cf Merge pull request #7 from fuinorg/dependabot/maven/aggregates/org.hibernate.validator-hibernate-validator-6.1.0.Final
Bump hibernate-validator from 6.0.10.Final to 6.1.0.Final in /aggregates
2020-01-10 09:32:06 +01:00
dependabot[bot]
fbfeebc4d3 Bump hibernate-validator from 6.0.10.Final to 6.1.0.Final in /aggregates
Bumps [hibernate-validator](https://github.com/hibernate/hibernate-validator) from 6.0.10.Final to 6.1.0.Final.
- [Release notes](https://github.com/hibernate/hibernate-validator/releases)
- [Changelog](https://github.com/hibernate/hibernate-validator/blob/master/changelog.txt)
- [Commits](https://github.com/hibernate/hibernate-validator/compare/6.0.10.Final...6.1.0.Final)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-08 17:38:18 +00:00
dependabot[bot]
efc865109c Bump hibernate-validator from 6.0.10.Final to 6.1.0.Final in /shared
Bumps [hibernate-validator](https://github.com/hibernate/hibernate-validator) from 6.0.10.Final to 6.1.0.Final.
- [Release notes](https://github.com/hibernate/hibernate-validator/releases)
- [Changelog](https://github.com/hibernate/hibernate-validator/blob/master/changelog.txt)
- [Commits](https://github.com/hibernate/hibernate-validator/compare/6.0.10.Final...6.1.0.Final)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-08 17:38:13 +00:00
dependabot[bot]
f9fcb691d4 Bump hibernate-validator in /java-se-cdi
Bumps [hibernate-validator](https://github.com/hibernate/hibernate-validator) from 6.0.10.Final to 6.1.0.Final.
- [Release notes](https://github.com/hibernate/hibernate-validator/releases)
- [Changelog](https://github.com/hibernate/hibernate-validator/blob/master/changelog.txt)
- [Commits](https://github.com/hibernate/hibernate-validator/compare/6.0.10.Final...6.1.0.Final)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-08 17:35:48 +00:00
Michael Schnell
a0a12d4f0d Back to Java 8 2020-01-04 10:58:54 +01:00
Michael Schnell
854b4c5f0f Added Java version hint 2020-01-04 10:55:59 +01:00
Michael Schnell
5e9b4fe53c Merge branch 'master' of github.com:fuinorg/ddd-cqrs-4-java-example 2020-01-04 10:53:36 +01:00
Michael Schnell
048e3d066e Update README.md 2020-01-02 17:57:49 +01:00
Michael Schnell
9c6654d957 Update README.md 2020-01-02 17:56:17 +01:00
Michael Schnell
040fabcb6d Update README.md 2020-01-02 17:55:33 +01:00
Michael Schnell
45d58b8b66 Update README.md 2020-01-02 17:52:01 +01:00
Michael Schnell
1a3a05e8d1 Update README.md 2020-01-02 17:49:49 +01:00
Michael Schnell
00a245384f Update README.md 2020-01-02 17:49:23 +01:00
123 changed files with 3450 additions and 1964 deletions

37
.github/workflows/maven.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Java Maven Build
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v2
- name: Show versions
run: ./mvnw -version
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'zulu'
cache: maven
- name: Cache Maven packages
uses: actions/cache@v1
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build with Maven
run: ./mvnw clean verify -U -B --file pom.xml

1
.gitignore vendored
View File

@@ -2,5 +2,6 @@
!.gitignore
!.gitkeep
!.mvn
!.github
target
*.log

View File

@@ -1,38 +1,31 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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
https://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.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
* Copyright 2007-present the original author or authors.
*
* 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.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL =
"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
@@ -80,13 +73,13 @@ public class MavenWrapperDownloader {
}
}
}
System.out.println("- Downloading from: : " + url);
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
@@ -102,6 +95,16 @@ public class MavenWrapperDownloader {
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());

Binary file not shown.

View File

@@ -1 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

201
LICENSE.txt Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

134
README.md
View File

@@ -1,5 +1,9 @@
# ddd-cqrs-4-java-example
Example applications and microservices that use [ddd-4-java](https://github.com/fuinorg/ddd-4-java) and [cqrs-4-java](https://github.com/fuinorg/cqrs-4-java) libraries and an [EventStore](https://eventstore.org/) to store the events (Event Sourcing).
Example Java DDD/CQRS/Event Sourcing microservices with [Quarkus](https://quarkus.io/), [Spring Boot](https://spring.io/projects/spring-boot/) and the [EventStore](https://eventstore.org/) from Greg Young. The code uses the lightweight [ddd-4-java](https://github.com/fuinorg/ddd-4-java) and [cqrs-4-java](https://github.com/fuinorg/cqrs-4-java) libaries. No special framework is used except the well known JEE/Spring standards.
[![Java Development Kit 11](https://img.shields.io/badge/JDK-11-green.svg)](https://openjdk.java.net/projects/jdk/11/)
[![Apache](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Build Status](https://github.com/fuinorg/ddd-cqrs-4-java-example/actions/workflows/maven.yml/badge.svg)](https://github.com/fuinorg/ddd-cqrs-4-java-example/actions/workflows/maven.yml)
## Background
This application shows how to implement [DDD](https://en.wikipedia.org/wiki/Domain-driven_design), [CQRS](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation) and [Event Sourcing](https://martinfowler.com/eaaDev/EventSourcing.html) without a DDD/CQRS framework. It uses just a few small libraries in addition to standard web application frameworks like [Quarkus](https://quarkus.io/) and [Spring Boot](https://spring.io/projects/spring-boot/).
@@ -15,14 +19,13 @@ Here is an overview of how such an application looks like:
## Components
- **[Shared](shared)** - Common code for all demo applications (commands, events, value objects and utilities).
- **[Aggregates](aggregates)** - DDD related code for all demo applications (aggregates, entities and business exceptions).
- **[Quarkus](quarkus)** - Two microservices (Command & Query) based on [Quarkus](https://quarkus.io/).
- **[Quarkus](quarkus)** - Two microservices (Command & Query) based on [Quarkus](https://quarkus.io/) that is the [successor of Wildfly Swarm/Thorntail](https://thorntail.io/posts/thorntail-community-announcement-on-quarkus/) and has CDI, JAX-RS and [SmallRye](https://smallrye.io/) ([Eclipse MicroProfile](http://microprofile.io/)).
- **[Spring Boot](spring-boot)** - Two microservices (Command & Query) based on [Spring Boot](https://spring.io/projects/spring-boot/).
- **[Java SE + CDI](java-se-cdi)** - Two standalone applications (Command & Query) using CDI for dependency injection.
## Getting started
### Prerequisites
#### Install everything yourself (Option 1)
Make sure you have the following tools installed/configured:
* [git](https://git-scm.com/) (VCS)
* [Docker CE](https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/)
@@ -30,85 +33,102 @@ Make sure you have the following tools installed/configured:
* *OPTIONAL* [GraalVM](https://www.graalvm.org/)
* Hostname should be set in /etc/hosts (See [Find and Change Your Hostname in Ubuntu](https://helpdeskgeek.com/linux-tips/find-and-change-your-hostname-in-ubuntu/) for more information)
#### Use lubuntu-developer-vm (Option 2)
The **[lubuntu-developer-vm](https://github.com/fuinorg/lubuntu-developer-vm)** has already (almost) everything installed. You only need to execute the following steps:
1. Download and install the [lubuntu-developer-vm](https://github.com/fuinorg/lubuntu-developer-vm) as described
2. OPTIONAL: Change memory of VM to 6 GB (instead of 4 GB default) if you want to create a native image with GraalVM
3. Start the VM and login (developer / developer)
4. Open a console (Shortcut = ctrl alt t)
5. Run a script that finalizes the setup of the developer virtual machine
```
bash <(curl \
-s https://raw.githubusercontent.com/fuinorg/ddd-cqrs-4-java-example/master/setup-lubuntu-developer-vm.sh)
```
6. Reboot
```
reboot
```
### Clone and install project
1. Open a console (Ubuntu shortcut = ctrl alt t)
2. Clone the git repository
1. Clone the git repository
```
git clone https://github.com/fuinorg/ddd-cqrs-4-java-example.git
```
3. Change into the project's directory and run a Maven build
2. Change into the project's directory and run a Maven build
```
cd ddd-cqrs-4-java-example
./mvnw install
```
Be patient - This may take a while (~5 minutes) as all dependencies and some Docker images must be downloaded and also some integration tests will be executed.
### Start Event Store and Maria DB
1. Open a console (Ubuntu shortcut = ctrl alt t)
2. Change into the project's directory and run Docker Compose
```
cd ddd-cqrs-4-java-example
docker-compose up
```
### Start Event Store and Maria DB (Console window 1)
Change into the project's directory and run Docker Compose
```
cd ddd-cqrs-4-java-example
docker-compose up
```
### Start command / query implementations
Start one command microservice and one query microservice - You can mix Quarkus & Spring Boot!
Start one query service and then one command service.
You can mix Quarkus & Spring Boot if you want to!
#### Quarkus Microservices
| Module | |
| :------------ | :---- |
| **[Command](quarkus/command)** | [![Overview](https://raw.github.com/fuinorg/ddd-cqrs-4-java-example/master/quarkus/command/doc/cdi-command-small.png)](quarkus/command) |
| **[Query](quarkus/query)** | [![Overview](https://raw.github.com/fuinorg/ddd-cqrs-4-java-example/master/quarkus/query/doc/cdi-view-small.png)](quarkus/query) |
##### Quarkus Query Service (Console window 2)
1. Start the Quarkus query service:
```
cd ddd-cqrs-4-java-example/quarkus/query
./mvnw quarkus:dev
```
2. Opening [http://localhost:8080/](http://localhost:8080/) should show the query welcome page
For more details see [quarkus/query](quarkus/query).
##### Quarkus Command Service (Console window 3)
1. Start the Quarkus command service:
```
cd ddd-cqrs-4-java-example/quarkus/command
./mvnw quarkus:dev
```
2. Opening [http://localhost:8081/](http://localhost:8081/) should show the command welcome page
For more details see [quarkus/command](quarkus/command).
#### Spring Boot Microservices
| Module | |
| :------------ | :---- |
| **[Command](spring-boot/command)** | [![Overview](https://raw.github.com/fuinorg/ddd-cqrs-4-java-example/master/spring-boot/command/doc/spring-command-small.png)](spring-boot/command) |
| **[Query](spring-boot/query)** | [![Overview](https://raw.github.com/fuinorg/ddd-cqrs-4-java-example/master/spring-boot/query/doc/spring-view-small.png)](spring-boot/query) |
##### Spring Boot Query Service (Console window 2)
1. Start the Spring Boot query service:
```
cd ddd-cqrs-4-java-example/spring-boot/query
./mvnw spring-boot:run
```
2. Opening [http://localhost:8080/](http://localhost:8080/) should show the query welcome page
### Test
For more details see [spring-boot/query](spring-boot/query).
##### Spring Boot Command Service (Console window 3)
1. Start the Spring Boot command service:
```
cd ddd-cqrs-4-java-example/spring-boot/command
./mvnw spring-boot:run
```
2. Opening [http://localhost:8081/](http://localhost:8081/) should show the command welcome page
For more details see [spring-boot/command](spring-boot/command).
### Verify projection and query data
1. Open [http://localhost:2113/](http://localhost:2113/) to access the event store UI (User: admin / Password: changeit)
You should see a projection named "qry-person-stream" when you click on "Projections" in the top menu.
2. Opening [http://localhost:8080/persons](http://localhost:8080/persons) should show an empty JSON array
3. Open a console (Ubuntu shortcut = ctrl alt t)
4. Change into the demo directory and execute a command using cURL (See [shell script](demo/create-person-command.sh) and [command](demo/create-person-command.json))
```
cd ddd-cqrs-4-java-example/demo
./create-person-command.sh
```
Command console should show something like
```
Update aggregate: id=PERSON 84565d62-115e-4502-b7c9-38ad69c64b05, version=-1, nextVersion=0
```
Query console should show something like
```
PersonCreatedEventHandler ... Handle PersonCreatedEvent: Person 'Peter Parker' was created
```
4. Refreshing [http://localhost:8080/persons](http://localhost:8080/persons) should show
### Execute a test command (Console window 4)
Change into the demo directory and execute a command using cURL (See [shell script](demo/create-person-command.sh) and [command](demo/create-person-command.json))
```
cd ddd-cqrs-4-java-example/demo
./create-person-command.sh
```
Command service (Console window 3) should show something like
```
Update aggregate: id=PERSON 84565d62-115e-4502-b7c9-38ad69c64b05, version=-1, nextVersion=0
```
Query service (Console window 2) should show something like
```
PersonCreatedEventHandler ... Handle PersonCreatedEvent: Person 'Peter Parker' was created
```
### Verify the query data was updated
1. Refreshing [http://localhost:8080/persons](http://localhost:8080/persons) should show
```json
[{"id":"84565d62-115e-4502-b7c9-38ad69c64b05","name":"Peter Parker"}]
```
5. Opening [http://localhost:8080/persons/84565d62-115e-4502-b7c9-38ad69c64b05](http://localhost:8080/persons/84565d62-115e-4502-b7c9-38ad69c64b05) should show
2. Opening [http://localhost:8080/persons/84565d62-115e-4502-b7c9-38ad69c64b05](http://localhost:8080/persons/84565d62-115e-4502-b7c9-38ad69c64b05) should show
```json
{"id":"84565d62-115e-4502-b7c9-38ad69c64b05","name":"Peter Parker"}
6. The event sourced data of the person aggregate could be found in a stream named [PERSON-84565d62-115e-4502-b7c9-38ad69c64b05](http://localhost:2113/web/index.html#/streams/PERSON-84565d62-115e-4502-b7c9-38ad69c64b05)
3. The event sourced data of the person aggregate could be found in a stream named [PERSON-84565d62-115e-4502-b7c9-38ad69c64b05](http://localhost:2113/web/index.html#/streams/PERSON-84565d62-115e-4502-b7c9-38ad69c64b05)
### Stop Event Store and Maria DB and clean up

View File

@@ -4,20 +4,18 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.fuin.cqrs4j.example</groupId>
<parent>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-root</artifactId>
<version>0.2.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>cqrs4j-example-aggregates</artifactId>
<version>0.1.0</version>
<name>cqrs4j-example-aggregates</name>
<description>DDD related code for all demo applications (aggregates, entities and business exceptions)</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
<esc.version>0.3.1</esc.version>
</properties>
<dependencies>
<!-- Compile -->
@@ -25,37 +23,32 @@
<dependency>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-shared</artifactId>
<version>0.1.0</version>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>ddd-4-java</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>cqrs-4-java</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>objects4j</artifactId>
<version>0.6.9</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.4</version>
<artifactId>jakarta.json</artifactId>
</dependency>
<!-- Test -->
@@ -63,79 +56,123 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>units4j</artifactId>
<version>0.8.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>2.4.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.10.Final</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>jaxb-impl</artifactId>
<groupId>com.sun.xml.bind</groupId>
</exclusion>
<exclusion>
<artifactId>jaxb-api</artifactId>
<groupId>javax.xml.bind</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<repositories>
<build>
<repository>
<id>sonatype.oss.snapshots</id>
<name>Sonatype OSS Snapshot Repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
<enabled>true</enabled>
</snapshots>
</repository>
<plugins>
</repositories>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<includes>
<include>**/*</include>
</includes>
<archive>
<manifestEntries>
<Automatic-Module-Name>org.fuin.cqrs4j.example.shared</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jdeps-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jdeps-plugin</artifactId>
<versionRange>[3.1.2,)</versionRange>
<goals>
<goal>jdkinternals</goal>
<goal>test-jdkinternals</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore />
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@@ -18,7 +18,6 @@ import org.fuin.cqrs4j.example.shared.PersonId;
import org.fuin.cqrs4j.example.shared.PersonName;
import org.fuin.objects4j.common.ExceptionShortIdentifable;
/**
* A name that should be unique does already exist.
*/
@@ -26,11 +25,11 @@ public final class DuplicatePersonNameException extends Exception implements Exc
private static final long serialVersionUID = 1000L;
private static final String SHORT_ID = "DUPLICATE_PERSON_NAME";
private PersonId personId;
private static final String SHORT_ID = "DUPLICATE_PERSON_NAME";
private PersonName name;
private final PersonId personId;
private final PersonName name;
/**
* Constructor with mandatory data.
@@ -64,9 +63,9 @@ public final class DuplicatePersonNameException extends Exception implements Exc
return name;
}
@Override
public final String getShortId() {
return SHORT_ID;
}
@Override
public final String getShortId() {
return SHORT_ID;
}
}

View File

@@ -12,13 +12,13 @@
*/
package org.fuin.cqrs4j.example.aggregates;
import javax.annotation.concurrent.NotThreadSafe;
import javax.validation.constraints.NotNull;
import org.fuin.cqrs4j.example.shared.PersonId;
import org.fuin.ddd4j.ddd.EntityType;
import org.fuin.ddd4j.esrepo.EventStoreRepository;
import org.fuin.esc.api.EventStore;
import org.fuin.objects4j.common.NotThreadSafe;
/**
* Event sourced repository for storing a {@link Person} aggregate.

View File

@@ -12,7 +12,7 @@ import org.fuin.cqrs4j.example.shared.PersonName;
import org.junit.Test;
/**
* Test for the {@link Person} class.
* Test for the {@link Person} class.
*/
public class PersonTest {
@@ -24,7 +24,9 @@ public class PersonTest {
final PersonName personName = new PersonName("Peter Parker");
// TEST
final Person testee = new Person(personId, personName, pid -> { return Optional.empty(); }) ;
final Person testee = new Person(personId, personName, pid -> {
return Optional.empty();
});
// VERIFY
assertThat(testee.getUncommittedChanges()).hasSize(1);
@@ -34,8 +36,7 @@ public class PersonTest {
assertThat(event.getName()).isEqualTo(personName);
}
@Test
public final void testCreateDuplicateName() {
@@ -46,12 +47,14 @@ public class PersonTest {
// TEST & VERIFY
try {
new Person(personId, personName, pid -> { return Optional.of(otherId); }) ;
new Person(personId, personName, pid -> {
return Optional.of(otherId);
});
fail("Excpected duplicate name exception");
} catch (final DuplicatePersonNameException ex) {
assertThat(ex.getMessage()).isEqualTo("The name 'Peter Parker' already exists: " + otherId);
}
}
}

View File

@@ -3,7 +3,7 @@ version: '2.4'
services:
eventstore:
image: eventstore/eventstore:release-4.1.3
image: eventstore/eventstore:release-5.0.9
container_name: "cqrs4j-quarkus-example-eventstore"
ports:
- "1113:1113"

View File

@@ -4,7 +4,7 @@ Minimal standalone example application that uses the [ddd-4-java](https://github
## Starting the demo
1. Start an EventStore locally on your PC
* You can use the [EventStore Docker Image](https://hub.docker.com/r/eventstore/eventstore/): ```docker run --name eventstore-node -p 2113:2113 -p 1113:1113 --rm eventstore/eventstore:release-4.1.3```
* You can use the [EventStore Docker Image](https://hub.docker.com/r/eventstore/eventstore/): ```docker run --name eventstore-node -p 2113:2113 -p 1113:1113 --rm eventstore/eventstore:release-5.0.9```
* Or simply start an instance (See [Install and run Event Store](https://eventstore.org/docs/server/index.html?tabs=tabid-1) for more information)
2. Run the [QryExampleApp](src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/app/QryExampleApp.java) to make the view/read part listen to new events
* You should see something like this on the console: ```INFO o.f.d.qry.handler.QryProjector - Create projection 'qry-person-stream' with events: [PersonCreatedEvent]```
@@ -12,7 +12,8 @@ Minimal standalone example application that uses the [ddd-4-java](https://github
3. Run the [CmdExampleApp](src/main/java/org/fuin/cqrs4j/example/javasecdi/cmd/app/CmdExampleApp.java) to create a [PersonCreatedEvent](src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/domain/PersonCreatedEvent.java)
* You should see something like this on the console: ```INFO o.f.d.cmd.app.CmdExampleApp - Updated event store...```
* There should also be an update on the 'QryExampleApp' console: ```INFO o.f.d.q.h.PersonCreatedEventHandler - Handle Person 'Peter Parker Inc.' was created```
* If you open the [Event Store UI](http://localhost:2113/web/index.html#/projections) (User 'admin' / Password 'changeit') and open the projection details for 'qry-person-stream' it should show 'Events processed = 1'
* If you open the [Event Store UI](http://localhost:2113/web/index.html#/projections) (User 'admin' / Password 'changeit') and open the projection details for 'qry-person-stream' it should show 'Events processed = 1'
* Look at the person's aggregate event stream: ```http://localhost:2113/web/index.html#/streams/PERSON-00000000-0000-0000-0000-000000000000`` - Replace the zero UUID with the one shown in the event handler message 'Person 'Peter Parker Inc.' (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) was created'
4. Kill the [QryExampleApp](src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/app/QryExampleApp.java)
5. Stop the event store

View File

@@ -5,15 +5,15 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.fuin</groupId>
<artifactId>pom</artifactId>
<version>1.6.0</version>
</parent>
<parent>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-root</artifactId>
<version>0.2.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>org.fuin.cqrs4j.example.javasecdi</groupId>
<artifactId>cqrs4j-javasecdi-example</artifactId>
<version>0.1.0</version>
<description>Minimal standalone example application that uses the 'ddd-4-java' and 'ddd-cqrs-4-java-example' libraries</description>
<scm>
@@ -28,10 +28,7 @@
</issueManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<esc.version>0.3.1</esc.version>
<esc.version>0.4.0</esc.version>
</properties>
<dependencyManagement>
@@ -41,7 +38,7 @@
<dependency>
<groupId>org.apache.deltaspike.distribution</groupId>
<artifactId>distributions-bom</artifactId>
<version>1.9.0</version>
<version>1.9.4</version>
<scope>import</scope>
<type>pom</type>
</dependency>
@@ -57,122 +54,106 @@
<dependency>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-shared</artifactId>
<version>0.1.0</version>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>ddd-4-java</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>cqrs-4-java</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-spi</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-esjc</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-eshttp</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>ext4logback</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
<optional>true</optional>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.8</version>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0</version>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-core</artifactId>
<version>3.0.4.Final</version>
<version>3.1.5.SP1</version>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile.config</groupId>
<artifactId>microprofile-config-api</artifactId>
<version>1.3</version>
<version>2.0</version>
</dependency>
<dependency>
<groupId>io.smallrye</groupId>
<artifactId>smallrye-config</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>io.smallrye.config</groupId>
<artifactId>smallrye-config</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1.4</version>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.4</version>
<artifactId>jakarta.json</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
@@ -188,41 +169,26 @@
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.10.Final</version>
<exclusions>
<exclusion>
<artifactId>jaxb-impl</artifactId>
<groupId>com.sun.xml.bind</groupId>
</exclusion>
<exclusion>
<artifactId>jaxb-api</artifactId>
<groupId>javax.xml.bind</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.2</version>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.2.Final</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.4.1</version>
</dependency>
<!-- Test -->
@@ -230,7 +196,6 @@
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-mem</artifactId>
<version>${esc.version}</version>
<scope>test</scope>
</dependency>
@@ -243,32 +208,144 @@
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>units4j</artifactId>
<version>0.8.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>2.4.6</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<build>
<plugins>
<pluginManagement>
</plugins>
<plugins>
</build>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jdeps-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<multiRelease>base</multiRelease>
<failOnWarning>true</failOnWarning>
</configuration>
<executions>
<execution>
<goals>
<goal>jdkinternals</goal>
<goal>test-jdkinternals</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<includes>
<include>**/*</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>3.0.0-M1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M3</version>
<executions>
<execution>
<id>enforce-java-and-maven-version</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireJavaVersion>
<version>${java.version}</version>
<message>Java 11 or later is required!</message>
</requireJavaVersion>
<requireMavenVersion>
<version>3.6.0</version>
<message>Please use at least Maven 3.6.0 as older versions may cause problems with Java 11+</message>
</requireMavenVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>sonatype.oss.snapshots</id>
<name>Sonatype OSS Snapshot Repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@@ -37,7 +37,7 @@ import org.slf4j.LoggerFactory;
public class CmdExampleApp {
private static final Logger LOG = LoggerFactory.getLogger(CmdExampleApp.class);
@Inject
private Instance<EventStore> eventStoreInstance;
@@ -48,7 +48,7 @@ public class CmdExampleApp {
public void execute() {
LOG.info("Executing...");
try (final EventStore eventStore = eventStoreInstance.get()) {
final PersonId id = new PersonId(UUID.fromString("f645969a-402d-41a9-882b-d2d8000d0f43"));
@@ -61,7 +61,7 @@ public class CmdExampleApp {
repo.update(person);
LOG.info("Updated event store...");
} catch (final Exception ex) {
throw new RuntimeException("Error saving person aggregate into event store", ex);
}
@@ -81,16 +81,16 @@ public class CmdExampleApp {
new LogbackStandalone().init(args, new NewLogConfigFileParams("org.fuin.cqrs4j.example.javasecdi", "logback"));
LOG.info("Start example");
try (final SeContainer container = SeContainerInitializer.newInstance().initialize()) {
final CmdExampleApp app = container.select(CmdExampleApp.class).get();
app.execute();
}
LOG.info("Finished example");
System.exit(0);
} catch (final RuntimeException ex) {
ex.printStackTrace(System.err);
System.exit(1);

View File

@@ -45,7 +45,8 @@ public class Person extends AbstractAggregateRoot<PersonId> implements Serializa
* @throws DuplicatePersonNameException
* The name already exists for another person.
*/
public Person(@NotNull final PersonId id, @NotNull final PersonName name, final PersonService service) throws DuplicatePersonNameException {
public Person(@NotNull final PersonId id, @NotNull final PersonName name, final PersonService service)
throws DuplicatePersonNameException {
super();
// VERIFY PRECONDITIONS

View File

@@ -1,6 +1,6 @@
package org.fuin.cqrs4j.example.javasecdi.cmd.domain;
import javax.annotation.concurrent.NotThreadSafe;
import org.fuin.objects4j.common.NotThreadSafe;
import javax.validation.constraints.NotNull;
import org.fuin.cqrs4j.example.shared.PersonId;

View File

@@ -11,10 +11,10 @@ import org.apache.deltaspike.jpa.api.transaction.TransactionScoped;
@ApplicationScoped
public class QryEntityManagerProducer {
private EntityManagerFactory emf;
@Produces
@Produces
@TransactionScoped
public EntityManager create() {
if (emf == null) {

View File

@@ -40,8 +40,10 @@ public class QryProjectionAdminEventStoreFactory {
config.getEventStorePassword());
credentialsProvider.setCredentials(AuthScope.ANY, credentials);
final SimpleSerializerDeserializerRegistry registry = new SimpleSerializerDeserializerRegistry();
final ProjectionAdminEventStore es = new ESHttpEventStore(threadFactory, new URL(url), ESEnvelopeType.JSON, registry, registry,
credentialsProvider);
final ProjectionAdminEventStore es = new ESHttpEventStore.Builder().threadFactory(threadFactory).url(new URL(url))
.envelopeType(ESEnvelopeType.JSON).serDesRegistry(registry).credentialsProvider(credentialsProvider).build();
es.open();
return es;
} catch (final MalformedURLException ex) {

View File

@@ -16,7 +16,9 @@ public class QryScheduledExecutorService {
@Produces
@ApplicationScoped
public ScheduledExecutorService create(ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(1, threadFactory, (runnable, executor) -> { System.out.println("Execution blocked"); });
return new ScheduledThreadPoolExecutor(1, threadFactory, (runnable, executor) -> {
System.out.println("Execution blocked");
});
}
}

View File

@@ -18,7 +18,7 @@ import org.slf4j.LoggerFactory;
*/
@ApplicationScoped
public class PersonCreatedEventHandler implements EventHandler<PersonCreatedEvent> {
private static final Logger LOG = LoggerFactory.getLogger(PersonCreatedEventHandler.class);
@Inject

View File

@@ -16,7 +16,7 @@ import org.slf4j.LoggerFactory;
public class QryEventChunkHandler {
private static final Logger LOG = LoggerFactory.getLogger(QryEventChunkHandler.class);
/** Unique name of the event store projection that is used. */
public static final ProjectionStreamId PROJECTION_STREAM_ID = new ProjectionStreamId("qry-person-stream");

View File

@@ -68,14 +68,19 @@ public class SharedConfig {
/**
* Constructor with all data.
*
* @param eventStoreHost Host.
* @param eventStoreHttpPort HTTP port
* @param eventStoreTcpPort TCP port.
* @param eventStoreUser User.
* @param eventStorePassword Password.
* @param eventStoreHost
* Host.
* @param eventStoreHttpPort
* HTTP port
* @param eventStoreTcpPort
* TCP port.
* @param eventStoreUser
* User.
* @param eventStorePassword
* Password.
*/
public SharedConfig(final String eventStoreHost, final int eventStoreHttpPort, final int eventStoreTcpPort,
final String eventStoreUser, final String eventStorePassword) {
public SharedConfig(final String eventStoreHost, final int eventStoreHttpPort, final int eventStoreTcpPort, final String eventStoreUser,
final String eventStorePassword) {
super();
this.eventStoreHost = eventStoreHost;
this.eventStoreHttpPort = eventStoreHttpPort;

View File

@@ -21,20 +21,22 @@ public class SharedEventStoreFactory {
/**
* Creates an event store.<br>
* <br>
* CAUTION: The returned event store instance is NOT thread safe.
* CAUTION: The returned event store instance is NOT thread safe.
*
* @param es Native event store API.
* @param registry Serialization registry.
* @param es
* Native event store API.
* @param registry
* Serialization registry.
*
* @return Dependent scope event store.
*/
*/
@Produces
@RequestScoped
public EventStore createEventStore(final com.github.msemys.esjc.EventStore es,
final SerDeserializerRegistry registry) {
public EventStore createEventStore(final com.github.msemys.esjc.EventStore es, final SerDeserializerRegistry registry) {
final EventStore eventstore = new ESJCEventStore.Builder().eventStore(es).serDesRegistry(registry)
.targetContentType(EnhancedMimeType.create("application", "json", Charset.forName("utf-8"))).build();
final EventStore eventstore = new ESJCEventStore(es, registry, registry,
EnhancedMimeType.create("application", "json", Charset.forName("utf-8")));
eventstore.open();
return eventstore;
@@ -43,7 +45,8 @@ public class SharedEventStoreFactory {
/**
* Closes the event store when the context is disposed.
*
* @param es Event store to close.
* @param es
* Event store to close.
*/
public void closeEventStore(@Disposes final EventStore es) {
es.close();

View File

@@ -24,8 +24,7 @@ public class SharedSerDeserializerRegistryFactory {
final JsonbDeSerializer jsonbDeSer = SharedUtils.createJsonbDeSerializer();
// Registry connects the type with the appropriate serializer and de-serializer
final SerDeserializerRegistry serDeserRegistry = SharedUtils.createSerDeserializerRegistry(typeRegistry,
jsonbDeSer);
final SerDeserializerRegistry serDeserRegistry = SharedUtils.createSerDeserializerRegistry(typeRegistry, jsonbDeSer);
return serDeserRegistry;

View File

@@ -39,7 +39,6 @@ import org.fuin.esc.spi.SerializedDataTypeRegistry;
import org.fuin.esc.spi.SimpleSerializedDataTypeRegistry;
import org.fuin.esc.spi.SimpleSerializerDeserializerRegistry;
/**
* Utility code shared between command (write) and query (read) module.
*/
@@ -51,16 +50,14 @@ public final class SharedUtils {
/** All JSON-B adapters from this module. */
public static JsonbAdapter<?, ?>[] JSONB_ADAPTERS = new JsonbAdapter<?, ?>[] { new EventIdConverter(),
new EntityIdPathConverter(new SharedEntityIdFactory()), new PersonId.Converter(),
new PersonName.Converter() };
new EntityIdPathConverter(new SharedEntityIdFactory()), new PersonId.Converter(), new PersonName.Converter() };
private SharedUtils() {
throw new UnsupportedOperationException("It is not allowed to create an instance of a utiliy class");
}
/**
* Create a registry that allows finding types (classes) based on their unique
* type name.
* Create a registry that allows finding types (classes) based on their unique type name.
*
* @return New instance.
*/
@@ -84,11 +81,12 @@ public final class SharedUtils {
}
/**
* Creates a registry that connects the type with the appropriate serializer and
* de-serializer.
* Creates a registry that connects the type with the appropriate serializer and de-serializer.
*
* @param typeRegistry Type registry (Mapping from type name to class).
* @param jsonbDeSer JSON-B serializer/deserializer to use.
* @param typeRegistry
* Type registry (Mapping from type name to class).
* @param jsonbDeSer
* JSON-B serializer/deserializer to use.
*
* @return New instance.
*/
@@ -120,9 +118,8 @@ public final class SharedUtils {
public static JsonbDeSerializer createJsonbDeSerializer() {
return JsonbDeSerializer.builder().withSerializers(EscSpiUtils.createEscJsonbSerializers())
.withDeserializers(EscSpiUtils.createEscJsonbDeserializers())
.withAdapters(JSONB_ADAPTERS).withPropertyVisibilityStrategy(new FieldAccessStrategy())
.withEncoding(Charset.forName("utf-8")).build();
.withDeserializers(EscSpiUtils.createEscJsonbDeserializers()).withAdapters(JSONB_ADAPTERS)
.withPropertyVisibilityStrategy(new FieldAccessStrategy()).withEncoding(Charset.forName("utf-8")).build();
}
@@ -138,8 +135,10 @@ public final class SharedUtils {
/**
* Constructor with all data.
*
* @param type Type.
* @param clasz Class.
* @param type
* Type.
* @param clasz
* Class.
*/
public TypeClass(final SerializedDataType type, final Class<?> clasz) {
super();

36
mvnw vendored
View File

@@ -8,7 +8,7 @@
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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
@@ -19,7 +19,7 @@
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
@@ -114,7 +114,6 @@ if $mingw ; then
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
@@ -212,7 +211,11 @@ else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
@@ -221,22 +224,38 @@ else
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
wget "$jarUrl" -O "$wrapperJarPath"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
curl -o "$wrapperJarPath" "$jarUrl"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
@@ -277,6 +296,11 @@ if $cygwin; then
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \

45
mvnw.cmd vendored
View File

@@ -7,7 +7,7 @@
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@@ -18,7 +18,7 @@
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@@ -26,7 +26,7 @@
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@@ -37,7 +37,7 @@
@echo off
@REM set title of command window
title %0
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
@@ -120,23 +120,44 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
echo Found %WRAPPER_JAR%
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
echo Finished downloading %WRAPPER_JAR%
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end

367
pom.xml
View File

@@ -1,20 +1,359 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-root</artifactId>
<version>0.1.0</version>
<packaging>pom</packaging>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-root</artifactId>
<version>0.2.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<java.version>11</java.version>
<maven.compiler.release>${java.version}</maven.compiler.release>
<maven.compiler.parameters>true</maven.compiler.parameters>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<esc.version>0.4.2</esc.version>
</properties>
<modules>
<module>shared</module>
<module>aggregates</module>
<module>java-se-cdi</module>
<module>quarkus</module>
<module>spring-boot</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>ddd-4-java</artifactId>
<version>0.4.0</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>cqrs-4-java</artifactId>
<version>0.4.0</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>objects4j</artifactId>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-api</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-spi</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-esjc</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-eshttp</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-mem</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>ext4logback</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>jakarta.json.bind</groupId>
<artifactId>jakarta.json.bind-api</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.5.7.Final</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.20.2</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>units4j</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>3.7.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.json</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0.8</version>
</dependency>
<dependency>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
<version>1.6.7</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>1.6.7</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jdeps-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<multiRelease>base</multiRelease>
<failOnWarning>true</failOnWarning>
</configuration>
<executions>
<execution>
<goals>
<goal>jdkinternals</goal>
<goal>test-jdkinternals</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<includes>
<include>**/*</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>3.0.0-M1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.37.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M3</version>
<executions>
<execution>
<id>enforce-java-and-maven-version</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireJavaVersion>
<version>${java.version}</version>
<message>Java 11 or later is required!</message>
</requireJavaVersion>
<requireMavenVersion>
<version>3.6.0</version>
<message>Please use at least Maven 3.6.0 as older versions may cause problems with Java 11+</message>
</requireMavenVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>sonatype.oss.snapshots</id>
<name>Sonatype OSS Snapshot Repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<modules>
<module>shared</module>
<module>aggregates</module>
<module>java-se-cdi</module>
<module>quarkus</module>
<module>spring-boot</module>
</modules>
</project>

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2007-present the original author or authors.
*
* 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.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}

Binary file not shown.

View File

@@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

View File

@@ -21,7 +21,7 @@ Make sure you installed everything as described [here](../../../../).
## *OPTIONAL* Build and run the command microservice in native mode
1. Make sure you have enough memory (~6-8 GB) on your PC or VM
2. Open a console (Ubuntu shortcut = <ctrl><alt><t>)
2. Open a console (Ubuntu shortcut = ctrl alt t)
3. Build the native executable
```
cd command

View File

@@ -19,7 +19,7 @@
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
@@ -212,9 +212,9 @@ else
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
@@ -246,7 +246,7 @@ else
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"

View File

@@ -18,7 +18,7 @@
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@@ -26,7 +26,7 @@
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@@ -120,7 +120,7 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
@@ -134,7 +134,7 @@ if exist %WRAPPER_JAR% (
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...

View File

@@ -6,34 +6,14 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.fuin.cqrs4j.example.quarkus</groupId>
<parent>
<groupId>org.fuin.cqrs4j.example.quarkus</groupId>
<artifactId>cqrs4j-quarkus-example-root</artifactId>
<version>0.2.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>cqrs4j-quarkus-example-command</artifactId>
<version>0.1.0</version>
<properties>
<maven.compiler.parameters>true</maven.compiler.parameters>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<esc.version>0.3.1</esc.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-universe-bom</artifactId>
<version>1.0.1.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
@@ -64,6 +44,12 @@
<artifactId>jakarta.security.jacc-api</artifactId>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.9.0</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-context-propagation</artifactId>
@@ -77,39 +63,35 @@
<dependency>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-aggregates</artifactId>
<version>0.1.0</version>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.fuin.cqrs4j.example.quarkus</groupId>
<artifactId>cqrs4j-quarkus-example-shared</artifactId>
<version>0.1.0</version>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-esjc</artifactId>
<version>${esc.version}</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>cqrs-4-java</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
</dependency>
<!-- test -->
<dependency>
@@ -133,7 +115,7 @@
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>1.0.1.Final</version>
<version>${quarkus.version}</version>
<executions>
<execution>
<goals>
@@ -144,13 +126,13 @@
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<systemProperties>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
@@ -159,8 +141,8 @@
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<executions>
<execution>
<goals>
@@ -179,12 +161,11 @@
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.31.0</version>
<configuration>
<images>
<image>
<name>eventstore/eventstore:release-4.1.3</name>
<name>eventstore/eventstore:release-${eventstore.version}</name>
<run>
<network>
<mode>bridge</mode>
@@ -241,21 +222,4 @@
</profile>
</profiles>
<repositories>
<repository>
<id>sonatype.oss.snapshots</id>
<name>Sonatype OSS Snapshot Repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@@ -40,8 +40,8 @@ public class AggregateAlreadyExistsExceptionMapper implements ExceptionMapper<Ag
LOG.info("{} {}", ex.getShortId(), ex.getMessage());
return Response.status(Status.CONFLICT).entity(SimpleResult.error(ex.getShortId(), ex.getMessage()))
.type(headers.getMediaType()).build();
return Response.status(Status.CONFLICT).entity(SimpleResult.error(ex.getShortId(), ex.getMessage())).type(headers.getMediaType())
.build();
}
}

View File

@@ -40,8 +40,8 @@ public class AggregateDeletedExceptionMapper implements ExceptionMapper<Aggregat
LOG.info("{} {}", ex.getShortId(), ex.getMessage());
return Response.status(Status.GONE).entity(SimpleResult.error(ex.getShortId(), ex.getMessage()))
.type(headers.getMediaType()).build();
return Response.status(Status.GONE).entity(SimpleResult.error(ex.getShortId(), ex.getMessage())).type(headers.getMediaType())
.build();
}
}

View File

@@ -40,8 +40,8 @@ public class AggregateNotFoundExceptionMapper implements ExceptionMapper<Aggrega
LOG.info("{} {}", ex.getShortId(), ex.getMessage());
return Response.status(Status.NOT_FOUND).entity(SimpleResult.error(ex.getShortId(), ex.getMessage()))
.type(headers.getMediaType()).build();
return Response.status(Status.NOT_FOUND).entity(SimpleResult.error(ex.getShortId(), ex.getMessage())).type(headers.getMediaType())
.build();
}
}

View File

@@ -40,8 +40,8 @@ public class AggregateVersionConflictExceptionMapper implements ExceptionMapper<
LOG.info("{} {}", ex.getShortId(), ex.getMessage());
return Response.status(Status.CONFLICT).entity(SimpleResult.error(ex.getShortId(), ex.getMessage()))
.type(headers.getMediaType()).build();
return Response.status(Status.CONFLICT).entity(SimpleResult.error(ex.getShortId(), ex.getMessage())).type(headers.getMediaType())
.build();
}
}

View File

@@ -35,13 +35,13 @@ public class AggregateVersionNotFoundExceptionMapper implements ExceptionMapper<
@Context
private HttpHeaders headers;
@Override
@Override
public Response toResponse(final AggregateVersionNotFoundException ex) {
LOG.error("{} {}", ex.getShortId(), ex.getMessage());
return Response.status(Status.NOT_FOUND).entity(SimpleResult.error(ex.getShortId(), ex.getMessage()))
.type(headers.getMediaType()).build();
return Response.status(Status.NOT_FOUND).entity(SimpleResult.error(ex.getShortId(), ex.getMessage())).type(headers.getMediaType())
.build();
}
}

View File

@@ -16,7 +16,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import org.fuin.objects4j.common.Nullable;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.ws.rs.core.Context;
@@ -55,7 +55,7 @@ public class ConstraintViolationExceptionMapper implements ExceptionMapper<Const
}
private static String asString(@Nullable final Set<ConstraintViolation<?>> constraintViolations) {
if (constraintViolations == null || constraintViolations.size() == 0) {
if (constraintViolations == null || constraintViolations.isEmpty()) {
return "";
}
final List<String> list = new ArrayList<>();

View File

@@ -48,7 +48,7 @@ public class PersonResource {
@Context
UriInfo uriInfo;
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@@ -64,18 +64,18 @@ public class PersonResource {
try {
// Create aggregate
final Person person = new Person(cmd.getAggregateRootId(), cmd.getName(), (name) -> {
final Person person = new Person(cmd.getAggregateRootId(), cmd.getName(), name -> {
// TODO Execute a call to the query side to verify if the name already exists
return Optional.empty();
});
repo.add(person);
// Send OK response
return Response.ok(SimpleResult.ok()).build();
return Response.ok(SimpleResult.ok()).build();
} catch (final DuplicatePersonNameException ex) {
throw new CommandExecutionFailedException(ex);
}
}
}

View File

@@ -3,7 +3,8 @@
quarkus.http.port=8081
quarkus.native.additional-build-args=-H:ReflectionConfigurationFiles=reflection-config.json,--report-unsupported-elements-at-runtime
quarkus.native.additional-build-args=-H:ReflectionConfigurationFiles=reflection-config.json,--initialize-at-run-time=org.apache.http.impl.auth.NTLMEngineImpl
quarkus.native.native-image-xmx=8192m
quarkus.index-dependency.ddd4j.group-id=org.fuin
quarkus.index-dependency.ddd4j.artifact-id=ddd-4-java

View File

@@ -31,37 +31,28 @@ import io.quarkus.test.junit.QuarkusTest;
import io.restassured.http.ContentType;
@QuarkusTest
public class PersonResourceIT {
class PersonResourceIT {
@Inject
IESJCEventStore eventStore;
@Inject
Jsonb jsonb;
@Test
public void testCreate() {
void testCreate() {
// PREPARE
final PersonId personId = new PersonId(UUID.randomUUID());
final PersonName personName = new PersonName("Peter Parker");
final CreatePersonCommand cmd = new CreatePersonCommand(personId, personName);
final String json = jsonb.toJson(cmd);
// TEST & VERIFY
final SimpleResult result =
given()
.accept(ContentType.JSON)
.contentType(ContentType.JSON)
.body(json)
.when()
.post("/persons/create")
.then()
.statusCode(200)
.extract()
.as(SimpleResult.class);
final SimpleResult result = given().accept(ContentType.JSON).contentType(ContentType.JSON).body(json).when().post("/persons/create")
.then().statusCode(200).extract().as(SimpleResult.class);
assertThat(result.getType(), is(equalTo(ResultType.OK)));
final SimpleStreamId personStreamId = new SimpleStreamId(PersonId.TYPE + "-" + personId);
final StreamEventsSlice slice = eventStore.readEventsForward(personStreamId, 0, 1);
final List<CommonEvent> events = slice.getEvents();
@@ -71,7 +62,7 @@ public class PersonResourceIT {
final PersonCreatedEvent event = (PersonCreatedEvent) ce.getData();
assertThat(event.getEntityId(), is(equalTo(personId)));
assertThat(event.getName(), is(equalTo(personName)));
}
}

View File

@@ -4,11 +4,50 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-root</artifactId>
<version>0.2.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>org.fuin.cqrs4j.example.quarkus</groupId>
<artifactId>cqrs4j-quarkus-example-root</artifactId>
<version>0.1.0</version>
<packaging>pom</packaging>
<properties>
<quarkus.version>2.2.1.Final</quarkus.version>
<eventstore.version>5.0.9</eventstore.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus.platform</groupId>
<artifactId>quarkus-bom</artifactId>
<version>${quarkus.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-core</artifactId>
<version>3.1.8.Final</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>shared</module>
<module>query</module>

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2007-present the original author or authors.
*
* 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.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}

Binary file not shown.

View File

@@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

View File

@@ -16,12 +16,42 @@ Make sure you installed everything as described [here](../../../../).
## Overview
![Overview](https://raw.github.com/fuinorg/ddd-cqrs-4-java-example/master/quarkus/query/doc/cdi-view.png)
## Running test in IDE
In case you want to run the integration test inside your IDE (Eclipse or other), you need to start the Eventstore and MariaDB before.
1. Start the Eventstore Docker container:
```
docker run -d --name eventstore-node \
-p 2113:2113 \
-p 1113:1113 \
--rm \
eventstore/eventstore:release-5.0.9
```
2. Start the MariaDB Docker container:
```
docker run -d --name mariadb \
-p 3306:3306 \
-e MYSQL_INITDB_SKIP_TZINFO=1 \
-e MYSQL_ROOT_PASSWORD=xyz \
-e MYSQL_DATABASE=querydb \
-e MYSQL_USER=mary \
-e MYSQL_PASSWORD=abc \
--rm \
mariadb:10.4
```
3. Run the test: [QryPersonResourceIT.java](src/test/java/org/fuin/cqrs4j/example/quarkus/query/api/QryPersonResourceIT.java)
4. Run `docker ps` to see the CONTAINER IDs and stop the Eventstore and MariaDB with `docker stop <CONTAINER_ID>`
# TODO ... (Does currently not work)
## *OPTIONAL* Build and run the query microservice in native mode
1. Make sure you have enough memory (~6-8 GB) on your PC or VM
2. Open a console (Ubuntu shortcut = <ctrl><alt><t>)
2. Open a console (Ubuntu shortcut = ctrl alt t)
3. Build the native executable
```
cd query

8
quarkus/query/mvnw vendored
View File

@@ -19,7 +19,7 @@
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
@@ -212,9 +212,9 @@ else
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
@@ -246,7 +246,7 @@ else
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"

View File

@@ -18,7 +18,7 @@
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@@ -26,7 +26,7 @@
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@@ -120,7 +120,7 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
@@ -134,7 +134,7 @@ if exist %WRAPPER_JAR% (
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...

View File

@@ -1,282 +1,246 @@
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
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"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<groupId>org.fuin.cqrs4j.example.quarkus</groupId>
<artifactId>cqrs4j-quarkus-example-query</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.fuin.cqrs4j.example.quarkus</groupId>
<artifactId>cqrs4j-quarkus-example-root</artifactId>
<version>0.2.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
<maven.compiler.parameters>true</maven.compiler.parameters>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<esc.version>0.3.1</esc.version>
</properties>
<artifactId>cqrs4j-quarkus-example-query</artifactId>
<dependencyManagement>
<dependencies>
<dependencies>
<!-- compile -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-universe-bom</artifactId>
<version>1.0.1.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
</dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
</dependencyManagement>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-scheduler</artifactId>
</dependency>
<!-- compile -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-mariadb</artifactId>
</dependency>
<dependency>
<groupId>jakarta.security.jacc</groupId>
<artifactId>jakarta.security.jacc-api</artifactId>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.9.0</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
<dependency>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-aggregates</artifactId>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.fuin.cqrs4j.example.quarkus</groupId>
<artifactId>cqrs4j-quarkus-example-shared</artifactId>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-scheduler</artifactId>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-eshttp</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm</artifactId>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
</dependency>
<!-- <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency> -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-mariadb</artifactId>
</dependency>
<!-- test -->
<dependency>
<groupId>jakarta.security.jacc</groupId>
<artifactId>jakarta.security.jacc-api</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-aggregates</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.fuin.cqrs4j.example.quarkus</groupId>
<artifactId>cqrs4j-quarkus-example-shared</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-eshttp</artifactId>
<version>${esc.version}</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<!-- test -->
<build>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<plugins>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.version}</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</dependencies>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemProperties>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
</systemProperties>
</configuration>
</plugin>
<build>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemProperties>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>1.0.1.Final</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
<images>
<image>
<name>eventstore/eventstore:release-${eventstore.version}</name>
<run>
<network>
<mode>bridge</mode>
</network>
<ports>
<port>1113:1113</port>
<port>2113:2113</port>
</ports>
<log>
<enabled>false</enabled>
</log>
<wait>
<http>
<url>http://localhost:2113/web/index.html#/</url>
<method>GET</method>
</http>
<time>20000</time>
</wait>
</run>
</image>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<image>
<name>mariadb:10.4</name>
<run>
<network>
<mode>bridge</mode>
</network>
<ports>
<port>3306:3306</port>
</ports>
<log>
<enabled>false</enabled>
</log>
<env>
<MYSQL_INITDB_SKIP_TZINFO>1</MYSQL_INITDB_SKIP_TZINFO>
<MYSQL_ROOT_PASSWORD>xyz</MYSQL_ROOT_PASSWORD>
<MYSQL_DATABASE>querydb</MYSQL_DATABASE>
<MYSQL_USER>mary</MYSQL_USER>
<MYSQL_PASSWORD>abc</MYSQL_PASSWORD>
</env>
<wait>
<time>10000</time>
</wait>
</run>
</image>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<systemProperties>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
</systemProperties>
</configuration>
</plugin>
</images>
</configuration>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemProperties>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
<executions>
<execution>
<id>start-images</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-images</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.31.0</version>
<configuration>
</plugin>
<images>
<image>
<name>eventstore/eventstore:release-4.1.3</name>
<run>
<network>
<mode>bridge</mode>
</network>
<ports>
<port>1113:1113</port>
<port>2113:2113</port>
</ports>
<log>
<enabled>false</enabled>
</log>
<wait>
<http>
<url>http://localhost:2113/web/index.html#/</url>
<method>GET</method>
</http>
<time>20000</time>
</wait>
</run>
</image>
</plugins>
<image>
<name>mariadb:10.4</name>
<run>
<network>
<mode>bridge</mode>
</network>
<ports>
<port>3306:3306</port>
</ports>
<log>
<enabled>false</enabled>
</log>
<env>
<MYSQL_INITDB_SKIP_TZINFO>1</MYSQL_INITDB_SKIP_TZINFO>
<MYSQL_ROOT_PASSWORD>xyz</MYSQL_ROOT_PASSWORD>
<MYSQL_DATABASE>querydb</MYSQL_DATABASE>
<MYSQL_USER>mary</MYSQL_USER>
<MYSQL_PASSWORD>abc</MYSQL_PASSWORD>
</env>
<wait>
<time>10000</time>
</wait>
</run>
</image>
</build>
</images>
</configuration>
<executions>
<execution>
<id>start-images</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-images</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
<repositories>
<repository>
<id>sonatype.oss.snapshots</id>
<name>Sonatype OSS Snapshot Repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<profiles>
<profile>
<id>native</id>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
</project>

View File

@@ -27,12 +27,13 @@ import org.fuin.objects4j.common.Contract;
@ApplicationScoped
public class QryProjectionPositionRepository implements ProjectionService {
private static final String ARG_STREAM_ID = "streamId";
@Inject
EntityManager em;
@Override
public void resetProjectionPosition(@NotNull final StreamId streamId) {
Contract.requireArgNotNull("streamId", streamId);
Contract.requireArgNotNull(ARG_STREAM_ID, streamId);
final QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString());
if (pos != null) {
pos.setNextPosition(0L);
@@ -41,7 +42,7 @@ public class QryProjectionPositionRepository implements ProjectionService {
@Override
public Long readProjectionPosition(@NotNull StreamId streamId) {
Contract.requireArgNotNull("streamId", streamId);
Contract.requireArgNotNull(ARG_STREAM_ID, streamId);
final QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString());
if (pos == null) {
return 0L;
@@ -51,7 +52,7 @@ public class QryProjectionPositionRepository implements ProjectionService {
@Override
public void updateProjectionPosition(@NotNull StreamId streamId, @NotNull Long nextEventNumber) {
Contract.requireArgNotNull("streamId", streamId);
Contract.requireArgNotNull(ARG_STREAM_ID, streamId);
Contract.requireArgNotNull("nextEventNumber", nextEventNumber);
final QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString());
if (pos == null) {

View File

@@ -14,5 +14,5 @@ package org.fuin.cqrs4j.example.quarkus.query.views;
/**
* Contains the views used in this query application. A view never uses code of another view, means all views are completely independent of
* each other. As an exception, the 'commons' package has some small classes that are not view specific.
* each other. As an exception, the 'commons' package has some small classes that are not view specific.
*/

View File

@@ -15,7 +15,6 @@ package org.fuin.cqrs4j.example.quarkus.query.views.personlist;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import org.fuin.cqrs4j.EventHandler;
import org.fuin.cqrs4j.example.shared.PersonCreatedEvent;
@@ -29,21 +28,20 @@ import org.slf4j.LoggerFactory;
*/
@ApplicationScoped
public class PersonCreatedEventHandler implements EventHandler<PersonCreatedEvent> {
private static final Logger LOG = LoggerFactory.getLogger(PersonCreatedEventHandler.class);
@Inject
EntityManager em;
@Override
public EventType getEventType() {
return PersonCreatedEvent.TYPE;
}
@Override
@Transactional
public void handle(final PersonCreatedEvent event) {
LOG.info("Handle " + event.getClass().getSimpleName() + ": " + event);
LOG.info("Handle {}: {}", event.getClass().getSimpleName(), event);
final PersonId personId = event.getEntityId();
if (em.find(PersonListEntry.class, personId.asString()) == null) {
em.persist(new PersonListEntry(personId, event.getName()));

View File

@@ -12,12 +12,15 @@
*/
package org.fuin.cqrs4j.example.quarkus.query.views.personlist;
import java.util.Set;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
import org.fuin.cqrs4j.EventDispatcher;
import org.fuin.cqrs4j.ProjectionService;
import org.fuin.cqrs4j.example.shared.SharedUtils;
import org.fuin.ddd4j.ddd.EventType;
import org.fuin.esc.api.ProjectionStreamId;
import org.fuin.esc.api.StreamEventsSlice;
import org.slf4j.Logger;
@@ -28,23 +31,36 @@ import org.slf4j.LoggerFactory;
public class PersonListEventChunkHandler {
private static final Logger LOG = LoggerFactory.getLogger(PersonListEventChunkHandler.class);
/** Unique name of the event store projection that is used. */
public static final ProjectionStreamId PROJECTION_STREAM_ID = new ProjectionStreamId("quarkus-qry-person-stream");
@Inject
EventDispatcher dispatcher;
PersonListEventDispatcher dispatcher;
@Inject
ProjectionService projectionService;
private ProjectionStreamId streamId;
/**
* Returns the name of the event store projection that is used by this handler.
*
* @return Unique projection stream name.
*/
public ProjectionStreamId getProjectionStreamId() {
if (streamId == null) {
final Set<EventType> eventTypes = dispatcher.getAllTypes();
final String name = "quarkus-qry-person-" + SharedUtils.calculateChecksum(eventTypes);
streamId = new ProjectionStreamId(name);
}
return streamId;
}
/**
* Returns the next event position to read.
*
* @return Number of the next event to read.
*/
public Long readNextEventNumber() {
return projectionService.readProjectionPosition(PROJECTION_STREAM_ID);
return projectionService.readProjectionPosition(getProjectionStreamId());
}
/**
@@ -53,10 +69,11 @@ public class PersonListEventChunkHandler {
* @param currentSlice
* Slice with events to dispatch.
*/
@Transactional
public void handleChunk(final StreamEventsSlice currentSlice) {
LOG.debug("Handle chunk: {}", currentSlice);
dispatcher.dispatchCommonEvents(currentSlice.getEvents());
projectionService.updateProjectionPosition(PROJECTION_STREAM_ID, currentSlice.getNextEventNumber());
projectionService.updateProjectionPosition(getProjectionStreamId(), currentSlice.getNextEventNumber());
}
}

View File

@@ -0,0 +1,67 @@
/**
* Copyright (C) 2015 Michael Schnell. All rights reserved. http://www.fuin.org/
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library. If not, see
* http://www.gnu.org/licenses/.
*/
package org.fuin.cqrs4j.example.quarkus.query.views.personlist;
import java.util.List;
import java.util.Set;
import javax.enterprise.context.ApplicationScoped;
import javax.validation.constraints.NotNull;
import org.fuin.cqrs4j.EventDispatcher;
import org.fuin.cqrs4j.SimpleEventDispatcher;
import org.fuin.ddd4j.ddd.Event;
import org.fuin.ddd4j.ddd.EventType;
import org.fuin.esc.api.CommonEvent;
/**
* Dispatches events for the person list view.
*/
@ApplicationScoped
public class PersonListEventDispatcher implements EventDispatcher {
private final SimpleEventDispatcher delegate;
/**
* Constructor with all events to be dispatched.
*
* @param createdHandler
* PersonCreatedEventHandler.
*/
public PersonListEventDispatcher(final PersonCreatedEventHandler createdHandler) {
super();
this.delegate = new SimpleEventDispatcher(createdHandler);
}
@Override
@NotNull
public Set<EventType> getAllTypes() {
return delegate.getAllTypes();
}
@Override
public void dispatchCommonEvents(@NotNull final List<CommonEvent> commonEvents) {
delegate.dispatchCommonEvents(commonEvents);
}
@Override
public void dispatchEvents(@NotNull final List<Event> events) {
delegate.dispatchEvents(events);
}
@Override
public void dispatchEvent(@NotNull final Event event) {
delegate.dispatchEvent(event);
}
}

View File

@@ -1,33 +0,0 @@
/**
* Copyright (C) 2015 Michael Schnell. All rights reserved. http://www.fuin.org/
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library. If not, see
* http://www.gnu.org/licenses/.
*/
package org.fuin.cqrs4j.example.quarkus.query.views.personlist;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import org.fuin.cqrs4j.EventDispatcher;
import org.fuin.cqrs4j.SimpleEventDispatcher;
/**
* Create an {@link EventDispatcher}.
*/
@ApplicationScoped
public class PersonListEventDispatcherFactory {
@Produces
@ApplicationScoped
public EventDispatcher createDispatcher(final PersonCreatedEventHandler createdHandler) {
return new SimpleEventDispatcher(createdHandler);
}
}

View File

@@ -13,7 +13,6 @@
package org.fuin.cqrs4j.example.quarkus.query.views.personlist;
import static org.fuin.cqrs4j.Cqrs4JUtils.tryLocked;
import static org.fuin.cqrs4j.example.quarkus.query.views.personlist.PersonListEventChunkHandler.PROJECTION_STREAM_ID;
import java.util.ArrayList;
import java.util.List;
@@ -24,7 +23,6 @@ import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.ObservesAsync;
import javax.inject.Inject;
import org.fuin.cqrs4j.EventDispatcher;
import org.fuin.cqrs4j.example.quarkus.query.app.QryCheckForViewUpdatesEvent;
import org.fuin.ddd4j.ddd.EventType;
import org.fuin.esc.api.TypeName;
@@ -53,7 +51,7 @@ public class PersonListProjector {
PersonListEventChunkHandler chunkHandler;
@Inject
EventDispatcher dispatcher;
PersonListEventDispatcher dispatcher;
/**
* Listens for timer events. If a second timer event occurs while the previous call is still being executed, the method will simply be
@@ -74,24 +72,32 @@ public class PersonListProjector {
private void readStreamEvents() {
// TODO Make sure a projection with the correct events exists
// We must update the projection if new events are defined or some are removed!
if (!eventstore.projectionExists(PROJECTION_STREAM_ID)) {
final Set<EventType> eventTypes = dispatcher.getAllTypes();
final List<TypeName> typeNames = new ArrayList<>();
for (final EventType eventType : eventTypes) {
typeNames.add(new TypeName(eventType.asBaseType()));
}
LOG.info("Create projection '{}' with events: {}", PROJECTION_STREAM_ID, typeNames);
eventstore.createProjection(PROJECTION_STREAM_ID, true, typeNames);
// Create an event store projection if it does not exist.
if (!eventstore.projectionExists(chunkHandler.getProjectionStreamId())) {
final List<TypeName> typeNames = getEventTypeNames();
LOG.info("Create projection '{}' with events: {}", chunkHandler.getProjectionStreamId(), typeNames);
eventstore.createProjection(chunkHandler.getProjectionStreamId(), true, typeNames);
}
// Read and dispatch events
final Long nextEventNumber = chunkHandler.readNextEventNumber();
eventstore.readAllEventsForward(PROJECTION_STREAM_ID, nextEventNumber, 100, (currentSlice) -> {
chunkHandler.handleChunk(currentSlice);
});
eventstore.readAllEventsForward(chunkHandler.getProjectionStreamId(), nextEventNumber, 100,
currentSlice -> chunkHandler.handleChunk(currentSlice));
}
/**
* Returns a list of all event type names used for this projection.
*
* @return List of event names.
*/
public List<TypeName> getEventTypeNames() {
final List<TypeName> typeNames = new ArrayList<>();
final Set<EventType> eventTypes = dispatcher.getAllTypes();
for (final EventType eventType : eventTypes) {
typeNames.add(new TypeName(eventType.asBaseType()));
}
return typeNames;
}
}

View File

@@ -1,17 +1,13 @@
# Configuration file
#quarkus.datasource.url=jdbc:postgresql://localhost:5432/querydb
#quarkus.datasource.driver=org.postgresql.Driver
#quarkus.datasource.username=postgres
#quarkus.datasource.password=abc
quarkus.datasource.url=jdbc:mariadb://localhost:3306/querydb
quarkus.datasource.driver=org.mariadb.jdbc.Driver
quarkus.datasource.db-kind=mariadb
quarkus.datasource.username=mary
quarkus.datasource.password=abc
quarkus.datasource.jdbc.url=jdbc:mariadb://localhost:3306/querydb
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.log.level=INFO
quarkus.native.additional-build-args=--report-unsupported-elements-at-runtime
quarkus.native.additional-build-args=--initialize-at-run-time=org.apache.http.impl.auth.NTLMEngineImpl
quarkus.native.native-image-xmx=8192m

View File

@@ -31,71 +31,52 @@ import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest
public class QryPersonResourceIT {
class QryPersonResourceIT {
@Inject
IESHttpEventStore eventStore;
@Inject
EntityManager em;
@Test
public void testGetByIdNotFound() {
given()
.pathParam("id", UUID.randomUUID())
.when()
.get("/persons/{id}")
.then()
.statusCode(404);
void testGetByIdNotFound() {
given().pathParam("id", UUID.randomUUID()).when().get("/persons/{id}").then().statusCode(404);
}
@ActivateRequestContext
public boolean findPerson(final PersonId personId) {
return em.find(PersonListEntry.class, personId.asString()) != null;
}
@Test
public void testGetByIdOK() {
void testGetByIdOK() {
// PREPARE
final PersonId personId = new PersonId(UUID.randomUUID());
final PersonName personName = new PersonName("Peter Parker");
final SimpleStreamId personStreamId = new SimpleStreamId(PersonId.TYPE + "-" + personId);
final PersonCreatedEvent event = new PersonCreatedEvent(personId, personName);
final CommonEvent ce = new SimpleCommonEvent(new EventId(event.getEventId().asBaseType()),
new TypeName(event.getEventType().asBaseType()), event);
final CommonEvent ce = new SimpleCommonEvent(new EventId(event.getEventId().asBaseType()),
new TypeName(event.getEventType().asBaseType()), event);
eventStore.appendToStream(personStreamId, ce);
await().atMost(5, SECONDS).until(() -> findPerson(personId));
// TEST & VERIFY
final PersonListEntry person =
given()
.pathParam("id", personId.asString())
.when()
.get("/persons/{id}")
.then()
.statusCode(200)
.extract()
.as(PersonListEntry.class);
final PersonListEntry person = given().pathParam("id", personId.asString()).when().get("/persons/{id}").then().statusCode(200)
.extract().as(PersonListEntry.class);
assertThat(person.getId(), is(equalTo(personId)));
assertThat(person.getName(), is(equalTo(personName)));
final PersonListEntry[] persons =
given()
.when()
.get("/persons")
.then()
.statusCode(200)
.extract()
.as(PersonListEntry[].class);
final PersonListEntry[] persons = given().when().get("/persons").then().statusCode(200).extract().as(PersonListEntry[].class);
assertThat(Arrays.asList(persons), is(not(empty())));
final PersonListEntry person0 = persons[0];
assertThat(person0.getId(), is(equalTo(personId)));
assertThat(person0.getName(), is(equalTo(personName)));
}
}
}

View File

@@ -4,36 +4,17 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.fuin.cqrs4j.example.quarkus</groupId>
<parent>
<groupId>org.fuin.cqrs4j.example.quarkus</groupId>
<artifactId>cqrs4j-quarkus-example-root</artifactId>
<version>0.2.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>cqrs4j-quarkus-example-shared</artifactId>
<version>0.1.0</version>
<name>cqrs4j-quarkus-example-shared</name>
<description>Quarkus CQRS Shared Code for Demo Application</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
<esc.version>0.3.1</esc.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-universe-bom</artifactId>
<version>1.0.1.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Compile -->
@@ -41,37 +22,32 @@
<dependency>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-shared</artifactId>
<version>0.1.0</version>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>ddd-4-java</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>cqrs-4-java</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>objects4j</artifactId>
<version>0.6.9</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-esjc</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-eshttp</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
@@ -97,22 +73,11 @@
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<exclusions>
<exclusion>
<artifactId>jaxb-impl</artifactId>
<groupId>com.sun.xml.bind</groupId>
</exclusion>
<exclusion>
<artifactId>jaxb-api</artifactId>
<groupId>javax.xml.bind</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.4</version>
<artifactId>jakarta.json</artifactId>
</dependency>
<dependency>
@@ -130,55 +95,111 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>units4j</artifactId>
<version>0.8.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>2.4.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<build>
<repository>
<id>sonatype.oss.snapshots</id>
<name>Sonatype OSS Snapshot Repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
<enabled>true</enabled>
</snapshots>
</repository>
<plugins>
</repositories>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<includes>
<include>**/*</include>
</includes>
<archive>
<manifestEntries>
<Automatic-Module-Name>org.fuin.cqrs4j.example.shared</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jdeps-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jdeps-plugin</artifactId>
<versionRange>[3.1.2,)</versionRange>
<goals>
<goal>jdkinternals</goal>
<goal>test-jdkinternals</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore />
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@@ -71,14 +71,19 @@ public class Config {
/**
* Constructor with all data.
*
* @param eventStoreHost Host.
* @param eventStoreHttpPort HTTP port
* @param eventStoreTcpPort TCP port.
* @param eventStoreUser User.
* @param eventStorePassword Password.
* @param eventStoreHost
* Host.
* @param eventStoreHttpPort
* HTTP port
* @param eventStoreTcpPort
* TCP port.
* @param eventStoreUser
* User.
* @param eventStorePassword
* Password.
*/
public Config(final String eventStoreHost, final int eventStoreHttpPort, final int eventStoreTcpPort,
final String eventStoreUser, final String eventStorePassword) {
public Config(final String eventStoreHost, final int eventStoreHttpPort, final int eventStoreTcpPort, final String eventStoreUser,
final String eventStorePassword) {
super();
this.eventStoreHost = eventStoreHost;
this.eventStoreHttpPort = eventStoreHttpPort;

View File

@@ -30,8 +30,7 @@ public class EsjcEventStoreFactory {
@ApplicationScoped
public EventStore createESJC(final ManagedExecutor executor, final Config config) {
return EventStoreBuilder.newBuilder().singleNodeAddress(config.getEventStoreHost(), config.getEventStoreTcpPort())
.executor(executor).userCredentials(config.getEventStoreUser(), config.getEventStorePassword())
.build();
.executor(executor).userCredentials(config.getEventStoreUser(), config.getEventStorePassword()).build();
}
}

View File

@@ -12,7 +12,7 @@
*/
package org.fuin.cqrs4j.example.quarkus.shared;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
@@ -43,20 +43,22 @@ public class EventStoreFactory {
/**
* Creates an ESJC event store.<br>
* <br>
* CAUTION: The returned event store instance is NOT thread safe.
* CAUTION: The returned event store instance is NOT thread safe.
*
* @param es Native event store API.
* @param registry Serialization registry.
* @param es
* Native event store API.
* @param registry
* Serialization registry.
*
* @return Dependent scope event store.
*/
*/
@Produces
@RequestScoped
public IESJCEventStore createEventStore(final com.github.msemys.esjc.EventStore es,
final SerDeserializerRegistry registry) {
public IESJCEventStore createEventStore(final com.github.msemys.esjc.EventStore es, final SerDeserializerRegistry registry) {
final IESJCEventStore eventstore = new ESJCEventStore.Builder().eventStore(es).serDesRegistry(registry)
.targetContentType(EnhancedMimeType.create("application", "json", StandardCharsets.UTF_8)).build();
final IESJCEventStore eventstore = new ESJCEventStore(es, registry, registry,
EnhancedMimeType.create("application", "json", Charset.forName("utf-8")));
eventstore.open();
return eventstore;
@@ -65,7 +67,8 @@ public class EventStoreFactory {
/**
* Closes the ESJC event store when the context is disposed.
*
* @param es Event store to close.
* @param es
* Event store to close.
*/
public void closeEventStore(@Disposes final IESJCEventStore es) {
es.close();
@@ -92,8 +95,10 @@ public class EventStoreFactory {
config.getEventStorePassword());
credentialsProvider.setCredentials(AuthScope.ANY, credentials);
final ThreadFactory threadFactory = Executors.defaultThreadFactory();
final IESHttpEventStore eventStore = new ESHttpEventStore(threadFactory, config.getEventStoreURL(), ESEnvelopeType.JSON, registry,
registry, credentialsProvider);
final IESHttpEventStore eventStore = new ESHttpEventStore.Builder().threadFactory(threadFactory).url(config.getEventStoreURL())
.envelopeType(ESEnvelopeType.JSON).serDesRegistry(registry).credentialsProvider(credentialsProvider).build();
eventStore.open();
return eventStore;
@@ -108,5 +113,5 @@ public class EventStoreFactory {
public void closeEventStore(@Disposes final IESHttpEventStore es) {
es.close();
}
}

View File

@@ -34,8 +34,7 @@ public class JsonbFactory {
*/
@Produces
public Jsonb createJsonb() {
final JsonbConfig config = new JsonbConfig()
.withAdapters(SharedUtils.JSONB_ADAPTERS)
final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS)
.withPropertyVisibilityStrategy(new FieldAccessStrategy());
return JsonbBuilder.create(config);
}

View File

@@ -37,8 +37,7 @@ public class SerDeserializerRegistryFactory {
final JsonbDeSerializer jsonbDeSer = SharedUtils.createJsonbDeSerializer();
// Registry connects the type with the appropriate serializer and de-serializer
return SharedUtils.createSerDeserializerRegistry(typeRegistry,
jsonbDeSer);
return SharedUtils.createSerDeserializerRegistry(typeRegistry, jsonbDeSer);
}

View File

@@ -1,38 +0,0 @@
#!/bin/bash
## Make sure hostname is set
MY_HOSTNAME=$(hostname)
if [ $(cat /etc/hosts | grep -c "$MY_HOSTNAME") -eq 0 ]; then
echo "Adding $MY_HOSTNAME to /etc/hosts"
sudo -- sh -c -e "echo '127.0.0.1 $MY_HOSTNAME' >> /etc/hosts"
else
echo "Host '$MY_HOSTNAME' already found in /etc/hosts"
fi
## Make sure ZLIB is in place
if [ $(dpkg-query -W -f='${Status}' zlib1g-dev 2>/dev/null | grep -c "ok installed") -eq 0 ]; then
sudo apt-get install zlib1g-dev
else
echo "zlib1g-dev already installed"
fi
## Install GraalVM 19.2.x (Based on OpenJDK 1.8.x)
. $SDKMAN_DIR/bin/sdkman-init.sh
if [ $(sdk list java | grep -c "installed | 19.2.1-grl") -eq 0 ]; then
sdk update
sdk install java 19.2.1-grl
else
echo "GraalVM 19.2.x already installed"
fi
## Configure GraalVM
if grep -q "export GRAALVM_HOME" ~/.profile; then
echo "GraalVM already exists in ~/.profile"
else
echo "Appending export of GRAALVM_HOME to ~/.profile"
echo "export GRAALVM_HOME=\"/home/developer/.sdkman/candidates/java/19.2.1-grl\"" >> ~/.profile
source ~/.profile
$GRAALVM_HOME/bin/gu install native-image
fi
echo "Setup successfully finished"

View File

@@ -1,38 +1,31 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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
https://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.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
* Copyright 2007-present the original author or authors.
*
* 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.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL =
"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
@@ -80,13 +73,13 @@ public class MavenWrapperDownloader {
}
}
}
System.out.println("- Downloading from: : " + url);
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
@@ -102,6 +95,16 @@ public class MavenWrapperDownloader {
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());

Binary file not shown.

View File

@@ -1 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

36
shared/mvnw vendored
View File

@@ -8,7 +8,7 @@
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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
@@ -19,7 +19,7 @@
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
@@ -114,7 +114,6 @@ if $mingw ; then
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
@@ -212,7 +211,11 @@ else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
@@ -221,22 +224,38 @@ else
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
wget "$jarUrl" -O "$wrapperJarPath"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
curl -o "$wrapperJarPath" "$jarUrl"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
@@ -277,6 +296,11 @@ if $cygwin; then
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \

45
shared/mvnw.cmd vendored
View File

@@ -7,7 +7,7 @@
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@@ -18,7 +18,7 @@
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@@ -26,7 +26,7 @@
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@@ -37,7 +37,7 @@
@echo off
@REM set title of command window
title %0
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
@@ -120,23 +120,44 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
echo Found %WRAPPER_JAR%
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
echo Finished downloading %WRAPPER_JAR%
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end

View File

@@ -1,166 +1,197 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-shared</artifactId>
<version>0.1.0</version>
<name>cqrs4j-example-shared</name>
<description>Shared code for all demo applications and client &amp; server</description>
<parent>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-root</artifactId>
<version>0.2.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
<esc.version>0.3.1</esc.version>
</properties>
<artifactId>cqrs4j-example-shared</artifactId>
<name>cqrs4j-example-shared</name>
<description>Shared code for all demo applications and client &amp; server</description>
<dependencies>
<dependencies>
<!-- Compile -->
<!-- Compile -->
<dependency>
<groupId>org.fuin</groupId>
<artifactId>ddd-4-java</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>ddd-4-java</artifactId>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>cqrs-4-java</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>cqrs-4-java</artifactId>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>objects4j</artifactId>
<version>0.6.9</version>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>objects4j</artifactId>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-api</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-api</artifactId>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-spi</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-spi</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>javax.json.bind</groupId>
<artifactId>javax.json.bind-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>jakarta.json.bind</groupId>
<artifactId>jakarta.json.bind-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
</dependency>
<!-- Test -->
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>units4j</artifactId>
<version>0.8.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.fuin</groupId>
<artifactId>units4j</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>2.4.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.10.Final</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>jaxb-impl</artifactId>
<groupId>com.sun.xml.bind</groupId>
</exclusion>
<exclusion>
<artifactId>jaxb-api</artifactId>
<groupId>javax.xml.bind</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.4</version>
<scope>test</scope>
</dependency>
<artifactId>jakarta.json</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</dependencies>
<repositories>
<build>
<repository>
<id>sonatype.oss.snapshots</id>
<name>Sonatype OSS Snapshot Repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
<enabled>true</enabled>
</snapshots>
</repository>
<plugins>
</repositories>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<includes>
<include>**/*</include>
</includes>
<archive>
<manifestEntries>
<Automatic-Module-Name>org.fuin.cqrs4j.example.shared</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jdeps-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jdeps-plugin</artifactId>
<versionRange>[3.1.2,)</versionRange>
<goals>
<goal>jdkinternals</goal>
<goal>test-jdkinternals</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore />
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@@ -17,7 +17,6 @@
*/
package org.fuin.cqrs4j.example.shared;
import javax.annotation.concurrent.Immutable;
import javax.json.bind.annotation.JsonbProperty;
import javax.validation.constraints.NotNull;
@@ -26,6 +25,7 @@ import org.fuin.ddd4j.ddd.DomainEventExpectedEntityIdPath;
import org.fuin.ddd4j.ddd.EventType;
import org.fuin.esc.spi.SerializedDataType;
import org.fuin.objects4j.common.Contract;
import org.fuin.objects4j.common.Immutable;
/**
* A new person should be created in the system.
@@ -56,8 +56,10 @@ public final class CreatePersonCommand extends AbstractAggregateCommand<PersonId
/**
* A new person was created in the system.
*
* @param id Identifies uniquely a person.
* @param name Name of a person.
* @param id
* Identifies uniquely a person.
* @param name
* Name of a person.
*/
public CreatePersonCommand(@NotNull final PersonId id, @NotNull final PersonName name) {
super(id, null);

View File

@@ -17,7 +17,6 @@
*/
package org.fuin.cqrs4j.example.shared;
import javax.annotation.concurrent.Immutable;
import javax.json.bind.annotation.JsonbProperty;
import javax.validation.constraints.NotNull;
@@ -26,6 +25,7 @@ import org.fuin.ddd4j.ddd.EntityIdPath;
import org.fuin.ddd4j.ddd.EventType;
import org.fuin.esc.spi.SerializedDataType;
import org.fuin.objects4j.common.Contract;
import org.fuin.objects4j.common.Immutable;
/**
* A new person was created in the system.
@@ -55,8 +55,10 @@ public final class PersonCreatedEvent extends AbstractDomainEvent<PersonId> {
/**
* A new person was created in the system.
*
* @param id Identifies uniquely a person.
* @param name Name of a person.
* @param id
* Identifies uniquely a person.
* @param name
* Name of a person.
*/
public PersonCreatedEvent(@NotNull final PersonId id, @NotNull final PersonName name) {
super(new EntityIdPath(id));

View File

@@ -19,13 +19,13 @@ package org.fuin.cqrs4j.example.shared;
import java.util.UUID;
import javax.annotation.concurrent.Immutable;
import javax.json.bind.adapter.JsonbAdapter;
import javax.validation.constraints.NotNull;
import org.fuin.ddd4j.ddd.AggregateRootUuid;
import org.fuin.ddd4j.ddd.EntityType;
import org.fuin.ddd4j.ddd.StringBasedEntityType;
import org.fuin.objects4j.common.Immutable;
import org.fuin.objects4j.ui.Label;
import org.fuin.objects4j.ui.ShortLabel;
import org.fuin.objects4j.ui.Tooltip;

View File

@@ -23,7 +23,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.concurrent.Immutable;
import javax.json.bind.adapter.JsonbAdapter;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
@@ -32,6 +31,7 @@ import javax.validation.Payload;
import javax.validation.constraints.NotNull;
import org.fuin.objects4j.common.ConstraintViolationException;
import org.fuin.objects4j.common.Immutable;
import org.fuin.objects4j.ui.Label;
import org.fuin.objects4j.ui.ShortLabel;
import org.fuin.objects4j.ui.Tooltip;
@@ -66,7 +66,8 @@ public final class PersonName extends AbstractStringValueObject {
/**
* Constructor with mandatory data.
*
* @param value Value.
* @param value
* Value.
*/
public PersonName(final String value) {
super();
@@ -83,14 +84,14 @@ public final class PersonName extends AbstractStringValueObject {
public final String toString() {
return value;
}
/**
* Verifies that a given string can be converted into the type.
*
* @param value Value to validate.
* @param value
* Value to validate.
*
* @return Returns <code>true</code> if it's a valid type else
* <code>false</code>.
* @return Returns <code>true</code> if it's a valid type else <code>false</code>.
*/
public static boolean isValid(final String value) {
if (value == null) {
@@ -107,16 +108,17 @@ public final class PersonName extends AbstractStringValueObject {
}
/**
* Verifies if the argument is valid and throws an exception if this is not the
* case.
* Verifies if the argument is valid and throws an exception if this is not the case.
*
* @param name Name of the value for a possible error message.
* @param value Value to check.
* @param name
* Name of the value for a possible error message.
* @param value
* Value to check.
*
* @throws ConstraintViolationException The value was not valid.
* @throws ConstraintViolationException
* The value was not valid.
*/
public static void requireArgValid(@NotNull final String name, @NotNull final String value)
throws ConstraintViolationException {
public static void requireArgValid(@NotNull final String name, @NotNull final String value) throws ConstraintViolationException {
if (!PersonName.isValid(value)) {
throw new ConstraintViolationException("The argument '" + name + "' is not valid: '" + value + "'");
@@ -163,8 +165,7 @@ public final class PersonName extends AbstractStringValueObject {
/**
* Converts the value object from/to string.
*/
public static final class Converter
implements ValueObjectConverter<String, PersonName>, JsonbAdapter<PersonName, String> {
public static final class Converter implements ValueObjectConverter<String, PersonName>, JsonbAdapter<PersonName, String> {
// Attribute Converter

View File

@@ -29,42 +29,42 @@ import org.fuin.ddd4j.ddd.EntityIdFactory;
*/
public final class SharedEntityIdFactory implements EntityIdFactory {
private Map<String, Function<String, EntityId>> valueOfMap;
private Map<String, Function<String, EntityId>> valueOfMap;
private Map<String, Function<String, Boolean>> isValidMap;
private Map<String, Function<String, Boolean>> isValidMap;
/**
* Default constructor.
*/
public SharedEntityIdFactory() {
super();
valueOfMap = new HashMap<>();
isValidMap = new HashMap<>();
valueOfMap.put(PersonId.TYPE.asString(), PersonId::valueOf);
isValidMap.put(PersonId.TYPE.asString(), PersonId::isValid);
}
/**
* Default constructor.
*/
public SharedEntityIdFactory() {
super();
valueOfMap = new HashMap<>();
isValidMap = new HashMap<>();
valueOfMap.put(PersonId.TYPE.asString(), PersonId::valueOf);
isValidMap.put(PersonId.TYPE.asString(), PersonId::isValid);
}
@Override
public EntityId createEntityId(final String type, final String id) {
final Function<String, EntityId> factory = valueOfMap.get(type);
if (factory == null) {
throw new IllegalArgumentException("Unknown type: " + type);
}
return factory.apply(id);
}
@Override
public EntityId createEntityId(final String type, final String id) {
final Function<String, EntityId> factory = valueOfMap.get(type);
if (factory == null) {
throw new IllegalArgumentException("Unknown type: " + type);
}
return factory.apply(id);
}
@Override
public boolean containsType(final String type) {
return valueOfMap.containsKey(type);
}
@Override
public boolean containsType(final String type) {
return valueOfMap.containsKey(type);
}
@Override
public boolean isValid(String type, String id) {
final Function<String, Boolean> func = isValidMap.get(type);
if (func == null) {
return false;
}
return func.apply(id);
}
@Override
public boolean isValid(String type, String id) {
final Function<String, Boolean> func = isValidMap.get(type);
if (func == null) {
return false;
}
return func.apply(id);
}
}

View File

@@ -19,7 +19,9 @@ package org.fuin.cqrs4j.example.shared;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.zip.Adler32;
import javax.json.bind.adapter.JsonbAdapter;
import javax.json.bind.config.PropertyVisibilityStrategy;
@@ -28,6 +30,7 @@ import org.fuin.ddd4j.ddd.AggregateVersionConverter;
import org.fuin.ddd4j.ddd.EntityIdConverter;
import org.fuin.ddd4j.ddd.EntityIdPathConverter;
import org.fuin.ddd4j.ddd.EventIdConverter;
import org.fuin.ddd4j.ddd.EventType;
import org.fuin.esc.spi.Base64Data;
import org.fuin.esc.spi.EscEvent;
import org.fuin.esc.spi.EscEvents;
@@ -45,12 +48,14 @@ import org.fuin.esc.spi.SimpleSerializerDeserializerRegistry;
*/
public final class SharedUtils {
private static final String APPLICATION_JSON = "application/json";
/** All types that will be written into and read from the event store. */
private static TypeClass[] USER_DEFINED_TYPES = new TypeClass[] {
private static final TypeClass[] USER_DEFINED_TYPES = new TypeClass[] {
new TypeClass(PersonCreatedEvent.SER_TYPE, PersonCreatedEvent.class) };
/** All JSON-B adapters from this module. */
public static JsonbAdapter<?, ?>[] JSONB_ADAPTERS = new JsonbAdapter<?, ?>[] { new EventIdConverter(),
public static final JsonbAdapter<?, ?>[] JSONB_ADAPTERS = new JsonbAdapter<?, ?>[] { new EventIdConverter(),
new EntityIdPathConverter(new SharedEntityIdFactory()), new EntityIdConverter(new SharedEntityIdFactory()),
new AggregateVersionConverter(), new PersonId.Converter(), new PersonName.Converter() };
@@ -98,14 +103,14 @@ public final class SharedUtils {
final SimpleSerializerDeserializerRegistry registry = new SimpleSerializerDeserializerRegistry();
// Base types always needed
registry.add(EscEvents.SER_TYPE, "application/json", jsonbDeSer);
registry.add(EscEvent.SER_TYPE, "application/json", jsonbDeSer);
registry.add(EscMeta.SER_TYPE, "application/json", jsonbDeSer);
registry.add(Base64Data.SER_TYPE, "application/json", jsonbDeSer);
registry.add(EscEvents.SER_TYPE, APPLICATION_JSON, jsonbDeSer);
registry.add(EscEvent.SER_TYPE, APPLICATION_JSON, jsonbDeSer);
registry.add(EscMeta.SER_TYPE, APPLICATION_JSON, jsonbDeSer);
registry.add(Base64Data.SER_TYPE, APPLICATION_JSON, jsonbDeSer);
// User defined types
for (final TypeClass tc : USER_DEFINED_TYPES) {
registry.add(tc.getType(), "application/json", jsonbDeSer);
registry.add(tc.getType(), APPLICATION_JSON, jsonbDeSer);
}
jsonbDeSer.init(typeRegistry, registry, registry);
@@ -126,9 +131,7 @@ public final class SharedUtils {
final JsonbDeSerializer jsonbDeSer = SharedUtils.createJsonbDeSerializer();
// Registry connects the type with the appropriate serializer and de-serializer
final SerDeserializerRegistry serDeserRegistry = SharedUtils.createSerDeserializerRegistry(typeRegistry, jsonbDeSer);
return serDeserRegistry;
return SharedUtils.createSerDeserializerRegistry(typeRegistry, jsonbDeSer);
}
@@ -141,12 +144,28 @@ public final class SharedUtils {
return JsonbDeSerializer.builder().withSerializers(EscSpiUtils.createEscJsonbSerializers())
.withDeserializers(EscSpiUtils.createEscJsonbDeserializers()).withAdapters(JSONB_ADAPTERS)
.withPropertyVisibilityStrategy(new FieldAccessStrategy()).withEncoding(Charset.forName("utf-8")).build();
.withPropertyVisibilityStrategy(new FieldAccessStrategy()).withEncoding(StandardCharsets.UTF_8).build();
}
/**
* Creates an Adler32 checksum based on on event type names.
*
* @param eventTypes
* Types to calculate a checksum for.
*
* @return Checksum based on all names.
*/
public static long calculateChecksum(final Collection<EventType> eventTypes) {
final Adler32 checksum = new Adler32();
for (final EventType eventType : eventTypes) {
checksum.update(eventType.asBaseType().getBytes(StandardCharsets.US_ASCII));
}
return checksum.getValue();
}
private static class FieldAccessStrategy implements PropertyVisibilityStrategy {
@Override
public boolean isVisible(Field field) {
return true;
@@ -156,9 +175,9 @@ public final class SharedUtils {
public boolean isVisible(Method method) {
return false;
}
}
}
/**
* Helper class for type/class combination.
*/

View File

@@ -35,74 +35,72 @@ import org.junit.Test;
// CHECKSTYLE:OFF
public final class CreatePersonCommandTest {
private static final String PERSON_UUID = "84565d62-115e-4502-b7c9-38ad69c64b05";
private static final String PERSON_UUID = "84565d62-115e-4502-b7c9-38ad69c64b05";
@Test
public final void testSerializeDeserialize() {
@Test
public final void testSerializeDeserialize() {
// PREPARE
final CreatePersonCommand original = createTestee();
// PREPARE
final CreatePersonCommand original = createTestee();
// TEST
final CreatePersonCommand copy = Utils4J.deserialize(Utils4J.serialize(original));
// TEST
final CreatePersonCommand copy = Utils4J.deserialize(Utils4J.serialize(original));
// VERIFY
assertThat(copy).isEqualTo(original);
assertThat(copy.getAggregateRootId()).isEqualTo(original.getAggregateRootId());
assertThat(copy.getName()).isEqualTo(original.getName());
// VERIFY
assertThat(copy).isEqualTo(original);
assertThat(copy.getAggregateRootId()).isEqualTo(original.getAggregateRootId());
assertThat(copy.getName()).isEqualTo(original.getName());
}
}
@Test
public final void testMarshalUnmarshalJson() {
@Test
public final void testMarshalUnmarshalJson() {
// PREPARE
final CreatePersonCommand original = createTestee();
// PREPARE
final CreatePersonCommand original = createTestee();
final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS)
.withPropertyVisibilityStrategy(new FieldAccessStrategy());
final Jsonb jsonb = JsonbBuilder.create(config);
final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS)
.withPropertyVisibilityStrategy(new FieldAccessStrategy());
final Jsonb jsonb = JsonbBuilder.create(config);
// TEST
final String json = jsonb.toJson(original, CreatePersonCommand.class);
final CreatePersonCommand copy = jsonb.fromJson(json, CreatePersonCommand.class);
// TEST
final String json = jsonb.toJson(original, CreatePersonCommand.class);
final CreatePersonCommand copy = jsonb.fromJson(json, CreatePersonCommand.class);
// VERIFY
assertThat(copy).isEqualTo(original);
assertThat(copy.getAggregateRootId()).isEqualTo(original.getAggregateRootId());
assertThat(copy.getName()).isEqualTo(original.getName());
// VERIFY
assertThat(copy).isEqualTo(original);
assertThat(copy.getAggregateRootId()).isEqualTo(original.getAggregateRootId());
assertThat(copy.getName()).isEqualTo(original.getName());
}
}
@Test
public final void testUnmarshalJsonFromFile() throws IOException {
@Test
public final void testUnmarshalJsonFromFile() throws IOException {
// PREPARE
// PREPARE
final String json = IOUtils.toString(this.getClass().getResourceAsStream("/commands/CreatePersonCommand.json"),
Charset.forName("utf-8"));
final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS)
.withPropertyVisibilityStrategy(new FieldAccessStrategy());
final Jsonb jsonb = JsonbBuilder.create(config);
final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS)
.withPropertyVisibilityStrategy(new FieldAccessStrategy());
final Jsonb jsonb = JsonbBuilder.create(config);
// TEST
final CreatePersonCommand copy = jsonb.fromJson(json, CreatePersonCommand.class);
// TEST
final CreatePersonCommand copy = jsonb.fromJson(json, CreatePersonCommand.class);
// VERIFY
assertThat(copy.getEventId().asBaseType()).isEqualTo(UUID.fromString("109a77b2-1de2-46fc-aee1-97fa7740a552"));
assertThat(copy.getTimestamp()).isEqualTo(ZonedDateTime.parse("2019-11-17T10:27:13.183+01:00[Europe/Berlin]"));
assertThat(copy.getAggregateRootId().asString()).isEqualTo(PERSON_UUID);
assertThat(copy.getName().asString()).isEqualTo("Peter Parker");
// VERIFY
assertThat(copy.getEventId().asBaseType()).isEqualTo(UUID.fromString("109a77b2-1de2-46fc-aee1-97fa7740a552"));
assertThat(copy.getEventTimestamp()).isEqualTo(ZonedDateTime.parse("2019-11-17T10:27:13.183+01:00[Europe/Berlin]"));
assertThat(copy.getAggregateRootId().asString()).isEqualTo(PERSON_UUID);
assertThat(copy.getName().asString()).isEqualTo("Peter Parker");
}
}
private CreatePersonCommand createTestee() {
final PersonId personId = new PersonId(UUID.fromString(PERSON_UUID));
final PersonName personName = new PersonName("Peter Parker");
return new CreatePersonCommand(personId, personName);
}
private CreatePersonCommand createTestee() {
final PersonId personId = new PersonId(UUID.fromString(PERSON_UUID));
final PersonName personName = new PersonName("Peter Parker");
return new CreatePersonCommand(personId, personName);
}
}
// CHECKSTYLE:ON

View File

@@ -33,7 +33,6 @@ import org.apache.commons.io.IOUtils;
import org.eclipse.yasson.FieldAccessStrategy;
import org.junit.Test;
// CHECKSTYLE:OFF
public final class PersonCreatedEventTest {
@@ -71,7 +70,7 @@ public final class PersonCreatedEventTest {
assertThat(copy.getName()).isEqualTo(original.getName());
}
@Test
public final void testUnmarshalJson() throws IOException {
@@ -92,12 +91,11 @@ public final class PersonCreatedEventTest {
}
@Test
public final void testToString() {
final PersonCreatedEvent testee = createTestee();
assertThat(testee.toString())
.isEqualTo("Person 'Peter Parker' (" + testee.getEntityId() + ") was created [Event " + testee.getEventId() + "]");
assertThat(testee)
.hasToString("Person 'Peter Parker' (" + testee.getEntityId() + ") was created [Event " + testee.getEventId() + "]");
}
private PersonCreatedEvent createTestee() {

View File

@@ -35,57 +35,55 @@ import nl.jqno.equalsverifier.Warning;
*/
public final class PersonIdTest {
private static final String PERSON_UUID = "84565d62-115e-4502-b7c9-38ad69c64b05";
private static final String PERSON_UUID = "84565d62-115e-4502-b7c9-38ad69c64b05";
@Test
public void testEquals() {
EqualsVerifier.forClass(PersonId.class).suppress(Warning.NONFINAL_FIELDS)
.withNonnullFields("entityType", "uuid")
.withPrefabValues(EntityType.class, new StringBasedEntityType("A"), new StringBasedEntityType("B"))
.verify();
}
@Test
public void testEquals() {
EqualsVerifier.forClass(PersonId.class).suppress(Warning.NONFINAL_FIELDS).withNonnullFields("entityType", "uuid")
.withPrefabValues(EntityType.class, new StringBasedEntityType("A"), new StringBasedEntityType("B")).verify();
}
@Test
public void testValueOf() {
final PersonId personId = PersonId.valueOf(PERSON_UUID);
@Test
public void testValueOf() {
final PersonId personId = PersonId.valueOf(PERSON_UUID);
assertThat(personId.asString()).isEqualTo(PERSON_UUID);
assertThat(personId.asString()).isEqualTo(PERSON_UUID);
}
}
@Test
public void testValueOfIllegalArgumentCharacter() {
try {
PersonId.valueOf("abc");
fail();
} catch (final ConstraintViolationException ex) {
assertThat(ex.getMessage()).isEqualTo("The argument 'value' is not valid: 'abc'");
}
}
@Test
public void testValueOfIllegalArgumentCharacter() {
try {
PersonId.valueOf("abc");
fail();
} catch (final ConstraintViolationException ex) {
assertThat(ex.getMessage()).isEqualTo("The argument 'value' is not valid: 'abc'");
}
}
@Test
public final void testConverterUnmarshal() throws Exception {
@Test
public final void testConverterUnmarshal() throws Exception {
// PREPARE
final String personIdValue = PERSON_UUID;
// PREPARE
final String personIdValue = PERSON_UUID;
// TEST
final PersonId personId = new PersonId.Converter().adaptFromJson(UUID.fromString(PERSON_UUID));
// TEST
final PersonId personId = new PersonId.Converter().adaptFromJson(UUID.fromString(PERSON_UUID));
// VERIFY
assertThat(personId.asString()).isEqualTo(personIdValue);
}
// VERIFY
assertThat(personId.asString()).isEqualTo(personIdValue);
}
@Test
public void testConverterMarshal() throws Exception {
@Test
public void testConverterMarshal() throws Exception {
final PersonId personId = PersonId.valueOf(PERSON_UUID);
final PersonId personId = PersonId.valueOf(PERSON_UUID);
// TEST
final UUID uuid = new PersonId.Converter().adaptToJson(personId);
// TEST
final UUID uuid = new PersonId.Converter().adaptToJson(personId);
// VERIFY
assertThat(uuid).isEqualTo(UUID.fromString(PERSON_UUID));
}
// VERIFY
assertThat(uuid).isEqualTo(UUID.fromString(PERSON_UUID));
}
}

View File

@@ -17,7 +17,6 @@
*/
package org.fuin.cqrs4j.example.shared;
import static org.assertj.core.api.Assertions.assertThat;
import org.fuin.objects4j.common.ConstraintViolationException;
@@ -76,8 +75,9 @@ public final class PersonNameTest {
assertThat(PersonName.isValid("Peter Parker")).isTrue();
assertThat(PersonName.isValid("")).isFalse();
assertThat(PersonName.isValid("123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789." + "12345")).isFalse();
assertThat(PersonName.isValid(
"123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "12345"))
.isFalse();
}
@@ -95,13 +95,12 @@ public final class PersonNameTest {
}
try {
PersonName.requireArgValid("d", "123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789." + "12345");
PersonName.requireArgValid("d",
"123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "12345");
Assert.fail();
} catch (final ConstraintViolationException ex) {
assertThat(ex.getMessage())
.isEqualTo("The argument 'd' is not valid: '" + "123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789." + "12345" + "'");
assertThat(ex.getMessage()).isEqualTo("The argument 'd' is not valid: '" + "123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789." + "12345" + "'");
}
}
@@ -113,8 +112,9 @@ public final class PersonNameTest {
assertThat(new PersonName.Validator().isValid("Peter Parker", null)).isTrue();
assertThat(new PersonName.Validator().isValid("", null)).isFalse();
assertThat(new PersonName.Validator().isValid("123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789." + "12345", null)).isFalse();
assertThat(new PersonName.Validator().isValid(
"123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "12345",
null)).isFalse();
}
@@ -126,8 +126,9 @@ public final class PersonNameTest {
assertThat(new PersonName.Converter().isValid(null)).isTrue();
assertThat(new PersonName.Converter().isValid("Peter Parker")).isTrue();
assertThat(new PersonName.Converter().isValid("123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789." + "12345")).isFalse();
assertThat(new PersonName.Converter().isValid(
"123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "12345"))
.isFalse();
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright (C) 2015 Michael Schnell. All rights reserved.
* http://www.fuin.org/
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option) any
* later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see http://www.gnu.org/licenses/.
*/
package org.fuin.cqrs4j.example.shared;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.HashSet;
import java.util.Set;
import org.fuin.ddd4j.ddd.EventType;
import org.junit.Test;
/**
* Test for the {@link SharedUtils} class.
*/
public final class SharedUtilsTest {
@Test
public void testCalculateChecksum() {
// PREPARE
final Set<EventType> eventTypes = new HashSet<>();
eventTypes.add(new EventType("PersonCreatedEvent"));
eventTypes.add(new EventType("PersonRenamedEvent"));
eventTypes.add(new EventType("PersonDeletedEvent"));
// TEST
final long checksum = SharedUtils.calculateChecksum(eventTypes);
// VERIFY
assertThat(checksum).isEqualTo(1341789591L);
}
}

View File

@@ -1,38 +1,31 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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
https://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.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
* Copyright 2007-present the original author or authors.
*
* 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.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL =
"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
@@ -80,13 +73,13 @@ public class MavenWrapperDownloader {
}
}
}
System.out.println("- Downloading from: : " + url);
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
@@ -102,6 +95,16 @@ public class MavenWrapperDownloader {
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());

Binary file not shown.

View File

@@ -1 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

View File

@@ -1,38 +1,31 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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
https://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.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
* Copyright 2007-present the original author or authors.
*
* 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.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL =
"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
@@ -80,13 +73,13 @@ public class MavenWrapperDownloader {
}
}
}
System.out.println("- Downloading from: : " + url);
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
@@ -102,6 +95,16 @@ public class MavenWrapperDownloader {
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());

View File

@@ -1 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

View File

@@ -8,7 +8,7 @@
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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
@@ -19,7 +19,7 @@
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
@@ -114,7 +114,6 @@ if $mingw ; then
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
@@ -212,7 +211,11 @@ else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
@@ -221,22 +224,38 @@ else
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
wget "$jarUrl" -O "$wrapperJarPath"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
curl -o "$wrapperJarPath" "$jarUrl"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
@@ -277,6 +296,11 @@ if $cygwin; then
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \

View File

@@ -7,7 +7,7 @@
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@@ -18,7 +18,7 @@
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@@ -26,7 +26,7 @@
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@@ -37,7 +37,7 @@
@echo off
@REM set title of command window
title %0
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
@@ -120,23 +120,44 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
echo Found %WRAPPER_JAR%
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
echo Finished downloading %WRAPPER_JAR%
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end

View File

@@ -2,28 +2,20 @@
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
<groupId>org.fuin.cqrs4j.example.spring</groupId>
<artifactId>cqrs4j-spring-example-root</artifactId>
<version>0.2.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>org.fuin.cqrs4j.example.spring</groupId>
<artifactId>cqrs4j-spring-example-command</artifactId>
<version>0.1.0</version>
<name>cqrs4j-spring-example-command</name>
<description>Spring Boot CQRS Command Demo Application</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
<esc.version>0.3.1</esc.version>
</properties>
<dependencies>
<!-- compile -->
@@ -31,19 +23,19 @@
<dependency>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-shared</artifactId>
<version>0.1.0</version>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.fuin.cqrs4j.example</groupId>
<artifactId>cqrs4j-example-aggregates</artifactId>
<version>0.1.0</version>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.fuin.cqrs4j.example.spring</groupId>
<artifactId>cqrs4j-spring-example-shared</artifactId>
<version>0.1.0</version>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
@@ -59,19 +51,16 @@
<dependency>
<groupId>org.fuin</groupId>
<artifactId>cqrs-4-java</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-spi</artifactId>
<version>${esc.version}</version>
</dependency>
<dependency>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-esjc</artifactId>
<version>${esc.version}</version>
</dependency>
<!-- runtime -->
@@ -113,6 +102,12 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
@@ -157,12 +152,11 @@
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.31.0</version>
<configuration>
<images>
<image>
<name>eventstore/eventstore:release-4.1.3</name>
<name>eventstore/eventstore:release-${eventstore.version}</name>
<run>
<network>
<mode>bridge</mode>

View File

@@ -8,24 +8,25 @@ import org.springframework.context.annotation.Bean;
import org.springframework.web.context.annotation.RequestScope;
@SpringBootApplication(scanBasePackages = { "org.fuin.cqrs4j.example.spring.command.app",
"org.fuin.cqrs4j.example.spring.command.controller", "org.fuin.cqrs4j.example.spring.shared" })
"org.fuin.cqrs4j.example.spring.command.controller", "org.fuin.cqrs4j.example.spring.shared" })
public class CmdApplication {
/**
* Creates an event sourced repository that can store a person.
*
* @param eventStore Event store to use.
*
* @return Repository only valid for the current request.
*/
@Bean
@RequestScope
public PersonRepository create(final IESJCEventStore eventStore) {
return new PersonRepository(eventStore);
}
/**
* Creates an event sourced repository that can store a person.
*
* @param eventStore
* Event store to use.
*
* @return Repository only valid for the current request.
*/
@Bean
@RequestScope
public PersonRepository create(final IESJCEventStore eventStore) {
return new PersonRepository(eventStore);
}
public static void main(String[] args) {
SpringApplication.run(CmdApplication.class, args);
}
public static void main(String[] args) {
SpringApplication.run(CmdApplication.class, args);
}
}

View File

@@ -40,33 +40,32 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/persons")
public class PersonController {
@Autowired
private PersonRepository repo;
@Autowired
private PersonRepository repo;
@Autowired
private Validator validator;
@Autowired
private Validator validator;
@PostMapping(path = "/create", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SimpleResult> create(@RequestBody final CreatePersonCommand cmd)
throws AggregateAlreadyExistsException, AggregateDeletedException, CommandExecutionFailedException,
DuplicatePersonNameException {
@PostMapping(path = "/create", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SimpleResult> create(@RequestBody final CreatePersonCommand cmd) throws AggregateAlreadyExistsException,
AggregateDeletedException, CommandExecutionFailedException, DuplicatePersonNameException {
// Verify preconditions
final Set<ConstraintViolation<CreatePersonCommand>> violations = validator.validate(cmd);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
// Verify preconditions
final Set<ConstraintViolation<CreatePersonCommand>> violations = validator.validate(cmd);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
// Create aggregate
final Person person = new Person(cmd.getAggregateRootId(), cmd.getName(), (name) -> {
// TODO Execute a call to the query side to verify if the name already exists
return Optional.empty();
});
repo.add(person);
// Create aggregate
final Person person = new Person(cmd.getAggregateRootId(), cmd.getName(), name -> {
// TODO Execute a call to the query side to verify if the name already exists
return Optional.empty();
});
repo.add(person);
// Send OK response
return new ResponseEntity<>(SimpleResult.ok(), HttpStatus.OK);
// Send OK response
return new ResponseEntity<>(SimpleResult.ok(), HttpStatus.OK);
}
}
}

View File

@@ -1,3 +1,3 @@
server.port = 8081
spring.http.converters.preferred-json-mapper=jsonb
spring.mvc.converters.preferred-json-mapper=jsonb

View File

@@ -39,49 +39,40 @@ import io.restassured.module.mockmvc.RestAssuredMockMvc;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = CmdApplication.class)
public class PersonControllerIT {
class PersonControllerIT {
@LocalServerPort
@LocalServerPort
int port;
@Autowired
WebApplicationContext wac;
@Autowired
IESJCEventStore eventStore;
@Autowired
@Autowired
WebApplicationContext wac;
@Autowired
IESJCEventStore eventStore;
@Autowired
Jsonb jsonb;
@BeforeEach
public void initRestAssuredMockMvcStandalone() {
RestAssured.port = port;
RestAssuredMockMvc.webAppContextSetup(wac);
}
@BeforeEach
public void initRestAssuredMockMvcStandalone() {
RestAssured.port = port;
RestAssuredMockMvc.webAppContextSetup(wac);
}
@Test
public void testCreate() {
void testCreate() {
// PREPARE
final PersonId personId = new PersonId(UUID.randomUUID());
final PersonName personName = new PersonName("Peter Parker");
final CreatePersonCommand cmd = new CreatePersonCommand(personId, personName);
final String json = jsonb.toJson(cmd);
// TEST & VERIFY
final SimpleResult result =
given()
.accept(ContentType.JSON)
.contentType(ContentType.JSON)
.body(json)
.when()
.post("/persons/create")
.then()
.statusCode(200)
.extract()
.as(SimpleResult.class);
final SimpleResult result = given().accept(ContentType.JSON).contentType(ContentType.JSON).body(json).when().post("/persons/create")
.then().statusCode(200).extract().as(SimpleResult.class);
assertThat(result.getType(), is(equalTo(ResultType.OK)));
final SimpleStreamId personStreamId = new SimpleStreamId(PersonId.TYPE + "-" + personId);
final StreamEventsSlice slice = eventStore.readEventsForward(personStreamId, 0, 1);
final List<CommonEvent> events = slice.getEvents();
@@ -91,7 +82,7 @@ public class PersonControllerIT {
final PersonCreatedEvent event = (PersonCreatedEvent) ce.getData();
assertThat(event.getEntityId(), is(equalTo(personId)));
assertThat(event.getName(), is(equalTo(personName)));
}
}

36
spring-boot/mvnw vendored
View File

@@ -8,7 +8,7 @@
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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
@@ -19,7 +19,7 @@
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
@@ -114,7 +114,6 @@ if $mingw ; then
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
@@ -212,7 +211,11 @@ else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
@@ -221,22 +224,38 @@ else
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
wget "$jarUrl" -O "$wrapperJarPath"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
curl -o "$wrapperJarPath" "$jarUrl"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
@@ -277,6 +296,11 @@ if $cygwin; then
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \

Some files were not shown because too many files have changed in this diff Show More