From 3fe467a2a3d1dff7a2d5e3dd8848dd2f4e549bbc Mon Sep 17 00:00:00 2001 From: Gaa56 Date: Wed, 22 Oct 2025 19:19:28 +0100 Subject: [PATCH 01/18] Create MessageProtocol interface --- .../java/sd/protocol/MessageProtocol.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 main/src/main/java/sd/protocol/MessageProtocol.java diff --git a/main/src/main/java/sd/protocol/MessageProtocol.java b/main/src/main/java/sd/protocol/MessageProtocol.java new file mode 100644 index 0000000..9f20437 --- /dev/null +++ b/main/src/main/java/sd/protocol/MessageProtocol.java @@ -0,0 +1,44 @@ +package sd.protocol; + + + +import java.io.Serializable; + +import sd.model.MessageType; + +/** + * Interface que define o contrato para todas as mensagens trocadas no simulador. + * Garante que qualquer mensagem possa ser identificada e roteada. + * * Esta interface estende Serializable para permitir que os objetos que a implementam + * sejam enviados através de Sockets (ObjectOutputStream). + * + */ +public interface MessageProtocol extends Serializable { + + /** + * Retorna o tipo da mensagem, indicando o seu propósito. + * @return O MessageType (ex: VEHICLE_TRANSFER, STATS_UPDATE). + */ + MessageType getType(); + + /** + * Retorna o objeto de dados (carga útil) que esta mensagem transporta. + * O tipo de objeto dependerá do MessageType. + * * - Se getType() == VEHICLE_TRANSFER, o payload será um objeto {@link sd.model.Vehicle}. + * - Se getType() == STATS_UPDATE, o payload será um objeto de estatísticas. + * * @return O objeto de dados (payload), que também deve ser Serializable. + */ + Object getPayload(); + + /** + * Retorna o ID do nó (Processo) que enviou esta mensagem. + * @return String (ex: "Cr1", "Cr5", "S"). + */ + String getSourceNode(); + + /** + * Retorna o ID do nó (Processo) de destino desta mensagem. + * @return String (ex: "Cr2", "DashboardServer"). + */ + String getDestinationNode(); +} From 211ea25ca594089bea7afc54bdf7cbad8e6258da Mon Sep 17 00:00:00 2001 From: Leandro Afonso Date: Wed, 22 Oct 2025 23:36:41 +0100 Subject: [PATCH 02/18] Step 2 - Finishing touches --- .../main/java/sd/config/SimulationConfig.java | 2 +- .../main/java/sd/engine/SimulationEngine.java | 45 ++++++------------- main/src/test/java/SimulationTest.java | 2 +- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/main/src/main/java/sd/config/SimulationConfig.java b/main/src/main/java/sd/config/SimulationConfig.java index 4a3fe89..d11ed42 100644 --- a/main/src/main/java/sd/config/SimulationConfig.java +++ b/main/src/main/java/sd/config/SimulationConfig.java @@ -31,7 +31,7 @@ public class SimulationConfig { * (por exemplo quando executado a partir do classpath/jar), * faz fallback para carregar a partir do classpath usando o ClassLoader. */ - IOException lastException = null; + IOException lastException = null; //FIXME: melhorar esta parte para reportar erros de forma mais clara try { try (InputStream input = new FileInputStream(filePath)) { diff --git a/main/src/main/java/sd/engine/SimulationEngine.java b/main/src/main/java/sd/engine/SimulationEngine.java index 94793f7..484ae80 100644 --- a/main/src/main/java/sd/engine/SimulationEngine.java +++ b/main/src/main/java/sd/engine/SimulationEngine.java @@ -264,32 +264,19 @@ public class SimulationEngine { */ private void processEvent(Event event) { switch (event.getType()) { - case VEHICLE_GENERATION: - handleVehicleGeneration(); - break; + case VEHICLE_GENERATION -> handleVehicleGeneration(); - case VEHICLE_ARRIVAL: - handleVehicleArrival(event); - break; + case VEHICLE_ARRIVAL -> handleVehicleArrival(event); - case TRAFFIC_LIGHT_CHANGE: - handleTrafficLightChange(event); - break; + case TRAFFIC_LIGHT_CHANGE -> handleTrafficLightChange(event); - case CROSSING_START: - handleCrossingStart(event); - break; + case CROSSING_START -> handleCrossingStart(event); - case CROSSING_END: - handleCrossingEnd(event); - break; + case CROSSING_END -> handleCrossingEnd(event); - case STATISTICS_UPDATE: - handleStatisticsUpdate(); - break; + case STATISTICS_UPDATE -> handleStatisticsUpdate(); - default: - System.err.println("Unknown event type: " + event.getType()); + default -> System.err.println("Unknown event type: " + event.getType()); } } @@ -386,7 +373,7 @@ public class SimulationEngine { * @param vehicle The vehicle to process. * @param intersection The intersection where the vehicle is. */ - private void tryProcessVehicle(Vehicle vehicle, Intersection intersection) { + private void tryProcessVehicle(Vehicle vehicle, Intersection intersection) { //FIXME // Find the direction (and light) this vehicle is queued at // This logic is a bit flawed: it just finds the *first* non-empty queue // A better approach would be to get the light from the vehicle's route @@ -591,16 +578,12 @@ public class SimulationEngine { * @return The crossing time in seconds. */ private double getCrossingTime(VehicleType type) { - switch (type) { - case BIKE: - return config.getBikeVehicleCrossingTime(); - case LIGHT: - return config.getLightVehicleCrossingTime(); - case HEAVY: - return config.getHeavyVehicleCrossingTime(); - default: - return 2.0; // Default fallback - } + return switch (type) { + case BIKE -> config.getBikeVehicleCrossingTime(); + case LIGHT -> config.getLightVehicleCrossingTime(); + case HEAVY -> config.getHeavyVehicleCrossingTime(); + default -> 2.0; + }; // Default fallback } /** diff --git a/main/src/test/java/SimulationTest.java b/main/src/test/java/SimulationTest.java index 7172a1a..b3a49df 100644 --- a/main/src/test/java/SimulationTest.java +++ b/main/src/test/java/SimulationTest.java @@ -43,7 +43,7 @@ class SimulationTest { assertEquals("TEST1", vehicle.getId()); assertNotNull(vehicle.getType()); assertNotNull(vehicle.getRoute()); - assertTrue(vehicle.getRoute().size() > 0); + assertTrue(!vehicle.getRoute().isEmpty()); } @Test From 1216089e80782aa4ba0266c211f8c00ea064e5a0 Mon Sep 17 00:00:00 2001 From: Leandro Afonso Date: Wed, 22 Oct 2025 23:37:27 +0100 Subject: [PATCH 03/18] Step 2 - Finishing touches --- STEP2_SUMMARY.md | 134 +++++++++++++++++++++++++++++++++++++++++++++++ TODO.md | 23 ++++++++ 2 files changed, 157 insertions(+) create mode 100644 STEP2_SUMMARY.md diff --git a/STEP2_SUMMARY.md b/STEP2_SUMMARY.md new file mode 100644 index 0000000..b234c44 --- /dev/null +++ b/STEP2_SUMMARY.md @@ -0,0 +1,134 @@ +# 🏁 Single-Process Prototype — Implementation Summary + +**Status:** ✅ Complete +**Date:** October 22, 2025 +**Branch:** `8-single-process-prototype` + +--- + +## Overview + +The single-process prototype implements a **discrete event simulation (DES)** of a 3×3 urban grid with five intersections, realistic vehicle behavior, and fully synchronized traffic lights. Everything runs under one process, laying the groundwork for the distributed architecture in Phase 3. + +--- + +## Core Architecture + +### **SimulationEngine** + +Drives the DES loop with a priority queue of timestamped events — vehicles, lights, crossings, and periodic stats updates. Handles five intersections (Cr1–Cr5) and six event types. + +**Main loop:** + +``` +while (events && time < duration): + event = nextEvent() + time = event.timestamp + handle(event) +``` + +### **VehicleGenerator** + +Spawns vehicles via: + +* **Poisson arrivals** (λ = 0.5 veh/s) or fixed intervals +* **Probabilistic routes** from E1–E3 +* **Type distribution**: 20% BIKE, 60% LIGHT, 20% HEAVY + +### **StatisticsCollector** + +Tracks system-wide and per-type metrics: throughput, avg. wait, queue sizes, light cycles — updated every 10 s and at simulation end. + +--- + +## Model Highlights + +* **Vehicle** – type, route, timings, lifecycle. +* **Intersection** – routing tables, traffic lights, queues. +* **TrafficLight** – red/green cycles with FIFO queues. +* **Event** – timestamped, comparable; 6 types for all DES actions. + +--- + +## Configuration (`simulation.properties`) + +```properties +simulation.duration=60.0 +simulation.arrival.model=POISSON +simulation.arrival.rate=0.5 + +vehicle.bike.crossingTime=1.5 +vehicle.light.crossingTime=2.0 +vehicle.heavy.crossingTime=4.0 + +statistics.update.interval=10.0 +``` + +**Speed logic:** +`t_bike = 0.5×t_car`, `t_heavy = 2×t_car`. + +--- + +## Topology + +``` +E1→Cr1→Cr4→Cr5→S +E2→Cr2→Cr5→S +E3→Cr3→S +Bi-dir: Cr1↔Cr2, Cr2↔Cr3 +``` + +--- + +## Results + +**Unit Tests:** 7/7 ✅ +**60-Second Simulation:** + +* Generated: 22 vehicles +* Completed: 5 (22.7%) +* Avg system time: 15.47 s +* Throughput: 0.08 veh/s +* All lights & intersections operational + +**Performance:** +~0.03 s real-time run (≈2000× speed-up), < 50 MB RAM. + +--- + +## Code Structure + +``` +sd/ +├── engine/SimulationEngine.java +├── model/{Vehicle,Intersection,TrafficLight,Event}.java +├── util/{VehicleGenerator,StatisticsCollector}.java +└── config/SimulationConfig.java +``` + +--- + +## Key Flow + +1. Initialize intersections, lights, first events. +2. Process events chronologically. +3. Vehicles follow routes → queue → cross → exit. +4. Lights toggle, queues drain, stats update. +5. Print summary and performance metrics. + +--- + +## Next Steps — Phase 3 + +* Split intersections into independent **processes**. +* Add **socket-based communication**. +* Run **traffic lights as threads**. +* Enable **distributed synchronization** and fault handling. + +--- + +## TL;DR + +Solid single-process DES ✅ +Everything’s working — traffic lights, routing, vehicles, stats. +Ready to go distributed next. \ No newline at end of file diff --git a/TODO.md b/TODO.md index 001c208..d323ab6 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,26 @@ +## ✅ SINGLE-PROCESS PROTOTYPE - COMPLETED + +### Phase 2 Status: DONE ✅ + +All components for the single-process prototype have been successfully implemented and tested: + +- ✅ **SimulationEngine** - Priority queue-based discrete event simulation +- ✅ **VehicleGenerator** - Poisson and Fixed arrival models +- ✅ **StatisticsCollector** - Comprehensive metrics tracking +- ✅ **Entry point** - Main simulation runner +- ✅ **60s test simulation** - Successfully validated event processing and routing + +### Test Results: +- All 7 unit tests passing +- 60-second simulation completed successfully +- Generated 22 vehicles with 5 completing their routes +- Traffic light state changes working correctly +- Vehicle routing through intersections validated + +--- + +## NEXT: Distributed Architecture Implementation + ### Compreender os Conceitos Fundamentais Primeiro, as tecnologias e paradigmas chave necessários para este projeto devem ser totalmente compreendidos. From f0dbdb551d3070a3e4f99ae5df4915fc5aef47bd Mon Sep 17 00:00:00 2001 From: Leandro Afonso Date: Thu, 23 Oct 2025 00:01:55 +0100 Subject: [PATCH 04/18] Add GitHub Actions workflow for Java CI with Maven This workflow builds a Java project using Maven, caches dependencies, and updates the dependency graph for improved Dependabot alerts. --- .github/workflows/maven.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..06b6aa0 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,35 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Java CI with Maven + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + - name: Build with Maven + run: mvn -B package --file pom.xml + + # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive + - name: Update dependency graph + uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 From bb18c1119ec99bf3e7086e6bc374880b05b977d3 Mon Sep 17 00:00:00 2001 From: Leandro Afonso Date: Thu, 23 Oct 2025 00:02:55 +0100 Subject: [PATCH 05/18] Update Maven build file path to main/pom.xml --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 06b6aa0..c68fc22 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -28,7 +28,7 @@ jobs: distribution: 'temurin' cache: maven - name: Build with Maven - run: mvn -B package --file pom.xml + run: mvn -B package --file main/pom.xml # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive - name: Update dependency graph From 3689f7a207db14d8d010cd10b78d45ef3ff002ed Mon Sep 17 00:00:00 2001 From: Leandro Afonso Date: Thu, 23 Oct 2025 00:08:16 +0100 Subject: [PATCH 06/18] Set working directory for dependency graph update Specify working directory for dependency graph update --- .github/workflows/maven.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index c68fc22..5472be2 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -33,3 +33,5 @@ jobs: # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive - name: Update dependency graph uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 + with: + working-directory: main From c30aa25de0368e5a92265e3f2b6266eebdb03a5c Mon Sep 17 00:00:00 2001 From: Leandro Afonso Date: Thu, 23 Oct 2025 00:14:34 +0100 Subject: [PATCH 07/18] Update Maven workflow to use JDK 17 and improve steps --- .github/workflows/maven.yml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 5472be2..6fa7075 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -21,17 +21,25 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Set up JDK 17 uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' cache: maven - - name: Build with Maven - run: mvn -B package --file main/pom.xml - # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive - - name: Update dependency graph - uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 + - name: Build with Maven + run: mvn -B package + working-directory: main + + # Generate dependency graph explicitly (run step supports -f) + - name: Generate dependency graph + run: mvn -B -f main/pom.xml com.github.ferstl:depgraph-maven-plugin:4.0.1:graph + + # Upload the generated dependency files so you can inspect them in the workflow run + - name: Upload dependency graph artifact + uses: actions/upload-artifact@v4 with: - working-directory: main + name: dependency-graph + path: main/target/** From 12b7aabe872a217ecc96b7913e1050e4edaffa32 Mon Sep 17 00:00:00 2001 From: Leandro Afonso Date: Thu, 23 Oct 2025 00:21:36 +0100 Subject: [PATCH 08/18] Enhance CI workflow with security and dependency checks Added security scan and dependency review jobs to the workflow. --- .github/workflows/maven.yml | 97 ++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 11 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 6fa7075..acc3264 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,11 +1,6 @@ # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - name: Java CI with Maven on: @@ -16,9 +11,7 @@ on: jobs: build: - runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 @@ -33,13 +26,95 @@ jobs: run: mvn -B package working-directory: main - # Generate dependency graph explicitly (run step supports -f) + # Generate dependency graph explicitly - name: Generate dependency graph - run: mvn -B -f main/pom.xml com.github.ferstl:depgraph-maven-plugin:4.0.1:graph + run: mvn -B com.github.ferstl:depgraph-maven-plugin:4.0.1:graph + working-directory: main - # Upload the generated dependency files so you can inspect them in the workflow run + # Upload the packaged JAR file as an artifact + - name: Upload package artifact + uses: actions/upload-artifact@v4 + with: + name: package + path: main/target/*.jar # Upload only the JAR + + # Upload the generated dependency graph so you can inspect it - name: Upload dependency graph artifact uses: actions/upload-artifact@v4 with: name: dependency-graph - path: main/target/** + path: main/target/dependency-graph.dot # Upload the specific graph file + + test-and-coverage: + runs-on: ubuntu-latest + needs: build # Make it dependent on the build job to ensure code compiles + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + + - name: Run tests and generate coverage report + # 'verify' runs all tests. 'jacoco:report' generates the coverage report. + # This assumes you have the JaCoCo plugin configured in your pom.xml + run: mvn -B verify jacoco:report + working-directory: main + + - name: Upload coverage report + # This uploads the HTML coverage report as an artifact + uses: actions/upload-artifact@v4 + with: + name: code-coverage-report + path: main/target/site/jacoco/ # Path to the JaCoCo HTML report + + security-scan: + # NEW JOB: This job runs GitHub's CodeQL to find security vulnerabilities. + # It runs in parallel with other jobs. + runs-on: ubuntu-latest + + # Required permissions for CodeQL to write results + permissions: + security-events: write # for github/codeql-action/analyze + actions: read # for github/codeql-action/init + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: 'java' # Specify the language to analyze + + - name: Build project for CodeQL + # CodeQL needs to monitor the build process. + # We skip tests here (-DskipTests) because we only need the compiled code + # for static analysis, and tests are run in the 'test-and-coverage' job. + run: mvn -B clean package -DskipTests + working-directory: main + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + + dependency-review: + # NEW JOB: This job checks for vulnerable dependencies on Pull Requests. + # It prevents merging PRs that introduce known vulnerabilities. + runs-on: ubuntu-latest + + # This job only needs to run on pull requests + if: github.event_name == 'pull_request' + + permissions: + contents: read # To read dependency files + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Dependency Review + uses: actions/dependency-review-action@v4 From 9093b13c5d43f5a278f3106e11c4e1090c5f79a3 Mon Sep 17 00:00:00 2001 From: Leandro Afonso Date: Thu, 23 Oct 2025 00:27:37 +0100 Subject: [PATCH 09/18] Rollback Oops --- .github/workflows/maven.yml | 92 +++---------------------------------- 1 file changed, 6 insertions(+), 86 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index acc3264..6819189 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -11,7 +11,9 @@ on: jobs: build: + runs-on: ubuntu-latest + steps: - uses: actions/checkout@v4 @@ -26,95 +28,13 @@ jobs: run: mvn -B package working-directory: main - # Generate dependency graph explicitly + # Generate dependency graph explicitly (run step supports -f) - name: Generate dependency graph - run: mvn -B com.github.ferstl:depgraph-maven-plugin:4.0.1:graph - working-directory: main + run: mvn -B -f main/pom.xml com.github.ferstl:depgraph-maven-plugin:4.0.1:graph - # Upload the packaged JAR file as an artifact - - name: Upload package artifact - uses: actions/upload-artifact@v4 - with: - name: package - path: main/target/*.jar # Upload only the JAR - - # Upload the generated dependency graph so you can inspect it + # Upload the generated dependency files so you can inspect them in the workflow run - name: Upload dependency graph artifact uses: actions/upload-artifact@v4 with: name: dependency-graph - path: main/target/dependency-graph.dot # Upload the specific graph file - - test-and-coverage: - runs-on: ubuntu-latest - needs: build # Make it dependent on the build job to ensure code compiles - - steps: - - uses: actions/checkout@v4 - - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'temurin' - cache: maven - - - name: Run tests and generate coverage report - # 'verify' runs all tests. 'jacoco:report' generates the coverage report. - # This assumes you have the JaCoCo plugin configured in your pom.xml - run: mvn -B verify jacoco:report - working-directory: main - - - name: Upload coverage report - # This uploads the HTML coverage report as an artifact - uses: actions/upload-artifact@v4 - with: - name: code-coverage-report - path: main/target/site/jacoco/ # Path to the JaCoCo HTML report - - security-scan: - # NEW JOB: This job runs GitHub's CodeQL to find security vulnerabilities. - # It runs in parallel with other jobs. - runs-on: ubuntu-latest - - # Required permissions for CodeQL to write results - permissions: - security-events: write # for github/codeql-action/analyze - actions: read # for github/codeql-action/init - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: 'java' # Specify the language to analyze - - - name: Build project for CodeQL - # CodeQL needs to monitor the build process. - # We skip tests here (-DskipTests) because we only need the compiled code - # for static analysis, and tests are run in the 'test-and-coverage' job. - run: mvn -B clean package -DskipTests - working-directory: main - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - - dependency-review: - # NEW JOB: This job checks for vulnerable dependencies on Pull Requests. - # It prevents merging PRs that introduce known vulnerabilities. - runs-on: ubuntu-latest - - # This job only needs to run on pull requests - if: github.event_name == 'pull_request' - - permissions: - contents: read # To read dependency files - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Dependency Review - uses: actions/dependency-review-action@v4 + path: main/target/** From 33ed84b0c2eb9ffcd7a8d31940056e6dbdc50c59 Mon Sep 17 00:00:00 2001 From: Leandro Afonso Date: Thu, 23 Oct 2025 00:36:13 +0100 Subject: [PATCH 10/18] Enhance Maven workflow with release publishing Added a publish-release job to create a GitHub release with the built JAR file when a tag is pushed. --- .github/workflows/maven.yml | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 6819189..344c385 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,17 +1,15 @@ -# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven - name: Java CI with Maven on: push: branches: [ "main" ] + tags: + - 'v*.*.*' pull_request: branches: [ "main" ] jobs: build: - runs-on: ubuntu-latest steps: @@ -28,13 +26,36 @@ jobs: run: mvn -B package working-directory: main - # Generate dependency graph explicitly (run step supports -f) + - name: Upload built JAR + uses: actions/upload-artifact@v4 + with: + name: package + path: main/target/*.jar + - name: Generate dependency graph run: mvn -B -f main/pom.xml com.github.ferstl:depgraph-maven-plugin:4.0.1:graph - # Upload the generated dependency files so you can inspect them in the workflow run - name: Upload dependency graph artifact uses: actions/upload-artifact@v4 with: name: dependency-graph path: main/target/** + + publish-release: + runs-on: ubuntu-latest + needs: [build] + if: startsWith(github.ref, 'refs/tags/') + permissions: + contents: write + + steps: + - name: Download built JAR + uses: actions/download-artifact@v4 + with: + name: package + path: main/target/ + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: main/target/*.jar From 8e95bc4c01a51f0a2816cfaae3d945cc2a23e77b Mon Sep 17 00:00:00 2001 From: Leandro Afonso Date: Thu, 23 Oct 2025 00:43:57 +0100 Subject: [PATCH 11/18] Testing job --- TODO.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index d323ab6..97d1982 100644 --- a/TODO.md +++ b/TODO.md @@ -39,7 +39,7 @@ Primeiro, as tecnologias e paradigmas chave necessários para este projeto devem - Uma **lista de eventos** central, frequentemente uma fila de prioridades, será necessária para armazenar eventos futuros, ordenados pelo seu timestamp. O ciclo principal da simulação retira o próximo evento da lista, processa-o e adiciona quaisquer novos eventos que resultem dele. -- **Processo de Poisson:** Para o modelo "mais realista" de chegadas de veículos, é especificado um processo de Poisson. A principal conclusão é que o tempo _entre_ chegadas consecutivas de veículos segue uma **distribuição exponencial**. Em Java, este intervalo pode ser gerado usando `Math.log(1 - Math.random()) / -lambda`, onde `lambda` (λi​) é a taxa de chegada especificada. +- **Processo de Poisson:** Para o modelo 'mais realista' de chegadas de veículos, é especificado um processo de Poisson. A principal conclusão é que o tempo _entre_ chegadas consecutivas de veículos segue uma **distribuição exponencial**. Em Java, este intervalo pode ser gerado usando `Math.log(1 - Math.random()) / -lambda`, onde `lambda` (λi​) é a taxa de chegada especificada. --- @@ -195,4 +195,4 @@ Assim que o sistema completo estiver a funcionar, as experiências exigidas pela - **Debugging:** Debugging de sistemas distribuídos podem ser difíceis. Uma framework de logging (como Log4j 2 ou SLF4J) pode ser usada para registar eventos//alterações de estado nos diferentes processos. -- **Configuração:** Valores como endereços IP, números de porta ou parâmetros da simulação não devem ser "hardcoded". Um ficheiro de configuração (ex: um ficheiro `.properties` ou `.json`) torna a aplicação mais fácil de executar e testar. \ No newline at end of file +- **Configuração:** Valores como endereços IP, números de porta ou parâmetros da simulação não devem ser "hardcoded". Um ficheiro de configuração (ex: um ficheiro `.properties` ou `.json`) torna a aplicação mais fácil de executar e testar. From 23f7a74798a753b19e3aa1d82c1e30f5d406e80d Mon Sep 17 00:00:00 2001 From: Leandro Afonso Date: Fri, 24 Oct 2025 20:20:15 +0100 Subject: [PATCH 12/18] Add dependency build to CI job --- main/pom.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/main/pom.xml b/main/pom.xml index 0adc5f4..56ce74f 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -42,6 +42,26 @@ sd.Entry + + org.apache.maven.plugins + maven-shade-plugin + 3.5.2 + + + package + + shade + + + + + sd.Entry + + + + + + From 6c5eab0e72fe5d13e18034e017e25b58f6617ec4 Mon Sep 17 00:00:00 2001 From: Gaa56 Date: Sat, 25 Oct 2025 17:41:55 +0100 Subject: [PATCH 13/18] Create SocketConnection wrapper class --- .../java/sd/protocol/MessageProtocol.java | 37 +++++++++---------- .../java/sd/protocol/SocketConnection.java | 5 +++ 2 files changed, 22 insertions(+), 20 deletions(-) create mode 100644 main/src/main/java/sd/protocol/SocketConnection.java diff --git a/main/src/main/java/sd/protocol/MessageProtocol.java b/main/src/main/java/sd/protocol/MessageProtocol.java index 9f20437..47975be 100644 --- a/main/src/main/java/sd/protocol/MessageProtocol.java +++ b/main/src/main/java/sd/protocol/MessageProtocol.java @@ -1,44 +1,41 @@ package sd.protocol; - - import java.io.Serializable; - -import sd.model.MessageType; +import sd.model.MessageType; // Assuming MessageType is in sd.model or sd.protocol /** - * Interface que define o contrato para todas as mensagens trocadas no simulador. - * Garante que qualquer mensagem possa ser identificada e roteada. - * * Esta interface estende Serializable para permitir que os objetos que a implementam - * sejam enviados através de Sockets (ObjectOutputStream). + * Interface defining the contract for all messages exchanged in the simulator. + * Ensures that any message can be identified and routed. + * * This interface extends Serializable to allow objects that implement it + * to be sent over Sockets (ObjectOutputStream). * */ public interface MessageProtocol extends Serializable { /** - * Retorna o tipo da mensagem, indicando o seu propósito. - * @return O MessageType (ex: VEHICLE_TRANSFER, STATS_UPDATE). + * Returns the type of the message, indicating its purpose. + * @return The MessageType (e.g., VEHICLE_TRANSFER, STATS_UPDATE). */ MessageType getType(); /** - * Retorna o objeto de dados (carga útil) que esta mensagem transporta. - * O tipo de objeto dependerá do MessageType. - * * - Se getType() == VEHICLE_TRANSFER, o payload será um objeto {@link sd.model.Vehicle}. - * - Se getType() == STATS_UPDATE, o payload será um objeto de estatísticas. - * * @return O objeto de dados (payload), que também deve ser Serializable. + * Returns the data object (payload) that this message carries. + * The type of object will depend on the MessageType. + * * - If getType() == VEHICLE_TRANSFER, the payload will be a {@link sd.model.Vehicle} object. + * - If getType() == STATS_UPDATE, the payload will be a statistics object. + * * @return The data object (payload), which must also be Serializable. */ Object getPayload(); /** - * Retorna o ID do nó (Processo) que enviou esta mensagem. - * @return String (ex: "Cr1", "Cr5", "S"). + * Returns the ID of the node (Process) that sent this message. + * @return String (e.g., "Cr1", "Cr5", "S"). */ String getSourceNode(); /** - * Retorna o ID do nó (Processo) de destino desta mensagem. - * @return String (ex: "Cr2", "DashboardServer"). + * Returns the ID of the destination node (Process) for this message. + * @return String (e.g., "Cr2", "DashboardServer"). */ String getDestinationNode(); -} +} \ No newline at end of file diff --git a/main/src/main/java/sd/protocol/SocketConnection.java b/main/src/main/java/sd/protocol/SocketConnection.java new file mode 100644 index 0000000..d56ad9c --- /dev/null +++ b/main/src/main/java/sd/protocol/SocketConnection.java @@ -0,0 +1,5 @@ +package sd.protocol; + +public class SocketConnection { + +} From 96903e4b7c3456a30b14dd140fc627e4025ce027 Mon Sep 17 00:00:00 2001 From: Gaa56 Date: Sat, 25 Oct 2025 17:43:25 +0100 Subject: [PATCH 14/18] SocketConnection --- .../java/sd/protocol/SocketConnection.java | 110 +++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) diff --git a/main/src/main/java/sd/protocol/SocketConnection.java b/main/src/main/java/sd/protocol/SocketConnection.java index d56ad9c..0198242 100644 --- a/main/src/main/java/sd/protocol/SocketConnection.java +++ b/main/src/main/java/sd/protocol/SocketConnection.java @@ -1,5 +1,111 @@ package sd.protocol; -public class SocketConnection { +import java.io.Closeable; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.Socket; +import java.net.UnknownHostException; -} +/** + * Wrapper class that simplifies communication via Sockets. + * * It encapsulates all stream logic (ObjectInputStream/ObjectOutputStream) + * so the rest of your code can simply "send" and "receive" objects + * that implement your MessageProtocol. + * * This is necessary to meet the requirement for inter-process communication + * (Intersections). + * * This class implements Closeable, so you can (and should) use it + * with a 'try-with-resources' block to ensure the socket is always closed. + */ +public class SocketConnection implements Closeable { + + private final Socket socket; + private final ObjectOutputStream outputStream; + private final ObjectInputStream inputStream; + + /** + * Constructor for the "Client" (who initiates the connection). + * Tries to connect to a process that is already listening (Server). + * + * @param host The host address (e.g., "localhost" from your simulation.properties) + * @param port The port (e.g., 8001 from your simulation.properties) + * @throws IOException If connection fails. + * @throws UnknownHostException If the host is not found. + */ + public SocketConnection(String host, int port) throws IOException, UnknownHostException { + this.socket = new Socket(host, port); + + // IMPORTANT: The order is crucial to prevent deadlocks when creating streams. + // The OutputStream (output stream) must be created first. + this.outputStream = new ObjectOutputStream(socket.getOutputStream()); + this.inputStream = new ObjectInputStream(socket.getInputStream()); + } + + /** + * Constructor for the "Server" (who accepts the connection). + * Receives a Socket that has already been accepted by a ServerSocket. + * + * @param acceptedSocket The Socket returned by serverSocket.accept(). + * @throws IOException If stream creation fails. + */ + public SocketConnection(Socket acceptedSocket) throws IOException { + this.socket = acceptedSocket; + + // IMPORTANT: The order is crucial. OutputStream (output stream) must be created first. + this.outputStream = new ObjectOutputStream(socket.getOutputStream()); + this.inputStream = new ObjectInputStream(socket.getInputStream()); + } + + /** + * Sends (serializes) a MessageProtocol object over the socket. + * + * @param message The "envelope" (which contains the Vehicle) to be sent. + * @throws IOException If writing to the stream fails. + */ + public void sendMessage(MessageProtocol message) throws IOException { + synchronized (outputStream) { + outputStream.writeObject(message); + outputStream.flush(); // Ensures the message is sent immediately. + } + } + + /** + * Tries to read (deserialize) a MessageProtocol object from the socket. + * This call is "blocked" until an object is received. + * + * @return The "envelope" (MessageProtocol) that was received. + * @throws IOException If the connection is lost or the stream is corrupted. + * @throws ClassNotFoundException If the received object is unknown. + */ + public MessageProtocol receiveMessage() throws IOException, ClassNotFoundException { + synchronized (inputStream) { + return (MessageProtocol) inputStream.readObject(); + } + } + + /** + * Closes the socket and all streams (Input and Output). + * It is called automatically if you use 'try-with-resources'. + */ + @Override + public void close() throws IOException { + try { + if (inputStream != null) inputStream.close(); + } catch (IOException e) { /* ignore */ } + + try { + if (outputStream != null) outputStream.close(); + } catch (IOException e) { /* ignore */ } + + if (socket != null && !socket.isClosed()) { + socket.close(); + } + } + + /** + * @return true if the socket is still connected. + */ + public boolean isConnected() { + return socket != null && socket.isConnected() && !socket.isClosed(); + } +} \ No newline at end of file From bc1a8da160d462ed26d1c1c00188b2e9a10be302 Mon Sep 17 00:00:00 2001 From: Gaa56 Date: Sat, 25 Oct 2025 18:00:58 +0100 Subject: [PATCH 15/18] Create MessageSerializer utility --- .../main/java/sd/util/MessageSerializer.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 main/src/main/java/sd/util/MessageSerializer.java diff --git a/main/src/main/java/sd/util/MessageSerializer.java b/main/src/main/java/sd/util/MessageSerializer.java new file mode 100644 index 0000000..2e7f461 --- /dev/null +++ b/main/src/main/java/sd/util/MessageSerializer.java @@ -0,0 +1,62 @@ +package sd.util; // Or sd.util if you prefer + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import sd.protocol.MessageProtocol; + +/** + * Utility class for serializing and deserializing MessageProtocol objects. + * * NOTE: The SocketConnection class already handles serialization/deserialization + * automatically via ObjectOutputStream and ObjectInputStream directly + * on the socket stream. This class serves more as an example or for + * scenarios where you might want to manipulate the bytes directly + * (e.g., for sending via UDP or other means). + */ +public class MessageSerializer { + + /** + * Serializes a MessageProtocol object into a byte array. + * * @param message The MessageProtocol object to be serialized. + * @return A byte array representing the serialized object. + * @throws IOException If an error occurs during serialization. + */ + public static byte[] serialize(MessageProtocol message) throws IOException { + // Use a ByteArrayOutputStream to write bytes into memory + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + + // Use an ObjectOutputStream to write the object into the byteStream + try (ObjectOutputStream objectStream = new ObjectOutputStream(byteStream)) { + objectStream.writeObject(message); + } // The try-with-resources automatically closes the objectStream + + // Return the resulting bytes + return byteStream.toByteArray(); + } + + /** + * Deserializes a byte array back into a MessageProtocol object. + * * @param data The byte array to be deserialized. + * @return The reconstructed MessageProtocol object. + * @throws IOException If an error occurs while reading the bytes. + * @throws ClassNotFoundException If the class of the serialized object cannot be found. + */ + public static MessageProtocol deserialize(byte[] data) throws IOException, ClassNotFoundException { + // Use a ByteArrayInputStream to read from the byte array + ByteArrayInputStream byteStream = new ByteArrayInputStream(data); + + // Use an ObjectInputStream to read the object from the byteStream + try (ObjectInputStream objectStream = new ObjectInputStream(byteStream)) { + // Read the object and cast it to MessageProtocol + return (MessageProtocol) objectStream.readObject(); + } // The try-with-resources automatically closes the objectStream + } + + // Private constructor to prevent instantiation of the utility class + private MessageSerializer() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated."); + } +} \ No newline at end of file From 1524188b29ec2539d9b24a59c203be3222d87d2f Mon Sep 17 00:00:00 2001 From: Gaa56 Date: Sun, 26 Oct 2025 17:00:34 +0000 Subject: [PATCH 16/18] Add connection retry logic --- .../java/sd/protocol/SocketConnection.java | 120 ++++++++++++++---- 1 file changed, 96 insertions(+), 24 deletions(-) diff --git a/main/src/main/java/sd/protocol/SocketConnection.java b/main/src/main/java/sd/protocol/SocketConnection.java index 0198242..f6392a4 100644 --- a/main/src/main/java/sd/protocol/SocketConnection.java +++ b/main/src/main/java/sd/protocol/SocketConnection.java @@ -1,21 +1,18 @@ -package sd.protocol; +package sd.protocol; import java.io.Closeable; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.net.ConnectException; import java.net.Socket; +import java.net.SocketTimeoutException; import java.net.UnknownHostException; +import java.util.concurrent.TimeUnit; /** * Wrapper class that simplifies communication via Sockets. - * * It encapsulates all stream logic (ObjectInputStream/ObjectOutputStream) - * so the rest of your code can simply "send" and "receive" objects - * that implement your MessageProtocol. - * * This is necessary to meet the requirement for inter-process communication - * (Intersections). - * * This class implements Closeable, so you can (and should) use it - * with a 'try-with-resources' block to ensure the socket is always closed. + * Includes connection retry logic for robustness. */ public class SocketConnection implements Closeable { @@ -23,46 +20,115 @@ public class SocketConnection implements Closeable { private final ObjectOutputStream outputStream; private final ObjectInputStream inputStream; + // --- Configuration for Retry Logic --- + /** Maximum number of connection attempts. */ + private static final int MAX_RETRIES = 5; + /** Delay between retry attempts in milliseconds. */ + private static final long RETRY_DELAY_MS = 1000; + /** * Constructor for the "Client" (who initiates the connection). * Tries to connect to a process that is already listening (Server). + * Includes retry logic in case of initial connection failure. * * @param host The host address (e.g., "localhost" from your simulation.properties) * @param port The port (e.g., 8001 from your simulation.properties) - * @throws IOException If connection fails. - * @throws UnknownHostException If the host is not found. + * @throws IOException If connection fails after all retries. + * @throws UnknownHostException If the host is not found (this error usually doesn't need retry). + * @throws InterruptedException If the thread is interrupted while waiting between retries. */ - public SocketConnection(String host, int port) throws IOException, UnknownHostException { - this.socket = new Socket(host, port); - - // IMPORTANT: The order is crucial to prevent deadlocks when creating streams. - // The OutputStream (output stream) must be created first. - this.outputStream = new ObjectOutputStream(socket.getOutputStream()); - this.inputStream = new ObjectInputStream(socket.getInputStream()); + public SocketConnection(String host, int port) throws IOException, UnknownHostException, InterruptedException { + Socket tempSocket = null; + IOException lastException = null; + + System.out.printf("[SocketConnection] Attempting to connect to %s:%d...%n", host, port); + + // --- Retry Loop --- + for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) { + try { + // Try to establish the connection + tempSocket = new Socket(host, port); + + // If successful, break out of the retry loop + System.out.printf("[SocketConnection] Connected successfully on attempt %d.%n", attempt); + lastException = null; // Clear last error on success + break; + + } catch (ConnectException | SocketTimeoutException e) { + // These are common errors indicating the server might not be ready. + lastException = e; + System.out.printf("[SocketConnection] Attempt %d/%d failed: %s. Retrying in %d ms...%n", + attempt, MAX_RETRIES, e.getMessage(), RETRY_DELAY_MS); + + if (attempt < MAX_RETRIES) { + // Wait before the next attempt + TimeUnit.MILLISECONDS.sleep(RETRY_DELAY_MS); + } + } catch (IOException e) { + // Other IOExceptions might be more permanent, but we retry anyway. + lastException = e; + System.out.printf("[SocketConnection] Attempt %d/%d failed with IOException: %s. Retrying in %d ms...%n", + attempt, MAX_RETRIES, e.getMessage(), RETRY_DELAY_MS); + if (attempt < MAX_RETRIES) { + TimeUnit.MILLISECONDS.sleep(RETRY_DELAY_MS); + } + } + } // --- End of Retry Loop --- + + // If after all retries tempSocket is still null, it means connection failed permanently. + if (tempSocket == null) { + System.err.printf("[SocketConnection] Failed to connect to %s:%d after %d attempts.%n", host, port, MAX_RETRIES); + if (lastException != null) { + throw lastException; // Throw the last exception encountered + } else { + // Should not happen if loop ran, but as a fallback + throw new IOException("Failed to connect after " + MAX_RETRIES + " attempts, reason unknown."); + } + } + + // If connection was successful, assign to final variable and create streams + this.socket = tempSocket; + try { + // IMPORTANT: The order is crucial. OutputStream first. + this.outputStream = new ObjectOutputStream(socket.getOutputStream()); + this.inputStream = new ObjectInputStream(socket.getInputStream()); + } catch (IOException e) { + // If stream creation fails even after successful socket connection, clean up. + System.err.println("[SocketConnection] Failed to create streams after connection: " + e.getMessage()); + try { socket.close(); } catch (IOException closeEx) { /* ignore */ } + throw e; // Re-throw the stream creation exception + } } + /** * Constructor for the "Server" (who accepts the connection). * Receives a Socket that has already been accepted by a ServerSocket. + * No retry logic needed here as the connection is already established. * * @param acceptedSocket The Socket returned by serverSocket.accept(). * @throws IOException If stream creation fails. */ public SocketConnection(Socket acceptedSocket) throws IOException { this.socket = acceptedSocket; - - // IMPORTANT: The order is crucial. OutputStream (output stream) must be created first. + + // IMPORTANT: The order is crucial. OutputStream first. this.outputStream = new ObjectOutputStream(socket.getOutputStream()); this.inputStream = new ObjectInputStream(socket.getInputStream()); + System.out.printf("[SocketConnection] Connection accepted from %s:%d.%n", + acceptedSocket.getInetAddress().getHostAddress(), acceptedSocket.getPort()); } /** * Sends (serializes) a MessageProtocol object over the socket. * * @param message The "envelope" (which contains the Vehicle) to be sent. - * @throws IOException If writing to the stream fails. + * @throws IOException If writing to the stream fails or socket is not connected. */ public void sendMessage(MessageProtocol message) throws IOException { + if (!isConnected()) { + throw new IOException("Socket is not connected."); + } synchronized (outputStream) { outputStream.writeObject(message); outputStream.flush(); // Ensures the message is sent immediately. @@ -74,10 +140,13 @@ public class SocketConnection implements Closeable { * This call is "blocked" until an object is received. * * @return The "envelope" (MessageProtocol) that was received. - * @throws IOException If the connection is lost or the stream is corrupted. + * @throws IOException If the connection is lost, the stream is corrupted, or socket is not connected. * @throws ClassNotFoundException If the received object is unknown. */ public MessageProtocol receiveMessage() throws IOException, ClassNotFoundException { + if (!isConnected()) { + throw new IOException("Socket is not connected."); + } synchronized (inputStream) { return (MessageProtocol) inputStream.readObject(); } @@ -89,21 +158,24 @@ public class SocketConnection implements Closeable { */ @Override public void close() throws IOException { + System.out.printf("[SocketConnection] Closing connection to %s:%d.%n", + socket != null ? socket.getInetAddress().getHostAddress() : "N/A", + socket != null ? socket.getPort() : -1); try { if (inputStream != null) inputStream.close(); } catch (IOException e) { /* ignore */ } - + try { if (outputStream != null) outputStream.close(); } catch (IOException e) { /* ignore */ } - + if (socket != null && !socket.isClosed()) { socket.close(); } } /** - * @return true if the socket is still connected. + * @return true if the socket is still connected and not closed. */ public boolean isConnected() { return socket != null && socket.isConnected() && !socket.isClosed(); From 06c34a198a97ab48d19e6c6f92ac6806f05d76c3 Mon Sep 17 00:00:00 2001 From: Gaa56 Date: Mon, 27 Oct 2025 09:15:33 +0000 Subject: [PATCH 17/18] Removed MessageSerializer --- main/src/main/java/sd/util/MessageSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/src/main/java/sd/util/MessageSerializer.java b/main/src/main/java/sd/util/MessageSerializer.java index 2e7f461..cd3e4ed 100644 --- a/main/src/main/java/sd/util/MessageSerializer.java +++ b/main/src/main/java/sd/util/MessageSerializer.java @@ -1,4 +1,4 @@ -package sd.util; // Or sd.util if you prefer +package sd.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; From d8b59cc502503a6312038f786ea681afa9f6f983 Mon Sep 17 00:00:00 2001 From: Gaa56 Date: Mon, 27 Oct 2025 09:18:33 +0000 Subject: [PATCH 18/18] Deleted MessageSerializer --- .../main/java/sd/util/MessageSerializer.java | 62 ------------------- 1 file changed, 62 deletions(-) delete mode 100644 main/src/main/java/sd/util/MessageSerializer.java diff --git a/main/src/main/java/sd/util/MessageSerializer.java b/main/src/main/java/sd/util/MessageSerializer.java deleted file mode 100644 index cd3e4ed..0000000 --- a/main/src/main/java/sd/util/MessageSerializer.java +++ /dev/null @@ -1,62 +0,0 @@ -package sd.util; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -import sd.protocol.MessageProtocol; - -/** - * Utility class for serializing and deserializing MessageProtocol objects. - * * NOTE: The SocketConnection class already handles serialization/deserialization - * automatically via ObjectOutputStream and ObjectInputStream directly - * on the socket stream. This class serves more as an example or for - * scenarios where you might want to manipulate the bytes directly - * (e.g., for sending via UDP or other means). - */ -public class MessageSerializer { - - /** - * Serializes a MessageProtocol object into a byte array. - * * @param message The MessageProtocol object to be serialized. - * @return A byte array representing the serialized object. - * @throws IOException If an error occurs during serialization. - */ - public static byte[] serialize(MessageProtocol message) throws IOException { - // Use a ByteArrayOutputStream to write bytes into memory - ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); - - // Use an ObjectOutputStream to write the object into the byteStream - try (ObjectOutputStream objectStream = new ObjectOutputStream(byteStream)) { - objectStream.writeObject(message); - } // The try-with-resources automatically closes the objectStream - - // Return the resulting bytes - return byteStream.toByteArray(); - } - - /** - * Deserializes a byte array back into a MessageProtocol object. - * * @param data The byte array to be deserialized. - * @return The reconstructed MessageProtocol object. - * @throws IOException If an error occurs while reading the bytes. - * @throws ClassNotFoundException If the class of the serialized object cannot be found. - */ - public static MessageProtocol deserialize(byte[] data) throws IOException, ClassNotFoundException { - // Use a ByteArrayInputStream to read from the byte array - ByteArrayInputStream byteStream = new ByteArrayInputStream(data); - - // Use an ObjectInputStream to read the object from the byteStream - try (ObjectInputStream objectStream = new ObjectInputStream(byteStream)) { - // Read the object and cast it to MessageProtocol - return (MessageProtocol) objectStream.readObject(); - } // The try-with-resources automatically closes the objectStream - } - - // Private constructor to prevent instantiation of the utility class - private MessageSerializer() { - throw new UnsupportedOperationException("This is a utility class and cannot be instantiated."); - } -} \ No newline at end of file