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
@@ -57,6 +57,11 @@ public class ClientToServerThread implements Runnable {
void notifyDisconnection(String message);
}
@FunctionalInterface
public interface ConnectionErrorListener {
void notifyConnectionError(String message);
}
private class ByteReadException extends Exception {
private ByteReadException(String message) {
super(message);
@@ -66,6 +71,7 @@ public class ClientToServerThread implements Runnable {
private Queue<StreamPacket> streamPackets = new ConcurrentLinkedQueue<>();
private List<ClientSocketListener> listeners = new ArrayList<>();
private List<DisconnectedFromHostListener> disconnectionListeners = new ArrayList<>();
private ConnectionErrorListener connectionErrorListener = null;
private Thread thread;
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
*/
@@ -212,6 +230,7 @@ public class ClientToServerThread implements Runnable {
return;
}
logger.error("Server Denied Connection, Exiting");
final String alertErrorText;
@@ -222,6 +241,7 @@ public class ClientToServerThread implements Runnable {
else{
alertErrorText = "Could not connect to server";
}
handleConnectionError("Server no longer available.");
notifyDisconnectListeners(alertErrorText);
closeSocket();
}
@@ -351,6 +371,12 @@ public class ClientToServerThread implements Runnable {
}
}
public void setConnectionErrorListener(ConnectionErrorListener listener){
synchronized (this){
connectionErrorListener = listener;
}
}
private int readByte() throws ByteReadException {
int currentByte = -1;
try {
@@ -365,6 +391,7 @@ public class ClientToServerThread implements Runnable {
notifyDisconnectListeners("Cannot read from server.");
closeSocket();
logger.warn("InputStream reach end of stream", 1);
handleConnectionError("Could not connect to server. Server is no longer available.");
}
return currentByte;
}
@@ -119,13 +119,23 @@ public class GameClient {
ViewManager.getInstance().setProperty("serverName", regattaData.getRegattaName());
ViewManager.getInstance().setProperty("mapName", regattaData.getCourseName());
getServerThread().setConnectionErrorListener((eMessage) -> {
ViewManager.getInstance().showErrorSnackBar(eMessage);
destroyClientToServerThread();
});
this.lobbyController = ViewManager.getInstance().goToLobby(true);
} 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.
* @param ipAddress IP to connect to.
@@ -224,7 +234,6 @@ public class GameClient {
break;
case RACE_XML:
System.out.println("HEY I GOT A RACE MANG AND I AM CLIENT " + ((Boolean) (server==null)).toString());
RaceXMLData raceXMLData = XMLParser.parseRace(
StreamParser.extractXmlMessage(packet)
);
+34 -28
View File
@@ -4,6 +4,7 @@ import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javafx.scene.Node;
import javafx.util.Pair;
@@ -34,6 +35,8 @@ public class MapMaker {
private int index = 0;
private XMLGenerator xmlGenerator = new XMLGenerator();
private List<String> maps = new ArrayList<>(Arrays.asList("default.xml", "horseshoe.xml"));
public static MapMaker getInstance() {
if (instance == null) {
instance = new MapMaker();
@@ -42,46 +45,49 @@ public class MapMaker {
}
private MapMaker() {
File dir = new File(MapMaker.class.getResource("/maps/").getPath());
File[] directoryListing = dir.listFiles();
if (directoryListing != null) {
for (File child : directoryListing) {
Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef(
child.getAbsolutePath(), "", 1, null, false
);
filePaths.add(child.getAbsolutePath());
RegattaXMLTemplate regattaTemplate = regattaRace.getKey();
regattas.add(new RegattaXMLData(
for (String mapPath : maps){
String path = ("/maps/" + mapPath);
Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef(
path, "", 1, null, false
);
RegattaXMLTemplate regattaTemplate = regattaRace.getKey();
filePaths.add(path);
regattas.add(new RegattaXMLData(
regattaTemplate.getRegattaId(),
regattaTemplate.getName(),
regattaTemplate.getCourseName(),
regattaTemplate.getLatitude(),
regattaTemplate.getLongitude(),
regattaTemplate.getUtcOffset()
));
));
RaceXMLTemplate raceTemplate = regattaRace.getValue();
xmlGenerator.setRaceTemplate(raceTemplate);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
Document doc = null;
try {
db = dbf.newDocumentBuilder();
doc = db.parse(new InputSource(new StringReader(xmlGenerator.getRaceAsXml())));
} catch (ParserConfigurationException | IOException | SAXException e) {
e.printStackTrace();
}
RaceXMLTemplate raceTemplate = regattaRace.getValue();
xmlGenerator.setRaceTemplate(raceTemplate);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
Document doc = null;
try {
db = dbf.newDocumentBuilder();
doc = db.parse(new InputSource(new StringReader(xmlGenerator.getRaceAsXml())));
} catch (ParserConfigurationException | IOException | SAXException e) {
e.printStackTrace();
}
RaceXMLData race = XMLParser.parseRace(doc);
maxPlayers.add(XMLParser.getMaxPlayers(doc));
RaceXMLData race = XMLParser.parseRace(doc);
maxPlayers.add(XMLParser.getMaxPlayers(doc));
mapPreviews.add(new MapPreview(
mapPreviews.add(new MapPreview(
new ArrayList<>(race.getCompoundMarks().values()),
race.getMarkSequence(), race.getCourseLimit()
));
races.add(race);
}
));
races.add(race);
}
}
public void next() {
@@ -272,6 +272,8 @@ public class ViewManager {
}
private void closeAll() {
if (stage!= null) stage.close();
try {
ServerAdvertiser.getInstance().unregister();
} catch (IOException e1) {
@@ -50,6 +50,15 @@ public class DirectConnectController implements Initializable {
*/
private void connectToServer() {
//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()
.runAsClient(serverAddress.getText(), Integer.parseInt(portNumber.getText()));
}