Add: JavaDOC in ServerLauncher

Fix: Action error handling in the entire network stack
Modified: TCP's broadcast methods name
This commit is contained in:
2026-04-25 17:34:28 +02:00
parent 59dd27f123
commit 3a8706603c
8 changed files with 100 additions and 52 deletions
@@ -1,7 +1,6 @@
package it.polimi.ingsw.gc14.Network; package it.polimi.ingsw.gc14.Network;
import it.polimi.ingsw.gc14.Controller.GameController; import it.polimi.ingsw.gc14.Controller.GameController;
import javafx.event.Event;
import java.io.Serializable; import java.io.Serializable;
@@ -12,9 +11,23 @@ public abstract class NetworkEvent implements Serializable {
} }
protected EventType eventType; protected EventType eventType;
public EventType getEventType() {return eventType;} public EventType getEventType() {return eventType;}
protected NetworkEvent(String username, EventType eventType) { protected boolean isError;
public boolean getIsError() {return isError;}
public void setIsError(boolean isError) {this.isError = isError;}
protected NetworkEvent(String username, EventType eventType, boolean isError) {
this.username = username; this.username = username;
this.eventType = eventType; this.eventType = eventType;
this.isError = isError;
}
@Override
public String toString() {
if(isError) {
return ("ERROR: action " + eventType.toString());
} else {
return ("ACTION: action " + eventType.toString());
}
} }
public abstract boolean apply(GameController gameController); public abstract boolean apply(GameController gameController);
@@ -23,13 +23,11 @@ public class ClientCallbackImpl extends UnicastRemoteObject implements IClientCa
@Override @Override
public void onAction(NetworkEvent event) throws RemoteException { public void onAction(NetworkEvent event) throws RemoteException {
if(event.getIsError()) {
System.out.println(event.toString());
} else {
event.apply(clientController.localController); // delega tutto al controller event.apply(clientController.localController); // delega tutto al controller
//clientController.view.update(); TODO //clientController.view.update(); TODO
} }
@Override
public void onError(String message) throws RemoteException {
clientController.onError(message);
} }
} }
@@ -8,5 +8,4 @@ import java.rmi.*;
public interface IClientCallback extends Remote { public interface IClientCallback extends Remote {
void onGameInit(Game model) throws RemoteException; void onGameInit(Game model) throws RemoteException;
void onAction(NetworkEvent action) throws RemoteException; void onAction(NetworkEvent action) throws RemoteException;
void onError(String message) throws RemoteException;
} }
@@ -83,10 +83,6 @@ public class RMIServer implements IGameServer {
cb.onGameInit(model); cb.onGameInit(model);
} }
} }
public void notifyError(String username, String message) throws RemoteException {
IClientCallback cb = clients.get(username);
if (cb != null) cb.onError(message);
}
@@ -1,6 +1,7 @@
package it.polimi.ingsw.gc14.Network.TCP.Client; package it.polimi.ingsw.gc14.Network.TCP.Client;
import it.polimi.ingsw.gc14.Controller.GameController; import it.polimi.ingsw.gc14.Controller.GameController;
import it.polimi.ingsw.gc14.Model.Game;
import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.Network.NetworkEvents.AddPlayer; import it.polimi.ingsw.gc14.Network.NetworkEvents.AddPlayer;
@@ -46,7 +47,21 @@ public class TCPClient implements Serializable{
private void ReceiveMessage(){ private void ReceiveMessage(){
while(true){ while(true){
try{ try{
((NetworkEvent)(socketReceive.readObject())).apply(controller); Object read = socketReceive.readObject();
if (read instanceof NetworkEvent) { //TODO non fare con instanceof
NetworkEvent event = (NetworkEvent) read;
if(event.getIsError()) {
System.out.println(event.toString());
} else {
event.apply(controller);
//clientController.view.update(); TODO
}
}
else if (read instanceof Game) {
controller.setModel((Game) read);
}
} }
catch(IOException e){ catch(IOException e){
e.printStackTrace(); e.printStackTrace();
@@ -43,8 +43,8 @@ public class ClientHandler implements Runnable {
while(true){ while(true){
try{ try{
input = (NetworkEvent) (in.readObject()); input = (NetworkEvent) (in.readObject());
if(actionQueue.add(input)){ if(!actionQueue.add(input)){
server.broadcastUpdate(input); System.out.println("An error occurred in inserting an action into queue");
} }
} }
catch(java.io.IOException e){ catch(java.io.IOException e){
@@ -53,8 +53,6 @@ public class ClientHandler implements Runnable {
catch (ClassNotFoundException e){ catch (ClassNotFoundException e){
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
} }
catch (IOException e) { catch (IOException e) {
@@ -118,11 +118,11 @@ public class TCPServer {
this.playerList = players; this.playerList = players;
} }
public void broadcastUpdate(NetworkEvent event){ public void notifAll(NetworkEvent event){
clientHandlers.forEach((x) -> x.notifyEvent(event)); clientHandlers.forEach((x) -> x.notifyEvent(event));
} }
public void broadcastModel(Game model){ public void notifyAll(Game model){
clientHandlers.forEach((x) -> x.notifyModel(model)); clientHandlers.forEach((x) -> x.notifyModel(model));
} }
} }
@@ -12,7 +12,7 @@ import java.rmi.RemoteException;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
public class ServerLauncher {
/** /**
* Main server launcher that handles both TCP and RMI connections. * Main server launcher that handles both TCP and RMI connections.
* The workflow is divided into two parts: game creation and game execution. * The workflow is divided into two parts: game creation and game execution.
@@ -31,15 +31,39 @@ public class ServerLauncher {
* - If the event is successfully applied to the model, all players receive the event * - If the event is successfully applied to the model, all players receive the event
* - Otherwise, the player who sent the action receives an error notification * - Otherwise, the player who sent the action receives an error notification
*/ */
public class ServerLauncher {
/**
* List containing the events that have to be applied to the game's model.
* Thread safe by design.
*/
BlockingQueue<NetworkEvent> actionQueue; BlockingQueue<NetworkEvent> actionQueue;
/** Game controller. Used to apply events */
GameController gameController; GameController gameController;
/** Server RMI. Handles RMI clients */
RMIServer serverRMI; RMIServer serverRMI;
/** Server TCP. Handles TCP clients */
TCPServer serverTCP; TCPServer serverTCP;
/**
* List containing the username of joined players.
* {@link LimitedList}'s limit defines at which size the list calls its action
* Both limit and action can be set with {@link LimitedList#setLimit(int)} and {@link LimitedList#setAction(Runnable)}
* The limit is set by the first player joining the game. The action consists in calling {@link #run()}
*/
static LimitedList<String> playerList; static LimitedList<String> playerList;
/**
* Class constructor that initializes the attributes.
* @param actionQueue is the list containing the events
* @param gameController is the game controller
* @param serverRMI is the server RMI
* @param serverTCP is the server TCP
*/
public ServerLauncher(BlockingQueue<NetworkEvent> actionQueue, GameController gameController, RMIServer serverRMI, TCPServer serverTCP) { public ServerLauncher(BlockingQueue<NetworkEvent> actionQueue, GameController gameController, RMIServer serverRMI, TCPServer serverTCP) {
this.actionQueue = actionQueue; this.actionQueue = actionQueue;
this.serverRMI = serverRMI; this.serverRMI = serverRMI;
@@ -47,17 +71,22 @@ public class ServerLauncher {
this.serverTCP = serverTCP; this.serverTCP = serverTCP;
} }
/**
* Takes the first event in the actionQueue and attempt to apply it to the game controller.
* If the event can be applied, all clients (both TCP and RMI) are notified with the event. Otherwise, the user who sent the action will be notified with an error.
* @return the outcome of attempting to apply the event to the controller
* @throws InterruptedException if any problem in accessing actionQueue is issued
* @throws RemoteException if any RMI problem is issued
*/
public boolean doFirstEvent() throws InterruptedException, RemoteException { public boolean doFirstEvent() throws InterruptedException, RemoteException {
NetworkEvent event = actionQueue.take(); NetworkEvent event = actionQueue.take();
if(event.apply(gameController)) { event.setIsError(!event.apply(gameController));
serverRMI.notifyAll(event); serverRMI.notifyAll(event);
serverTCP.broadcastUpdate(event); serverTCP.notifAll(event);
return true;
} else { return !event.getIsError();
serverRMI.notifyError(event.getUsername(), "Mossa non valida"); // TODO Converrebbe mettere in network event un booleano che dice se è stato accettato e fare una notifyAll anche per errori
//serverTCP // TODO non esiste un notify error (guarda sopra)
return false;
}
} }
@@ -91,7 +120,7 @@ public class ServerLauncher {
public void run() throws InterruptedException, RemoteException { public void run() throws InterruptedException, RemoteException {
serverRMI.notifyAll(gameController.getModel()); serverRMI.notifyAll(gameController.getModel());
serverTCP.broadcastModel(gameController.getModel()); serverTCP.notifyAll(gameController.getModel());
// Game execution // Game execution