chore: Initial import of FLEX training material
This commit is contained in:
parent
c01246d4f7
commit
12235acc42
1020 changed files with 53940 additions and 0 deletions
56
flex-training-flexinale/.gitignore
vendored
Normal file
56
flex-training-flexinale/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
### IntelliJ
|
||||
.idea/
|
||||
out/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
target/
|
||||
|
||||
~*xlsx
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
201
flex-training-flexinale/LICENSE
Normal file
201
flex-training-flexinale/LICENSE
Normal 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.
|
||||
14
flex-training-flexinale/README.md
Normal file
14
flex-training-flexinale/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# flex-training-flexinale
|
||||
iSAQB Advanced Level FLEX training: This code contains our case study for the "flexinale" example.
|
||||
This is the main repo containing blueprint and solution.
|
||||
|
||||
## Architecture as a monolithic system
|
||||
This part is in the folder flexinale-monolith
|
||||
|
||||
## Architecture as a modulithic system
|
||||
Part 1 is in the folder flexinale-modulith-1-onion
|
||||
Part 2 is in the folder flexinale-modulith-1-components
|
||||
|
||||
## Architecture as a distributed, service-oriented, event-based system
|
||||
This part is in the folder flexinale-distributed
|
||||
|
||||
6
flex-training-flexinale/flexinale-distributed/README.md
Normal file
6
flex-training-flexinale/flexinale-distributed/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# flex-training-filmfestival
|
||||
iSAQB Advanced Level FLEX training: This code contains our case study code for the "filmfestival" example.
|
||||
This is the main repo containing blueprint and solution.
|
||||
|
||||
## Architecture as a distributed, service-oriented, event-based system
|
||||
This part is in the folder flexinale-distributed
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FindBugsFilter>
|
||||
<Match>
|
||||
<!-- spotbugs message is Possible null pointer dereference of Kino.kinoSaele in equals method.
|
||||
But the if statements before that line guarantee not null. -->
|
||||
<Class name="de.accso.flexinale.backoffice.domain.model.Kino" />
|
||||
<Bug pattern="NP_NULL_ON_SOME_PATH_MIGHT_BE_INFEASIBLE" />
|
||||
</Match>
|
||||
|
||||
<Match>
|
||||
<Class name="de.accso.flexinale.infrastructure.FlexinaleSpringConfig" />
|
||||
<Bug pattern="CT_CONSTRUCTOR_THROW"/>
|
||||
</Match>
|
||||
</FindBugsFilter>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
FROM amazoncorretto:21.0.1-alpine3.18
|
||||
|
||||
WORKDIR /app
|
||||
COPY ../../target/flexinale-distributed-backoffice-2024.3.0-spring-boot-fat-jar.jar /app
|
||||
|
||||
EXPOSE 8081
|
||||
|
||||
CMD ["java", "-jar", "flexinale-distributed-backoffice-2024.3.0-spring-boot-fat-jar.jar"]
|
||||
|
|
@ -0,0 +1 @@
|
|||
docker build -t de.accso/flexinale-distributed-backoffice:2024.3.0 -f Dockerfile ../../
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
FROM amazoncorretto:21.0.1-alpine3.18
|
||||
|
||||
WORKDIR /app
|
||||
COPY ../../target/flexinale-distributed-backoffice-2024.3.0-spring-boot-fat-jar.jar /app
|
||||
|
||||
EXPOSE 8081
|
||||
|
||||
CMD ["java", "-jar", "flexinale-distributed-backoffice-2024.3.0-spring-boot-fat-jar.jar"]
|
||||
|
|
@ -0,0 +1 @@
|
|||
podman build -t de.accso/flexinale-distributed-backoffice:2024.3.0 -f Dockerfile ../../
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>de.accso</groupId>
|
||||
<artifactId>flexinale-distributed</artifactId>
|
||||
<version>2024.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<artifactId>flexinale-distributed-backoffice</artifactId>
|
||||
<version>2024.3.0</version>
|
||||
<name>Flexinale Distributed Backoffice</name>
|
||||
<description>Flexinale - FLEX case-study "film festival", distributed services, backoffice</description>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-registry-prometheus</artifactId>
|
||||
<version>${micrometer.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${org-postgres.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>${apache-poi.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>${apache-poi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>de.accso</groupId>
|
||||
<artifactId>flexinale-distributed-common</artifactId>
|
||||
<version>2024.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.accso</groupId>
|
||||
<artifactId>flexinale-distributed-common</artifactId>
|
||||
<version>2024.3.0</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.accso</groupId>
|
||||
<artifactId>flexinale-distributed-security</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<version>2024.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.accso</groupId>
|
||||
<artifactId>flexinale-distributed-security_api_contract</artifactId>
|
||||
<version>2024.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.accso</groupId>
|
||||
<artifactId>flexinale-distributed-backoffice_api_contract</artifactId>
|
||||
<version>2024.3.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<!-- name extension of spring boot fat jar-->
|
||||
<configuration>
|
||||
<classifier>spring-boot-fat-jar</classifier>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build-info</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<additionalProperties>
|
||||
<flexinale.implementation>Distributed</flexinale.implementation>
|
||||
<flexinale.app>Backoffice</flexinale.app>
|
||||
</additionalProperties>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
<version>${spotbugs-maven-plugin.version}</version>
|
||||
<configuration>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.h3xstream.findsecbugs</groupId>
|
||||
<artifactId>findsecbugs-plugin</artifactId>
|
||||
<version>${findsecbugs-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<excludeFilterFile>SpotbugsExcludeFilter.xml</excludeFilterFile>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<!-- overwrite dependency on spotbugs if you want to specify the version of spotbugs -->
|
||||
<dependency>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs</artifactId>
|
||||
<version>${spotbugs.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Distributed - start Backoffice app ("FlexinaleDistributedApplicationBackoffice")" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" folderName="App Distributed">
|
||||
<option name="ENABLE_LAUNCH_OPTIMIZATION" value="false" />
|
||||
<module name="flexinale-distributed-backoffice" />
|
||||
<option name="SPRING_BOOT_MAIN_CLASS" value="de.accso.flexinale.FlexinaleDistributedApplicationBackoffice" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="de.accso.flexinale.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Distributed Backoffice - Actuator Events Published" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" folderName="Actuator Distributed" path="$PROJECT_DIR$/flexinale-distributed/flexinale-distributed-backoffice/src/test/curl/backoffice-actuator-events-published.http" requestIdentifier="#1">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Distributed Backoffice - Actuator Health" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" folderName="Actuator Distributed" path="$PROJECT_DIR$/flexinale-distributed/flexinale-distributed-backoffice/src/test/curl/backoffice-actuator-health.http" requestIdentifier="#1">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Distributed Backoffice - Actuator Info" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" folderName="Actuator Distributed" path="$PROJECT_DIR$/flexinale-distributed/flexinale-distributed-backoffice/src/test/curl/backoffice-actuator-info.http" requestIdentifier="#1">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Distributed Backoffice - Actuator Metrics" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" folderName="Actuator Distributed" path="$PROJECT_DIR$/flexinale-distributed/flexinale-distributed-backoffice/src/test/curl/backoffice-actuator-metrics.http" requestIdentifier="#1">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Distributed Backoffice - Actuator Prometheus" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" folderName="Actuator Distributed" path="$PROJECT_DIR$/flexinale-distributed/flexinale-distributed-backoffice/src/test/curl/backoffice-actuator-prometheus.http" requestIdentifier="#1">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package de.accso.flexinale;
|
||||
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
@SpringBootApplication
|
||||
@Profile({"!test-integrated &!test-distributed & !testdata"})
|
||||
public class FlexinaleDistributedApplicationBackoffice {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(FlexinaleDistributedApplicationBackoffice.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager(final EntityManagerFactory entityManagerFactory) {
|
||||
return new JpaTransactionManager(entityManagerFactory);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package de.accso.flexinale.backoffice.api_in.rest;
|
||||
|
||||
import org.apache.poi.poifs.filesystem.FileMagic;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
final class ExcelHelper {
|
||||
private ExcelHelper() {
|
||||
}
|
||||
|
||||
static boolean isExcelFile(final InputStream stream) throws IOException {
|
||||
return (FileMagic.valueOf(stream) == FileMagic.OOXML);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
package de.accso.flexinale.backoffice.api_in.rest;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_out.event.FilmPublisher;
|
||||
import de.accso.flexinale.backoffice.api_out.event.VorfuehrungPublisher;
|
||||
import de.accso.flexinale.backoffice.application.services.FilmUploadService;
|
||||
import de.accso.flexinale.backoffice.domain.model.Film;
|
||||
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
|
||||
import de.accso.flexinale.backoffice.application.services.FilmService;
|
||||
import de.accso.flexinale.backoffice.application.services.VorfuehrungService;
|
||||
import de.accso.flexinale.common.application.PersistMode;
|
||||
import de.accso.flexinale.common.application.PersistedEntityAndResult;
|
||||
import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalStateException;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static de.accso.flexinale.common.application.PersistedEntityAndResult.PersistedResult.ADDED;
|
||||
import static de.accso.flexinale.common.application.PersistedEntityAndResult.PersistedResult.UPDATED;
|
||||
|
||||
@RestController
|
||||
@Profile({ "!testdata-besucherportal & !testdata-ticketing" })
|
||||
public class FilmRestController {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FilmRestController.class);
|
||||
|
||||
@Autowired
|
||||
private FilmService filmService;
|
||||
|
||||
@Autowired
|
||||
private FilmUploadService filmUploadService;
|
||||
|
||||
@Autowired
|
||||
private FilmPublisher filmPublisher;
|
||||
|
||||
@Autowired
|
||||
private VorfuehrungService vorfuehrungService;
|
||||
|
||||
@Autowired
|
||||
private VorfuehrungPublisher vorfuehrungPublisher;
|
||||
|
||||
@GetMapping(value = "/rest/filme", produces = "application/json")
|
||||
@PreAuthorize("hasRole('ROLE_BESUCHER')")
|
||||
public List<Film> filme() {
|
||||
return filmService.filme();
|
||||
}
|
||||
|
||||
@GetMapping(value = "/rest/film/{id}", produces = "application/json")
|
||||
@PreAuthorize("hasRole('ROLE_BESUCHER')")
|
||||
public Film film(@PathVariable final String id) {
|
||||
Identifiable.Id filmId = Identifiable.Id.of(id);
|
||||
Film film = filmService.film(filmId);
|
||||
if (film == null) {
|
||||
throw new RestResourceNotFoundException("no Film %s found.".formatted(id));
|
||||
}
|
||||
|
||||
return film;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
ResponseEntity<RestResponseMessage> loadAndPersistAndPublishNewFilme(
|
||||
final BufferedInputStream stream, final String originalFilename) throws IOException
|
||||
{
|
||||
// load and persist
|
||||
Collection<PersistedEntityAndResult<Film>> addedAndUpdatedFilms =
|
||||
filmUploadService.loadDataFromExcelSheetAndPersistAndReturn(stream, PersistMode.UPDATE);
|
||||
|
||||
List<Film> addedFilms = addedAndUpdatedFilms.stream()
|
||||
.filter(filmWithResult -> filmWithResult.result().equals(ADDED))
|
||||
.map(PersistedEntityAndResult::entity)
|
||||
.toList();
|
||||
List<Film> updatedFilms = addedAndUpdatedFilms.stream()
|
||||
.filter(filmWithResult -> filmWithResult.result().equals(UPDATED))
|
||||
.map(PersistedEntityAndResult::entity)
|
||||
.toList();
|
||||
|
||||
publishFilmsAndVorfuehrungen(addedFilms, updatedFilms);
|
||||
|
||||
String message = "Uploaded the Excel file %s adding %d new Film entities and updating %d existing Film entities."
|
||||
.formatted(originalFilename, addedFilms.size(), updatedFilms.size());
|
||||
|
||||
RestUploadResult restUploadResult = new RestUploadResult(HttpStatus.OK, message);
|
||||
return ResponseEntity.status(restUploadResult.status())
|
||||
.body(new RestResponseMessage(restUploadResult.message()));
|
||||
}
|
||||
|
||||
private void publishFilmsAndVorfuehrungen(final List<Film> addedFilms, final List<Film> updatedFilms) {
|
||||
filmPublisher.publishNewFilms(addedFilms);
|
||||
filmPublisher.publishUpdatedFilms(updatedFilms);
|
||||
|
||||
List<Vorfuehrung> vorfuehrungen = vorfuehrungService.vorfuehrungen();
|
||||
for (Film updatedFilm: updatedFilms) {
|
||||
List<Vorfuehrung> vorfuehrungenToPublishAsUpdated = vorfuehrungen.stream()
|
||||
.filter(vorfuehrung -> vorfuehrung.film.id.equals(updatedFilm.id))
|
||||
.toList();
|
||||
vorfuehrungPublisher.publishUpdatedVorfuehrungen(vorfuehrungenToPublishAsUpdated);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/rest/filme")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public ResponseEntity<RestResponseMessage> uploadFilme(@RequestParam("file") final MultipartFile file) {
|
||||
try (BufferedInputStream stream = new BufferedInputStream(file.getInputStream())) {
|
||||
if (!ExcelHelper.isExcelFile(stream)) {
|
||||
String message = "Please upload a valid Excel file!";
|
||||
throw new FlexinaleIllegalStateException(message);
|
||||
}
|
||||
|
||||
return loadAndPersistAndPublishNewFilme(stream, file.getOriginalFilename());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
String message = "Could not upload the Excel file: %s: %s".formatted(file.getOriginalFilename(), ex.getMessage());
|
||||
RestBadRequestException exception = new RestBadRequestException(message, ex);
|
||||
LOGGER.error(message, exception);
|
||||
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
package de.accso.flexinale.backoffice.api_in.rest;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_out.event.KinoPublisher;
|
||||
import de.accso.flexinale.backoffice.api_out.event.VorfuehrungPublisher;
|
||||
import de.accso.flexinale.backoffice.application.services.KinoUploadService;
|
||||
import de.accso.flexinale.backoffice.application.services.KinoSaalUploadService;
|
||||
import de.accso.flexinale.backoffice.domain.model.Kino;
|
||||
import de.accso.flexinale.backoffice.domain.model.KinoSaal;
|
||||
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
|
||||
import de.accso.flexinale.backoffice.application.services.KinoService;
|
||||
import de.accso.flexinale.backoffice.application.services.VorfuehrungService;
|
||||
import de.accso.flexinale.common.application.PersistMode;
|
||||
import de.accso.flexinale.common.application.PersistedEntityAndResult;
|
||||
import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalStateException;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static de.accso.flexinale.common.application.PersistedEntityAndResult.PersistedResult.ADDED;
|
||||
import static de.accso.flexinale.common.application.PersistedEntityAndResult.PersistedResult.UPDATED;
|
||||
|
||||
@RestController
|
||||
@Profile({ "!testdata-besucherportal & !testdata-ticketing" })
|
||||
public class KinoKinoSaalRestController {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KinoKinoSaalRestController.class);
|
||||
|
||||
@Autowired
|
||||
private KinoService kinoService;
|
||||
|
||||
@Autowired
|
||||
private KinoUploadService kinoUploadService;
|
||||
|
||||
@Autowired
|
||||
private KinoSaalUploadService kinoSaalUploadService;
|
||||
|
||||
@Autowired
|
||||
private KinoPublisher kinoPublisher;
|
||||
|
||||
@Autowired
|
||||
private VorfuehrungService vorfuehrungService;
|
||||
|
||||
@Autowired
|
||||
private VorfuehrungPublisher vorfuehrungPublisher;
|
||||
|
||||
@GetMapping(value = "/rest/kinos", produces = "application/json")
|
||||
@PreAuthorize("hasRole('ROLE_BESUCHER')")
|
||||
public List<Kino> kinos() {
|
||||
return kinoService.kinos();
|
||||
}
|
||||
|
||||
@GetMapping(value = "/rest/kino/{id}", produces = "application/json")
|
||||
@PreAuthorize("hasRole('ROLE_BESUCHER')")
|
||||
public Kino kino(@PathVariable final String id) {
|
||||
Identifiable.Id kinoId = Identifiable.Id.of(id);
|
||||
Kino kino = kinoService.kino(kinoId);
|
||||
if (kino == null) {
|
||||
throw new RestResourceNotFoundException("no Kino %s found.".formatted(id));
|
||||
}
|
||||
|
||||
return kino;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
@PostMapping("/rest/kinos")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public ResponseEntity<RestResponseMessage> uploadKinosKinoSaele(@RequestParam("file") final MultipartFile file) {
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
|
||||
try {
|
||||
Collection<KinoSaal> alleKinoSaele;
|
||||
|
||||
// we need to open the stream twice, separately for KinoSaele ...
|
||||
try (BufferedInputStream stream = new BufferedInputStream(file.getInputStream())) {
|
||||
if (!ExcelHelper.isExcelFile(stream)) {
|
||||
String message = "Please upload a valid Excel file!";
|
||||
throw new FlexinaleIllegalStateException(message);
|
||||
}
|
||||
alleKinoSaele = loadKinoSaele(stream);
|
||||
}
|
||||
|
||||
// ... and for Kino
|
||||
try (BufferedInputStream stream = new BufferedInputStream(file.getInputStream())) {
|
||||
return loadAndPersistAndPublishNewKinosKinoSaele(stream, originalFilename, alleKinoSaele);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
String message = "Could not upload the Excel file: %s: %s".formatted(file.getOriginalFilename(), ex.getMessage());
|
||||
RestBadRequestException exception = new RestBadRequestException(message, ex);
|
||||
LOGGER.error(message, exception);
|
||||
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
Collection<KinoSaal> loadKinoSaele(final BufferedInputStream stream) throws IOException {
|
||||
return kinoSaalUploadService.loadDataFromExcelSheet(stream);
|
||||
}
|
||||
|
||||
ResponseEntity<RestResponseMessage> loadAndPersistAndPublishNewKinosKinoSaele(
|
||||
final BufferedInputStream stream, final String originalFilename,
|
||||
final Collection<KinoSaal> alleKinoSaele) throws IOException {
|
||||
// and then load and persist all Kinos (including their KinoSaele)
|
||||
Map<Identifiable.Id, Collection<KinoSaal>> alleKinosUndIhreSaele =
|
||||
kinoSaalUploadService.mapKinoSaeleToKino(alleKinoSaele);
|
||||
|
||||
List<Kino> addedKinos;
|
||||
List<Kino> updatedKinos;
|
||||
try {
|
||||
kinoUploadService.beforeLoad(alleKinosUndIhreSaele); // fix state of Kino-KinoSaal in map
|
||||
// load and persist
|
||||
Collection<PersistedEntityAndResult<Kino>> addedAndUpdatedKinos =
|
||||
kinoUploadService.loadDataFromExcelSheetAndPersistAndReturn(stream, PersistMode.UPDATE);
|
||||
|
||||
addedKinos = addedAndUpdatedKinos.stream()
|
||||
.filter(kinoWithResult -> kinoWithResult.result().equals(ADDED))
|
||||
.map(PersistedEntityAndResult::entity)
|
||||
.toList();
|
||||
updatedKinos = addedAndUpdatedKinos.stream()
|
||||
.filter(kinoWithResult -> kinoWithResult.result().equals(UPDATED))
|
||||
.map(PersistedEntityAndResult::entity)
|
||||
.toList();
|
||||
|
||||
publishKinosAndVorfuehrungen(addedKinos, updatedKinos);
|
||||
}
|
||||
finally {
|
||||
kinoUploadService.afterLoad(); // clear map
|
||||
}
|
||||
|
||||
String message = "Uploaded the Excel file %s adding %d new Kinos entities and updating %d existing Kinos entities."
|
||||
.formatted(originalFilename, addedKinos.size(), updatedKinos.size());
|
||||
|
||||
RestUploadResult restUploadResult = new RestUploadResult(HttpStatus.OK, message);
|
||||
return ResponseEntity.status(restUploadResult.status())
|
||||
.body(new RestResponseMessage(restUploadResult.message()));
|
||||
}
|
||||
|
||||
private void publishKinosAndVorfuehrungen(final List<Kino> addedKinos, final List<Kino> updatedKinos) {
|
||||
kinoPublisher.publishNewKinos(addedKinos);
|
||||
kinoPublisher.publishUpdatedKinos(updatedKinos);
|
||||
|
||||
List<Vorfuehrung> vorfuehrungen = vorfuehrungService.vorfuehrungen();
|
||||
List<Vorfuehrung> vorfuehrungenToPublishAsUpdated = new ArrayList<>();
|
||||
for (Kino updatedKino: updatedKinos) {
|
||||
for (KinoSaal updatedKinoSaal: updatedKino.kinoSaele) {
|
||||
vorfuehrungen.stream()
|
||||
.filter(vorfuehrung -> vorfuehrung.kinoSaal.id.equals(updatedKinoSaal.id))
|
||||
.forEach(vorfuehrungenToPublishAsUpdated::add);
|
||||
}
|
||||
}
|
||||
vorfuehrungPublisher.publishUpdatedVorfuehrungen(vorfuehrungenToPublishAsUpdated);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package de.accso.flexinale.backoffice.api_in.rest;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@SuppressWarnings("unused")
|
||||
public class RestBadRequestException extends RuntimeException {
|
||||
|
||||
// see https://www.springboottutorial.com/spring-boot-exception-handling-for-rest-services
|
||||
|
||||
public RestBadRequestException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public RestBadRequestException(final String message, final Exception ex) {
|
||||
super(message, ex);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package de.accso.flexinale.backoffice.api_in.rest;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
public class RestResourceNotFoundException extends RuntimeException {
|
||||
|
||||
// see https://www.springboottutorial.com/spring-boot-exception-handling-for-rest-services
|
||||
|
||||
public RestResourceNotFoundException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package de.accso.flexinale.backoffice.api_in.rest;
|
||||
|
||||
record RestResponseMessage(String message) {
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package de.accso.flexinale.backoffice.api_in.rest;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
record RestUploadResult(HttpStatus status, String message) {
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
package de.accso.flexinale.backoffice.api_in.rest;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_out.event.VorfuehrungPublisher;
|
||||
import de.accso.flexinale.backoffice.application.services.VorfuehrungUploadService;
|
||||
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
|
||||
import de.accso.flexinale.backoffice.application.services.VorfuehrungService;
|
||||
import de.accso.flexinale.common.application.PersistMode;
|
||||
import de.accso.flexinale.common.application.PersistedEntityAndResult;
|
||||
import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalStateException;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static de.accso.flexinale.common.application.PersistedEntityAndResult.PersistedResult.ADDED;
|
||||
import static de.accso.flexinale.common.application.PersistedEntityAndResult.PersistedResult.UPDATED;
|
||||
|
||||
@RestController
|
||||
@Profile({ "!testdata-besucherportal & !testdata-ticketing" })
|
||||
public class VorfuehrungRestController {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(VorfuehrungRestController.class);
|
||||
|
||||
@Autowired
|
||||
private VorfuehrungService vorfuehrungService;
|
||||
|
||||
@Autowired
|
||||
private VorfuehrungUploadService vorfuehrungUploadService;
|
||||
|
||||
@Autowired
|
||||
private VorfuehrungPublisher vorfuehrungPublisher;
|
||||
|
||||
@GetMapping(value = "/rest/vorfuehrungen", produces = "application/json")
|
||||
@PreAuthorize("hasRole('ROLE_BESUCHER')")
|
||||
public List<Vorfuehrung> vorfuehrungen() {
|
||||
return vorfuehrungService.vorfuehrungen();
|
||||
}
|
||||
|
||||
@GetMapping(value = "/rest/vorfuehrungen/{id}", produces = "application/json")
|
||||
@PreAuthorize("hasRole('ROLE_BESUCHER')")
|
||||
public Vorfuehrung vorfuehrung(@PathVariable final String id) {
|
||||
Identifiable.Id vorfuehrungId = Identifiable.Id.of(id);
|
||||
Vorfuehrung vorfuehrung = vorfuehrungService.vorfuehrung(vorfuehrungId);
|
||||
if (vorfuehrung == null) {
|
||||
throw new RestResourceNotFoundException("no Vorfuehrung %s found.".formatted(id));
|
||||
}
|
||||
|
||||
return vorfuehrung;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
@PostMapping("/rest/vorfuehrungen")
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public ResponseEntity<RestResponseMessage> uploadVorfuehrungen(@RequestParam("file") final MultipartFile file) {
|
||||
try (BufferedInputStream stream = new BufferedInputStream(file.getInputStream())) {
|
||||
if (!ExcelHelper.isExcelFile(stream)) {
|
||||
String message = "Please upload a valid Excel file!";
|
||||
throw new FlexinaleIllegalStateException(message);
|
||||
}
|
||||
|
||||
return loadAndPersistAndPublishNewVorfuehrungen(stream, file.getOriginalFilename());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
String message = "Could not upload the Excel file: %s: %s".formatted(file.getOriginalFilename(), ex.getMessage());
|
||||
RestBadRequestException exception = new RestBadRequestException(message, ex);
|
||||
LOGGER.error(message, exception);
|
||||
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
ResponseEntity<RestResponseMessage> loadAndPersistAndPublishNewVorfuehrungen(
|
||||
final BufferedInputStream stream, final String originalFilename) throws IOException
|
||||
{
|
||||
// load and persist
|
||||
Collection<PersistedEntityAndResult<Vorfuehrung>> addedAndUpdatedVorfuehrungen =
|
||||
vorfuehrungUploadService.loadDataFromExcelSheetAndPersistAndReturn(stream, PersistMode.UPDATE);
|
||||
|
||||
// publish as events
|
||||
List<Vorfuehrung> addedVorfuehrungen = addedAndUpdatedVorfuehrungen.stream()
|
||||
.filter(vorfuehrungWithResult -> vorfuehrungWithResult.result().equals(ADDED))
|
||||
.map(PersistedEntityAndResult::entity)
|
||||
.toList();
|
||||
vorfuehrungPublisher.publishNewVorfuehrungen(addedVorfuehrungen);
|
||||
List<Vorfuehrung> updatedVorfuehrungen = addedAndUpdatedVorfuehrungen.stream()
|
||||
.filter(vorfuehrungWithResult -> vorfuehrungWithResult.result().equals(UPDATED))
|
||||
.map(PersistedEntityAndResult::entity)
|
||||
.toList();
|
||||
vorfuehrungPublisher.publishUpdatedVorfuehrungen(updatedVorfuehrungen);
|
||||
|
||||
String message = "Uploaded the Excel file %s adding %d new Vorfuehrungen entities and updating %d existing Vorfuehrungen entities."
|
||||
.formatted(originalFilename, addedVorfuehrungen.size(), updatedVorfuehrungen.size());
|
||||
|
||||
RestUploadResult restUploadResult = new RestUploadResult(HttpStatus.OK, message);
|
||||
return ResponseEntity.status(restUploadResult.status())
|
||||
.body(new RestResponseMessage(restUploadResult.message()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package de.accso.flexinale.backoffice.api_out.event;
|
||||
|
||||
import de.accso.flexinale.backoffice.application.services.FilmService;
|
||||
import de.accso.flexinale.backoffice.application.services.KinoService;
|
||||
import de.accso.flexinale.backoffice.application.services.VorfuehrungService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Profile({"!test-integrated & !testdata"})
|
||||
public class BootstrappingPostConstructBackoffice {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BootstrappingPostConstructBackoffice.class);
|
||||
|
||||
@Autowired
|
||||
FilmService filmService;
|
||||
|
||||
@Autowired
|
||||
FilmPublisher filmPublisher;
|
||||
|
||||
@Autowired
|
||||
KinoService kinoService;
|
||||
|
||||
@Autowired
|
||||
KinoPublisher kinoPublisher;
|
||||
|
||||
@Autowired
|
||||
VorfuehrungService vorfuehrungService;
|
||||
|
||||
@Autowired
|
||||
VorfuehrungPublisher vorfuehrungPublisher;
|
||||
|
||||
// Alternatively annotate method with @EventListener(ApplicationReadyEvent.class)
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
LOGGER.info("Publishing existing data for FKKsV as *Created events");
|
||||
|
||||
loadAllFilmeFromDatabaseAndPublish();
|
||||
loadAllKinosFromDatabaseAndPublish();
|
||||
loadAllVorfuehrungenFromDatabaseAndPublish();
|
||||
|
||||
LOGGER.info("Publishing existing data for FKKsV as *Created events ... done");
|
||||
}
|
||||
|
||||
private void loadAllVorfuehrungenFromDatabaseAndPublish() {
|
||||
filmPublisher.publishNewFilms( filmService.filme() );
|
||||
}
|
||||
|
||||
private void loadAllKinosFromDatabaseAndPublish() {
|
||||
kinoPublisher.publishNewKinos( kinoService.kinos() );
|
||||
}
|
||||
|
||||
private void loadAllFilmeFromDatabaseAndPublish() {
|
||||
vorfuehrungPublisher.publishNewVorfuehrungen( vorfuehrungService.vorfuehrungen() );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package de.accso.flexinale.backoffice.api_out.event;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_contract.event.FilmCRUDEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.FilmCreatedEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.FilmDeletedEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.FilmUpdatedEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.FilmTO;
|
||||
import de.accso.flexinale.backoffice.api_out.event.mapper.Film2FilmTOMapper;
|
||||
import de.accso.flexinale.backoffice.domain.model.Film;
|
||||
import de.accso.flexinale.common.api.eventbus.EventBus;
|
||||
import de.accso.flexinale.common.api.eventbus.EventBusFactory;
|
||||
import de.accso.flexinale.common.api.eventbus.EventNotification;
|
||||
import de.accso.flexinale.common.api.eventbus.EventPublisher.EventPublisher3;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class FilmPublisher implements EventPublisher3<FilmCreatedEvent, FilmUpdatedEvent, FilmDeletedEvent> {
|
||||
private final EventBus<FilmCreatedEvent> createBus;
|
||||
private final EventBus<FilmUpdatedEvent> updateBus;
|
||||
private final EventBus<FilmDeletedEvent> deleteBus;
|
||||
|
||||
private final EventNotification notification;
|
||||
|
||||
public FilmPublisher(final EventBusFactory eventBusFactory,
|
||||
final EventNotification notification) {
|
||||
this.createBus = eventBusFactory.createOrGetEventBusFor(FilmCreatedEvent.class);
|
||||
this.updateBus = eventBusFactory.createOrGetEventBusFor(FilmUpdatedEvent.class);
|
||||
this.deleteBus = eventBusFactory.createOrGetEventBusFor(FilmDeletedEvent.class);
|
||||
|
||||
this.notification = notification;
|
||||
}
|
||||
|
||||
public void publishNewFilms(final Collection<Film> films) {
|
||||
publishCRUDEvents(films, FilmCRUDEvent.CRUD.CREATE);
|
||||
}
|
||||
|
||||
public void publishUpdatedFilms(final Collection<Film> films) {
|
||||
publishCRUDEvents(films, FilmCRUDEvent.CRUD.UPDATE);
|
||||
}
|
||||
|
||||
// currently we do not publish Deletions events
|
||||
public void publishDeletedFilms(final Collection<Film> films) {
|
||||
publishCRUDEvents(films, FilmCRUDEvent.CRUD.DELETE);
|
||||
}
|
||||
|
||||
private void publishCRUDEvents(final Collection<Film> changedFilms, final FilmCRUDEvent.CRUD mode) {
|
||||
for (Film film: changedFilms) {
|
||||
FilmTO filmTO = Film2FilmTOMapper.map(film);
|
||||
switch (mode) {
|
||||
case CREATE -> this.post (FilmCreatedEvent.class, new FilmCreatedEvent(filmTO));
|
||||
case UPDATE -> this.post2(FilmUpdatedEvent.class, new FilmUpdatedEvent(filmTO));
|
||||
case DELETE -> this.post3(FilmDeletedEvent.class, new FilmDeletedEvent(filmTO));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return FilmPublisher.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post(final Class<FilmCreatedEvent> eventType, final FilmCreatedEvent event) {
|
||||
this.createBus.publish(eventType, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post2(final Class<FilmUpdatedEvent> eventType, final FilmUpdatedEvent event) {
|
||||
this.updateBus.publish(eventType, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post3(final Class<FilmDeletedEvent> eventType, final FilmDeletedEvent event) {
|
||||
this.deleteBus.publish(eventType, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package de.accso.flexinale.backoffice.api_out.event;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_contract.event.KinoCRUDEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.KinoCreatedEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.KinoDeletedEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.KinoUpdatedEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.KinoTO;
|
||||
import de.accso.flexinale.backoffice.api_out.event.mapper.KinoKinoSaal2KinoKinoSaalTOMapper;
|
||||
import de.accso.flexinale.backoffice.domain.model.Kino;
|
||||
import de.accso.flexinale.common.api.eventbus.EventBus;
|
||||
import de.accso.flexinale.common.api.eventbus.EventBusFactory;
|
||||
import de.accso.flexinale.common.api.eventbus.EventNotification;
|
||||
import de.accso.flexinale.common.api.eventbus.EventPublisher.EventPublisher3;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class KinoPublisher implements EventPublisher3<KinoCreatedEvent, KinoUpdatedEvent, KinoDeletedEvent> {
|
||||
private final EventBus<KinoCreatedEvent> createBus;
|
||||
private final EventBus<KinoUpdatedEvent> updateBus;
|
||||
private final EventBus<KinoDeletedEvent> deleteBus;
|
||||
|
||||
private final EventNotification notification;
|
||||
|
||||
public KinoPublisher(final EventBusFactory eventBusFactory,
|
||||
final EventNotification notification) {
|
||||
this.createBus = eventBusFactory.createOrGetEventBusFor(KinoCreatedEvent.class);
|
||||
this.updateBus = eventBusFactory.createOrGetEventBusFor(KinoUpdatedEvent.class);
|
||||
this.deleteBus = eventBusFactory.createOrGetEventBusFor(KinoDeletedEvent.class);
|
||||
|
||||
this.notification = notification;
|
||||
}
|
||||
|
||||
public void publishNewKinos(final Collection<Kino> kinos) {
|
||||
publishCRUDEvents(kinos, KinoCRUDEvent.CRUD.CREATE);
|
||||
}
|
||||
|
||||
public void publishUpdatedKinos(final Collection<Kino> kinos) {
|
||||
publishCRUDEvents(kinos, KinoCRUDEvent.CRUD.UPDATE);
|
||||
}
|
||||
|
||||
// currently we do not publish Deletions events
|
||||
public void publishDeletedKinos(final Collection<Kino> kinos) {
|
||||
publishCRUDEvents(kinos, KinoCRUDEvent.CRUD.DELETE);
|
||||
}
|
||||
|
||||
private void publishCRUDEvents(final Collection<Kino> changedKinos, final KinoCRUDEvent.CRUD mode) {
|
||||
for (Kino kino: changedKinos) {
|
||||
KinoTO kinoTO = KinoKinoSaal2KinoKinoSaalTOMapper.mapKino(kino);
|
||||
switch (mode) {
|
||||
case CREATE -> this.post (KinoCreatedEvent.class, new KinoCreatedEvent(kinoTO));
|
||||
case UPDATE -> this.post2(KinoUpdatedEvent.class, new KinoUpdatedEvent(kinoTO));
|
||||
case DELETE -> this.post3(KinoDeletedEvent.class, new KinoDeletedEvent(kinoTO));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return KinoPublisher.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post(final Class<KinoCreatedEvent> eventType, final KinoCreatedEvent event) {
|
||||
this.createBus.publish(eventType, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post2(final Class<KinoUpdatedEvent> eventType, final KinoUpdatedEvent event) {
|
||||
this.updateBus.publish(eventType, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post3(final Class<KinoDeletedEvent> eventType, final KinoDeletedEvent event) {
|
||||
this.deleteBus.publish(eventType, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package de.accso.flexinale.backoffice.api_out.event;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_contract.event.VorfuehrungCRUDEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.VorfuehrungCreatedEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.VorfuehrungDeletedEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.VorfuehrungUpdatedEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.VorfuehrungTO;
|
||||
import de.accso.flexinale.backoffice.api_out.event.mapper.Vorfuehrung2VorfuehrungTOMapper;
|
||||
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
|
||||
import de.accso.flexinale.common.api.eventbus.EventBus;
|
||||
import de.accso.flexinale.common.api.eventbus.EventBusFactory;
|
||||
import de.accso.flexinale.common.api.eventbus.EventNotification;
|
||||
import de.accso.flexinale.common.api.eventbus.EventPublisher.EventPublisher3;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class VorfuehrungPublisher implements EventPublisher3<VorfuehrungCreatedEvent, VorfuehrungUpdatedEvent, VorfuehrungDeletedEvent> {
|
||||
private final EventBus<VorfuehrungCreatedEvent> createBus;
|
||||
private final EventBus<VorfuehrungUpdatedEvent> updateBus;
|
||||
private final EventBus<VorfuehrungDeletedEvent> deleteBus;
|
||||
|
||||
private final EventNotification notification;
|
||||
|
||||
public VorfuehrungPublisher(final EventBusFactory eventBusFactory,
|
||||
final EventNotification notification) {
|
||||
this.createBus = eventBusFactory.createOrGetEventBusFor(VorfuehrungCreatedEvent.class);
|
||||
this.updateBus = eventBusFactory.createOrGetEventBusFor(VorfuehrungUpdatedEvent.class);
|
||||
this.deleteBus = eventBusFactory.createOrGetEventBusFor(VorfuehrungDeletedEvent.class);
|
||||
|
||||
this.notification = notification;
|
||||
}
|
||||
|
||||
public void publishNewVorfuehrungen(final Collection<Vorfuehrung> vorfuehrungen) {
|
||||
publishCRUDEvents(vorfuehrungen, VorfuehrungCRUDEvent.CRUD.CREATE);
|
||||
}
|
||||
|
||||
public void publishUpdatedVorfuehrungen(final Collection<Vorfuehrung> vorfuehrungen) {
|
||||
publishCRUDEvents(vorfuehrungen, VorfuehrungCRUDEvent.CRUD.UPDATE);
|
||||
}
|
||||
|
||||
// currently we do not publish Deletions events
|
||||
public void publishDeletedVorfuehrungen(final Collection<Vorfuehrung> vorfuehrungen) {
|
||||
publishCRUDEvents(vorfuehrungen, VorfuehrungCRUDEvent.CRUD.DELETE);
|
||||
}
|
||||
|
||||
private void publishCRUDEvents(final Collection<Vorfuehrung> changedVorfuehrungen, final VorfuehrungCRUDEvent.CRUD mode) {
|
||||
for (Vorfuehrung vorfuehrung: changedVorfuehrungen) {
|
||||
VorfuehrungTO vorfuehrungTO = Vorfuehrung2VorfuehrungTOMapper.map(vorfuehrung);
|
||||
switch (mode) {
|
||||
case CREATE -> this.post (VorfuehrungCreatedEvent.class, new VorfuehrungCreatedEvent(vorfuehrungTO));
|
||||
case UPDATE -> this.post2(VorfuehrungUpdatedEvent.class, new VorfuehrungUpdatedEvent(vorfuehrungTO));
|
||||
case DELETE -> this.post3(VorfuehrungDeletedEvent.class, new VorfuehrungDeletedEvent(vorfuehrungTO));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return VorfuehrungPublisher.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post(final Class<VorfuehrungCreatedEvent> eventType, final VorfuehrungCreatedEvent event) {
|
||||
this.createBus.publish(eventType, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post2(final Class<VorfuehrungUpdatedEvent> eventType, final VorfuehrungUpdatedEvent event) {
|
||||
this.updateBus.publish(eventType, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post3(final Class<VorfuehrungDeletedEvent> eventType, final VorfuehrungDeletedEvent event) {
|
||||
this.deleteBus.publish(eventType, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package de.accso.flexinale.backoffice.api_out.event.mapper;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.FilmTO;
|
||||
import de.accso.flexinale.backoffice.domain.model.Film;
|
||||
|
||||
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
public final class Film2FilmTOMapper {
|
||||
|
||||
public static FilmTO map(final Film film) {
|
||||
return new FilmTO(film.id(), film.version,
|
||||
new FilmTO.Titel(getRawOrNull(film.titel)),
|
||||
new FilmTO.ImdbUrl(getRawOrNull(film.imdbUrl)),
|
||||
new FilmTO.DauerInMinuten(getRawOrNull(film.dauerInMinuten)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package de.accso.flexinale.backoffice.api_out.event.mapper;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.KinoSaalTO;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.KinoTO;
|
||||
import de.accso.flexinale.backoffice.domain.model.Kino;
|
||||
import de.accso.flexinale.backoffice.domain.model.KinoSaal;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
public final class KinoKinoSaal2KinoKinoSaalTOMapper {
|
||||
|
||||
public static KinoTO mapKino(final Kino kino) {
|
||||
final KinoTO mappedKino = new KinoTO(kino.id(), kino.version(),
|
||||
new KinoTO.Name(getRawOrNull(kino.name)),
|
||||
new KinoTO.Adresse(getRawOrNull(kino.adresse)),
|
||||
new KinoTO.EmailAdresse(getRawOrNull(kino.emailAdresse)),
|
||||
new HashSet<>());
|
||||
|
||||
kino.kinoSaele.stream()
|
||||
.map(kinoSaal -> mapKinoSaal(kinoSaal, mappedKino))
|
||||
.forEach(kinoSaal -> mappedKino.kinoSaele().add(kinoSaal));
|
||||
|
||||
return mappedKino;
|
||||
}
|
||||
|
||||
static KinoSaalTO mapKinoSaal(final KinoSaal kinoSaal) {
|
||||
Kino kino = kinoSaal.kino;
|
||||
KinoTO mappedKino = mapKino(kino);
|
||||
return new KinoSaalTO(kinoSaal.id(), kino.version,
|
||||
new KinoSaalTO.Name(getRawOrNull(kinoSaal.name)),
|
||||
new KinoSaalTO.AnzahlPlaetze(getRawOrNull(kinoSaal.anzahlPlaetze)),
|
||||
mappedKino);
|
||||
}
|
||||
|
||||
private static KinoSaalTO mapKinoSaal(final KinoSaal kinoSaal, final KinoTO kino) {
|
||||
return new KinoSaalTO(kinoSaal.id(), kinoSaal.version,
|
||||
new KinoSaalTO.Name(getRawOrNull(kinoSaal.name)),
|
||||
new KinoSaalTO.AnzahlPlaetze(getRawOrNull(kinoSaal.anzahlPlaetze)),
|
||||
kino);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package de.accso.flexinale.backoffice.api_out.event.mapper;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.FilmTO;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.KinoSaalTO;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.VorfuehrungTO;
|
||||
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
|
||||
|
||||
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
public final class Vorfuehrung2VorfuehrungTOMapper {
|
||||
|
||||
public static VorfuehrungTO map(final Vorfuehrung vorfuehrung) {
|
||||
FilmTO filmTO = Film2FilmTOMapper.map(vorfuehrung.film);
|
||||
KinoSaalTO kinoSaalTO = KinoKinoSaal2KinoKinoSaalTOMapper.mapKinoSaal(vorfuehrung.kinoSaal);
|
||||
|
||||
return new VorfuehrungTO(vorfuehrung.id(), vorfuehrung.version(),
|
||||
new VorfuehrungTO.Zeit(getRawOrNull(vorfuehrung.zeit)),
|
||||
filmTO, kinoSaalTO, kinoSaalTO.kino().id());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package de.accso.flexinale.backoffice.application.services;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.model.Film;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Transactional
|
||||
public class FilmService {
|
||||
|
||||
private final de.accso.flexinale.backoffice.domain.services.FilmService filmService;
|
||||
|
||||
public FilmService(de.accso.flexinale.backoffice.domain.services.FilmService filmService) {
|
||||
this.filmService = filmService;
|
||||
}
|
||||
|
||||
public List<Film> filme() {
|
||||
return filmService.filme();
|
||||
}
|
||||
|
||||
public Film film(Identifiable.Id filmId) {
|
||||
return filmService.film(filmId);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package de.accso.flexinale.backoffice.application.services;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.dao.FilmDao;
|
||||
import de.accso.flexinale.backoffice.domain.model.Film;
|
||||
import de.accso.flexinale.common.domain.model.AbstractDao;
|
||||
import de.accso.flexinale.common.application.services.AbstractExcelDataUploadService;
|
||||
import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalArgumentException;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Transactional
|
||||
public class FilmUploadService extends AbstractExcelDataUploadService<Film> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FilmUploadService.class);
|
||||
|
||||
private final FilmDao filmDao;
|
||||
|
||||
public FilmUploadService(final FilmDao filmDao) {
|
||||
this.filmDao = filmDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractDao<Film> getDao() {
|
||||
return filmDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameOfExcelDataType() {
|
||||
return Film.class.getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Film createDataFromExcelRow(final Row excelRow) {
|
||||
String filmId = excelRow.getCell(0).getStringCellValue();
|
||||
|
||||
Cell cellDauer = excelRow.getCell(3);
|
||||
int dauerInMinuten =
|
||||
switch(cellDauer.getCellType()) {
|
||||
case NUMERIC -> (int) cellDauer.getNumericCellValue();
|
||||
case STRING -> Integer.parseInt(cellDauer.getStringCellValue());
|
||||
default -> throw new FlexinaleIllegalArgumentException("Dauer is not a number");
|
||||
};
|
||||
|
||||
Film film = new Film(
|
||||
Identifiable.Id.of(filmId),
|
||||
new Film.Titel(excelRow.getCell(1).getStringCellValue()),
|
||||
new Film.ImdbUrl(excelRow.getCell(2).getStringCellValue()),
|
||||
new Film.DauerInMinuten(dauerInMinuten)
|
||||
);
|
||||
|
||||
LOGGER.debug("New Film created " + film);
|
||||
|
||||
return film;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package de.accso.flexinale.backoffice.application.services;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.dao.KinoSaalDao;
|
||||
import de.accso.flexinale.backoffice.domain.model.Kino;
|
||||
import de.accso.flexinale.backoffice.domain.model.KinoSaal;
|
||||
import de.accso.flexinale.common.application.PersistMode;
|
||||
import de.accso.flexinale.common.application.PersistedEntityAndResult;
|
||||
import de.accso.flexinale.common.domain.model.AbstractDao;
|
||||
import de.accso.flexinale.common.application.services.AbstractExcelDataUploadService;
|
||||
import de.accso.flexinale.common.shared_kernel.DeveloperMistakeException;
|
||||
import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalArgumentException;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
@Transactional
|
||||
public class KinoSaalUploadService extends AbstractExcelDataUploadService<KinoSaal> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KinoSaalUploadService.class);
|
||||
|
||||
private final KinoSaalDao kinoSaalDao;
|
||||
|
||||
public KinoSaalUploadService(final KinoSaalDao kinoSaalDao) {
|
||||
this.kinoSaalDao = kinoSaalDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractDao<KinoSaal> getDao() {
|
||||
return kinoSaalDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameOfExcelDataType() {
|
||||
return KinoSaal.class.getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PersistedEntityAndResult<KinoSaal>> loadDataFromExcelSheetAndPersistAndReturn(
|
||||
final InputStream stream, final PersistMode mode) {
|
||||
throw new DeveloperMistakeException("method must not be called on KinoSaalUploadService");
|
||||
}
|
||||
|
||||
@Override
|
||||
public KinoSaal createDataFromExcelRow(final Row excelRow) {
|
||||
String kinoSaalId = excelRow.getCell(0).getStringCellValue();
|
||||
|
||||
String kinoId = excelRow.getCell(3).getStringCellValue();
|
||||
|
||||
Cell cellAnzahlPlaetze = excelRow.getCell(2);
|
||||
int anzahlPlaetze =
|
||||
switch(cellAnzahlPlaetze.getCellType()) {
|
||||
case NUMERIC -> (int) cellAnzahlPlaetze.getNumericCellValue();
|
||||
case STRING -> Integer.parseInt(cellAnzahlPlaetze.getStringCellValue());
|
||||
default -> throw new FlexinaleIllegalArgumentException("Anzahl Plaetze is not a number");
|
||||
};
|
||||
|
||||
KinoSaal kinoSaal = new KinoSaal(
|
||||
Identifiable.Id.of(kinoSaalId),
|
||||
new KinoSaal.Name(excelRow.getCell(1).getStringCellValue()),
|
||||
new KinoSaal.AnzahlPlaetze(anzahlPlaetze),
|
||||
new Kino(Identifiable.Id.of(kinoId))
|
||||
);
|
||||
|
||||
LOGGER.debug("New KinoSaal created: " + kinoSaal);
|
||||
|
||||
return kinoSaal;
|
||||
}
|
||||
|
||||
public Map<Identifiable.Id, Collection<KinoSaal>> mapKinoSaeleToKino(final Collection<KinoSaal> kinoSaele) {
|
||||
Map<Identifiable.Id, Collection<KinoSaal>> saeleUndKinos = new HashMap<>();
|
||||
for (KinoSaal saal : kinoSaele) {
|
||||
Identifiable.Id key = saal.kino.id();
|
||||
|
||||
Collection<KinoSaal> kinoSaeleAlreadyMapped = saeleUndKinos.get(key);
|
||||
if (kinoSaeleAlreadyMapped == null) {
|
||||
HashSet<KinoSaal> saele = new HashSet<>();
|
||||
saele.add(saal);
|
||||
saeleUndKinos.put(key, saele);
|
||||
}
|
||||
else {
|
||||
kinoSaeleAlreadyMapped.add(saal);
|
||||
saeleUndKinos.put(key, kinoSaeleAlreadyMapped);
|
||||
}
|
||||
}
|
||||
return saeleUndKinos;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package de.accso.flexinale.backoffice.application.services;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.model.Kino;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Transactional
|
||||
public class KinoService {
|
||||
|
||||
private final de.accso.flexinale.backoffice.domain.services.KinoService kinoService;
|
||||
|
||||
public KinoService(de.accso.flexinale.backoffice.domain.services.KinoService kinoService) {
|
||||
this.kinoService = kinoService;
|
||||
}
|
||||
|
||||
|
||||
public Kino kino(Identifiable.Id kinoId) {
|
||||
return kinoService.kino(kinoId);
|
||||
}
|
||||
|
||||
public List<Kino> kinos() {
|
||||
return kinoService.kinos();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package de.accso.flexinale.backoffice.application.services;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.dao.KinoDao;
|
||||
import de.accso.flexinale.backoffice.domain.model.Kino;
|
||||
import de.accso.flexinale.backoffice.domain.model.KinoSaal;
|
||||
import de.accso.flexinale.common.domain.model.AbstractDao;
|
||||
import de.accso.flexinale.common.application.services.AbstractExcelDataUploadService;
|
||||
import de.accso.flexinale.common.shared_kernel.DeveloperMistakeException;
|
||||
import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalStateException;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@Transactional
|
||||
public class KinoUploadService extends AbstractExcelDataUploadService<Kino> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KinoUploadService.class);
|
||||
|
||||
private final KinoDao kinoDao;
|
||||
|
||||
private final Map<Identifiable.Id, Collection<KinoSaal>> alleKinosUndIhreSaele = new HashMap<>();
|
||||
|
||||
public KinoUploadService(KinoDao kinoDao) {
|
||||
this.kinoDao = kinoDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractDao<Kino> getDao() {
|
||||
return kinoDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameOfExcelDataType() {
|
||||
return Kino.class.getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeLoad(Object... o) {
|
||||
if ((o.length != 1) && (!(o[0] instanceof Map))) {
|
||||
throw new DeveloperMistakeException("wrong type: expecting a " +
|
||||
"Map<Identifiable.Id, Collection<KinoSaal>> of Kino and their KinoSaele");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Identifiable.Id, Collection<KinoSaal>> newKinoAndKinoSaele = (Map<Identifiable.Id, Collection<KinoSaal>>) o[0];
|
||||
this.alleKinosUndIhreSaele.putAll(newKinoAndKinoSaele);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterLoad(Object... o) {
|
||||
alleKinosUndIhreSaele.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Kino createDataFromExcelRow(final Row excelRow) {
|
||||
String kinoId = excelRow.getCell(0).getStringCellValue();
|
||||
|
||||
Collection<KinoSaal> saeleImKino = alleKinosUndIhreSaele.get(Identifiable.Id.of(kinoId));
|
||||
if (saeleImKino == null || saeleImKino.isEmpty()) {
|
||||
throw new FlexinaleIllegalStateException("no Saele for Kino %s found".formatted(kinoId));
|
||||
}
|
||||
|
||||
Kino kino = new Kino(
|
||||
Identifiable.Id.of(kinoId),
|
||||
new Kino.Name(excelRow.getCell(1).getStringCellValue()),
|
||||
new Kino.Adresse(excelRow.getCell(2).getStringCellValue()),
|
||||
new Kino.EmailAdresse(excelRow.getCell(3).getStringCellValue()),
|
||||
Set.copyOf(saeleImKino)
|
||||
);
|
||||
|
||||
LOGGER.debug("New Kino created: " + kino);
|
||||
|
||||
return kino;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package de.accso.flexinale.backoffice.application.services;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Transactional
|
||||
public class VorfuehrungService {
|
||||
|
||||
private final de.accso.flexinale.backoffice.domain.services.VorfuehrungService vorfuehrungService;
|
||||
|
||||
public VorfuehrungService(de.accso.flexinale.backoffice.domain.services.VorfuehrungService vorfuehrungService) {
|
||||
this.vorfuehrungService = vorfuehrungService;
|
||||
}
|
||||
|
||||
|
||||
public List<Vorfuehrung> vorfuehrungen() {
|
||||
return vorfuehrungService.vorfuehrungen();
|
||||
}
|
||||
|
||||
public Vorfuehrung vorfuehrung(Identifiable.Id vorfuehrungId) {
|
||||
return vorfuehrungService.vorfuehrung(vorfuehrungId);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package de.accso.flexinale.backoffice.application.services;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.dao.FilmDao;
|
||||
import de.accso.flexinale.backoffice.domain.dao.KinoSaalDao;
|
||||
import de.accso.flexinale.backoffice.domain.dao.VorfuehrungDao;
|
||||
import de.accso.flexinale.backoffice.domain.model.Film;
|
||||
import de.accso.flexinale.backoffice.domain.model.KinoSaal;
|
||||
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
|
||||
import de.accso.flexinale.common.domain.model.AbstractDao;
|
||||
import de.accso.flexinale.common.application.services.AbstractExcelDataUploadService;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Transactional
|
||||
public class VorfuehrungUploadService extends AbstractExcelDataUploadService<Vorfuehrung> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(VorfuehrungUploadService.class);
|
||||
|
||||
private final FilmDao filmDao;
|
||||
private final KinoSaalDao kinoSaalDao;
|
||||
|
||||
private final VorfuehrungDao vorfuehrungDao;
|
||||
|
||||
public VorfuehrungUploadService(final VorfuehrungDao vorfuehrungDao,
|
||||
final FilmDao filmDao,
|
||||
final KinoSaalDao kinoSaalDao) {
|
||||
this.filmDao = filmDao;
|
||||
this.kinoSaalDao = kinoSaalDao;
|
||||
this.vorfuehrungDao = vorfuehrungDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractDao<Vorfuehrung> getDao() {
|
||||
return vorfuehrungDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameOfExcelDataType() {
|
||||
return Vorfuehrung.class.getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vorfuehrung createDataFromExcelRow(final Row excelRow) {
|
||||
String vorfuehrungId = excelRow.getCell(0).getStringCellValue();
|
||||
|
||||
// expects date/time in format like for example 2023-02-20T17:45
|
||||
LocalDateTime zeit = LocalDateTime.parse(excelRow.getCell(1).getStringCellValue());
|
||||
|
||||
String filmId = excelRow.getCell(2).getStringCellValue();
|
||||
Film film = filmDao.findById(Identifiable.Id.of(filmId)).orElseThrow(IllegalStateException::new);
|
||||
|
||||
String kinoSaalId = excelRow.getCell(3).getStringCellValue();
|
||||
KinoSaal kinoSaal = kinoSaalDao.findById(Identifiable.Id.of(kinoSaalId)).orElseThrow(IllegalStateException::new);
|
||||
|
||||
Vorfuehrung vorfuehrung = new Vorfuehrung(Identifiable.Id.of(vorfuehrungId), new Vorfuehrung.Zeit(zeit), film, kinoSaal);
|
||||
|
||||
LOGGER.debug("New Vorfuehrung created: " + vorfuehrung);
|
||||
|
||||
return vorfuehrung;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package de.accso.flexinale.backoffice.domain.dao;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.model.Film;
|
||||
import de.accso.flexinale.common.domain.model.AbstractDao;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface FilmDao extends AbstractDao<Film> {
|
||||
|
||||
@Override
|
||||
Optional<Film> findById(final Identifiable.Id id);
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package de.accso.flexinale.backoffice.domain.dao;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.model.Kino;
|
||||
import de.accso.flexinale.common.domain.model.AbstractDao;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface KinoDao extends AbstractDao<Kino> {
|
||||
|
||||
@Override
|
||||
Optional<Kino> findById(final Identifiable.Id id);
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package de.accso.flexinale.backoffice.domain.dao;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.model.KinoSaal;
|
||||
import de.accso.flexinale.common.domain.model.AbstractDao;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface KinoSaalDao extends AbstractDao<KinoSaal> {
|
||||
|
||||
@Override
|
||||
Optional<KinoSaal> findById(final Identifiable.Id id);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package de.accso.flexinale.backoffice.domain.dao;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
|
||||
import de.accso.flexinale.common.domain.model.AbstractDao;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public interface VorfuehrungDao extends AbstractDao<Vorfuehrung> {
|
||||
|
||||
@Override
|
||||
Optional<Vorfuehrung> findById(final Identifiable.Id id);
|
||||
|
||||
List<Vorfuehrung> findByFilmId(final Identifiable.Id filmId);
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package de.accso.flexinale.backoffice.domain.model;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.*;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
public class Film implements Identifiable, Versionable, Mergeable<Film>, EqualsByContent {
|
||||
public record Titel(String raw) implements RawWrapper<String> {}
|
||||
public record ImdbUrl(String raw) implements RawWrapper<String> {}
|
||||
public record DauerInMinuten(Integer raw) implements RawWrapper<Integer> {}
|
||||
|
||||
public final Id id;
|
||||
public final Version version;
|
||||
|
||||
public Titel titel;
|
||||
public ImdbUrl imdbUrl;
|
||||
public DauerInMinuten dauerInMinuten;
|
||||
|
||||
public Film(final Id id) {
|
||||
this(id, Versionable.unknownVersion());
|
||||
}
|
||||
|
||||
public Film(final Id id, final Version version) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Film(final Id id,
|
||||
final Titel titel, final ImdbUrl imdbUrl, final DauerInMinuten dauerInMinuten) {
|
||||
this(id, Versionable.unknownVersion(), titel, imdbUrl, dauerInMinuten);
|
||||
}
|
||||
|
||||
public Film(final Id id, final Version version,
|
||||
final Titel titel, final ImdbUrl imdbUrl, final DauerInMinuten dauerInMinuten) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.titel = titel;
|
||||
this.imdbUrl = imdbUrl;
|
||||
this.dauerInMinuten = dauerInMinuten;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Film merge(final Film newData) {
|
||||
return new Film(this.id, this.version,
|
||||
newData.titel, newData.imdbUrl, newData.dauerInMinuten);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (!equalsByContent(o)) return false;
|
||||
|
||||
if (this == o) {return true;}
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
final Film that = (Film) o;
|
||||
return new EqualsBuilder().append(version, that.version).isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equalsByContent(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
final Film that = (Film) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(id, that.id)
|
||||
.append(titel, that.titel).append(imdbUrl, that.imdbUrl)
|
||||
.append(dauerInMinuten, that.dauerInMinuten).isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(titel).append(imdbUrl).append(dauerInMinuten).toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
package de.accso.flexinale.backoffice.domain.model;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.*;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Kino implements Identifiable, Versionable, Mergeable<Kino>, EqualsByContent {
|
||||
public record Name(String raw) implements RawWrapper<String> {}
|
||||
public record Adresse(String raw) implements RawWrapper<String> {}
|
||||
public record EmailAdresse(String raw) implements RawWrapper<String> {}
|
||||
|
||||
public final Id id;
|
||||
public final Version version;
|
||||
|
||||
public Name name;
|
||||
public Adresse adresse;
|
||||
public EmailAdresse emailAdresse;
|
||||
@DoNotCheckInArchitectureTests
|
||||
public Set<KinoSaal> kinoSaele = new HashSet<>();
|
||||
|
||||
public Kino(final Id id) {
|
||||
this(id, Versionable.unknownVersion());
|
||||
}
|
||||
|
||||
public Kino(final Id id, final Version version) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Kino(final Id id,
|
||||
final Name name, final Adresse adresse,
|
||||
final EmailAdresse emailAdresse, final Set<KinoSaal> kinoSaele) {
|
||||
this(id, Versionable.unknownVersion(), name, adresse, emailAdresse, kinoSaele);
|
||||
}
|
||||
|
||||
public Kino(final Id id, final Version version,
|
||||
final Name name, final Adresse adresse,
|
||||
final EmailAdresse emailAdresse, final Set<KinoSaal> kinoSaele) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.name = name;
|
||||
this.adresse = adresse;
|
||||
this.emailAdresse = emailAdresse;
|
||||
this.kinoSaele = kinoSaele;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Kino merge(final Kino newData) {
|
||||
Map<Id, KinoSaal> mapIdToOldKinoSaal = new HashMap<>();
|
||||
this.kinoSaele.forEach(oldKinoSaal -> {
|
||||
mapIdToOldKinoSaal.put(oldKinoSaal.id(), oldKinoSaal);
|
||||
});
|
||||
|
||||
Set<KinoSaal> mergedKinoSaele = newData.kinoSaele.stream().map(newKinoSaal -> {
|
||||
KinoSaal oldKinoSaal = mapIdToOldKinoSaal.get(newKinoSaal.id);
|
||||
if (oldKinoSaal != null) {
|
||||
return oldKinoSaal.merge(newKinoSaal);
|
||||
}
|
||||
else {
|
||||
return newKinoSaal;
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Kino mergedKino = new Kino(this.id, this.version,
|
||||
newData.name, newData.adresse, newData.emailAdresse, mergedKinoSaele);
|
||||
mergedKinoSaele.forEach(kinoSaal -> kinoSaal.kino = mergedKino);
|
||||
|
||||
return mergedKino;
|
||||
}
|
||||
|
||||
public void addSaele(Collection<KinoSaal> saele) {
|
||||
kinoSaele.addAll(saele);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (!equalsByContent(o)) return false;
|
||||
|
||||
if (this == o) {return true;}
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
Kino that = (Kino) o;
|
||||
return new EqualsBuilder().append(version, that.version).isEquals();
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantValue")
|
||||
@Override
|
||||
public boolean equalsByContent(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
Kino that = (Kino) o;
|
||||
|
||||
boolean result = new EqualsBuilder()
|
||||
.append(id, that.id)
|
||||
.append(name, that.name)
|
||||
.append(adresse, that.adresse).append(emailAdresse, that.emailAdresse)
|
||||
.isEquals();
|
||||
if (!result) return false;
|
||||
|
||||
if (kinoSaele == null && that.kinoSaele == null) return true;
|
||||
if (kinoSaele == null && that.kinoSaele != null) return false;
|
||||
if (kinoSaele != null && that.kinoSaele == null) return false;
|
||||
|
||||
List<KinoSaal> thisKSList = kinoSaele.stream().toList();
|
||||
List<KinoSaal> thatKSList = that.kinoSaele.stream().toList();
|
||||
if (thisKSList.size() != thatKSList.size()) return false;
|
||||
for (int counter = 0; counter < thisKSList.size(); counter++) {
|
||||
if (!thisKSList.get(counter).equalsByContent(thatKSList.get(counter))) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(name).append(adresse).append(emailAdresse)
|
||||
.append(kinoSaele.stream().toList()) // need to use list, as Set does not support deep equals
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
package de.accso.flexinale.backoffice.domain.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import de.accso.flexinale.common.shared_kernel.*;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
public class KinoSaal implements Identifiable, Versionable, Mergeable<KinoSaal>, EqualsByContent {
|
||||
public record Name(String raw) implements RawWrapper<String> {}
|
||||
public record AnzahlPlaetze(Integer raw) implements RawWrapper<Integer> {}
|
||||
|
||||
public final Id id;
|
||||
public final Version version;
|
||||
|
||||
public Name name;
|
||||
public AnzahlPlaetze anzahlPlaetze = new KinoSaal.AnzahlPlaetze(0);
|
||||
|
||||
@JsonIgnore
|
||||
@DoNotCheckInArchitectureTests
|
||||
public Kino kino;
|
||||
|
||||
public KinoSaal(final Id id) {
|
||||
this(id, Versionable.unknownVersion());
|
||||
}
|
||||
|
||||
public KinoSaal(final Id id, final Version version) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public KinoSaal(final Id id,
|
||||
final Name name, final AnzahlPlaetze anzahlPlaetze, final Kino kino) {
|
||||
this(id, Versionable.unknownVersion(), name, anzahlPlaetze, kino);
|
||||
}
|
||||
|
||||
public KinoSaal(final Id id, final Version version,
|
||||
final Name name, final AnzahlPlaetze anzahlPlaetze, final Kino kino) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.name = name;
|
||||
this.anzahlPlaetze = anzahlPlaetze;
|
||||
this.kino = kino;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KinoSaal merge(final KinoSaal newData) {
|
||||
return new KinoSaal(this.id,
|
||||
newData.name, newData.anzahlPlaetze,
|
||||
/* needs to be corrected outside */ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KinoSaal{" +
|
||||
"id='" + id + '\'' +
|
||||
", version=" + version +
|
||||
", name='" + name + '\'' +
|
||||
", anzahlPlaetze=" + anzahlPlaetze +
|
||||
(kino != null ? ", kino.id=" + kino.id : ", kino=null") +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (!equalsByContent(o)) return false;
|
||||
|
||||
if (this == o) {return true;}
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
KinoSaal that = (KinoSaal) o;
|
||||
return new EqualsBuilder().append(version, that.version).isEquals();
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantValue")
|
||||
@Override
|
||||
public boolean equalsByContent(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
KinoSaal that = (KinoSaal) o;
|
||||
|
||||
boolean result = new EqualsBuilder()
|
||||
.append(id, that.id)
|
||||
.append(name, that.name)
|
||||
.append(anzahlPlaetze, that.anzahlPlaetze).
|
||||
isEquals();
|
||||
if (!result) return false;
|
||||
|
||||
if (kino == null && that.kino == null) return true;
|
||||
if (kino == null && that.kino != null) return false;
|
||||
if (kino != null) {
|
||||
result = kino.id.equals(that.kino.id); // do not check kino but only its id (otherwise Stackoverflow error)
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
HashCodeBuilder builder = new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(name).append(anzahlPlaetze);
|
||||
if (kino != null) {
|
||||
builder.append(kino.id); // do not use kino but only its id (otherwise Stackoverflow error)
|
||||
}
|
||||
return builder.toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
package de.accso.flexinale.backoffice.domain.model;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.*;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class Vorfuehrung implements Identifiable, Versionable, Mergeable<Vorfuehrung>, EqualsByContent { // TODO is only final as otherwise Spotbugs complains, get rid of Exception in constructor!
|
||||
public record Zeit(LocalDateTime raw) implements RawWrapper<LocalDateTime> {
|
||||
public Zeit(LocalDateTime raw) {
|
||||
this.raw = raw.withNano(0); // precision is second
|
||||
}
|
||||
}
|
||||
|
||||
public final Id id;
|
||||
public final Version version;
|
||||
|
||||
public final Zeit zeit;
|
||||
|
||||
@DoNotCheckInArchitectureTests
|
||||
public final Film film;
|
||||
@DoNotCheckInArchitectureTests
|
||||
public final KinoSaal kinoSaal;
|
||||
|
||||
public Vorfuehrung(final Id id,
|
||||
final Zeit zeit,
|
||||
final Film film,
|
||||
final KinoSaal kinoSaal) {
|
||||
this(id, Versionable.unknownVersion(), zeit, film, kinoSaal);
|
||||
}
|
||||
|
||||
public Vorfuehrung(final Id id, final Version version,
|
||||
final Zeit zeit,
|
||||
final Film film,
|
||||
final KinoSaal kinoSaal) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.zeit = zeit;
|
||||
this.film = film;
|
||||
this.kinoSaal = kinoSaal;
|
||||
|
||||
//TODO this validation should not be done here. If class is not final, Spotbugs complains. For DB entities use "nullable=false" and "optional=false" for DB checks. In domain classes check with jakarta.annotation NonNull? Also: Why is KinoSaal obligatory but not Film?
|
||||
if (kinoSaal == null) {
|
||||
throw new FlexinaleIllegalArgumentException("KinoSaal of Vorfuehrung " + this +
|
||||
" must not be null");
|
||||
}
|
||||
//TODO this validation should not be done here but in KinoSaal itself
|
||||
if (kinoSaal.anzahlPlaetze == null) {
|
||||
throw new FlexinaleIllegalArgumentException("KinoSaal's Anzahl Plaetze of Vorfuehrung " + this +
|
||||
" must not be null");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vorfuehrung merge(final Vorfuehrung newData) {
|
||||
// merging Vorfuehrung has some business flaws - like when its film or its kinoSaal is changed,
|
||||
// then all sold tickets might get obsolete - we ignore this here but care for that in Ticketing
|
||||
Film mergedFilm = this.film.merge(newData.film);
|
||||
|
||||
Kino mergedKino = this.kinoSaal.kino.merge(newData.kinoSaal.kino);
|
||||
Optional<KinoSaal> mergedKinoSaal = mergedKino.kinoSaele.stream().filter(
|
||||
kinoSaal -> kinoSaal.id.equals(this.kinoSaal.id)).findFirst();
|
||||
if (mergedKinoSaal.isEmpty()) {
|
||||
throw new DeveloperMistakeException("merged KinoSaal from Vorfuehrung could not be retrieved");
|
||||
}
|
||||
|
||||
return new Vorfuehrung(this.id, this.version,
|
||||
newData.zeit, mergedFilm, mergedKinoSaal.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (!equalsByContent(o)) return false;
|
||||
|
||||
if (this == o) {return true;}
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
Vorfuehrung that = (Vorfuehrung) o;
|
||||
return new EqualsBuilder().append(version, that.version).isEquals();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedAssignment", "DataFlowIssue"})
|
||||
@Override
|
||||
public boolean equalsByContent(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
Vorfuehrung that = (Vorfuehrung) o;
|
||||
|
||||
boolean result = new EqualsBuilder()
|
||||
.append(id, that.id)
|
||||
.append(zeit, that.zeit)
|
||||
.isEquals();
|
||||
if (!result) return false;
|
||||
|
||||
if (film == null && that.film == null) result = true;
|
||||
if (film == null && that.film != null) return false;
|
||||
if (film != null) {
|
||||
result = film.equalsByContent(that.film);
|
||||
if (!result) return false;
|
||||
}
|
||||
|
||||
if (kinoSaal == null && that.kinoSaal == null) result = true;
|
||||
if (kinoSaal == null && that.kinoSaal != null) return false;
|
||||
if (kinoSaal != null) {
|
||||
result = kinoSaal.equalsByContent(that.kinoSaal);
|
||||
return result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(zeit)
|
||||
.append(film)
|
||||
.append(kinoSaal)
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package de.accso.flexinale.backoffice.domain.services;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.dao.FilmDao;
|
||||
import de.accso.flexinale.backoffice.domain.model.Film;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FilmService {
|
||||
|
||||
private final FilmDao filmDao;
|
||||
|
||||
public FilmService(final FilmDao filmDao) {
|
||||
this.filmDao = filmDao;
|
||||
}
|
||||
|
||||
public List<Film> filme() {
|
||||
return filmDao.findAll();
|
||||
}
|
||||
|
||||
public Film film(final Identifiable.Id id) {
|
||||
return filmDao.findById(id).orElse(null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package de.accso.flexinale.backoffice.domain.services;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.dao.KinoDao;
|
||||
import de.accso.flexinale.backoffice.domain.model.Kino;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class KinoService {
|
||||
|
||||
private final KinoDao kinoDao;
|
||||
|
||||
public KinoService(final KinoDao kinoDao) {
|
||||
this.kinoDao = kinoDao;
|
||||
}
|
||||
|
||||
public List<Kino> kinos() {
|
||||
return kinoDao.findAll();
|
||||
}
|
||||
|
||||
public Kino kino(final Identifiable.Id id) {
|
||||
return kinoDao.findById(id).orElse(null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package de.accso.flexinale.backoffice.domain.services;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.dao.VorfuehrungDao;
|
||||
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class VorfuehrungService {
|
||||
|
||||
private final VorfuehrungDao vorfuehrungDao;
|
||||
|
||||
public VorfuehrungService(final VorfuehrungDao vorfuehrungDao) {
|
||||
this.vorfuehrungDao = vorfuehrungDao;
|
||||
}
|
||||
|
||||
public List<Vorfuehrung> vorfuehrungen() {
|
||||
return vorfuehrungDao.findAll();
|
||||
}
|
||||
|
||||
public Vorfuehrung vorfuehrung(final Identifiable.Id id) {
|
||||
return vorfuehrungDao.findById(id).orElse(null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure;
|
||||
|
||||
import de.accso.flexinale.common.api.eventbus.EventNotification;
|
||||
import de.accso.flexinale.common.api.event.Event;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
@Component
|
||||
@Endpoint(id = "backofficeEventsPublished")
|
||||
public class FlexinaleBackofficeActuatorEndpointEventsPublished implements EventNotification {
|
||||
private final Queue<Event> eventsPublished = new ConcurrentLinkedQueue<>(); // event list is ordered by production time
|
||||
|
||||
@ReadOperation
|
||||
public List<Event> eventsPublished() {
|
||||
return eventsPublished.stream().toList();
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public List<Event> eventsPublishedFilteredBy(@Selector Identifiable.Id correlationId) {
|
||||
return eventsPublished.stream().filter(event -> event.correlationId().equals(correlationId)).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(final Event event) {// might want to use a generic subscriber
|
||||
eventsPublished.add(event);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import de.accso.flexinale.backoffice.api_out.event.FilmPublisher;
|
||||
import de.accso.flexinale.backoffice.api_out.event.KinoPublisher;
|
||||
import de.accso.flexinale.backoffice.api_out.event.VorfuehrungPublisher;
|
||||
import de.accso.flexinale.backoffice.application.services.FilmService;
|
||||
import de.accso.flexinale.backoffice.application.services.KinoService;
|
||||
import de.accso.flexinale.backoffice.application.services.VorfuehrungService;
|
||||
import de.accso.flexinale.backoffice.application.services.FilmUploadService;
|
||||
import de.accso.flexinale.backoffice.application.services.KinoUploadService;
|
||||
import de.accso.flexinale.backoffice.application.services.KinoSaalUploadService;
|
||||
import de.accso.flexinale.backoffice.application.services.VorfuehrungUploadService;
|
||||
import de.accso.flexinale.backoffice.domain.dao.FilmDao;
|
||||
import de.accso.flexinale.backoffice.domain.dao.KinoDao;
|
||||
import de.accso.flexinale.backoffice.domain.dao.KinoSaalDao;
|
||||
import de.accso.flexinale.backoffice.domain.dao.VorfuehrungDao;
|
||||
import de.accso.flexinale.backoffice.infrastructure.persistence.*;
|
||||
import de.accso.flexinale.common.api.eventbus.EventBusFactory;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@Configuration
|
||||
@Profile({ "!testdata-besucherportal & !testdata-ticketing" })
|
||||
@EnableJpaRepositories({"de.accso.flexinale.backoffice.infrastructure.persistence"})
|
||||
@EnableTransactionManagement
|
||||
@EntityScan(basePackages={"de.accso.flexinale.backoffice.infrastructure.persistence"})
|
||||
public class FlexinaleBackofficeSpringFactory {
|
||||
|
||||
@Bean
|
||||
public FilmService createApplicationFilmService(final de.accso.flexinale.backoffice.domain.services.FilmService filmService) {
|
||||
return new FilmService(filmService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public de.accso.flexinale.backoffice.domain.services.FilmService createBackofficeFilmService(final FilmDao filmDao) {
|
||||
return new de.accso.flexinale.backoffice.domain.services.FilmService(filmDao);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilmUploadService createBackofficeFilmUploadService(final FilmDao filmDao) {
|
||||
return new FilmUploadService(filmDao);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilmDao createBackofficeFilmDao(final FilmJpaRepository filmJpaRepository) {
|
||||
return new FilmJpaRepositoryDelegate(filmJpaRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilmPublisher createBackofficeFilmPublisher(final EventBusFactory eventBusFactory,
|
||||
final FlexinaleBackofficeActuatorEndpointEventsPublished endpointEventsPublished) {
|
||||
return new FilmPublisher(eventBusFactory, endpointEventsPublished);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@Bean
|
||||
public KinoService createApplicationKinoService(final de.accso.flexinale.backoffice.domain.services.KinoService kinoService) {
|
||||
return new KinoService(kinoService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public de.accso.flexinale.backoffice.domain.services.KinoService createBackofficeKinoService(final KinoDao KinoDao) {
|
||||
return new de.accso.flexinale.backoffice.domain.services.KinoService(KinoDao);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KinoUploadService createBackofficeKinoUploadService(final KinoDao kinoDao) {
|
||||
return new KinoUploadService(kinoDao);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KinoSaalUploadService createBackofficeKinoSaalUploadService(final KinoSaalDao kinoSaalDao) {
|
||||
return new KinoSaalUploadService(kinoSaalDao);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KinoDao createBackofficeKinoDao(final KinoJpaRepository kinoJpaRepository) {
|
||||
return new KinoJpaRepositoryDelegate(kinoJpaRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KinoSaalDao createBackofficeKinoSaalDao(final KinoSaalJpaRepository kinoSaalJpaRepository) {
|
||||
return new KinoSaalJpaRepositoryDelegate(kinoSaalJpaRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KinoPublisher createBackofficeKinoPublisher(final EventBusFactory eventBusFactory,
|
||||
final FlexinaleBackofficeActuatorEndpointEventsPublished endpointEventsPublished) {
|
||||
return new KinoPublisher(eventBusFactory, endpointEventsPublished);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@Bean
|
||||
public VorfuehrungService createApplicationVorfuehrungService(final de.accso.flexinale.backoffice.domain.services.VorfuehrungService vorfuehrungService) {
|
||||
return new VorfuehrungService(vorfuehrungService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public de.accso.flexinale.backoffice.domain.services.VorfuehrungService createBackofficeVorfuehrungService(final VorfuehrungDao vorfuehrungDao) {
|
||||
return new de.accso.flexinale.backoffice.domain.services.VorfuehrungService(vorfuehrungDao);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public VorfuehrungUploadService createBackofficeVorfuehrungUploadService(final VorfuehrungDao vorfuehrungDao,
|
||||
final FilmDao filmDao,
|
||||
final KinoSaalDao kinoSaalDao) {
|
||||
return new VorfuehrungUploadService(vorfuehrungDao, filmDao, kinoSaalDao);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public VorfuehrungDao createBackofficeVorfuehrungDao(final VorfuehrungJpaRepository vorfuehrungJpaRepository) {
|
||||
return new VorfuehrungJpaRepositoryDelegate(vorfuehrungJpaRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public VorfuehrungPublisher createBackofficeVorfuehrungPublisher(final EventBusFactory eventBusFactory,
|
||||
final FlexinaleBackofficeActuatorEndpointEventsPublished endpointEventsPublished) {
|
||||
return new VorfuehrungPublisher(eventBusFactory, endpointEventsPublished);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
// Actuator Event serialization
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jsonBackofficeCustomizer() {
|
||||
return builder -> builder.visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@jakarta.persistence.Entity(name = "Film")
|
||||
public class FilmEntity implements Identifiable, Versionable, Serializable {
|
||||
@jakarta.persistence.Id
|
||||
public String id; // primary key
|
||||
|
||||
@jakarta.persistence.Column
|
||||
public String titel;
|
||||
|
||||
@jakarta.persistence.Column
|
||||
public String imdbUrl;
|
||||
|
||||
@jakarta.persistence.Column
|
||||
public Integer dauerInMinuten;
|
||||
|
||||
@jakarta.persistence.Version
|
||||
private Integer version = 0;
|
||||
|
||||
protected FilmEntity() {
|
||||
}
|
||||
|
||||
public FilmEntity(final String id, final Integer version,
|
||||
final String titel, final String imdbUrl, final Integer dauerInMinuten) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.titel = titel;
|
||||
this.imdbUrl = imdbUrl;
|
||||
this.dauerInMinuten = dauerInMinuten;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return Identifiable.Id.of(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return Versionable.Version.of(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
FilmEntity that = (FilmEntity) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(id, that.id).append(version, that.version)
|
||||
.append(titel, that.titel)
|
||||
.append(imdbUrl, that.imdbUrl)
|
||||
.append(dauerInMinuten, that.dauerInMinuten)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(titel).append(imdbUrl).append(dauerInMinuten).toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface FilmJpaRepository extends JpaRepository<FilmEntity, String> {
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.dao.FilmDao;
|
||||
import de.accso.flexinale.backoffice.domain.model.Film;
|
||||
import de.accso.flexinale.backoffice.infrastructure.persistence.mapper.FilmEntity2FilmMapper;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class FilmJpaRepositoryDelegate implements FilmDao {
|
||||
|
||||
private final FilmJpaRepository filmJpaRepository;
|
||||
|
||||
public FilmJpaRepositoryDelegate(final FilmJpaRepository filmJpaRepository) {
|
||||
this.filmJpaRepository = filmJpaRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Film> findAll() {
|
||||
List<FilmEntity> filmEntities = filmJpaRepository.findAll();
|
||||
|
||||
return filmEntities.stream()
|
||||
.map(FilmEntity2FilmMapper::map)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Film> findById(final Identifiable.Id id) {
|
||||
Optional<FilmEntity> filmEntity = filmJpaRepository.findById(id.id());
|
||||
return FilmEntity2FilmMapper.map(filmEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Film save(final Film film) {
|
||||
FilmEntity filmEntity = FilmEntity2FilmMapper.map(film);
|
||||
FilmEntity savedEntity = filmJpaRepository.save(filmEntity);
|
||||
return FilmEntity2FilmMapper.map(savedEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final Film film) {
|
||||
FilmEntity filmEntity = FilmEntity2FilmMapper.map(film);
|
||||
filmJpaRepository.delete(filmEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(final Identifiable.Id id) {
|
||||
filmJpaRepository.deleteById(id.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
filmJpaRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.FetchType;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@jakarta.persistence.Entity(name = "Kino")
|
||||
public class KinoEntity implements Identifiable, Versionable, Serializable {
|
||||
@jakarta.persistence.Id
|
||||
public String id; // primary key
|
||||
|
||||
@jakarta.persistence.Column
|
||||
public String name;
|
||||
|
||||
@jakarta.persistence.Column
|
||||
public String adresse;
|
||||
|
||||
@jakarta.persistence.Column
|
||||
public String emailAdresse;
|
||||
|
||||
@jakarta.persistence.Version
|
||||
private Integer version = 0;
|
||||
|
||||
@jakarta.persistence.OneToMany(mappedBy = "kino", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
public Set<KinoSaalEntity> kinoSaele = new HashSet<>();
|
||||
|
||||
protected KinoEntity() {
|
||||
}
|
||||
|
||||
public KinoEntity(final String id, final Integer version,
|
||||
final String name, final String adresse, final String emailAdresse) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.name = name;
|
||||
this.adresse = adresse;
|
||||
this.emailAdresse = emailAdresse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return Identifiable.Id.of(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return Versionable.Version.of(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
KinoEntity that = (KinoEntity) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(id, that.id).append(version, that.version)
|
||||
.append(name, that.name)
|
||||
.append(adresse, that.adresse)
|
||||
.append(emailAdresse, that.emailAdresse)
|
||||
.append(kinoSaele.stream().toList(), that.kinoSaele.stream().toList()) // need to use list, as Set does not support deep equals
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(name).append(adresse)
|
||||
.append(emailAdresse)
|
||||
.append(kinoSaele.stream().toList()) // need to use list, as Set does not support deep equals
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface KinoJpaRepository extends JpaRepository<KinoEntity, String> {
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.dao.KinoDao;
|
||||
import de.accso.flexinale.backoffice.domain.model.Kino;
|
||||
import de.accso.flexinale.backoffice.infrastructure.persistence.mapper.KinoKinoSaalEntity2KinoKinoSaalMapper;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class KinoJpaRepositoryDelegate implements KinoDao {
|
||||
|
||||
private final KinoJpaRepository kinoJpaRepository;
|
||||
|
||||
public KinoJpaRepositoryDelegate(final KinoJpaRepository KinoJpaRepository) {
|
||||
this.kinoJpaRepository = KinoJpaRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Kino> findAll() {
|
||||
List<KinoEntity> kinoEntities = kinoJpaRepository.findAll();
|
||||
|
||||
return kinoEntities.stream()
|
||||
.map(KinoKinoSaalEntity2KinoKinoSaalMapper::mapKino)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Kino> findById(final Identifiable.Id id) {
|
||||
Optional<KinoEntity> kinoEntity = kinoJpaRepository.findById(id.id());
|
||||
return KinoKinoSaalEntity2KinoKinoSaalMapper.mapKino(kinoEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Kino save(final Kino kino) {
|
||||
KinoEntity kinoEntity = KinoKinoSaalEntity2KinoKinoSaalMapper.mapKino(kino);
|
||||
KinoEntity savedEntity = kinoJpaRepository.save(kinoEntity);
|
||||
return KinoKinoSaalEntity2KinoKinoSaalMapper.mapKino(savedEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final Kino kino) {
|
||||
KinoEntity kinoEntity = KinoKinoSaalEntity2KinoKinoSaalMapper.mapKino(kino);
|
||||
kinoJpaRepository.delete(kinoEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(final Identifiable.Id id) {
|
||||
kinoJpaRepository.deleteById(id.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
kinoJpaRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@jakarta.persistence.Entity(name = "KinoSaal")
|
||||
public class KinoSaalEntity implements Identifiable, Versionable, Serializable {
|
||||
@jakarta.persistence.Id
|
||||
public String id; // primary key
|
||||
|
||||
@jakarta.persistence.Column
|
||||
public String name;
|
||||
|
||||
@jakarta.persistence.Column
|
||||
public Integer anzahlPlaetze = 0;
|
||||
|
||||
@jakarta.persistence.ManyToOne
|
||||
@jakarta.persistence.JoinColumn(name = "kino", nullable = false)
|
||||
public KinoEntity kino;
|
||||
|
||||
@jakarta.persistence.Version
|
||||
private Integer version = 0;
|
||||
|
||||
protected KinoSaalEntity() {
|
||||
}
|
||||
|
||||
public KinoSaalEntity(final String id, final Integer version,
|
||||
final String name, final Integer anzahlPlaetze, final KinoEntity kino) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.name = name;
|
||||
this.anzahlPlaetze = anzahlPlaetze;
|
||||
this.kino = kino;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return Identifiable.Id.of(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return Versionable.Version.of(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KinoSaalEntity{" +
|
||||
"id='" + id + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", anzahlPlaetze=" + anzahlPlaetze +
|
||||
(kino != null ? ", kino.id=" + kino.id : ", kino=null") +
|
||||
", version=" + version +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
KinoSaalEntity that = (KinoSaalEntity) o;
|
||||
|
||||
EqualsBuilder builder = new EqualsBuilder()
|
||||
.append(id, that.id).append(version, that.version)
|
||||
.append(name, that.name).append(anzahlPlaetze, that.anzahlPlaetze);
|
||||
if (kino != null) {
|
||||
builder.append(kino.id, that.kino.id); // do not check kino but only its id (otherwise Stackoverflow error)
|
||||
}
|
||||
return builder.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
HashCodeBuilder builder = new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(name).append(anzahlPlaetze);
|
||||
if (kino != null) {
|
||||
builder.append(kino.id); // do not check kino but only its id (otherwise Stackoverflow error)
|
||||
}
|
||||
return builder.toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface KinoSaalJpaRepository extends JpaRepository<KinoSaalEntity, String> {
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.dao.KinoSaalDao;
|
||||
import de.accso.flexinale.backoffice.domain.model.KinoSaal;
|
||||
import de.accso.flexinale.backoffice.infrastructure.persistence.mapper.KinoKinoSaalEntity2KinoKinoSaalMapper;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class KinoSaalJpaRepositoryDelegate implements KinoSaalDao {
|
||||
|
||||
private final KinoSaalJpaRepository kinoSaalJpaRepository;
|
||||
|
||||
public KinoSaalJpaRepositoryDelegate(final KinoSaalJpaRepository kinoSaalJpaRepository) {
|
||||
this.kinoSaalJpaRepository = kinoSaalJpaRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KinoSaal> findAll() {
|
||||
List<KinoSaalEntity> kinoSaalEntities = kinoSaalJpaRepository.findAll();
|
||||
|
||||
return kinoSaalEntities.stream()
|
||||
.map(KinoKinoSaalEntity2KinoKinoSaalMapper::mapKinoSaal)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<KinoSaal> findById(final Identifiable.Id id) {
|
||||
Optional<KinoSaalEntity> kinoSaalEntity = kinoSaalJpaRepository.findById(id.id());
|
||||
return KinoKinoSaalEntity2KinoKinoSaalMapper.mapToKinoSaal(kinoSaalEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KinoSaal save(final KinoSaal kinoSaal) {
|
||||
KinoSaalEntity kinoSaalEntity = KinoKinoSaalEntity2KinoKinoSaalMapper.mapKinoSaal(kinoSaal);
|
||||
KinoSaalEntity savedEntity = kinoSaalJpaRepository.save(kinoSaalEntity);
|
||||
return KinoKinoSaalEntity2KinoKinoSaalMapper.mapKinoSaal(savedEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final KinoSaal kinoSaal) {
|
||||
KinoSaalEntity kinoSaalEntity = KinoKinoSaalEntity2KinoKinoSaalMapper.mapKinoSaal(kinoSaal);
|
||||
kinoSaalJpaRepository.delete(kinoSaalEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(final Identifiable.Id id) {
|
||||
kinoSaalJpaRepository.deleteById(id.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
kinoSaalJpaRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.DateTimeHelper;
|
||||
import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalArgumentException;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@jakarta.persistence.Entity(name = "Vorfuehrung")
|
||||
public final class VorfuehrungEntity implements Identifiable, Versionable, Serializable { // TODO is only final as otherwise Spotbugs complains, get rid of Exception in constructor!
|
||||
@jakarta.persistence.Id
|
||||
public String id; // primary key
|
||||
|
||||
@jakarta.persistence.Column
|
||||
public Long zeit; // save EPOCH seconds instead of Date/Time (Timezone is UTC)
|
||||
|
||||
@jakarta.persistence.ManyToOne
|
||||
public FilmEntity film;
|
||||
|
||||
@jakarta.persistence.ManyToOne
|
||||
public KinoSaalEntity kinoSaal;
|
||||
|
||||
@jakarta.persistence.Version
|
||||
private Integer version = 0;
|
||||
|
||||
protected VorfuehrungEntity() {
|
||||
}
|
||||
|
||||
public VorfuehrungEntity(final String id, final Integer version,
|
||||
final LocalDateTime zeit,
|
||||
final FilmEntity film,
|
||||
final KinoSaalEntity kinoSaal) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.zeit = DateTimeHelper.toEpochSeconds(zeit);
|
||||
this.film = film;
|
||||
this.kinoSaal = kinoSaal;
|
||||
|
||||
//TODO this validation should not be done here. If class is not final, Spotbugs complains. For DB entities use "nullable=false" and "optional=false" for DB checks. In domain classes check with jakarta.annotation NonNull? Also: Why is KinoSaal obligatory but not Film?
|
||||
if (kinoSaal == null) {
|
||||
throw new FlexinaleIllegalArgumentException("KinoSaal of Vorfuehrung " + this +
|
||||
" must not be null");
|
||||
}
|
||||
//TODO this validation should not be done here but in KinoSaal itself
|
||||
if (kinoSaal.anzahlPlaetze == null) {
|
||||
throw new FlexinaleIllegalArgumentException("KinoSaal's Anzahl Plaetze of Vorfuehrung " + this +
|
||||
" must not be null");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return Identifiable.Id.of(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return Versionable.Version.of(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
VorfuehrungEntity that = (VorfuehrungEntity) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(id, that.id).append(version, that.version)
|
||||
.append(zeit, that.zeit)
|
||||
.append(film, that.film).append(kinoSaal, that.kinoSaal)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(zeit).append(film).append(kinoSaal)
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface VorfuehrungJpaRepository extends JpaRepository<VorfuehrungEntity, String> {
|
||||
|
||||
@Query("SELECT v FROM Vorfuehrung v WHERE v.film.id = :filmId ORDER BY v.zeit")
|
||||
List<VorfuehrungEntity> findByFilmId(final String filmId);
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.dao.VorfuehrungDao;
|
||||
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
|
||||
import de.accso.flexinale.backoffice.infrastructure.persistence.mapper.VorfuehrungEntity2VorfuehrungMapper;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class VorfuehrungJpaRepositoryDelegate implements VorfuehrungDao {
|
||||
|
||||
private final VorfuehrungJpaRepository vorfuehrungJpaRepository;
|
||||
|
||||
public VorfuehrungJpaRepositoryDelegate(final VorfuehrungJpaRepository vorfuehrungJpaRepository) {
|
||||
this.vorfuehrungJpaRepository = vorfuehrungJpaRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vorfuehrung> findAll() {
|
||||
List<VorfuehrungEntity> vorfuehrungEntities = vorfuehrungJpaRepository.findAll();
|
||||
|
||||
return vorfuehrungEntities.stream()
|
||||
.map(VorfuehrungEntity2VorfuehrungMapper::map)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Vorfuehrung> findById(final Identifiable.Id id) {
|
||||
Optional<VorfuehrungEntity> vorfuehrungEntity = vorfuehrungJpaRepository.findById(id.id());
|
||||
return VorfuehrungEntity2VorfuehrungMapper.map(vorfuehrungEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Vorfuehrung> findByFilmId(final Identifiable.Id filmId) {
|
||||
List<VorfuehrungEntity> vorfuehrungEntities = vorfuehrungJpaRepository.findByFilmId(filmId.id());
|
||||
return VorfuehrungEntity2VorfuehrungMapper.map(vorfuehrungEntities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vorfuehrung save(final Vorfuehrung vorfuehrung) {
|
||||
VorfuehrungEntity vorfuehrungEntity = VorfuehrungEntity2VorfuehrungMapper.map(vorfuehrung);
|
||||
VorfuehrungEntity savedEntity = vorfuehrungJpaRepository.save(vorfuehrungEntity);
|
||||
return VorfuehrungEntity2VorfuehrungMapper.map(savedEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final Vorfuehrung vorfuehrung) {
|
||||
VorfuehrungEntity vorfuehrungEntity = VorfuehrungEntity2VorfuehrungMapper.map(vorfuehrung);
|
||||
vorfuehrungJpaRepository.delete(vorfuehrungEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(final Identifiable.Id id) {
|
||||
vorfuehrungJpaRepository.deleteById(id.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
vorfuehrungJpaRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence.mapper;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.model.Film;
|
||||
import de.accso.flexinale.backoffice.infrastructure.persistence.FilmEntity;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
public final class FilmEntity2FilmMapper {
|
||||
|
||||
public static Film map(final FilmEntity filmEntity) {
|
||||
return new Film(filmEntity.id(), filmEntity.version(),
|
||||
new Film.Titel(filmEntity.titel), new Film.ImdbUrl(filmEntity.imdbUrl),
|
||||
new Film.DauerInMinuten(filmEntity.dauerInMinuten));
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public static Optional<Film> map(final Optional<FilmEntity> optionalFilmEntity) {
|
||||
if (optionalFilmEntity.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
else {
|
||||
FilmEntity filmEntity = optionalFilmEntity.get();
|
||||
return Optional.of(map(filmEntity));
|
||||
}
|
||||
}
|
||||
|
||||
public static FilmEntity map(final Film film) {
|
||||
return new FilmEntity(film.id().id(), film.version().version(),
|
||||
getRawOrNull(film.titel), getRawOrNull(film.imdbUrl), getRawOrNull(film.dauerInMinuten));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence.mapper;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.model.Kino;
|
||||
import de.accso.flexinale.backoffice.domain.model.KinoSaal;
|
||||
import de.accso.flexinale.backoffice.infrastructure.persistence.KinoEntity;
|
||||
import de.accso.flexinale.backoffice.infrastructure.persistence.KinoSaalEntity;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
public final class KinoKinoSaalEntity2KinoKinoSaalMapper {
|
||||
|
||||
public static Kino mapKino(final KinoEntity kinoEntity) {
|
||||
final Kino kino = new Kino(kinoEntity.id(), kinoEntity.version());
|
||||
Set<KinoSaal> mappedKinoSaele = kinoEntity.kinoSaele.stream()
|
||||
.map(kinoSaalEntity -> mapKinoSaal(kinoSaalEntity, kino))
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
|
||||
kino.name = new Kino.Name(kinoEntity.name);
|
||||
kino.adresse = new Kino.Adresse(kinoEntity.adresse);
|
||||
kino.emailAdresse = new Kino.EmailAdresse(kinoEntity.emailAdresse);
|
||||
kino.kinoSaele = mappedKinoSaele;
|
||||
|
||||
return kino;
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public static Optional<Kino> mapKino(final Optional<KinoEntity> optionalKinoEntity) {
|
||||
if (optionalKinoEntity.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
else {
|
||||
KinoEntity kinoEntity = optionalKinoEntity.get();
|
||||
return Optional.of(mapKino(kinoEntity));
|
||||
}
|
||||
}
|
||||
|
||||
public static KinoEntity mapKino(final Kino kino) {
|
||||
final KinoEntity kinoEntity = new KinoEntity(kino.id().id(), kino.version().version(),
|
||||
getRawOrNull(kino.name), getRawOrNull(kino.adresse), getRawOrNull(kino.emailAdresse));
|
||||
|
||||
kinoEntity.kinoSaele = kino.kinoSaele.stream()
|
||||
.map(kinoSaal -> mapKinoSaal(kinoSaal, kinoEntity))
|
||||
.collect(Collectors.toCollection(HashSet::new));
|
||||
|
||||
return kinoEntity;
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public static Optional<KinoSaal> mapToKinoSaal(final Optional<KinoSaalEntity> kinoSaalEntity) {
|
||||
return kinoSaalEntity.map(KinoKinoSaalEntity2KinoKinoSaalMapper::mapKinoSaal);
|
||||
}
|
||||
|
||||
public static KinoSaal mapKinoSaal(KinoSaalEntity kinoSaalEntity) {
|
||||
KinoEntity kinoEntity = kinoSaalEntity.kino;
|
||||
Kino mappedKino = mapKino(kinoEntity);
|
||||
return new KinoSaal(kinoSaalEntity.id(), kinoEntity.version(),
|
||||
new KinoSaal.Name(kinoSaalEntity.name), new KinoSaal.AnzahlPlaetze(kinoSaalEntity.anzahlPlaetze), mappedKino);
|
||||
}
|
||||
|
||||
private static KinoSaal mapKinoSaal(final KinoSaalEntity kinoSaalEntity, Kino kino) {
|
||||
return new KinoSaal(kinoSaalEntity.id(), kinoSaalEntity.version(),
|
||||
new KinoSaal.Name(kinoSaalEntity.name), new KinoSaal.AnzahlPlaetze(kinoSaalEntity.anzahlPlaetze), kino);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"OptionalUsedAsFieldOrParameterType", "unused"})
|
||||
public static Optional<KinoSaalEntity> mapFromKinoSaal(final Optional<KinoSaal> kinoSaal) {
|
||||
return kinoSaal.map(KinoKinoSaalEntity2KinoKinoSaalMapper::mapKinoSaal);
|
||||
}
|
||||
|
||||
public static KinoSaalEntity mapKinoSaal(final KinoSaal kinoSaal) {
|
||||
Kino kino = kinoSaal.kino;
|
||||
KinoEntity mappedKino = mapKino(kino);
|
||||
return new KinoSaalEntity(kinoSaal.id().id(), kinoSaal.version().version(),
|
||||
getRawOrNull(kinoSaal.name), getRawOrNull(kinoSaal.anzahlPlaetze), mappedKino);
|
||||
}
|
||||
|
||||
private static KinoSaalEntity mapKinoSaal(final KinoSaal kinoSaal, final KinoEntity kinoEntity) {
|
||||
return new KinoSaalEntity(kinoSaal.id().id(), kinoEntity.version().version(),
|
||||
getRawOrNull(kinoSaal.name), getRawOrNull(kinoSaal.anzahlPlaetze), kinoEntity);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package de.accso.flexinale.backoffice.infrastructure.persistence.mapper;
|
||||
|
||||
import de.accso.flexinale.backoffice.domain.model.Film;
|
||||
import de.accso.flexinale.backoffice.domain.model.KinoSaal;
|
||||
import de.accso.flexinale.backoffice.domain.model.Vorfuehrung;
|
||||
import de.accso.flexinale.backoffice.infrastructure.persistence.FilmEntity;
|
||||
import de.accso.flexinale.backoffice.infrastructure.persistence.KinoSaalEntity;
|
||||
import de.accso.flexinale.backoffice.infrastructure.persistence.VorfuehrungEntity;
|
||||
import de.accso.flexinale.common.shared_kernel.DateTimeHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
public class VorfuehrungEntity2VorfuehrungMapper {
|
||||
|
||||
public static Vorfuehrung map(final VorfuehrungEntity vorfuehrungEntity) {
|
||||
Film mappedFilm = FilmEntity2FilmMapper.map(vorfuehrungEntity.film);
|
||||
KinoSaal mappedKinoSaal = KinoKinoSaalEntity2KinoKinoSaalMapper.mapKinoSaal(vorfuehrungEntity.kinoSaal);
|
||||
|
||||
return new Vorfuehrung(vorfuehrungEntity.id(), vorfuehrungEntity.version(),
|
||||
new Vorfuehrung.Zeit(DateTimeHelper.fromEpochSeconds(vorfuehrungEntity.zeit)),
|
||||
mappedFilm, mappedKinoSaal);
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public static Optional<Vorfuehrung> map(final Optional<VorfuehrungEntity> optionalVorfuehrungEntity) {
|
||||
if (optionalVorfuehrungEntity.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
else {
|
||||
VorfuehrungEntity vorfuehrungEntity = optionalVorfuehrungEntity.get();
|
||||
return Optional.of(map(vorfuehrungEntity));
|
||||
}
|
||||
}
|
||||
|
||||
public static VorfuehrungEntity map(final Vorfuehrung vorfuehrung) {
|
||||
FilmEntity mappedFilm = FilmEntity2FilmMapper.map(vorfuehrung.film);
|
||||
KinoSaalEntity mappedKinoSaal = KinoKinoSaalEntity2KinoKinoSaalMapper.mapKinoSaal(vorfuehrung.kinoSaal);
|
||||
|
||||
return new VorfuehrungEntity(vorfuehrung.id().id(), vorfuehrung.version().version(),
|
||||
getRawOrNull(vorfuehrung.zeit), mappedFilm, mappedKinoSaal);
|
||||
}
|
||||
|
||||
public static List<Vorfuehrung> map(final List<VorfuehrungEntity> vorfuehrungEntities) {
|
||||
return vorfuehrungEntities.stream().map(VorfuehrungEntity2VorfuehrungMapper::map)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
application.title=FLEXinale as Distributed Services, Backoffice
|
||||
application.version=@pom.version@ @maven.build.timestamp@
|
||||
spring.banner.location=classpath:/flexinale-banner.txt
|
||||
|
||||
#########################################################################
|
||||
# For endpoint /version
|
||||
#########################################################################
|
||||
build.version=@pom.version@
|
||||
build.date=@maven.build.timestamp@
|
||||
|
||||
#########################################################################
|
||||
# Persistence
|
||||
#########################################################################
|
||||
spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/distributed-backoffice
|
||||
spring.datasource.name=flexinale
|
||||
spring.datasource.username=flexinale
|
||||
spring.datasource.password=flexinale
|
||||
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
spring.jpa.database=postgresql
|
||||
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
|
||||
spring.jpa.generate-ddl=true
|
||||
# uses schema if existing (or creates anew)
|
||||
# in a real production environment one should use 'validate' which does just validation but doesn't change anything
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
# Pros and Cons: See https://www.baeldung.com/spring-open-session-in-view,
|
||||
# https://stackoverflow.com/questions/30549489/what-is-this-spring-jpa-open-in-view-true-property-in-spring-boot
|
||||
spring.jpa.open-in-view=false
|
||||
# spring.jpa.show-sql=true
|
||||
|
||||
#########################################################################
|
||||
# Web
|
||||
#########################################################################
|
||||
server.error.path=/error
|
||||
server.error.include-stacktrace=always
|
||||
server.error.include-exception=true
|
||||
server.error.include-message=always
|
||||
server.error.whitelabel.enabled=false
|
||||
server.port=8081
|
||||
|
||||
#########################################################################
|
||||
# Security
|
||||
#########################################################################
|
||||
security.enable-csrf=true
|
||||
|
||||
#########################################################################
|
||||
# Kafka
|
||||
#########################################################################
|
||||
spring.kafka.consumer.group-id=flexinale-distributed-backoffice
|
||||
|
||||
# Spring Kafka Consumer
|
||||
spring.kafka.consumer.bootstrap-servers=localhost:29092
|
||||
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
|
||||
spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
|
||||
|
||||
# Spring Kafka Producer
|
||||
spring.kafka.producer.bootstrap-servers=localhost:29092
|
||||
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
|
||||
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
|
||||
|
||||
#########################################################################
|
||||
# Metrics endpoints, micrometer/prometheus/grafana
|
||||
#########################################################################
|
||||
# enable and expose
|
||||
management.endpoints.web.exposure.include=*
|
||||
management.endpoint.health.show-details=always
|
||||
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
|
||||
|
||||
#########################################################################
|
||||
# flexinale properties
|
||||
#########################################################################
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-------------------------------------------------------------------------
|
||||
,------. ,--. ,------. ,--. ,--. ,--. ,--.
|
||||
| .---' | | | .---' \ `.' / `--' ,--,--, ,--,--. | | ,---.
|
||||
| `--, | | | `--, .' \ ,--. | \ ' ,-. | | | | .-. :
|
||||
| |` | '--. | `---. / .'. \ | | | || | \ '-' | | | \ --.
|
||||
`--' `-----' `------' '--' '--' `--' `--''--' `--`--' `--' `----'
|
||||
${application.title} on port ${server.port}
|
||||
(version ${application.version})
|
||||
Powered by Spring Boot ${spring-boot.version}
|
||||
-------------------------------------------------------------------------
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{YYYYMMdd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.orm.jpa" level="INFO"/>
|
||||
<logger name="org.springframework.boot.autoconfigure.domain.EntityScan" level="INFO"/>
|
||||
|
||||
<logger name="org.apache.kafka" level="WARN"/>
|
||||
<logger name="org.apache.kafka.clients.admin.AdminClient" level="INFO"/>
|
||||
<logger name="org.apache.kafka.clients.consumer.ConsumerConfig" level="INFO"/>
|
||||
<logger name="org.apache.kafka.clients.producer.ProducerConfig" level="INFO"/>
|
||||
|
||||
<logger name="de.accso" level="INFO"/>
|
||||
<root level="WARN">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Flexinale Distributed - Backoffice</title>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Flexinale Distributed - Backoffice
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# curl -v -X GET -u admin:admin1 http://localhost:8081/actuator/backofficeEventsPublished
|
||||
GET http://localhost:8081/actuator/backofficeEventsPublished
|
||||
Authorization: Basic admin admin1
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# curl -v -X GET -u admin:admin1 http://localhost:8081/actuator/health
|
||||
GET http://localhost:8081/actuator/health
|
||||
Authorization: Basic admin admin1
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# curl -v -X GET -u admin:admin1 http://localhost:8081/actuator/info
|
||||
GET http://localhost:8081/actuator/info
|
||||
Authorization: Basic admin admin1
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# curl -v -X GET -u admin:admin1 http://localhost:8081/actuator/metrics
|
||||
GET http://localhost:8081/actuator/metrics
|
||||
Authorization: Basic admin admin1
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# curl -v -X GET -u admin:admin1 http://localhost:8081/actuator/prometheus
|
||||
GET http://localhost:8081/actuator/prometheus
|
||||
Authorization: Basic admin admin1
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package de.accso.flexinale;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(classes = {FlexinaleDistributedApplicationBackoffice.class})
|
||||
@ActiveProfiles("smoketest")
|
||||
public class ApplicationPropertiesFileTest {
|
||||
|
||||
@Value("${application.version}")
|
||||
private String propertyApplicationVersion;
|
||||
|
||||
@Test
|
||||
public void testReadsTestPropertiesFile() {
|
||||
assertThat(propertyApplicationVersion).isEqualTo("test");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package de.accso.flexinale;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.DoNotCheckInArchitectureTests;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
@SpringBootTest(classes = {FlexinaleDistributedApplicationBackoffice.class})
|
||||
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
|
||||
@ActiveProfiles("smoketest")
|
||||
@DoNotCheckInArchitectureTests
|
||||
class FlexinaleDistributedApplicationBackofficeSmokeTest {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("EmptyMethod")
|
||||
void testLoadInitialApplicationContext() {
|
||||
// nope
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package de.accso.flexinale;
|
||||
|
||||
import de.accso.flexinale.common.application.Config;
|
||||
import de.accso.flexinale.common.shared_kernel.DoNotCheckInArchitectureTests;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(classes = {FlexinaleDistributedApplicationBackoffice.class})
|
||||
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
|
||||
@ActiveProfiles("configtest")
|
||||
@DoNotCheckInArchitectureTests
|
||||
class FlexinaleDistributedApplicationBackofficeSpringConfigTest {
|
||||
|
||||
@Autowired
|
||||
Config config;
|
||||
|
||||
@Test
|
||||
void testLoadSpringConfig() {
|
||||
// arrange, act
|
||||
// nope, is loaded auto-magically by Spring, see application-configtest.properties
|
||||
|
||||
// assert
|
||||
assertThat(config.getQuoteOnline()).isEqualTo(33); // default
|
||||
assertThat(config.getMinZeitZwischenVorfuehrungenInMinuten()).isEqualTo(30); // default
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
# empty
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
application.title=FLEXinale as Distributed Services, Backoffice
|
||||
application.version=test
|
||||
spring.banner.location=classpath:/flexinale-banner.txt
|
||||
|
||||
#########################################################################
|
||||
# For endpoint /version
|
||||
#########################################################################
|
||||
build.version=@pom.version@
|
||||
build.date=@maven.build.timestamp@
|
||||
|
||||
#########################################################################
|
||||
# Persistence
|
||||
#########################################################################
|
||||
spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/distributed-backoffice
|
||||
spring.datasource.name=flexinale
|
||||
spring.datasource.username=flexinale
|
||||
spring.datasource.password=flexinale
|
||||
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
spring.jpa.database=postgresql
|
||||
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
|
||||
spring.jpa.generate-ddl=true
|
||||
# spring.jpa.show-sql=true
|
||||
spring.jpa.hibernate.ddl-auto=create
|
||||
|
||||
#########################################################################
|
||||
# Web
|
||||
#########################################################################
|
||||
spring.thymeleaf.prefix=classpath:/templates/
|
||||
spring.thymeleaf.suffix=.html
|
||||
server.error.path=/error
|
||||
server.port=9091
|
||||
|
||||
#########################################################################
|
||||
# flexinale properties
|
||||
#########################################################################
|
||||
# Quote for online kontingent in percent
|
||||
de.accso.flexinale.kontingent.quote.online=33
|
||||
# time in minutes
|
||||
de.accso.flexinale.vorfuehrung.min-zeit-zwischen-vorfuehrungen-in-minuten=30
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{YYYYMMdd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.orm.jpa" level="INFO"/>
|
||||
<logger name="org.springframework.boot.autoconfigure.domain.EntityScan" level="INFO"/>
|
||||
|
||||
<logger name="org.apache.kafka" level="WARN"/>
|
||||
<logger name="org.apache.kafka.clients.admin.AdminClient" level="INFO"/>
|
||||
<logger name="org.apache.kafka.clients.consumer.ConsumerConfig" level="INFO"/>
|
||||
<logger name="org.apache.kafka.clients.producer.ProducerConfig" level="INFO"/>
|
||||
|
||||
<logger name="de.accso" level="INFO"/>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FindBugsFilter>
|
||||
<Match>
|
||||
<!-- spotbugs message is Possible null pointer dereference of Kino.kinoSaele in equals method.
|
||||
But the if statements before that line guarantee not null. -->
|
||||
<Class name="de.accso.flexinale.backoffice.api_contract.event.model.KinoTO" />
|
||||
<Bug pattern="NP_NULL_ON_SOME_PATH_MIGHT_BE_INFEASIBLE" />
|
||||
</Match>
|
||||
<Match>
|
||||
<!-- spotbugs message is ... may expose internal representation by returning KinoTO.kinoSaele -->
|
||||
<Class name="de.accso.flexinale.backoffice.api_contract.event.model.KinoTO" />
|
||||
<Bug pattern="EI_EXPOSE_REP" />
|
||||
</Match>
|
||||
<Match>
|
||||
<!-- spotbugs message is ... may expose internal representation by returning KinoTO.kinoSaele -->
|
||||
<Class name="de.accso.flexinale.backoffice.api_contract.event.model.KinoTO" />
|
||||
<Bug pattern="EI_EXPOSE_REP2"/>
|
||||
</Match>
|
||||
</FindBugsFilter>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>de.accso</groupId>
|
||||
<artifactId>flexinale-distributed</artifactId>
|
||||
<version>2024.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<artifactId>flexinale-distributed-backoffice_api_contract</artifactId>
|
||||
<version>2024.3.0</version>
|
||||
<name>Flexinale Distributed Backoffice API Contract</name>
|
||||
<description>Flexinale - FLEX case-study "film festival", distributed services, backoffice_api-contract</description>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>de.accso</groupId>
|
||||
<artifactId>flexinale-distributed-common</artifactId>
|
||||
<version>2024.3.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
<version>${spotbugs-maven-plugin.version}</version>
|
||||
<configuration>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.h3xstream.findsecbugs</groupId>
|
||||
<artifactId>findsecbugs-plugin</artifactId>
|
||||
<version>${findsecbugs-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<excludeFilterFile>SpotbugsExcludeFilter.xml</excludeFilterFile>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<!-- overwrite dependency on spotbugs if you want to specify the version of spotbugs -->
|
||||
<dependency>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs</artifactId>
|
||||
<version>${spotbugs.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import de.accso.flexinale.common.api.event.Event;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public final class AllBackofficeEvents {
|
||||
|
||||
public static final Set<Class<? extends Event>> eventTypes =
|
||||
Set.of(
|
||||
FilmCreatedEvent.class,
|
||||
FilmUpdatedEvent.class,
|
||||
FilmDeletedEvent.class,
|
||||
KinoCreatedEvent.class,
|
||||
KinoUpdatedEvent.class,
|
||||
KinoDeletedEvent.class,
|
||||
VorfuehrungCreatedEvent.class,
|
||||
VorfuehrungUpdatedEvent.class,
|
||||
VorfuehrungDeletedEvent.class
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.FilmTO;
|
||||
import de.accso.flexinale.common.api.event.AbstractEvent;
|
||||
import de.accso.flexinale.common.api.event.Event;
|
||||
import de.accso.flexinale.common.shared_kernel.DoNotCheckInArchitectureTests;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
public abstract sealed class FilmCRUDEvent extends AbstractEvent implements Event
|
||||
permits FilmCreatedEvent, FilmUpdatedEvent, FilmDeletedEvent {
|
||||
|
||||
public enum CRUD { CREATE, UPDATE, DELETE }
|
||||
|
||||
@DoNotCheckInArchitectureTests
|
||||
public final FilmTO film;
|
||||
|
||||
protected FilmCRUDEvent(final FilmTO film) {
|
||||
this.film = film;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
final FilmCRUDEvent that = (FilmCRUDEvent) o;
|
||||
|
||||
return new EqualsBuilder().appendSuper(super.equals(o))
|
||||
.append(version(), that.version())
|
||||
.append(film, that.film).isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.appendSuper(super.hashCode()).append(film)
|
||||
.append(version())
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.FilmTO;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
|
||||
@SuppressWarnings({"unused", "CanBeFinal"})
|
||||
public non-sealed class FilmCreatedEvent extends FilmCRUDEvent {
|
||||
private static Version version = Versionable.initialVersion().inc();
|
||||
|
||||
private FilmCreatedEvent() { super(null); } // needed for (de)serialization via Jackson
|
||||
|
||||
public FilmCreatedEvent(final FilmTO film) {
|
||||
super(film);
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonGetter("version") // needed as otherwise the static field version is not (de)serialized
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.FilmTO;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
|
||||
@SuppressWarnings({"unused", "CanBeFinal"})
|
||||
public non-sealed class FilmDeletedEvent extends FilmCRUDEvent {
|
||||
private static Version version = Versionable.initialVersion().inc();
|
||||
|
||||
private FilmDeletedEvent() { super(null); } // needed for (de)serialization via Jackson
|
||||
|
||||
public FilmDeletedEvent(final FilmTO film) {
|
||||
super(film);
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonGetter("version") // needed as otherwise the static field version is not (de)serialized
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.FilmTO;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
|
||||
@SuppressWarnings({"unused", "CanBeFinal"})
|
||||
public non-sealed class FilmUpdatedEvent extends FilmCRUDEvent {
|
||||
private static Version version = Versionable.initialVersion().inc();
|
||||
|
||||
private FilmUpdatedEvent() { super(null); } // needed for (de)serialization via Jackson
|
||||
|
||||
public FilmUpdatedEvent(final FilmTO film) {
|
||||
super(film);
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonGetter("version") // needed as otherwise the static field version is not (de)serialized
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.KinoTO;
|
||||
import de.accso.flexinale.common.api.event.AbstractEvent;
|
||||
import de.accso.flexinale.common.api.event.Event;
|
||||
import de.accso.flexinale.common.shared_kernel.DoNotCheckInArchitectureTests;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
public abstract sealed class KinoCRUDEvent extends AbstractEvent implements Event
|
||||
permits KinoCreatedEvent, KinoUpdatedEvent, KinoDeletedEvent {
|
||||
|
||||
public enum CRUD { CREATE, UPDATE, DELETE }
|
||||
|
||||
@DoNotCheckInArchitectureTests
|
||||
public final KinoTO kino;
|
||||
|
||||
protected KinoCRUDEvent(final KinoTO kino) {
|
||||
this.kino = kino;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
final KinoCRUDEvent that = (KinoCRUDEvent) o;
|
||||
|
||||
return new EqualsBuilder().appendSuper(super.equals(o))
|
||||
.append(version(), that.version())
|
||||
.append(kino, that.kino).isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.appendSuper(super.hashCode()).append(kino)
|
||||
.append(version())
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.KinoTO;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
|
||||
@SuppressWarnings({"unused", "CanBeFinal"})
|
||||
public non-sealed class KinoCreatedEvent extends KinoCRUDEvent {
|
||||
private static Version version = Versionable.initialVersion().inc();
|
||||
|
||||
private KinoCreatedEvent() { super(null); } // needed for (de)serialization via Jackson
|
||||
|
||||
public KinoCreatedEvent(final KinoTO kino) {
|
||||
super(kino);
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonGetter("version") // needed as otherwise the static field version is not (de)serialized
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.KinoTO;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
|
||||
@SuppressWarnings({"unused", "CanBeFinal"})
|
||||
public non-sealed class KinoDeletedEvent extends KinoCRUDEvent {
|
||||
private static Version version = Versionable.initialVersion().inc();
|
||||
|
||||
private KinoDeletedEvent() { super(null); } // needed for (de)serialization via Jackson
|
||||
|
||||
public KinoDeletedEvent(final KinoTO kino) {
|
||||
super(kino);
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonGetter("version") // needed as otherwise the static field version is not (de)serialized
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.KinoTO;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
|
||||
@SuppressWarnings({"unused", "CanBeFinal"})
|
||||
public non-sealed class KinoUpdatedEvent extends KinoCRUDEvent {
|
||||
private static Version version = Versionable.initialVersion().inc();
|
||||
|
||||
private KinoUpdatedEvent() { super(null); } // needed for (de)serialization via Jackson
|
||||
|
||||
public KinoUpdatedEvent(final KinoTO kino) {
|
||||
super(kino);
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonGetter("version") // needed as otherwise the static field version is not (de)serialized
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.VorfuehrungTO;
|
||||
import de.accso.flexinale.common.api.event.AbstractEvent;
|
||||
import de.accso.flexinale.common.api.event.Event;
|
||||
import de.accso.flexinale.common.shared_kernel.DoNotCheckInArchitectureTests;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
public abstract sealed class VorfuehrungCRUDEvent extends AbstractEvent implements Event
|
||||
permits VorfuehrungCreatedEvent, VorfuehrungUpdatedEvent, VorfuehrungDeletedEvent {
|
||||
|
||||
public enum CRUD { CREATE, UPDATE, DELETE }
|
||||
|
||||
@DoNotCheckInArchitectureTests
|
||||
public final VorfuehrungTO vorfuehrung;
|
||||
|
||||
protected VorfuehrungCRUDEvent(final VorfuehrungTO vorfuehrung) {
|
||||
this.vorfuehrung = vorfuehrung;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
final VorfuehrungCRUDEvent that = (VorfuehrungCRUDEvent) o;
|
||||
|
||||
return new EqualsBuilder().appendSuper(super.equals(o))
|
||||
.append(version(), that.version())
|
||||
.append(vorfuehrung, that.vorfuehrung).isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.appendSuper(super.hashCode()).append(vorfuehrung)
|
||||
.append(version())
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.VorfuehrungTO;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
|
||||
@SuppressWarnings({"unused", "CanBeFinal"})
|
||||
public non-sealed class VorfuehrungCreatedEvent extends VorfuehrungCRUDEvent {
|
||||
private static Version version = Versionable.initialVersion().inc();
|
||||
|
||||
private VorfuehrungCreatedEvent() { super(null); } // needed for (de)serialization via Jackson
|
||||
|
||||
public VorfuehrungCreatedEvent(final VorfuehrungTO vorfuehrung) {
|
||||
super(vorfuehrung);
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonGetter("version") // needed as otherwise the static field version is not (de)serialized
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.VorfuehrungTO;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
|
||||
@SuppressWarnings({"unused", "CanBeFinal"})
|
||||
public non-sealed class VorfuehrungDeletedEvent extends VorfuehrungCRUDEvent {
|
||||
private static Version version = Versionable.initialVersion().inc();
|
||||
|
||||
private VorfuehrungDeletedEvent() { super(null); } // needed for (de)serialization via Jackson
|
||||
|
||||
public VorfuehrungDeletedEvent(final VorfuehrungTO vorfuehrung) {
|
||||
super(vorfuehrung);
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonGetter("version") // needed as otherwise the static field version is not (de)serialized
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.model.VorfuehrungTO;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
|
||||
@SuppressWarnings({"unused", "CanBeFinal"})
|
||||
public non-sealed class VorfuehrungUpdatedEvent extends VorfuehrungCRUDEvent {
|
||||
private static Version version = Versionable.initialVersion().inc();
|
||||
|
||||
private VorfuehrungUpdatedEvent() { super(null); } // needed for (de)serialization via Jackson
|
||||
|
||||
public VorfuehrungUpdatedEvent(final VorfuehrungTO vorfuehrung) {
|
||||
super(vorfuehrung);
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonGetter("version") // needed as otherwise the static field version is not (de)serialized
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event.model;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.EqualsByContent;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.common.shared_kernel.RawWrapper;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public record FilmTO(Id id, Version version,
|
||||
Titel titel, ImdbUrl imdbUrl, DauerInMinuten dauerInMinuten)
|
||||
implements Identifiable, Versionable, EqualsByContent, Serializable
|
||||
{
|
||||
public record Titel(String raw) implements RawWrapper<String> {}
|
||||
public record ImdbUrl(String raw) implements RawWrapper<String> {}
|
||||
public record DauerInMinuten(Integer raw) implements RawWrapper<Integer> {}
|
||||
|
||||
@Override
|
||||
public boolean equalsByContent(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
final FilmTO that = (FilmTO) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(id, that.id)
|
||||
.append(titel, that.titel).append(imdbUrl, that.imdbUrl)
|
||||
.append(dauerInMinuten, that.dauerInMinuten).isEquals();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package de.accso.flexinale.backoffice.api_contract.event.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import de.accso.flexinale.common.shared_kernel.*;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public record KinoSaalTO(Id id, Version version,
|
||||
Name name, AnzahlPlaetze anzahlPlaetze,
|
||||
@JsonIgnore @DoNotCheckInArchitectureTests KinoTO kino)
|
||||
implements Identifiable, Versionable, EqualsByContent, Serializable
|
||||
{
|
||||
public record Name(String raw) implements RawWrapper<String> {}
|
||||
public record AnzahlPlaetze(Integer raw) implements RawWrapper<Integer> {}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KinoSaalTO{" +
|
||||
"id='" + id + '\'' +
|
||||
", version=" + version +
|
||||
", name='" + name + '\'' +
|
||||
", anzahlPlaetze=" + anzahlPlaetze +
|
||||
(kino != null ? ", kino.id=" + kino.id() : ", kino=null") +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (!equalsByContent(o)) return false;
|
||||
|
||||
if (this == o) {return true;}
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
KinoSaalTO that = (KinoSaalTO) o;
|
||||
return new EqualsBuilder().append(version, that.version).isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
HashCodeBuilder builder = new HashCodeBuilder(17, 37).append(id).append(version)
|
||||
.append(name).append(anzahlPlaetze);
|
||||
if (kino != null) {
|
||||
builder.append(kino.id()); // do not use kino but only its id (otherwise Stackoverflow error)
|
||||
}
|
||||
return builder.toHashCode();
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantValue")
|
||||
@Override
|
||||
public boolean equalsByContent(final Object o) {
|
||||
if (this == o) {return true;}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {return false;}
|
||||
|
||||
KinoSaalTO that = (KinoSaalTO) o;
|
||||
|
||||
boolean result = new EqualsBuilder()
|
||||
.append(id, that.id)
|
||||
.append(name, that.name)
|
||||
.append(anzahlPlaetze, that.anzahlPlaetze).
|
||||
isEquals();
|
||||
if (!result) return false;
|
||||
|
||||
if (kino == null && that.kino == null) return true;
|
||||
if (kino == null && that.kino != null) return false;
|
||||
if (kino != null) {
|
||||
result = kino.id().equals(that.kino.id()); // do not check kino but only its id (otherwise Stackoverflow error)
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue