diff --git a/racevisionGame/src/main/java/network/BinaryMessageDecoder.java b/racevisionGame/src/main/java/network/BinaryMessageDecoder.java index 9ae2ba47..7bd9c233 100644 --- a/racevisionGame/src/main/java/network/BinaryMessageDecoder.java +++ b/racevisionGame/src/main/java/network/BinaryMessageDecoder.java @@ -17,42 +17,71 @@ import java.util.zip.CRC32; */ public class BinaryMessageDecoder { - ///Length of the header. + /** + * Length of the header. + */ private static final int headerLength = 15; - ///Length of the CRC. - private static final int CRCLength = 4;//TODO these should probably be static defined somewhere else to be shared. + /** + * Length of the CRC. + */ + private static final int CRCLength = 4; - ///The value the first sync byte should have. + /** + * The value the first sync byte should have. + */ private static final byte syncByte1 = (byte) 0x47; - //The value the second sync byte should have. + /** + * The value the second sync byte should have. + */ private static final byte syncByte2 = (byte) 0x83; - ///The full message. + /** + * The full message. + */ private byte[] fullMessage; - ///The messageHeader. + /** + * The messageHeader. + */ private byte[] messageHeader; - ///The messageBody. + /** + * The messageBody. + */ private byte[] messageBody; - ///The sync bytes from the header.. + /** + * The sync bytes from the header. + */ private byte headerSync1; private byte headerSync2; - ///The message type from the header. + /** + * The message type from the header. + */ private byte headerMessageType; - ///The timestamp from the header. + /** + * The timestamp from the header. + */ private long headerTimeStamp; - ///The source ID from the header. + /** + * The source ID from the header. + */ private int headerSourceID; - ///The message body length from the header. + /** + * The message body length from the header. + */ private int messageBodyLength; - ///CRC value read from message header. + /** + * CRC value read from message header. + */ private long messageCRCValue; - ///Calculated CRC value from message. + + /** + * Calculated CRC value from message. + */ private long calculatedCRCValue; @@ -114,104 +143,34 @@ public class BinaryMessageDecoder { //Check the message body length. throw new InvalidMessageException("MessageBody length in header does not equal the messageBody length. MessageBody length in header is: " + messageBodyLength + ", should be: " + messageBody.length); - }else if (headerSync1 != syncByte1) { + } else if (headerSync1 != syncByte1) { //Check the first sync byte. throw new InvalidMessageException("Sync byte 1 is wrong. Sync byte is: " + headerSync1 + ", should be: " + syncByte1); - }else if (headerSync2 != syncByte2) { + } else if (headerSync2 != syncByte2) { //Check the second sync byte. throw new InvalidMessageException("Sync byte 2 is wrong. Sync byte is: " + headerSync2 + ", should be: " + syncByte2); - }else if (calculatedCRCValue != messageCRCValue) { + } else if (calculatedCRCValue != messageCRCValue) { //Check the CRC value. throw new InvalidMessageException("CRC value is wrong. The calculated value is: " + calculatedCRCValue + ", should be: " + messageCRCValue); } //Now we create the message object based on what is actually in the message body. - MessageType mType = MessageType.fromByte(headerMessageType); + MessageType messageType = MessageType.fromByte(headerMessageType); - /*MessageDecoder decoder = null; + MessageDecoder decoder = null; try { - decoder = DecoderFactory.create(mType); + decoder = DecoderFactory.create(messageType); + } catch (InvalidMessageTypeException e) { - throw new InvalidMessageException("Could not create decoder for MessageType: " + mType, e); + throw new InvalidMessageException("Could not create decoder for MessageType: " + messageType, e); + } - return decoder.decode(messageBody);*/ - - - switch(mType) { - case HEARTBEAT: - //System.out.println("Decoding HeartBeat Message!"); - HeartBeatDecoder heartBeatDecoder = new HeartBeatDecoder(); - return heartBeatDecoder.decode(messageBody); - - case RACESTATUS: - //System.out.println("Race Status Message"); - RaceStatusDecoder rsdecoder = new RaceStatusDecoder(); - return rsdecoder.decode(messageBody); - - case DISPLAYTEXTMESSAGE: - //System.out.println("Display Text Message"); - //No decoder for this. - //throw new InvalidMessageException("Cannot decode DISPLAYTEXTMESSAGE - no decoder."); - - case XMLMESSAGE: - //System.out.println("XML Message!"); - XMLMessageDecoder xmdecoder = new XMLMessageDecoder(); - return xmdecoder.decode(messageBody); - - case RACESTARTSTATUS: - //System.out.println("Race Start Status Message"); - RaceStartStatusDecoder rssDecoder = new RaceStartStatusDecoder(); - return rssDecoder.decode(messageBody); - - case YACHTEVENTCODE: - //System.out.println("Yacht Action Code!"); - //No decoder for this. - //throw new InvalidMessageException("Cannot decode YACHTEVENTCODE - no decoder."); - - case YACHTACTIONCODE: - //System.out.println("Yacht Action Code!"); - //No decoder for this. - //throw new InvalidMessageException("Cannot decode YACHTACTIONCODE - no decoder."); - - case CHATTERTEXT: - //System.out.println("Chatter Text Message!"); - //No decoder for this. - //throw new InvalidMessageException("Cannot decode CHATTERTEXT - no decoder."); - - case BOATLOCATION: - //System.out.println("Boat Location Message!"); - BoatLocationDecoder blDecoder = new BoatLocationDecoder(); - return blDecoder.decode(messageBody); - - case MARKROUNDING: - //System.out.println("Mark Rounding Message!"); - MarkRoundingDecoder mrDecoder = new MarkRoundingDecoder(); - return mrDecoder.decode(messageBody); - - case COURSEWIND: - //System.out.println("Course Wind Message!"); - CourseWindsDecoder cwDecoder = new CourseWindsDecoder(); - return cwDecoder.decode(messageBody); - - case AVGWIND: - //System.out.println("Average Wind Message!"); - AverageWindDecoder awDecoder = new AverageWindDecoder(); - return awDecoder.decode(messageBody); - - case BOATACTION: - BoatActionDecoder baDecoder = new BoatActionDecoder(); - return baDecoder.decode(messageBody); - - default: - //System.out.println("Broken Message!"); - //throw new InvalidMessageException("Broken message! Did not recognise message type: " + headerMessageType + "."); - return null; + return decoder.decode(messageBody); - } } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/AverageWindDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/AverageWindDecoder.java index 1b0f12d5..139aed13 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/AverageWindDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/AverageWindDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.AverageWind; import network.Utils.ByteConverter; @@ -32,64 +33,67 @@ public class AverageWindDecoder implements MessageDecoder { @Override - public AC35Data decode(byte[] encodedMessage) { + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; + try { - byte messageVersionNumber = encodedMessage[0]; + byte messageVersionNumber = encodedMessage[0]; - byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7); - long time = ByteConverter.bytesToLong(byteTime); + byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7); + long time = ByteConverter.bytesToLong(byteTime); - byte[] byteRawPeriod = Arrays.copyOfRange(encodedMessage, 7, 9); - int intRawPeriod = ByteConverter.bytesToInt(byteRawPeriod); - long rawPeriod = unpackAverageWindPeriod(intRawPeriod); + byte[] byteRawPeriod = Arrays.copyOfRange(encodedMessage, 7, 9); + int intRawPeriod = ByteConverter.bytesToInt(byteRawPeriod); + long rawPeriod = unpackAverageWindPeriod(intRawPeriod); - byte[] byteRawSpeed = Arrays.copyOfRange(encodedMessage, 9, 11); - int intRawSpeed = ByteConverter.bytesToInt(byteRawSpeed); - double rawSpeedKnots = unpackMMperSecToKnots(intRawSpeed); + byte[] byteRawSpeed = Arrays.copyOfRange(encodedMessage, 9, 11); + int intRawSpeed = ByteConverter.bytesToInt(byteRawSpeed); + double rawSpeedKnots = unpackMMperSecToKnots(intRawSpeed); - byte[] bytePeriod2 = Arrays.copyOfRange(encodedMessage, 11, 13); - int intPeriod2 = ByteConverter.bytesToInt(bytePeriod2); - long period2 = unpackAverageWindPeriod(intPeriod2); + byte[] bytePeriod2 = Arrays.copyOfRange(encodedMessage, 11, 13); + int intPeriod2 = ByteConverter.bytesToInt(bytePeriod2); + long period2 = unpackAverageWindPeriod(intPeriod2); - byte[] byteSpeed2 = Arrays.copyOfRange(encodedMessage, 13, 15); - int intSpeed2 = ByteConverter.bytesToInt(byteSpeed2); - double speed2Knots = unpackMMperSecToKnots(intSpeed2); + byte[] byteSpeed2 = Arrays.copyOfRange(encodedMessage, 13, 15); + int intSpeed2 = ByteConverter.bytesToInt(byteSpeed2); + double speed2Knots = unpackMMperSecToKnots(intSpeed2); - byte[] bytePeriod3 = Arrays.copyOfRange(encodedMessage, 15, 17); - int intPeriod3 = ByteConverter.bytesToInt(bytePeriod3); - long period3 = unpackAverageWindPeriod(intPeriod3); + byte[] bytePeriod3 = Arrays.copyOfRange(encodedMessage, 15, 17); + int intPeriod3 = ByteConverter.bytesToInt(bytePeriod3); + long period3 = unpackAverageWindPeriod(intPeriod3); - byte[] byteSpeed3 = Arrays.copyOfRange(encodedMessage, 17, 19); - int intSpeed3 = ByteConverter.bytesToInt(byteSpeed3); - double speed3Knots = unpackMMperSecToKnots(intSpeed3); + byte[] byteSpeed3 = Arrays.copyOfRange(encodedMessage, 17, 19); + int intSpeed3 = ByteConverter.bytesToInt(byteSpeed3); + double speed3Knots = unpackMMperSecToKnots(intSpeed3); - byte[] bytePeriod4 = Arrays.copyOfRange(encodedMessage, 19, 21); - int intPeriod4 = ByteConverter.bytesToInt(bytePeriod4); - long period4 = unpackAverageWindPeriod(intPeriod4); + byte[] bytePeriod4 = Arrays.copyOfRange(encodedMessage, 19, 21); + int intPeriod4 = ByteConverter.bytesToInt(bytePeriod4); + long period4 = unpackAverageWindPeriod(intPeriod4); - byte[] byteSpeed4 = Arrays.copyOfRange(encodedMessage, 21, 23); - int intSpeed4 = ByteConverter.bytesToInt(byteSpeed4); - double speed4Knots = unpackMMperSecToKnots(intSpeed4); + byte[] byteSpeed4 = Arrays.copyOfRange(encodedMessage, 21, 23); + int intSpeed4 = ByteConverter.bytesToInt(byteSpeed4); + double speed4Knots = unpackMMperSecToKnots(intSpeed4); + message = new AverageWind( + messageVersionNumber, + time, + rawPeriod, + rawSpeedKnots, + period2, + speed2Knots, + period3, + speed3Knots, + period4, + speed4Knots); + return message; - message = new AverageWind( - messageVersionNumber, - time, - rawPeriod, - rawSpeedKnots, - period2, - speed2Knots, - period3, - speed3Knots, - period4, - speed4Knots ); - - return message; + } catch (Exception e) { + throw new InvalidMessageException("Could not decode AverageWind message.", e); + } } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/BoatActionDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/BoatActionDecoder.java index a3a5d38a..1df1e2f0 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/BoatActionDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/BoatActionDecoder.java @@ -1,5 +1,6 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.BoatAction; import network.Messages.Enums.BoatActionEnum; @@ -29,14 +30,19 @@ public class BoatActionDecoder implements MessageDecoder { } @Override - public AC35Data decode(byte[] encodedMessage) { + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; - BoatActionEnum boatActionEnum = BoatActionEnum.fromByte(encodedMessage[0]); + try { + BoatActionEnum boatActionEnum = BoatActionEnum.fromByte(encodedMessage[0]); - message = new BoatAction(boatActionEnum); + message = new BoatAction(boatActionEnum); - return message; + return message; + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode BoatAction message.", e); + } } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java index 1e175588..2965e809 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.BoatLocation; import network.Messages.Enums.BoatLocationDeviceEnum; @@ -39,115 +40,121 @@ public class BoatLocationDecoder implements MessageDecoder { @Override - public AC35Data decode(byte[] encodedMessage) { + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; - byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1); - byte messageVersionNumber = messageVersionNumberBytes[0]; - - byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7); - long time = bytesToLong(timeBytes); - - byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11); - int sourceID = bytesToInt(sourceIDBytes); - - byte[] seqNumBytes = Arrays.copyOfRange(encodedMessage, 11, 15); - int seqNum = bytesToInt(seqNumBytes); - - byte[] deviceTypeBytes = Arrays.copyOfRange(encodedMessage, 15, 16); - BoatLocationDeviceEnum deviceType = BoatLocationDeviceEnum.fromByte(deviceTypeBytes[0]); - - byte[] latitudeBytes = Arrays.copyOfRange(encodedMessage, 16, 20); - int numLatitude = bytesToInt(latitudeBytes); - double latitude = unpackGPS(numLatitude); - - byte[] longitudeBytes = Arrays.copyOfRange(encodedMessage, 20, 24); - int numLongitude = bytesToInt(longitudeBytes); - double longitude = unpackGPS(numLongitude); - - byte[] altitudeBytes = Arrays.copyOfRange(encodedMessage, 24, 28); - int numAltitude = bytesToInt(altitudeBytes); - - byte[] headingBytes = Arrays.copyOfRange(encodedMessage, 28, 30); - int numHeading = bytesToInt(headingBytes); - Bearing heading = Bearing.fromDegrees(unpackHeading(numHeading)); - - byte[] pitchBytes = Arrays.copyOfRange(encodedMessage, 30, 32); - short numPitch = bytesToShort(pitchBytes); - - byte[] rollBytes = Arrays.copyOfRange(encodedMessage, 32, 34); - short numRoll = bytesToShort(rollBytes); - - byte[] boatSpeedBytes = Arrays.copyOfRange(encodedMessage, 34, 36); - int numBoatSpeed = bytesToInt(boatSpeedBytes); - double boatSpeedKnots = unpackMMperSecToKnots(numBoatSpeed); - - byte[] cogBytes = Arrays.copyOfRange(encodedMessage, 36, 38); - int numCog = bytesToInt(cogBytes); - Bearing cog = Bearing.fromDegrees(unpackHeading(numCog)); - - byte[] sogBytes = Arrays.copyOfRange(encodedMessage, 38, 40); - int numSog = bytesToInt(sogBytes); - double sogKnots = unpackMMperSecToKnots(numSog); - - byte[] apparentWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 40, 42); - int numApparentWindSpeed = bytesToInt(apparentWindSpeedBytes); - double apparentWindSpeedKnots = unpackMMperSecToKnots(numApparentWindSpeed); - - byte[] apparentWindAngleBytes = Arrays.copyOfRange(encodedMessage, 42, 44); - short numApparentWindAngle = bytesToShort(apparentWindAngleBytes); - Azimuth apparentWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numApparentWindAngle)); - - byte[] trueWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 44, 46); - int numTrueWindSpeed = bytesToInt(trueWindSpeedBytes); - double trueWindSpeedKnots = unpackMMperSecToKnots(numTrueWindSpeed); - - byte[] trueWindDirectionBytes = Arrays.copyOfRange(encodedMessage, 46, 48); - short numTrueWindDirection = bytesToShort(trueWindDirectionBytes); - Bearing trueWindDirection = Bearing.fromDegrees(unpackHeading(numTrueWindDirection)); - - byte[] trueWindAngleBytes = Arrays.copyOfRange(encodedMessage, 48, 50); - short numTrueWindAngle = bytesToShort(trueWindAngleBytes); - Azimuth trueWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numTrueWindAngle)); - - byte[] currentDriftBytes = Arrays.copyOfRange(encodedMessage, 50, 52); - int numCurrentDrift = bytesToInt(currentDriftBytes); - double currentDriftKnots = unpackMMperSecToKnots(numCurrentDrift); - - byte[] currentSetBytes = Arrays.copyOfRange(encodedMessage, 52, 54); - int numCurrentSet = bytesToShort(currentSetBytes); - Bearing currentSet = Bearing.fromDegrees(unpackHeading(numCurrentSet)); - - byte[] rudderAngleBytes = Arrays.copyOfRange(encodedMessage, 54, 56); - short numRudderAngle = bytesToShort(rudderAngleBytes); - Azimuth rudderAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numRudderAngle)); - - - message = new BoatLocation( - messageVersionNumber, - time, - sourceID, - seqNum, - deviceType, - latitude, - longitude, - numAltitude, - heading, - numPitch, - numRoll, - boatSpeedKnots, - cog, - sogKnots, - apparentWindSpeedKnots, - apparentWindAngle, - trueWindSpeedKnots, - trueWindDirection, - trueWindAngle, - currentDriftKnots, - currentSet, - rudderAngle ); + try { - return message; + byte[] messageVersionNumberBytes = Arrays.copyOfRange(encodedMessage, 0, 1); + byte messageVersionNumber = messageVersionNumberBytes[0]; + + byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7); + long time = bytesToLong(timeBytes); + + byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11); + int sourceID = bytesToInt(sourceIDBytes); + + byte[] seqNumBytes = Arrays.copyOfRange(encodedMessage, 11, 15); + int seqNum = bytesToInt(seqNumBytes); + + byte[] deviceTypeBytes = Arrays.copyOfRange(encodedMessage, 15, 16); + BoatLocationDeviceEnum deviceType = BoatLocationDeviceEnum.fromByte(deviceTypeBytes[0]); + + byte[] latitudeBytes = Arrays.copyOfRange(encodedMessage, 16, 20); + int numLatitude = bytesToInt(latitudeBytes); + double latitude = unpackGPS(numLatitude); + + byte[] longitudeBytes = Arrays.copyOfRange(encodedMessage, 20, 24); + int numLongitude = bytesToInt(longitudeBytes); + double longitude = unpackGPS(numLongitude); + + byte[] altitudeBytes = Arrays.copyOfRange(encodedMessage, 24, 28); + int numAltitude = bytesToInt(altitudeBytes); + + byte[] headingBytes = Arrays.copyOfRange(encodedMessage, 28, 30); + int numHeading = bytesToInt(headingBytes); + Bearing heading = Bearing.fromDegrees(unpackHeading(numHeading)); + + byte[] pitchBytes = Arrays.copyOfRange(encodedMessage, 30, 32); + short numPitch = bytesToShort(pitchBytes); + + byte[] rollBytes = Arrays.copyOfRange(encodedMessage, 32, 34); + short numRoll = bytesToShort(rollBytes); + + byte[] boatSpeedBytes = Arrays.copyOfRange(encodedMessage, 34, 36); + int numBoatSpeed = bytesToInt(boatSpeedBytes); + double boatSpeedKnots = unpackMMperSecToKnots(numBoatSpeed); + + byte[] cogBytes = Arrays.copyOfRange(encodedMessage, 36, 38); + int numCog = bytesToInt(cogBytes); + Bearing cog = Bearing.fromDegrees(unpackHeading(numCog)); + + byte[] sogBytes = Arrays.copyOfRange(encodedMessage, 38, 40); + int numSog = bytesToInt(sogBytes); + double sogKnots = unpackMMperSecToKnots(numSog); + + byte[] apparentWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 40, 42); + int numApparentWindSpeed = bytesToInt(apparentWindSpeedBytes); + double apparentWindSpeedKnots = unpackMMperSecToKnots(numApparentWindSpeed); + + byte[] apparentWindAngleBytes = Arrays.copyOfRange(encodedMessage, 42, 44); + short numApparentWindAngle = bytesToShort(apparentWindAngleBytes); + Azimuth apparentWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numApparentWindAngle)); + + byte[] trueWindSpeedBytes = Arrays.copyOfRange(encodedMessage, 44, 46); + int numTrueWindSpeed = bytesToInt(trueWindSpeedBytes); + double trueWindSpeedKnots = unpackMMperSecToKnots(numTrueWindSpeed); + + byte[] trueWindDirectionBytes = Arrays.copyOfRange(encodedMessage, 46, 48); + short numTrueWindDirection = bytesToShort(trueWindDirectionBytes); + Bearing trueWindDirection = Bearing.fromDegrees(unpackHeading(numTrueWindDirection)); + + byte[] trueWindAngleBytes = Arrays.copyOfRange(encodedMessage, 48, 50); + short numTrueWindAngle = bytesToShort(trueWindAngleBytes); + Azimuth trueWindAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numTrueWindAngle)); + + byte[] currentDriftBytes = Arrays.copyOfRange(encodedMessage, 50, 52); + int numCurrentDrift = bytesToInt(currentDriftBytes); + double currentDriftKnots = unpackMMperSecToKnots(numCurrentDrift); + + byte[] currentSetBytes = Arrays.copyOfRange(encodedMessage, 52, 54); + int numCurrentSet = bytesToShort(currentSetBytes); + Bearing currentSet = Bearing.fromDegrees(unpackHeading(numCurrentSet)); + + byte[] rudderAngleBytes = Arrays.copyOfRange(encodedMessage, 54, 56); + short numRudderAngle = bytesToShort(rudderAngleBytes); + Azimuth rudderAngle = Azimuth.fromDegrees(unpackTrueWindAngle(numRudderAngle)); + + + message = new BoatLocation( + messageVersionNumber, + time, + sourceID, + seqNum, + deviceType, + latitude, + longitude, + numAltitude, + heading, + numPitch, + numRoll, + boatSpeedKnots, + cog, + sogKnots, + apparentWindSpeedKnots, + apparentWindAngle, + trueWindSpeedKnots, + trueWindDirection, + trueWindAngle, + currentDriftKnots, + currentSet, + rudderAngle); + + return message; + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode BoatLocation message.", e); + } } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/BoatStatusDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/BoatStatusDecoder.java index ed2c6cf0..27b88a39 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/BoatStatusDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/BoatStatusDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.BoatStatus; import network.Messages.Enums.BoatStatusEnum; @@ -39,10 +40,12 @@ public class BoatStatusDecoder { * Decodes the contained message. * @param encodedMessage The message to decode. * @return The decoded message. + * @throws InvalidMessageException Thrown if the encoded message is invalid in some way, or cannot be decoded. */ - public BoatStatus decode(byte[] encodedMessage) { + public BoatStatus decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; + try { byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 0, 4); int sourceID = bytesToInt(sourceIDBytes); @@ -76,6 +79,10 @@ public class BoatStatusDecoder { return message; + } catch (Exception e) { + throw new InvalidMessageException("Could not decode BoatStatus message.", e); + } + } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/CourseWindDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/CourseWindDecoder.java index 6a26e4ae..4941df10 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/CourseWindDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/CourseWindDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.CourseWind; import shared.model.Bearing; @@ -38,49 +39,55 @@ public class CourseWindDecoder { * Decodes the contained message. * @param encodedMessage The message to decode. * @return The decoded message. + * @throws InvalidMessageException Thrown if the encoded message is invalid in some way, or cannot be decoded. */ - public CourseWind decode(byte[] encodedMessage) { + public CourseWind decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; - byte[] windId = Arrays.copyOfRange(encodedMessage, 0, 1); + try { - byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7); - long time = bytesToLong(timeBytes); + byte[] windId = Arrays.copyOfRange(encodedMessage, 0, 1); - byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11); - int raceIDInt = bytesToInt(raceIDBytes); + byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7); + long time = bytesToLong(timeBytes); - byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 11, 13); - int windDirectionInt = bytesToInt(windDirectionBytes); - Bearing windDirection = Bearing.fromDegrees(unpackHeading(windDirectionInt)); + byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11); + int raceIDInt = bytesToInt(raceIDBytes); - byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 13, 15); - int windSpeedInt = bytesToInt(windSpeedBytes); - double windSpeedKnots = unpackMMperSecToKnots(windSpeedInt); + byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 11, 13); + int windDirectionInt = bytesToInt(windDirectionBytes); + Bearing windDirection = Bearing.fromDegrees(unpackHeading(windDirectionInt)); - byte[] bestUpwindAngleBytes = Arrays.copyOfRange(encodedMessage, 15, 17); - int bestUpwindAngleInt = bytesToInt(bestUpwindAngleBytes); - Bearing bestUpwindAngle = Bearing.fromDegrees(unpackHeading(bestUpwindAngleInt)); + byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 13, 15); + int windSpeedInt = bytesToInt(windSpeedBytes); + double windSpeedKnots = unpackMMperSecToKnots(windSpeedInt); - byte[] bestDownwindAngleBytes = Arrays.copyOfRange(encodedMessage, 17, 19); - int bestDownwindAngleInt = bytesToInt(bestDownwindAngleBytes); - Bearing bestDownwindAngle = Bearing.fromDegrees(unpackHeading(bestDownwindAngleInt)); + byte[] bestUpwindAngleBytes = Arrays.copyOfRange(encodedMessage, 15, 17); + int bestUpwindAngleInt = bytesToInt(bestUpwindAngleBytes); + Bearing bestUpwindAngle = Bearing.fromDegrees(unpackHeading(bestUpwindAngleInt)); - byte[] flags = Arrays.copyOfRange(encodedMessage, 19, 20); + byte[] bestDownwindAngleBytes = Arrays.copyOfRange(encodedMessage, 17, 19); + int bestDownwindAngleInt = bytesToInt(bestDownwindAngleBytes); + Bearing bestDownwindAngle = Bearing.fromDegrees(unpackHeading(bestDownwindAngleInt)); + byte[] flags = Arrays.copyOfRange(encodedMessage, 19, 20); - message = new CourseWind( - windId[0], - time, - raceIDInt, - windDirection, - windSpeedKnots, - bestUpwindAngle, - bestDownwindAngle, - flags[0] ); + message = new CourseWind( + windId[0], + time, + raceIDInt, + windDirection, + windSpeedKnots, + bestUpwindAngle, + bestDownwindAngle, + flags[0]); - return message; + return message; + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode CourseWind message.", e); + } } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/CourseWindsDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/CourseWindsDecoder.java index f478ac6b..d6b7b70e 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/CourseWindsDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/CourseWindsDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.CourseWind; import network.Messages.CourseWinds; @@ -38,41 +39,46 @@ public class CourseWindsDecoder implements MessageDecoder { @Override - public AC35Data decode(byte[] encodedMessage) { + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; - //The header is three bytes. - byte messageVersionNumber = encodedMessage[0]; - byte byteWindID = encodedMessage[1]; - byte loopCount = encodedMessage[2]; + try { + //The header is three bytes. + byte messageVersionNumber = encodedMessage[0]; + byte byteWindID = encodedMessage[1]; + byte loopCount = encodedMessage[2]; - //A CourseWind object is 20 bytes. - final int courseWindByteLength = 20; - List loopMessages = new ArrayList(); + //A CourseWind object is 20 bytes. + final int courseWindByteLength = 20; - //The header is 3 bytes, so we need the remaining bytes. - byte[] loopMessagesBytes = Arrays.copyOfRange(encodedMessage, 3, courseWindByteLength * loopCount + 3); + List loopMessages = new ArrayList(); - for (int messageLoopIndex = 0; messageLoopIndex < (loopCount * courseWindByteLength); messageLoopIndex += courseWindByteLength) { + //The header is 3 bytes, so we need the remaining bytes. + byte[] loopMessagesBytes = Arrays.copyOfRange(encodedMessage, 3, courseWindByteLength * loopCount + 3); - byte[] messageBytes = Arrays.copyOfRange(loopMessagesBytes, messageLoopIndex, messageLoopIndex + courseWindByteLength); + for (int messageLoopIndex = 0; messageLoopIndex < (loopCount * courseWindByteLength); messageLoopIndex += courseWindByteLength) { - CourseWindDecoder courseWindDecoder = new CourseWindDecoder(); - CourseWind courseWind = courseWindDecoder.decode(messageBytes); + byte[] messageBytes = Arrays.copyOfRange(loopMessagesBytes, messageLoopIndex, messageLoopIndex + courseWindByteLength); - loopMessages.add(courseWind); - } + CourseWindDecoder courseWindDecoder = new CourseWindDecoder(); + CourseWind courseWind = courseWindDecoder.decode(messageBytes); + loopMessages.add(courseWind); + } - message = new CourseWinds( - messageVersionNumber, - byteWindID, - loopMessages ); + message = new CourseWinds( + messageVersionNumber, + byteWindID, + loopMessages); - return message; + return message; + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode CourseWinds message.", e); + } } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/HeartBeatDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/HeartBeatDecoder.java index 49cdcc5f..bc86244b 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/HeartBeatDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/HeartBeatDecoder.java @@ -1,5 +1,6 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.Enums.BoatActionEnum; import network.Messages.HeartBeat; @@ -30,12 +31,18 @@ public class HeartBeatDecoder implements MessageDecoder { } @Override - public AC35Data decode(byte[] encodedMessage) { + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; - message = new HeartBeat(bytesToLong(encodedMessage)); + try { - return message; + message = new HeartBeat(bytesToLong(encodedMessage)); + + return message; + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode HeartBeat message.", e); + } } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/JoinAcceptanceDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/JoinAcceptanceDecoder.java index eaa82c18..5766b47f 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/JoinAcceptanceDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/JoinAcceptanceDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.Enums.JoinAcceptanceEnum; import network.Messages.JoinAcceptance; @@ -32,27 +33,32 @@ public class JoinAcceptanceDecoder implements MessageDecoder { @Override - public AC35Data decode(byte[] encodedMessage) { + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; - //SourceID is first four bytes. - byte[] sourceIdBytes = Arrays.copyOfRange(encodedMessage, 0, 4); + try { - //Next byte is acceptance type. - byte[] acceptanceBytes = Arrays.copyOfRange(encodedMessage, 4, 5); + //SourceID is first four bytes. + byte[] sourceIdBytes = Arrays.copyOfRange(encodedMessage, 0, 4); + //Next byte is acceptance type. + byte[] acceptanceBytes = Arrays.copyOfRange(encodedMessage, 4, 5); - //SourceID is an int. - int sourceID = ByteConverter.bytesToInt(sourceIdBytes); + //SourceID is an int. + int sourceID = ByteConverter.bytesToInt(sourceIdBytes); - //Acceptance enum is a byte. - JoinAcceptanceEnum acceptanceType = JoinAcceptanceEnum.fromByte(acceptanceBytes[0]); + //Acceptance enum is a byte. + JoinAcceptanceEnum acceptanceType = JoinAcceptanceEnum.fromByte(acceptanceBytes[0]); - message = new JoinAcceptance(acceptanceType, sourceID); + message = new JoinAcceptance(acceptanceType, sourceID); - return message; + return message; + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode JoinAcceptance message.", e); + } } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/MarkRoundingDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/MarkRoundingDecoder.java index 58ad8f64..6db46f27 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/MarkRoundingDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/MarkRoundingDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.Enums.MarkRoundingBoatStatusEnum; import network.Messages.Enums.MarkRoundingSideEnum; @@ -33,48 +34,54 @@ public class MarkRoundingDecoder implements MessageDecoder { } @Override - public AC35Data decode(byte[] encodedMessage) { + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; - byte messageVersionNumber = encodedMessage[0]; + try { - byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7); - long time = ByteConverter.bytesToLong(byteTime); + byte messageVersionNumber = encodedMessage[0]; - byte[] byteAck = Arrays.copyOfRange(encodedMessage, 7, 9); - int ackNumber = ByteConverter.bytesToInt(byteAck); + byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7); + long time = ByteConverter.bytesToLong(byteTime); - byte[] byteRaceID = Arrays.copyOfRange(encodedMessage, 9, 13); - int raceID = ByteConverter.bytesToInt(byteRaceID); + byte[] byteAck = Arrays.copyOfRange(encodedMessage, 7, 9); + int ackNumber = ByteConverter.bytesToInt(byteAck); - byte[] byteSourceID = Arrays.copyOfRange(encodedMessage, 13, 17); - int sourceID = ByteConverter.bytesToInt(byteSourceID); + byte[] byteRaceID = Arrays.copyOfRange(encodedMessage, 9, 13); + int raceID = ByteConverter.bytesToInt(byteRaceID); - byte byteBoatStatus = encodedMessage[17]; - MarkRoundingBoatStatusEnum boatStatus = MarkRoundingBoatStatusEnum.fromByte(byteBoatStatus); + byte[] byteSourceID = Arrays.copyOfRange(encodedMessage, 13, 17); + int sourceID = ByteConverter.bytesToInt(byteSourceID); - byte byteRoundingSide = encodedMessage[18]; - MarkRoundingSideEnum roundingSide = MarkRoundingSideEnum.fromByte(byteRoundingSide); + byte byteBoatStatus = encodedMessage[17]; + MarkRoundingBoatStatusEnum boatStatus = MarkRoundingBoatStatusEnum.fromByte(byteBoatStatus); - byte byteMarkType = encodedMessage[19]; - MarkRoundingTypeEnum markType = MarkRoundingTypeEnum.fromByte(byteMarkType); + byte byteRoundingSide = encodedMessage[18]; + MarkRoundingSideEnum roundingSide = MarkRoundingSideEnum.fromByte(byteRoundingSide); - byte byteMarkID = encodedMessage[20]; + byte byteMarkType = encodedMessage[19]; + MarkRoundingTypeEnum markType = MarkRoundingTypeEnum.fromByte(byteMarkType); + byte byteMarkID = encodedMessage[20]; - message = new MarkRounding( - messageVersionNumber, - time, - ackNumber, - raceID, - sourceID, - boatStatus, - roundingSide, - markType, - byteMarkID); + message = new MarkRounding( + messageVersionNumber, + time, + ackNumber, + raceID, + sourceID, + boatStatus, + roundingSide, + markType, + byteMarkID); - return message; + + return message; + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode AverageWind message.", e); + } } /** diff --git a/racevisionGame/src/main/java/network/MessageDecoders/MessageDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/MessageDecoder.java index 39b4370f..c20c653f 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/MessageDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/MessageDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; @@ -15,7 +16,8 @@ public interface MessageDecoder { * Decodes a given message. * @param encodedMessage The message to decode. * @return The decoded message. + * @throws InvalidMessageException Thrown if the encoded message is invalid in some way, or cannot be decoded. */ - public AC35Data decode(byte[] encodedMessage); + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException; } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/RaceStartStatusDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/RaceStartStatusDecoder.java index 062f1212..2776ea6f 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/RaceStartStatusDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/RaceStartStatusDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.Enums.RaceStartTypeEnum; import network.Messages.RaceStartStatus; @@ -35,38 +36,42 @@ public class RaceStartStatusDecoder implements MessageDecoder { @Override - public AC35Data decode(byte[] encodedMessage) { + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; + try { - byte messageVersion = encodedMessage[0]; + byte messageVersion = encodedMessage[0]; - byte[] timestamp = Arrays.copyOfRange(encodedMessage, 1, 7); - long time = bytesToLong(timestamp); + byte[] timestamp = Arrays.copyOfRange(encodedMessage, 1, 7); + long time = bytesToLong(timestamp); - byte[] ackNumber = Arrays.copyOfRange(encodedMessage, 7, 9); - short ack = bytesToShort(ackNumber); + byte[] ackNumber = Arrays.copyOfRange(encodedMessage, 7, 9); + short ack = bytesToShort(ackNumber); - byte[] raceStartTime = Arrays.copyOfRange(encodedMessage, 9, 15); - long startTime = bytesToLong(raceStartTime); + byte[] raceStartTime = Arrays.copyOfRange(encodedMessage, 9, 15); + long startTime = bytesToLong(raceStartTime); - byte[] raceIdentifier = Arrays.copyOfRange(encodedMessage, 15, 19); - int raceID = bytesToInt(raceIdentifier); + byte[] raceIdentifier = Arrays.copyOfRange(encodedMessage, 15, 19); + int raceID = bytesToInt(raceIdentifier); - byte notificationType = encodedMessage[19]; + byte notificationType = encodedMessage[19]; + message = new RaceStartStatus( + messageVersion, + time, + ack, + startTime, + raceID, + RaceStartTypeEnum.fromByte(notificationType) + ); - message = new RaceStartStatus( - messageVersion, - time, - ack, - startTime, - raceID, - RaceStartTypeEnum.fromByte(notificationType) - ); + return message; - return message; + } catch (Exception e) { + throw new InvalidMessageException("Could not decode RaceStartStatus message.", e); + } } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/RaceStatusDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/RaceStatusDecoder.java index 15700f49..7e26e105 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/RaceStatusDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/RaceStatusDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.BoatStatus; import network.Messages.Enums.RaceStatusEnum; @@ -43,70 +44,75 @@ public class RaceStatusDecoder implements MessageDecoder { @Override - public AC35Data decode(byte[] encodedMessage) { + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; + try { - byte[] versionNumBytes = Arrays.copyOfRange(encodedMessage, 0, 1); - byte versionNum = versionNumBytes[0]; + byte[] versionNumBytes = Arrays.copyOfRange(encodedMessage, 0, 1); + byte versionNum = versionNumBytes[0]; - byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7); - long time = bytesToLong(timeBytes); + byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7); + long time = bytesToLong(timeBytes); - byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11); - int raceID = bytesToInt(raceIDBytes); + byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11); + int raceID = bytesToInt(raceIDBytes); - byte[] raceStatusBytes = Arrays.copyOfRange(encodedMessage, 11, 12); - RaceStatusEnum raceStatus = RaceStatusEnum.fromByte(raceStatusBytes[0]); + byte[] raceStatusBytes = Arrays.copyOfRange(encodedMessage, 11, 12); + RaceStatusEnum raceStatus = RaceStatusEnum.fromByte(raceStatusBytes[0]); - byte[] expectedStartBytes = Arrays.copyOfRange(encodedMessage, 12, 18); - long expectedStart = bytesToLong(expectedStartBytes); + byte[] expectedStartBytes = Arrays.copyOfRange(encodedMessage, 12, 18); + long expectedStart = bytesToLong(expectedStartBytes); - byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 18, 20); - int windDirectionInt = bytesToInt(windDirectionBytes); - Bearing windDirection = Bearing.fromDegrees(AC35UnitConverter.unpackHeading(windDirectionInt)); + byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 18, 20); + int windDirectionInt = bytesToInt(windDirectionBytes); + Bearing windDirection = Bearing.fromDegrees(AC35UnitConverter.unpackHeading(windDirectionInt)); - byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 20, 22); - int windSpeedInt = bytesToInt(windSpeedBytes); - double windSpeedKnots = AC35UnitConverter.unpackMMperSecToKnots(windSpeedInt); + byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 20, 22); + int windSpeedInt = bytesToInt(windSpeedBytes); + double windSpeedKnots = AC35UnitConverter.unpackMMperSecToKnots(windSpeedInt); - byte[] numberOfBoatsBytes = Arrays.copyOfRange(encodedMessage, 22, 23); - int numberOfBoats = bytesToInt(numberOfBoatsBytes); + byte[] numberOfBoatsBytes = Arrays.copyOfRange(encodedMessage, 22, 23); + int numberOfBoats = bytesToInt(numberOfBoatsBytes); - byte[] raceTypeBytes = Arrays.copyOfRange(encodedMessage, 23, 24); - RaceTypeEnum raceType = RaceTypeEnum.fromByte(raceTypeBytes[0]); + byte[] raceTypeBytes = Arrays.copyOfRange(encodedMessage, 23, 24); + RaceTypeEnum raceType = RaceTypeEnum.fromByte(raceTypeBytes[0]); - byte[] boatStatusesBytes = Arrays.copyOfRange(encodedMessage, 24, 25 + 20 * numberOfBoats); - List boatStatuses = new ArrayList<>(); + byte[] boatStatusesBytes = Arrays.copyOfRange(encodedMessage, 24, 25 + 20 * numberOfBoats); + List boatStatuses = new ArrayList<>(); - //BoatStatus is 20 bytes. - int boatStatusByteLength = 20; + //BoatStatus is 20 bytes. + int boatStatusByteLength = 20; - //Decode each BoatStatus. - for (int boatLoopIndex = 0; boatLoopIndex < (numberOfBoats * boatStatusByteLength); boatLoopIndex += boatStatusByteLength) { + //Decode each BoatStatus. + for (int boatLoopIndex = 0; boatLoopIndex < (numberOfBoats * boatStatusByteLength); boatLoopIndex += boatStatusByteLength) { - byte[] boatStatusBytes = Arrays.copyOfRange(boatStatusesBytes, boatLoopIndex, boatLoopIndex + boatStatusByteLength); + byte[] boatStatusBytes = Arrays.copyOfRange(boatStatusesBytes, boatLoopIndex, boatLoopIndex + boatStatusByteLength); - BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder(); + BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder(); - boatStatuses.add(boatStatusDecoder.decode(boatStatusBytes)); - } + boatStatuses.add(boatStatusDecoder.decode(boatStatusBytes)); + } - message = new RaceStatus( - versionNum, - time, - raceID, - raceStatus, - expectedStart, - windDirection, - windSpeedKnots, - raceType, - boatStatuses ); + message = new RaceStatus( + versionNum, + time, + raceID, + raceStatus, + expectedStart, + windDirection, + windSpeedKnots, + raceType, + boatStatuses); - return message; + return message; + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode RaceStatus message.", e); + } } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/RequestToJoinDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/RequestToJoinDecoder.java index 1abf61a6..59c881d1 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/RequestToJoinDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/RequestToJoinDecoder.java @@ -1,6 +1,7 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.Enums.RequestToJoinEnum; import network.Messages.RequestToJoin; @@ -31,20 +32,26 @@ public class RequestToJoinDecoder implements MessageDecoder{ @Override - public AC35Data decode(byte[] encodedRequest) { + public AC35Data decode(byte[] encodedRequest) throws InvalidMessageException { this.encodedRequest = encodedRequest; - //Request type is first four bytes. - byte[] requestTypeBytes = Arrays.copyOfRange(encodedRequest, 0, 4); + try { - //Request type is an integral type. - int requestTypeInt = ByteConverter.bytesToInt(requestTypeBytes); - RequestToJoinEnum requestType = RequestToJoinEnum.fromInt(requestTypeInt); + //Request type is first four bytes. + byte[] requestTypeBytes = Arrays.copyOfRange(encodedRequest, 0, 4); + //Request type is an integral type. + int requestTypeInt = ByteConverter.bytesToInt(requestTypeBytes); + RequestToJoinEnum requestType = RequestToJoinEnum.fromInt(requestTypeInt); - message = new RequestToJoin(requestType); - return message; + message = new RequestToJoin(requestType); + + return message; + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode RequestToJoin message.", e); + } } diff --git a/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java index 99c56e28..80a62048 100644 --- a/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java +++ b/racevisionGame/src/main/java/network/MessageDecoders/XMLMessageDecoder.java @@ -1,5 +1,6 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.Enums.XMLMessageType; import network.Messages.XMLMessage; @@ -35,36 +36,42 @@ public class XMLMessageDecoder implements MessageDecoder { @Override - public AC35Data decode(byte[] encodedMessage) { + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { this.encodedMessage = encodedMessage; - 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); + try { + 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); + 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 ); - return message; + message = new XMLMessage( + messageVersionNumber, + ackNumber, + timeStamp, + xmlMsgSubType, + sequenceNumber, + xmlMessage); + + return message; + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode XMLMessage message.", e); + } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/AverageWindEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/AverageWindEncoder.java index dc1966fc..b8bce3df 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/AverageWindEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/AverageWindEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.AverageWind; @@ -24,63 +25,68 @@ public class AverageWindEncoder implements MessageEncoder { @Override - public byte[] encode(AC35Data message) { + public byte[] encode(AC35Data message) throws InvalidMessageException { - //Downcast. - AverageWind averageWind = (AverageWind) message; + try { + //Downcast. + AverageWind averageWind = (AverageWind) message; - byte messageVersionNumber = averageWind.getMessageVersionNumber(); - long time = averageWind.getTime(); - byte[] byteTime = longToBytes(time,6); + byte messageVersionNumber = averageWind.getMessageVersionNumber(); - long rawPeriod = averageWind.getRawPeriod(); - int rawPeriodInt = packAverageWindPeriod(rawPeriod); - byte[] byteRawPeriod = intToBytes(rawPeriodInt, 2); + long time = averageWind.getTime(); + byte[] byteTime = longToBytes(time, 6); - double rawSampleSpeed = averageWind.getRawSpeedKnots(); - int rawSampleSpeedInt = packKnotsToMMperSec(rawSampleSpeed); - byte[] byteRawSpeed = intToBytes(rawSampleSpeedInt, 2); + long rawPeriod = averageWind.getRawPeriod(); + int rawPeriodInt = packAverageWindPeriod(rawPeriod); + byte[] byteRawPeriod = intToBytes(rawPeriodInt, 2); - long period2 = averageWind.getSampleTwoPeriod(); - int period2Int = packAverageWindPeriod(period2); - byte[] bytePeriod2 = intToBytes(period2Int, 2); + double rawSampleSpeed = averageWind.getRawSpeedKnots(); + int rawSampleSpeedInt = packKnotsToMMperSec(rawSampleSpeed); + byte[] byteRawSpeed = intToBytes(rawSampleSpeedInt, 2); - double speed2 = averageWind.getSampleTwoSpeedKnots(); - int speed2Int = packKnotsToMMperSec(speed2); - byte[] byteSpeed2 = intToBytes(speed2Int, 2); + long period2 = averageWind.getSampleTwoPeriod(); + int period2Int = packAverageWindPeriod(period2); + byte[] bytePeriod2 = intToBytes(period2Int, 2); - long period3 = averageWind.getSampleThreePeriod(); - int period3Int = packAverageWindPeriod(period3); - byte[] bytePeriod3 = intToBytes(period3Int, 2); + double speed2 = averageWind.getSampleTwoSpeedKnots(); + int speed2Int = packKnotsToMMperSec(speed2); + byte[] byteSpeed2 = intToBytes(speed2Int, 2); - double speed3 = averageWind.getSampleThreeSpeedKnots(); - int speed3Int = packKnotsToMMperSec(speed3); - byte[] byteSpeed3 = intToBytes(speed3Int, 2); + long period3 = averageWind.getSampleThreePeriod(); + int period3Int = packAverageWindPeriod(period3); + byte[] bytePeriod3 = intToBytes(period3Int, 2); - long period4 = averageWind.getSampleFourPeriod(); - int period4Int = packAverageWindPeriod(period4); - byte[] bytePeriod4 = intToBytes(period4Int, 2); + double speed3 = averageWind.getSampleThreeSpeedKnots(); + int speed3Int = packKnotsToMMperSec(speed3); + byte[] byteSpeed3 = intToBytes(speed3Int, 2); - double speed4 = averageWind.getSampleFourSpeedKnots(); - int speed4Int = packKnotsToMMperSec(speed4); - byte[] byteSpeed4 = intToBytes(speed4Int, 2); + long period4 = averageWind.getSampleFourPeriod(); + int period4Int = packAverageWindPeriod(period4); + byte[] bytePeriod4 = intToBytes(period4Int, 2); + double speed4 = averageWind.getSampleFourSpeedKnots(); + int speed4Int = packKnotsToMMperSec(speed4); + byte[] byteSpeed4 = intToBytes(speed4Int, 2); - ByteBuffer result = ByteBuffer.allocate(23); - result.put(messageVersionNumber); - result.put(byteTime); - result.put(byteRawPeriod); - result.put(byteRawSpeed); - result.put(bytePeriod2); - result.put(byteSpeed2); - result.put(bytePeriod3); - result.put(byteSpeed3); - result.put(bytePeriod4); - result.put(byteSpeed4); - return result.array(); + ByteBuffer result = ByteBuffer.allocate(23); + result.put(messageVersionNumber); + result.put(byteTime); + result.put(byteRawPeriod); + result.put(byteRawSpeed); + result.put(bytePeriod2); + result.put(byteSpeed2); + result.put(bytePeriod3); + result.put(byteSpeed3); + result.put(bytePeriod4); + result.put(byteSpeed4); + return result.array(); + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode AverageWind message.", e); + } } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/BoatActionEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/BoatActionEncoder.java index 8083487f..31e02386 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/BoatActionEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/BoatActionEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.BoatAction; @@ -22,19 +23,25 @@ public class BoatActionEncoder implements MessageEncoder { @Override - public byte[] encode(AC35Data message) { + public byte[] encode(AC35Data message) throws InvalidMessageException { - //Downcast. - BoatAction boatAction = (BoatAction) message; + try { - //Message is 1 byte. - ByteBuffer boatActionMessage = ByteBuffer.allocate(1); + //Downcast. + BoatAction boatAction = (BoatAction) message; - boatActionMessage.put(intToBytes(boatAction.getBoatAction().getValue(), 1)); + //Message is 1 byte. + ByteBuffer boatActionMessage = ByteBuffer.allocate(1); - byte [] result = boatActionMessage.array(); + boatActionMessage.put(intToBytes(boatAction.getBoatAction().getValue(), 1)); - return result; + byte[] result = boatActionMessage.array(); + + return result; + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode BoatAction message.", e); + } } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/BoatLocationEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/BoatLocationEncoder.java index 9c3833ac..b982a592 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/BoatLocationEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/BoatLocationEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.BoatLocation; @@ -24,61 +25,67 @@ public class BoatLocationEncoder implements MessageEncoder { @Override - public byte[] encode(AC35Data message) { - - //Downcast. - BoatLocation boatLocation = (BoatLocation) message; - - - int messageVersionNumber = 0b1; - byte[] messageVersionBytes = intToBytes(messageVersionNumber, 1); - byte[] time = longToBytes(boatLocation.getTime(), 6); - byte[] sourceID = intToBytes(boatLocation.getSourceID(), 4); - byte[] seqNum = longToBytes(boatLocation.getSequenceNumber(), 4); - byte[] deviceType = intToBytes(boatLocation.getDeviceType().getValue(), 1); - byte[] latitude = intToBytes(packGPS(boatLocation.getLatitude()), 4); - byte[] longitude = intToBytes(packGPS(boatLocation.getLongitude()), 4); - byte[] altitude = intToBytes(boatLocation.getAltitude(), 4); - byte[] heading = intToBytes(packHeading(boatLocation.getHeading().degrees()), 2); - byte[] pitch = intToBytes(boatLocation.getPitch(), 2); - byte[] roll = intToBytes(boatLocation.getRoll(), 2); - byte[] boatSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSpeedKnots()), 2); - byte[] cog = intToBytes(packHeading(boatLocation.getBoatCOG().degrees()), 2); - byte[] sog = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSOGKnots()), 2); - byte[] apparentWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getApparentWindSpeedKnots()), 2); - byte[] apparentWindAngle = intToBytes(packTrueWindAngle(boatLocation.getApparentWindAngle().degrees()), 2); - byte[] trueWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getTrueWindSpeedKnots()), 2); - byte[] trueWindDirection = intToBytes(packHeading(boatLocation.getTrueWindDirection().degrees()), 2); - byte[] trueWindAngle = intToBytes(packTrueWindAngle(boatLocation.getTrueWindAngle().degrees()), 2); - byte[] currentDrift = intToBytes(packKnotsToMMperSec(boatLocation.getCurrentDriftKnots()), 2); - byte[] currentSet = intToBytes(packHeading(boatLocation.getCurrentSet().degrees()), 2); - byte[] rudderAngle = intToBytes(packTrueWindAngle(boatLocation.getRudderAngle().degrees()), 2); - - ByteBuffer result = ByteBuffer.allocate(56); - result.put(messageVersionBytes); - result.put(time); - result.put(sourceID); - result.put(seqNum); - result.put(deviceType); - result.put(latitude); - result.put(longitude); - result.put(altitude); - result.put(heading); - result.put(pitch); - result.put(roll); - result.put(boatSpeed); - result.put(cog); - result.put(sog); - result.put(apparentWindSpeed); - result.put(apparentWindAngle); - result.put(trueWindSpeed); - result.put(trueWindDirection); - result.put(trueWindAngle); - result.put(currentDrift); - result.put(currentSet); - result.put(rudderAngle); - - return result.array(); + public byte[] encode(AC35Data message) throws InvalidMessageException { + + try { + + //Downcast. + BoatLocation boatLocation = (BoatLocation) message; + + + int messageVersionNumber = 0b1; + byte[] messageVersionBytes = intToBytes(messageVersionNumber, 1); + byte[] time = longToBytes(boatLocation.getTime(), 6); + byte[] sourceID = intToBytes(boatLocation.getSourceID(), 4); + byte[] seqNum = longToBytes(boatLocation.getSequenceNumber(), 4); + byte[] deviceType = intToBytes(boatLocation.getDeviceType().getValue(), 1); + byte[] latitude = intToBytes(packGPS(boatLocation.getLatitude()), 4); + byte[] longitude = intToBytes(packGPS(boatLocation.getLongitude()), 4); + byte[] altitude = intToBytes(boatLocation.getAltitude(), 4); + byte[] heading = intToBytes(packHeading(boatLocation.getHeading().degrees()), 2); + byte[] pitch = intToBytes(boatLocation.getPitch(), 2); + byte[] roll = intToBytes(boatLocation.getRoll(), 2); + byte[] boatSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSpeedKnots()), 2); + byte[] cog = intToBytes(packHeading(boatLocation.getBoatCOG().degrees()), 2); + byte[] sog = intToBytes(packKnotsToMMperSec(boatLocation.getBoatSOGKnots()), 2); + byte[] apparentWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getApparentWindSpeedKnots()), 2); + byte[] apparentWindAngle = intToBytes(packTrueWindAngle(boatLocation.getApparentWindAngle().degrees()), 2); + byte[] trueWindSpeed = intToBytes(packKnotsToMMperSec(boatLocation.getTrueWindSpeedKnots()), 2); + byte[] trueWindDirection = intToBytes(packHeading(boatLocation.getTrueWindDirection().degrees()), 2); + byte[] trueWindAngle = intToBytes(packTrueWindAngle(boatLocation.getTrueWindAngle().degrees()), 2); + byte[] currentDrift = intToBytes(packKnotsToMMperSec(boatLocation.getCurrentDriftKnots()), 2); + byte[] currentSet = intToBytes(packHeading(boatLocation.getCurrentSet().degrees()), 2); + byte[] rudderAngle = intToBytes(packTrueWindAngle(boatLocation.getRudderAngle().degrees()), 2); + + ByteBuffer result = ByteBuffer.allocate(56); + result.put(messageVersionBytes); + result.put(time); + result.put(sourceID); + result.put(seqNum); + result.put(deviceType); + result.put(latitude); + result.put(longitude); + result.put(altitude); + result.put(heading); + result.put(pitch); + result.put(roll); + result.put(boatSpeed); + result.put(cog); + result.put(sog); + result.put(apparentWindSpeed); + result.put(apparentWindAngle); + result.put(trueWindSpeed); + result.put(trueWindDirection); + result.put(trueWindAngle); + result.put(currentDrift); + result.put(currentSet); + result.put(rudderAngle); + + return result.array(); + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode BoatLocation message.", e); + } } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/BoatStatusEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/BoatStatusEncoder.java index 3a40cbba..fe7ecb18 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/BoatStatusEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/BoatStatusEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.BoatStatus; import java.nio.ByteBuffer; @@ -25,32 +26,40 @@ public class BoatStatusEncoder { * Encodes a given BoatStatus message. * @param message The message to encode. * @return The encoded message. + * @throws InvalidMessageException Thrown if the message is invalid in some way, or cannot be encoded. */ - public byte[] encode(BoatStatus message) { - - //Downcast. - BoatStatus boatStatus = (BoatStatus) message; - - //BoatStatus is 20 bytes. - ByteBuffer boatStatusBuffer = ByteBuffer.allocate(20); - - byte[] sourceID = intToBytes(boatStatus.getSourceID()); - byte[] boatStatusBytes = intToBytes(boatStatus.getBoatStatus().getValue(), 1); - byte[] legNum = intToBytes(boatStatus.getLegNumber(), 1); - byte[] numPenalties = intToBytes(boatStatus.getNumPenaltiesAwarded(), 1); - byte[] numPenaltiesServed = intToBytes(boatStatus.getNumPenaltiesServed(), 1); - byte[] estNextMarkTime = longToBytes(boatStatus.getEstTimeAtNextMark(), 6); - byte[] estFinishTime = longToBytes(boatStatus.getEstTimeAtFinish(), 6); - - boatStatusBuffer.put(sourceID); - boatStatusBuffer.put(boatStatusBytes); - boatStatusBuffer.put(legNum); - boatStatusBuffer.put(numPenalties); - boatStatusBuffer.put(numPenaltiesServed); - boatStatusBuffer.put(estNextMarkTime); - boatStatusBuffer.put(estFinishTime); - - return boatStatusBuffer.array(); + public byte[] encode(BoatStatus message) throws InvalidMessageException { + + try { + + + //Downcast. + BoatStatus boatStatus = (BoatStatus) message; + + //BoatStatus is 20 bytes. + ByteBuffer boatStatusBuffer = ByteBuffer.allocate(20); + + byte[] sourceID = intToBytes(boatStatus.getSourceID()); + byte[] boatStatusBytes = intToBytes(boatStatus.getBoatStatus().getValue(), 1); + byte[] legNum = intToBytes(boatStatus.getLegNumber(), 1); + byte[] numPenalties = intToBytes(boatStatus.getNumPenaltiesAwarded(), 1); + byte[] numPenaltiesServed = intToBytes(boatStatus.getNumPenaltiesServed(), 1); + byte[] estNextMarkTime = longToBytes(boatStatus.getEstTimeAtNextMark(), 6); + byte[] estFinishTime = longToBytes(boatStatus.getEstTimeAtFinish(), 6); + + boatStatusBuffer.put(sourceID); + boatStatusBuffer.put(boatStatusBytes); + boatStatusBuffer.put(legNum); + boatStatusBuffer.put(numPenalties); + boatStatusBuffer.put(numPenaltiesServed); + boatStatusBuffer.put(estNextMarkTime); + boatStatusBuffer.put(estFinishTime); + + return boatStatusBuffer.array(); + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode BoatStatus message.", e); + } } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/CourseWindEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/CourseWindEncoder.java index b6e407c0..2f5f4897 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/CourseWindEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/CourseWindEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.CourseWind; import shared.model.Bearing; @@ -28,46 +29,53 @@ public class CourseWindEncoder { * Encodes a given CourseWind message. * @param message The message to encode. * @return The encoded message. + * @throws InvalidMessageException Thrown if the message is invalid in some way, or cannot be encoded. */ - public byte[] encode(CourseWind message) { + public byte[] encode(CourseWind message) throws InvalidMessageException { - CourseWind courseWind = message; + try { + CourseWind courseWind = message; - //CourseWind is 20 bytes. - ByteBuffer courseWindBuffer = ByteBuffer.allocate(20); + //CourseWind is 20 bytes. + ByteBuffer courseWindBuffer = ByteBuffer.allocate(20); - byte[] windId = intToBytes(courseWind.getID(), 1); - byte[] timeBytes = longToBytes(courseWind.getTime(), 6); + byte[] windId = intToBytes(courseWind.getID(), 1); - byte[] raceIDBytes = intToBytes(courseWind.getRaceID(), 4); + byte[] timeBytes = longToBytes(courseWind.getTime(), 6); - int windDirectionInt = packHeading(courseWind.getWindDirection().degrees()); - byte[] windDirectionBytes = intToBytes(windDirectionInt, 2); + byte[] raceIDBytes = intToBytes(courseWind.getRaceID(), 4); - int windSpeedInt = packKnotsToMMperSec(courseWind.getWindSpeedKnots()); - byte[] windSpeedBytes = intToBytes(windSpeedInt, 2); + int windDirectionInt = packHeading(courseWind.getWindDirection().degrees()); + byte[] windDirectionBytes = intToBytes(windDirectionInt, 2); - int bestUpwindAngleInt = packHeading(courseWind.getBestUpwindAngle().degrees()); - byte[] bestUpwindAngleBytes = intToBytes(bestUpwindAngleInt, 2); + int windSpeedInt = packKnotsToMMperSec(courseWind.getWindSpeedKnots()); + byte[] windSpeedBytes = intToBytes(windSpeedInt, 2); - int bestDownwindAngleInt = packHeading(courseWind.getBestDownwindAngle().degrees()); - byte[] bestDownwindAngleBytes = intToBytes(bestDownwindAngleInt, 2); + int bestUpwindAngleInt = packHeading(courseWind.getBestUpwindAngle().degrees()); + byte[] bestUpwindAngleBytes = intToBytes(bestUpwindAngleInt, 2); - byte[] flags = intToBytes(courseWind.getFlags(), 1); + int bestDownwindAngleInt = packHeading(courseWind.getBestDownwindAngle().degrees()); + byte[] bestDownwindAngleBytes = intToBytes(bestDownwindAngleInt, 2); - courseWindBuffer.put(windId); - courseWindBuffer.put(timeBytes); - courseWindBuffer.put(raceIDBytes); - courseWindBuffer.put(windDirectionBytes); - courseWindBuffer.put(windSpeedBytes); - courseWindBuffer.put(bestUpwindAngleBytes); - courseWindBuffer.put(bestDownwindAngleBytes); - courseWindBuffer.put(flags); + byte[] flags = intToBytes(courseWind.getFlags(), 1); - return courseWindBuffer.array(); + courseWindBuffer.put(windId); + courseWindBuffer.put(timeBytes); + courseWindBuffer.put(raceIDBytes); + courseWindBuffer.put(windDirectionBytes); + courseWindBuffer.put(windSpeedBytes); + courseWindBuffer.put(bestUpwindAngleBytes); + courseWindBuffer.put(bestDownwindAngleBytes); + courseWindBuffer.put(flags); + + return courseWindBuffer.array(); + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode CourseWind message.", e); + } } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/CourseWindsEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/CourseWindsEncoder.java index 193144c3..86bd1197 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/CourseWindsEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/CourseWindsEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.BoatAction; import network.Messages.CourseWind; @@ -24,33 +25,39 @@ public class CourseWindsEncoder implements MessageEncoder { @Override - public byte[] encode(AC35Data message) { + public byte[] encode(AC35Data message) throws InvalidMessageException { - //Downcast. - CourseWinds courseWinds = (CourseWinds) message; + try { + //Downcast. + CourseWinds courseWinds = (CourseWinds) message; - byte messageVersionNumber = CourseWinds.currentMessageVersionNumber; - byte byteWindID = courseWinds.getSelectedWindID(); + byte messageVersionNumber = CourseWinds.currentMessageVersionNumber; - byte[] loopcount = intToBytes(courseWinds.getCourseWinds().size(), 1); + byte byteWindID = courseWinds.getSelectedWindID(); - ByteBuffer result = ByteBuffer.allocate(3 + 20 * courseWinds.getCourseWinds().size()); + byte[] loopcount = intToBytes(courseWinds.getCourseWinds().size(), 1); - result.put(messageVersionNumber); - result.put(byteWindID); - result.put(loopcount); + ByteBuffer result = ByteBuffer.allocate(3 + 20 * courseWinds.getCourseWinds().size()); - //Encode each CourseWind. - for (CourseWind wind: courseWinds.getCourseWinds()){ + result.put(messageVersionNumber); + result.put(byteWindID); + result.put(loopcount); - CourseWindEncoder courseWindEncoder = new CourseWindEncoder(); - byte[] encodedCourseWind = courseWindEncoder.encode(wind); + //Encode each CourseWind. + for (CourseWind wind : courseWinds.getCourseWinds()) { - result.put(encodedCourseWind); + CourseWindEncoder courseWindEncoder = new CourseWindEncoder(); + byte[] encodedCourseWind = courseWindEncoder.encode(wind); + + result.put(encodedCourseWind); + } + return result.array(); + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode CourseWinds message.", e); } - return result.array(); } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/HeartBeatEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/HeartBeatEncoder.java index dcf64b61..ecbefe41 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/HeartBeatEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/HeartBeatEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.HeartBeat; @@ -22,18 +23,24 @@ public class HeartBeatEncoder implements MessageEncoder { @Override - public byte[] encode(AC35Data message) { + public byte[] encode(AC35Data message) throws InvalidMessageException { - //Downcast. - HeartBeat heartbeat = (HeartBeat) message; + try { - //Message is 4 bytes. - ByteBuffer heartBeat = ByteBuffer.allocate(4); - heartBeat.put(longToBytes(heartbeat.getSequenceNumber(), 4)); + //Downcast. + HeartBeat heartbeat = (HeartBeat) message; - byte[] result = heartBeat.array(); + //Message is 4 bytes. + ByteBuffer heartBeat = ByteBuffer.allocate(4); + heartBeat.put(longToBytes(heartbeat.getSequenceNumber(), 4)); - return result; + byte[] result = heartBeat.array(); + + return result; + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode HeartBeat message.", e); + } } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/JoinAcceptanceEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/JoinAcceptanceEncoder.java index 2b23c0dd..8f236454 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/JoinAcceptanceEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/JoinAcceptanceEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.JoinAcceptance; import network.Utils.ByteConverter; @@ -23,22 +24,28 @@ public class JoinAcceptanceEncoder implements MessageEncoder { @Override - public byte[] encode(AC35Data message) { + public byte[] encode(AC35Data message) throws InvalidMessageException { - //Downcast. - JoinAcceptance joinAcceptance = (JoinAcceptance) message; + try { - //Message is 5 bytes. - ByteBuffer joinAcceptanceBuffer = ByteBuffer.allocate(5); + //Downcast. + JoinAcceptance joinAcceptance = (JoinAcceptance) message; - //Source ID is first four bytes. - joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getSourceID(), 4)); - //Acceptance type is next byte. - joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getAcceptanceType().getValue(), 1)); + //Message is 5 bytes. + ByteBuffer joinAcceptanceBuffer = ByteBuffer.allocate(5); - byte [] result = joinAcceptanceBuffer.array(); + //Source ID is first four bytes. + joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getSourceID(), 4)); + //Acceptance type is next byte. + joinAcceptanceBuffer.put(intToBytes(joinAcceptance.getAcceptanceType().getValue(), 1)); - return result; + byte[] result = joinAcceptanceBuffer.array(); + + return result; + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode JoinAcceptance message.", e); + } } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/MarkRoundingEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/MarkRoundingEncoder.java index de86691a..2c30b0cd 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/MarkRoundingEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/MarkRoundingEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.MarkRounding; @@ -23,35 +24,41 @@ public class MarkRoundingEncoder implements MessageEncoder { @Override - public byte[] encode(AC35Data message) { - - //Downcast. - MarkRounding markRounding = (MarkRounding) message; - - byte messageVersionNumber = markRounding.getMessageVersionNumber(); - byte[] byteTime = longToBytes(markRounding.getTime(), 6); - byte[] byteAck = intToBytes(markRounding.getAckNum(), 2); - byte[] byteRaceID = intToBytes(markRounding.getRaceID(), 4); - byte[] byteSourceID = intToBytes(markRounding.getSourceID(), 4); - byte[] byteBoatStatus = intToBytes(markRounding.getBoatStatus().getValue(), 1); - byte[] byteRoundingSide = intToBytes(markRounding.getRoundingSide().getValue(), 1); - byte[] byteMarkType = intToBytes(markRounding.getMarkType().getValue(), 1); - byte[] byteMarkID = intToBytes(markRounding.getMarkID(), 1); - - - ByteBuffer result = ByteBuffer.allocate(21); - - result.put(messageVersionNumber); - result.put(byteTime); - result.put(byteAck); - result.put(byteRaceID); - result.put(byteSourceID); - result.put(byteBoatStatus); - result.put(byteRoundingSide); - result.put(byteMarkType); - result.put(byteMarkID); - - return result.array(); + public byte[] encode(AC35Data message) throws InvalidMessageException { + + try { + + //Downcast. + MarkRounding markRounding = (MarkRounding) message; + + byte messageVersionNumber = markRounding.getMessageVersionNumber(); + byte[] byteTime = longToBytes(markRounding.getTime(), 6); + byte[] byteAck = intToBytes(markRounding.getAckNum(), 2); + byte[] byteRaceID = intToBytes(markRounding.getRaceID(), 4); + byte[] byteSourceID = intToBytes(markRounding.getSourceID(), 4); + byte[] byteBoatStatus = intToBytes(markRounding.getBoatStatus().getValue(), 1); + byte[] byteRoundingSide = intToBytes(markRounding.getRoundingSide().getValue(), 1); + byte[] byteMarkType = intToBytes(markRounding.getMarkType().getValue(), 1); + byte[] byteMarkID = intToBytes(markRounding.getMarkID(), 1); + + + ByteBuffer result = ByteBuffer.allocate(21); + + result.put(messageVersionNumber); + result.put(byteTime); + result.put(byteAck); + result.put(byteRaceID); + result.put(byteSourceID); + result.put(byteBoatStatus); + result.put(byteRoundingSide); + result.put(byteMarkType); + result.put(byteMarkID); + + return result.array(); + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode MarkRounding message.", e); + } } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/MessageEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/MessageEncoder.java index d5ec4cd8..f91bb639 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/MessageEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/MessageEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; @@ -15,7 +16,8 @@ public interface MessageEncoder { * Encodes a given message. * @param message The message to encode. * @return Message in byte encoded form. + * @throws InvalidMessageException Thrown if the message is invalid in some way, or cannot be encoded. */ - public byte[] encode(AC35Data message); + public byte[] encode(AC35Data message) throws InvalidMessageException; } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/RaceStartStatusEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/RaceStartStatusEncoder.java index f2d41d20..ad9a65f0 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/RaceStartStatusEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/RaceStartStatusEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.RaceStartStatus; import network.Utils.ByteConverter; @@ -24,28 +25,34 @@ public class RaceStartStatusEncoder implements MessageEncoder { @Override - public byte[] encode(AC35Data message) { + public byte[] encode(AC35Data message) throws InvalidMessageException { - //Downcast. - RaceStartStatus raceStartStatus = (RaceStartStatus) message; + try { + //Downcast. + RaceStartStatus raceStartStatus = (RaceStartStatus) message; - byte messageVersion = raceStartStatus.getMessageVersionNumber(); - byte[] timestamp = longToBytes(raceStartStatus.getTimestamp(), 6); - byte[] ackNumber = intToBytes(raceStartStatus.getAckNum(), 2); - byte[] raceStartTime = longToBytes(raceStartStatus.getRaceStartTime(), 6); - byte[] raceIdentifier = intToBytes(raceStartStatus.getRaceID()); - byte[] notificationType = intToBytes(raceStartStatus.getNotificationType().getValue(), 1); - ByteBuffer result = ByteBuffer.allocate(20); - result.put(messageVersion); - result.put(timestamp); - result.put(ackNumber); - result.put(raceStartTime); - result.put(raceIdentifier); - result.put(notificationType); + byte messageVersion = raceStartStatus.getMessageVersionNumber(); + byte[] timestamp = longToBytes(raceStartStatus.getTimestamp(), 6); + byte[] ackNumber = intToBytes(raceStartStatus.getAckNum(), 2); + byte[] raceStartTime = longToBytes(raceStartStatus.getRaceStartTime(), 6); + byte[] raceIdentifier = intToBytes(raceStartStatus.getRaceID()); + byte[] notificationType = intToBytes(raceStartStatus.getNotificationType().getValue(), 1); - return result.array(); + ByteBuffer result = ByteBuffer.allocate(20); + result.put(messageVersion); + result.put(timestamp); + result.put(ackNumber); + result.put(raceStartTime); + result.put(raceIdentifier); + result.put(notificationType); + + return result.array(); + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode RaceStartStatus message.", e); + } } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/RaceStatusEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/RaceStatusEncoder.java index fcb06d82..fd87cd0c 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/RaceStatusEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/RaceStatusEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.BoatStatus; import network.Messages.RaceStatus; @@ -28,68 +29,74 @@ public class RaceStatusEncoder implements MessageEncoder { @Override - public byte[] encode(AC35Data message) { + public byte[] encode(AC35Data message) throws InvalidMessageException { - //Downcast. - RaceStatus raceStatus = (RaceStatus) message; + try { + //Downcast. + RaceStatus raceStatus = (RaceStatus) message; - List boatStatuses = raceStatus.getBoatStatuses(); - //24 byte header, plus 20 bytes per boat status. - ByteBuffer raceStatusMessage = ByteBuffer.allocate(24 + 20 * boatStatuses.size()); + List boatStatuses = raceStatus.getBoatStatuses(); - //Version Number 1 bytes. this changes with the pdf. (2) - byte versionNum = 0b10; + //24 byte header, plus 20 bytes per boat status. + ByteBuffer raceStatusMessage = ByteBuffer.allocate(24 + 20 * boatStatuses.size()); - //time (6 bytes) - byte[] timeBytes = longToBytes(raceStatus.getCurrentTime(), 6); + //Version Number 1 bytes. this changes with the pdf. (2) + byte versionNum = 0b10; - //race identifier in case multiple races are going at once. - byte[] raceID = intToBytes(raceStatus.getRaceID()); + //time (6 bytes) + byte[] timeBytes = longToBytes(raceStatus.getCurrentTime(), 6); - //race status 0 - 10 - byte[] raceStatusByte = intToBytes(raceStatus.getRaceStatus().getValue(), 1); + //race identifier in case multiple races are going at once. + byte[] raceID = intToBytes(raceStatus.getRaceID()); - //number of milliseconds from Jan 1, 1970 for when the data is valid - byte[] expectedStart = longToBytes(raceStatus.getExpectedStartTime(), 6); + //race status 0 - 10 + byte[] raceStatusByte = intToBytes(raceStatus.getRaceStatus().getValue(), 1); - //North = 0x0000 East = 0x4000 South = 0x8000. - int windDirectionInt = AC35UnitConverter.packHeading(raceStatus.getWindDirection().degrees()); - byte[] raceWind = intToBytes(windDirectionInt, 2); + //number of milliseconds from Jan 1, 1970 for when the data is valid + byte[] expectedStart = longToBytes(raceStatus.getExpectedStartTime(), 6); - //mm/sec - int windSpeedInt = AC35UnitConverter.packKnotsToMMperSec(raceStatus.getWindSpeed()); - byte[] windSpeed = intToBytes(windSpeedInt, 2); + //North = 0x0000 East = 0x4000 South = 0x8000. + int windDirectionInt = AC35UnitConverter.packHeading(raceStatus.getWindDirection().degrees()); + byte[] raceWind = intToBytes(windDirectionInt, 2); + //mm/sec + int windSpeedInt = AC35UnitConverter.packKnotsToMMperSec(raceStatus.getWindSpeed()); + byte[] windSpeed = intToBytes(windSpeedInt, 2); - byte[] numBoats = intToBytes(boatStatuses.size(), 1); - //1 match race, 2 fleet race - byte[] bytesRaceType = intToBytes(raceStatus.getRaceType().getValue(), 1); + byte[] numBoats = intToBytes(boatStatuses.size(), 1); + //1 match race, 2 fleet race + byte[] bytesRaceType = intToBytes(raceStatus.getRaceType().getValue(), 1); - raceStatusMessage.put(versionNum); - raceStatusMessage.put(timeBytes); - raceStatusMessage.put(raceID); - raceStatusMessage.put(raceStatusByte); - raceStatusMessage.put(expectedStart); - raceStatusMessage.put(raceWind); - raceStatusMessage.put(windSpeed); - raceStatusMessage.put(numBoats); - raceStatusMessage.put(bytesRaceType); - //Encode each BoatStatus. - for (BoatStatus boatStatus : boatStatuses) { + raceStatusMessage.put(versionNum); + raceStatusMessage.put(timeBytes); + raceStatusMessage.put(raceID); + raceStatusMessage.put(raceStatusByte); + raceStatusMessage.put(expectedStart); + raceStatusMessage.put(raceWind); + raceStatusMessage.put(windSpeed); + raceStatusMessage.put(numBoats); + raceStatusMessage.put(bytesRaceType); - BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder(); + //Encode each BoatStatus. + for (BoatStatus boatStatus : boatStatuses) { - byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus); + BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder(); - raceStatusMessage.put(boatStatusEncoded); - } + byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus); + + raceStatusMessage.put(boatStatusEncoded); + } - return raceStatusMessage.array(); + return raceStatusMessage.array(); + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode RaceStatus message.", e); + } } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java index b508030f..f82aff38 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/RaceVisionByteEncoder.java @@ -113,8 +113,10 @@ public class RaceVisionByteEncoder { MessageEncoder encoder = null; try { encoder = EncoderFactory.create(message.getType()); + } catch (InvalidMessageTypeException e) { throw new InvalidMessageException("Could not create encoder for MessageType: " + message.getType(), e); + } byte[] encodedMessage = encoder.encode(message); diff --git a/racevisionGame/src/main/java/network/MessageEncoders/RequestToJoinEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/RequestToJoinEncoder.java index b01e92de..e5ef7eee 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/RequestToJoinEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/RequestToJoinEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.RequestToJoin; import network.Utils.ByteConverter; @@ -21,19 +22,25 @@ public class RequestToJoinEncoder implements MessageEncoder { @Override - public byte[] encode(AC35Data message) { + public byte[] encode(AC35Data message) throws InvalidMessageException { - //Downcast. - RequestToJoin requestToJoin = (RequestToJoin) message; + try { + //Downcast. + RequestToJoin requestToJoin = (RequestToJoin) message; - ByteBuffer requestToJoinBuffer = ByteBuffer.allocate(4); - requestToJoinBuffer.put(ByteConverter.intToBytes(requestToJoin.getRequestType().getValue(), 4)); + ByteBuffer requestToJoinBuffer = ByteBuffer.allocate(4); - byte [] result = requestToJoinBuffer.array(); + requestToJoinBuffer.put(ByteConverter.intToBytes(requestToJoin.getRequestType().getValue(), 4)); - return result; + byte[] result = requestToJoinBuffer.array(); + + return result; + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode RequestToJoin message.", e); + } } } diff --git a/racevisionGame/src/main/java/network/MessageEncoders/XMLMessageEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/XMLMessageEncoder.java index 92a75ca7..c0039d65 100644 --- a/racevisionGame/src/main/java/network/MessageEncoders/XMLMessageEncoder.java +++ b/racevisionGame/src/main/java/network/MessageEncoders/XMLMessageEncoder.java @@ -1,6 +1,7 @@ package network.MessageEncoders; +import network.Exceptions.InvalidMessageException; import network.Messages.AC35Data; import network.Messages.XMLMessage; @@ -24,39 +25,45 @@ public class XMLMessageEncoder implements MessageEncoder { @Override - public byte[] encode(AC35Data message) { + public byte[] encode(AC35Data message) throws InvalidMessageException { - //Downcast. - XMLMessage xmlMessage = (XMLMessage) message; + try { + //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); + byte[] messageBytes = xmlMessage.getXmlMessage().getBytes(StandardCharsets.UTF_8); - //ackNumber converted to bytes - byte[] ackNumberBytes = intToBytes(xmlMessage.getAckNumber(), 2); + //Message is 14 + xmlMessage.length bytes. + ByteBuffer tempOutputByteBuffer = ByteBuffer.allocate(14 + messageBytes.length); - //Timestamp converted to bytes. - byte[] timestampBytes = longToBytes(xmlMessage.getTimeStamp(), 6); + //ackNumber converted to bytes + byte[] ackNumberBytes = intToBytes(xmlMessage.getAckNumber(), 2); - //sequenceNumber converted to bytes - byte[] sequenceNumberBytes = intToBytes(xmlMessage.getSequenceNumber(), 2); + //Timestamp converted to bytes. + byte[] timestampBytes = longToBytes(xmlMessage.getTimeStamp(), 6); - //xmlMsgLength converted to bytes - byte[] xmlMsgLengthBytes = intToBytes(xmlMessage.getXmlMsgLength(), 2); + //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(); + 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(); + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode XMLMessage message.", e); + } } } diff --git a/racevisionGame/src/main/java/visualiser/gameController/ControllerClient.java b/racevisionGame/src/main/java/visualiser/gameController/ControllerClient.java index 6c49cd69..bb91f2a4 100644 --- a/racevisionGame/src/main/java/visualiser/gameController/ControllerClient.java +++ b/racevisionGame/src/main/java/visualiser/gameController/ControllerClient.java @@ -56,18 +56,21 @@ public class ControllerClient { BoatAction boatAction = new BoatAction(protocolCode); //Encode BoatAction. - byte[] encodedBoatAction = new byte[0]; try { - encodedBoatAction = RaceVisionByteEncoder.encode(boatAction); + byte[] encodedBoatAction = RaceVisionByteEncoder.encode(boatAction); + + BinaryMessageEncoder binaryMessage = new BinaryMessageEncoder(MessageType.BOATACTION, System.currentTimeMillis(), 0, + (short) encodedBoatAction.length, encodedBoatAction); + + System.out.println("Sending out key: " + protocolCode); + outputStream.write(binaryMessage.getFullMessage()); + } catch (InvalidMessageException e) { Logger.getGlobal().log(Level.WARNING, "Could not encode BoatAction: " + boatAction, e); + } - BinaryMessageEncoder binaryMessage = new BinaryMessageEncoder(MessageType.BOATACTION, System.currentTimeMillis(), 0, - (short) encodedBoatAction.length, encodedBoatAction); - System.out.println("Sending out key: " + protocolCode); - outputStream.write(binaryMessage.getFullMessage()); } } } diff --git a/racevisionGame/src/main/java/visualiser/gameController/ControllerServer.java b/racevisionGame/src/main/java/visualiser/gameController/ControllerServer.java index df54d16d..d4c62d11 100644 --- a/racevisionGame/src/main/java/visualiser/gameController/ControllerServer.java +++ b/racevisionGame/src/main/java/visualiser/gameController/ControllerServer.java @@ -1,6 +1,7 @@ package visualiser.gameController; import network.BinaryMessageDecoder; +import network.Exceptions.InvalidMessageException; import network.MessageDecoders.BoatActionDecoder; import network.Messages.BoatAction; import network.Messages.Enums.BoatActionEnum; @@ -10,6 +11,8 @@ import visualiser.gameController.Keys.KeyFactory; import java.io.DataInputStream; import java.io.IOException; import java.net.Socket; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Service for dispatching key press data to race from client @@ -46,12 +49,22 @@ public class ControllerServer implements Runnable { byte[] message = new byte[20]; try { if (inputStream.available() > 0) { + inputStream.read(message); + BinaryMessageDecoder encodedMessage = new BinaryMessageDecoder(message); BoatActionDecoder boatActionDecoder = new BoatActionDecoder(); - boatActionDecoder.decode(encodedMessage.getMessageBody()); - BoatAction boatAction = boatActionDecoder.getMessage(); - System.out.println("Received key: " + boatAction.getBoatAction()); + + try { + boatActionDecoder.decode(encodedMessage.getMessageBody()); + BoatAction boatAction = boatActionDecoder.getMessage(); + System.out.println("Received key: " + boatAction.getBoatAction()); + + } catch (InvalidMessageException e) { + Logger.getGlobal().log(Level.WARNING, "Could not decode BoatAction message.", e); + } + + } } catch (IOException e) { e.printStackTrace(); diff --git a/racevisionGame/src/test/java/network/MessageDecoders/BoatStatusDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/BoatStatusDecoderTest.java index 088a85cb..45a2e1db 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/BoatStatusDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/BoatStatusDecoderTest.java @@ -1,5 +1,6 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.MessageEncoders.BoatStatusEncoder; import network.MessageEncoders.RaceVisionByteEncoder; import network.Messages.BoatStatus; @@ -55,8 +56,9 @@ public class BoatStatusDecoderTest { * Encodes and decodes a BoatStatus, and returns it. * @param boatStatus The BoatStatus to encode and decode. * @return The decoded BoatStatus. + * @throws InvalidMessageException Thrown if message cannot be encoded or decoded. */ - private static BoatStatus encodeDecodeBoatStatus(BoatStatus boatStatus) { + private static BoatStatus encodeDecodeBoatStatus(BoatStatus boatStatus) throws InvalidMessageException { BoatStatusEncoder boatStatusEncoder = new BoatStatusEncoder(); byte[] boatStatusEncoded = boatStatusEncoder.encode(boatStatus); diff --git a/racevisionGame/src/test/java/network/MessageDecoders/CourseWindDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/CourseWindDecoderTest.java index 0a8753db..cef452f2 100644 --- a/racevisionGame/src/test/java/network/MessageDecoders/CourseWindDecoderTest.java +++ b/racevisionGame/src/test/java/network/MessageDecoders/CourseWindDecoderTest.java @@ -1,5 +1,6 @@ package network.MessageDecoders; +import network.Exceptions.InvalidMessageException; import network.MessageEncoders.CourseWindEncoder; import network.Messages.BoatStatus; import network.Messages.CourseWind; @@ -43,8 +44,9 @@ public class CourseWindDecoderTest { * Encodes and decodes a CourseWind, and returns it. * @param courseWind The CourseWind to encode and decode. * @return The decoded CourseWind. + * @throws InvalidMessageException Thrown if message cannot be encoded or decoded. */ - private static CourseWind encodeDecodeCourseWind(CourseWind courseWind) { + private static CourseWind encodeDecodeCourseWind(CourseWind courseWind) throws InvalidMessageException { CourseWindEncoder courseWindEncoder = new CourseWindEncoder(); byte[] courseWindEncoded = courseWindEncoder.encode(courseWind);