Added LatestMessages to network.Messages. This is an object that encapsulates the latest up to date set of race messages.

Race stores a reference to it. MockRace writes to it, and eventually, VisualiserRace will read from it.
Updated MockRace, MockOutput, Event to use it.

Angle now implements hashCode().
This commit is contained in:
fjc40
2017-07-06 16:02:11 +12:00
parent 3a0b81834f
commit 8e18ad62ca
9 changed files with 361 additions and 109 deletions
@@ -3,6 +3,7 @@ package mock.app;
import mock.model.MockRace;
import mock.model.Polars;
import network.Messages.Enums.MessageType;
import network.Messages.LatestMessages;
import org.xml.sax.SAXException;
import shared.dataInput.*;
import shared.exceptions.InvalidBoatDataException;
@@ -28,6 +29,8 @@ public class Event {
private String boatXML;
private Polars boatPolars;
private MockOutput mockOutput;
private LatestMessages latestMessages;
public Event(String raceXML, String regattaXML, String boatXML, Polars boatPolars) {
@@ -36,9 +39,13 @@ public class Event {
this.regattaXML = regattaXML;
this.boatPolars = boatPolars;
this.latestMessages = new LatestMessages();
try {
mockOutput = new MockOutput();
this.mockOutput = new MockOutput(this.latestMessages);
new Thread(mockOutput).start();
} catch (IOException e) {
e.printStackTrace();
}
@@ -57,7 +64,7 @@ public class Event {
RegattaDataSource regattaDataSource = new RegattaXMLReader(this.regattaXML);
//Create and start race.
MockRace newRace = new MockRace(boatDataSource, raceDataSource, regattaDataSource, this.boatPolars, this.mockOutput);
MockRace newRace = new MockRace(boatDataSource, raceDataSource, regattaDataSource, this.boatPolars, this.latestMessages);
new Thread(newRace).start();
@@ -7,6 +7,7 @@ import network.MessageEncoders.RaceVisionByteEncoder;
import network.MessageEncoders.XMLMessageEncoder;
import network.Messages.BoatLocation;
import network.Messages.Enums.MessageType;
import network.Messages.LatestMessages;
import network.Messages.RaceStatus;
import network.Messages.XMLMessage;
@@ -37,8 +38,14 @@ public class MockOutput implements Runnable
///Output stream which wraps around mockSocket outstream.
private DataOutputStream outToVisualiser;
///A queue that contains items that are waiting to be sent.
private ArrayBlockingQueue<byte[]> messagesToSendQueue = new ArrayBlockingQueue<>(99999999);
/**
* An object containing the set of latest messages to send.
* Every server frame, MockOutput reads messages from this, and send them.
*/
private LatestMessages latestMessages;
///Sequence numbers used in messages.
private short messageNumber = 1;
@@ -56,11 +63,15 @@ public class MockOutput implements Runnable
/**
* Ctor.
* @param latestMessages The collection of messages to send to connected clients.
* @throws IOException if server socket cannot be opened.
*/
public MockOutput() throws IOException {
lastHeartbeatTime = System.currentTimeMillis();
serverSocket = new ServerSocket(serverPort);
public MockOutput(LatestMessages latestMessages) throws IOException {
this.lastHeartbeatTime = System.currentTimeMillis();
this.serverSocket = new ServerSocket(serverPort);
this.latestMessages = latestMessages;
}
/**
@@ -91,77 +102,92 @@ public class MockOutput implements Runnable
* @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)
*/
public synchronized void parseXMLString(String xmlString, int messageType){
XMLMessageEncoder encoder = new XMLMessageEncoder(messageNumber, System.currentTimeMillis(), messageType, xmlSequenceNumber,(short) xmlString.length(), xmlString);
public synchronized byte[] parseXMLString(String xmlString, int messageType) {
XMLMessageEncoder encoder = new XMLMessageEncoder(
messageNumber,
System.currentTimeMillis(),
messageType,
xmlSequenceNumber,
(short) xmlString.length(),
xmlString);
//iterates the sequence numbers
xmlSequenceNumber++;
byte[] encodedXML = encoder.encode();
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.XMLMESSAGE, System.currentTimeMillis(), messageNumber, (short)encodedXML.length, encodedXML);
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
MessageType.XMLMESSAGE,
System.currentTimeMillis(),
messageNumber,
(short)encodedXML.length,
encodedXML);
//iterates the message number
messageNumber++;
addMessageToBufferToSend(binaryMessageEncoder.getFullMessage());
return binaryMessageEncoder.getFullMessage();
}
/**
* Used to give the mocOutput information about boat location to be made into a message and sent
* @param sourceID id of the boat
* @param lat latitude of boat
* @param lon longitude of boat
* @param heading heading of boat
* @param speed speed of boat
* @param time historical time of race
* Encodes/serialises a BoatLocation message, and returns it.
* @param boatLocation The BoatLocation message to serialise.
* @return The BoatLocation message in a serialised form.
*/
public synchronized void parseBoatLocation(int sourceID, double lat, double lon, double heading, double speed, long time){
private synchronized byte[] parseBoatLocation(BoatLocation boatLocation){
BoatLocation boatLocation = new BoatLocation(sourceID, lat, lon, boatLocationSequenceNumber, heading, speed, time);
//iterates the sequence number
boatLocationSequenceNumber++;
//encodeds the messages
//Encodes the message.
byte[] encodedBoatLoc = RaceVisionByteEncoder.boatLocation(boatLocation);
//encodeds the full message with header
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.BOATLOCATION, System.currentTimeMillis(), messageNumber, (short)encodedBoatLoc.length,
encodedBoatLoc);
//Encodes the full message with header.
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
MessageType.BOATLOCATION,
System.currentTimeMillis(),
messageNumber,
(short) encodedBoatLoc.length,
encodedBoatLoc );
//iterates the message number
messageNumber++;
addMessageToBufferToSend(binaryMessageEncoder.getFullMessage());
return binaryMessageEncoder.getFullMessage();
}
/**
* Parse the race status data and add it to the buffer to be sent
* @param raceStatus race status to parses
* Encodes/serialises a RaceStatus message, and returns it.
* @param raceStatus The RaceStatus message to serialise.
* @return The RaceStatus message in a serialised form.
*/
public synchronized void parseRaceStatus(RaceStatus raceStatus){
private synchronized byte[] parseRaceStatus(RaceStatus raceStatus){
//iterates the sequence number
raceStatusSequenceNumber++;
//encodeds the messages
//Encodes the messages.
byte[] encodedRaceStatus = RaceVisionByteEncoder.raceStatus(raceStatus);
//encodeds the full message with header
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.RACESTATUS, System.currentTimeMillis(), messageNumber, (short)encodedRaceStatus.length,
encodedRaceStatus);
//Encodes the full message with header.
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
MessageType.RACESTATUS,
System.currentTimeMillis(),
messageNumber,
(short) encodedRaceStatus.length,
encodedRaceStatus );
//iterates the message number
messageNumber++;
addMessageToBufferToSend(binaryMessageEncoder.getFullMessage());
return binaryMessageEncoder.getFullMessage();
}
/**
* Add a message to the buffer to be sent
* @param messagesToSendBuffer message to add to the buffer
*/
private synchronized void addMessageToBufferToSend(byte[] messagesToSendBuffer) {
this.messagesToSendQueue.add(messagesToSendBuffer);
}
/**
* Sending loop of the Server
@@ -175,7 +201,7 @@ public class MockOutput implements Runnable
outToVisualiser = new DataOutputStream(mockSocket.getOutputStream());
if (boatsXml == null || regattaXml == null || raceXml == null){
if (boatsXml == null || regattaXml == null || raceXml == null) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
@@ -184,34 +210,91 @@ public class MockOutput implements Runnable
continue;
}
parseXMLString(raceXml, XMLMessage.XMLTypeRace);
parseXMLString(regattaXml, XMLMessage.XMLTypeRegatta);
parseXMLString(boatsXml, XMLMessage.XMLTypeBoat);
//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;
while(true) {
try {
//Sends a heartbeat every so often.
if (timeSinceHeartbeat() >= heartbeatPeriod) {
outToVisualiser.write(heartbeat());
lastHeartbeatTime = System.currentTimeMillis();
}
//Checks the buffer to see if there is anything to send.
while (messagesToSendQueue.size() > 0) {
//Grabs message from head of queue.
byte[] binaryMessage = messagesToSendQueue.remove();
long currentFrameTime = System.currentTimeMillis();
//sends the message to the visualiser
outToVisualiser.write(binaryMessage);
//This is the time elapsed, in milliseconds, since the last server "frame".
long framePeriod = currentFrameTime - previousFrameTime;
//We only attempt to send packets every X milliseconds.
long minimumFramePeriod = 16;
if (framePeriod >= minimumFramePeriod) {
//Sends a heartbeat every so often.
if (timeSinceHeartbeat() >= heartbeatPeriod) {
outToVisualiser.write(heartbeat());
lastHeartbeatTime = System.currentTimeMillis();
}
//Send XML messages.
if (!sentXMLs) {
outToVisualiser.write(raceXMLBlob);
outToVisualiser.write(regattaXMLBlob);
outToVisualiser.write(boatsXMLBlob);
sentXMLs = true;
}
//Sens the RaceStatus message.
if (this.latestMessages.getRaceStatus() != null) {
byte[] raceStatusBlob = this.parseRaceStatus(this.latestMessages.getRaceStatus());
this.outToVisualiser.write(raceStatusBlob);
}
//Send all of the BoatLocation messages.
for (int sourceID : this.latestMessages.getBoatLocationMap().keySet()) {
//Get the message.
BoatLocation boatLocation = this.latestMessages.getBoatLocation(sourceID);
if (boatLocation != null) {
//Encode.
byte[] boatLocationBlob = this.parseBoatLocation(boatLocation);
//Write it.
this.outToVisualiser.write(boatLocationBlob);
}
}
previousFrameTime = currentFrameTime;
} else {
//Wait until the frame period will be large enough.
long timeToWait = minimumFramePeriod - framePeriod;
try {
Thread.sleep(timeToWait);
} catch (InterruptedException e) {
//If we get interrupted, exit the function.
e.printStackTrace();
//Re-set the interrupt flag.
Thread.currentThread().interrupt();
return;
}
}
}catch(SocketException e){
} catch (SocketException e) {
break;
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
@@ -247,7 +330,7 @@ public class MockOutput implements Runnable
public static void main(String argv[]) throws Exception
{
MockOutput client = new MockOutput();
MockOutput client = new MockOutput(new LatestMessages());
client.run();
}