LatestMessages can hold MarkRounding messages. It also holds XMLMessage for each message type.

MockOutput now uses LatestMessages for xml messages.
Moved xml message encoding into RaceVisionByteEncoder. Removed XMLMessageEncoder.
Moved XML message sub types into an enumeration (XMLMessageType).
XMLMessage can now be queried for its attributes (like timestamp, length, etc...).

VisualiserInput now uses LatestMessages.
VisualiserInput now (as it did previously) uses switch statements for checking packet type, instead of if statements.
VisualiserRace now uses LatestMessages instead of VisualiserInput.
This commit is contained in:
fjc40
2017-07-07 02:05:21 +12:00
parent 8e18ad62ca
commit f057ad58b7
20 changed files with 767 additions and 418 deletions
@@ -3,7 +3,9 @@ package mock.app;
import mock.model.MockRace;
import mock.model.Polars;
import network.Messages.Enums.MessageType;
import network.Messages.Enums.XMLMessageType;
import network.Messages.LatestMessages;
import network.Messages.XMLMessage;
import org.xml.sax.SAXException;
import shared.dataInput.*;
import shared.exceptions.InvalidBoatDataException;
@@ -79,13 +81,10 @@ public class Event {
private void sendXMLs() {
mockOutput.setRegattaXml(regattaXML);
mockOutput.parseXMLString(regattaXML, MessageType.XMLMESSAGE.getValue());
mockOutput.setRaceXml(raceXML);
mockOutput.parseXMLString(raceXML, MessageType.XMLMESSAGE.getValue());
mockOutput.setBoatsXml(boatXML);
mockOutput.parseXMLString(boatXML, MessageType.XMLMESSAGE.getValue());
}
/**
@@ -4,38 +4,46 @@ package mock.app;
import network.BinaryMessageEncoder;
import network.MessageEncoders.RaceVisionByteEncoder;
import network.MessageEncoders.XMLMessageEncoder;
import network.Messages.BoatLocation;
import network.Messages.*;
import network.Messages.Enums.MessageType;
import network.Messages.LatestMessages;
import network.Messages.RaceStatus;
import network.Messages.XMLMessage;
import network.Messages.Enums.XMLMessageType;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.ArrayBlockingQueue;
/**
* TCP server to send race information to connected clients.
*/
public class MockOutput implements Runnable
{
///Timestamp of the last sent heartbeat message.
/**
* Timestamp of the last sent heartbeat message.
*/
private long lastHeartbeatTime;
///Period for the heartbeat - that is, how often we send it.
/**
* Period for the heartbeat - that is, how often we send it.
*/
private double heartbeatPeriod = 5.0;
///Port to expose server on.
/**
* Port to expose server on.
*/
private int serverPort = 4942;
///Socket used to listen for clients on.
/**
* Socket used to listen for clients on.
*/
private ServerSocket serverSocket;
///Socket used to communicate with a client.
/**
* Socket used to communicate with a client.
*/
private Socket mockSocket;
///Output stream which wraps around mockSocket outstream.
/**
* Output stream which wraps around mockSocket outstream.
*/
private DataOutputStream outToVisualiser;
@@ -47,17 +55,32 @@ public class MockOutput implements Runnable
///Sequence numbers used in messages.
private short messageNumber = 1;
private short xmlSequenceNumber = 1;
/**
* Ack numbers used in messages.
*/
private int ackNumber = 1;
/**
* Sequence number for race xml messages.
*/
private short raceXMLSequenceNumber = 1;
/**
* Sequence number for boat xml messages.
*/
private short boatXMLSequenceNumber = 1;
/**
* Sequence number for regatta xml messages.
*/
private short regattaXMLSequenceNumber = 1;
/**
* Sequence number for heartbeat messages.
*/
private int heartbeatSequenceNum = 1;
private int boatLocationSequenceNumber = 1;
private int raceStatusSequenceNumber = 1;
///Strings containing XML data as strings.
private String raceXml;
private String regattaXml;
private String boatsXml;
private boolean stop = false; //whether or not hte thread keeps running
@@ -74,6 +97,19 @@ public class MockOutput implements Runnable
this.latestMessages = latestMessages;
}
/**
* Increments the ackNumber value, and returns it.
* @return Incremented ackNumber.
*/
private int getNextAckNumber(){
this.ackNumber++;
return this.ackNumber;
}
/**
* Calculates the time since last heartbeat message, in seconds.
* @return Time since last heartbeat message, in seconds.
@@ -83,56 +119,105 @@ public class MockOutput implements Runnable
return (now - lastHeartbeatTime) / 1000.0;
}
//returns the heartbeat message
/**
* Increment the heartbeat value
* @return message for heartbeat data
* Generates the next heartbeat message and returns it. Increments the heartbeat sequence number.
* @return The next heartbeat message.
*/
private byte[] heartbeat(){
byte[] heartbeatMessage = RaceVisionByteEncoder.heartBeat(heartbeatSequenceNum);
private Heartbeat createHeartbeatMessage() {
//Create the heartbeat message.
Heartbeat heartbeat = new Heartbeat(this.heartbeatSequenceNum);
heartbeatSequenceNum++;
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.HEARTBEAT, System.currentTimeMillis(), messageNumber, (short)heartbeatMessage.length, heartbeatMessage);
messageNumber++;
return binaryMessageEncoder.getFullMessage();
return heartbeat;
}
/**
* Used to give the mockOutput an xml string to be made into a message and sent
* @param xmlString the xml string to send
* @param messageType the kind of xml string, values given in AC35 spec (5 regatta, 6 race, 7 boat)
* Serializes a heartbeat message into a packet to be sent, and returns the byte array.
* @param heartbeat The heartbeat message to serialize.
* @return Byte array containing the next heartbeat message.
*/
public synchronized byte[] parseXMLString(String xmlString, int messageType) {
private byte[] parseHeartbeat(Heartbeat heartbeat) {
XMLMessageEncoder encoder = new XMLMessageEncoder(
messageNumber,
//Serializes the heartbeat message.
byte[] heartbeatMessage = RaceVisionByteEncoder.heartBeat(heartbeat);
//Places the serialized message in a packet.
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
MessageType.HEARTBEAT,
System.currentTimeMillis(),
getNextAckNumber(),
(short) heartbeatMessage.length,
heartbeatMessage );
return binaryMessageEncoder.getFullMessage();
}
/**
* Creates an XMLMessage of a specified subtype using the xml contents string.
* @param xmlString The contents of the xml file.
* @param messageType The subtype of xml message (race, regatta, boat).
* @return The created XMLMessage object.
*/
private XMLMessage createXMLMessage(String xmlString, XMLMessageType messageType) {
//Get the correct sequence number to use, and increment it.
short sequenceNumber = 0;
if (messageType == XMLMessageType.RACE) {
sequenceNumber = this.raceXMLSequenceNumber;
this.raceXMLSequenceNumber++;
} else if (messageType == XMLMessageType.BOAT) {
sequenceNumber = this.boatXMLSequenceNumber;
this.boatXMLSequenceNumber++;
} else if (messageType == XMLMessageType.REGATTA) {
sequenceNumber = this.regattaXMLSequenceNumber;
this.regattaXMLSequenceNumber++;
}
//Create the message.
XMLMessage message = new XMLMessage(
XMLMessage.currentVersionNumber,
getNextAckNumber(),
System.currentTimeMillis(),
messageType,
xmlSequenceNumber,
(short) xmlString.length(),
xmlString);
sequenceNumber,
xmlString );
//iterates the sequence numbers
xmlSequenceNumber++;
return message;
}
byte[] encodedXML = encoder.encode();
/**
* Encodes/serialises a XMLMessage message, and returns it.
* @param xmlMessage The XMLMessage message to serialise.
* @return The XMLMessage message in a serialised form.
*/
private synchronized byte[] parseXMLMessage(XMLMessage xmlMessage) {
//Serialize the xml message.
byte[] encodedXML = RaceVisionByteEncoder.xmlMessage(xmlMessage);
//Place the message in a packet.
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
MessageType.XMLMESSAGE,
System.currentTimeMillis(),
messageNumber,
(short)encodedXML.length,
encodedXML);
xmlMessage.getAckNumber(), //We use the ack number from the xml message.
(short) encodedXML.length,
encodedXML );
//iterates the message number
messageNumber++;
return binaryMessageEncoder.getFullMessage();
}
/**
* Encodes/serialises a BoatLocation message, and returns it.
* @param boatLocation The BoatLocation message to serialise.
@@ -148,12 +233,10 @@ public class MockOutput implements Runnable
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
MessageType.BOATLOCATION,
System.currentTimeMillis(),
messageNumber,
getNextAckNumber(),
(short) encodedBoatLoc.length,
encodedBoatLoc );
//iterates the message number
messageNumber++;
return binaryMessageEncoder.getFullMessage();
@@ -166,9 +249,6 @@ public class MockOutput implements Runnable
*/
private synchronized byte[] parseRaceStatus(RaceStatus raceStatus){
//iterates the sequence number
raceStatusSequenceNumber++;
//Encodes the messages.
byte[] encodedRaceStatus = RaceVisionByteEncoder.raceStatus(raceStatus);
@@ -176,12 +256,10 @@ public class MockOutput implements Runnable
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
MessageType.RACESTATUS,
System.currentTimeMillis(),
messageNumber,
getNextAckNumber(),
(short) encodedRaceStatus.length,
encodedRaceStatus );
//iterates the message number
messageNumber++;
return binaryMessageEncoder.getFullMessage();
@@ -196,12 +274,14 @@ public class MockOutput implements Runnable
try {
while (!stop){
//Wait for a client to connect.
System.out.println("Waiting for a connection...");//TEMP DEBUG REMOVE
mockSocket = serverSocket.accept();
outToVisualiser = new DataOutputStream(mockSocket.getOutputStream());
if (boatsXml == null || regattaXml == null || raceXml == null) {
//Wait until all of the xml files have been set.
if (!this.latestMessages.hasAllXMLMessages()) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
@@ -210,11 +290,6 @@ public class MockOutput implements Runnable
continue;
}
//Encode xml files. We send them inside the loop, depending on the sentXMLs boolean.
byte[] raceXMLBlob = parseXMLString(raceXml, XMLMessage.XMLTypeRace);
byte[] regattaXMLBlob = parseXMLString(regattaXml, XMLMessage.XMLTypeRegatta);
byte[] boatsXMLBlob = parseXMLString(boatsXml, XMLMessage.XMLTypeBoat);
long previousFrameTime = System.currentTimeMillis();
boolean sentXMLs = false;
@@ -234,19 +309,25 @@ public class MockOutput implements Runnable
//Sends a heartbeat every so often.
if (timeSinceHeartbeat() >= heartbeatPeriod) {
outToVisualiser.write(heartbeat());
outToVisualiser.write(parseHeartbeat(createHeartbeatMessage()));
lastHeartbeatTime = System.currentTimeMillis();
}
//Send XML messages.
if (!sentXMLs) {
//Serialise them.
byte[] raceXMLBlob = parseXMLMessage(latestMessages.getRaceXMLMessage());
byte[] regattaXMLBlob = parseXMLMessage(latestMessages.getRegattaXMLMessage());
byte[] boatsXMLBlob = parseXMLMessage(latestMessages.getBoatXMLMessage());
//Send them.
outToVisualiser.write(raceXMLBlob);
outToVisualiser.write(regattaXMLBlob);
outToVisualiser.write(boatsXMLBlob);
sentXMLs = true;
}
//Sens the RaceStatus message.
//Sends the RaceStatus message.
if (this.latestMessages.getRaceStatus() != null) {
byte[] raceStatusBlob = this.parseRaceStatus(this.latestMessages.getRaceStatus());
@@ -305,29 +386,42 @@ public class MockOutput implements Runnable
}
/**
* Sets the Race XML to send
* @param raceXml XML to send to the CLient
* Sets the Race XML to send.
* @param raceXml XML to send to the Client.
*/
public void setRaceXml(String raceXml) {
this.raceXml = raceXml;
//Create the message.
XMLMessage message = this.createXMLMessage(raceXml, XMLMessageType.RACE);
//Place it in LatestMessages.
this.latestMessages.setRaceXMLMessage(message);
}
/**
* Sets the Regatta XMl to send
* @param regattaXml XML to send to CLient
* Sets the Regatta XMl to send.
* @param regattaXml XML to send to Client.
*/
public void setRegattaXml(String regattaXml) {
this.regattaXml = regattaXml;
//Create the message.
XMLMessage message = this.createXMLMessage(regattaXml, XMLMessageType.REGATTA);
//Place it in LatestMessages.
this.latestMessages.setRegattaXMLMessage(message);
}
/**
* Sets the Boats XML to send
* @param boatsXml XMl to send to the CLient
* Sets the Boats XML to send.
* @param boatsXml XMl to send to the Client.
*/
public void setBoatsXml(String boatsXml) {
this.boatsXml = boatsXml;
//Create the message.
XMLMessage message = this.createXMLMessage(boatsXml, XMLMessageType.BOAT);
//Place it in LatestMessages.
this.latestMessages.setBoatXMLMessage(message);
}
public static void main(String argv[]) throws Exception
{
MockOutput client = new MockOutput(new LatestMessages());