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
|
|
@ -0,0 +1,8 @@
|
|||
FROM amazoncorretto:21.0.1-alpine3.18
|
||||
|
||||
WORKDIR /app
|
||||
COPY ../../target/flexinale-distributed-ticketing-2024.3.0-spring-boot-fat-jar.jar /app
|
||||
|
||||
EXPOSE 8082
|
||||
|
||||
CMD ["java", "-jar", "flexinale-distributed-ticketing-2024.3.0-spring-boot-fat-jar.jar"]
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
docker build -t de.accso/flexinale-distributed-ticketing:2024.3.0 -f Dockerfile ../../
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
FROM amazoncorretto:21.0.1-alpine3.18
|
||||
|
||||
WORKDIR /app
|
||||
COPY ../../target/flexinale-distributed-ticketing-2024.3.0-spring-boot-fat-jar.jar /app
|
||||
|
||||
EXPOSE 8082
|
||||
|
||||
CMD ["java", "-jar", "flexinale-distributed-ticketing-2024.3.0-spring-boot-fat-jar.jar"]
|
||||
|
|
@ -0,0 +1 @@
|
|||
podman build -t de.accso/flexinale-distributed-ticketing:2024.3.0 -f Dockerfile ../../
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
<?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-ticketing</artifactId>
|
||||
<version>2024.3.0</version>
|
||||
<name>Flexinale Distributed Ticketing</name>
|
||||
<description>Flexinale - FLEX case-study "film festival", distributed services, ticketing</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-web</artifactId>
|
||||
</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.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>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-ticketing_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>
|
||||
<dependency>
|
||||
<groupId>de.accso</groupId>
|
||||
<artifactId>flexinale-distributed-besucherportal_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>Ticketing</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>
|
||||
</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 Ticketing app ("FlexinaleDistributedApplicationTicketing")" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" folderName="App Distributed">
|
||||
<option name="ENABLE_LAUNCH_OPTIMIZATION" value="false" />
|
||||
<module name="flexinale-distributed-ticketing" />
|
||||
<option name="SPRING_BOOT_MAIN_CLASS" value="de.accso.flexinale.FlexinaleDistributedApplicationTicketing" />
|
||||
<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 Ticketing - Actuator Events Consumed" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" folderName="Actuator Distributed" path="$PROJECT_DIR$/flexinale-distributed/flexinale-distributed-ticketing/src/test/curl/ticketing-actuator-events-consumed.http" requestIdentifier="#1">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Distributed Ticketing - Actuator Events Published" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" folderName="Actuator Distributed" path="$PROJECT_DIR$/flexinale-distributed/flexinale-distributed-ticketing/src/test/curl/ticketing-actuator-events-published.http" requestIdentifier="#1">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Distributed Ticketing - Actuator Health" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" folderName="Actuator Distributed" path="$PROJECT_DIR$/flexinale-distributed/flexinale-distributed-ticketing/src/test/curl/ticketing-actuator-health.http" requestIdentifier="#1">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Distributed Ticketing - Actuator Info" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" folderName="Actuator Distributed" path="$PROJECT_DIR$/flexinale-distributed/flexinale-distributed-ticketing/src/test/curl/ticketing-actuator-info.http" requestIdentifier="#1">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Distributed Ticketing - Actuator Metrics" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" folderName="Actuator Distributed" path="$PROJECT_DIR$/flexinale-distributed/flexinale-distributed-ticketing/src/test/curl/ticketing-actuator-metrics.http" requestIdentifier="#1">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Distributed Ticketing - Actuator Prometheus" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" folderName="Actuator Distributed" path="$PROJECT_DIR$/flexinale-distributed/flexinale-distributed-ticketing/src/test/curl/ticketing-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 FlexinaleDistributedApplicationTicketing {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(FlexinaleDistributedApplicationTicketing.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager(final EntityManagerFactory entityManagerFactory) {
|
||||
return new JpaTransactionManager(entityManagerFactory);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package de.accso.flexinale.ticketing.api_in.event;
|
||||
|
||||
import de.accso.flexinale.besucherportal.api_contract.event.GutscheinEinloesenBeauftragtEvent;
|
||||
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.EventSubscriber;
|
||||
import de.accso.flexinale.common.application.caching.InMemoryCache;
|
||||
import de.accso.flexinale.common.api.event.Event;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.ticketing.application.services.TicketService;
|
||||
import de.accso.flexinale.ticketing.domain.model.KontingentBereitsAusgeschoepftException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static de.accso.flexinale.common.api.eventbus.EventSubscriptionAtStart.START_READING_FROM_LAST_TIME;
|
||||
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class GutscheinEinloesenBeauftragtSubscriber implements EventSubscriber<GutscheinEinloesenBeauftragtEvent> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(GutscheinEinloesenBeauftragtSubscriber.class);
|
||||
|
||||
private final TicketService ticketService;
|
||||
|
||||
// caches are currently never cleared - might want to use Cache implementation with automatic time-to-live
|
||||
private final InMemoryCache<Identifiable.Id, Event> gutscheinEinloesenEventCache;
|
||||
|
||||
private final EventNotification notification;
|
||||
|
||||
public GutscheinEinloesenBeauftragtSubscriber(final EventBusFactory eventBusFactory,
|
||||
final TicketService ticketService,
|
||||
final EventNotification notification) {
|
||||
EventBus<GutscheinEinloesenBeauftragtEvent> eventBus =
|
||||
eventBusFactory.createOrGetEventBusFor(GutscheinEinloesenBeauftragtEvent.class);
|
||||
eventBus.subscribe(GutscheinEinloesenBeauftragtEvent.class, this, START_READING_FROM_LAST_TIME);
|
||||
|
||||
this.ticketService = ticketService;
|
||||
this.notification = notification;
|
||||
this.gutscheinEinloesenEventCache = new InMemoryCache<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return GutscheinEinloesenBeauftragtSubscriber.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupName() {
|
||||
return "flexinale-distributed-ticketing"; //TODO make configurable, use "spring.kafka.consumer.group-id" from application.properties
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(final GutscheinEinloesenBeauftragtEvent event) {
|
||||
LOGGER.debug("received new event " + event);
|
||||
|
||||
this.notification.notify(event);
|
||||
|
||||
// idem potence - do not buy same tickets twice
|
||||
if (gutscheinEinloesenEventCache.containsKey(event.correlationId())) {
|
||||
LOGGER.info(("received GutscheinEinloesenBeauftragtEvent twice with same correlationId=%s , " +
|
||||
"so already handled. Ignore and do nothing here.").formatted(event.correlationId()));
|
||||
return;
|
||||
}
|
||||
|
||||
gutscheinEinloesenEventCache.put(event.correlationId(), event);
|
||||
|
||||
try {
|
||||
ticketService.loeseGutscheineOnlineFuerVorfuehrungEin(
|
||||
event.gutscheinEinloesenAuftrag.vorfuehrungId(),
|
||||
event.gutscheinEinloesenAuftrag.filmId(),
|
||||
event.gutscheinEinloesenAuftrag.besucherId(),
|
||||
getRawOrNull(event.gutscheinEinloesenAuftrag.anzahlTickets()));
|
||||
}
|
||||
catch (KontingentBereitsAusgeschoepftException kbaEx) {
|
||||
LOGGER.info("Could not get %s tickets for Vorfuehrung %s, Film %s for Besucher %s: Kontingent bereits ausgeschöpft"
|
||||
.formatted(getRawOrNull(event.gutscheinEinloesenAuftrag.anzahlTickets()),
|
||||
event.gutscheinEinloesenAuftrag.vorfuehrungId(), event.gutscheinEinloesenAuftrag.filmId(),
|
||||
event.gutscheinEinloesenAuftrag.besucherId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package de.accso.flexinale.ticketing.api_in.event;
|
||||
|
||||
import de.accso.flexinale.backoffice.api_contract.event.VorfuehrungCreatedEvent;
|
||||
import de.accso.flexinale.backoffice.api_contract.event.VorfuehrungUpdatedEvent;
|
||||
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.EventSubscriber;
|
||||
import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalStateException;
|
||||
import de.accso.flexinale.ticketing.application.services.TicketService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static de.accso.flexinale.common.api.eventbus.EventSubscriptionAtStart.START_READING_FROM_BEGINNING;
|
||||
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class VorfuehrungSubscriber implements EventSubscriber.EventSubscriber2<VorfuehrungCreatedEvent, VorfuehrungUpdatedEvent> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(VorfuehrungSubscriber.class);
|
||||
|
||||
final TicketService ticketService;
|
||||
|
||||
private final EventNotification notification;
|
||||
|
||||
@SuppressWarnings({"RedundantCast", "unchecked"})
|
||||
public VorfuehrungSubscriber(final EventBusFactory eventBusFactory,
|
||||
final TicketService ticketService,
|
||||
final EventNotification notification) {
|
||||
EventBus<VorfuehrungCreatedEvent> eventBusCreated = eventBusFactory.createOrGetEventBusFor(VorfuehrungCreatedEvent.class);
|
||||
EventBus<VorfuehrungUpdatedEvent> eventBusUpdated = eventBusFactory.createOrGetEventBusFor(VorfuehrungUpdatedEvent.class);
|
||||
|
||||
eventBusCreated.subscribe(VorfuehrungCreatedEvent.class, (EventSubscriber) this, START_READING_FROM_BEGINNING);
|
||||
eventBusUpdated.subscribe(VorfuehrungUpdatedEvent.class, (EventSubscriber) this, START_READING_FROM_BEGINNING);
|
||||
|
||||
this.ticketService = ticketService;
|
||||
this.notification = notification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return VorfuehrungSubscriber.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupName() {
|
||||
return "flexinale-distributed-ticketing"; //TODO make configurable, use "spring.kafka.consumer.group-id" from application.properties
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(final VorfuehrungCreatedEvent event) {
|
||||
LOGGER.debug("received new event " + event);
|
||||
|
||||
this.notification.notify(event);
|
||||
|
||||
try {
|
||||
// check if Vorfuehrung is already there (then do nothing, event was sent more than once)
|
||||
if ( ! ticketService.vorfuehrungIstBereitsImVerkauf(event.vorfuehrung.id())) {
|
||||
ticketService.gebeVorfuehrungInDenVerkauf(event.vorfuehrung.id(), getRawOrNull(event.vorfuehrung.kinoSaal().anzahlPlaetze()));
|
||||
}
|
||||
}
|
||||
catch (FlexinaleIllegalStateException ex) {
|
||||
LOGGER.warn("received VorfuehrungCreatedEvent ignored as Kontingent already exist for Vorfuehrung %s"
|
||||
.formatted(event.vorfuehrung.id()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive2(final VorfuehrungUpdatedEvent event) {
|
||||
LOGGER.debug("received new event " + event);
|
||||
|
||||
this.notification.notify(event);
|
||||
|
||||
if ( ! ticketService.vorfuehrungIstBereitsImVerkauf(event.vorfuehrung.id())){
|
||||
// Events might not be delivered in same order as sent: So the Updated event might have overtaken a Created event.
|
||||
LOGGER.warn("received VorfuehrungUpdatedEvent although Vorfuehrung does not yet exist: %s Handling this as VorfuehrungCreated"
|
||||
.formatted(event.vorfuehrung.id()));
|
||||
ticketService.gebeVorfuehrungInDenVerkauf(event.vorfuehrung.id(), getRawOrNull(event.vorfuehrung.kinoSaal().anzahlPlaetze()));
|
||||
}
|
||||
ticketService.aktualisiereVorfuehrung(event.vorfuehrung.id(), getRawOrNull(event.vorfuehrung.kinoSaal().anzahlPlaetze()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package de.accso.flexinale.ticketing.api_out.event;
|
||||
|
||||
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;
|
||||
import de.accso.flexinale.common.api.event.EventContext;
|
||||
import de.accso.flexinale.ticketing.api_contract.event.OnlineKontingentChangedEvent;
|
||||
import de.accso.flexinale.ticketing.api_contract.event.model.OnlineKontingentTO;
|
||||
import de.accso.flexinale.ticketing.application.services.OnlineKontingentChangedPublication;
|
||||
import de.accso.flexinale.ticketing.domain.model.Kontingent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
public class OnlineKontingentChangedPublisher implements EventPublisher<OnlineKontingentChangedEvent>, OnlineKontingentChangedPublication {
|
||||
private final EventBus<OnlineKontingentChangedEvent> onlineKontingentChangedEventEventBus;
|
||||
private final EventNotification notification;
|
||||
|
||||
public OnlineKontingentChangedPublisher(final EventBusFactory eventBusFactory,
|
||||
final EventNotification notification) {
|
||||
this.onlineKontingentChangedEventEventBus = eventBusFactory.createOrGetEventBusFor(OnlineKontingentChangedEvent.class);
|
||||
this.notification = notification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishOnlineKontingentChanged(final List<Kontingent> kontingente) {
|
||||
EventContext predecessorEventContext = onlineKontingentChangedEventEventBus.getEventContextHolder().get();
|
||||
|
||||
kontingente.forEach(kontingent -> {
|
||||
OnlineKontingentTO onlineKontingentTO =
|
||||
new OnlineKontingentTO(kontingent.id, kontingent.version,
|
||||
kontingent.getVorfuehrungId(),
|
||||
new OnlineKontingentTO.RestKontingent(getRawOrNull(kontingent.getRestKontingentOnline())));
|
||||
|
||||
post(OnlineKontingentChangedEvent.class,
|
||||
(predecessorEventContext == null)
|
||||
? new OnlineKontingentChangedEvent(onlineKontingentTO)
|
||||
: new OnlineKontingentChangedEvent(predecessorEventContext, onlineKontingentTO)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return OnlineKontingentChangedPublisher.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post(final Class<OnlineKontingentChangedEvent> eventType, final OnlineKontingentChangedEvent event) {
|
||||
this.onlineKontingentChangedEventEventBus.publish(OnlineKontingentChangedEvent.class, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package de.accso.flexinale.ticketing.api_out.event;
|
||||
|
||||
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;
|
||||
import de.accso.flexinale.common.api.event.EventContext;
|
||||
import de.accso.flexinale.ticketing.api_contract.event.TicketGekauftEvent;
|
||||
import de.accso.flexinale.ticketing.api_contract.event.TicketUngueltigEvent;
|
||||
import de.accso.flexinale.ticketing.api_contract.event.model.TicketTO;
|
||||
import de.accso.flexinale.ticketing.api_out.event.mapper.Ticket2TicketTOMapper;
|
||||
import de.accso.flexinale.ticketing.application.services.TicketPublication;
|
||||
import de.accso.flexinale.ticketing.domain.model.Ticket;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TicketPublisher implements EventPublisher.EventPublisher2<TicketGekauftEvent, TicketUngueltigEvent>, TicketPublication {
|
||||
private final EventBus<TicketGekauftEvent> ticketGekauftEventEventBus;
|
||||
private final EventBus<TicketUngueltigEvent> ticketUngueltigEventEventBus;
|
||||
|
||||
private final EventNotification notification;
|
||||
|
||||
public TicketPublisher(final EventBusFactory eventBusFactory,
|
||||
final EventNotification notification) {
|
||||
this.ticketGekauftEventEventBus = eventBusFactory.createOrGetEventBusFor(TicketGekauftEvent.class);
|
||||
this.ticketUngueltigEventEventBus = eventBusFactory.createOrGetEventBusFor(TicketUngueltigEvent.class);
|
||||
|
||||
this.notification = notification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishGekaufteTickets(final List<Ticket> tickets) {
|
||||
EventContext predecessorEventContext = ticketGekauftEventEventBus.getEventContextHolder().get();
|
||||
|
||||
tickets.forEach(ticket -> {
|
||||
TicketTO mappedTicket = Ticket2TicketTOMapper.map(ticket);
|
||||
post(TicketGekauftEvent.class,
|
||||
(predecessorEventContext == null) ? new TicketGekauftEvent(mappedTicket)
|
||||
: new TicketGekauftEvent(predecessorEventContext, mappedTicket));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishUngueltigeTickets(final List<Ticket> tickets) {
|
||||
EventContext predecessorEventContext = ticketUngueltigEventEventBus.getEventContextHolder().get();
|
||||
|
||||
tickets.forEach(ticket -> {
|
||||
TicketTO mappedTicket = Ticket2TicketTOMapper.map(ticket);
|
||||
post2(TicketUngueltigEvent.class,
|
||||
(predecessorEventContext == null) ? new TicketUngueltigEvent(mappedTicket)
|
||||
: new TicketUngueltigEvent(predecessorEventContext, mappedTicket));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return TicketPublisher.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post(final Class<TicketGekauftEvent> eventType, final TicketGekauftEvent event) {
|
||||
this.ticketGekauftEventEventBus.publish(eventType, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post2(final Class<TicketUngueltigEvent> eventType, final TicketUngueltigEvent event) {
|
||||
this.ticketUngueltigEventEventBus.publish(eventType, event);
|
||||
this.notification.notify(event);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package de.accso.flexinale.ticketing.api_out.event.mapper;
|
||||
|
||||
import de.accso.flexinale.ticketing.api_contract.event.model.TicketTO;
|
||||
import de.accso.flexinale.ticketing.domain.model.Ticket;
|
||||
|
||||
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
public class Ticket2TicketTOMapper {
|
||||
|
||||
public static TicketTO map(final Ticket ticket) {
|
||||
TicketTO.VerkaufsKanal verkaufsKanal = switch (ticket.verkaufsKanal) {
|
||||
case ONLINE -> TicketTO.VerkaufsKanal.ONLINE;
|
||||
case ZENTRAL -> TicketTO.VerkaufsKanal.ZENTRAL;
|
||||
case KINOKASSE -> TicketTO.VerkaufsKanal.KINOKASSE;
|
||||
};
|
||||
return new TicketTO(ticket.id(), ticket.version(), ticket.filmId, ticket.vorfuehrungId,
|
||||
ticket.besucherId, verkaufsKanal,
|
||||
new TicketTO.Gueltig(getRawOrNull(ticket.gueltig)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package de.accso.flexinale.ticketing.application.services;
|
||||
|
||||
import de.accso.flexinale.ticketing.domain.model.Kontingent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface OnlineKontingentChangedPublication {
|
||||
void publishOnlineKontingentChanged(List<Kontingent> kontingente);
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package de.accso.flexinale.ticketing.application.services;
|
||||
|
||||
import de.accso.flexinale.ticketing.domain.model.Ticket;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TicketPublication {
|
||||
void publishGekaufteTickets(List<Ticket> tickets);
|
||||
void publishUngueltigeTickets(List<Ticket> tickets);
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
package de.accso.flexinale.ticketing.application.services;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalArgumentException;
|
||||
import de.accso.flexinale.common.shared_kernel.FlexinaleIllegalStateException;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.ticketing.domain.dao.KontingentDao;
|
||||
import de.accso.flexinale.ticketing.domain.dao.TicketDao;
|
||||
import de.accso.flexinale.ticketing.domain.model.Kontingent;
|
||||
import de.accso.flexinale.ticketing.domain.model.Ticket;
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Transactional
|
||||
public class TicketService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TicketService.class);
|
||||
|
||||
private final TicketDao ticketDao;
|
||||
|
||||
private final KontingentDao kontingentDao;
|
||||
|
||||
private final OnlineKontingentChangedPublication onlineKontingentChangedPublisher;
|
||||
|
||||
private final TicketPublication ticketPublisher;
|
||||
|
||||
private final int quoteOnline;
|
||||
|
||||
public TicketService(final TicketDao ticketDao,
|
||||
final KontingentDao kontingentDao,
|
||||
final OnlineKontingentChangedPublication onlineKontingentChangedPublisher,
|
||||
final TicketPublication ticketPublisher,
|
||||
final int quoteOnline) {
|
||||
this.ticketDao = ticketDao;
|
||||
this.kontingentDao = kontingentDao;
|
||||
this.onlineKontingentChangedPublisher = onlineKontingentChangedPublisher;
|
||||
this.ticketPublisher = ticketPublisher;
|
||||
this.quoteOnline = quoteOnline;
|
||||
}
|
||||
|
||||
public List<Ticket> findByBesucher(final Identifiable.Id besucherId) {
|
||||
return ticketDao.findByBesucher(besucherId);
|
||||
}
|
||||
|
||||
public List<Ticket> tickets() {
|
||||
return ticketDao.findAll();
|
||||
}
|
||||
|
||||
public void loeseGutscheineOnlineFuerVorfuehrungEin(final Identifiable.Id vorfuehrungId, final Identifiable.Id filmId,
|
||||
final Identifiable.Id besucherId, final int anzahlGutscheine) {
|
||||
loeseGutscheineFuerVorfuehrungEin(vorfuehrungId, filmId, besucherId, anzahlGutscheine,
|
||||
Ticket.VerkaufsKanal.ONLINE);
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private void loeseGutscheineFuerVorfuehrungEin(final Identifiable.Id vorfuehrungId, final Identifiable.Id filmId,
|
||||
final Identifiable.Id besucherId, final int anzahlGutscheine,
|
||||
final Ticket.VerkaufsKanal verkaufsKanal) {
|
||||
Optional<Kontingent> optionalKontingent = kontingentDao.findByVorfuehrung(vorfuehrungId);
|
||||
|
||||
if (optionalKontingent.isEmpty()) {
|
||||
String message = "Kontingent for Vorfuehrung %s could not be found".formatted(vorfuehrungId);
|
||||
LOGGER.error(message);
|
||||
throw new FlexinaleIllegalArgumentException(message);
|
||||
}
|
||||
|
||||
Kontingent kontingent = optionalKontingent.get();
|
||||
Kontingent reduziertesKontingent = kontingent.reduziereKontingent(verkaufsKanal, anzahlGutscheine);
|
||||
Kontingent umAnzahlGekaufteTicketsReduziertesKontingent = kontingentDao.save(reduziertesKontingent);
|
||||
|
||||
List<Ticket> ticketsToBePublished = new ArrayList<>();
|
||||
for (int ticketCounter=0; ticketCounter < anzahlGutscheine; ticketCounter++) {
|
||||
Ticket ticket = ticketDao.save(
|
||||
new Ticket(Identifiable.Id.of(), filmId, vorfuehrungId, besucherId, verkaufsKanal));
|
||||
ticketsToBePublished.add(ticket);
|
||||
}
|
||||
ticketPublisher.publishGekaufteTickets(ticketsToBePublished);
|
||||
|
||||
LOGGER.info("%d tickets bought for Vorfuehrung with id=%s and Besucher with id=%s on channel=%s"
|
||||
.formatted(anzahlGutscheine, vorfuehrungId, besucherId, verkaufsKanal));
|
||||
|
||||
onlineKontingentChangedPublisher.publishOnlineKontingentChanged(List.of(umAnzahlGekaufteTicketsReduziertesKontingent));
|
||||
}
|
||||
|
||||
public void gebeVorfuehrungInDenVerkauf(final Identifiable.Id vorfuehrungId, final int kapazitaet) {
|
||||
if (vorfuehrungIstBereitsImVerkauf(vorfuehrungId)) {
|
||||
String message = "Kontingent for Vorfuehrung %s already exists. No Kontingent created".formatted(vorfuehrungId);
|
||||
LOGGER.error(message);
|
||||
throw new FlexinaleIllegalStateException(message);
|
||||
}
|
||||
|
||||
Kontingent kontingent = new Kontingent(Identifiable.Id.of(), kapazitaet, quoteOnline, vorfuehrungId);
|
||||
kontingentDao.save(kontingent);
|
||||
|
||||
onlineKontingentChangedPublisher.publishOnlineKontingentChanged(List.of(kontingent));
|
||||
}
|
||||
|
||||
public boolean vorfuehrungIstBereitsImVerkauf(final Identifiable.Id vorfuehrungId) {
|
||||
return kontingentDao.findByVorfuehrung(vorfuehrungId).isPresent();
|
||||
}
|
||||
|
||||
public void aktualisiereVorfuehrung(final Identifiable.Id vorfuehrungId, final int kapazitaet){
|
||||
// 1) Invalidate all existing tickets
|
||||
List<Ticket> ticketsByVorfuehrung = ticketDao.findByVorfuehrung(vorfuehrungId);
|
||||
List<Ticket> ungueltigeTickets = new ArrayList<>();
|
||||
for (Ticket ticket : ticketsByVorfuehrung) {
|
||||
ticket.gueltig = new Ticket.Gueltig(false);
|
||||
Ticket ungueltigesTicket = ticketDao.save(ticket);
|
||||
ungueltigeTickets.add(ungueltigesTicket);
|
||||
}
|
||||
|
||||
// 2) Recalculate Kontingent
|
||||
Optional<Kontingent> kontingentOptional = kontingentDao.findByVorfuehrung(vorfuehrungId);
|
||||
if (kontingentOptional.isEmpty()) {
|
||||
LOGGER.warn("could not recalculate Kontingente for Vorfuehrung %s. Kontingent does not exist. Creating new Kontingent"
|
||||
.formatted(vorfuehrungId));
|
||||
}
|
||||
else {
|
||||
Kontingent kontingent = kontingentOptional.get();
|
||||
Kontingent neuBerechnetesKontingent = kontingentDao.save(
|
||||
new Kontingent(kontingent.id, kontingent.version, kapazitaet, quoteOnline, kontingent.getVorfuehrungId())
|
||||
);
|
||||
|
||||
// publish tickets and new Kontingent - at the end, after all database changes have succeeded.
|
||||
onlineKontingentChangedPublisher.publishOnlineKontingentChanged(List.of(neuBerechnetesKontingent));
|
||||
|
||||
ticketPublisher.publishUngueltigeTickets(ungueltigeTickets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package de.accso.flexinale.ticketing.domain.dao;
|
||||
|
||||
import de.accso.flexinale.common.domain.model.AbstractDao;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.ticketing.domain.model.Kontingent;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface KontingentDao extends AbstractDao<Kontingent> {
|
||||
|
||||
@Override
|
||||
Optional<Kontingent> findById(final Identifiable.Id id);
|
||||
|
||||
Optional<Kontingent> findByVorfuehrung(final Identifiable.Id vorfuehrungId);
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package de.accso.flexinale.ticketing.domain.dao;
|
||||
|
||||
import de.accso.flexinale.common.domain.model.AbstractDao;
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.ticketing.domain.model.Ticket;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface TicketDao extends AbstractDao<Ticket> {
|
||||
|
||||
@Override
|
||||
Optional<Ticket> findById(final Identifiable.Id id);
|
||||
|
||||
List<Ticket> findByBesucher(final Identifiable.Id besucherId);
|
||||
|
||||
List<Ticket> findByVorfuehrung(final Identifiable.Id vorfuehrungId);
|
||||
|
||||
int gesamtZahlDerTicketsFuer(final Identifiable.Id besucherId);
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
package de.accso.flexinale.ticketing.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 static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
public class Kontingent implements Identifiable, Versionable, EqualsByContent {
|
||||
public record RestKontingent(Integer raw) implements RawWrapper<Integer> {}
|
||||
|
||||
public enum KontingentType {
|
||||
ONLINE,
|
||||
ZENTRAL,
|
||||
KINOKASSE
|
||||
}
|
||||
|
||||
public final Id id;
|
||||
public final Version version;
|
||||
|
||||
private final Id vorfuehrungId;
|
||||
private final RestKontingent restKontingentOnline;
|
||||
private final RestKontingent restKontingentZentral;
|
||||
private final RestKontingent restKontingentKinokasse;
|
||||
|
||||
public Kontingent(final Id id,
|
||||
final RestKontingent restKontingentOnline,
|
||||
final RestKontingent restKontingentZentral,
|
||||
final RestKontingent restKontingentKinokasse,
|
||||
final Id vorfuehrungId) {
|
||||
this(id, Versionable.unknownVersion(), restKontingentOnline, restKontingentZentral, restKontingentKinokasse, vorfuehrungId);
|
||||
}
|
||||
|
||||
public Kontingent(final Id id, final Version version,
|
||||
final RestKontingent restKontingentOnline,
|
||||
final RestKontingent restKontingentZentral,
|
||||
final RestKontingent restKontingentKinokasse,
|
||||
final Id vorfuehrungId) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.restKontingentOnline = restKontingentOnline;
|
||||
this.restKontingentZentral = restKontingentZentral;
|
||||
this.restKontingentKinokasse = restKontingentKinokasse;
|
||||
this.vorfuehrungId = vorfuehrungId;
|
||||
}
|
||||
|
||||
public Kontingent(final Id id,
|
||||
final int gesamtKapazitaetVerkauf,
|
||||
final int quoteOnline,
|
||||
final Id vorfuehrungId) {
|
||||
this(id, Versionable.unknownVersion(), gesamtKapazitaetVerkauf, quoteOnline, vorfuehrungId);
|
||||
}
|
||||
|
||||
public Kontingent(final Id id, final Version version,
|
||||
final int gesamtKapazitaetVerkauf,
|
||||
final int quoteOnline,
|
||||
final Id vorfuehrungId) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.vorfuehrungId = vorfuehrungId;
|
||||
|
||||
this.restKontingentOnline =
|
||||
new RestKontingent((int) Math.ceil ((float)(gesamtKapazitaetVerkauf * quoteOnline)/100));
|
||||
this.restKontingentZentral =
|
||||
new RestKontingent((int) Math.floor((float)(gesamtKapazitaetVerkauf - restKontingentOnline.raw)/2));
|
||||
this.restKontingentKinokasse =
|
||||
new RestKontingent(gesamtKapazitaetVerkauf - restKontingentZentral.raw - restKontingentOnline.raw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public RestKontingent getRestKontingentOnline() {
|
||||
return restKontingentOnline;
|
||||
}
|
||||
|
||||
public RestKontingent getRestKontingentZentral() {
|
||||
return restKontingentZentral;
|
||||
}
|
||||
|
||||
public RestKontingent getRestKontingentKinokasse() {
|
||||
return restKontingentKinokasse;
|
||||
}
|
||||
|
||||
public Id getVorfuehrungId() {
|
||||
return vorfuehrungId;
|
||||
}
|
||||
|
||||
public Kontingent reduziereKontingent(final Ticket.VerkaufsKanal verkaufsKanal, final int anzahlGutscheine) {
|
||||
return switch (verkaufsKanal) {
|
||||
case ONLINE ->
|
||||
reduziereKontingent(Kontingent.KontingentType.ONLINE, anzahlGutscheine);
|
||||
case ZENTRAL ->
|
||||
reduziereKontingent(Kontingent.KontingentType.ZENTRAL, anzahlGutscheine);
|
||||
case KINOKASSE ->
|
||||
reduziereKontingent(Kontingent.KontingentType.KINOKASSE, anzahlGutscheine);
|
||||
};
|
||||
}
|
||||
|
||||
private Kontingent reduziereKontingent(final KontingentType kontingentType, final int kontingentReduktion) {
|
||||
if (kontingentReduktion < 0) {
|
||||
throw new FlexinaleIllegalArgumentException("reduction of Kontingent has to be >=0 but is "
|
||||
+ kontingentReduktion);
|
||||
}
|
||||
|
||||
return switch (kontingentType) {
|
||||
case ONLINE ->
|
||||
new Kontingent(this.id, this.version,
|
||||
reduziereDiesesKontingent(getRawOrNull(restKontingentOnline), kontingentReduktion),
|
||||
this.restKontingentZentral,
|
||||
this.restKontingentKinokasse,
|
||||
this.vorfuehrungId
|
||||
);
|
||||
case ZENTRAL ->
|
||||
new Kontingent(this.id, this.version,
|
||||
this.restKontingentOnline,
|
||||
reduziereDiesesKontingent(getRawOrNull(restKontingentZentral), kontingentReduktion),
|
||||
this.restKontingentKinokasse,
|
||||
this.vorfuehrungId);
|
||||
case KINOKASSE ->
|
||||
new Kontingent(this.id, this.version,
|
||||
this.restKontingentOnline,
|
||||
this.restKontingentZentral,
|
||||
reduziereDiesesKontingent(getRawOrNull(restKontingentKinokasse), kontingentReduktion),
|
||||
this.vorfuehrungId);
|
||||
};
|
||||
}
|
||||
|
||||
private RestKontingent reduziereDiesesKontingent(final int kontingent, final int reduziereUm) {
|
||||
int reduziertesKontingent = kontingent - reduziereUm;
|
||||
if (reduziertesKontingent < 0) {
|
||||
throw new KontingentBereitsAusgeschoepftException();
|
||||
}
|
||||
|
||||
return new RestKontingent(reduziertesKontingent);
|
||||
}
|
||||
|
||||
@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;}
|
||||
Kontingent that = (Kontingent) 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;}
|
||||
|
||||
Kontingent that = (Kontingent) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(id, that.id)
|
||||
.append(restKontingentOnline, that.restKontingentOnline)
|
||||
.append(restKontingentZentral, that.restKontingentZentral)
|
||||
.append(restKontingentKinokasse, that.restKontingentKinokasse)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(restKontingentOnline)
|
||||
.append(restKontingentZentral).append(restKontingentKinokasse)
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package de.accso.flexinale.ticketing.domain.model;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.DoNotCheckInArchitectureTests;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@DoNotCheckInArchitectureTests
|
||||
public class KontingentBereitsAusgeschoepftException extends RuntimeException {
|
||||
|
||||
//TODO is this exception needed? replace by boolean value in the "Ticketing" interface's method, which is currently void
|
||||
// if we keep the exception, then perhaps move as inner class to "Kontingent"?
|
||||
|
||||
public KontingentBereitsAusgeschoepftException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public KontingentBereitsAusgeschoepftException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public KontingentBereitsAusgeschoepftException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public KontingentBereitsAusgeschoepftException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
protected KontingentBereitsAusgeschoepftException(final String message, final Throwable cause,
|
||||
final boolean enableSuppression, final boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package de.accso.flexinale.ticketing.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 Ticket implements Identifiable, Versionable, EqualsByContent {
|
||||
public record Gueltig(Boolean raw) implements RawWrapper<Boolean> {}
|
||||
|
||||
public enum VerkaufsKanal {
|
||||
ONLINE,
|
||||
ZENTRAL,
|
||||
KINOKASSE
|
||||
}
|
||||
|
||||
public final Id id;
|
||||
public final Version version;
|
||||
|
||||
public final Id filmId;
|
||||
public final Id vorfuehrungId;
|
||||
public final Id besucherId;
|
||||
@DoNotCheckInArchitectureTests
|
||||
public VerkaufsKanal verkaufsKanal;
|
||||
public Gueltig gueltig;
|
||||
|
||||
public Ticket(final Id id,
|
||||
final Id filmId, final Id vorfuehrungId, final Id besucherId,
|
||||
final VerkaufsKanal verkaufsKanal){
|
||||
this(id, filmId, vorfuehrungId, besucherId, verkaufsKanal, new Gueltig(true));
|
||||
}
|
||||
|
||||
public Ticket(final Id id,
|
||||
final Id filmId, final Id vorfuehrungId, final Id besucherId,
|
||||
final VerkaufsKanal verkaufsKanal, final Gueltig gueltig) {
|
||||
this(id, Versionable.unknownVersion(), filmId, vorfuehrungId, besucherId, verkaufsKanal, gueltig);
|
||||
}
|
||||
|
||||
public Ticket(final Id id, final Version version,
|
||||
final Id filmId, final Id vorfuehrungId, final Id besucherId,
|
||||
final VerkaufsKanal verkaufsKanal, final Gueltig gueltig) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.filmId = filmId;
|
||||
this.vorfuehrungId = vorfuehrungId;
|
||||
this.besucherId = besucherId;
|
||||
this.verkaufsKanal = verkaufsKanal;
|
||||
this.gueltig = gueltig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@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;}
|
||||
Ticket that = (Ticket) 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;}
|
||||
|
||||
Ticket that = (Ticket) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(id, that.id)
|
||||
.append(filmId, that.filmId)
|
||||
.append(vorfuehrungId, that.vorfuehrungId)
|
||||
.append(besucherId, that.besucherId)
|
||||
.append(verkaufsKanal, that.verkaufsKanal)
|
||||
.append(gueltig, that.gueltig)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(filmId).append(vorfuehrungId).append(besucherId)
|
||||
.append(verkaufsKanal)
|
||||
.append(gueltig)
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package de.accso.flexinale.ticketing.domain.services;
|
||||
|
||||
import de.accso.flexinale.ticketing.domain.dao.KontingentDao;
|
||||
import de.accso.flexinale.ticketing.domain.model.Kontingent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class KontingentService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KontingentService.class);
|
||||
|
||||
final KontingentDao kontingentDao;
|
||||
|
||||
public KontingentService(final KontingentDao kontingentDao) {
|
||||
this.kontingentDao = kontingentDao;
|
||||
}
|
||||
|
||||
public List<Kontingent> kontingente() {
|
||||
return kontingentDao.findAll();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package de.accso.flexinale.ticketing.infrastructure;
|
||||
|
||||
import de.accso.flexinale.ticketing.api_out.event.OnlineKontingentChangedPublisher;
|
||||
import de.accso.flexinale.ticketing.api_out.event.TicketPublisher;
|
||||
import de.accso.flexinale.ticketing.application.services.TicketService;
|
||||
import de.accso.flexinale.ticketing.domain.services.KontingentService;
|
||||
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 BootstrappingPostConstructTicketing {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BootstrappingPostConstructTicketing.class);
|
||||
|
||||
@Autowired
|
||||
TicketService ticketService;
|
||||
|
||||
@Autowired
|
||||
TicketPublisher ticketPublisher;
|
||||
|
||||
@Autowired
|
||||
KontingentService kontingentService;
|
||||
|
||||
@Autowired
|
||||
OnlineKontingentChangedPublisher onlineKontingentChangedPublisher;
|
||||
|
||||
// Alternatively annotate method with @EventListener(ApplicationReadyEvent.class)
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
LOGGER.info("Publishing existing Tickets and Kontingente as events");
|
||||
|
||||
loadAllTicketsFromDatabaseAndPublish();
|
||||
loadAllKontingenteFromDatabaseAndPublish();
|
||||
|
||||
LOGGER.info("Publishing existing Tickets and Kontingente as events ... done");
|
||||
}
|
||||
|
||||
private void loadAllKontingenteFromDatabaseAndPublish() {
|
||||
onlineKontingentChangedPublisher.publishOnlineKontingentChanged( kontingentService.kontingente() );
|
||||
}
|
||||
|
||||
private void loadAllTicketsFromDatabaseAndPublish() {
|
||||
ticketPublisher.publishGekaufteTickets( ticketService.tickets() );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package de.accso.flexinale.ticketing.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 = "ticketingEventsConsumed")
|
||||
public class FlexinaleTicketingActuatorEndpointEventsConsumed implements EventNotification {
|
||||
private final Queue<Event> eventsConsumed = new ConcurrentLinkedQueue<>(); // event list is ordered by consumption time
|
||||
|
||||
@ReadOperation
|
||||
public List<Event> eventsConsumed() {
|
||||
return eventsConsumed.stream().toList();
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public List<Event> eventsConsumedFilteredBy(@Selector Identifiable.Id correlationId) {
|
||||
return eventsConsumed.stream().filter(event -> event.correlationId().equals(correlationId)).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(final Event event) {// might want to use a generic subscriber
|
||||
eventsConsumed.add(event);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package de.accso.flexinale.ticketing.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 = "ticketingEventsPublished")
|
||||
public class FlexinaleTicketingActuatorEndpointEventsPublished 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,100 @@
|
|||
package de.accso.flexinale.ticketing.infrastructure;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import de.accso.flexinale.common.application.Config;
|
||||
import de.accso.flexinale.common.api.eventbus.EventBusFactory;
|
||||
import de.accso.flexinale.ticketing.api_in.event.GutscheinEinloesenBeauftragtSubscriber;
|
||||
import de.accso.flexinale.ticketing.api_out.event.OnlineKontingentChangedPublisher;
|
||||
import de.accso.flexinale.ticketing.api_out.event.TicketPublisher;
|
||||
import de.accso.flexinale.ticketing.api_in.event.VorfuehrungSubscriber;
|
||||
import de.accso.flexinale.ticketing.application.services.OnlineKontingentChangedPublication;
|
||||
import de.accso.flexinale.ticketing.application.services.TicketPublication;
|
||||
import de.accso.flexinale.ticketing.application.services.TicketService;
|
||||
import de.accso.flexinale.ticketing.domain.dao.KontingentDao;
|
||||
import de.accso.flexinale.ticketing.domain.dao.TicketDao;
|
||||
import de.accso.flexinale.ticketing.domain.services.KontingentService;
|
||||
import de.accso.flexinale.ticketing.infrastructure.persistence.KontingentJpaRepository;
|
||||
import de.accso.flexinale.ticketing.infrastructure.persistence.KontingentJpaRepositoryDelegate;
|
||||
import de.accso.flexinale.ticketing.infrastructure.persistence.TicketJpaRepository;
|
||||
import de.accso.flexinale.ticketing.infrastructure.persistence.TicketJpaRepositoryDelegate;
|
||||
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-backoffice & !testdata-besucherportal" })
|
||||
@EnableJpaRepositories({"de.accso.flexinale.ticketing.infrastructure.persistence"})
|
||||
@EnableTransactionManagement
|
||||
@EntityScan(basePackages={"de.accso.flexinale.ticketing.infrastructure.persistence"})
|
||||
public class FlexinaleTicketingSpringFactory {
|
||||
|
||||
@Bean
|
||||
public KontingentDao createTicketingKontingentDao(final KontingentJpaRepository kontingentJpaRepository) {
|
||||
return new KontingentJpaRepositoryDelegate(kontingentJpaRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TicketDao createTicketingTicketDao(final TicketJpaRepository ticketJpaRepository) {
|
||||
return new TicketJpaRepositoryDelegate(ticketJpaRepository);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@Bean
|
||||
public TicketService createTicketingTicketService(final TicketDao ticketDao,
|
||||
final KontingentDao kontingentDao,
|
||||
final OnlineKontingentChangedPublication onlineKontingentChangedPublisher,
|
||||
final TicketPublication ticketPublisher,
|
||||
final Config config) {
|
||||
return new TicketService(ticketDao, kontingentDao, onlineKontingentChangedPublisher,
|
||||
ticketPublisher, config.getQuoteOnline());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OnlineKontingentChangedPublication createTicketingOnlineKontingentChangedPublisher(
|
||||
final EventBusFactory eventBusFactory,
|
||||
final FlexinaleTicketingActuatorEndpointEventsPublished endpointEventsPublished) {
|
||||
return new OnlineKontingentChangedPublisher(eventBusFactory, endpointEventsPublished);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KontingentService createTicketingKontingentService(final KontingentDao kontingentDao) {
|
||||
return new KontingentService(kontingentDao);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@Bean
|
||||
public GutscheinEinloesenBeauftragtSubscriber createTicketingGutscheinEinloesenBeauftragtSubscriber(
|
||||
final EventBusFactory eventBusFactory,
|
||||
final TicketService ticketService,
|
||||
final FlexinaleTicketingActuatorEndpointEventsConsumed endpointEventsConsumed) {
|
||||
return new GutscheinEinloesenBeauftragtSubscriber(eventBusFactory, ticketService, endpointEventsConsumed);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TicketPublication createTicketingTicketPublisher(final EventBusFactory eventBusFactory,
|
||||
final FlexinaleTicketingActuatorEndpointEventsPublished endpointEventsPublished) {
|
||||
return new TicketPublisher(eventBusFactory, endpointEventsPublished);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public VorfuehrungSubscriber createTicketingVorfuehrungSubscriber(final EventBusFactory eventBusFactory,
|
||||
final TicketService ticketService,
|
||||
final FlexinaleTicketingActuatorEndpointEventsConsumed endpointEventsConsumed) {
|
||||
return new VorfuehrungSubscriber(eventBusFactory, ticketService, endpointEventsConsumed);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
// Actuator Event serialization
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jsonTicketingCustomizer() {
|
||||
return builder -> builder.visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package de.accso.flexinale.ticketing.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="Kontingent")
|
||||
public class KontingentEntity implements Identifiable, Versionable, Serializable {
|
||||
@jakarta.persistence.Id
|
||||
public String id;
|
||||
|
||||
@jakarta.persistence.Version
|
||||
private Integer version = 0;
|
||||
|
||||
@jakarta.persistence.Column
|
||||
private Integer restKontingentOnline = 0;
|
||||
|
||||
@jakarta.persistence.Column
|
||||
private Integer restKontingentZentral = 0;
|
||||
|
||||
@jakarta.persistence.Column
|
||||
private Integer restKontingentKinokasse = 0;
|
||||
|
||||
@jakarta.persistence.Column
|
||||
private String vorfuehrungId;
|
||||
|
||||
|
||||
protected KontingentEntity() {
|
||||
}
|
||||
|
||||
public KontingentEntity(final String id, final Integer version,
|
||||
final Integer restKontingentOnline,
|
||||
final Integer restKontingentZentral,
|
||||
final Integer restKontingentKinokasse,
|
||||
final String vorfuehrungId) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.restKontingentOnline = restKontingentOnline;
|
||||
this.restKontingentZentral = restKontingentZentral;
|
||||
this.restKontingentKinokasse = restKontingentKinokasse;
|
||||
this.vorfuehrungId = vorfuehrungId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return Identifiable.Id.of(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return Versionable.Version.of(version);
|
||||
}
|
||||
|
||||
public Integer getRestKontingentOnline() {
|
||||
return restKontingentOnline;
|
||||
}
|
||||
|
||||
public Integer getRestKontingentZentral() {
|
||||
return restKontingentZentral;
|
||||
}
|
||||
|
||||
public Integer getRestKontingentKinokasse() {
|
||||
return restKontingentKinokasse;
|
||||
}
|
||||
|
||||
public String getVorfuehrungId() {
|
||||
return vorfuehrungId;
|
||||
}
|
||||
|
||||
@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;}
|
||||
|
||||
KontingentEntity that = (KontingentEntity) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(id, that.id).append(version, that.version)
|
||||
.append(restKontingentOnline, that.restKontingentOnline)
|
||||
.append(restKontingentZentral, that.restKontingentZentral)
|
||||
.append(restKontingentKinokasse, that.restKontingentKinokasse)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(restKontingentOnline)
|
||||
.append(restKontingentZentral).append(restKontingentKinokasse)
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package de.accso.flexinale.ticketing.infrastructure.persistence;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface KontingentJpaRepository extends JpaRepository<KontingentEntity, String> {
|
||||
|
||||
@Query("SELECT k FROM Kontingent k " +
|
||||
"WHERE k.vorfuehrungId = :vorfuehrungId")
|
||||
Optional<KontingentEntity> findByVorfuehrung(final String vorfuehrungId);
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package de.accso.flexinale.ticketing.infrastructure.persistence;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.ticketing.domain.dao.KontingentDao;
|
||||
import de.accso.flexinale.ticketing.domain.model.Kontingent;
|
||||
import de.accso.flexinale.ticketing.infrastructure.persistence.mapper.KontingentEntity2KontingentMapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class KontingentJpaRepositoryDelegate implements KontingentDao {
|
||||
|
||||
private final KontingentJpaRepository kontingentJpaRepository;
|
||||
|
||||
public KontingentJpaRepositoryDelegate(KontingentJpaRepository kontingentJpaRepository) {
|
||||
this.kontingentJpaRepository = kontingentJpaRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Kontingent> findAll() {
|
||||
List<KontingentEntity> KontingentEntities = kontingentJpaRepository.findAll();
|
||||
|
||||
return KontingentEntities.stream()
|
||||
.map(KontingentEntity2KontingentMapper::map)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Kontingent> findById(final Identifiable.Id id) {
|
||||
Optional<KontingentEntity> kontingentEntity = kontingentJpaRepository.findById(id.id());
|
||||
return KontingentEntity2KontingentMapper.map(kontingentEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Kontingent> findByVorfuehrung(final Identifiable.Id vorfuehrungId) {
|
||||
Optional<KontingentEntity> kontingentEntity = kontingentJpaRepository.findByVorfuehrung(vorfuehrungId.id());
|
||||
return KontingentEntity2KontingentMapper.map(kontingentEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Kontingent save(final Kontingent kontingent) {
|
||||
KontingentEntity kontingentEntity = KontingentEntity2KontingentMapper.map(kontingent);
|
||||
KontingentEntity savedEntity = kontingentJpaRepository.save(kontingentEntity);
|
||||
return KontingentEntity2KontingentMapper.map(savedEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final Kontingent kontingent) {
|
||||
KontingentEntity kontingentEntity = KontingentEntity2KontingentMapper.map(kontingent);
|
||||
kontingentJpaRepository.delete(kontingentEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(final Identifiable.Id id) {
|
||||
kontingentJpaRepository.deleteById(id.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
kontingentJpaRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package de.accso.flexinale.ticketing.infrastructure.persistence;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.common.shared_kernel.Versionable;
|
||||
import de.accso.flexinale.ticketing.domain.model.Ticket;
|
||||
import jakarta.persistence.EnumType;
|
||||
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="Ticket")
|
||||
public class TicketEntity implements Identifiable, Versionable, Serializable {
|
||||
|
||||
@jakarta.persistence.Id
|
||||
public String id; // primary key
|
||||
|
||||
public String filmId;
|
||||
|
||||
public String vorfuehrungId;
|
||||
|
||||
public String benutzerId;
|
||||
|
||||
public boolean gueltig = true;
|
||||
|
||||
@jakarta.persistence.Enumerated(EnumType.STRING)
|
||||
public Ticket.VerkaufsKanal verkaufsKanal;
|
||||
|
||||
@jakarta.persistence.Version
|
||||
private Integer version = 0;
|
||||
|
||||
protected TicketEntity() {
|
||||
}
|
||||
|
||||
public TicketEntity(final String id, final Integer version,
|
||||
final String filmId,
|
||||
final String vorfuehrungId,
|
||||
final String benutzerId,
|
||||
final Ticket.VerkaufsKanal verkaufsKanal,
|
||||
final boolean gueltig) {
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.filmId = filmId;
|
||||
this.vorfuehrungId = vorfuehrungId;
|
||||
this.benutzerId = benutzerId;
|
||||
this.verkaufsKanal = verkaufsKanal;
|
||||
this.gueltig = gueltig;
|
||||
}
|
||||
|
||||
@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;}
|
||||
|
||||
TicketEntity that = (TicketEntity) o;
|
||||
|
||||
return new EqualsBuilder()
|
||||
.append(id, that.id).append(version, that.version)
|
||||
.append(filmId, that.filmId)
|
||||
.append(vorfuehrungId, that.vorfuehrungId).append(benutzerId, that.benutzerId)
|
||||
.append(verkaufsKanal, that.verkaufsKanal)
|
||||
.append(gueltig, that.gueltig)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(id).append(version)
|
||||
.append(filmId).append(vorfuehrungId).append(benutzerId)
|
||||
.append(verkaufsKanal)
|
||||
.append(gueltig)
|
||||
.toHashCode();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package de.accso.flexinale.ticketing.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 TicketJpaRepository extends JpaRepository<TicketEntity, String> {
|
||||
|
||||
@Query("SELECT t FROM Ticket t " +
|
||||
"WHERE t.benutzerId = :benutzerId")
|
||||
List<TicketEntity> findByBenutzer(final String benutzerId);
|
||||
|
||||
@Query("SELECT t FROM Ticket t " +
|
||||
"WHERE t.vorfuehrungId = :vorfuehrungId")
|
||||
List<TicketEntity> findByVorfuehrung(final String vorfuehrungId);
|
||||
|
||||
@Query("SELECT count(t) FROM Ticket t WHERE t.benutzerId = :benutzerId")
|
||||
int gesamtZahlDerTicketsFuer(final String benutzerId);
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package de.accso.flexinale.ticketing.infrastructure.persistence;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.ticketing.domain.dao.TicketDao;
|
||||
import de.accso.flexinale.ticketing.domain.model.Ticket;
|
||||
import de.accso.flexinale.ticketing.infrastructure.persistence.mapper.TicketEntity2TicketMapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class TicketJpaRepositoryDelegate implements TicketDao {
|
||||
|
||||
private final TicketJpaRepository ticketJpaRepository;
|
||||
|
||||
public TicketJpaRepositoryDelegate(TicketJpaRepository ticketJpaRepository) {
|
||||
this.ticketJpaRepository = ticketJpaRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Ticket> findAll() {
|
||||
List<TicketEntity> ticketEntities = ticketJpaRepository.findAll();
|
||||
|
||||
return TicketEntity2TicketMapper.map(ticketEntities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Ticket> findById(final Identifiable.Id id) {
|
||||
Optional<TicketEntity> TicketEntity = ticketJpaRepository.findById(id.id());
|
||||
return TicketEntity2TicketMapper.map(TicketEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Ticket> findByBesucher(final Identifiable.Id besucherId) {
|
||||
List<TicketEntity> ticketEntitiesForBesucher = ticketJpaRepository.findByBenutzer(besucherId.id());
|
||||
return TicketEntity2TicketMapper.map(ticketEntitiesForBesucher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Ticket> findByVorfuehrung(final Identifiable.Id vorfuehrungId) {
|
||||
List<TicketEntity> ticketEntitiesForBesucher = ticketJpaRepository.findByVorfuehrung(vorfuehrungId.id());
|
||||
return TicketEntity2TicketMapper.map(ticketEntitiesForBesucher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int gesamtZahlDerTicketsFuer(final Identifiable.Id besucherId) {
|
||||
return ticketJpaRepository.gesamtZahlDerTicketsFuer(besucherId.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ticket save(final Ticket ticket) {
|
||||
TicketEntity ticketEntity = TicketEntity2TicketMapper.map(ticket);
|
||||
TicketEntity savedEntity = ticketJpaRepository.save(ticketEntity);
|
||||
return TicketEntity2TicketMapper.map(savedEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final Ticket ticket) {
|
||||
TicketEntity ticketEntity = TicketEntity2TicketMapper.map(ticket);
|
||||
ticketJpaRepository.delete(ticketEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(final Identifiable.Id id) {
|
||||
ticketJpaRepository.deleteById(id.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
ticketJpaRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package de.accso.flexinale.ticketing.infrastructure.persistence.mapper;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.ticketing.domain.model.Kontingent;
|
||||
import de.accso.flexinale.ticketing.infrastructure.persistence.KontingentEntity;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static de.accso.flexinale.common.shared_kernel.RawWrapper.getRawOrNull;
|
||||
|
||||
public final class KontingentEntity2KontingentMapper {
|
||||
|
||||
public static Kontingent map(final KontingentEntity kontingentEntity) {
|
||||
return new Kontingent(kontingentEntity.id(),
|
||||
kontingentEntity.version(),
|
||||
new Kontingent.RestKontingent(kontingentEntity.getRestKontingentOnline()),
|
||||
new Kontingent.RestKontingent(kontingentEntity.getRestKontingentZentral()),
|
||||
new Kontingent.RestKontingent(kontingentEntity.getRestKontingentKinokasse()),
|
||||
Identifiable.Id.of(kontingentEntity.getVorfuehrungId()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public static Optional<Kontingent> map(final Optional<KontingentEntity> optionalKontingentEntity) {
|
||||
if (optionalKontingentEntity.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
else {
|
||||
KontingentEntity kontingentEntity = optionalKontingentEntity.get();
|
||||
return Optional.of(map(kontingentEntity));
|
||||
}
|
||||
}
|
||||
|
||||
public static KontingentEntity map(final Kontingent kontingent) {
|
||||
return new KontingentEntity(kontingent.id().id(),
|
||||
kontingent.version().version(),
|
||||
getRawOrNull(kontingent.getRestKontingentOnline()),
|
||||
getRawOrNull(kontingent.getRestKontingentZentral()),
|
||||
getRawOrNull(kontingent.getRestKontingentKinokasse()),
|
||||
kontingent.getVorfuehrungId().id());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package de.accso.flexinale.ticketing.infrastructure.persistence.mapper;
|
||||
|
||||
import de.accso.flexinale.common.shared_kernel.Identifiable;
|
||||
import de.accso.flexinale.ticketing.domain.model.Ticket;
|
||||
import de.accso.flexinale.ticketing.infrastructure.persistence.TicketEntity;
|
||||
|
||||
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 final class TicketEntity2TicketMapper {
|
||||
|
||||
public static Ticket map(final TicketEntity ticketEntity) {
|
||||
return new Ticket(ticketEntity.id(), ticketEntity.version(),
|
||||
Identifiable.Id.of(ticketEntity.filmId), Identifiable.Id.of(ticketEntity.vorfuehrungId),
|
||||
Identifiable.Id.of(ticketEntity.benutzerId),
|
||||
ticketEntity.verkaufsKanal, new Ticket.Gueltig(ticketEntity.gueltig));
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
public static Optional<Ticket> map(final Optional<TicketEntity> optionalTicketEntity) {
|
||||
if (optionalTicketEntity.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
else {
|
||||
TicketEntity ticketEntity = optionalTicketEntity.get();
|
||||
return Optional.of(map(ticketEntity));
|
||||
}
|
||||
}
|
||||
|
||||
public static TicketEntity map(final Ticket ticket) {
|
||||
return new TicketEntity(ticket.id().id(), ticket.version().version(),
|
||||
ticket.filmId.id(), ticket.vorfuehrungId.id(), ticket.besucherId.id(),
|
||||
ticket.verkaufsKanal, getRawOrNull(ticket.gueltig));
|
||||
}
|
||||
|
||||
public static List<Ticket> map(final List<TicketEntity> ticketEntities) {
|
||||
return ticketEntities.stream().map(TicketEntity2TicketMapper::map)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
application.title=FLEXinale as Distributed Services, Ticketing
|
||||
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-ticketing
|
||||
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=8082
|
||||
|
||||
#########################################################################
|
||||
# Security
|
||||
#########################################################################
|
||||
security.enable-csrf=true
|
||||
|
||||
#########################################################################
|
||||
# Kafka
|
||||
#########################################################################
|
||||
spring.kafka.consumer.group-id=flexinale-distributed-ticketing
|
||||
|
||||
# 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
|
||||
#########################################################################
|
||||
# Quote for online kontingent in percent
|
||||
de.accso.flexinale.kontingent.quote.online=33
|
||||
|
|
@ -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 - Ticketing</title>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Flexinale Distributed - Ticketing
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# curl -v -X GET -u admin:admin1 http://localhost:8082/actuator/ticketingEventsConsumed
|
||||
GET http://localhost:8082/actuator/ticketingEventsConsumed
|
||||
Authorization: Basic admin admin1
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# curl -v -X GET -u admin:admin1 http://localhost:8082/actuator/ticketingEventsPublished
|
||||
GET http://localhost:8082/actuator/ticketingEventsPublished
|
||||
Authorization: Basic admin admin1
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# curl -v -X GET -u admin:admin1 http://localhost:8082/actuator/health
|
||||
GET http://localhost:8082/actuator/health
|
||||
Authorization: Basic admin admin1
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# curl -v -X GET -u admin:admin1 http://localhost:8082/actuator/info
|
||||
GET http://localhost:8082/actuator/info
|
||||
Authorization: Basic admin admin1
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# curl -v -X GET -u admin:admin1 http://localhost:8082/actuator/metrics
|
||||
GET http://localhost:8082/actuator/metrics
|
||||
Authorization: Basic admin admin1
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# curl -v -X GET -u admin:admin1 http://localhost:8082/actuator/prometheus
|
||||
GET http://localhost:8082/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 = {FlexinaleDistributedApplicationTicketing.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 = {FlexinaleDistributedApplicationTicketing.class})
|
||||
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
|
||||
@ActiveProfiles("smoketest")
|
||||
@DoNotCheckInArchitectureTests
|
||||
class FlexinaleDistributedApplicationTicketingSmokeTest {
|
||||
|
||||
@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 = {FlexinaleDistributedApplicationTicketing.class})
|
||||
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
|
||||
@ActiveProfiles("configtest")
|
||||
@DoNotCheckInArchitectureTests
|
||||
class FlexinaleDistributedApplicationTicketingSpringConfigTest {
|
||||
|
||||
@Autowired
|
||||
Config config;
|
||||
|
||||
@Test
|
||||
void testLoadSpringConfig() {
|
||||
// arrange, act
|
||||
// nope, is loaded auto-magically by Spring, see application-configtest.properties
|
||||
|
||||
// assert
|
||||
assertThat(config.getQuoteOnline()).isEqualTo(12);
|
||||
assertThat(config.getMinZeitZwischenVorfuehrungenInMinuten()).isEqualTo(30); // default
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# Quote for online kontingent in percent
|
||||
de.accso.flexinale.kontingent.quote.online=12
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
application.title=FLEXinale as Distributed Services, Ticketing
|
||||
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-ticketing
|
||||
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
|
||||
server.port=9092
|
||||
|
||||
#########################################################################
|
||||
# Web
|
||||
#########################################################################
|
||||
spring.thymeleaf.prefix=classpath:/templates/
|
||||
spring.thymeleaf.suffix=.html
|
||||
server.error.path=/error
|
||||
|
||||
#########################################################################
|
||||
# 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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue