Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

```
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package dev.luismachadoreis.flighttracker.server.ping.domain;

import java.time.Instant;
public record PingCreatedEvent (
Ping ping,
Instant timestamp
) {}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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));
}

}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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 {

Expand Down Expand Up @@ -42,24 +42,17 @@ void shouldRegisterPingCreatedEvent() {

// Then
@SuppressWarnings("unchecked")
Collection<Object> events = (Collection<Object>) ReflectionTestUtils.getField(ping, "domainEvents");
var events = Optional.ofNullable(
(Collection<Object>) 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());
}
}

This file was deleted.