diff --git a/README.md b/README.md index a517f64..abc5424 100644 --- a/README.md +++ b/README.md @@ -293,6 +293,68 @@ app: - `ReadWriteRoutingAspect`: Sets the context based on transaction type - `DbContextHolder`: Thread-local holder for the current context +## Message Payloads + +The application uses two main DTOs for message communication: + +### PingDTO +Used to publish flight position updates to the flight-tracker-event-app via WebSocket. + +```json +{ + "id": "uuid", + "aircraft": { + "icao24": "string", + "callsign": "string", + "origin_country": "string", + "last_contact": "timestamp", + "squawk": "string", + "spi": boolean, + "sensors": [integer] + }, + "vector": { + "velocity": double, + "true_track": double, + "vertical_rate": double + }, + "position": { + "longitude": double, + "latitude": double, + "geo_altitude": double, + "baro_altitude": double, + "on_ground": boolean, + "source": integer, + "time": "timestamp" + }, + "last_update": "timestamp" +} +``` + +### FlightDataDTO +Used to subscribe to flight tracker data from the flight tracker producer via Kafka. + +```json +{ + "icao24": "string", + "callsign": "string", + "origin_country": "string", + "last_contact": long, + "time_position": long, + "longitude": double, + "latitude": double, + "baro_altitude": double, + "on_ground": boolean, + "velocity": double, + "true_track": double, + "vertical_rate": double, + "sensors": [integer], + "geo_altitude": double, + "squawk": "string", + "spi": boolean, + "position_source": integer +} +``` + ## Project Structure ``` diff --git a/src/main/java/dev/luismachadoreis/flighttracker/server/ping/domain/Ping.java b/src/main/java/dev/luismachadoreis/flighttracker/server/ping/domain/Ping.java index 1c23547..aa8fbda 100644 --- a/src/main/java/dev/luismachadoreis/flighttracker/server/ping/domain/Ping.java +++ b/src/main/java/dev/luismachadoreis/flighttracker/server/ping/domain/Ping.java @@ -1,14 +1,21 @@ package dev.luismachadoreis.flighttracker.server.ping.domain; -import dev.luismachadoreis.flighttracker.server.ping.domain.event.PingCreated; -import jakarta.persistence.*; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.springframework.data.domain.AbstractAggregateRoot; - import java.time.Instant; -import java.util.UUID; import java.util.Arrays; +import java.util.UUID; + +import org.springframework.data.domain.AbstractAggregateRoot; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Converter; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import lombok.Getter; +import lombok.NoArgsConstructor; @Entity @Getter @@ -131,19 +138,7 @@ public Integer[] convertToEntityAttribute(String dbData) { * Register the PingCreated event. */ public void registerPingCreated() { - registerEvent(new PingCreated( - this.id, - this.aircraft.icao24(), - this.aircraft.callsign(), - this.position.latitude(), - this.position.longitude(), - this.vector.trueTrack(), - this.position.geoAltitude(), - this.position.baroAltitude(), - this.position.onGround(), - this.vector.velocity(), - this.vector.verticalRate(), - this.lastUpdate - )); + registerEvent(new PingCreatedEvent(this, this.lastUpdate)); } + } \ No newline at end of file diff --git a/src/main/java/dev/luismachadoreis/flighttracker/server/ping/domain/PingCreatedEvent.java b/src/main/java/dev/luismachadoreis/flighttracker/server/ping/domain/PingCreatedEvent.java new file mode 100644 index 0000000..cb67b39 --- /dev/null +++ b/src/main/java/dev/luismachadoreis/flighttracker/server/ping/domain/PingCreatedEvent.java @@ -0,0 +1,7 @@ +package dev.luismachadoreis.flighttracker.server.ping.domain; + +import java.time.Instant; +public record PingCreatedEvent ( + Ping ping, + Instant timestamp +) {} \ No newline at end of file diff --git a/src/main/java/dev/luismachadoreis/flighttracker/server/ping/domain/event/PingCreated.java b/src/main/java/dev/luismachadoreis/flighttracker/server/ping/domain/event/PingCreated.java deleted file mode 100644 index d86bf53..0000000 --- a/src/main/java/dev/luismachadoreis/flighttracker/server/ping/domain/event/PingCreated.java +++ /dev/null @@ -1,32 +0,0 @@ -package dev.luismachadoreis.flighttracker.server.ping.domain.event; - -import java.time.Instant; -import java.util.UUID; - -import com.fasterxml.jackson.annotation.JsonProperty; -public record PingCreated ( - @JsonProperty("ping_id") - UUID pingId, - @JsonProperty("icao24") - String icao24, - @JsonProperty("callsign") - String callsign, - @JsonProperty("latitude") - Double latitude, - @JsonProperty("longitude") - Double longitude, - @JsonProperty("true_track") - Double trueTrack, - @JsonProperty("geo_altitude") - Double geoAltitude, - @JsonProperty("baro_altitude") - Double baroAltitude, - @JsonProperty("on_ground") - Boolean onGround, - @JsonProperty("velocity") - Double velocity, - @JsonProperty("vertical_rate") - Double verticalRate, - @JsonProperty("timestamp") - Instant timestamp -) {} \ No newline at end of file diff --git a/src/main/java/dev/luismachadoreis/flighttracker/server/ping/infrastructure/pubsub/PingEventPublisher.java b/src/main/java/dev/luismachadoreis/flighttracker/server/ping/infrastructure/pubsub/PingEventPublisher.java index 10a3716..9b26ba3 100644 --- a/src/main/java/dev/luismachadoreis/flighttracker/server/ping/infrastructure/pubsub/PingEventPublisher.java +++ b/src/main/java/dev/luismachadoreis/flighttracker/server/ping/infrastructure/pubsub/PingEventPublisher.java @@ -1,40 +1,37 @@ package dev.luismachadoreis.flighttracker.server.ping.infrastructure.pubsub; -import dev.luismachadoreis.flighttracker.server.common.utils.JsonUtils; -import dev.luismachadoreis.flighttracker.server.ping.domain.event.PingCreated; -import dev.luismachadoreis.flighttracker.server.ping.infrastructure.websocket.MapUpdatesHandler; -import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.transaction.event.TransactionPhase; import org.springframework.transaction.event.TransactionalEventListener; +import dev.luismachadoreis.flighttracker.server.common.utils.JsonUtils; +import dev.luismachadoreis.flighttracker.server.ping.application.dto.PingDTO; +import dev.luismachadoreis.flighttracker.server.ping.application.dto.PingMapper; +import dev.luismachadoreis.flighttracker.server.ping.domain.PingCreatedEvent; +import dev.luismachadoreis.flighttracker.server.ping.infrastructure.websocket.MapUpdatesHandler; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + /** * Publishes PingCreated events to the MapUpdatesHandler. */ @Slf4j @Component +@AllArgsConstructor public class PingEventPublisher { + private final PingMapper pingMapper; private final MapUpdatesHandler mapUpdatesHandler; private final JsonUtils jsonUtils; - /** - * Constructor for PingEventPublisher. - * @param mapUpdatesHandler the MapUpdatesHandler to publish to - * @param jsonUtils the JsonUtils to use for serialization - */ - public PingEventPublisher(MapUpdatesHandler mapUpdatesHandler, JsonUtils jsonUtils) { - this.mapUpdatesHandler = mapUpdatesHandler; - this.jsonUtils = jsonUtils; - } - /** * Handles PingCreated events. * @param event the PingCreated event */ @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) - public void handlePingCreated(PingCreated event) { - mapUpdatesHandler.sendMessage(jsonUtils.toJson(event)); + public void handlePingCreated(PingCreatedEvent event) { + PingDTO pingDTO = pingMapper.toDTO(event.ping()); + mapUpdatesHandler.sendMessage(jsonUtils.toJson(pingDTO)); } } \ No newline at end of file diff --git a/src/test/java/dev/luismachadoreis/flighttracker/server/ping/domain/PingCreatedEventTest.java b/src/test/java/dev/luismachadoreis/flighttracker/server/ping/domain/PingCreatedEventTest.java new file mode 100644 index 0000000..3b6c076 --- /dev/null +++ b/src/test/java/dev/luismachadoreis/flighttracker/server/ping/domain/PingCreatedEventTest.java @@ -0,0 +1,27 @@ +package dev.luismachadoreis.flighttracker.server.ping.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Instant; + +import org.junit.jupiter.api.Test; + +class PingCreatedEventTest { + + @Test + void shouldCreatePingCreatedEvent() { + // Given + var aircraft = new Ping.Aircraft("ABC123", "FL123", "US", Instant.now(), "7700", true, new Integer[]{1, 2}); + var vector = new Ping.Vector(500.0, 180.0, 0.0); + var position = new Ping.Position(10.0, 20.0, 30000.0, 29000.0, false, 1, Instant.now()); + var ping = new Ping(aircraft, vector, position); + var timestamp = Instant.now(); + + // When + var event = new PingCreatedEvent(ping, timestamp); + + // Then + assertThat(event.ping()).isEqualTo(ping); + assertThat(event.timestamp()).isEqualTo(timestamp); + } +} \ No newline at end of file diff --git a/src/test/java/dev/luismachadoreis/flighttracker/server/ping/domain/PingTest.java b/src/test/java/dev/luismachadoreis/flighttracker/server/ping/domain/PingTest.java index 3a921d8..533e58c 100644 --- a/src/test/java/dev/luismachadoreis/flighttracker/server/ping/domain/PingTest.java +++ b/src/test/java/dev/luismachadoreis/flighttracker/server/ping/domain/PingTest.java @@ -1,13 +1,13 @@ package dev.luismachadoreis.flighttracker.server.ping.domain; -import dev.luismachadoreis.flighttracker.server.ping.domain.event.PingCreated; -import org.junit.jupiter.api.Test; -import org.springframework.test.util.ReflectionTestUtils; +import static org.assertj.core.api.Assertions.assertThat; import java.time.Instant; import java.util.Collection; +import java.util.Optional; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; +import org.springframework.test.util.ReflectionTestUtils; class PingTest { @@ -42,24 +42,17 @@ void shouldRegisterPingCreatedEvent() { // Then @SuppressWarnings("unchecked") - Collection events = (Collection) ReflectionTestUtils.getField(ping, "domainEvents"); + var events = Optional.ofNullable( + (Collection) ReflectionTestUtils.getField(ping, "domainEvents") + ).orElseThrow(() -> new IllegalStateException("Domain events collection is null")); + assertThat(events) .hasSize(1) .first() - .isInstanceOf(PingCreated.class); + .isInstanceOf(PingCreatedEvent.class); - var event = (PingCreated) events.iterator().next(); - assertThat(event.pingId()).isEqualTo(ping.getId()); - assertThat(event.icao24()).isEqualTo(aircraft.icao24()); - assertThat(event.callsign()).isEqualTo(aircraft.callsign()); - assertThat(event.latitude()).isEqualTo(position.latitude()); - assertThat(event.longitude()).isEqualTo(position.longitude()); - assertThat(event.trueTrack()).isEqualTo(vector.trueTrack()); - assertThat(event.geoAltitude()).isEqualTo(position.geoAltitude()); - assertThat(event.baroAltitude()).isEqualTo(position.baroAltitude()); - assertThat(event.onGround()).isEqualTo(position.onGround()); - assertThat(event.velocity()).isEqualTo(vector.velocity()); - assertThat(event.verticalRate()).isEqualTo(vector.verticalRate()); + var event = (PingCreatedEvent) events.stream().findFirst().orElseThrow(() -> new IllegalStateException("No event found")); + assertThat(event.ping()).isEqualTo(ping); assertThat(event.timestamp()).isEqualTo(ping.getLastUpdate()); } } \ No newline at end of file diff --git a/src/test/java/dev/luismachadoreis/flighttracker/server/ping/domain/event/PingCreatedTest.java b/src/test/java/dev/luismachadoreis/flighttracker/server/ping/domain/event/PingCreatedTest.java deleted file mode 100644 index cd2dca9..0000000 --- a/src/test/java/dev/luismachadoreis/flighttracker/server/ping/domain/event/PingCreatedTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package dev.luismachadoreis.flighttracker.server.ping.domain.event; - -import org.junit.jupiter.api.Test; - -import java.time.Instant; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; - -class PingCreatedTest { - - @Test - void shouldCreatePingCreatedEvent() { - // Given - var id = UUID.randomUUID(); - var icao24 = "ABC123"; - var callsign = "FL123"; - var latitude = 10.0; - var longitude = 20.0; - var geoAltitude = 30000.0; - var baroAltitude = 29000.0; - var onGround = false; - var velocity = 100.0; - var verticalRate = 1000.0; - var timestamp = Instant.now(); - var trueTrack = 10.0; - // When - var event = new PingCreated( - id, - icao24, - callsign, - latitude, - longitude, - trueTrack, - geoAltitude, - baroAltitude, - onGround, - velocity, - verticalRate, - timestamp - ); - - // Then - assertThat(event.pingId()).isEqualTo(id); - assertThat(event.icao24()).isEqualTo(icao24); - assertThat(event.callsign()).isEqualTo(callsign); - assertThat(event.latitude()).isEqualTo(latitude); - assertThat(event.longitude()).isEqualTo(longitude); - assertThat(event.geoAltitude()).isEqualTo(geoAltitude); - assertThat(event.baroAltitude()).isEqualTo(baroAltitude); - assertThat(event.onGround()).isEqualTo(onGround); - assertThat(event.timestamp()).isEqualTo(timestamp); - } -} \ No newline at end of file