Copied remaining files into appropriate package. These need to be refactored and put into the shared package.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package mock.app;
|
||||
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.stage.Stage;
|
||||
import mock.dataInput.PolarParser;
|
||||
import mock.model.Polars;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class App extends Application {
|
||||
|
||||
/**
|
||||
* Entry point for running the programme
|
||||
*
|
||||
* @param args for starting the programme
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
try {
|
||||
Polars boatPolars = PolarParser.parse("polars/acc_polars.csv");
|
||||
|
||||
String regattaXML = readFile("mockXML/regattaTest.xml", StandardCharsets.UTF_8);
|
||||
String raceXML = readFile("mockXML/raceTest.xml", StandardCharsets.UTF_8);
|
||||
String boatXML = readFile("mockXML/boatTest.xml", StandardCharsets.UTF_8);
|
||||
|
||||
Event raceEvent = new Event(raceXML, regattaXML, boatXML, boatPolars);
|
||||
raceEvent.start();
|
||||
|
||||
} catch (Exception e) {
|
||||
//Catch all exceptions, print, and exit.
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the Initial Race XML files that are necessary to run the mock.
|
||||
* @param path path of the XML
|
||||
* @param encoding encoding of the xml
|
||||
* @return
|
||||
* @throws IOException No file etc
|
||||
* @throws ParserConfigurationException Issue with the XML formatting
|
||||
* @throws SAXException Issue with XML formatting
|
||||
* @throws TransformerException Issue with the XML format
|
||||
*/
|
||||
private String readFile(String path, Charset encoding) throws IOException, ParserConfigurationException, SAXException, TransformerException {
|
||||
|
||||
InputSource fXmlFile = new InputSource(getClass().getClassLoader().getResourceAsStream(path));
|
||||
|
||||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||
Document doc = dBuilder.parse(fXmlFile);
|
||||
doc.getDocumentElement().normalize();
|
||||
|
||||
return XMLReader.getContents(doc);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package mock.app;
|
||||
|
||||
import mock.model.Polars;
|
||||
import network.Messages.Enums.MessageType;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
|
||||
/**
|
||||
* A Race Event, this holds all of the race's information as well as handling the connection to its clients.
|
||||
*/
|
||||
public class Event {
|
||||
|
||||
String raceXML;
|
||||
String regattaXML;
|
||||
String boatXML;
|
||||
Polars boatPolars;
|
||||
MockOutput mockOutput;
|
||||
|
||||
public Event(String raceXML, String regattaXML, String boatXML, Polars boatPolars) {
|
||||
|
||||
this.raceXML = getRaceXMLAtCurrentTime(raceXML);
|
||||
this.boatXML = boatXML;
|
||||
this.regattaXML = regattaXML;
|
||||
this.boatPolars = boatPolars;
|
||||
try {
|
||||
mockOutput = new MockOutput();
|
||||
new Thread(mockOutput).start();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the initial race data and then begins race simulation
|
||||
*/
|
||||
public void start() {
|
||||
try {
|
||||
sendXMLs();
|
||||
Race newRace = new Race(new RaceXMLReader(this.raceXML, new BoatXMLReader(boatXML, this.boatPolars)), mockOutput);
|
||||
new Thread((newRace)).start();
|
||||
|
||||
} catch (ParserConfigurationException | IOException | SAXException | ParseException | StreamedCourseXMLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends out each xml string, via the mock output
|
||||
*/
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the xml description of the race to show the race was created now, and starts in 3 minutes
|
||||
* @param raceXML
|
||||
* @return String containing edited xml
|
||||
*/
|
||||
private String getRaceXMLAtCurrentTime(String raceXML) {
|
||||
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
ZonedDateTime creationTime = ZonedDateTime.now();
|
||||
return raceXML.replace("CREATION_TIME", dateFormat.format(creationTime))
|
||||
.replace("START_TIME", dateFormat.format(creationTime.plusMinutes(3)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
package mock.app;
|
||||
|
||||
|
||||
|
||||
import network.BinaryMessageEncoder;
|
||||
import network.MessageEncoders.RaceVisionByteEncoder;
|
||||
import network.MessageEncoders.XMLMessageEncoder;
|
||||
import network.Messages.BoatLocation;
|
||||
import network.Messages.Enums.MessageType;
|
||||
import network.Messages.RaceStatus;
|
||||
import network.Messages.XMLMessage;
|
||||
|
||||
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.
|
||||
private long lastHeartbeatTime;
|
||||
|
||||
///Period for the heartbeat - that is, how often we send it.
|
||||
private double heartbeatPeriod = 5.0;
|
||||
|
||||
///Port to expose server on.
|
||||
private int serverPort = 4942;
|
||||
///Socket used to listen for clients on.
|
||||
private ServerSocket serverSocket;
|
||||
///Socket used to communicate with a client.
|
||||
private Socket mockSocket;
|
||||
///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);
|
||||
|
||||
///Sequence numbers used in messages.
|
||||
private short messageNumber = 1;
|
||||
private short xmlSequenceNumber = 1;
|
||||
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
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
* @throws IOException if server socket cannot be opened.
|
||||
*/
|
||||
public MockOutput() throws IOException {
|
||||
lastHeartbeatTime = System.currentTimeMillis();
|
||||
serverSocket = new ServerSocket(serverPort);
|
||||
|
||||
}
|
||||
/**
|
||||
* Calculates the time since last heartbeat message, in seconds.
|
||||
* @return Time since last heartbeat message, in seconds.
|
||||
*/
|
||||
private double timeSinceHeartbeat() {
|
||||
long now = System.currentTimeMillis();
|
||||
return (now - lastHeartbeatTime) / 1000.0;
|
||||
}
|
||||
|
||||
//returns the heartbeat message
|
||||
|
||||
/**
|
||||
* Increment the heartbeat value
|
||||
* @return message for heartbeat data
|
||||
*/
|
||||
private byte[] heartbeat(){
|
||||
byte[] heartbeatMessage = RaceVisionByteEncoder.heartBeat(heartbeatSequenceNum);
|
||||
heartbeatSequenceNum++;
|
||||
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(MessageType.HEARTBEAT, System.currentTimeMillis(), messageNumber, (short)heartbeatMessage.length, heartbeatMessage);
|
||||
messageNumber++;
|
||||
return binaryMessageEncoder.getFullMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
public synchronized void 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);
|
||||
//iterates the message number
|
||||
messageNumber++;
|
||||
|
||||
addMessageToBufferToSend(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
|
||||
*/
|
||||
public synchronized void parseBoatLocation(int sourceID, double lat, double lon, double heading, double speed, long time){
|
||||
|
||||
BoatLocation boatLocation = new BoatLocation(sourceID, lat, lon, boatLocationSequenceNumber, heading, speed, time);
|
||||
//iterates the sequence number
|
||||
boatLocationSequenceNumber++;
|
||||
|
||||
//encodeds the messages
|
||||
byte[] encodedBoatLoc = RaceVisionByteEncoder.boatLocation(boatLocation);
|
||||
|
||||
//encodeds 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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the race status data and add it to the buffer to be sent
|
||||
* @param raceStatus race status to parses
|
||||
*/
|
||||
public synchronized void parseRaceStatus(RaceStatus raceStatus){
|
||||
|
||||
//iterates the sequence number
|
||||
raceStatusSequenceNumber++;
|
||||
|
||||
//encodeds 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);
|
||||
|
||||
//iterates the message number
|
||||
messageNumber++;
|
||||
|
||||
addMessageToBufferToSend(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
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
while (!stop){
|
||||
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){
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
parseXMLString(raceXml, XMLMessage.XMLTypeRace);
|
||||
parseXMLString(regattaXml, XMLMessage.XMLTypeRegatta);
|
||||
parseXMLString(boatsXml, XMLMessage.XMLTypeBoat);
|
||||
|
||||
|
||||
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();
|
||||
|
||||
//sends the message to the visualiser
|
||||
outToVisualiser.write(binaryMessage);
|
||||
|
||||
}
|
||||
}catch(SocketException e){
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop(){
|
||||
stop = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Race XML to send
|
||||
* @param raceXml XML to send to the CLient
|
||||
*/
|
||||
public void setRaceXml(String raceXml) {
|
||||
this.raceXml = raceXml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Regatta XMl to send
|
||||
* @param regattaXml XML to send to CLient
|
||||
*/
|
||||
public void setRegattaXml(String regattaXml) {
|
||||
this.regattaXml = regattaXml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Boats XML to send
|
||||
* @param boatsXml XMl to send to the CLient
|
||||
*/
|
||||
public void setBoatsXml(String boatsXml) {
|
||||
this.boatsXml = boatsXml;
|
||||
}
|
||||
|
||||
public static void main(String argv[]) throws Exception
|
||||
{
|
||||
MockOutput client = new MockOutput();
|
||||
client.run();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user