Various bug fixes

- Fixed bug where an invalid port number would crash the program
- Closed the stage before cleaning up resources. This speeds up closing the app.
- Added error handling for when the client looses connection to the server.

Tags: #story[1281]
This commit is contained in:
Michael Rausch
2017-09-27 17:14:55 +13:00
parent 67f3124cfb
commit 2b3a972ed5
10 changed files with 95 additions and 39 deletions
@@ -77,9 +77,9 @@ public class MessageFactory {
} }
public static void updateBoats(List<ServerYacht> yachts) { public static void updateBoats(List<ServerYacht> yachts) {
for (ServerYacht serverYacht : yachts) { // for (ServerYacht serverYacht : yachts) {
System.out.println(serverYacht); // System.out.println(serverYacht);
} // }
xmlGenerator.getRace().setBoats(yachts); xmlGenerator.getRace().setBoats(yachts);
String xmlStr = xmlGenerator.getBoatsAsXml(); String xmlStr = xmlGenerator.getBoatsAsXml();
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length()); MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
@@ -1,5 +1,7 @@
package seng302.gameServer; package seng302.gameServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.discoveryServer.DiscoveryServerClient; import seng302.discoveryServer.DiscoveryServerClient;
import seng302.discoveryServer.util.ServerListing; import seng302.discoveryServer.util.ServerListing;
@@ -38,6 +40,7 @@ public class ServerAdvertiser {
private DiscoveryServerClient repositoryClient; private DiscoveryServerClient repositoryClient;
private Hashtable<String ,String> props; private Hashtable<String ,String> props;
private Logger logger = LoggerFactory.getLogger(ServerAdvertiser.class);
private ServerAdvertiser() throws IOException{ private ServerAdvertiser() throws IOException{
jmdnsInstance = JmDNS.create(InetAddress.getByName(getLocalHostIp())); jmdnsInstance = JmDNS.create(InetAddress.getByName(getLocalHostIp()));
@@ -128,7 +131,7 @@ public class ServerAdvertiser {
try { try {
jmdnsInstance.registerService(serviceInfo); jmdnsInstance.registerService(serviceInfo);
} catch (IOException e) { } catch (IOException e) {
System.out.println("Failed"); logger.warn("Failed to register service info");
} }
} }
}, 0); }, 0);
@@ -136,7 +136,6 @@ public class StreamParser {
long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14)); long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14));
String xmlMessage = new String( String xmlMessage = new String(
(Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim(); (Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim();
System.out.println(xmlMessage);
//Create XML document Object //Create XML document Object
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db; DocumentBuilder db;
@@ -1,6 +1,7 @@
package seng302.utilities; package seng302.utilities;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -380,7 +381,7 @@ public class XMLParser {
/** /**
* This ungodly combination of existing methods and code blocks parses a race definition file. * This ungodly combination of existing methods and code blocks parses a race definition file.
* Look upon it and despair. * Look upon it and despair.
* @param url the location of the race def file * @param url The input file path
* @param serverName the name of the server * @param serverName the name of the server
* @param repetitions the repetitions of a segment of the race def file. * @param repetitions the repetitions of a segment of the race def file.
* @param maxPlayers max number of players. uses the default race max if null or greater than the actual max. * @param maxPlayers max number of players. uses the default race max if null or greater than the actual max.
@@ -395,7 +396,7 @@ public class XMLParser {
Document doc = null; Document doc = null;
try { try {
db = dbf.newDocumentBuilder(); db = dbf.newDocumentBuilder();
doc = db.parse(url); doc = db.parse(XMLParser.class.getResourceAsStream(url));
} catch (ParserConfigurationException | IOException | SAXException e) { } catch (ParserConfigurationException | IOException | SAXException e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -57,6 +57,11 @@ public class ClientToServerThread implements Runnable {
void notifyDisconnection(String message); void notifyDisconnection(String message);
} }
@FunctionalInterface
public interface ConnectionErrorListener {
void notifyConnectionError(String message);
}
private class ByteReadException extends Exception { private class ByteReadException extends Exception {
private ByteReadException(String message) { private ByteReadException(String message) {
super(message); super(message);
@@ -66,6 +71,7 @@ public class ClientToServerThread implements Runnable {
private Queue<StreamPacket> streamPackets = new ConcurrentLinkedQueue<>(); private Queue<StreamPacket> streamPackets = new ConcurrentLinkedQueue<>();
private List<ClientSocketListener> listeners = new ArrayList<>(); private List<ClientSocketListener> listeners = new ArrayList<>();
private List<DisconnectedFromHostListener> disconnectionListeners = new ArrayList<>(); private List<DisconnectedFromHostListener> disconnectionListeners = new ArrayList<>();
private ConnectionErrorListener connectionErrorListener = null;
private Thread thread; private Thread thread;
private Socket socket; private Socket socket;
@@ -183,6 +189,18 @@ public class ClientToServerThread implements Runnable {
} }
} }
private void handleConnectionError(String message){
if (connectionErrorListener != null){
connectionErrorListener.notifyConnectionError(message);
}
try {
this.socket.close();
} catch (IOException e) {
logger.error("Couldn't close socket");
}
}
/** /**
* Sends a request to the server asking for a source ID * Sends a request to the server asking for a source ID
*/ */
@@ -212,6 +230,7 @@ public class ClientToServerThread implements Runnable {
return; return;
} }
logger.error("Server Denied Connection, Exiting"); logger.error("Server Denied Connection, Exiting");
final String alertErrorText; final String alertErrorText;
@@ -222,6 +241,7 @@ public class ClientToServerThread implements Runnable {
else{ else{
alertErrorText = "Could not connect to server"; alertErrorText = "Could not connect to server";
} }
handleConnectionError("Server no longer available.");
notifyDisconnectListeners(alertErrorText); notifyDisconnectListeners(alertErrorText);
closeSocket(); closeSocket();
} }
@@ -351,6 +371,12 @@ public class ClientToServerThread implements Runnable {
} }
} }
public void setConnectionErrorListener(ConnectionErrorListener listener){
synchronized (this){
connectionErrorListener = listener;
}
}
private int readByte() throws ByteReadException { private int readByte() throws ByteReadException {
int currentByte = -1; int currentByte = -1;
try { try {
@@ -365,6 +391,7 @@ public class ClientToServerThread implements Runnable {
notifyDisconnectListeners("Cannot read from server."); notifyDisconnectListeners("Cannot read from server.");
closeSocket(); closeSocket();
logger.warn("InputStream reach end of stream", 1); logger.warn("InputStream reach end of stream", 1);
handleConnectionError("Could not connect to server. Server is no longer available.");
} }
return currentByte; return currentByte;
} }
@@ -119,13 +119,23 @@ public class GameClient {
ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName()); ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName());
ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName()); ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName());
getServerThread().setConnectionErrorListener((eMessage) -> {
ViewManager.getInstance().showErrorSnackBar(eMessage);
destroyClientToServerThread();
});
this.lobbyController = ViewManager.getInstance().goToLobby(true); this.lobbyController = ViewManager.getInstance().goToLobby(true);
} catch (IOException ioe) { } catch (IOException ioe) {
ViewManager.getInstance().showErrorSnackBar("Unable to find server"); ViewManager.getInstance().showErrorSnackBar("There are no servers currently available.");
} }
} }
private void destroyClientToServerThread() {
socketThread.closeSocket();
socketThread = null;
}
/** /**
* Connect to a game as the host at the given address and starts the visualiser. * Connect to a game as the host at the given address and starts the visualiser.
* @param ipAddress IP to connect to. * @param ipAddress IP to connect to.
@@ -224,7 +234,6 @@ public class GameClient {
break; break;
case RACE_XML: case RACE_XML:
System.out.println("HEY I GOT A RACE MANG AND I AM CLIENT " + ((Boolean) (server==null)).toString());
RaceXMLData raceXMLData = XMLParser.parseRace( RaceXMLData raceXMLData = XMLParser.parseRace(
StreamParser.extractXmlMessage(packet) StreamParser.extractXmlMessage(packet)
); );
+13 -7
View File
@@ -4,6 +4,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.util.Pair; import javafx.util.Pair;
@@ -34,6 +35,8 @@ public class MapMaker {
private int index = 0; private int index = 0;
private XMLGenerator xmlGenerator = new XMLGenerator(); private XMLGenerator xmlGenerator = new XMLGenerator();
private List<String> maps = new ArrayList<>(Arrays.asList("default.xml", "horseshoe.xml"));
public static MapMaker getInstance() { public static MapMaker getInstance() {
if (instance == null) { if (instance == null) {
instance = new MapMaker(); instance = new MapMaker();
@@ -42,15 +45,17 @@ public class MapMaker {
} }
private MapMaker() { private MapMaker() {
File dir = new File(MapMaker.class.getResource("/maps/").getPath()); for (String mapPath : maps){
File[] directoryListing = dir.listFiles(); String path = ("/maps/" + mapPath);
if (directoryListing != null) {
for (File child : directoryListing) {
Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef( Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef(
child.getAbsolutePath(), "", 1, null, false path, "", 1, null, false
); );
filePaths.add(child.getAbsolutePath());
RegattaXMLTemplate regattaTemplate = regattaRace.getKey(); RegattaXMLTemplate regattaTemplate = regattaRace.getKey();
filePaths.add(path);
regattas.add(new RegattaXMLData( regattas.add(new RegattaXMLData(
regattaTemplate.getRegattaId(), regattaTemplate.getRegattaId(),
regattaTemplate.getName(), regattaTemplate.getName(),
@@ -79,9 +84,10 @@ public class MapMaker {
new ArrayList<>(race.getCompoundMarks().values()), new ArrayList<>(race.getCompoundMarks().values()),
race.getMarkSequence(), race.getCourseLimit() race.getMarkSequence(), race.getCourseLimit()
)); ));
races.add(race); races.add(race);
} }
}
} }
public void next() { public void next() {
@@ -272,6 +272,8 @@ public class ViewManager {
} }
private void closeAll() { private void closeAll() {
if (stage!= null) stage.close();
try { try {
ServerAdvertiser.getInstance().unregister(); ServerAdvertiser.getInstance().unregister();
} catch (IOException e1) { } catch (IOException e1) {
@@ -50,6 +50,15 @@ public class DirectConnectController implements Initializable {
*/ */
private void connectToServer() { private void connectToServer() {
//TODO fix port number validation //TODO fix port number validation
try{
Integer.parseInt(portNumber.getText());
}
catch (NumberFormatException e){
ViewManager.getInstance().showErrorSnackBar("You need to enter a valid port number");
return;
}
ViewManager.getInstance().getGameClient() ViewManager.getInstance().getGameClient()
.runAsClient(serverAddress.getText(), Integer.parseInt(portNumber.getText())); .runAsClient(serverAddress.getText(), Integer.parseInt(portNumber.getText()));
} }
+1 -1
View File
@@ -1,4 +1,4 @@
/* a separate file to dynamically change snackbar's color */ /* a separate file to dynamically change snackbar's color */
.jfx-snackbar-toast { .jfx-snackbar-toast {
-fx-text-fill: red !important; -fx-text-fill: black !important;
} }