Documentation

This commit is contained in:
Gaa56
2025-12-07 15:51:50 +00:00
parent 1b6ad03057
commit b624cfe11e
3 changed files with 108 additions and 96 deletions

View File

@@ -20,58 +20,65 @@ import sd.protocol.MessageProtocol;
import sd.protocol.SocketConnection; import sd.protocol.SocketConnection;
/** /**
* Processo responsável pelo nó de saída do sistema de simulação de tráfego * Represents the final Exit Node ("S") of the distributed traffic simulation.
* distribuído.
* *
* Este processo representa o ponto final ("S") onde os veículos completam as * This process acts as a "sink" for all vehicles completing their routes.
* suas rotas. * Unlike intersections, it does not route traffic but focuses on data collection.
* As suas principais responsabilidades são: * Its primary responsibilities are:
* - Receber veículos que terminam a sua rota vindos das interseções * - Accepting TCP connections from intersection processes.
* - Calcular e agregar estatísticas finais dos veículos * - Receiving {@link Vehicle} objects via the network.
* - Enviar estatísticas periódicas para o dashboard * - Calculating final performance metrics (Total System Time, Waiting Time, Crossing Time).
* - Gerar relatórios finais ao terminar a simulação * - Aggregating statistics by {@link VehicleType}.
* - Reporting real-time data to the Dashboard service via {@link SocketClient}.
* - Generating a final statistical report upon shutdown.
*/ */
public class ExitNodeProcess { public class ExitNodeProcess {
// --- Configuration and Networking ---
private final SimulationConfig config; private final SimulationConfig config;
private ServerSocket serverSocket; private ServerSocket serverSocket;
/**
* Thread pool to handle concurrent incoming connections from multiple intersections.
*/
private final ExecutorService connectionHandlerPool; private final ExecutorService connectionHandlerPool;
/** /**
* Flag para controlar a execução do processo (volatile para visibilidade entre * Volatile flag to control the lifecycle of the process.
* threads)
*/ */
private volatile boolean running; private volatile boolean running;
/** Simulation start time (milliseconds) to calculate relative times */ /** * Simulation start time (in milliseconds) used to calculate relative arrival times.
* This is synchronized with the Coordinator.
*/
private long simulationStartMillis; private long simulationStartMillis;
/** Counter de veículos que completaram a rota */ // --- Statistics and Metrics ---
/** Total count of vehicles that have successfully completed their route. */
private int totalVehiclesReceived; private int totalVehiclesReceived;
/** Soma dos tempos no sistema de todos os veículos */ /** Accumulated time (in seconds) that all vehicles spent in the system. */
private double totalSystemTime; private double totalSystemTime;
/** Soma dos tempos de espera de todos os veículos */ /** Accumulated time (in seconds) that all vehicles spent waiting at red lights. */
private double totalWaitingTime; private double totalWaitingTime;
/** Soma dos tempos de travessia de todos os veículos */ /** Accumulated time (in seconds) that all vehicles spent crossing intersections. */
private double totalCrossingTime; private double totalCrossingTime;
/** Contagem de veículos por tipo */ /** Counter of vehicles separated by {@link VehicleType}. */
private final Map<VehicleType, Integer> vehicleTypeCount; private final Map<VehicleType, Integer> vehicleTypeCount;
/** Tempo total de espera acumulado por tipo de veículo */ /** Accumulated wait time separated by {@link VehicleType}. */
private final Map<VehicleType, Double> vehicleTypeWaitTime; private final Map<VehicleType, Double> vehicleTypeWaitTime;
/** Socket para comunicação com o dashboard */ /** Client connection to send updates to the Dashboard. */
private SocketClient dashboardClient; private SocketClient dashboardClient;
/** /**
* Método para iniciar o processo * Main entry point for the Exit Node process.
* * * @param args Command line arguments. Optional args[0] for config file path.
* @param args Argumentos da linha de comandos. Se fornecido, args[0] deve ser
* o caminho para um ficheiro de configuração personalizado.
*/ */
public static void main(String[] args) { public static void main(String[] args) {
System.out.println("=".repeat(60)); System.out.println("=".repeat(60));
@@ -101,14 +108,10 @@ public class ExitNodeProcess {
} }
/** /**
* Constrói um novo processo de nó de saída. * Constructs a new ExitNodeProcess.
* * * Initializes all data structures required for statistics collection
* Inicializa todas as estruturas de dados necessárias para recolher * and sets up the thread pool for handling concurrent network connections.
* estatísticas * * @param config The loaded {@link SimulationConfig} containing ports and addresses.
* e configura o pool de threads para processar as ligações concorrentes.
*
* @param config Configuração da simulação contendo portas e endereços dos
* serviços
*/ */
public ExitNodeProcess(SimulationConfig config) { public ExitNodeProcess(SimulationConfig config) {
this.config = config; this.config = config;
@@ -133,12 +136,11 @@ public class ExitNodeProcess {
System.out.println(" - Dashboard: " + config.getDashboardHost() + ":" + config.getDashboardPort()); System.out.println(" - Dashboard: " + config.getDashboardHost() + ":" + config.getDashboardPort());
} }
/** /**
* Inicializa o processo de ligação ao dashboard. * Initializes the connection to the external Dashboard service.
* * * Attempts to establish a TCP connection to the dashboard. If successful,
* Tenta conectar-se ao dashboard. Se a ligação falhar, o processo * this connection will be used to stream live statistics.
* continua a funcionar normalmente, mas sem enviar estatísticas. * If the connection fails, the process logs a warning but continues operation.
*
*/ */
public void initialize() { public void initialize() {
System.out.println("Connecting to dashboard..."); System.out.println("Connecting to dashboard...");
@@ -158,15 +160,12 @@ public class ExitNodeProcess {
} }
/** /**
* Inicia o socket e começa a aceitar ligações. * Starts the server socket and begins the main event loop.
* * * This method:
* Este é o loop principal do processo que: * 1. Binds a {@link ServerSocket} to the configured exit port.
* 1. Cria um socket na porta definida * 2. Enters a loop accepting incoming connections from Intersections.
* 2. Aguarda pelas ligações das interseções * 3. Submits each new connection to the {@code connectionHandlerPool} for asynchronous processing.
* 3. Delega cada ligação a uma thread da pool para processamento assíncrono * * @throws IOException If the server socket cannot be bound.
*
* @throws IOException Se o socket não puder ser criado ou houver erro na
* aceitação
*/ */
public void start() throws IOException { public void start() throws IOException {
int port = config.getExitPort(); int port = config.getExitPort();
@@ -189,14 +188,12 @@ public class ExitNodeProcess {
} }
} }
/** /**
* Processa uma ligação recebida de uma interseção. * Handles an active connection from an Intersection process.
* * * Continuously reads {@link MessageProtocol} objects from the socket.
* Mantém a ligação aberta e processa continuamente mensagens do tipo * Expects primarily {@link MessageType#VEHICLE_TRANSFER} messages containing
* VEHICLE_TRANSFER. Cada mensagem representa um veículo que chegou ao nó de * {@link Vehicle} payloads.
* saída. * * @param clientSocket The accepted socket connection.
*
* @param clientSocket Socket da ligação estabelecida com a interseção
*/ */
private void handleIncomingConnection(Socket clientSocket) { private void handleIncomingConnection(Socket clientSocket) {
String clientAddress = clientSocket.getInetAddress().getHostAddress(); String clientAddress = clientSocket.getInetAddress().getHostAddress();
@@ -252,15 +249,14 @@ public class ExitNodeProcess {
} }
/** /**
* Processa um veículo que chegou ao nó de saída. * Processes a vehicle that has completed its route.
* * * This method is {@code synchronized} to ensure thread safety when updating
* Método sincronizado para garantir thread-safety ao atualizar as estatísticas. * shared statistical counters. It calculates final metrics:
* Calcula as métricas finais do veículo e atualiza: * - System Time: Total time since entry.
* - Counters globais; * - Wait Time: Total time spent at red lights.
* - Estatísticas por tipo de veículo; * - Crossing Time: Total time spent crossing intersections.
* - Faz update ao dashboard a cada 10 veículos. * * It triggers an immediate update to the Dashboard.
* * * @param vehicle The vehicle that has arrived at the Exit Node.
* @param vehicle Veículo que completou a sua rota
*/ */
private synchronized void processExitingVehicle(Vehicle vehicle) { private synchronized void processExitingVehicle(Vehicle vehicle) {
totalVehiclesReceived++; totalVehiclesReceived++;
@@ -289,13 +285,10 @@ public class ExitNodeProcess {
} }
/** /**
* Envia as estatísticas para o dashboard. * Sends current aggregated statistics to the Dashboard.
* * * Constructs a {@link StatsUpdatePayload} containing global counters and
* Prepara e envia uma mensagem STATS_UPDATE com: * per-type metrics, converting seconds to milliseconds as expected by the frontend.
* - O total de veículos processados; * Wraps the payload in a {@link Message} and sends it via the dashboard client.
* - A média dos tempos (sistema, espera, travessia);
* - As contagens e médias por cada tipo de veículo.
*
*/ */
private void sendStatsToDashboard() { private void sendStatsToDashboard() {
if (dashboardClient == null || !dashboardClient.isConnected()) { if (dashboardClient == null || !dashboardClient.isConnected()) {
@@ -346,15 +339,14 @@ public class ExitNodeProcess {
} }
} }
/** /**
* Termina o processo * Gracefully shuts down the exit node process.
* * * Sequence of operations:
* Executa a seguinte sequência: * 1. Prints final statistics to the console.
* Imprime as estatísticas finais no terminal; * 2. Sends one last update to the dashboard.
* Envia a última atualização de estatísticas ao dashboard; * 3. Closes the server socket to stop accepting connections.
* Fecha o socket; * 4. Shuts down the thread pool.
* Aguarda pela finalização das threads; * 5. Closes the dashboard connection.
* Fecha a ligação com o dashboard;
*/ */
public void shutdown() { public void shutdown() {
System.out.println("\n[Exit] Shutting down..."); System.out.println("\n[Exit] Shutting down...");
@@ -390,15 +382,12 @@ public class ExitNodeProcess {
} }
/** /**
* Imprime as estatísticas finais detalhadas no terminal * Prints a detailed statistical report to the console.
* * * Included metrics:
* Gera um relatório com: * - Total vehicles processed.
* Total de veículos que completaram a rota; * - Average System Time, Waiting Time, and Crossing Time.
* Médias de tempo no sistema, espera e travessia; * - Distribution count and percentage by Vehicle Type.
* Distribuição e médias pelo tipo de veículo (BIKE, LIGHT, HEAVY); * - Average wait time by Vehicle Type.
*
* Este método é chamado durante o shutdown para fornecer um resumo
* da simulação antes de terminar o processo.
*/ */
private void printFinalStatistics() { private void printFinalStatistics() {
System.out.println("\n=== EXIT NODE STATISTICS ==="); System.out.println("\n=== EXIT NODE STATISTICS ===");

View File

@@ -1,7 +1,8 @@
package sd.protocol; package sd.protocol;
import java.io.Serializable; import java.io.Serializable;
import sd.model.MessageType; // Assuming MessageType is in sd.model or sd.protocol
import sd.model.MessageType;
/** /**
* Interface defining the contract for all messages exchanged in the simulator. * Interface defining the contract for all messages exchanged in the simulator.

View File

@@ -23,9 +23,30 @@ import sd.serialization.SerializerFactory;
*/ */
public class SocketConnection implements Closeable { public class SocketConnection implements Closeable {
// --- Network Resources ---
/**
* The underlying TCP socket used for network communication.
*/
private final Socket socket; private final Socket socket;
/**
* The raw output stream for writing bytes to the network.
* Wrapped by {@link DataOutputStream} during message sending.
*/
private final OutputStream outputStream; private final OutputStream outputStream;
/**
* The raw input stream for reading bytes from the network.
* Wrapped by {@link DataInputStream} during message reception.
*/
private final InputStream inputStream; private final InputStream inputStream;
// --- Serialization ---
/**
* The serializer strategy used to convert objects to/from byte arrays (e.g., JSON).
*/
private final MessageSerializer serializer; private final MessageSerializer serializer;
// --- Configuration for Retry Logic --- // --- Configuration for Retry Logic ---
@@ -159,7 +180,7 @@ public class SocketConnection implements Closeable {
} }
try { try {
// Lê um prefixo de 4 bytes - indicador de tamanho
DataInputStream dataIn = new DataInputStream(inputStream); DataInputStream dataIn = new DataInputStream(inputStream);
int length = dataIn.readInt(); int length = dataIn.readInt();
@@ -167,11 +188,11 @@ public class SocketConnection implements Closeable {
throw new IOException("Invalid message length: " + length); throw new IOException("Invalid message length: " + length);
} }
// Ler dados da mensagem
byte[] data = new byte[length]; byte[] data = new byte[length];
dataIn.readFully(data); dataIn.readFully(data);
// Deserialize do JSON - use concrete Message class, not interface // JSON deserialization- use concrete Message class, not interface
return serializer.deserialize(data, sd.model.Message.class); return serializer.deserialize(data, sd.model.Message.class);
} catch (SerializationException e) { } catch (SerializationException e) {
@@ -179,7 +200,7 @@ public class SocketConnection implements Closeable {
} }
} }
/** /**
* Closes the socket and all streams (Input and Output). * Closes the socket and all streams (Input and Output).
*/ */
@Override @Override
@@ -190,7 +211,8 @@ public class SocketConnection implements Closeable {
} }
/** /**
* @return true if the socket is still connected and not closed. * Checks the current state of the connection.
* @return {@code true} if the socket is connected and currently open, {@code false} otherwise.
*/ */
public boolean isConnected() { public boolean isConnected() {
return socket != null && socket.isConnected() && !socket.isClosed(); return socket != null && socket.isConnected() && !socket.isClosed();