Renamed Heartbeat to HeartBeat.
Added HeartBeatDecoder. Added HeartBeatEncoder. BinaryMessageDecoder now uses HeartBeatDecoder. MockOutput now logs a warning if a heartBeat cannot be encoded. Added HeartBeatDecoderTest. issue #35 #36 #story[1095]
This commit is contained in:
@@ -7,12 +7,9 @@ import network.Exceptions.InvalidMessageException;
|
|||||||
import network.MessageEncoders.RaceVisionByteEncoder;
|
import network.MessageEncoders.RaceVisionByteEncoder;
|
||||||
import network.Messages.*;
|
import network.Messages.*;
|
||||||
import network.Messages.Enums.MessageType;
|
import network.Messages.Enums.MessageType;
|
||||||
import network.Messages.Enums.XMLMessageType;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -101,24 +98,25 @@ public class MockOutput implements Runnable
|
|||||||
* Generates the next heartbeat message and returns it. Increments the heartbeat sequence number.
|
* Generates the next heartbeat message and returns it. Increments the heartbeat sequence number.
|
||||||
* @return The next heartbeat message.
|
* @return The next heartbeat message.
|
||||||
*/
|
*/
|
||||||
private Heartbeat createHeartbeatMessage() {
|
private HeartBeat createHeartbeatMessage() {
|
||||||
|
|
||||||
//Create the heartbeat message.
|
//Create the heartbeat message.
|
||||||
Heartbeat heartbeat = new Heartbeat(this.heartbeatSequenceNum);
|
HeartBeat heartBeat = new HeartBeat(this.heartbeatSequenceNum);
|
||||||
heartbeatSequenceNum++;
|
heartbeatSequenceNum++;
|
||||||
|
|
||||||
return heartbeat;
|
return heartBeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializes a heartbeat message into a packet to be sent, and returns the byte array.
|
* Serializes a heartbeat message into a packet to be sent, and returns the byte array.
|
||||||
* @param heartbeat The heartbeat message to serialize.
|
* @param heartBeat The heartbeat message to serialize.
|
||||||
* @return Byte array containing the next heartbeat message.
|
* @return Byte array containing the next heartbeat message.
|
||||||
|
* @throws InvalidMessageException Thrown if the message cannot be encoded.
|
||||||
*/
|
*/
|
||||||
private byte[] parseHeartbeat(Heartbeat heartbeat) {
|
private byte[] parseHeartbeat(HeartBeat heartBeat) throws InvalidMessageException {
|
||||||
|
|
||||||
//Serializes the heartbeat message.
|
//Serializes the heartbeat message.
|
||||||
byte[] heartbeatMessage = RaceVisionByteEncoder.heartBeat(heartbeat);
|
byte[] heartbeatMessage = RaceVisionByteEncoder.encode(heartBeat);
|
||||||
|
|
||||||
//Places the serialized message in a packet.
|
//Places the serialized message in a packet.
|
||||||
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
|
BinaryMessageEncoder binaryMessageEncoder = new BinaryMessageEncoder(
|
||||||
@@ -213,7 +211,15 @@ public class MockOutput implements Runnable
|
|||||||
public void sendHeartBeat() throws IOException {
|
public void sendHeartBeat() throws IOException {
|
||||||
//Sends a heartbeat every so often.
|
//Sends a heartbeat every so often.
|
||||||
if (timeSinceHeartbeat() >= heartbeatPeriod) {
|
if (timeSinceHeartbeat() >= heartbeatPeriod) {
|
||||||
outToVisualiser.write(parseHeartbeat(createHeartbeatMessage()));
|
|
||||||
|
HeartBeat heartBeat = createHeartbeatMessage();
|
||||||
|
|
||||||
|
try {
|
||||||
|
outToVisualiser.write(parseHeartbeat(heartBeat));
|
||||||
|
} catch (InvalidMessageException e) {
|
||||||
|
Logger.getGlobal().log(Level.WARNING, "Could not encode HeartBeat: " + heartBeat, e);
|
||||||
|
}
|
||||||
|
|
||||||
lastHeartbeatTime = System.currentTimeMillis();
|
lastHeartbeatTime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,9 +133,8 @@ public class BinaryMessageDecoder {
|
|||||||
switch(mType) {
|
switch(mType) {
|
||||||
case HEARTBEAT:
|
case HEARTBEAT:
|
||||||
//System.out.println("Decoding HeartBeat Message!");
|
//System.out.println("Decoding HeartBeat Message!");
|
||||||
//TODO maybe use HeartbeatDecoder.decode(message).
|
HeartBeatDecoder heartBeatDecoder = new HeartBeatDecoder(messageBody);
|
||||||
//TODO also, decoders for each message type should encapsulate the constructing of the object. E.g., return HeartbeatDecoder.decode(message);.
|
return heartBeatDecoder.getMessage();
|
||||||
return new Heartbeat(bytesToLong(messageBody));
|
|
||||||
|
|
||||||
case RACESTATUS:
|
case RACESTATUS:
|
||||||
//System.out.println("Race Status Message");
|
//System.out.println("Race Status Message");
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
import network.Messages.Enums.BoatActionEnum;
|
||||||
|
import network.Messages.HeartBeat;
|
||||||
|
|
||||||
|
import static network.Utils.ByteConverter.bytesToLong;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes {@link network.Messages.HeartBeat} messages.
|
||||||
|
*/
|
||||||
|
public class HeartBeatDecoder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encoded message.
|
||||||
|
*/
|
||||||
|
private byte[] encodedMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decoded message.
|
||||||
|
*/
|
||||||
|
private HeartBeat message;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a decoder to decode a given message.
|
||||||
|
* @param encodedMessage The message to decode.
|
||||||
|
*/
|
||||||
|
public HeartBeatDecoder(byte[] encodedMessage) {
|
||||||
|
this.encodedMessage = encodedMessage;
|
||||||
|
|
||||||
|
decode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the contained message.
|
||||||
|
*/
|
||||||
|
private void decode() {
|
||||||
|
|
||||||
|
message = new HeartBeat(bytesToLong(encodedMessage));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the decoded message.
|
||||||
|
* @return The decoded message.
|
||||||
|
*/
|
||||||
|
public HeartBeat getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -29,6 +29,8 @@ public class EncoderFactory {
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
||||||
|
case HEARTBEAT: return new HeartBeatEncoder();
|
||||||
|
|
||||||
case BOATLOCATION: return new BoatLocationEncoder();
|
case BOATLOCATION: return new BoatLocationEncoder();
|
||||||
|
|
||||||
case REQUEST_TO_JOIN: return new RequestToJoinEncoder();
|
case REQUEST_TO_JOIN: return new RequestToJoinEncoder();
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package network.MessageEncoders;
|
||||||
|
|
||||||
|
|
||||||
|
import network.Messages.AC35Data;
|
||||||
|
import network.Messages.HeartBeat;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import static network.Utils.ByteConverter.intToBytes;
|
||||||
|
import static network.Utils.ByteConverter.longToBytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This encoder can encode a {@link HeartBeat} message.
|
||||||
|
*/
|
||||||
|
public class HeartBeatEncoder implements MessageEncoder {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
public HeartBeatEncoder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] encode(AC35Data message) {
|
||||||
|
|
||||||
|
//Downcast.
|
||||||
|
HeartBeat heartbeat = (HeartBeat) message;
|
||||||
|
|
||||||
|
//Message is 4 bytes.
|
||||||
|
ByteBuffer heartBeat = ByteBuffer.allocate(4);
|
||||||
|
heartBeat.put(longToBytes(heartbeat.getSequenceNumber(), 4));
|
||||||
|
|
||||||
|
byte[] result = heartBeat.array();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,20 +19,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class RaceVisionByteEncoder {
|
public class RaceVisionByteEncoder {
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes a heartbeat message.
|
|
||||||
* @param heartbeat Heartbeat message.
|
|
||||||
* @return Serialized message.
|
|
||||||
*/
|
|
||||||
public static byte[] heartBeat(Heartbeat heartbeat) {
|
|
||||||
|
|
||||||
ByteBuffer heartBeat = ByteBuffer.allocate(4);
|
|
||||||
heartBeat.put(longToBytes(heartbeat.getSequenceNumber(), 4));
|
|
||||||
|
|
||||||
byte[] result = heartBeat.array();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializes a RaceStatus message.
|
* Serializes a RaceStatus message.
|
||||||
|
|||||||
+2
-2
@@ -6,7 +6,7 @@ import network.Messages.Enums.MessageType;
|
|||||||
/**
|
/**
|
||||||
* Represents a Heartbeat message.
|
* Represents a Heartbeat message.
|
||||||
*/
|
*/
|
||||||
public class Heartbeat extends AC35Data {
|
public class HeartBeat extends AC35Data {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sequence number of the heartbeat.
|
* Sequence number of the heartbeat.
|
||||||
@@ -17,7 +17,7 @@ public class Heartbeat extends AC35Data {
|
|||||||
* Ctor.
|
* Ctor.
|
||||||
* @param sequenceNumber Sequence number of the heartbeat.
|
* @param sequenceNumber Sequence number of the heartbeat.
|
||||||
*/
|
*/
|
||||||
public Heartbeat(long sequenceNumber) {
|
public HeartBeat(long sequenceNumber) {
|
||||||
super(MessageType.HEARTBEAT);
|
super(MessageType.HEARTBEAT);
|
||||||
this.sequenceNumber = sequenceNumber;
|
this.sequenceNumber = sequenceNumber;
|
||||||
}
|
}
|
||||||
@@ -1,26 +1,13 @@
|
|||||||
package visualiser.app;
|
package visualiser.app;
|
||||||
import javafx.application.Platform;
|
|
||||||
import network.BinaryMessageDecoder;
|
import network.BinaryMessageDecoder;
|
||||||
import network.Exceptions.InvalidMessageException;
|
import network.Exceptions.InvalidMessageException;
|
||||||
import network.Messages.*;
|
import network.Messages.*;
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import shared.dataInput.BoatXMLReader;
|
|
||||||
import shared.dataInput.RaceXMLReader;
|
|
||||||
import shared.dataInput.RegattaXMLReader;
|
|
||||||
import shared.exceptions.InvalidBoatDataException;
|
|
||||||
import shared.exceptions.InvalidRaceDataException;
|
|
||||||
import shared.exceptions.InvalidRegattaDataException;
|
|
||||||
import shared.exceptions.XMLReaderException;
|
|
||||||
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
|
||||||
|
|
||||||
import static network.Utils.ByteConverter.bytesToShort;
|
import static network.Utils.ByteConverter.bytesToShort;
|
||||||
|
|
||||||
@@ -213,12 +200,12 @@ public class VisualiserInput implements Runnable {
|
|||||||
|
|
||||||
//Heartbeat.
|
//Heartbeat.
|
||||||
case HEARTBEAT: {
|
case HEARTBEAT: {
|
||||||
Heartbeat heartbeat = (Heartbeat) message;
|
HeartBeat heartBeat = (HeartBeat) message;
|
||||||
|
|
||||||
//Check that the heartbeat number is greater than the previous value, and then set the last heartbeat time.
|
//Check that the heartbeat number is greater than the previous value, and then set the last heartbeat time.
|
||||||
if (heartbeat.getSequenceNumber() > this.lastHeartbeatSequenceNum) {
|
if (heartBeat.getSequenceNumber() > this.lastHeartbeatSequenceNum) {
|
||||||
lastHeartbeatTime = System.currentTimeMillis();
|
lastHeartbeatTime = System.currentTimeMillis();
|
||||||
lastHeartbeatSequenceNum = heartbeat.getSequenceNumber();
|
lastHeartbeatSequenceNum = heartBeat.getSequenceNumber();
|
||||||
//System.out.println("HeartBeat Message! " + lastHeartbeatSequenceNum);
|
//System.out.println("HeartBeat Message! " + lastHeartbeatSequenceNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package network.MessageDecoders;
|
||||||
|
|
||||||
|
import network.Exceptions.InvalidMessageException;
|
||||||
|
import network.MessageEncoders.RaceVisionByteEncoder;
|
||||||
|
import network.Messages.BoatAction;
|
||||||
|
import network.Messages.Enums.BoatActionEnum;
|
||||||
|
import network.Messages.HeartBeat;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for the HeartBeat encoder and decoder
|
||||||
|
*/
|
||||||
|
public class HeartBeatDecoderTest {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes and decodes a given message.
|
||||||
|
* @param message Message to encode/decode.
|
||||||
|
* @return The decoded message.
|
||||||
|
*/
|
||||||
|
private HeartBeat encodeDecodeMessage(HeartBeat message) throws InvalidMessageException {
|
||||||
|
|
||||||
|
//Encode.
|
||||||
|
byte [] testEncodedMessage = RaceVisionByteEncoder.encode(message);
|
||||||
|
|
||||||
|
//Decode.
|
||||||
|
HeartBeatDecoder testDecoder = new HeartBeatDecoder(testEncodedMessage);
|
||||||
|
HeartBeat decodedMessage = testDecoder.getMessage();
|
||||||
|
|
||||||
|
return decodedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if a heartbeat message with a given sequence number can be encoded and decoded correctly.
|
||||||
|
* @param sequenceNumber The sequenceNumber to use.
|
||||||
|
*/
|
||||||
|
private void heartBeatTest(long sequenceNumber) throws Exception {
|
||||||
|
|
||||||
|
//Prepare message.
|
||||||
|
HeartBeat beforeMessage = new HeartBeat(sequenceNumber);
|
||||||
|
|
||||||
|
|
||||||
|
//Encode/decode it.
|
||||||
|
HeartBeat afterMessage = encodeDecodeMessage(beforeMessage);
|
||||||
|
|
||||||
|
|
||||||
|
//Compare.
|
||||||
|
assertEquals(beforeMessage.getSequenceNumber(), afterMessage.getSequenceNumber());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if a heartbeat message with a sequence number of zero can be encoded and decoded correctly.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void heartBeatZeroTest() throws Exception {
|
||||||
|
heartBeatTest(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if a heartbeat message with a sequence number of 1234512 can be encoded and decoded correctly.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void heartBeatNonZeroTest() throws Exception {
|
||||||
|
heartBeatTest(1234512);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user