Merge branch 'master' into story_64_sails

# Conflicts:
#	racevisionGame/src/main/java/mock/app/MockOutput.java
#	racevisionGame/src/main/java/mock/model/MockRace.java
#	racevisionGame/src/main/java/mock/model/commandFactory/CommandFactory.java
#	racevisionGame/src/main/java/network/MessageDecoders/BoatActionDecoder.java
#	racevisionGame/src/main/java/network/MessageDecoders/BoatLocationDecoder.java
#	racevisionGame/src/main/java/visualiser/app/VisualiserInput.java
#	racevisionGame/src/main/java/visualiser/gameController/ControllerServer.java
#	racevisionGame/src/main/java/visualiser/model/ResizableRaceCanvas.java
#	racevisionGame/src/main/java/visualiser/model/VisualiserRace.java
#	racevisionGame/src/main/resources/visualiser/scenes/connect.fxml
#	racevisionGame/src/main/resources/visualiser/scenes/lobby.fxml
#	racevisionGame/src/test/java/mock/model/MockRaceTest.java
#	racevisionGame/src/test/java/network/Utils/AC35UnitConverterTest.java
#	racevisionGame/src/test/java/network/XMLMessageEncoderTest.java
This commit is contained in:
Joseph
2017-08-17 09:13:49 +12:00
184 changed files with 12652 additions and 4461 deletions
@@ -1,56 +1,107 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.AverageWind;
import network.Utils.ByteConverter;
import static network.Utils.AC35UnitConverter.*;
import java.util.Arrays;
/**
* Created by hba56 on 23/04/17.
* Decodes {@link AverageWind} messages.
*/
public class AverageWindDecoder {
byte messageVersionNumber;
byte[] byteTime;
byte[] byteRawPeriod;
byte[] byteRawSpeed;
byte[] bytePeriod2;
byte[] byteSpeed2;
byte[] bytePeriod3;
byte[] byteSpeed3;
byte[] bytePeriod4;
byte[] byteSpeed4;
public class AverageWindDecoder implements MessageDecoder {
AverageWind averageWind;
/**
* The encoded message.
*/
private byte[] encodedMessage;
public AverageWindDecoder(byte[] encodedAverageWind) {
messageVersionNumber = encodedAverageWind[0];
byteTime = Arrays.copyOfRange(encodedAverageWind, 1, 7);
byteRawPeriod = Arrays.copyOfRange(encodedAverageWind, 7, 9);
byteRawSpeed = Arrays.copyOfRange(encodedAverageWind, 9, 11);
bytePeriod2 = Arrays.copyOfRange(encodedAverageWind, 11, 13);
byteSpeed2 = Arrays.copyOfRange(encodedAverageWind, 13, 15);
bytePeriod3 = Arrays.copyOfRange(encodedAverageWind, 15, 17);
byteSpeed3 = Arrays.copyOfRange(encodedAverageWind, 17, 19);
bytePeriod4 = Arrays.copyOfRange(encodedAverageWind, 19, 21);
byteSpeed4 = Arrays.copyOfRange(encodedAverageWind, 21, 23);
/**
* The decoded message.
*/
private AverageWind message;
int msgNum = ByteConverter.bytesToInt(messageVersionNumber);
long lngTime = ByteConverter.bytesToLong(byteTime);
int intRawPeriod = ByteConverter.bytesToInt(byteRawPeriod);
int intRawSpeed = ByteConverter.bytesToInt(byteRawSpeed);
int intPeriod2 = ByteConverter.bytesToInt(bytePeriod2);
int intSpeed2 = ByteConverter.bytesToInt(byteSpeed2);
int intPeriod3 = ByteConverter.bytesToInt(bytePeriod3);
int intSpeed3 = ByteConverter.bytesToInt(byteSpeed3);
int intPeriod4 = ByteConverter.bytesToInt(bytePeriod4);
int intSpeed4 = ByteConverter.bytesToInt(byteSpeed4);
this.averageWind = new AverageWind(msgNum, lngTime, intRawPeriod, intRawSpeed, intPeriod2, intSpeed2, intPeriod3, intSpeed3, intPeriod4, intSpeed4);
public AverageWindDecoder() {
}
@Override
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
try {
byte messageVersionNumber = encodedMessage[0];
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[] 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[] 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[] 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[] 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;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode AverageWind message.", e);
}
}
public AverageWind getAverageWind() {
return averageWind;
/**
* Returns the decoded message.
* @return The decoded message.
*/
public AverageWind getMessage() {
return message;
}
}
@@ -1,18 +1,56 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.BoatAction;
import network.Messages.Enums.BoatActionEnum;
public class BoatActionDecoder {
byte byteBoatAction;
BoatActionEnum boatAction;
import java.util.Arrays;
public BoatActionDecoder(byte[] encodedBoatAction) {
byteBoatAction = encodedBoatAction[0];
/**
* Decodes {@link BoatAction} messages.
*/
public class BoatActionDecoder implements MessageDecoder {
boatAction = BoatActionEnum.fromByte(byteBoatAction);
/**
* The encoded message.
*/
private byte[] encodedMessage;
/**
* The decoded message.
*/
private BoatAction message;
/**
* Constructs a decoder to decode a given message.
*/
public BoatActionDecoder() {
}
public BoatActionEnum getBoatAction() {
return boatAction;
@Override
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
try {
BoatActionEnum boatActionEnum = BoatActionEnum.fromByte(encodedMessage[0]);
message = new BoatAction(boatActionEnum);
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode BoatAction message.", e);
}
}
}
/**
* Returns the decoded message.
* @return The decoded message.
*/
public BoatAction getMessage() {
return message;
}
}
@@ -1,140 +1,168 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.BoatLocation;
import network.Messages.Enums.BoatLocationDeviceEnum;
import shared.model.Azimuth;
import shared.model.Bearing;
import java.util.Arrays;
import static network.Utils.AC35UnitConverter.*;
import static network.Utils.ByteConverter.*;
/**
* Created by hba56 on 21/04/17.
* Decodes {@link BoatLocation} messages.
*/
public class BoatLocationDecoder {
private byte messageVersionNumber;
private byte[] time;
private byte[] sourceID;
private byte[] seqNum;
private byte deviceType;
private byte[] latitude;
private byte[] longitude;
private byte[] altitude;
private byte[] heading;
private byte[] pitch;
private byte[] roll;
private byte[] boatSpeed;
private byte[] cog;
private byte[] sog;
private byte[] apparentWindSpeed;
private byte[] apparentWindAngle;
private byte[] trueWindSpeed;
private byte[] trueWindDirection;
private byte[] trueWindAngle;
private byte[] currentDrift;
private byte[] currentSet;
private byte[] rudderAngle;
public class BoatLocationDecoder implements MessageDecoder {
/**
* The encoded message.
*/
private byte[] encodedMessage;
/**
* The decoded message.
*/
private BoatLocation message;
public BoatLocationDecoder(byte[] encodedBoatLocation) {
byte numMessageVersionNumber = 0;
long numTime = 0;
int numSourceID = 0;
int numSeqNum = 0;
byte numDeviceType = 0;
int numLatitude = 0;
int numLongitude = 0;
int numAltitude = 0;
int numHeading = 0;
short numPitch = 0;
short numRoll = 0;
int numBoatSpeed = 0;
int numCog = 0;
int numSog = 0;
int numApparentWindSpeed = 0;
short numApparentWindAngle = 0;
int numTrueWindSpeed = 0;
short numTrueWindDirection = 0;
short numTrueWindAngle = 0;
int numCurrentDrift = 0;
int numCurrentSet = 0;
short numRudderAngle = 0;
try {
messageVersionNumber = encodedBoatLocation[0];
numMessageVersionNumber = messageVersionNumber;
time = Arrays.copyOfRange(encodedBoatLocation, 1, 7);
numTime = bytesToLong(time);
sourceID = Arrays.copyOfRange(encodedBoatLocation, 7, 11);
numSourceID = bytesToInt(sourceID);
seqNum = Arrays.copyOfRange(encodedBoatLocation, 11, 15);
numSeqNum = bytesToInt(seqNum);
deviceType = encodedBoatLocation[15];
numDeviceType = deviceType;
latitude = Arrays.copyOfRange(encodedBoatLocation, 16, 20);
numLatitude = bytesToInt(latitude);
longitude = Arrays.copyOfRange(encodedBoatLocation, 20, 24);
numLongitude = bytesToInt(longitude);
altitude = Arrays.copyOfRange(encodedBoatLocation, 24, 28);
numAltitude = bytesToInt(altitude);
heading = Arrays.copyOfRange(encodedBoatLocation, 28, 30);
numHeading = bytesToInt(heading);
pitch = Arrays.copyOfRange(encodedBoatLocation, 30, 32);
numPitch = bytesToShort(pitch);
roll = Arrays.copyOfRange(encodedBoatLocation, 32, 34);
numRoll = bytesToShort(roll);
boatSpeed = Arrays.copyOfRange(encodedBoatLocation, 34, 36);
numBoatSpeed = bytesToInt(boatSpeed);
cog = Arrays.copyOfRange(encodedBoatLocation, 36, 38);
numCog = bytesToInt(cog);
sog = Arrays.copyOfRange(encodedBoatLocation, 38, 40);
numSog = bytesToInt(sog);
apparentWindSpeed = Arrays.copyOfRange(encodedBoatLocation, 40, 42);
numApparentWindSpeed = bytesToInt(apparentWindSpeed);
apparentWindAngle = Arrays.copyOfRange(encodedBoatLocation, 42, 44);
numApparentWindAngle = bytesToShort(apparentWindAngle);
trueWindSpeed = Arrays.copyOfRange(encodedBoatLocation, 44, 46);
numTrueWindSpeed = bytesToInt(trueWindSpeed);
trueWindDirection = Arrays.copyOfRange(encodedBoatLocation, 46, 48);
numTrueWindDirection = bytesToShort(trueWindDirection);
trueWindAngle = Arrays.copyOfRange(encodedBoatLocation, 48, 50);
numTrueWindAngle = bytesToShort(trueWindAngle);
currentDrift = Arrays.copyOfRange(encodedBoatLocation, 50, 52);
numCurrentDrift = bytesToInt(currentDrift);
currentSet = Arrays.copyOfRange(encodedBoatLocation, 52, 54);
numCurrentSet = bytesToShort(currentSet);
rudderAngle = Arrays.copyOfRange(encodedBoatLocation, 54, 56);
numRudderAngle = bytesToShort(rudderAngle);
} catch(ArrayIndexOutOfBoundsException e){
}
message = new BoatLocation(numMessageVersionNumber, numTime,
numSourceID, numSeqNum, numDeviceType, numLatitude,
numLongitude, numAltitude, numHeading, numPitch,
numRoll, numBoatSpeed, numCog, numSog, numApparentWindSpeed,
numApparentWindAngle, numTrueWindSpeed, numTrueWindDirection,
numTrueWindAngle, numCurrentDrift, numCurrentSet, numRudderAngle
);/*
message = new BoatLocation(messageVersionNumber, bytesToLong(time),
bytesToInt(sourceID), bytesToInt(seqNum),
deviceType, bytesToInt(latitude),
bytesToInt(longitude), bytesToInt(altitude),
bytesToInt(heading), bytesToShort(pitch),
bytesToShort(roll), bytesToInt(boatSpeed),
bytesToInt(cog), bytesToInt(sog),
bytesToInt(apparentWindSpeed), bytesToShort(apparentWindAngle),
bytesToInt(trueWindSpeed), bytesToShort(trueWindDirection),
bytesToShort(trueWindAngle), bytesToInt(currentDrift),
bytesToInt(currentSet), bytesToShort(rudderAngle)
);*/
// System.out.println(bytesToInt(sourceID));
// System.out.println(bytesToInt(boatSpeed));
/**
* Constructs a decoder to decode a given message.
*/
public BoatLocationDecoder() {
}
@Override
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
try {
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);
}
}
/**
* Returns the decoded message.
* @return The decoded message.
*/
public BoatLocation getMessage() {
return message;
}
@@ -0,0 +1,98 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.BoatStatus;
import network.Messages.Enums.BoatStatusEnum;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static network.Utils.ByteConverter.*;
/**
* Decodes {@link BoatStatus} messages.
*/
public class BoatStatusDecoder {
/**
* The encoded message.
*/
private byte[] encodedMessage;
/**
* The decoded message.
*/
private BoatStatus message;
/**
* Constructs a decoder to decode a given message.
*/
public 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) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
try {
byte[] sourceIDBytes = Arrays.copyOfRange(encodedMessage, 0, 4);
int sourceID = bytesToInt(sourceIDBytes);
byte[] boatStatusBytes = Arrays.copyOfRange(encodedMessage, 4, 5);
BoatStatusEnum boatStatus = BoatStatusEnum.fromByte(boatStatusBytes[0]);
byte[] legNumberBytes = Arrays.copyOfRange(encodedMessage, 5, 6);
byte legNumber = legNumberBytes[0];
byte[] numPenaltiesAwardedBytes = Arrays.copyOfRange(encodedMessage, 6, 7);
byte numPenaltiesAwarded = numPenaltiesAwardedBytes[0];
byte[] numPenaltiesServedBytes = Arrays.copyOfRange(encodedMessage, 7, 8);
byte numPenaltiesServed = numPenaltiesServedBytes[0];
byte[] estTimeAtNextMarkBytes = Arrays.copyOfRange(encodedMessage, 8, 14);
long estTimeAtNextMark = bytesToLong(estTimeAtNextMarkBytes);
byte[] estTimeAtFinishBytes = Arrays.copyOfRange(encodedMessage, 14, 20);
long estTimeAtFinish = bytesToLong(estTimeAtFinishBytes);
message = new BoatStatus(
sourceID,
boatStatus,
legNumber,
numPenaltiesAwarded,
numPenaltiesServed,
estTimeAtNextMark,
estTimeAtFinish );
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode BoatStatus message.", e);
}
}
/**
* Returns the decoded message.
* @return The decoded message.
*/
public BoatStatus getMessage() {
return message;
}
}
@@ -1,64 +1,102 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.CourseWind;
import shared.model.Bearing;
import java.util.ArrayList;
import java.util.Arrays;
import static network.Utils.ByteConverter.bytesToInt;
import static network.Utils.ByteConverter.bytesToLong;
import static network.Utils.AC35UnitConverter.*;
import static network.Utils.ByteConverter.*;
/**
* Created by hba56 on 23/04/17.
* Decodes {@link CourseWind} messages.
*/
public class CourseWindDecoder {
byte messageVersionNumber;
byte byteWindID;
byte loopCount;
ArrayList<CourseWind> loopMessages = new ArrayList();
public CourseWindDecoder(byte[] encodedCourseWind) {
final int lengthInBytesOfMessages = 20;
/**
* The encoded message.
*/
private byte[] encodedMessage;
messageVersionNumber = encodedCourseWind[0];
byteWindID = encodedCourseWind[1];
loopCount = encodedCourseWind[2];
byte[] loopMessagesBytes = Arrays.copyOfRange(encodedCourseWind, 3, lengthInBytesOfMessages*loopCount+3);
int messageLoopIndex = 0;
/**
* The decoded message.
*/
private CourseWind message;
for (int i=0; i < loopCount; i++) {
byte[] messageBytes = Arrays.copyOfRange(loopMessagesBytes, messageLoopIndex, messageLoopIndex+20);
ArrayList test = new ArrayList();
byte[] windId = Arrays.copyOfRange(messageBytes, 0, 1);
byte[] time = Arrays.copyOfRange(messageBytes, 1, 7);
byte[] raceID = Arrays.copyOfRange(messageBytes, 7, 11);
byte[] windDirection = Arrays.copyOfRange(messageBytes, 11, 13);
byte[] windSpeed = Arrays.copyOfRange(messageBytes, 13, 15);
byte[] bestUpwindAngle = Arrays.copyOfRange(messageBytes, 15, 17);
byte[] bestDownwindAngle = Arrays.copyOfRange(messageBytes, 17, 19);
byte[] flags = Arrays.copyOfRange(messageBytes, 19, 20);
CourseWind message = new CourseWind(windId[0], bytesToLong(time),
bytesToInt(raceID), bytesToInt(windDirection),
bytesToInt(windSpeed), bytesToInt(bestUpwindAngle),
bytesToInt(bestDownwindAngle), flags[0]);
loopMessages.add(message);
messageLoopIndex += 20;
/**
* Constructs a decoder to decode a given message.
*/
public 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) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
try {
byte[] windId = Arrays.copyOfRange(encodedMessage, 0, 1);
byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7);
long time = bytesToLong(timeBytes);
byte[] raceIDBytes = Arrays.copyOfRange(encodedMessage, 7, 11);
int raceIDInt = bytesToInt(raceIDBytes);
byte[] windDirectionBytes = Arrays.copyOfRange(encodedMessage, 11, 13);
int windDirectionInt = bytesToInt(windDirectionBytes);
Bearing windDirection = Bearing.fromDegrees(unpackHeading(windDirectionInt));
byte[] windSpeedBytes = Arrays.copyOfRange(encodedMessage, 13, 15);
int windSpeedInt = bytesToInt(windSpeedBytes);
double windSpeedKnots = unpackMMperSecToKnots(windSpeedInt);
byte[] bestUpwindAngleBytes = Arrays.copyOfRange(encodedMessage, 15, 17);
int bestUpwindAngleInt = bytesToInt(bestUpwindAngleBytes);
Bearing bestUpwindAngle = Bearing.fromDegrees(unpackHeading(bestUpwindAngleInt));
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]);
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode CourseWind message.", e);
}
}
public ArrayList<CourseWind> getLoopMessages() {
return loopMessages;
/**
* Returns the decoded message.
* @return The decoded message.
*/
public CourseWind getMessage() {
return message;
}
public byte getMessageVersionNumber() {
return messageVersionNumber;
}
public byte getByteWindID() {
return byteWindID;
}
}
@@ -0,0 +1,93 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.CourseWind;
import network.Messages.CourseWinds;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static network.Utils.ByteConverter.bytesToInt;
import static network.Utils.ByteConverter.bytesToLong;
/**
* Decodes {@link CourseWinds} messages.
*/
public class CourseWindsDecoder implements MessageDecoder {
/**
* The encoded message.
*/
private byte[] encodedMessage;
/**
* The decoded message.
*/
private CourseWinds message;
/**
* Constructs a decoder to decode a given message.
*/
public CourseWindsDecoder() {
}
@Override
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
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<CourseWind> loopMessages = new ArrayList();
//The header is 3 bytes, so we need the remaining bytes.
byte[] loopMessagesBytes = Arrays.copyOfRange(encodedMessage, 3, courseWindByteLength * loopCount + 3);
for (int messageLoopIndex = 0; messageLoopIndex < (loopCount * courseWindByteLength); messageLoopIndex += courseWindByteLength) {
byte[] messageBytes = Arrays.copyOfRange(loopMessagesBytes, messageLoopIndex, messageLoopIndex + courseWindByteLength);
CourseWindDecoder courseWindDecoder = new CourseWindDecoder();
CourseWind courseWind = courseWindDecoder.decode(messageBytes);
loopMessages.add(courseWind);
}
message = new CourseWinds(
messageVersionNumber,
byteWindID,
loopMessages);
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode CourseWinds message.", e);
}
}
/**
* Returns the decoded message.
* @return The decoded message.
*/
public CourseWinds getMessage() {
return message;
}
}
@@ -0,0 +1,70 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageTypeException;
import network.Messages.Enums.MessageType;
/**
* Factory to create the appropriate decoder for a given message.
*/
public class DecoderFactory {
/**
* Private constructor. Currently doesn't need to be constructed.
*/
private DecoderFactory(){
}
/**
* Creates the correct type of decoder for a given message type.
* @param type Type of message you want a decoder for.
* @return The decoder.
* @throws InvalidMessageTypeException If you pass in a {@link MessageType} that isn't recognised.
*/
public static MessageDecoder create(MessageType type) throws InvalidMessageTypeException {
switch (type) {
case HEARTBEAT: return new HeartBeatDecoder();
case RACESTATUS: return new RaceStatusDecoder();
//case DISPLAYTEXTMESSAGE: return new DisplayTextMessageDecoder();//TODO
case XMLMESSAGE: return new XMLMessageDecoder();
case RACESTARTSTATUS: return new RaceStartStatusDecoder();
//case YACHTEVENTCODE: return new YachtEventCodeDecoder();//TODO
//case YACHTACTIONCODE: return new YachtActionCodeDecoder();//TODO
//case CHATTERTEXT: return new ChatterTextDecoder();//TODO
case BOATLOCATION: return new BoatLocationDecoder();
case MARKROUNDING: return new MarkRoundingDecoder();
case COURSEWIND: return new CourseWindsDecoder();
case AVGWIND: return new AverageWindDecoder();
case REQUEST_TO_JOIN: return new RequestToJoinDecoder();
case JOIN_ACCEPTANCE: return new JoinAcceptanceDecoder();
case BOATACTION: return new BoatActionDecoder();
default: throw new InvalidMessageTypeException("Unrecognised message type: " + type);
}
}
}
@@ -0,0 +1,57 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.Enums.BoatActionEnum;
import network.Messages.HeartBeat;
import static network.Utils.ByteConverter.bytesToLong;
/**
* Decodes {@link network.Messages.HeartBeat} messages.
*/
public class HeartBeatDecoder implements MessageDecoder {
/**
* The encoded message.
*/
private byte[] encodedMessage;
/**
* The decoded message.
*/
private HeartBeat message;
/**
* Constructs a decoder to decode a given message.
*/
public HeartBeatDecoder() {
}
@Override
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
try {
message = new HeartBeat(bytesToLong(encodedMessage));
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode HeartBeat message.", e);
}
}
/**
* Returns the decoded message.
* @return The decoded message.
*/
public HeartBeat getMessage() {
return message;
}
}
@@ -0,0 +1,74 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.Enums.JoinAcceptanceEnum;
import network.Messages.JoinAcceptance;
import network.Utils.ByteConverter;
import java.util.Arrays;
/**
* Decoder for {@link JoinAcceptance} messages.
*/
public class JoinAcceptanceDecoder implements MessageDecoder {
/**
* The encoded message.
*/
private byte[] encodedMessage;
/**
* The decoded message.
*/
private JoinAcceptance message;
/**
* Constructs a decoder to decode a given message.
*/
public JoinAcceptanceDecoder() {
}
@Override
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
try {
//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);
//Acceptance enum is a byte.
JoinAcceptanceEnum acceptanceType = JoinAcceptanceEnum.fromByte(acceptanceBytes[0]);
message = new JoinAcceptance(acceptanceType, sourceID);
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode JoinAcceptance message.", e);
}
}
/**
* Returns the decoded message.
* @return The decoded message.
*/
public JoinAcceptance getMessage() {
return message;
}
}
@@ -1,52 +1,97 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.Enums.MarkRoundingBoatStatusEnum;
import network.Messages.Enums.MarkRoundingSideEnum;
import network.Messages.Enums.MarkRoundingTypeEnum;
import network.Messages.MarkRounding;
import network.Utils.ByteConverter;
import java.util.Arrays;
/**
* Created by hba56 on 23/04/17.
* Decoder for {@link MarkRounding} messages.
*/
public class MarkRoundingDecoder {
byte messageVersionNumber;
byte[] byteTime;
byte[] byteAck;
byte[] byteRaceID;
byte[] byteSourceID;
byte byteBoatStatus;
byte byteRoundingSide;
byte byteMarkType;
byte byteMarkID;
public class MarkRoundingDecoder implements MessageDecoder {
MarkRounding markRounding;
/**
* The encoded message.
*/
private byte[] encodedMessage;
public MarkRoundingDecoder(byte[] encodedMarkRounding) {
messageVersionNumber = encodedMarkRounding[0];
byteTime = Arrays.copyOfRange(encodedMarkRounding, 1, 7);
byteAck = Arrays.copyOfRange(encodedMarkRounding, 7, 9);
byteRaceID = Arrays.copyOfRange(encodedMarkRounding, 9, 13);
byteSourceID = Arrays.copyOfRange(encodedMarkRounding, 13, 17);
byteBoatStatus = encodedMarkRounding[17];
byteRoundingSide = encodedMarkRounding[18];
byteMarkType = encodedMarkRounding[19];
byteMarkID = encodedMarkRounding[20];
/**
* The decoded message.
*/
private MarkRounding message;
int intMsgVer = ByteConverter.bytesToInt(messageVersionNumber);
long lngTime = ByteConverter.bytesToLong(byteTime);
int intAck = ByteConverter.bytesToInt(byteAck);
int intRaceID = ByteConverter.bytesToInt(byteRaceID);
int intSourceID = ByteConverter.bytesToInt(byteSourceID);
int intBoatState = ByteConverter.bytesToInt(byteBoatStatus);
int intRoundingSide = ByteConverter.bytesToInt(byteRoundingSide);
int intMarkType = ByteConverter.bytesToInt(byteMarkType);
int intMarkID = ByteConverter.bytesToInt(byteMarkID);
markRounding = new MarkRounding(intMsgVer, lngTime, intAck, intRaceID, intSourceID, intBoatState, intRoundingSide, intMarkType, intMarkID);
/**
* Constructs a decoder to decode a given message.
*/
public MarkRoundingDecoder() {
}
public MarkRounding getMarkRounding() {
return markRounding;
@Override
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
try {
byte messageVersionNumber = encodedMessage[0];
byte[] byteTime = Arrays.copyOfRange(encodedMessage, 1, 7);
long time = ByteConverter.bytesToLong(byteTime);
byte[] byteAck = Arrays.copyOfRange(encodedMessage, 7, 9);
int ackNumber = ByteConverter.bytesToInt(byteAck);
byte[] byteRaceID = Arrays.copyOfRange(encodedMessage, 9, 13);
int raceID = ByteConverter.bytesToInt(byteRaceID);
byte[] byteSourceID = Arrays.copyOfRange(encodedMessage, 13, 17);
int sourceID = ByteConverter.bytesToInt(byteSourceID);
byte byteBoatStatus = encodedMessage[17];
MarkRoundingBoatStatusEnum boatStatus = MarkRoundingBoatStatusEnum.fromByte(byteBoatStatus);
byte byteRoundingSide = encodedMessage[18];
MarkRoundingSideEnum roundingSide = MarkRoundingSideEnum.fromByte(byteRoundingSide);
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);
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode AverageWind message.", e);
}
}
/**
* Returns the decoded message.
*
* @return The decoded message.
*/
public MarkRounding getMessage() {
return message;
}
}
@@ -0,0 +1,23 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
/**
* This is the interface that all message decoders must implement.
* It allows for {@link #decode(byte[])}ing messages.
*/
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) throws InvalidMessageException;
}
@@ -1,66 +1,86 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.Enums.RaceStartTypeEnum;
import network.Messages.RaceStartStatus;
import java.util.Arrays;
import static network.Utils.ByteConverter.*;
/**
* Created by hba56 on 21/04/17.
* Decodes {@link RaceStartStatus} messages.
*/
public class RaceStartStatusDecoder {
private byte messageVersion;
private byte[] timestamp;
private byte[] ackNumber;
private byte[] raceStartTime;
private byte[] raceIdentifier;
private byte notificationType;
public class RaceStartStatusDecoder implements MessageDecoder {
private long time;
private short ack;
private long startTime;
private int raceID;
private char notification;
/**
* The encoded message.
*/
private byte[] encodedMessage;
/**
* The decoded message.
*/
private RaceStartStatus message;
public RaceStartStatusDecoder(byte[] encodedRaceStartStatus) {
messageVersion = encodedRaceStartStatus[0];
timestamp = Arrays.copyOfRange(encodedRaceStartStatus, 1, 7);
ackNumber = Arrays.copyOfRange(encodedRaceStartStatus, 7, 9);
raceStartTime = Arrays.copyOfRange(encodedRaceStartStatus, 9, 15);
raceIdentifier = Arrays.copyOfRange(encodedRaceStartStatus, 15, 19);
notificationType = encodedRaceStartStatus[19];
time = bytesToLong(timestamp);
ack = bytesToShort(ackNumber);
startTime = bytesToLong(raceStartTime);
raceID = bytesToInt(raceIdentifier);
notification = bytesToChar(notificationType);
/**
* Constructs a decoder to decode a given message.
*/
public RaceStartStatusDecoder() {
}
public byte getMessageVersion() {
return messageVersion;
@Override
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
try {
byte messageVersion = encodedMessage[0];
byte[] timestamp = Arrays.copyOfRange(encodedMessage, 1, 7);
long time = bytesToLong(timestamp);
byte[] ackNumber = Arrays.copyOfRange(encodedMessage, 7, 9);
short ack = bytesToShort(ackNumber);
byte[] raceStartTime = Arrays.copyOfRange(encodedMessage, 9, 15);
long startTime = bytesToLong(raceStartTime);
byte[] raceIdentifier = Arrays.copyOfRange(encodedMessage, 15, 19);
int raceID = bytesToInt(raceIdentifier);
byte notificationType = encodedMessage[19];
message = new RaceStartStatus(
messageVersion,
time,
ack,
startTime,
raceID,
RaceStartTypeEnum.fromByte(notificationType)
);
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode RaceStartStatus message.", e);
}
}
public long getTime() {
return time;
}
public short getAck() {
return ack;
}
public long getStartTime() {
return startTime;
}
public int getRaceID() {
return raceID;
}
public char getNotification() {
return notification;
/**
* Returns the decoded message.
* @return The decoded message.
*/
public RaceStartStatus getMessage() {
return message;
}
}
@@ -1,119 +1,125 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.BoatStatus;
import network.Messages.Enums.RaceStatusEnum;
import network.Messages.Enums.RaceTypeEnum;
import network.Messages.RaceStatus;
import network.Utils.AC35UnitConverter;
import shared.model.Bearing;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static network.Utils.ByteConverter.*;
/**
* Created by hba56 on 21/04/17.
* Decodes {@link RaceStatus} messages.
*/
public class RaceStatusDecoder {
private byte versionNum;
private byte[] timeBytes;
private byte[] raceID;
private byte raceStatus;
private byte[] expectedStart;
private byte[] raceWind;
private byte[] windSpeed;
private byte numBoats;
private byte bytesRaceType;
private byte[] boatsBytes;
public class RaceStatusDecoder implements MessageDecoder {
private long time;
private int race;
private byte raceState;
private long startTime;
private int raceWindDir;
private short raceWindSpeed;
private int numberOfBoats;
private int raceType;
private ArrayList<BoatStatus> boats = new ArrayList<>();
/**
* The encoded message.
*/
private byte[] encodedMessage;
/**
* The decoded message.
*/
private RaceStatus message;
public RaceStatusDecoder(byte[] encodedRaceStatus){
versionNum = encodedRaceStatus[0];
timeBytes = Arrays.copyOfRange(encodedRaceStatus, 1, 7);
raceID = Arrays.copyOfRange(encodedRaceStatus, 7, 11);
raceStatus = encodedRaceStatus[11];
expectedStart = Arrays.copyOfRange(encodedRaceStatus, 12, 18);
raceWind = Arrays.copyOfRange(encodedRaceStatus, 18, 20);
windSpeed = Arrays.copyOfRange(encodedRaceStatus, 20, 22);
numBoats = encodedRaceStatus[22];
bytesRaceType = encodedRaceStatus[23];
boatsBytes = Arrays.copyOfRange(encodedRaceStatus, 24, 25+20*this.numBoats);
time = bytesToLong(timeBytes);
race = bytesToInt(raceID);
raceState = raceStatus;
startTime = bytesToLong(expectedStart);
raceWindDir = bytesToInt(raceWind);
raceWindSpeed = bytesToShort(windSpeed);
numberOfBoats = bytesToInt(numBoats);
/**
* Constructs a decoder to decode a given message.
*/
public RaceStatusDecoder() {
}
int boatLoopIndex = 0;
for (int i=0; i < numberOfBoats; i++) {
byte[] boatBytes = Arrays.copyOfRange(boatsBytes, boatLoopIndex, boatLoopIndex+20);
@Override
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
byte[] sourceID = Arrays.copyOfRange(boatBytes, 0, 3);
byte boatStatus = boatBytes[4];
byte legNumber = boatBytes[5];
byte numPenaltiesAwarded = boatBytes[6];
byte numPenaltiesServed = boatBytes[7];
byte[] estTimeAtNextMark = Arrays.copyOfRange(boatBytes, 8, 14);
byte[] estTimeAtFinish = Arrays.copyOfRange(boatBytes, 14, 20);
try {
BoatStatus boat = new BoatStatus(bytesToInt(sourceID),boatStatus,
legNumber, numPenaltiesAwarded, numPenaltiesServed,
bytesToLong(estTimeAtNextMark), bytesToLong(estTimeAtFinish));
byte[] versionNumBytes = Arrays.copyOfRange(encodedMessage, 0, 1);
byte versionNum = versionNumBytes[0];
boats.add(boat);
boatLoopIndex += 20;
byte[] timeBytes = Arrays.copyOfRange(encodedMessage, 1, 7);
long time = bytesToLong(timeBytes);
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[] 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[] 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[] raceTypeBytes = Arrays.copyOfRange(encodedMessage, 23, 24);
RaceTypeEnum raceType = RaceTypeEnum.fromByte(raceTypeBytes[0]);
byte[] boatStatusesBytes = Arrays.copyOfRange(encodedMessage, 24, 25 + 20 * numberOfBoats);
List<BoatStatus> boatStatuses = new ArrayList<>();
//BoatStatus is 20 bytes.
int boatStatusByteLength = 20;
//Decode each BoatStatus.
for (int boatLoopIndex = 0; boatLoopIndex < (numberOfBoats * boatStatusByteLength); boatLoopIndex += boatStatusByteLength) {
byte[] boatStatusBytes = Arrays.copyOfRange(boatStatusesBytes, boatLoopIndex, boatLoopIndex + boatStatusByteLength);
BoatStatusDecoder boatStatusDecoder = new BoatStatusDecoder();
boatStatuses.add(boatStatusDecoder.decode(boatStatusBytes));
}
message = new RaceStatus(
versionNum,
time,
raceID,
raceStatus,
expectedStart,
windDirection,
windSpeedKnots,
raceType,
boatStatuses);
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode RaceStatus message.", e);
}
}
public byte getVersionNum() {
return versionNum;
}
public long getTime() {
return time;
}
public int getRace() {
return race;
}
public byte getRaceState() {
return raceState;
}
public long getStartTime() {
return startTime;
}
public int getRaceWindDir() {
return raceWindDir;
}
public short getRaceWindSpeed() {
return raceWindSpeed;
}
public int getNumberOfBoats() {
return numberOfBoats;
}
public int getRaceType() {
return raceType;
}
public ArrayList<BoatStatus> getBoats() {
return boats;
/**
* Returns the decoded message.
* @return The decoded message.
*/
public RaceStatus getMessage() {
return message;
}
}
@@ -0,0 +1,67 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.Enums.RequestToJoinEnum;
import network.Messages.RequestToJoin;
import network.Utils.ByteConverter;
import java.util.Arrays;
/**
* Decoder for {@link network.Messages.RequestToJoin} messages.
*/
public class RequestToJoinDecoder implements MessageDecoder{
/**
* The encoded message.
*/
private byte[] encodedRequest;
/**
* The decoded message.
*/
private RequestToJoin message;
/**
* Constructs a decoder to decode a given message.
*/
public RequestToJoinDecoder() {
}
@Override
public AC35Data decode(byte[] encodedRequest) throws InvalidMessageException {
this.encodedRequest = encodedRequest;
try {
//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;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode RequestToJoin message.", e);
}
}
/**
* Returns the decoded message.
* @return The decoded message.
*/
public RequestToJoin getMessage() {
return message;
}
}
@@ -1,6 +1,9 @@
package network.MessageDecoders;
import network.Exceptions.InvalidMessageException;
import network.Messages.AC35Data;
import network.Messages.Enums.XMLMessageType;
import network.Messages.XMLMessage;
import java.util.Arrays;
@@ -9,73 +12,74 @@ import static network.Utils.ByteConverter.bytesToShort;
/**
* Created by hba56 on 20/04/17.
* Decodes {@link network.Messages.XMLMessage} messages.
*/
public class XMLMessageDecoder {
private byte messageVersionNumber;
private short ackNumber;
private long timeStamp;
private byte xmlMsgSubType;
private short sequenceNumber;
private short xmlMsgLength;
private String xmlMessage;
public class XMLMessageDecoder implements MessageDecoder {
private byte[] bytes;
/**
* The encoded message.
*/
private byte[] encodedMessage;
public XMLMessageDecoder(byte[] bytes) {
this.bytes = bytes;
}
public void decode(){
byte[] ackNumberBytes = Arrays.copyOfRange(bytes, 1, 3);
byte[] timeStampBytes = Arrays.copyOfRange(bytes, 3, 9);
byte[] sequenceNumberBytes = Arrays.copyOfRange(bytes, 10, 12);
byte[] xmlMsgLengthBytes = Arrays.copyOfRange(bytes, 12, 14);
byte[] xmlMessagebytes = Arrays.copyOfRange(bytes, 14, bytes.length);
this.xmlMsgSubType = bytes[9];
this.messageVersionNumber = bytes[0];
this.ackNumber = bytesToShort(ackNumberBytes);
this.timeStamp = bytesToLong(timeStampBytes);
this.sequenceNumber = bytesToShort(sequenceNumberBytes);
this.xmlMsgLength = bytesToShort(xmlMsgLengthBytes);
this.xmlMessage = new String(xmlMessagebytes).trim();
}
public byte getMessageVersionNumber() {
return messageVersionNumber;
}
public short getAckNumber() {
return ackNumber;
}
public long getTimeStamp() {
return timeStamp;
}
public XMLMessageType getXmlMsgSubType() {
return XMLMessageType.fromByte(xmlMsgSubType);
}
public short getSequenceNumber() {
return sequenceNumber;
}
public short getXmlMsgLength() {
return xmlMsgLength;
}
/**
* The decoded message.
*/
private XMLMessage message;
/**
* Returns the contents of the XML message (e.g., the contents of a race.xml file).
* @return The contents of the XML message.
* Constructs a decoder to decode a given message.
*/
public String getXmlMessageContents() {
return xmlMessage;
public XMLMessageDecoder() {
}
@Override
public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException {
this.encodedMessage = encodedMessage;
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);
message = new XMLMessage(
messageVersionNumber,
ackNumber,
timeStamp,
xmlMsgSubType,
sequenceNumber,
xmlMessage);
return message;
} catch (Exception e) {
throw new InvalidMessageException("Could not decode XMLMessage message.", e);
}
}
/**
* Returns the decoded message.
* @return The decoded message.
*/
public XMLMessage getMessage() {
return message;
}
}