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]
main
fjc40 9 years ago
parent c3ed30019c
commit 8ef906472b

@ -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.

@ -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);
}
}
Loading…
Cancel
Save