Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package fr.gouv.cacem.monitorenv.domain.entities.lastPositions

import org.locationtech.jts.geom.Point
import java.time.ZonedDateTime

data class LastPositionEntity(
val course: Double?,
val destination: String?,
val geom: Point?,
val heading: Double?,
val id: Int,
val mmsi: Int?,
val status: String?,
val speed: Double?,
val shipname: String?,
val timestamp: ZonedDateTime?,
)
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
package fr.gouv.cacem.monitorenv.domain.entities.vessels

import fr.gouv.cacem.monitorenv.domain.entities.lastPositions.LastPositionEntity
import java.math.BigDecimal

data class Vessel(
val id: Int,
val shipId: Int,
val status: String?,
data class VesselEntity(
val category: String?,
val commercialName: String?,
val flag: String?,
val id: Int,
val isBanned: Boolean,
val imo: String?,
val mmsi: String?,
val immatriculation: String?,
val shipName: String?,
val flag: String?,
val portOfRegistry: String?,
val professionalType: String?,
val leisureType: String?,
val commercialName: String?,
val length: BigDecimal?,
val mmsi: String?,
val ownerLastName: String?,
val ownerFirstName: String?,
val ownerDateOfBirth: String?,
Expand All @@ -31,4 +27,10 @@ data class Vessel(
val ownerLegalStatus: String?,
val ownerLegalStatusLabel: String?,
val ownerStartDate: String?,
val portOfRegistry: String?,
val professionalType: String?,
val shipId: Int?,
val shipName: String?,
val status: String?,
val lastPositions: MutableList<LastPositionEntity>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package fr.gouv.cacem.monitorenv.domain.repositories

import fr.gouv.cacem.monitorenv.domain.entities.lastPositions.LastPositionEntity

interface ILastPositionRepository {
fun findAll(shipId: Int): List<LastPositionEntity>
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package fr.gouv.cacem.monitorenv.domain.repositories

import fr.gouv.cacem.monitorenv.domain.entities.vessels.Vessel
import fr.gouv.cacem.monitorenv.domain.entities.vessels.VesselEntity

interface IVesselRepository {
fun findVesselById(id: Int): Vessel?
fun findVesselById(id: Int): VesselEntity?

fun search(searched: String): List<Vessel>
fun search(searched: String): List<VesselEntity>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package fr.gouv.cacem.monitorenv.domain.use_cases.lastPositions

import fr.gouv.cacem.monitorenv.config.UseCase
import fr.gouv.cacem.monitorenv.domain.entities.lastPositions.LastPositionEntity
import fr.gouv.cacem.monitorenv.domain.repositories.ILastPositionRepository

@UseCase
class GetLastPositions(
private val lastPositionRepository: ILastPositionRepository,
) {
fun execute(shipId: Int): List<LastPositionEntity> = lastPositionRepository.findAll(shipId)
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
package fr.gouv.cacem.monitorenv.domain.use_cases.vessels

import fr.gouv.cacem.monitorenv.config.UseCase
import fr.gouv.cacem.monitorenv.domain.entities.vessels.Vessel
import fr.gouv.cacem.monitorenv.domain.entities.vessels.VesselEntity
import fr.gouv.cacem.monitorenv.domain.exceptions.BackendUsageErrorCode
import fr.gouv.cacem.monitorenv.domain.exceptions.BackendUsageException
import fr.gouv.cacem.monitorenv.domain.repositories.ILastPositionRepository
import fr.gouv.cacem.monitorenv.domain.repositories.IVesselRepository
import org.slf4j.LoggerFactory

@UseCase
class GetVesselById(
private val vesselRepository: IVesselRepository,
private val lastPositionRepository: ILastPositionRepository,
) {
private val logger = LoggerFactory.getLogger(GetVesselById::class.java)

fun execute(id: Int): Vessel {
fun execute(id: Int): VesselEntity {
vesselRepository.findVesselById(id)?.let { vessel ->
logger.info("GET vessel ${vessel.id}")
vessel.shipId?.let { shipId ->
val lastPositions = lastPositionRepository.findAll(shipId)
vessel.lastPositions.addAll(lastPositions)
}
return vessel
}
throw BackendUsageException(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package fr.gouv.cacem.monitorenv.domain.use_cases.vessels

import fr.gouv.cacem.monitorenv.config.UseCase
import fr.gouv.cacem.monitorenv.domain.entities.vessels.Vessel
import fr.gouv.cacem.monitorenv.domain.entities.vessels.VesselEntity
import fr.gouv.cacem.monitorenv.domain.repositories.IVesselRepository

@UseCase
class SearchVessels(
private val vesselRepository: IVesselRepository,
) {
fun execute(searched: String): List<Vessel> = vesselRepository.search(searched)
fun execute(searched: String): List<VesselEntity> = vesselRepository.search(searched)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs.lastPositions

import fr.gouv.cacem.monitorenv.domain.entities.lastPositions.LastPositionEntity
import org.locationtech.jts.geom.Point
import java.time.ZonedDateTime

data class LastPositionOutput(
val course: Double?,
val destination: String?,
val geom: Point?,
val heading: Double?,
val id: Int,
val mmsi: Int?,
val shipname: String?,
val status: String?,
val speed: Double?,
val timestamp: ZonedDateTime?,
) {
companion object {
fun toLastPositionOutput(lastPosition: LastPositionEntity) =
LastPositionOutput(
course = lastPosition.course,
destination = lastPosition.destination,
geom = lastPosition.geom,
heading = lastPosition.heading,
id = lastPosition.id,
mmsi = lastPosition.mmsi,
shipname = lastPosition.shipname,
status = lastPosition.status,
speed = lastPosition.speed,
timestamp = lastPosition.timestamp,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs.vessels

import fr.gouv.cacem.monitorenv.domain.entities.vessels.Vessel
import fr.gouv.cacem.monitorenv.domain.entities.vessels.VesselEntity
import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs.lastPositions.LastPositionOutput
import java.math.BigDecimal

data class VesselDataOutput(
Expand Down Expand Up @@ -28,9 +29,10 @@ data class VesselDataOutput(
val ownerBusinessSegmentLabel: String?,
val ownerLegalStatusLabel: String?,
val ownerStartDate: String?,
val lastPositions: List<LastPositionOutput>,
) {
companion object {
fun fromVessel(vessel: Vessel): VesselDataOutput =
fun fromVessel(vessel: VesselEntity): VesselDataOutput =
VesselDataOutput(
id = vessel.id,
status = vessel.status,
Expand All @@ -44,6 +46,7 @@ data class VesselDataOutput(
leisureType = vessel.leisureType,
professionalType = vessel.professionalType,
commercialName = vessel.commercialName,
lastPositions = vessel.lastPositions.map { LastPositionOutput.toLastPositionOutput(it) },
length = vessel.length,
ownerLastName = vessel.ownerLastName,
ownerFirstName = vessel.ownerFirstName,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs.vessels

import fr.gouv.cacem.monitorenv.domain.entities.vessels.Vessel
import fr.gouv.cacem.monitorenv.domain.entities.vessels.VesselEntity

data class VesselIdentityDataOutput(
val id: Int,
val category: String?,
val flag: String?,
val mmsi: String?,
val id: Int,
val imo: String?,
val immatriculation: String?,
val mmsi: String?,
val shipId: Int?,
val shipName: String?,
val category: String?,
) {
companion object {
fun fromVessel(vessel: Vessel): VesselIdentityDataOutput =
fun fromVessel(vessel: VesselEntity): VesselIdentityDataOutput =
VesselIdentityDataOutput(
id = vessel.id,
shipId = vessel.shipId,
flag = vessel.flag,
mmsi = vessel.mmsi,
imo = vessel.imo,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package fr.gouv.cacem.monitorenv.infrastructure.api.endpoints.bff.v1

import fr.gouv.cacem.monitorenv.domain.use_cases.lastPositions.GetLastPositions
import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs.lastPositions.LastPositionOutput
import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.bff.outputs.lastPositions.LastPositionOutput.Companion.toLastPositionOutput
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.websocket.server.PathParam
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/bff/v1/last_positions")
@Tag(name = "APIs for Vessel's last positions")
class LastPositions(
private val getLastPositions: GetLastPositions,
) {
@GetMapping("/{shipId}")
@Operation(summary = "Get last position of vessel by ship id")
fun getLastPositionsByShipId(
@PathParam("Ship ID")
@PathVariable(name = "shipId")
shipId: Int,
): List<LastPositionOutput> = getLastPositions.execute(shipId).map { toLastPositionOutput(it) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,59 @@ data class AISPositionModel(
val course: Short?,
val heading: Short?,
val speed: Short?,
val imo: String?,
val callsign: String?,
val shipname: String?,
val shiptype: Int?,
val toBow: Short?,
val toStern: Short?,
val toPort: Short?,
val toStarboard: Short?,
val draught: Short?,
val destination: String?,
) {
companion object {
fun toAISPositionModel(aisPosition: AISPayload): AISPositionModel =
AISPositionModel(
id = AISPositionPK(mmsi = aisPosition.mmsi, ts = aisPosition.ts),
id = AISPositionPK(mmsi = aisPosition.mmsi, ts = aisPosition.features?.ais?.ts),
coord = aisPosition.coord.let { WKTReader().read(it) },
status = aisPosition.status,
course = aisPosition.course?.let { (it * 100).roundToInt().toShort() },
speed = aisPosition.speed?.let { (it * 100).roundToInt().toShort() },
heading = aisPosition.heading?.let { (it * 100).roundToInt().toShort() },
course = aisPosition.course?.let(toShort()),
speed = aisPosition.speed?.let(toShort()),
heading = aisPosition.heading?.let(toShort()),
imo = aisPosition.features?.ais?.imo,
callsign = aisPosition.features?.ais?.callsign,
shipname = aisPosition.features?.ais?.shipname,
shiptype = aisPosition.features?.ais?.shiptype,
toBow =
aisPosition.features
?.ais
?.toBow
?.let(toShort()),
toStern =
aisPosition.features
?.ais
?.toStern
?.let(toShort()),
toPort =
aisPosition.features
?.ais
?.toPort
?.let(toShort()),
toStarboard =
aisPosition.features
?.ais
?.toStarboard
?.let(toShort()),
draught =
aisPosition.features
?.ais
?.draught
?.let(toShort()),
destination = aisPosition.features?.ais?.destination,
)

private fun toShort(): (Double) -> Short = { (it * 100).roundToInt().toShort() }
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package fr.gouv.cacem.monitorenv.infrastructure.database.model

import fr.gouv.cacem.monitorenv.domain.entities.lastPositions.LastPositionEntity
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.Id
import jakarta.persistence.Table
import org.locationtech.jts.geom.Point
import java.time.ZonedDateTime

@Entity
@Table(name = "last_positions")
data class LastPositionModel(
val course: Short?,
val destination: String?,
@Id
val id: Int,
@Column(name = "coord")
val geom: Point?,
val heading: Short?,
val mmsi: Int?,
@Column(name = "vessel_id")
val shipId: Int,
val shipname: String?,
val speed: Short?,
val status: String?,
@Column(name = "ts")
val timestamp: ZonedDateTime?,
) {
fun toLastPosition(): LastPositionEntity =
LastPositionEntity(
course = course?.let(toDouble()),
destination = destination,
id = id,
geom = geom,
heading = heading?.let(toDouble()),
mmsi = mmsi,
shipname = shipname,
status = status,
speed = speed?.let(toDouble()),
timestamp = timestamp,
)

companion object {
private fun toDouble(): (Short) -> Double = { (it.toDouble() / 100) }
}
}
Loading
Loading