From b486f99dbef9e18d2c5b4b89d24d52b6bf24313b Mon Sep 17 00:00:00 2001 From: fjc40 Date: Sun, 6 Aug 2017 01:01:05 +1200 Subject: [PATCH] Added XMLMessageEncoder. Refactored XMLMessageDecoder to be consistent with other decoders - only needs to expose the XMLMessage. Refactored BoatLocationDecoder to be consistent with other decoders - only needs to expose the BoatLocation. Updated XMLMessageDecoderTest to use new encoder/decoder. Also tests all three message types. Removed XMLMessageEncoderTest as it was redundant. Updated BinaryMessageDecoderTest.xmlMessageTest() to use updated XMLMessage encoder/decoder. issue #35 #36 #story[1095] --- .../src/main/java/mock/app/MockOutput.java | 31 ++- .../java/network/BinaryMessageDecoder.java | 3 +- .../MessageDecoders/BoatLocationDecoder.java | 242 +++++++++--------- .../MessageDecoders/XMLMessageDecoder.java | 107 ++++---- .../MessageEncoders/EncoderFactory.java | 2 + .../RaceVisionByteEncoder.java | 37 --- .../MessageEncoders/XMLMessageEncoder.java | 62 +++++ .../network/BinaryMessageDecoderTest.java | 68 ++--- .../BoatLocationDecoderTest.java | 2 +- .../XMLMessageDecoderTest.java | 77 +++++- .../java/network/XMLMessageEncoderTest.java | 50 ---- .../test/resources/network/raceXML/Boats.xml | 119 +++++++++ .../test/resources/network/raceXML/Race.xml | 58 +++++ 13 files changed, 538 insertions(+), 320 deletions(-) create mode 100644 racevisionGame/src/main/java/network/MessageEncoders/XMLMessageEncoder.java delete mode 100644 racevisionGame/src/test/java/network/XMLMessageEncoderTest.java create mode 100644 racevisionGame/src/test/resources/network/raceXML/Boats.xml create mode 100644 racevisionGame/src/test/resources/network/raceXML/Race.xml diff --git a/racevisionGame/src/main/java/mock/app/MockOutput.java b/racevisionGame/src/main/java/mock/app/MockOutput.java index 23e7b738..2119fa06 100644 --- a/racevisionGame/src/main/java/mock/app/MockOutput.java +++ b/racevisionGame/src/main/java/mock/app/MockOutput.java @@ -134,11 +134,12 @@ public class MockOutput implements Runnable * Encodes/serialises a XMLMessage message, and returns it. * @param xmlMessage The XMLMessage message to serialise. * @return The XMLMessage message in a serialised form. + * @throws InvalidMessageException Thrown if the message cannot be encoded. */ - private synchronized byte[] parseXMLMessage(XMLMessage xmlMessage) { + private synchronized byte[] parseXMLMessage(XMLMessage xmlMessage) throws InvalidMessageException { //Serialize the xml message. - byte[] encodedXML = RaceVisionByteEncoder.xmlMessage(xmlMessage); + byte[] encodedXML = RaceVisionByteEncoder.encode(xmlMessage); //Place the message in a packet. BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder( @@ -262,15 +263,23 @@ public class MockOutput implements Runnable //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; + + try { + 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; + + } catch (InvalidMessageException e) { + Logger.getGlobal().log(Level.WARNING, "Could not encode XMLMessage: " + latestMessages.getRaceXMLMessage(), e); + continue; //Go to next iteration. + } + } //Sends the RaceStatus message. diff --git a/racevisionGame/src/main/java/network/BinaryMessageDecoder.java b/racevisionGame/src/main/java/network/BinaryMessageDecoder.java index 69ecc1f0..34a5d88d 100644 --- a/racevisionGame/src/main/java/network/BinaryMessageDecoder.java +++ b/racevisionGame/src/main/java/network/BinaryMessageDecoder.java @@ -149,8 +149,7 @@ public class BinaryMessageDecoder { case XMLMESSAGE: //System.out.println("XML Message!"); XMLMessageDecoder xmdecoder = new XMLMessageDecoder(messageBody); - xmdecoder.decode(); - return new XMLMessage(XMLMessage.currentVersionNumber, xmdecoder.getAckNumber(), xmdecoder.getTimeStamp(), xmdecoder.getXmlMsgSubType(), xmdecoder.getSequenceNumber(), xmdecoder.getXmlMessageContents()); + return xmdecoder.getMessage(); case RACESTARTSTATUS: //System.out.println("Race Start Status Message"); diff --git a/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java index db90a343..c0f4a652 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java @@ -11,132 +11,138 @@ import static network.Utils.ByteConverter.bytesToShort; /** - * Created by hba56 on 21/04/17. + * Decodes {@link BoatLocation} messages. */ public class BoatLocationDecoder { - private byte messageVersionNumber; - private byte[] time; - private byte[] sourceID; - private byte[] seqNum; - private byte deviceType; - private byte[] latitude; - private byte[] longitude; - private byte[] altitude; - private byte[] heading; - private byte[] pitch; - private byte[] roll; - private byte[] boatSpeed; - private byte[] cog; - private byte[] sog; - private byte[] apparentWindSpeed; - private byte[] apparentWindAngle; - private byte[] trueWindSpeed; - private byte[] trueWindDirection; - private byte[] trueWindAngle; - private byte[] currentDrift; - private byte[] currentSet; - private byte[] rudderAngle; + /** + * The encoded message. + */ + private byte[] encodedMessage; + + /** + * The decoded message. + */ private BoatLocation message; - public BoatLocationDecoder(byte[] encodedBoatLocation) { - byte numMessageVersionNumber = 0; - long numTime = 0; - int numSourceID = 0; - int numSeqNum = 0; - byte numDeviceType = 0; - int numLatitude = 0; - int numLongitude = 0; - int numAltitude = 0; - int numHeading = 0; - short numPitch = 0; - short numRoll = 0; - int numBoatSpeed = 0; - int numCog = 0; - int numSog = 0; - int numApparentWindSpeed = 0; - short numApparentWindAngle = 0; - int numTrueWindSpeed = 0; - short numTrueWindDirection = 0; - short numTrueWindAngle = 0; - int numCurrentDrift = 0; - int numCurrentSet = 0; - short numRudderAngle = 0; - - try { - messageVersionNumber = encodedBoatLocation[0]; - numMessageVersionNumber = messageVersionNumber; - time = Arrays.copyOfRange(encodedBoatLocation, 1, 7); - numTime = bytesToLong(time); - sourceID = Arrays.copyOfRange(encodedBoatLocation, 7, 11); - numSourceID = bytesToInt(sourceID); - seqNum = Arrays.copyOfRange(encodedBoatLocation, 11, 15); - numSeqNum = bytesToInt(seqNum); - deviceType = encodedBoatLocation[15]; - numDeviceType = deviceType; - latitude = Arrays.copyOfRange(encodedBoatLocation, 16, 20); - numLatitude = bytesToInt(latitude); - longitude = Arrays.copyOfRange(encodedBoatLocation, 20, 24); - numLongitude = bytesToInt(longitude); - altitude = Arrays.copyOfRange(encodedBoatLocation, 24, 28); - numAltitude = bytesToInt(altitude); - heading = Arrays.copyOfRange(encodedBoatLocation, 28, 30); - numHeading = bytesToInt(heading); - pitch = Arrays.copyOfRange(encodedBoatLocation, 30, 32); - numPitch = bytesToShort(pitch); - roll = Arrays.copyOfRange(encodedBoatLocation, 32, 34); - numRoll = bytesToShort(roll); - boatSpeed = Arrays.copyOfRange(encodedBoatLocation, 34, 36); - numBoatSpeed = bytesToInt(boatSpeed); - cog = Arrays.copyOfRange(encodedBoatLocation, 36, 38); - numCog = bytesToInt(cog); - sog = Arrays.copyOfRange(encodedBoatLocation, 38, 40); - numSog = bytesToInt(sog); - apparentWindSpeed = Arrays.copyOfRange(encodedBoatLocation, 40, 42); - numApparentWindSpeed = bytesToInt(apparentWindSpeed); - apparentWindAngle = Arrays.copyOfRange(encodedBoatLocation, 42, 44); - numApparentWindAngle = bytesToShort(apparentWindAngle); - trueWindSpeed = Arrays.copyOfRange(encodedBoatLocation, 44, 46); - numTrueWindSpeed = bytesToInt(trueWindSpeed); - trueWindDirection = Arrays.copyOfRange(encodedBoatLocation, 46, 48); - numTrueWindDirection = bytesToShort(trueWindDirection); - trueWindAngle = Arrays.copyOfRange(encodedBoatLocation, 48, 50); - numTrueWindAngle = bytesToShort(trueWindAngle); - currentDrift = Arrays.copyOfRange(encodedBoatLocation, 50, 52); - numCurrentDrift = bytesToInt(currentDrift); - currentSet = Arrays.copyOfRange(encodedBoatLocation, 52, 54); - numCurrentSet = bytesToShort(currentSet); - rudderAngle = Arrays.copyOfRange(encodedBoatLocation, 54, 56); - numRudderAngle = bytesToShort(rudderAngle); - } catch(ArrayIndexOutOfBoundsException e){ - - } - - message = new BoatLocation(numMessageVersionNumber, numTime, - numSourceID, numSeqNum, numDeviceType, numLatitude, - numLongitude, numAltitude, numHeading, numPitch, - numRoll, numBoatSpeed, numCog, numSog, numApparentWindSpeed, - numApparentWindAngle, numTrueWindSpeed, numTrueWindDirection, - numTrueWindAngle, numCurrentDrift, numCurrentSet, numRudderAngle - );/* - message = new BoatLocation(messageVersionNumber, bytesToLong(time), - bytesToInt(sourceID), bytesToInt(seqNum), - deviceType, bytesToInt(latitude), - bytesToInt(longitude), bytesToInt(altitude), - bytesToInt(heading), bytesToShort(pitch), - bytesToShort(roll), bytesToInt(boatSpeed), - bytesToInt(cog), bytesToInt(sog), - bytesToInt(apparentWindSpeed), bytesToShort(apparentWindAngle), - bytesToInt(trueWindSpeed), bytesToShort(trueWindDirection), - bytesToShort(trueWindAngle), bytesToInt(currentDrift), - bytesToInt(currentSet), bytesToShort(rudderAngle) - );*/ - -// System.out.println(bytesToInt(sourceID)); -// System.out.println(bytesToInt(boatSpeed)); + + + + /** + * Constructs a decoder to decode a given message. + * @param encodedMessage The message to decode. + */ + public BoatLocationDecoder(byte[] encodedMessage) { + + this.encodedMessage = encodedMessage; + + decode(); + } + + + /** + * Decodes the contained message. + */ + private void decode() { + + byte[] messageVersionNumber = Arrays.copyOfRange(encodedMessage, 0, 1); + byte numMessageVersionNumber = messageVersionNumber[0]; + + byte[] time = Arrays.copyOfRange(encodedMessage, 1, 7); + long numTime = bytesToLong(time); + + byte[] sourceID = Arrays.copyOfRange(encodedMessage, 7, 11); + int numSourceID = bytesToInt(sourceID); + + byte[] seqNum = Arrays.copyOfRange(encodedMessage, 11, 15); + int numSeqNum = bytesToInt(seqNum); + + byte[] deviceType = Arrays.copyOfRange(encodedMessage, 15, 16); + byte numDeviceType = deviceType[0]; + + byte[] latitude = Arrays.copyOfRange(encodedMessage, 16, 20); + int numLatitude = bytesToInt(latitude); + + byte[] longitude = Arrays.copyOfRange(encodedMessage, 20, 24); + int numLongitude = bytesToInt(longitude); + + byte[] altitude = Arrays.copyOfRange(encodedMessage, 24, 28); + int numAltitude = bytesToInt(altitude); + + byte[] heading = Arrays.copyOfRange(encodedMessage, 28, 30); + int numHeading = bytesToInt(heading); + + byte[] pitch = Arrays.copyOfRange(encodedMessage, 30, 32); + short numPitch = bytesToShort(pitch); + + byte[] roll = Arrays.copyOfRange(encodedMessage, 32, 34); + short numRoll = bytesToShort(roll); + + byte[] boatSpeed = Arrays.copyOfRange(encodedMessage, 34, 36); + int numBoatSpeed = bytesToInt(boatSpeed); + + byte[] cog = Arrays.copyOfRange(encodedMessage, 36, 38); + int numCog = bytesToInt(cog); + + byte[] sog = Arrays.copyOfRange(encodedMessage, 38, 40); + int numSog = bytesToInt(sog); + + byte[] apparentWindSpeed = Arrays.copyOfRange(encodedMessage, 40, 42); + int numApparentWindSpeed = bytesToInt(apparentWindSpeed); + + byte[] apparentWindAngle = Arrays.copyOfRange(encodedMessage, 42, 44); + short numApparentWindAngle = bytesToShort(apparentWindAngle); + + byte[] trueWindSpeed = Arrays.copyOfRange(encodedMessage, 44, 46); + int numTrueWindSpeed = bytesToInt(trueWindSpeed); + + byte[] trueWindDirection = Arrays.copyOfRange(encodedMessage, 46, 48); + short numTrueWindDirection = bytesToShort(trueWindDirection); + + byte[] trueWindAngle = Arrays.copyOfRange(encodedMessage, 48, 50); + short numTrueWindAngle = bytesToShort(trueWindAngle); + + byte[] currentDrift = Arrays.copyOfRange(encodedMessage, 50, 52); + int numCurrentDrift = bytesToInt(currentDrift); + + byte[] currentSet = Arrays.copyOfRange(encodedMessage, 52, 54); + int numCurrentSet = bytesToShort(currentSet); + + byte[] rudderAngle = Arrays.copyOfRange(encodedMessage, 54, 56); + short numRudderAngle = bytesToShort(rudderAngle); + + + message = new BoatLocation( + numMessageVersionNumber, + numTime, + numSourceID, + numSeqNum, + numDeviceType, + numLatitude, + numLongitude, + numAltitude, + numHeading, + numPitch, + numRoll, + numBoatSpeed, + numCog, + numSog, + numApparentWindSpeed, + numApparentWindAngle, + numTrueWindSpeed, + numTrueWindDirection, + numTrueWindAngle, + numCurrentDrift, + numCurrentSet, + numRudderAngle ); + } + /** + * Returns the decoded message. + * @return The decoded message. + */ public BoatLocation getMessage() { return message; } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java index 18ead92e..4fb985a1 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java @@ -1,10 +1,8 @@ package network.MessageDecoders; import network.Messages.Enums.XMLMessageType; +import network.Messages.XMLMessage; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; import java.util.Arrays; import static network.Utils.ByteConverter.bytesToLong; @@ -12,73 +10,70 @@ import static network.Utils.ByteConverter.bytesToShort; /** - * Created by hba56 on 20/04/17. + * Decodes {@link network.Messages.XMLMessage} messages. */ public class XMLMessageDecoder { - private byte messageVersionNumber; - private short ackNumber; - private long timeStamp; - private byte xmlMsgSubType; - private short sequenceNumber; - private short xmlMsgLength; - private String xmlMessage; - - private byte[] bytes; - - public XMLMessageDecoder(byte[] bytes) { - this.bytes = bytes; - } - - public void decode(){ - byte[] ackNumberBytes = Arrays.copyOfRange(bytes, 1, 3); - byte[] timeStampBytes = Arrays.copyOfRange(bytes, 3, 9); - byte[] sequenceNumberBytes = Arrays.copyOfRange(bytes, 10, 12); - byte[] xmlMsgLengthBytes = Arrays.copyOfRange(bytes, 12, 14); - byte[] xmlMessagebytes = Arrays.copyOfRange(bytes, 14, bytes.length); - - this.xmlMsgSubType = bytes[9]; - this.messageVersionNumber = bytes[0]; - this.ackNumber = bytesToShort(ackNumberBytes); - this.timeStamp = bytesToLong(timeStampBytes); + /** + * The encoded message. + */ + private byte[] encodedMessage; - this.sequenceNumber = bytesToShort(sequenceNumberBytes); - this.xmlMsgLength = bytesToShort(xmlMsgLengthBytes); - this.xmlMessage = new String(xmlMessagebytes).trim(); - } + /** + * The decoded message. + */ + private XMLMessage message; - public byte getMessageVersionNumber() { - return messageVersionNumber; - } - public short getAckNumber() { - return ackNumber; - } - public long getTimeStamp() { - return timeStamp; - } - - public XMLMessageType getXmlMsgSubType() { - return XMLMessageType.fromByte(xmlMsgSubType); - } + /** + * Constructs a decoder to decode a given message. + * @param encodedMessage The message to decode. + */ + public XMLMessageDecoder(byte[] encodedMessage) { + this.encodedMessage = encodedMessage; - public short getSequenceNumber() { - return sequenceNumber; + decode(); } - public short getXmlMsgLength() { - return xmlMsgLength; + /** + * Decodes the contained message. + */ + private void decode() { + + byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1); + byte[] ackNumberBytes = Arrays.copyOfRange(encodedMessage, 1, 3); + byte[] timeStampBytes = Arrays.copyOfRange(encodedMessage, 3, 9); + byte[] xmlMsgSubTypeBytes = Arrays.copyOfRange(encodedMessage, 9, 10); + byte[] sequenceNumberBytes = Arrays.copyOfRange(encodedMessage, 10, 12); + byte[] xmlMsgLengthBytes = Arrays.copyOfRange(encodedMessage, 12, 14); + byte[] xmlMessagebytes = Arrays.copyOfRange(encodedMessage, 14, encodedMessage.length); + + + byte messageVersionNumber = messageVersionNumberBytes[0]; + short ackNumber = bytesToShort(ackNumberBytes); + long timeStamp = bytesToLong(timeStampBytes); + XMLMessageType xmlMsgSubType = XMLMessageType.fromByte(xmlMsgSubTypeBytes[0]); + short sequenceNumber = bytesToShort(sequenceNumberBytes); + short xmlMsgLength = bytesToShort(xmlMsgLengthBytes); + String xmlMessage = new String(xmlMessagebytes); + + + message = new XMLMessage( + messageVersionNumber, + ackNumber, + timeStamp, + xmlMsgSubType, + sequenceNumber, + xmlMessage ); } - /** - * Returns the contents of the XML message (e.g., the contents of a race.xml file). - * @return The contents of the XML message. + * Returns the decoded message. + * @return The decoded message. */ - public String getXmlMessageContents() { - return xmlMessage; + public XMLMessage getMessage() { + return message; } - } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java b/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java index 8eff9cae..52bff99a 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/EncoderFactory.java @@ -31,6 +31,8 @@ public class EncoderFactory { case HEARTBEAT: return new HeartBeatEncoder(); + case XMLMESSAGE: return new XMLMessageEncoder(); + case BOATLOCATION: return new BoatLocationEncoder(); case REQUEST_TO_JOIN: return new RequestToJoinEncoder(); diff --git a/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java index 51e232d7..b6b7c774 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java @@ -170,43 +170,6 @@ public class RaceVisionByteEncoder { } - /** - * Serializes an xml message into a byte array. - * @param xmlMessage The message to serialize. - * @return byte array contaning serialized message. - */ - public static byte[] xmlMessage(XMLMessage xmlMessage) { - - - byte[] messageBytes = xmlMessage.getXmlMessage().getBytes(StandardCharsets.UTF_8); - - ByteBuffer tempOutputByteBuffer = ByteBuffer.allocate(14 + messageBytes.length); - - //ackNumber converted to bytes - byte[] ackNumberBytes = intToBytes(xmlMessage.getAckNumber(), 2); - - //Timestamp converted to bytes. - byte[] timestampBytes = longToBytes(xmlMessage.getTimeStamp(), 6); - - //sequenceNumber converted to bytes - byte[] sequenceNumberBytes = intToBytes(xmlMessage.getSequenceNumber(), 2); - - //xmlMsgLength converted to bytes - byte[] xmlMsgLengthBytes = intToBytes(xmlMessage.getXmlMsgLength(), 2); - - - tempOutputByteBuffer.put(xmlMessage.getVersionNumber()); - tempOutputByteBuffer.put(ackNumberBytes); - tempOutputByteBuffer.put(timestampBytes); - tempOutputByteBuffer.put(xmlMessage.getXmlMsgSubType().getValue()); - tempOutputByteBuffer.put(sequenceNumberBytes); - tempOutputByteBuffer.put(xmlMsgLengthBytes); - tempOutputByteBuffer.put(messageBytes); - - return tempOutputByteBuffer.array(); - - } - public static byte[] markRounding(int time, int ackNumber, int raceID, int sourceID, int boatStatus, int roundingSide, int markType, int markID){ int messageVersionNumber = 0b1; byte[] byteTime = longToBytes(time, 6); diff --git a/racevisionGame/src/main/java/network/MessageEncoders/XMLMessageEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/XMLMessageEncoder.java new file mode 100644 index 00000000..92a75ca7 --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageEncoders/XMLMessageEncoder.java @@ -0,0 +1,62 @@ +package network.MessageEncoders; + + +import network.Messages.AC35Data; +import network.Messages.XMLMessage; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +import static network.Utils.ByteConverter.intToBytes; +import static network.Utils.ByteConverter.longToBytes; + +/** + * This encoder can encode a {@link XMLMessage} message. + */ +public class XMLMessageEncoder implements MessageEncoder { + + + /** + * Constructor. + */ + public XMLMessageEncoder() { + } + + + @Override + public byte[] encode(AC35Data message) { + + //Downcast. + XMLMessage xmlMessage = (XMLMessage) message; + + + byte[] messageBytes = xmlMessage.getXmlMessage().getBytes(StandardCharsets.UTF_8); + + //Message is 14 + xmlMessage.length bytes. + ByteBuffer tempOutputByteBuffer = ByteBuffer.allocate(14 + messageBytes.length); + + //ackNumber converted to bytes + byte[] ackNumberBytes = intToBytes(xmlMessage.getAckNumber(), 2); + + //Timestamp converted to bytes. + byte[] timestampBytes = longToBytes(xmlMessage.getTimeStamp(), 6); + + //sequenceNumber converted to bytes + byte[] sequenceNumberBytes = intToBytes(xmlMessage.getSequenceNumber(), 2); + + //xmlMsgLength converted to bytes + byte[] xmlMsgLengthBytes = intToBytes(xmlMessage.getXmlMsgLength(), 2); + + + tempOutputByteBuffer.put(xmlMessage.getVersionNumber()); + tempOutputByteBuffer.put(ackNumberBytes); + tempOutputByteBuffer.put(timestampBytes); + tempOutputByteBuffer.put(xmlMessage.getXmlMsgSubType().getValue()); + tempOutputByteBuffer.put(sequenceNumberBytes); + tempOutputByteBuffer.put(xmlMsgLengthBytes); + tempOutputByteBuffer.put(messageBytes); + + return tempOutputByteBuffer.array(); + + } +} diff --git a/racevisionGame/src/test/java/network/BinaryMessageDecoderTest.java b/racevisionGame/src/test/java/network/BinaryMessageDecoderTest.java index 7414d709..c7c843e5 100644 --- a/racevisionGame/src/test/java/network/BinaryMessageDecoderTest.java +++ b/racevisionGame/src/test/java/network/BinaryMessageDecoderTest.java @@ -2,6 +2,7 @@ package network; import network.Exceptions.InvalidMessageException; import network.MessageDecoders.XMLMessageDecoder; +import network.MessageDecoders.XMLMessageDecoderTest; import network.MessageEncoders.RaceVisionByteEncoder; import network.Messages.AC35Data; import network.Messages.Enums.MessageType; @@ -21,29 +22,46 @@ import java.nio.charset.StandardCharsets; import static org.junit.Assert.fail; /** - * Created by hba56 on 21/04/17. + * Tests the binary message decoder and encoder for a variety of messages. */ public class BinaryMessageDecoderTest { + + + /** + * Tests if an XMLMessage can be encoded and decoded correctly. + */ @Test - public void decodeTest(){ - try{ - String xmlString = XMLReader.readXMLFileToString("network/raceXML/Regatta.xml", StandardCharsets.UTF_8); + public void xmlMessageTest() throws Exception { + + try { + + String filePath = "network/raceXML/Regatta.xml"; + XMLMessageType messageType = XMLMessageType.REGATTA; + + String xmlString = XMLReader.readXMLFileToString(filePath, StandardCharsets.UTF_8); long time = System.currentTimeMillis(); - XMLMessage xmlMessagePre = new XMLMessage( + XMLMessage xmlMessage = new XMLMessage( (byte)1, 1, time, - XMLMessageType.REGATTA, + messageType, (short)1, - xmlString ); + xmlString ); + + byte[] encodedMessage = RaceVisionByteEncoder.encode(xmlMessage); + - byte[] encodedMessage = RaceVisionByteEncoder.xmlMessage(xmlMessagePre); + BinaryMessageEncoder encoder = new BinaryMessageEncoder( + xmlMessage.getType(), + time, + 1, + (short)encodedMessage.length, + encodedMessage ); - BinaryMessageEncoder testMessage = new BinaryMessageEncoder(MessageType.XMLMESSAGE, time, 1, (short)encodedMessage.length, encodedMessage); + BinaryMessageDecoder decoder = new BinaryMessageDecoder(encoder.getFullMessage()); - BinaryMessageDecoder decoder = new BinaryMessageDecoder(testMessage.getFullMessage()); AC35Data message = null; try { @@ -56,7 +74,7 @@ public class BinaryMessageDecoderTest { if (!(message instanceof XMLMessage)){ Assert.assertFalse(true); } - XMLMessage xmlMessage = (XMLMessage) message; + XMLMessage xmlMessageDecoded = (XMLMessage) message; //message length @@ -66,29 +84,17 @@ public class BinaryMessageDecoderTest { //source ID Assert.assertEquals((short) 1, decoder.getHeaderSourceID()); //message type - Assert.assertEquals(26, decoder.getHeaderMessageType()); - - XMLMessageDecoder decoderXML = new XMLMessageDecoder(decoder.getMessageBody()); - decoderXML.decode(); - - //tests from seng302.Networking.MessageDecoders.XMLMessageDecoderTest to make sure the file is still good - Assert.assertEquals((byte)1, decoderXML.getMessageVersionNumber()); - Assert.assertEquals((short)1, decoderXML.getAckNumber()); - Assert.assertEquals(time, decoderXML.getTimeStamp()); - Assert.assertEquals(XMLMessageType.REGATTA, decoderXML.getXmlMsgSubType()); - Assert.assertEquals((short)1, decoderXML.getSequenceNumber()); - Assert.assertEquals((short)xmlString.length(), decoderXML.getXmlMsgLength()); - -// Reader reader = decoderXML.getXmlMessageInputStream().getCharacterStream(); -// int c; -// String contents = ""; -// while((c = reader.read()) != -1) { -// contents += (char)c; -// } -// Assert.assertEquals(xmlString.toString(), contents); + Assert.assertEquals(MessageType.XMLMESSAGE.getValue(), decoder.getHeaderMessageType()); + + + XMLMessageDecoderTest.compareXMLMessages(xmlMessage, xmlMessageDecoded); + } catch (XMLReaderException | TransformerException e){ fail("couldn't read file" + e.getMessage()); } } + + //TODO add some tests for more messages types. + } diff --git a/racevisionGame/src/test/java/network/MessageDecoders/BoatLocationDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/BoatLocationDecoderTest.java index 18893609..22831eaa 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/BoatLocationDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/BoatLocationDecoderTest.java @@ -16,7 +16,7 @@ public class BoatLocationDecoderTest { * Creates a BoatLocation message, encodes it, decodes it, and checks that the result matches the starting message. */ @Test - public void getByteArrayTest() throws Exception { + public void boatLocationEncodeDecodeTest() throws Exception { //Create message. long time = System.currentTimeMillis(); diff --git a/racevisionGame/src/test/java/network/MessageDecoders/XMLMessageDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/XMLMessageDecoderTest.java index b0d0eee3..fb0683a3 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/XMLMessageDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/XMLMessageDecoderTest.java @@ -1,5 +1,6 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.MessageEncoders.RaceVisionByteEncoder; import network.Messages.Enums.XMLMessageType; import network.Messages.XMLMessage; @@ -14,13 +15,21 @@ import java.nio.charset.StandardCharsets; import static org.junit.Assert.fail; /** - * Created by hba56 on 20/04/17. + * Test for the XMLMessage encoder and decoder */ public class XMLMessageDecoderTest { - @Test - public void getByteArrayTest(){ - try{ - String xmlString = XMLReader.readXMLFileToString("network/raceXML/Regatta.xml", StandardCharsets.UTF_8); + + + /** + * Creates an XML message of the given type, using the specified filePath, encodes it, decodes it, and checks that the result matches the starting message. + * @param filePath The file path for xml file. + * @param type The type of xml file. + * @throws InvalidMessageException Thrown if message cannot be encoded. + */ + private void xmlMessageTest(String filePath, XMLMessageType type) throws InvalidMessageException { + + try { + String xmlString = XMLReader.readXMLFileToString(filePath, StandardCharsets.UTF_8); long time = System.currentTimeMillis(); @@ -28,27 +37,67 @@ public class XMLMessageDecoderTest { (byte)1, 1, time, - XMLMessageType.REGATTA, + type, (short)1, xmlString ); - byte[] encodedXML = RaceVisionByteEncoder.xmlMessage(message); + byte[] encodedXML = RaceVisionByteEncoder.encode(message); XMLMessageDecoder decoderXML = new XMLMessageDecoder(encodedXML); - decoderXML.decode(); + XMLMessage decodedMessage = decoderXML.getMessage(); + + compareXMLMessages(message, decodedMessage); - Assert.assertEquals((byte)1, decoderXML.getMessageVersionNumber()); - Assert.assertEquals((short)1, decoderXML.getAckNumber()); - Assert.assertEquals(time, decoderXML.getTimeStamp()); - Assert.assertEquals(XMLMessageType.REGATTA, decoderXML.getXmlMsgSubType()); - Assert.assertEquals((short)1, decoderXML.getSequenceNumber()); - Assert.assertEquals((short)xmlString.length(), decoderXML.getXmlMsgLength()); } catch (XMLReaderException | TransformerException e){ fail("couldn't read file" + e.getMessage()); } + + } + + /** + * Compares two XML messages to check that they are the same. + * @param originalMessage The first message to test. + * @param decodedMessage The second message to test. + */ + public static void compareXMLMessages(XMLMessage originalMessage, XMLMessage decodedMessage) { + + Assert.assertEquals(originalMessage.getVersionNumber(), decodedMessage.getVersionNumber()); + Assert.assertEquals(originalMessage.getAckNumber(), decodedMessage.getAckNumber()); + Assert.assertEquals(originalMessage.getTimeStamp(), decodedMessage.getTimeStamp()); + Assert.assertEquals(originalMessage.getXmlMsgSubType(), decodedMessage.getXmlMsgSubType()); + Assert.assertEquals(originalMessage.getSequenceNumber(), decodedMessage.getSequenceNumber()); + Assert.assertEquals(originalMessage.getXmlMsgLength(), decodedMessage.getXmlMsgLength()); + Assert.assertEquals(originalMessage.getXmlMessage(), decodedMessage.getXmlMessage()); + + } + + /** + * Tests if a regatta.xml message can be encoded and decoded. + */ + @Test + public void regattaXMLMessageTest() throws Exception { + xmlMessageTest("network/raceXML/Regatta.xml", XMLMessageType.REGATTA); + } + + + /** + * Tests if a race.xml message can be encoded and decoded. + */ + @Test + public void raceXMLMessageTest() throws Exception { + xmlMessageTest("network/raceXML/Race.xml", XMLMessageType.RACE); + } + + + /** + * Tests if a boat.xml message can be encoded and decoded. + */ + @Test + public void boatXMLMessageTest() throws Exception { + xmlMessageTest("network/raceXML/Boats.xml", XMLMessageType.BOAT); } } diff --git a/racevisionGame/src/test/java/network/XMLMessageEncoderTest.java b/racevisionGame/src/test/java/network/XMLMessageEncoderTest.java deleted file mode 100644 index 44a99997..00000000 --- a/racevisionGame/src/test/java/network/XMLMessageEncoderTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package network; - -import network.MessageEncoders.RaceVisionByteEncoder; -import network.Messages.Enums.XMLMessageType; -import network.Messages.XMLMessage; -import org.junit.Assert; -import org.junit.Test; -import shared.dataInput.XMLReader; -import shared.exceptions.XMLReaderException; - -import javax.xml.transform.TransformerException; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; - -import static org.junit.Assert.fail; - -/** - * Created by hba56 on 19/04/17. - */ -public class XMLMessageEncoderTest { - @Test - public void getByteArrayTest() { - try { - - String xmlString = XMLReader.readXMLFileToString("network/raceXML/Regatta.xml", StandardCharsets.UTF_8); - - - XMLMessage message = new XMLMessage( - (byte)1, - 1, - System.currentTimeMillis(), - XMLMessageType.REGATTA, - (short)1, - xmlString ); - - int xmlMessageLength = xmlString.getBytes().length; - - byte[] encodedXML = RaceVisionByteEncoder.xmlMessage(message); - - //1 + 2 + 6 + 1 + 2 + 2 + xml.byteLength - Assert.assertEquals(14 + xmlMessageLength, encodedXML.length); - - } catch (XMLReaderException | TransformerException e){ - fail("couldn't read file" + e.getMessage()); - } - } - -} diff --git a/racevisionGame/src/test/resources/network/raceXML/Boats.xml b/racevisionGame/src/test/resources/network/raceXML/Boats.xml new file mode 100644 index 00000000..ed4b6ded --- /dev/null +++ b/racevisionGame/src/test/resources/network/raceXML/Boats.xml @@ -0,0 +1,119 @@ + + + + 2017-04-19T15:49:40+1200 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/racevisionGame/src/test/resources/network/raceXML/Race.xml b/racevisionGame/src/test/resources/network/raceXML/Race.xml new file mode 100644 index 00000000..29478c60 --- /dev/null +++ b/racevisionGame/src/test/resources/network/raceXML/Race.xml @@ -0,0 +1,58 @@ + + + 17041901 + Fleet + 2017-04-19T15:30:00+1200 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file