diff --git a/main/src/main/java/sd/IntersectionProcess.java b/main/src/main/java/sd/IntersectionProcess.java index cfd3b1a..3d359bc 100644 --- a/main/src/main/java/sd/IntersectionProcess.java +++ b/main/src/main/java/sd/IntersectionProcess.java @@ -271,16 +271,20 @@ public class IntersectionProcess { /** * Processa a fila de veículos quando um semáforo fica verde. * - *
Para cada veículo na fila:
+ *+ * Para cada veículo na fila: + *
*Os veículos que não couberem no tempo verde ficam à espera do próximo ciclo.
+ *+ * Os veículos que não couberem no tempo verde ficam à espera do próximo ciclo. + *
* - * @param light o semáforo que acabou de ficar verde + * @param light o semáforo que acabou de ficar verde * @param currentTime o tempo atual da simulação em segundos */ private void processQueuedVehiclesForLight(TrafficLight light, double currentTime) { @@ -326,8 +330,8 @@ public class IntersectionProcess { * Agenda a travessia e partida de um veículo. * Cria um evento de fim de travessia agendado para o tempo correto. * - * @param vehicle o veículo que vai atravessar - * @param startTime quando a travessia começa (segundos de simulação) + * @param vehicle o veículo que vai atravessar + * @param startTime quando a travessia começa (segundos de simulação) * @param crossingDuration quanto tempo demora a atravessar (segundos) */ private void scheduleVehicleCrossing(Vehicle vehicle, double startTime, double crossingDuration) { diff --git a/main/src/main/java/sd/analysis/MultiRunAnalyzer.java b/main/src/main/java/sd/analysis/MultiRunAnalyzer.java index 4ff9ebb..02c3307 100644 --- a/main/src/main/java/sd/analysis/MultiRunAnalyzer.java +++ b/main/src/main/java/sd/analysis/MultiRunAnalyzer.java @@ -14,36 +14,61 @@ import java.util.TreeSet; import sd.model.VehicleType; /** - * Executes multiple simulation runs and aggregates results. - * Calculates statistical measures including mean, standard deviation, - * and confidence intervals across all runs. + * Responsável pela agregação e análise estatística de múltiplas execuções da simulação. + *
+ * Esta classe coleta resultados individuais ({@link SimulationRunResult}) e calcula
+ * métricas consolidadas, incluindo média, desvio padrão, mediana e intervalos de
+ * confiança de 95%. O objetivo é fornecer uma visão robusta do comportamento do
+ * sistema, mitigando a variância estocástica de execuções isoladas.
*/
public class MultiRunAnalyzer {
+ /** Lista acumulada de resultados de execuções individuais. */
private final List
+ * O relatório inclui:
+ *
+ * Calcula média, desvio padrão, mediana, intervalo de confiança (95%) e extremos (min/max).
+ *
+ * @param metricName O nome descritivo da métrica (ex: "Tempo de Espera").
+ * @param values A lista de valores numéricos brutos extraídos das execuções.
+ * @return Uma string formatada com os dados estatísticos.
*/
private String analyzeMetric(String metricName, List
+ * Utilizado internamente para transformar a lista de objetos complexos {@link SimulationRunResult}
+ * em listas simples de Doubles para processamento estatístico.
+ *
+ * @param extractor Função lambda que define qual campo extrair de cada resultado.
+ * @return Lista de valores double correspondentes.
*/
private List
+ * Este método atua como um wrapper para {@link #saveCSVSummary(String)}.
+ *
+ * @param filename O caminho do ficheiro CSV de destino.
+ * @throws IOException Se ocorrer um erro de escrita no disco.
*/
public void saveCSV(String filename) throws IOException {
saveCSVSummary(filename);
}
/**
- * Generates a CSV summary for easy import into spreadsheet tools.
+ * Gera e grava o sumário CSV detalhado com métricas chave por execução.
+ *
+ * Colunas incluídas: Execução, VeículosGerados, VeículosCompletados, TaxaConclusão,
+ * TempoMédioSistema, TempoMédioEspera, TempoMínimoSistema, TempoMáximoSistema.
+ *
+ * @param filename O caminho do ficheiro CSV de destino.
+ * @throws IOException Se ocorrer um erro de escrita no disco.
*/
public void saveCSVSummary(String filename) throws IOException {
try (PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(filename)))) {
@@ -231,4 +282,4 @@ public class MultiRunAnalyzer {
}
}
}
-}
+}
\ No newline at end of file
diff --git a/main/src/main/java/sd/analysis/SimulationBatchRunner.java b/main/src/main/java/sd/analysis/SimulationBatchRunner.java
deleted file mode 100644
index 7dd9547..0000000
--- a/main/src/main/java/sd/analysis/SimulationBatchRunner.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package sd.analysis;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-/**
- * Orquestra múltiplas execuções de simulação para análise estatística.
- *
- * Em vez de correr uma única simulação manualmente, esta ferramenta permite
- * correr um "lote"
- * de N simulações consecutivas. Isto é essencial para recolher dados
- * estatisticamente significativos
- * (calcular intervalos de confiança, etc.) conforme exigido pelas
- * especificações do projeto.
- *
- * Utilização:
- * java sd.analysis.SimulationBatchRunner
+ * Esta classe atua como um registo estruturado de métricas de desempenho, armazenando
+ * dados de latência (tempos de sistema/espera), vazão (throughput) e ocupação de recursos
+ * (tamanhos de fila). Os dados aqui contidos servem como base para a análise
+ * estatística agregada realizada pelo {@link MultiRunAnalyzer}.
*/
public class SimulationRunResult {
@@ -17,11 +21,22 @@ public class SimulationRunResult {
private final long endTimeMillis;
// Global metrics
+ /** Total de veículos instanciados pelos geradores durante a execução. */
private int totalVehiclesGenerated;
+
+ /** Total de veículos que completaram o percurso e saíram do sistema com sucesso. */
private int totalVehiclesCompleted;
+
+ /** Média global do tempo total (em segundos) desde a geração até a saída. */
private double averageSystemTime; // seconds
+
+ /** Menor tempo de sistema registado (em segundos). */
private double minSystemTime; // seconds
+
+ /** Maior tempo de sistema registado (em segundos). */
private double maxSystemTime; // seconds
+
+ /** Média global do tempo (em segundos) que os veículos passaram parados em filas. */
private double averageWaitingTime; // seconds
// Per-type metrics
@@ -34,6 +49,12 @@ public class SimulationRunResult {
private final Map
+ * Esta classe fornece algoritmos para cálculo de medidas de tendência central (média, mediana),
+ * dispersão (desvio padrão amostral) e inferência estatística (Intervalos de Confiança).
+ * É utilizada para normalizar e validar os resultados estocásticos obtidos através de
+ * múltiplas execuções do sistema.
*/
public class StatisticalAnalysis {
/**
- * Calculates the mean (average) of a list of values.
+ * Calcula a média aritmética de um conjunto de valores.
+ * * @param values Lista de valores numéricos (double).
+ * @return A soma dos valores dividida pelo tamanho da amostra, ou 0.0 se a lista for nula/vazia.
*/
public static double mean(List
+ * Utiliza o denominador {@code n - 1} (Correção de Bessel) para fornecer um
+ * estimador não viesado da variância populacional, adequado para as amostras
+ * de simulação.
+ * * @param values Lista de observações.
+ * @return O desvio padrão calculado, ou 0.0 se o tamanho da amostra for < 2.
*/
public static double standardDeviation(List
+ * Utiliza a distribuição t de Student para maior precisão em amostras pequenas (n < 30),
+ * onde a aproximação pela distribuição Normal (Z) seria inadequada. O intervalo define
+ * a faixa onde a verdadeira média populacional reside com 95% de probabilidade.
+ * * @param values Lista de observações.
+ * @return Um array de double onde índice 0 é o limite inferior e índice 1 é o limite superior.
*/
public static double[] confidenceInterval95(List
+ * Baseia-se nos graus de liberdade (gl = n - 1). Para amostras grandes (gl >= 30),
+ * aproxima-se do valor Z de 1.96.
+ * * @param sampleSize O tamanho da amostra (n).
+ * @return O fator multiplicativo t apropriado.
*/
private static double getTCriticalValue(int sampleSize) {
int df = sampleSize - 1; // degrees of freedom
@@ -94,7 +113,9 @@ public class StatisticalAnalysis {
}
/**
- * Calculates the minimum value.
+ * Identifica o valor mínimo absoluto na amostra.
+ * * @param values Lista de valores.
+ * @return O menor valor encontrado.
*/
public static double min(List
+ * Nota de Desempenho: Este método ordena uma cópia da lista, resultando em
+ * complexidade O(n log n).
+ * * @param values Lista de valores.
+ * @return O valor central (ou média dos dois centrais) da distribuição ordenada.
*/
public static double median(List
+ * Útil para logging e geração de relatórios textuais.
+ * * @param metricName Nome da métrica a ser exibida.
+ * @param values Os dados brutos associados à métrica.
+ * @return String formatada contendo Média, Desvio Padrão, IC95%, Min, Max e N.
*/
public static String formatSummary(String metricName, List Lê propriedades de um ficheiro .properties e fornece getters
- * type-safe com valores padrão para robustez.
+ * Responsável pelo carregamento, validação e acesso centralizado às configurações da simulação.
+ *
+ * Esta classe atua como uma fachada (Facade) para os parâmetros do sistema, abstraindo a origem
+ * dos dados (ficheiros {@code .properties} ou JSON). Implementa uma estratégia robusta de
+ * carregamento de recursos, suportando tanto caminhos absolutos do sistema de ficheiros quanto
+ * recursos embutidos no classpath.
+ *
+ * Além de propriedades chave-valor simples, gerencia a desserialização da topologia da rede
+ * através da classe interna {@link NetworkConfig}.
*/
public class SimulationConfig {
- /** Propriedades carregadas do ficheiro */
+ /** Armazenamento em memória das propriedades chave-valor carregadas. */
private final Properties properties;
+
+ /** Estrutura hierárquica da configuração da rede carregada via JSON. */
private NetworkConfig networkConfig;
+ /**
+ * Objeto de transferência de dados (DTO) que representa a configuração global da rede.
+ * Mapeado a partir do ficheiro {@code network_config.json}.
+ */
public static class NetworkConfig {
private List Tenta múltiplas estratégias:
+ * Inicializa o gestor de configuração carregando propriedades do caminho especificado.
+ * * Implementa uma estratégia de carregamento em cascata (fallback) para garantir robustez
+ * em diferentes ambientes de execução (IDE, JAR, Docker):
*
+ * Utiliza a biblioteca Gson para desserialização. Em caso de falha, emite um aviso para o
+ * {@code System.err} mas não aborta a execução, permitindo o uso de defaults ou redes vazias.
+ */
private void loadNetworkConfig() {
try (InputStream is = getClass().getClassLoader().getResourceAsStream("network_config.json")) {
if (is == null) {
@@ -151,6 +177,10 @@ public class SimulationConfig {
}
}
+ /**
+ * Retorna a configuração estruturada da rede.
+ * @return Objeto {@link NetworkConfig} ou null se o carregamento falhou.
+ */
public NetworkConfig getNetworkConfig() {
return networkConfig;
}
@@ -158,56 +188,50 @@ public class SimulationConfig {
// --- Network configurations ---
/**
- * Gets the host address for a specific intersection.
- *
- * @param intersectionId The ID of the intersection (e.g., "Cr1").
- * @return The host (e.g., "localhost").
+ * Obtém o endereço de host (nome DNS ou IP) para uma interseção específica.
+ * * @param intersectionId O ID da interseção (ex: "Cr1").
+ * @return O host configurado ou "localhost" por omissão.
*/
public String getIntersectionHost(String intersectionId) {
return properties.getProperty("intersection." + intersectionId + ".host", "localhost");
}
/**
- * Gets the port number for a specific intersection.
- *
- * @param intersectionId The ID of the intersection (e.g., "Cr1").
- * @return The port number.
+ * Obtém a porta de escuta TCP para uma interseção específica.
+ * * @param intersectionId O ID da interseção (ex: "Cr1").
+ * @return O número da porta. Retorna 0 se não configurado.
*/
public int getIntersectionPort(String intersectionId) {
return Integer.parseInt(properties.getProperty("intersection." + intersectionId + ".port", "0"));
}
/**
- * Gets the host address for the dashboard server.
- *
- * @return The dashboard host.
+ * Obtém o endereço de host do servidor de Dashboard (monitorização).
+ * @return O host do dashboard (padrão: "localhost").
*/
public String getDashboardHost() {
return properties.getProperty("dashboard.host", "localhost");
}
/**
- * Gets the port number for the dashboard server.
- *
- * @return The dashboard port.
+ * Obtém a porta de conexão do servidor de Dashboard.
+ * @return A porta do dashboard (padrão: 9000).
*/
public int getDashboardPort() {
return Integer.parseInt(properties.getProperty("dashboard.port", "9000"));
}
/**
- * Gets the host address for the exit node.
- *
- * @return The exit node host.
+ * Obtém o endereço de host do nó de saída (Exit Node), para onde os veículos são encaminhados ao sair da malha.
+ * @return O host do nó de saída (padrão: "localhost").
*/
public String getExitHost() {
return properties.getProperty("exit.host", "localhost");
}
/**
- * Gets the port number for the exit node.
- *
- * @return The exit node port.
+ * Obtém a porta de conexão do nó de saída.
+ * @return A porta do nó de saída (padrão: 9001).
*/
public int getExitPort() {
return Integer.parseInt(properties.getProperty("exit.port", "9001"));
@@ -216,64 +240,64 @@ public class SimulationConfig {
// --- Simulation configurations ---
/**
- * Gets the total duration of the simulation in virtual seconds.
- *
- * @return The simulation duration.
+ * Define a duração total da execução da simulação em segundos virtuais.
+ * @return A duração em segundos (padrão: 3600).
*/
public double getSimulationDuration() {
return Double.parseDouble(properties.getProperty("simulation.duration", "3600"));
}
/**
- * Get time scaling factor for visualization.
- * 0 = instant (pure DES), 0.01 = 100x speed, 0.1 = 10x speed, 1.0 = real-time
+ * Obtém o fator de escala temporal para visualização/execução.
+ *
+ * Este é o período adicional executado após o fim da geração de veículos para permitir
+ * que os veículos restantes no sistema completem os seus percursos.
+ * @return O tempo de drenagem (padrão: 60.0s).
*/
public double getDrainTime() {
return Double.parseDouble(properties.getProperty("simulation.drain.time", "60.0"));
}
/**
- * Gets the vehicle arrival model ("POISSON" or "FIXED").
- *
- * @return The arrival model as a string.
+ * Determina o modelo estocástico utilizado para a chegada de veículos.
+ * @return "POISSON" (distribuição exponencial) ou "FIXED" (intervalo determinístico).
*/
public String getArrivalModel() {
return properties.getProperty("simulation.arrival.model", "POISSON");
}
/**
- * Gets the average arrival rate (lambda) for the POISSON model.
- * This represents the average number of vehicles arriving per second.
- *
- * @return The arrival rate.
+ * Obtém a taxa média de chegada (lambda) para o modelo Poisson.
+ * @return Veículos por segundo (padrão: 0.5).
*/
public double getArrivalRate() {
return Double.parseDouble(properties.getProperty("simulation.arrival.rate", "0.5"));
}
/**
- * Gets the fixed time interval between vehicle arrivals for the FIXED model.
- *
- * @return The fixed interval in seconds.
+ * Obtém o intervalo fixo entre chegadas para o modelo determinístico.
+ * @return O intervalo em segundos (padrão: 2.0).
*/
public double getFixedArrivalInterval() {
return Double.parseDouble(properties.getProperty("simulation.arrival.fixed.interval", "2.0"));
}
/**
- * Gets the routing policy to use for vehicle route selection.
- *
- * @return The routing policy (RANDOM, SHORTEST_PATH, or LEAST_CONGESTED).
+ * Obtém a política de roteamento utilizada pelos veículos para navegar na malha.
+ * @return A política: "RANDOM", "SHORTEST_PATH" ou "LEAST_CONGESTED".
*/
public String getRoutingPolicy() {
return properties.getProperty("simulation.routing.policy", "RANDOM");
@@ -282,11 +306,10 @@ public class SimulationConfig {
// --- Traffic light configurations ---
/**
- * Gets the duration of the GREEN light state for a specific traffic light.
- *
- * @param intersectionId The ID of the intersection (e.g., "Cr1").
- * @param direction The direction of the light (e.g., "North").
- * @return The green light time in seconds.
+ * Obtém a duração do estado VERDE para um semáforo específico.
+ * * @param intersectionId ID da interseção.
+ * @param direction Direção do fluxo (ex: "North").
+ * @return Duração em segundos (padrão: 30.0).
*/
public double getTrafficLightGreenTime(String intersectionId, String direction) {
String key = "trafficlight." + intersectionId + "." + direction + ".green";
@@ -294,11 +317,10 @@ public class SimulationConfig {
}
/**
- * Gets the duration of the RED light state for a specific traffic light.
- *
- * @param intersectionId The ID of the intersection (e.g., "Cr1").
- * @param direction The direction of the light (e.g., "North").
- * @return The red light time in seconds.
+ * Obtém a duração do estado VERMELHO para um semáforo específico.
+ * * @param intersectionId ID da interseção.
+ * @param direction Direção do fluxo.
+ * @return Duração em segundos (padrão: 30.0).
*/
public double getTrafficLightRedTime(String intersectionId, String direction) {
String key = "trafficlight." + intersectionId + "." + direction + ".red";
@@ -308,83 +330,74 @@ public class SimulationConfig {
// --- Vehicle configurations ---
/**
- * Gets the probability (0.0 to 1.0) that a generated vehicle is of type LIGHT.
- *
- * @return The probability for LIGHT vehicles.
+ * Probabilidade (0.0 a 1.0) de geração de um veículo do tipo LIGEIRO (LIGHT).
+ * @return Probabilidade (padrão: 0.7).
*/
public double getLightVehicleProbability() {
return Double.parseDouble(properties.getProperty("vehicle.probability.light", "0.7"));
}
/**
- * Gets the average time it takes a LIGHT vehicle to cross an intersection.
- *
- * @return The crossing time in seconds.
+ * Tempo médio necessário para um veículo LIGEIRO atravessar uma interseção.
+ * @return Tempo em segundos (padrão: 2.0).
*/
public double getLightVehicleCrossingTime() {
return Double.parseDouble(properties.getProperty("vehicle.crossing.time.light", "2.0"));
}
/**
- * Gets the probability (0.0 to 1.0) that a generated vehicle is of type BIKE.
- *
- * @return The probability for BIKE vehicles.
+ * Probabilidade (0.0 a 1.0) de geração de um veículo do tipo BICICLETA (BIKE).
+ * @return Probabilidade (padrão: 0.0).
*/
public double getBikeVehicleProbability() {
return Double.parseDouble(properties.getProperty("vehicle.probability.bike", "0.0"));
}
/**
- * Gets the average time it takes a BIKE vehicle to cross an intersection.
- *
- * @return The crossing time in seconds.
+ * Tempo médio necessário para uma BICICLETA atravessar uma interseção.
+ * @return Tempo em segundos (padrão: 1.5).
*/
public double getBikeVehicleCrossingTime() {
return Double.parseDouble(properties.getProperty("vehicle.crossing.time.bike", "1.5"));
}
/**
- * Gets the probability (0.0 to 1.0) that a generated vehicle is of type HEAVY.
- *
- * @return The probability for HEAVY vehicles.
+ * Probabilidade (0.0 a 1.0) de geração de um veículo PESADO (HEAVY).
+ * @return Probabilidade (padrão: 0.0).
*/
public double getHeavyVehicleProbability() {
return Double.parseDouble(properties.getProperty("vehicle.probability.heavy", "0.0"));
}
/**
- * Gets the average time it takes a HEAVY vehicle to cross an intersection.
- *
- * @return The crossing time in seconds.
+ * Tempo médio necessário para um veículo PESADO atravessar uma interseção.
+ * @return Tempo em segundos (padrão: 4.0).
*/
public double getHeavyVehicleCrossingTime() {
return Double.parseDouble(properties.getProperty("vehicle.crossing.time.heavy", "4.0"));
}
/**
- * Gets the base travel time between intersections for light vehicles.
- *
- * @return The base travel time in seconds.
+ * Define o tempo base de viagem entre interseções para veículos padrão.
+ * @return Tempo em segundos (padrão: 8.0).
*/
public double getBaseTravelTime() {
return Double.parseDouble(properties.getProperty("vehicle.travel.time.base", "8.0"));
}
/**
- * Gets the travel time multiplier for bike vehicles.
- * Bike travel time = base time × this multiplier.
- *
- * @return The multiplier for bike travel time.
+ * Multiplicador de tempo de viagem para bicicletas.
+ * Tempo efetivo = Base * Multiplicador.
+ * @return Fator multiplicativo (padrão: 0.5).
*/
public double getBikeTravelTimeMultiplier() {
return Double.parseDouble(properties.getProperty("vehicle.travel.time.bike.multiplier", "0.5"));
}
/**
- * Gets the travel time multiplier for heavy vehicles.
- * Heavy vehicle travel time = base time × this multiplier.
- *
- * @return The multiplier for heavy vehicle travel time.
+ * Multiplicador de tempo de viagem para veículos pesados.
+ * Tempo efetivo = Base * Multiplicador.
+ * @return Fator multiplicativo (padrão: 4.0).
*/
public double getHeavyTravelTimeMultiplier() {
return Double.parseDouble(properties.getProperty("vehicle.travel.time.heavy.multiplier", "4.0"));
@@ -393,9 +406,8 @@ public class SimulationConfig {
// --- Statistics ---
/**
- * Gets the interval (in virtual seconds) between periodic statistics updates.
- *
- * @return The statistics update interval.
+ * Intervalo de tempo (em segundos virtuais) para agregação e envio de estatísticas periódicas.
+ * @return Intervalo de atualização (padrão: 1.0).
*/
public double getStatisticsUpdateInterval() {
return Double.parseDouble(properties.getProperty("statistics.update.interval", "1.0"));
@@ -404,21 +416,19 @@ public class SimulationConfig {
// --- Generic getters ---
/**
- * Generic method to get any property as a string, with a default value.
- *
- * @param key The property key.
- * @param defaultValue The value to return if the key is not found.
- * @return The property value or the default.
+ * Recupera uma propriedade genérica como String, com valor padrão de segurança.
+ * * @param key A chave da propriedade.
+ * @param defaultValue O valor a retornar caso a chave não exista.
+ * @return O valor da propriedade ou o default.
*/
public String getProperty(String key, String defaultValue) {
return properties.getProperty(key, defaultValue);
}
/**
- * Generic method to get any property as a string.
- *
- * @param key The property key.
- * @return The property value, or null if not found.
+ * Recupera uma propriedade genérica como String.
+ * * @param key A chave da propriedade.
+ * @return O valor da propriedade ou null se não encontrada.
*/
public String getProperty(String key) {
return properties.getProperty(key);
diff --git a/main/src/main/java/sd/coordinator/CoordinatorProcess.java b/main/src/main/java/sd/coordinator/CoordinatorProcess.java
index 61024bc..dd9135e 100644
--- a/main/src/main/java/sd/coordinator/CoordinatorProcess.java
+++ b/main/src/main/java/sd/coordinator/CoordinatorProcess.java
@@ -24,47 +24,53 @@ import sd.serialization.SerializationException;
import sd.util.VehicleGenerator;
/**
- * Coordenador central da simulação distribuída.
- *
- * Responsabilidades:
+ * Coordenador central da arquitetura de simulação distribuída.
+ *
+ * Este processo atua como o "cérebro" da simulação, sendo responsável por:
* Usa motor DES para agendar eventos de geração com precisão.
- * Mantém fila de prioridade e processa eventos em ordem cronológica.
*/
public class CoordinatorProcess {
private final SimulationConfig config;
private final VehicleGenerator vehicleGenerator;
+
+ /** Mapa de clientes TCP persistentes para cada interseção (Worker Nodes). */
private final Map This approximation tracks queue sizes by incrementing when vehicles are sent
- * to intersections. While not perfectly accurate (doesn't track departures in real-time),
- * it provides useful congestion information for the LEAST_CONGESTED routing policy. This is a practical solution that enables dynamic routing without requiring
- * bidirectional communication or complex state synchronization.
+ * Utilizado exclusivamente pela política {@link LeastCongestedRouteSelector}.
+ * O coordenador incrementa este contador ao enviar um veículo para uma interseção.
+ * Nota: Esta é uma visão "borda" (edge) e pode não refletir a saída em tempo real
+ * dos veículos, mas serve como heurística suficiente para balanceamento de carga.
*/
private final Map
+ * Executa a sequência:
+ * 1. Retira o próximo evento da fila prioritária.
+ * 2. Avança o relógio virtual para o timestamp do evento.
+ * 3. Aplica escala temporal (Time Scale) para visualização, se necessário.
+ * 4. Processa o evento.
+ */
public void run() {
double duration = config.getSimulationDuration();
double drainTime = config.getDrainTime();
@@ -264,14 +288,9 @@ public class CoordinatorProcess {
}
/**
- * Trata um único evento de simulação.
- *
- * É aqui que a magia acontece. Dependendo do tipo de evento (como
- * VEHICLE_GENERATION),
- * atualizamos o estado do mundo. Para a geração de veículos, criamos um novo
- * veículo,
- * enviamo-lo para uma interseção e depois agendamos o *próximo* evento de
- * geração.
+ * Trata o processamento de um evento DES retirado da fila.
+ * * @param event O evento a ser processado.
+ * @param generationDuration Duração da fase de geração ativa (antes do 'drain time').
*/
private void processEvent(SimulationEvent event, double generationDuration) {
double currentTime = clock.getCurrentTime();
@@ -285,7 +304,7 @@ public class CoordinatorProcess {
generateAndSendVehicle();
- // Schedule next vehicle generation
+ // Schedule next vehicle generation (Recursive scheduling)
double nextArrivalTime = vehicleGenerator.getNextArrivalTime(currentTime);
eventQueue.schedule(new SimulationEvent(
nextArrivalTime,
@@ -309,9 +328,8 @@ public class CoordinatorProcess {
}
/**
- * Guarda o histórico completo de eventos de simulação num ficheiro de texto.
- * Isto permite-nos auditar exatamente o que aconteceu e quando, o que é crucial
- * para depuração e verificação.
+ * Exporta o log completo de eventos DES para auditoria e debug.
+ * Caminho: {@code logs/coordinator-event-history.txt}.
*/
private void exportEventHistory() {
try (java.io.PrintWriter writer = new java.io.PrintWriter(
@@ -324,6 +342,10 @@ public class CoordinatorProcess {
}
}
+ /**
+ * Gera um novo veículo e envia-o via TCP para a interseção de entrada apropriada.
+ * Também atualiza o rastreio local de filas para balanceamento de carga.
+ */
private void generateAndSendVehicle() {
double currentTime = clock.getCurrentTime();
@@ -355,6 +377,9 @@ public class CoordinatorProcess {
sendVehicleToIntersection(vehicle, entryIntersection);
}
+ /**
+ * Serializa e transmite o objeto Veículo para o nó (interseção) de destino.
+ */
private void sendVehicleToIntersection(Vehicle vehicle, String intersectionId) {
SocketClient client = intersectionClients.get(intersectionId);
@@ -379,6 +404,9 @@ public class CoordinatorProcess {
}
}
+ /**
+ * Encerra graciosamente a simulação, enviando sinais de SHUTDOWN para todos os nós.
+ */
public void shutdown() {
System.out.println();
System.out.println("=".repeat(60));
@@ -415,10 +443,9 @@ public class CoordinatorProcess {
}
/**
- * Altera dinamicamente a política de roteamento durante a simulação.
- * Novos veículos gerados usarão a nova política.
- *
- * @param policyName nome da nova política (RANDOM, SHORTEST_PATH, LEAST_CONGESTED)
+ * Altera dinamicamente a política de roteamento durante a simulação (Hot-swap).
+ * Thread-safe.
+ * * @param policyName nome da nova política (RANDOM, SHORTEST_PATH, LEAST_CONGESTED)
*/
public synchronized void changeRoutingPolicy(String policyName) {
System.out.println("\n" + "=".repeat(60));
@@ -454,8 +481,8 @@ public class CoordinatorProcess {
}
/**
- * Verifica se há solicitação de mudança de política do dashboard
- * e aplica se houver.
+ * Verifica se há solicitação de mudança de política proveniente do dashboard
+ * e aplica a alteração se houver.
*/
private void checkForPolicyChanges() {
if (dashboardStatistics != null) {
@@ -467,8 +494,8 @@ public class CoordinatorProcess {
}
/**
- * Define a referência para as estatísticas do dashboard.
- * Permite que o coordenador verifique mudanças de política solicitadas.
+ * Injeta a referência para as estatísticas do dashboard.
+ * Permite que o coordenador consuma intenções de mudança de política do utilizador.
*/
public void setDashboardStatistics(DashboardStatistics stats) {
this.dashboardStatistics = stats;
@@ -512,6 +539,11 @@ public class CoordinatorProcess {
}
}
+ /**
+ * Sincronização Global: Envia o timestamp de início (System.currentTimeMillis)
+ * para todos os componentes distribuídos, garantindo uma base de tempo comum
+ * para métricas de latência.
+ */
private void sendSimulationStartTime() {
long startTimeMillis = System.currentTimeMillis();
@@ -543,4 +575,4 @@ public class CoordinatorProcess {
}
}
}
-}
+}
\ No newline at end of file
diff --git a/main/src/main/java/sd/coordinator/SocketClient.java b/main/src/main/java/sd/coordinator/SocketClient.java
index fcb59ec..4dafc48 100644
--- a/main/src/main/java/sd/coordinator/SocketClient.java
+++ b/main/src/main/java/sd/coordinator/SocketClient.java
@@ -10,10 +10,14 @@ import sd.serialization.SerializationException;
import sd.serialization.SerializerFactory;
/**
- * Cliente socket para comunicação com um processo de interseção.
- *
- * Gere uma ligação TCP persistente para uma interseção,
- * fornecendo uma forma simples de enviar mensagens serializadas.
+ * Esta classe encapsula a gestão do socket raw, oferecendo uma interface de alto nível
+ * para envio de objetos {@link Message}. Implementa o protocolo de camada de aplicação
+ * proprietário, garantindo a serialização correta e o enquadramento (framing) dos dados
+ * na stream TCP.
+ *
+ * É utilizada pelo Coordenador para controlar Interseções e enviar telemetria para o Dashboard.
*/
public class SocketClient {
@@ -25,11 +29,11 @@ public class SocketClient {
private MessageSerializer serializer;
/**
- * Cria um novo cliente socket para uma interseção.
+ * Instancia um novo cliente socket configurado para um destino específico.
*
- * @param intersectionId ID da interseção (ex: "Cr1")
- * @param host endereço do host (ex: "localhost")
- * @param port número da porta
+ * @param intersectionId Identificador lógico do nó de destino (ex: "Cr1", "Dashboard").
+ * @param host Endereço IP ou hostname do destino.
+ * @param port Porta TCP de escuta do destino.
*/
public SocketClient(String intersectionId, String host, int port) {
this.intersectionId = intersectionId;
@@ -39,9 +43,8 @@ public class SocketClient {
}
/**
- * Liga-se ao processo da interseção via TCP.
- *
- * @throws IOException se a ligação não puder ser estabelecida
+ * Estabelece a conexão TCP (Handshake SYN/ACK) com o host remoto.
+ * * @throws IOException Se o host for inalcançável ou a conexão for recusada.
*/
public void connect() throws IOException {
try {
@@ -55,12 +58,22 @@ public class SocketClient {
}
/**
- * Envia uma mensagem para a interseção ligada.
- * A mensagem é serializada e enviada pelo socket.
+ * Serializa e transmite uma mensagem através do socket conectado.
+ *
+ * Protocolo de Envio (Length-Prefix Framing):
+ *
+ * Operação idempotente: pode ser chamada múltiplas vezes sem erro.
*/
public void close() {
try {
@@ -104,7 +121,8 @@ public class SocketClient {
}
/**
- * @return true if connected and socket is open, false otherwise
+ * Verifica o estado atual da conexão.
+ * * @return true se o socket estiver instanciado, conectado e aberto; false caso contrário.
*/
public boolean isConnected() {
return socket != null && socket.isConnected() && !socket.isClosed();
@@ -119,4 +137,4 @@ public class SocketClient {
return String.format("SocketClient[intersection=%s, host=%s, port=%d, connected=%s]",
intersectionId, host, port, isConnected());
}
-}
+}
\ No newline at end of file
diff --git a/main/src/main/java/sd/dashboard/BatchAnalysisDialog.java b/main/src/main/java/sd/dashboard/BatchAnalysisDialog.java
index c7744e9..ebb9b0c 100644
--- a/main/src/main/java/sd/dashboard/BatchAnalysisDialog.java
+++ b/main/src/main/java/sd/dashboard/BatchAnalysisDialog.java
@@ -25,8 +25,17 @@ import sd.analysis.SimulationRunResult;
import sd.model.VehicleType;
/**
- * Dialog for running batch performance analysis.
- * Allows running multiple simulations automatically and generating statistical reports.
+ * Diálogo para configuração e execução de análise de desempenho em lote (Batch Processing).
+ *
+ * Esta classe fornece uma interface gráfica para automatizar múltiplas execuções da simulação
+ * sob diferentes cenários de carga. É responsável por:
+ *
+ * Esta classe apresenta um diálogo modal que permite ao operador sobrepor (override)
+ * as configurações estáticas carregadas do ficheiro {@code .properties} imediatamente
+ * antes da execução. Oferece controlo granular sobre:
+ *
+ * A interface é construída dinamicamente usando layouts JavaFX ({@link GridPane}, {@link VBox}).
+ * Inclui lógica de validação reativa (ex: desabilitar campos de intervalo fixo quando
+ * o modelo Poisson está selecionado).
+ * *
+
+[Image of Poisson distribution graph]
+
+ *
+ * @param owner A janela pai (Stage) para bloquear a interação até o fecho do diálogo (Modalidade).
+ * @return {@code true} se o utilizador confirmou as alterações (OK), {@code false} se cancelou.
*/
public static boolean showAdvancedConfig(Stage owner) {
Dialog
+ * Esta classe implementa o padrão Thread-per-Client. Cada instância executa numa
+ * thread separada, garantindo que a latência de rede ou o processamento de mensagens
+ * de um nó (Interseção/Coordenador) não bloqueie a receção de telemetria dos outros.
+ *
+ * As suas principais funções são:
+ *
+ * Estabelece o wrapper {@link SocketConnection}, entra num loop de leitura bloqueante
+ * e gere exceções de I/O. Garante o fecho limpo do socket em caso de desconexão ou erro.
+ */
@Override
public void run() {
String clientInfo = clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort();
@@ -61,6 +84,16 @@ public class DashboardClientHandler implements Runnable {
}
}
+ /**
+ * Valida e extrai os dados estatísticos da mensagem.
+ *
+ * Implementa uma lógica de correção de tipagem para payloads desserializados via Gson.
+ * Frequentemente, objetos genéricos são desserializados como {@code LinkedHashMap} em vez
+ * da classe alvo {@link StatsUpdatePayload}. Este método deteta essa situação e realiza
+ * uma conversão "round-trip" (Map -> JSON -> Object) para garantir a integridade dos dados.
+ *
+ * @param message A mensagem recebida da rede.
+ */
private void processMessage(MessageProtocol message) {
if (message.getType() != MessageType.STATS_UPDATE) {
System.out.println("[Handler] Ignoring non-statistics message type: " + message.getType());
@@ -78,6 +111,7 @@ public class DashboardClientHandler implements Runnable {
stats = (StatsUpdatePayload) payload;
} else if (payload instanceof java.util.Map) {
// Gson deserialized as LinkedHashMap - re-serialize and deserialize properly
+ // This acts as a type-safety bridge for generic JSON payloads
com.google.gson.Gson gson = new com.google.gson.Gson();
String json = gson.toJson(payload);
stats = gson.fromJson(json, StatsUpdatePayload.class);
@@ -90,6 +124,15 @@ public class DashboardClientHandler implements Runnable {
updateStatistics(senderId, stats);
}
+ /**
+ * Aplica os dados recebidos ao modelo global de estatísticas.
+ *
+ * Distingue entre atualizações incrementais (ex: contagem de veículos) e
+ * substituições de estado (ex: tempo total de sistema reportado pelo nó de saída).
+ *
+ * @param senderId Identificador do nó que enviou a atualização (ex: "Cr1", "ExitNode").
+ * @param stats O objeto DTO contendo as métricas normalizadas.
+ */
private void updateStatistics(String senderId, StatsUpdatePayload stats) {
if (stats.getTotalVehiclesGenerated() >= 0) {
statistics.updateVehiclesGenerated(stats.getTotalVehiclesGenerated());
@@ -134,4 +177,4 @@ public class DashboardClientHandler implements Runnable {
System.out.println("[Handler] Successfully updated statistics from: " + senderId);
}
-}
+}
\ No newline at end of file
diff --git a/main/src/main/java/sd/dashboard/DashboardServer.java b/main/src/main/java/sd/dashboard/DashboardServer.java
index 8807478..6f76a3b 100644
--- a/main/src/main/java/sd/dashboard/DashboardServer.java
+++ b/main/src/main/java/sd/dashboard/DashboardServer.java
@@ -10,17 +10,43 @@ import java.util.concurrent.atomic.AtomicBoolean;
import sd.config.SimulationConfig;
/**
- * Agrega e apresenta estatísticas em tempo real de todos os processos da simulação.
- * Usa um thread pool para gerir ligações concorrentes de clientes.
+ * Servidor central de agregação de telemetria e estatísticas.
+ *
+ * Este componente atua como o nó de monitorização do sistema distribuído.
+ * Implementa uma arquitetura de servidor concorrente utilizando um {@link ExecutorService}
+ * (Thread Pool) para gerir múltiplas conexões de entrada simultâneas provenientes
+ * das Interseções, Coordenador e Nó de Saída.
+ *
+ * Suporta dois modos de operação:
+ *
+ * Analisa os argumentos de linha de comando para determinar o modo de execução.
+ * Se a flag {@code --gui} ou {@code -g} estiver presente, inicia o subsistema JavaFX.
+ * Caso contrário, inicia o modo servidor de terminal padrão.
+ *
+ * @param args Argumentos de CLI (ex: caminho do config, flags de modo).
+ */
public static void main(String[] args) {
// Check if GUI mode is requested
boolean useGUI = false;
@@ -70,13 +96,24 @@ public class DashboardServer {
}
}
+ /**
+ * Inicializa a infraestrutura do servidor.
+ *
+ * @param config A configuração carregada contendo a porta de escuta.
+ */
public DashboardServer(SimulationConfig config) {
this.port = config.getDashboardPort();
this.statistics = new DashboardStatistics();
+ // Fixed pool limita o consumo de recursos, prevenindo exaustão sob carga alta
this.clientHandlerPool = Executors.newFixedThreadPool(10);
this.running = new AtomicBoolean(false);
}
+ /**
+ * Inicia a escuta por conexões (Bind & Listen) e a thread de despacho.
+ *
+ * @throws IOException Se a porta já estiver em uso ou ocorrer erro de bind.
+ */
public void start() throws IOException {
if (running.get()) {
System.out.println("Dashboard Server is already running.");
@@ -95,6 +132,13 @@ public class DashboardServer {
acceptThread.start();
}
+ /**
+ * Loop principal de aceitação de conexões (Dispatcher).
+ *
+ * Bloqueia em {@code accept()} até que uma nova conexão chegue, delegando
+ * imediatamente o processamento para um {@link DashboardClientHandler} gerido
+ * pelo Thread Pool.
+ */
private void acceptConnections() {
while (running.get()) {
try {
@@ -112,6 +156,10 @@ public class DashboardServer {
}
}
+ /**
+ * Ciclo de renderização de métricas para o modo CLI (Headless).
+ * Atualiza o ecrã a cada 5 segundos.
+ */
@SuppressWarnings("BusyWait")
private void displayLoop() {
final long DISPLAY_INTERVAL_MS = 5000;
@@ -127,6 +175,9 @@ public class DashboardServer {
}
}
+ /**
+ * Renderiza o snapshot atual das estatísticas no stdout.
+ */
public void displayStatistics() {
System.out.println("\n" + "=".repeat(60));
System.out.println("REAL-TIME SIMULATION STATISTICS");
@@ -135,6 +186,13 @@ public class DashboardServer {
System.out.println("=".repeat(60));
}
+ /**
+ * Procedimento de encerramento gracioso (Graceful Shutdown).
+ *
+ * 1. Altera flag de execução.
+ * 2. Fecha o socket do servidor para desbloquear a thread de aceitação.
+ * 3. Força o encerramento do pool de threads de clientes.
+ */
public void stop() {
if (!running.get()) {
return;
@@ -162,4 +220,4 @@ public class DashboardServer {
public boolean isRunning() {
return running.get();
}
-}
+}
\ No newline at end of file
diff --git a/main/src/main/java/sd/dashboard/DashboardStatistics.java b/main/src/main/java/sd/dashboard/DashboardStatistics.java
index aabcd5e..dd9f2f8 100644
--- a/main/src/main/java/sd/dashboard/DashboardStatistics.java
+++ b/main/src/main/java/sd/dashboard/DashboardStatistics.java
@@ -9,8 +9,13 @@ import java.util.concurrent.atomic.AtomicLong;
import sd.model.VehicleType;
/**
- * Armazenamento thread-safe de estatísticas agregadas da simulação.
- * Usa tipos atómicos e coleções concorrentes para atualizações sem locks.
+ * Repositório central de estado da simulação, desenhado para acesso concorrente de alta frequência.
+ *
+ * Esta classe atua como a "Single Source of Truth" para o Dashboard. Utiliza primitivas
+ * de concorrência do pacote {@code java.util.concurrent} (como {@link AtomicInteger} e
+ * {@link ConcurrentHashMap}) para permitir leituras e escritas simultâneas sem a necessidade
+ * de bloqueios explícitos (Lock-Free), minimizando a latência de processamento das mensagens
+ * recebidas dos múltiplos nós da rede.
*/
public class DashboardStatistics {
@@ -19,13 +24,21 @@ public class DashboardStatistics {
private final AtomicLong totalSystemTime;
private final AtomicLong totalWaitingTime;
+ /** Mapa thread-safe para armazenar métricas granulares por interseção. */
private final Map
+ * Utiliza {@link Map#compute} para garantir que a criação do objeto {@link IntersectionStats}
+ * seja thread-safe sem necessidade de blocos synchronized externos.
+ *
+ * @param intersectionId ID da interseção.
+ * @param arrivals Total acumulado de chegadas.
+ * @param departures Total acumulado de partidas.
+ * @param currentQueueSize Tamanho instantâneo da fila.
+ */
public void updateIntersectionStats(String intersectionId, int arrivals,
int departures, int currentQueueSize) {
intersectionStats.compute(intersectionId, (id, stats) -> {
@@ -111,6 +135,8 @@ public class DashboardStatistics {
lastUpdateTime = System.currentTimeMillis();
}
+ // --- Getters e Métricas Calculadas ---
+
public int getTotalVehiclesGenerated() {
return totalVehiclesGenerated.get();
}
@@ -119,12 +145,20 @@ public class DashboardStatistics {
return totalVehiclesCompleted.get();
}
+ /**
+ * Calcula o tempo médio no sistema em tempo real.
+ * @return Média em milissegundos (0.0 se nenhum veículo completou).
+ */
public double getAverageSystemTime() {
int completed = totalVehiclesCompleted.get();
if (completed == 0) return 0.0;
return (double) totalSystemTime.get() / completed;
}
+ /**
+ * Calcula o tempo médio de espera em tempo real.
+ * @return Média em milissegundos (0.0 se nenhum veículo completou).
+ */
public double getAverageWaitingTime() {
int completed = totalVehiclesCompleted.get();
if (completed == 0) return 0.0;
@@ -154,10 +188,11 @@ public class DashboardStatistics {
}
/**
- * Obtém os tamanhos atuais das filas de todas as interseções.
- * Usado pela política LEAST_CONGESTED para roteamento dinâmico.
- *
- * @return mapa com intersectionId -> queueSize
+ * Obtém um snapshot dos tamanhos atuais das filas de todas as interseções.
+ *
+ * Utilizado primariamente pelo algoritmo de roteamento dinâmico (LEAST_CONGESTED)
+ * para tomar decisões de encaminhamento baseadas na carga atual da rede.
+ * * @return Mapa contendo {@code intersectionId -> queueSize}.
*/
public Map No DES, o tempo avança em saltos discretos de evento para evento,
- * não de forma contínua como o tempo real.
+ * No DES, o tempo avança em saltos discretos de evento para evento,
+ * não de forma contínua como o tempo real.
+ * Esta classe garante que todos os processos no sistema distribuído
- * mantêm uma visão sincronizada do tempo de simulação.
+ * Esta classe garante que todos os processos no sistema distribuído
+ * mantêm uma visão sincronizada do tempo de simulação.
+ * Cria ficheiros de trace detalhados com:
+ *
+ * Cria ficheiros de trace detalhados com:
* Esta classe é o "gémeo digital" de um carro, mota ou camião.
- * Mantém toda a informação necessária:
+ * Esta classe é o "gémeo digital" de um carro, mota ou camião.
+ * Mantém toda a informação necessária:
+ * O objeto é serializado e enviado pela rede à medida que o veículo
- * se move entre processos distribuídos.
+ * O objeto é serializado e enviado pela rede à medida que o veículo
+ * se move entre processos distribuídos.
+ *
+ *
+ *
+ * @return Uma String contendo o relatório completo formatado.
*/
public String generateReport() {
if (results.isEmpty()) {
@@ -153,7 +178,13 @@ public class MultiRunAnalyzer {
}
/**
- * Analyzes a single metric and returns formatted statistics.
+ * Analisa uma métrica específica e retorna as estatísticas formatadas.
+ *
- *
*
- * @param filePath caminho do ficheiro .properties
- * @throws IOException se o ficheiro não for encontrado
+ * @param filePath O caminho ou nome do recurso do ficheiro {@code .properties}.
+ * @throws IOException Se o ficheiro não puder ser localizado em nenhuma das estratégias,
+ * com uma mensagem detalhada das tentativas falhadas.
*/
public SimulationConfig(String filePath) throws IOException {
properties = new Properties();
@@ -135,6 +155,12 @@ public class SimulationConfig {
throw new IOException(errorMsg.toString(), fileSystemException);
}
+ /**
+ * Carrega a configuração da topologia de rede a partir do ficheiro "network_config.json".
+ *
+ *
+ * @return O fator de escala.
*/
public double getTimeScale() {
return Double.parseDouble(properties.getProperty("simulation.time.scale", "0"));
}
/**
- * Gets the drain time (in virtual seconds) to allow vehicles to exit after
- * generation stops.
- *
- * @return The drain time.
+ * Obtém o tempo de "drenagem" (drain time) em segundos virtuais.
+ *
- *
- *
- *
+ *
+ * Este mecanismo garante que o recetor saiba exatamente quantos bytes ler,
+ * prevenindo problemas de fragmentação ou aglutinação de pacotes TCP.
*
- * @param message mensagem a enviar
- * @throws SerializationException se a serialização falhar
- * @throws IOException se a escrita no socket falhar
+ * @param message O objeto de domínio a ser enviado.
+ * @throws SerializationException Se o objeto não puder ser convertido para bytes.
+ * @throws IOException Se houver falha na escrita do socket (ex: conexão resetada).
*/
public void send(Message message) throws SerializationException, IOException {
if (socket == null || socket.isClosed()) {
@@ -71,11 +84,13 @@ public class SocketClient {
byte[] data = serializer.serialize(message);
int length = data.length;
+ // Write 4-byte length header (Big Endian)
outputStream.write((length >> 24) & 0xFF);
outputStream.write((length >> 16) & 0xFF);
outputStream.write((length >> 8) & 0xFF);
outputStream.write(length & 0xFF);
+ // Write payload
outputStream.write(data);
outputStream.flush();
@@ -86,8 +101,10 @@ public class SocketClient {
}
/**
- * Closes the socket connection safely.
- * Calling it multiple times won’t cause issues.
+ * Realiza o encerramento gracioso (graceful shutdown) da conexão.
+ * Liberta os recursos do sistema operativo (descritores de arquivo).
+ *
+ *
+ * A execução ocorre numa thread separada (background) para manter a responsividade da UI.
*/
public class BatchAnalysisDialog {
@@ -38,16 +47,17 @@ public class BatchAnalysisDialog {
private Button startButton;
private Button closeButton;
+ // Flags de controlo de concorrência
private volatile boolean isRunning = false;
private volatile boolean shouldStop = false;
+ /** Referência partilhada para capturar estatísticas em tempo real do Dashboard. */
private DashboardStatistics sharedStatistics;
/**
- * Shows the batch analysis dialog.
- *
- * @param owner parent window
- * @param statistics shared statistics object (optional, can be null)
+ * Exibe o diálogo de análise em lote.
+ * * @param owner A janela pai (Stage) para modalidade.
+ * @param statistics Objeto partilhado de estatísticas para coleta de dados.
*/
public static void show(Stage owner, DashboardStatistics statistics) {
BatchAnalysisDialog dialog = new BatchAnalysisDialog();
@@ -55,6 +65,9 @@ public class BatchAnalysisDialog {
dialog.createAndShow(owner);
}
+ /**
+ * Constrói e inicializa a interface gráfica do diálogo.
+ */
private void createAndShow(Stage owner) {
dialog = new Stage();
dialog.initOwner(owner);
@@ -64,37 +77,34 @@ public class BatchAnalysisDialog {
VBox root = new VBox(20);
root.setPadding(new Insets(20));
root.setAlignment(Pos.TOP_CENTER);
+ // Estilo Dark Mode conforme guidelines visuais
root.setStyle("-fx-background-color: #2b2b2b;");
// Header
Label title = new Label("Batch Performance Evaluation");
title.setStyle("-fx-font-size: 18px; -fx-font-weight: bold; -fx-text-fill: white;");
- Label subtitle = new Label("Run multiple simulations automatically to generate statistical analysis");
+ Label subtitle = new Label("Executar múltiplas simulações para gerar análise estatística consolidada");
subtitle.setStyle("-fx-font-size: 12px; -fx-text-fill: #cccccc;");
subtitle.setWrapText(true);
- // Configuration panel
+ // Painéis de Componentes
VBox configPanel = createConfigPanel();
-
- // Progress panel
VBox progressPanel = createProgressPanel();
-
- // Log area
VBox logPanel = createLogPanel();
-
- // Control buttons
HBox buttonBox = createButtonBox();
root.getChildren().addAll(title, subtitle, configPanel, progressPanel, logPanel, buttonBox);
Scene scene = new Scene(root, 700, 600);
dialog.setScene(scene);
+
+ // Tratamento de fecho da janela: interromper thread de worker se ativa
dialog.setOnCloseRequest(e -> {
if (isRunning) {
- e.consume();
+ e.consume(); // Previne fecho imediato
shouldStop = true;
- log("Stopping after current run completes...");
+ log("A parar após conclusão da execução atual...");
}
});
@@ -106,13 +116,13 @@ public class BatchAnalysisDialog {
panel.setPadding(new Insets(15));
panel.setStyle("-fx-background-color: rgba(255, 255, 255, 0.05); -fx-background-radius: 5;");
- Label header = new Label("Configuration");
+ Label header = new Label("Configuração");
header.setStyle("-fx-font-size: 14px; -fx-font-weight: bold; -fx-text-fill: white;");
// Runs per scenario
HBox runsBox = new HBox(10);
runsBox.setAlignment(Pos.CENTER_LEFT);
- Label runsLabel = new Label("Runs per scenario:");
+ Label runsLabel = new Label("Execuções por cenário:");
runsLabel.setStyle("-fx-text-fill: white; -fx-min-width: 150px;");
Spinner
+ *
*/
public class ConfigurationDialog {
/**
- * Mostra um diálogo com opções avançadas de configuração.
- *
- * @param owner janela pai
- * @return true se o utilizador confirmar, false se cancelar
+ * Exibe o diálogo de configuração avançada e captura as intenções do utilizador.
+ *
+ *
*/
public class DashboardClientHandler implements Runnable {
private final Socket clientSocket;
private final DashboardStatistics statistics;
+ /**
+ * Inicializa o handler com o socket ativo e a referência para o agregador de estatísticas.
+ *
+ * @param clientSocket O socket TCP conectado ao nó remoto.
+ * @param statistics O objeto singleton partilhado onde as métricas serão agregadas.
+ */
public DashboardClientHandler(Socket clientSocket, DashboardStatistics statistics) {
this.clientSocket = clientSocket;
this.statistics = statistics;
}
+ /**
+ * Ciclo de vida da conexão.
+ *
+ *
*/
public class DashboardServer {
private final int port;
+
+ /** Armazenamento em memória (Thread-safe) do estado global do sistema. */
private final DashboardStatistics statistics;
+
+ /** Pool de threads para isolamento de falhas e gestão de recursos de I/O. */
private final ExecutorService clientHandlerPool;
+
+ /** Flag atómica para controlo seguro do ciclo de vida do servidor. */
private final AtomicBoolean running;
+
private ServerSocket serverSocket;
+ /**
+ * Ponto de entrada (Bootstrap) da aplicação de monitorização.
+ *
*
*/
public class VehicleTracer {
-
+
private static VehicleTracer instance;
private static final Object instanceLock = new Object();
-
+
private final Map
- *
*
- *