bullshit fixes

This commit is contained in:
2025-11-06 20:31:59 +00:00
parent 5dc1b40c88
commit 84cba39597
3 changed files with 390 additions and 369 deletions

View File

@@ -22,41 +22,43 @@ import sd.protocol.SocketConnection;
/** /**
* Main class for an Intersection Process in the distributed traffic simulation. * Main class for an Intersection Process in the distributed traffic simulation.
* * Each IntersectionProcess runs as an independent Java application (JVM instance) * * Each IntersectionProcess runs as an independent Java application (JVM
* instance)
* representing one of the five intersections (Cr1-Cr5) in the network. * representing one of the five intersections (Cr1-Cr5) in the network.
*/ */
public class IntersectionProcess { public class IntersectionProcess {
private final String intersectionId; private final String intersectionId;
private final SimulationConfig config; private final SimulationConfig config;
private final Intersection intersection; private final Intersection intersection;
private ServerSocket serverSocket; private ServerSocket serverSocket;
private final Map<String, SocketConnection> outgoingConnections; private final Map<String, SocketConnection> outgoingConnections;
private final ExecutorService connectionHandlerPool; private final ExecutorService connectionHandlerPool;
private final ExecutorService trafficLightPool; private final ExecutorService trafficLightPool;
private volatile boolean running; //Quando uma thread escreve um valor volatile, todas as outras private volatile boolean running; // Quando uma thread escreve um valor volatile, todas as outras
//threads veem a mudança imediatamente. // threads veem a mudança imediatamente.
// Traffic Light Coordination // Traffic Light Coordination
/** /**
* Lock to ensure mutual exclusion between traffic lights. * Lock to ensure mutual exclusion between traffic lights.
* Only one traffic light can be green at any given time within this intersection. * Only one traffic light can be green at any given time within this
* intersection.
*/ */
private final Lock trafficCoordinationLock; private final Lock trafficCoordinationLock;
/** /**
* Tracks which direction currently has the green light. * Tracks which direction currently has the green light.
* null means no direction is currently green (all are red). * null means no direction is currently green (all are red).
*/ */
private volatile String currentGreenDirection; private volatile String currentGreenDirection;
/** /**
* Constructs a new IntersectionProcess. * Constructs a new IntersectionProcess.
* *
@@ -74,113 +76,113 @@ public class IntersectionProcess {
this.running = false; this.running = false;
this.trafficCoordinationLock = new ReentrantLock(); this.trafficCoordinationLock = new ReentrantLock();
this.currentGreenDirection = null; this.currentGreenDirection = null;
System.out.println("=".repeat(60)); System.out.println("=".repeat(60));
System.out.println("INTERSECTION PROCESS: " + intersectionId); System.out.println("INTERSECTION PROCESS: " + intersectionId);
System.out.println("=".repeat(60)); System.out.println("=".repeat(60));
} }
public void initialize() { public void initialize() {
System.out.println("\n[" + intersectionId + "] Initializing intersection..."); System.out.println("\n[" + intersectionId + "] Initializing intersection...");
createTrafficLights(); createTrafficLights();
configureRouting(); configureRouting();
System.out.println("[" + intersectionId + "] Initialization complete."); System.out.println("[" + intersectionId + "] Initialization complete.");
} }
/** /**
* Creates traffic lights for this intersection based on its physical connections. * Creates traffic lights for this intersection based on its physical
* connections.
* Each intersection has different number and directions of traffic lights * Each intersection has different number and directions of traffic lights
* according to the network topology. * according to the network topology.
*/ */
private void createTrafficLights() { private void createTrafficLights() {
System.out.println("\n[" + intersectionId + "] Creating traffic lights..."); System.out.println("\n[" + intersectionId + "] Creating traffic lights...");
String[] directions = new String[0]; String[] directions = new String[0];
switch (intersectionId) { switch (intersectionId) {
case "Cr1": case "Cr1":
directions = new String[]{"East", "South"}; directions = new String[] { "East", "South" };
break; break;
case "Cr2": case "Cr2":
directions = new String[]{"West", "East", "South"}; directions = new String[] { "West", "East", "South" };
break; break;
case "Cr3": case "Cr3":
directions = new String[]{"West", "South"}; directions = new String[] { "West", "South" };
break; break;
case "Cr4": case "Cr4":
directions = new String[]{"East"}; directions = new String[] { "East" };
break; break;
case "Cr5": case "Cr5":
directions = new String[]{"East"}; directions = new String[] { "East" };
break; break;
} }
for (String direction : directions) { for (String direction : directions) {
double greenTime = config.getTrafficLightGreenTime(intersectionId, direction); double greenTime = config.getTrafficLightGreenTime(intersectionId, direction);
double redTime = config.getTrafficLightRedTime(intersectionId, direction); double redTime = config.getTrafficLightRedTime(intersectionId, direction);
TrafficLight light = new TrafficLight( TrafficLight light = new TrafficLight(
intersectionId + "-" + direction, intersectionId + "-" + direction,
direction, direction,
greenTime, greenTime,
redTime redTime);
);
intersection.addTrafficLight(light); intersection.addTrafficLight(light);
System.out.println(" Created traffic light: " + direction + System.out.println(" Created traffic light: " + direction +
" (Green: " + greenTime + "s, Red: " + redTime + "s)"); " (Green: " + greenTime + "s, Red: " + redTime + "s)");
} }
} }
private void configureRouting() { private void configureRouting() {
System.out.println("\n[" + intersectionId + "] Configuring routing..."); System.out.println("\n[" + intersectionId + "] Configuring routing...");
switch (intersectionId) { switch (intersectionId) {
case "Cr1": case "Cr1":
intersection.configureRoute("Cr2", "East"); intersection.configureRoute("Cr2", "East");
intersection.configureRoute("Cr4", "South"); intersection.configureRoute("Cr4", "South");
break; break;
case "Cr2": case "Cr2":
intersection.configureRoute("Cr1", "West"); intersection.configureRoute("Cr1", "West");
intersection.configureRoute("Cr3", "East"); intersection.configureRoute("Cr3", "East");
intersection.configureRoute("Cr5", "South"); intersection.configureRoute("Cr5", "South");
break; break;
case "Cr3": case "Cr3":
intersection.configureRoute("Cr2", "West"); intersection.configureRoute("Cr2", "West");
intersection.configureRoute("S", "South"); intersection.configureRoute("S", "South");
break; break;
case "Cr4": case "Cr4":
intersection.configureRoute("Cr5", "East"); intersection.configureRoute("Cr5", "East");
break; break;
case "Cr5": case "Cr5":
intersection.configureRoute("S", "East"); intersection.configureRoute("S", "East");
break; break;
default: default:
System.err.println(" Error: unknown intersection ID: " + intersectionId); System.err.println(" Error: unknown intersection ID: " + intersectionId);
} }
System.out.println(" Routing configured."); System.out.println(" Routing configured.");
} }
/** /**
* Starts all traffic light threads. * Starts all traffic light threads.
*/ */
private void startTrafficLights() { private void startTrafficLights() {
System.out.println("\n[" + intersectionId + "] Starting traffic light threads..."); System.out.println("\n[" + intersectionId + "] Starting traffic light threads...");
for (TrafficLight light : intersection.getTrafficLights()) { for (TrafficLight light : intersection.getTrafficLights()) {
trafficLightPool.submit(() -> runTrafficLightCycle(light)); trafficLightPool.submit(() -> runTrafficLightCycle(light));
System.out.println(" Started thread for: " + light.getDirection()); System.out.println(" Started thread for: " + light.getDirection());
} }
} }
/** /**
* The main loop for a traffic light thread. * The main loop for a traffic light thread.
* Continuously cycles between green and red states. * Continuously cycles between green and red states.
@@ -191,7 +193,7 @@ public class IntersectionProcess {
*/ */
private void runTrafficLightCycle(TrafficLight light) { private void runTrafficLightCycle(TrafficLight light) {
System.out.println("[" + light.getId() + "] Traffic light thread started."); System.out.println("[" + light.getId() + "] Traffic light thread started.");
while (running) { while (running) {
try { try {
// Acquire coordination lock to become green // Acquire coordination lock to become green
@@ -203,26 +205,26 @@ public class IntersectionProcess {
Thread.sleep(100); // Brief wait before retrying Thread.sleep(100); // Brief wait before retrying
trafficCoordinationLock.lock(); trafficCoordinationLock.lock();
} }
if (!running) { if (!running) {
break; // Exit if shutting down break; // Exit if shutting down
} }
// Mark this direction as the current green light // Mark this direction as the current green light
currentGreenDirection = light.getDirection(); currentGreenDirection = light.getDirection();
light.changeState(TrafficLightState.GREEN); light.changeState(TrafficLightState.GREEN);
System.out.println("[" + light.getId() + "] State: GREEN"); System.out.println("[" + light.getId() + "] State: GREEN");
} finally { } finally {
trafficCoordinationLock.unlock(); trafficCoordinationLock.unlock();
} }
// Process vehicles while green // Process vehicles while green
processGreenLight(light); processGreenLight(light);
// Wait for green duration // Wait for green duration
Thread.sleep((long) (light.getGreenTime() * 1000)); Thread.sleep((long) (light.getGreenTime() * 1000));
// Release coordination lock (turn red) // Release coordination lock (turn red)
trafficCoordinationLock.lock(); trafficCoordinationLock.lock();
try { try {
@@ -232,19 +234,19 @@ public class IntersectionProcess {
} finally { } finally {
trafficCoordinationLock.unlock(); trafficCoordinationLock.unlock();
} }
// Wait for red duration // Wait for red duration
Thread.sleep((long) (light.getRedTime() * 1000)); Thread.sleep((long) (light.getRedTime() * 1000));
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.out.println("[" + light.getId() + "] Traffic light thread interrupted."); System.out.println("[" + light.getId() + "] Traffic light thread interrupted.");
break; break;
} }
} }
System.out.println("[" + light.getId() + "] Traffic light thread stopped."); System.out.println("[" + light.getId() + "] Traffic light thread stopped.");
} }
/** /**
* Processes vehicles when a traffic light is GREEN. * Processes vehicles when a traffic light is GREEN.
* Dequeues vehicles and sends them to their next destination. * Dequeues vehicles and sends them to their next destination.
@@ -254,11 +256,11 @@ public class IntersectionProcess {
private void processGreenLight(TrafficLight light) { private void processGreenLight(TrafficLight light) {
while (light.getState() == TrafficLightState.GREEN && light.getQueueSize() > 0) { while (light.getState() == TrafficLightState.GREEN && light.getQueueSize() > 0) {
Vehicle vehicle = light.removeVehicle(); Vehicle vehicle = light.removeVehicle();
if (vehicle != null) { if (vehicle != null) {
// Get crossing time based on vehicle type // Get crossing time based on vehicle type
double crossingTime = getCrossingTimeForVehicle(vehicle); double crossingTime = getCrossingTimeForVehicle(vehicle);
// Simulate crossing time // Simulate crossing time
try { try {
Thread.sleep((long) (crossingTime * 1000)); Thread.sleep((long) (crossingTime * 1000));
@@ -266,19 +268,19 @@ public class IntersectionProcess {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
break; break;
} }
// Update vehicle statistics // Update vehicle statistics
vehicle.addCrossingTime(crossingTime); vehicle.addCrossingTime(crossingTime);
// Update intersection statistics // Update intersection statistics
intersection.incrementVehiclesSent(); intersection.incrementVehiclesSent();
// Send vehicle to next destination // Send vehicle to next destination
sendVehicleToNextDestination(vehicle); sendVehicleToNextDestination(vehicle);
} }
} }
} }
/** /**
* Gets the crossing time for a vehicle based on its type. * Gets the crossing time for a vehicle based on its type.
* *
@@ -297,7 +299,7 @@ public class IntersectionProcess {
return config.getLightVehicleCrossingTime(); return config.getLightVehicleCrossingTime();
} }
} }
/** /**
* Sends a vehicle to its next destination via socket connection. * Sends a vehicle to its next destination via socket connection.
* *
@@ -305,56 +307,55 @@ public class IntersectionProcess {
*/ */
public void sendVehicleToNextDestination(Vehicle vehicle) { public void sendVehicleToNextDestination(Vehicle vehicle) {
String nextDestination = vehicle.getCurrentDestination(); String nextDestination = vehicle.getCurrentDestination();
try { try {
// Get or create connection to next destination // Get or create connection to next destination
SocketConnection connection = getOrCreateConnection(nextDestination); SocketConnection connection = getOrCreateConnection(nextDestination);
// Create and send message // Create and send message
MessageProtocol message = new VehicleTransferMessage( MessageProtocol message = new VehicleTransferMessage(
intersectionId, intersectionId,
nextDestination, nextDestination,
vehicle vehicle);
);
connection.sendMessage(message); connection.sendMessage(message);
System.out.println("[" + intersectionId + "] Sent vehicle " + vehicle.getId() + System.out.println("[" + intersectionId + "] Sent vehicle " + vehicle.getId() +
" to " + nextDestination); " to " + nextDestination);
// Note: vehicle route is advanced when it arrives at the next intersection // Note: vehicle route is advanced when it arrives at the next intersection
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
System.err.println("[" + intersectionId + "] Failed to send vehicle " + System.err.println("[" + intersectionId + "] Failed to send vehicle " +
vehicle.getId() + " to " + nextDestination + ": " + e.getMessage()); vehicle.getId() + " to " + nextDestination + ": " + e.getMessage());
} }
} }
/** /**
* Gets an existing connection to a destination or creates a new one. * Gets an existing connection to a destination or creates a new one.
* *
* @param destinationId The ID of the destination node. * @param destinationId The ID of the destination node.
* @return The SocketConnection to that destination. * @return The SocketConnection to that destination.
* @throws IOException If connection cannot be established. * @throws IOException If connection cannot be established.
* @throws InterruptedException If connection attempt is interrupted. * @throws InterruptedException If connection attempt is interrupted.
*/ */
private synchronized SocketConnection getOrCreateConnection(String destinationId) private synchronized SocketConnection getOrCreateConnection(String destinationId)
throws IOException, InterruptedException { throws IOException, InterruptedException {
if (!outgoingConnections.containsKey(destinationId)) { if (!outgoingConnections.containsKey(destinationId)) {
String host = getHostForDestination(destinationId); String host = getHostForDestination(destinationId);
int port = getPortForDestination(destinationId); int port = getPortForDestination(destinationId);
System.out.println("[" + intersectionId + "] Creating connection to " + System.out.println("[" + intersectionId + "] Creating connection to " +
destinationId + " at " + host + ":" + port); destinationId + " at " + host + ":" + port);
SocketConnection connection = new SocketConnection(host, port); SocketConnection connection = new SocketConnection(host, port);
outgoingConnections.put(destinationId, connection); outgoingConnections.put(destinationId, connection);
} }
return outgoingConnections.get(destinationId); return outgoingConnections.get(destinationId);
} }
/** /**
* Gets the host address for a destination node from configuration. * Gets the host address for a destination node from configuration.
* *
@@ -368,7 +369,7 @@ public class IntersectionProcess {
return config.getIntersectionHost(destinationId); return config.getIntersectionHost(destinationId);
} }
} }
/** /**
* Gets the port number for a destination node from configuration. * Gets the port number for a destination node from configuration.
* *
@@ -382,7 +383,7 @@ public class IntersectionProcess {
return config.getIntersectionPort(destinationId); return config.getIntersectionPort(destinationId);
} }
} }
/** /**
* Starts the server socket and begins accepting incoming connections. * Starts the server socket and begins accepting incoming connections.
* This is the main listening loop of the process. * This is the main listening loop of the process.
@@ -393,31 +394,43 @@ public class IntersectionProcess {
int port = config.getIntersectionPort(intersectionId); int port = config.getIntersectionPort(intersectionId);
serverSocket = new ServerSocket(port); serverSocket = new ServerSocket(port);
running = true; running = true;
System.out.println("\n[" + intersectionId + "] Server started on port " + port); System.out.println("\n[" + intersectionId + "] Server started on port " + port);
// Start traffic light threads when running is true // Start traffic light threads when running is true
startTrafficLights(); startTrafficLights();
System.out.println("[" + intersectionId + "] Waiting for incoming connections...\n"); System.out.println("[" + intersectionId + "] Waiting for incoming connections...\n");
// Main accept loop // Main accept loop
while (running) { while (running) {
try { try {
Socket clientSocket = serverSocket.accept(); Socket clientSocket = serverSocket.accept();
System.out.println("[" + intersectionId + "] New connection accepted from " +
clientSocket.getInetAddress().getHostAddress());
// Check running flag again before handling - prevents accepting during shutdown
if (!running) {
clientSocket.close();
break;
}
// Handle each connection in a separate thread // Handle each connection in a separate thread
connectionHandlerPool.submit(() -> handleIncomingConnection(clientSocket)); connectionHandlerPool.submit(() -> handleIncomingConnection(clientSocket));
} catch (IOException e) { } catch (IOException e) {
if (running) { // Expected when serverSocket.close() is called during shutdown
System.err.println("[" + intersectionId + "] Error accepting connection: " + if (!running) {
e.getMessage()); break; // Normal shutdown
} }
// Unexpected error during normal operation
System.err.println("[" + intersectionId + "] Error accepting connection: " +
e.getMessage());
} }
} }
} }
/** /**
* Handles an incoming connection from another process. * Handles an incoming connection from another process.
* Continuously listens for vehicle transfer messages. * Continuously listens for vehicle transfer messages.
@@ -426,38 +439,49 @@ public class IntersectionProcess {
*/ */
private void handleIncomingConnection(Socket clientSocket) { private void handleIncomingConnection(Socket clientSocket) {
try (SocketConnection connection = new SocketConnection(clientSocket)) { try (SocketConnection connection = new SocketConnection(clientSocket)) {
// Set socket timeout so receiveMessage() won't block forever
clientSocket.setSoTimeout(1000); // 1 second timeout
System.out.println("[" + intersectionId + "] New connection accepted from " + System.out.println("[" + intersectionId + "] New connection accepted from " +
clientSocket.getInetAddress().getHostAddress()); clientSocket.getInetAddress().getHostAddress());
// Continuously receive messages while connection is active // Continuously receive messages while connection is active
while (running && connection.isConnected()) { while (running && connection.isConnected()) {
try { try {
MessageProtocol message = connection.receiveMessage(); MessageProtocol message = connection.receiveMessage();
if (message.getType() == MessageType.VEHICLE_TRANSFER) { if (message.getType() == MessageType.VEHICLE_TRANSFER) {
Vehicle vehicle = (Vehicle) message.getPayload(); Vehicle vehicle = (Vehicle) message.getPayload();
System.out.println("[" + intersectionId + "] Received vehicle: " + System.out.println("[" + intersectionId + "] Received vehicle: " +
vehicle.getId() + " from " + message.getSourceNode()); vehicle.getId() + " from " + message.getSourceNode());
// Add vehicle to appropriate queue // Add vehicle to appropriate queue
intersection.receiveVehicle(vehicle); intersection.receiveVehicle(vehicle);
} }
} catch (java.net.SocketTimeoutException e) {
// Timeout is expected - just check running flag and continue
if (!running) {
break;
}
// Continue waiting for next message
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
System.err.println("[" + intersectionId + "] Unknown message type received: " + System.err.println("[" + intersectionId + "] Unknown message type received: " +
e.getMessage()); e.getMessage());
break; // Invalid message, close connection
} }
} }
} catch (IOException e) { } catch (IOException e) {
if (running) { if (running) {
System.err.println("[" + intersectionId + "] Connection error: " + e.getMessage()); System.err.println("[" + intersectionId + "] Connection error: " + e.getMessage());
} }
// Expected during shutdown
} }
} }
/** /**
* Stops the intersection process gracefully. * Stops the intersection process gracefully.
* Shuts down all threads and closes all connections. * Shuts down all threads and closes all connections.
@@ -465,47 +489,46 @@ public class IntersectionProcess {
public void shutdown() { public void shutdown() {
System.out.println("\n[" + intersectionId + "] Shutting down..."); System.out.println("\n[" + intersectionId + "] Shutting down...");
running = false; running = false;
// Close server socket if (serverSocket != null && !serverSocket.isClosed()) {
try { try {
if (serverSocket != null && !serverSocket.isClosed()) {
serverSocket.close(); serverSocket.close();
} catch (IOException e) {
System.err.println("[" + intersectionId + "] Error closing server socket: " +
e.getMessage());
} }
} catch (IOException e) {
System.err.println("[" + intersectionId + "] Error closing server socket: " +
e.getMessage());
} }
synchronized (outgoingConnections) {
// Shutdown thread pools for (SocketConnection conn : outgoingConnections.values()) {
try {
conn.close();
} catch (Exception e) {
// Ignore errors during shutdown
}
}
outgoingConnections.clear();
}
trafficLightPool.shutdown(); trafficLightPool.shutdown();
connectionHandlerPool.shutdown(); connectionHandlerPool.shutdownNow(); // Use shutdownNow() to interrupt running tasks
try { try {
if (!trafficLightPool.awaitTermination(5, TimeUnit.SECONDS)) { if (!trafficLightPool.awaitTermination(2, TimeUnit.SECONDS)) {
trafficLightPool.shutdownNow(); trafficLightPool.shutdownNow();
} }
if (!connectionHandlerPool.awaitTermination(5, TimeUnit.SECONDS)) { if (!connectionHandlerPool.awaitTermination(2, TimeUnit.SECONDS)) {
connectionHandlerPool.shutdownNow(); connectionHandlerPool.shutdownNow();
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
trafficLightPool.shutdownNow(); trafficLightPool.shutdownNow();
connectionHandlerPool.shutdownNow(); connectionHandlerPool.shutdownNow();
Thread.currentThread().interrupt();
} }
// Close all outgoing connections
for (Map.Entry<String, SocketConnection> entry : outgoingConnections.entrySet()) {
try {
entry.getValue().close();
} catch (IOException e) {
System.err.println("[" + intersectionId + "] Error closing connection to " +
entry.getKey() + ": " + e.getMessage());
}
}
System.out.println("[" + intersectionId + "] Shutdown complete."); System.out.println("[" + intersectionId + "] Shutdown complete.");
System.out.println("=".repeat(60)); System.out.println("=".repeat(60) + "\n");
} }
/** /**
* Gets the Intersection object managed by this process. * Gets the Intersection object managed by this process.
* Useful for testing and monitoring. * Useful for testing and monitoring.
@@ -515,40 +538,40 @@ public class IntersectionProcess {
public Intersection getIntersection() { public Intersection getIntersection() {
return intersection; return intersection;
} }
// --- Inner class for Vehicle Transfer Messages --- // --- Inner class for Vehicle Transfer Messages ---
/** /**
* Implementation of MessageProtocol for vehicle transfers between processes. * Implementation of MessageProtocol for vehicle transfers between processes.
*/ */
private static class VehicleTransferMessage implements MessageProtocol { private static class VehicleTransferMessage implements MessageProtocol {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final String sourceNode; private final String sourceNode;
private final String destinationNode; private final String destinationNode;
private final Vehicle payload; private final Vehicle payload;
public VehicleTransferMessage(String sourceNode, String destinationNode, Vehicle vehicle) { public VehicleTransferMessage(String sourceNode, String destinationNode, Vehicle vehicle) {
this.sourceNode = sourceNode; this.sourceNode = sourceNode;
this.destinationNode = destinationNode; this.destinationNode = destinationNode;
this.payload = vehicle; this.payload = vehicle;
} }
@Override @Override
public MessageType getType() { public MessageType getType() {
return MessageType.VEHICLE_TRANSFER; return MessageType.VEHICLE_TRANSFER;
} }
@Override @Override
public Object getPayload() { public Object getPayload() {
return payload; return payload;
} }
@Override @Override
public String getSourceNode() { public String getSourceNode() {
return sourceNode; return sourceNode;
} }
@Override @Override
public String getDestinationNode() { public String getDestinationNode() {
return destinationNode; return destinationNode;

View File

@@ -9,150 +9,100 @@ import sd.model.Vehicle;
/** /**
* Implements the control logic for a single TrafficLight * Implements the control logic for a single TrafficLight
* as a Runnable task that runs in its own Thread. * as a Runnable task that runs in its own Thread.
*
*/ */
public class TrafficLightThread implements Runnable { public class TrafficLightThread implements Runnable {
/**
* The TrafficLight object (the *model*) that this thread controls.
* Contains the queue and the state.
*/
private final TrafficLight light; private final TrafficLight light;
/**
* The IntersectionProcess (the Process) that "owns" this thread.
* Used to call methods on the process, such as sendVehicleToNextDestination().
*/
private final IntersectionProcess process; private final IntersectionProcess process;
/**
* The simulation configuration, used to get timings (e.g., crossing time).
*/
private final SimulationConfig config; private final SimulationConfig config;
/**
* Volatile flag to control the graceful shutdown mechanism.
* When set to 'false', the 'run()' loop terminates.
*/
private volatile boolean running; private volatile boolean running;
// Store the thread reference for proper interruption
private Thread currentThread;
/**
* Constructor for the Traffic Light Thread.
*
* @param light The TrafficLight object (model) to be controlled.
* @param process The parent IntersectionProcess (for callbacks).
* @param config The simulation configuration (to get timings).
*/
public TrafficLightThread(TrafficLight light, IntersectionProcess process, SimulationConfig config) { public TrafficLightThread(TrafficLight light, IntersectionProcess process, SimulationConfig config) {
this.light = light; this.light = light;
this.process = process; this.process = process;
this.config = config; this.config = config;
this.running = false; // Starts as 'stopped' this.running = false;
} }
/**
* The main entry point for the thread.
* Implements the GREEN/RED cycle logic extracted from IntersectionProcess.
*
*/
@Override @Override
public void run() { public void run() {
// Capture the current thread reference
this.currentThread = Thread.currentThread();
this.running = true; this.running = true;
System.out.println("[" + light.getId() + "] Traffic light thread started."); System.out.println("[" + light.getId() + "] Traffic light thread started.");
try { try {
// Main thread loop, continues while 'running' is true while (running && !Thread.currentThread().isInterrupted()) {
// This 'running' flag is controlled by the parent IntersectionProcess
while (running) {
// --- GREEN Phase --- // --- GREEN Phase ---
light.changeState(TrafficLightState.GREEN); // light.changeState(TrafficLightState.GREEN);
System.out.println("[" + light.getId() + "] State: GREEN"); System.out.println("[" + light.getId() + "] State: GREEN");
// Process vehicles in the queue
processGreenLightQueue(); processGreenLightQueue();
// Wait for green duration if (!running || Thread.currentThread().isInterrupted()) break;
Thread.sleep((long) (light.getGreenTime() * 1000)); //
if (!running) break; // Check flag after sleep // Wait for green duration
Thread.sleep((long) (light.getGreenTime() * 1000));
if (!running || Thread.currentThread().isInterrupted()) break;
// --- RED Phase --- // --- RED Phase ---
light.changeState(TrafficLightState.RED); // light.changeState(TrafficLightState.RED);
System.out.println("[" + light.getId() + "] State: RED"); System.out.println("[" + light.getId() + "] State: RED");
// Wait for red duration // Wait for red duration
Thread.sleep((long) (light.getRedTime() * 1000)); // Thread.sleep((long) (light.getRedTime() * 1000));
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
// Apanha a InterruptedException (outra forma de parar a thread)
System.out.println("[" + light.getId() + "] Traffic light thread interrupted."); System.out.println("[" + light.getId() + "] Traffic light thread interrupted.");
this.running = false; // Garante que o loop termina // Restore interrupt status
Thread.currentThread().interrupt();
} finally {
this.running = false;
System.out.println("[" + light.getId() + "] Traffic light thread stopped.");
} }
System.out.println("[" + light.getId() + "] Traffic light thread stopped.");
} }
/**
* Processes vehicles in the queue while the traffic light is GREEN.
* Logic extracted from IntersectionProcess.processGreenLight()
*
*/
private void processGreenLightQueue() throws InterruptedException { private void processGreenLightQueue() throws InterruptedException {
// while (running && !Thread.currentThread().isInterrupted()
while (running && light.getState() == TrafficLightState.GREEN && light.getQueueSize() > 0) { && light.getState() == TrafficLightState.GREEN
&& light.getQueueSize() > 0) {
Vehicle vehicle = light.removeVehicle(); // Vehicle vehicle = light.removeVehicle();
if (vehicle != null) { if (vehicle != null) {
// 1. Get the crossing time (t_sem) double crossingTime = getCrossingTimeForVehicle(vehicle);
double crossingTime = getCrossingTimeForVehicle(vehicle); //
// 2. Simulate the time the vehicle takes to cross Thread.sleep((long) (crossingTime * 1000));
Thread.sleep((long) (crossingTime * 1000)); //
// 3. Update vehicle statistics vehicle.addCrossingTime(crossingTime);
vehicle.addCrossingTime(crossingTime); // process.getIntersection().incrementVehiclesSent();
process.sendVehicleToNextDestination(vehicle);
// 4. Update intersection statistics
process.getIntersection().incrementVehiclesSent(); //
// 5. Call the parent Process to send the vehicle
process.sendVehicleToNextDestination(vehicle); //
} }
} }
} }
/**
* Gets the crossing time for a vehicle based on its type.
* Logic extracted from IntersectionProcess.getCrossingTimeForVehicle()
*
*
* @param vehicle The vehicle.
* @return The crossing time in seconds.
*/
private double getCrossingTimeForVehicle(Vehicle vehicle) { private double getCrossingTimeForVehicle(Vehicle vehicle) {
switch (vehicle.getType()) { // return switch (vehicle.getType()) {
case BIKE: case BIKE -> config.getBikeVehicleCrossingTime();
return config.getBikeVehicleCrossingTime(); // case LIGHT -> config.getLightVehicleCrossingTime();
case LIGHT: case HEAVY -> config.getHeavyVehicleCrossingTime();
return config.getLightVehicleCrossingTime(); // default -> config.getLightVehicleCrossingTime();
case HEAVY: };
return config.getHeavyVehicleCrossingTime(); //
default:
return config.getLightVehicleCrossingTime(); //
}
} }
/** /**
* Requests the thread to stop gracefully (graceful shutdown). * Requests the thread to stop gracefully.
* Sets the 'running' flag to false. The thread will finish * Sets the running flag and interrupts the thread to unblock any sleep() calls.
* its current sleep cycle and exit the 'run()' loop.
*/ */
public void shutdown() { public void shutdown() {
this.running = false; this.running = false;
if (currentThread != null && currentThread.isAlive()) {
currentThread.interrupt();
}
} }
} }

View File

@@ -1,5 +1,5 @@
import java.io.IOException; import java.io.IOException;
import java.io.ObjectOutputStream; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@@ -19,9 +19,10 @@ import sd.IntersectionProcess;
import sd.model.MessageType; import sd.model.MessageType;
import sd.model.Vehicle; import sd.model.Vehicle;
import sd.model.VehicleType; import sd.model.VehicleType;
import sd.protocol.SocketConnection;
/** /**
* Tests for IntersectionProcess - covers initialization, traffic lights, * Tests for IntersectionProcess - covers initialization, traffic lights,
* vehicle transfer and network stuff * vehicle transfer and network stuff
*/ */
public class IntersectionProcessTest { public class IntersectionProcessTest {
@@ -37,10 +38,10 @@ public class IntersectionProcessTest {
public void setUp() throws IOException { public void setUp() throws IOException {
// create temp config file // create temp config file
configFile = tempDir.resolve("test-simulation.properties"); configFile = tempDir.resolve("test-simulation.properties");
String configContent = """ String configContent = """
# Test Simulation Configuration # Test Simulation Configuration
# Intersection Network Configuration # Intersection Network Configuration
intersection.Cr1.host=localhost intersection.Cr1.host=localhost
intersection.Cr1.port=18001 intersection.Cr1.port=18001
@@ -52,15 +53,15 @@ public class IntersectionProcessTest {
intersection.Cr4.port=18004 intersection.Cr4.port=18004
intersection.Cr5.host=localhost intersection.Cr5.host=localhost
intersection.Cr5.port=18005 intersection.Cr5.port=18005
# Exit Configuration # Exit Configuration
exit.host=localhost exit.host=localhost
exit.port=18099 exit.port=18099
# Dashboard Configuration # Dashboard Configuration
dashboard.host=localhost dashboard.host=localhost
dashboard.port=18100 dashboard.port=18100
# Traffic Light Timing (seconds) # Traffic Light Timing (seconds)
trafficLight.Cr1.East.greenTime=5.0 trafficLight.Cr1.East.greenTime=5.0
trafficLight.Cr1.East.redTime=5.0 trafficLight.Cr1.East.redTime=5.0
@@ -68,31 +69,31 @@ public class IntersectionProcessTest {
trafficLight.Cr1.South.redTime=5.0 trafficLight.Cr1.South.redTime=5.0
trafficLight.Cr1.West.greenTime=5.0 trafficLight.Cr1.West.greenTime=5.0
trafficLight.Cr1.West.redTime=5.0 trafficLight.Cr1.West.redTime=5.0
trafficLight.Cr2.West.greenTime=4.0 trafficLight.Cr2.West.greenTime=4.0
trafficLight.Cr2.West.redTime=6.0 trafficLight.Cr2.West.redTime=6.0
trafficLight.Cr2.East.greenTime=4.0 trafficLight.Cr2.East.greenTime=4.0
trafficLight.Cr2.East.redTime=6.0 trafficLight.Cr2.East.redTime=6.0
trafficLight.Cr2.South.greenTime=4.0 trafficLight.Cr2.South.greenTime=4.0
trafficLight.Cr2.South.redTime=6.0 trafficLight.Cr2.South.redTime=6.0
trafficLight.Cr3.West.greenTime=3.0 trafficLight.Cr3.West.greenTime=3.0
trafficLight.Cr3.West.redTime=7.0 trafficLight.Cr3.West.redTime=7.0
trafficLight.Cr3.East.greenTime=3.0 trafficLight.Cr3.East.greenTime=3.0
trafficLight.Cr3.East.redTime=7.0 trafficLight.Cr3.East.redTime=7.0
trafficLight.Cr4.East.greenTime=6.0 trafficLight.Cr4.East.greenTime=6.0
trafficLight.Cr4.East.redTime=4.0 trafficLight.Cr4.East.redTime=4.0
trafficLight.Cr5.East.greenTime=5.0 trafficLight.Cr5.East.greenTime=5.0
trafficLight.Cr5.East.redTime=5.0 trafficLight.Cr5.East.redTime=5.0
# Vehicle Crossing Times (seconds) # Vehicle Crossing Times (seconds)
vehicle.bike.crossingTime=2.0 vehicle.bike.crossingTime=2.0
vehicle.light.crossingTime=3.0 vehicle.light.crossingTime=3.0
vehicle.heavy.crossingTime=5.0 vehicle.heavy.crossingTime=5.0
"""; """;
Files.writeString(configFile, configContent); Files.writeString(configFile, configContent);
} }
@@ -156,7 +157,7 @@ public class IntersectionProcessTest {
public void testTrafficLightCreation_Cr1_HasCorrectDirections() throws IOException { public void testTrafficLightCreation_Cr1_HasCorrectDirections() throws IOException {
intersectionProcess = new IntersectionProcess("Cr1", configFile.toString()); intersectionProcess = new IntersectionProcess("Cr1", configFile.toString());
intersectionProcess.initialize(); intersectionProcess.initialize();
// cant access private fields but initialization succeds // cant access private fields but initialization succeds
assertNotNull(intersectionProcess); assertNotNull(intersectionProcess);
} }
@@ -165,7 +166,7 @@ public class IntersectionProcessTest {
public void testTrafficLightCreation_Cr3_HasCorrectDirections() throws IOException { public void testTrafficLightCreation_Cr3_HasCorrectDirections() throws IOException {
intersectionProcess = new IntersectionProcess("Cr3", configFile.toString()); intersectionProcess = new IntersectionProcess("Cr3", configFile.toString());
intersectionProcess.initialize(); intersectionProcess.initialize();
// Cr3 has west and south only // Cr3 has west and south only
assertNotNull(intersectionProcess); assertNotNull(intersectionProcess);
} }
@@ -174,7 +175,7 @@ public class IntersectionProcessTest {
public void testTrafficLightCreation_Cr4_HasSingleDirection() throws IOException { public void testTrafficLightCreation_Cr4_HasSingleDirection() throws IOException {
intersectionProcess = new IntersectionProcess("Cr4", configFile.toString()); intersectionProcess = new IntersectionProcess("Cr4", configFile.toString());
intersectionProcess.initialize(); intersectionProcess.initialize();
// Cr4 only has east direction // Cr4 only has east direction
assertNotNull(intersectionProcess); assertNotNull(intersectionProcess);
} }
@@ -186,8 +187,8 @@ public class IntersectionProcessTest {
public void testServerStart_BindsToCorrectPort() throws IOException, InterruptedException { public void testServerStart_BindsToCorrectPort() throws IOException, InterruptedException {
intersectionProcess = new IntersectionProcess("Cr1", configFile.toString()); intersectionProcess = new IntersectionProcess("Cr1", configFile.toString());
intersectionProcess.initialize(); intersectionProcess.initialize();
// start server in seperate thread // start server in separate thread
Thread serverThread = new Thread(() -> { Thread serverThread = new Thread(() -> {
try { try {
intersectionProcess.start(); intersectionProcess.start();
@@ -196,14 +197,23 @@ public class IntersectionProcessTest {
} }
}); });
serverThread.start(); serverThread.start();
Thread.sleep(500); // wait for server to start // Wait for server to actually start with retries
boolean serverReady = false;
// try connecting to check if its running for (int i = 0; i < 20; i++) {
try (Socket clientSocket = new Socket("localhost", 18001)) { Thread.sleep(100);
assertTrue(clientSocket.isConnected()); try (Socket testSocket = new Socket()) {
testSocket.connect(new java.net.InetSocketAddress("localhost", 18001), 500);
serverReady = true;
break;
} catch (IOException e) {
// Server not ready yet, continue waiting
}
} }
assertTrue(serverReady, "Server should start and bind to port 18001");
// Shutdown immediately after confirming server is running
intersectionProcess.shutdown(); intersectionProcess.shutdown();
serverThread.join(2000); serverThread.join(2000);
} }
@@ -214,30 +224,36 @@ public class IntersectionProcessTest {
// test 2 intersections on diferent ports // test 2 intersections on diferent ports
IntersectionProcess cr1 = new IntersectionProcess("Cr1", configFile.toString()); IntersectionProcess cr1 = new IntersectionProcess("Cr1", configFile.toString());
IntersectionProcess cr2 = new IntersectionProcess("Cr2", configFile.toString()); IntersectionProcess cr2 = new IntersectionProcess("Cr2", configFile.toString());
cr1.initialize(); cr1.initialize();
cr2.initialize(); cr2.initialize();
Thread thread1 = new Thread(() -> { Thread thread1 = new Thread(() -> {
try { cr1.start(); } catch (IOException e) { } try {
cr1.start();
} catch (IOException e) {
}
}); });
Thread thread2 = new Thread(() -> { Thread thread2 = new Thread(() -> {
try { cr2.start(); } catch (IOException e) { } try {
cr2.start();
} catch (IOException e) {
}
}); });
thread1.start(); thread1.start();
thread2.start(); thread2.start();
Thread.sleep(500); Thread.sleep(500);
// check both are running // check both are running
try (Socket socket1 = new Socket("localhost", 18001); try (Socket socket1 = new Socket("localhost", 18001);
Socket socket2 = new Socket("localhost", 18002)) { Socket socket2 = new Socket("localhost", 18002)) {
assertTrue(socket1.isConnected()); assertTrue(socket1.isConnected());
assertTrue(socket2.isConnected()); assertTrue(socket2.isConnected());
} }
cr1.shutdown(); cr1.shutdown();
cr2.shutdown(); cr2.shutdown();
thread1.join(2000); thread1.join(2000);
@@ -252,33 +268,35 @@ public class IntersectionProcessTest {
// setup reciever intersection // setup reciever intersection
intersectionProcess = new IntersectionProcess("Cr2", configFile.toString()); intersectionProcess = new IntersectionProcess("Cr2", configFile.toString());
intersectionProcess.initialize(); intersectionProcess.initialize();
Thread serverThread = new Thread(() -> { Thread serverThread = new Thread(() -> {
try { try {
intersectionProcess.start(); intersectionProcess.start();
} catch (IOException e) { } } catch (IOException e) {
}
}); });
serverThread.start(); serverThread.start();
Thread.sleep(500); Thread.sleep(500);
// create test vehicle try {
java.util.List<String> route = Arrays.asList("Cr2", "Cr3", "S"); // create test vehicle - FIXED: use 4-parameter constructor
Vehicle vehicle = new Vehicle("V001", VehicleType.LIGHT, 0.0, route); java.util.List<String> route = Arrays.asList("Cr2", "Cr3", "S");
Vehicle vehicle = new Vehicle("V001", VehicleType.LIGHT, 0.0, route);
// send vehicle from Cr1 to Cr2
try (Socket socket = new Socket("localhost", 18002)) { // send vehicle from Cr1 to Cr2 - FIXED: use SocketConnection
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); try (Socket socket = new Socket("localhost", 18002);
SocketConnection conn = new SocketConnection(socket)) {
TestVehicleMessage message = new TestVehicleMessage("Cr1", "Cr2", vehicle);
out.writeObject(message); TestVehicleMessage message = new TestVehicleMessage("Cr1", "Cr2", vehicle);
out.flush(); conn.sendMessage(message);
Thread.sleep(1000); // wait for procesing Thread.sleep(1000); // wait for processing
}
} finally {
intersectionProcess.shutdown();
serverThread.join(2000);
} }
intersectionProcess.shutdown();
serverThread.join(2000);
} }
// routing config tests // routing config tests
@@ -287,7 +305,7 @@ public class IntersectionProcessTest {
public void testRoutingConfiguration_Cr1() throws IOException { public void testRoutingConfiguration_Cr1() throws IOException {
intersectionProcess = new IntersectionProcess("Cr1", configFile.toString()); intersectionProcess = new IntersectionProcess("Cr1", configFile.toString());
intersectionProcess.initialize(); intersectionProcess.initialize();
// indirect test - if init works routing should be ok // indirect test - if init works routing should be ok
assertNotNull(intersectionProcess); assertNotNull(intersectionProcess);
} }
@@ -296,7 +314,7 @@ public class IntersectionProcessTest {
public void testRoutingConfiguration_Cr5() throws IOException { public void testRoutingConfiguration_Cr5() throws IOException {
intersectionProcess = new IntersectionProcess("Cr5", configFile.toString()); intersectionProcess = new IntersectionProcess("Cr5", configFile.toString());
intersectionProcess.initialize(); intersectionProcess.initialize();
// Cr5 routes to exit // Cr5 routes to exit
assertNotNull(intersectionProcess); assertNotNull(intersectionProcess);
} }
@@ -308,19 +326,20 @@ public class IntersectionProcessTest {
public void testShutdown_GracefulTermination() throws IOException, InterruptedException { public void testShutdown_GracefulTermination() throws IOException, InterruptedException {
intersectionProcess = new IntersectionProcess("Cr1", configFile.toString()); intersectionProcess = new IntersectionProcess("Cr1", configFile.toString());
intersectionProcess.initialize(); intersectionProcess.initialize();
Thread serverThread = new Thread(() -> { Thread serverThread = new Thread(() -> {
try { try {
intersectionProcess.start(); intersectionProcess.start();
} catch (IOException e) { } } catch (IOException e) {
}
}); });
serverThread.start(); serverThread.start();
Thread.sleep(500); Thread.sleep(500);
// shutdown should be fast // shutdown should be fast
assertDoesNotThrow(() -> intersectionProcess.shutdown()); assertDoesNotThrow(() -> intersectionProcess.shutdown());
serverThread.join(2000); serverThread.join(2000);
} }
@@ -329,31 +348,36 @@ public class IntersectionProcessTest {
public void testShutdown_ClosesServerSocket() throws IOException, InterruptedException { public void testShutdown_ClosesServerSocket() throws IOException, InterruptedException {
intersectionProcess = new IntersectionProcess("Cr1", configFile.toString()); intersectionProcess = new IntersectionProcess("Cr1", configFile.toString());
intersectionProcess.initialize(); intersectionProcess.initialize();
// Start server in separate thread
Thread serverThread = new Thread(() -> { Thread serverThread = new Thread(() -> {
try { try {
intersectionProcess.start(); intersectionProcess.start();
} catch (IOException e) { } } catch (IOException e) {
// Expected on shutdown
}
}); });
serverThread.start(); serverThread.start();
// Wait for server to start
Thread.sleep(500); Thread.sleep(500);
// verify server running // Shutdown
try (Socket socket = new Socket("localhost", 18001)) {
assertTrue(socket.isConnected());
}
intersectionProcess.shutdown(); intersectionProcess.shutdown();
serverThread.join(2000); serverThread.join(2000);
// after shutdown conection should fail // Give shutdown time to complete
Thread.sleep(500); Thread.sleep(200);
Exception exception = assertThrows(IOException.class, () -> {
Socket socket = new Socket("localhost", 18001); // Verify we cannot connect (server socket is closed)
socket.close(); boolean connectionFailed = false;
}); try (Socket testSocket = new Socket()) {
assertNotNull(exception); testSocket.connect(new InetSocketAddress("localhost", 18001), 500);
} catch (IOException e) {
connectionFailed = true; // Expected - server should be closed
}
assertTrue(connectionFailed, "Server socket should be closed after shutdown");
} }
@Test @Test
@@ -361,23 +385,24 @@ public class IntersectionProcessTest {
public void testShutdown_StopsTrafficLightThreads() throws IOException, InterruptedException { public void testShutdown_StopsTrafficLightThreads() throws IOException, InterruptedException {
intersectionProcess = new IntersectionProcess("Cr1", configFile.toString()); intersectionProcess = new IntersectionProcess("Cr1", configFile.toString());
intersectionProcess.initialize(); intersectionProcess.initialize();
Thread serverThread = new Thread(() -> { Thread serverThread = new Thread(() -> {
try { try {
intersectionProcess.start(); intersectionProcess.start();
} catch (IOException e) { } } catch (IOException e) {
}
}); });
serverThread.start(); serverThread.start();
Thread.sleep(500); Thread.sleep(500);
int threadCountBefore = Thread.activeCount(); int threadCountBefore = Thread.activeCount();
intersectionProcess.shutdown(); intersectionProcess.shutdown();
serverThread.join(2000); serverThread.join(2000);
Thread.sleep(500); // wait for threads to die Thread.sleep(500); // wait for threads to die
// thread count should decrese (traffic light threads stop) // thread count should decrese (traffic light threads stop)
int threadCountAfter = Thread.activeCount(); int threadCountAfter = Thread.activeCount();
assertTrue(threadCountAfter <= threadCountBefore); assertTrue(threadCountAfter <= threadCountBefore);
@@ -388,45 +413,68 @@ public class IntersectionProcessTest {
@Test @Test
@Timeout(15) @Timeout(15)
public void testIntegration_TwoIntersectionsVehicleTransfer() throws IOException, InterruptedException { public void testIntegration_TwoIntersectionsVehicleTransfer() throws IOException, InterruptedException {
// setup 2 intersections IntersectionProcess cr1 = null;
IntersectionProcess cr1 = new IntersectionProcess("Cr1", configFile.toString()); IntersectionProcess cr2 = null;
IntersectionProcess cr2 = new IntersectionProcess("Cr2", configFile.toString()); Thread thread1 = null;
Thread thread2 = null;
cr1.initialize();
cr2.initialize(); try {
// setup 2 intersections
// start both cr1 = new IntersectionProcess("Cr1", configFile.toString());
Thread thread1 = new Thread(() -> { cr2 = new IntersectionProcess("Cr2", configFile.toString());
try { cr1.start(); } catch (IOException e) { }
}); cr1.initialize();
cr2.initialize();
Thread thread2 = new Thread(() -> {
try { cr2.start(); } catch (IOException e) { } // start both
}); final IntersectionProcess cr1Final = cr1;
thread1 = new Thread(() -> {
thread1.start(); try {
thread2.start(); cr1Final.start();
} catch (IOException e) {
Thread.sleep(1000); // wait for servers }
});
// send vehicle to Cr1 that goes to Cr2
java.util.List<String> route = Arrays.asList("Cr1", "Cr2", "S"); final IntersectionProcess cr2Final = cr2;
Vehicle vehicle = new Vehicle("V001", VehicleType.LIGHT, 0.0, route); thread2 = new Thread(() -> {
try {
try (Socket socket = new Socket("localhost", 18001)) { cr2Final.start();
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); } catch (IOException e) {
}
TestVehicleMessage message = new TestVehicleMessage("Entry", "Cr1", vehicle); });
out.writeObject(message);
out.flush(); thread1.start();
thread2.start();
Thread.sleep(2000); // time for processing
Thread.sleep(1000); // wait for servers
// send vehicle to Cr1 that goes to Cr2 - FIXED: use 4-parameter constructor
java.util.List<String> route = Arrays.asList("Cr1", "Cr2", "S");
Vehicle vehicle = new Vehicle("V001", VehicleType.LIGHT, 0.0, route);
// FIXED: use SocketConnection
try (Socket socket = new Socket("localhost", 18001);
SocketConnection conn = new SocketConnection(socket)) {
TestVehicleMessage message = new TestVehicleMessage("Entry", "Cr1", vehicle);
conn.sendMessage(message);
Thread.sleep(2000); // time for processing
}
} finally {
if (cr1 != null) {
cr1.shutdown();
}
if (cr2 != null) {
cr2.shutdown();
}
if (thread1 != null) {
thread1.join(2000);
}
if (thread2 != null) {
thread2.join(2000);
}
} }
cr1.shutdown();
cr2.shutdown();
thread1.join(2000);
thread2.join(2000);
} }
@Test @Test
@@ -439,32 +487,32 @@ public class IntersectionProcessTest {
// helper class for testing vehicle messages // helper class for testing vehicle messages
private static class TestVehicleMessage implements sd.protocol.MessageProtocol { private static class TestVehicleMessage implements sd.protocol.MessageProtocol {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final String sourceNode; private final String sourceNode;
private final String destinationNode; private final String destinationNode;
private final Vehicle payload; private final Vehicle payload;
public TestVehicleMessage(String sourceNode, String destinationNode, Vehicle vehicle) { public TestVehicleMessage(String sourceNode, String destinationNode, Vehicle vehicle) {
this.sourceNode = sourceNode; this.sourceNode = sourceNode;
this.destinationNode = destinationNode; this.destinationNode = destinationNode;
this.payload = vehicle; this.payload = vehicle;
} }
@Override @Override
public MessageType getType() { public MessageType getType() {
return MessageType.VEHICLE_TRANSFER; return MessageType.VEHICLE_TRANSFER;
} }
@Override @Override
public Object getPayload() { public Object getPayload() {
return payload; return payload;
} }
@Override @Override
public String getSourceNode() { public String getSourceNode() {
return sourceNode; return sourceNode;
} }
@Override @Override
public String getDestinationNode() { public String getDestinationNode() {
return destinationNode; return destinationNode;