diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index caa4313e..5b308813 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -21,7 +21,7 @@ public class App extends Application public static void main(String[] args) { new ServerThread("Racevision Test Server"); - new Thread(new Simulator(1000)).run(); + //new Thread(new Simulator(1000)).run(); launch(args); } } \ No newline at end of file diff --git a/src/main/java/seng302/server/ServerThread.java b/src/main/java/seng302/server/ServerThread.java index 68015574..8059827b 100644 --- a/src/main/java/seng302/server/ServerThread.java +++ b/src/main/java/seng302/server/ServerThread.java @@ -1,29 +1,44 @@ package seng302.server; import seng302.server.messages.*; +import seng302.server.simulator.Boat; +import seng302.server.simulator.Simulator; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; +import java.util.*; -public class ServerThread implements Runnable{ +public class ServerThread implements Runnable, Observer { private Thread runner; private StreamingServerSocket server; + private long startTime; + boolean raceStarted = false; + private List boats; + private Simulator raceSimulator; + private final int HEARTBEAT_PERIOD = 5000; - private final int RACE_STATUS_PERIOD = 1000; + private final int RACE_STATUS_PERIOD = 1000/2; + private final int RACE_START_STATUS_PERIOD = 1000/2; private final int BOAT_LOCATION_PERIOD = 1000/5; private final int PORT_NUMBER = 8085; + private final int TIME_TILL_RACE_START = 10; + private static final int LOG_LEVEL = 1; public ServerThread(String threadName){ runner = new Thread(this, threadName); - System.out.println("Spawning Server Thread"); + serverLog("Spawning Server", 0); + raceSimulator = new Simulator(BOAT_LOCATION_PERIOD); + boats = raceSimulator.getBoats(); runner.start(); } + public static void serverLog(String message, int logLevel){ + if(logLevel <= LOG_LEVEL){ + System.out.println("[SERVER] " + message); + } + } + /** * Creates and returns an XML Message from the file specified * @param fileName The source XML file @@ -38,6 +53,9 @@ public class ServerThread implements Runnable{ } catch (IOException e) { e.printStackTrace(); } + catch (NullPointerException e){ + return null; + } if (fileContents != null){ return new XMLMessage(fileContents, type, server.getSequenceNumber()); @@ -47,56 +65,113 @@ public class ServerThread implements Runnable{ } /** - * @return A sample race status message + * @return Get a race status message for the current race */ - public Message getTestRaceStatusMessage(){ - BoatSubMessage boat1 = new BoatSubMessage(1, BoatStatus.PRESTART, 0, 0, 0, - 10000, 10000); + public Message getRaceStatusMessage(){ + List boatSubMessages = new ArrayList(); + BoatStatus boatStatus; + RaceStatus raceStatus; - BoatSubMessage boat2 = new BoatSubMessage(2, BoatStatus.PRESTART, 0, 0, 0, - 10000, 10000); + if (raceStarted){ + boatStatus = BoatStatus.RACING; + raceStatus = RaceStatus.STARTED; + } + else{ + boatStatus = BoatStatus.PRESTART; + raceStatus = RaceStatus.PRESTART; + } - BoatSubMessage boat3 = new BoatSubMessage(3, BoatStatus.PRESTART, 0, 0, 0, - 10000, 10000); + for (Boat b : boats){ + BoatSubMessage m = new BoatSubMessage(b.getSourceID(), boatStatus, b.getLastPassedCorner().getSeqID(), 0, 0, 0, 0); + boatSubMessages.add(m); + } - - List boats = new ArrayList(); - boats.add(boat1); - boats.add(boat2); - boats.add(boat3); - - return new RaceStatusMessage(1, RaceStatus.PRESTART, 1000, WindDirection.EAST, - 100, 3, RaceType.MATCH_RACE, 1, boats); + return new RaceStatusMessage(1, raceStatus, startTime, WindDirection.EAST, + 100, boats.size(), RaceType.MATCH_RACE, 1, boatSubMessages); } /** - * @return A list of sample boat location messages + * Starts an instance of the race simulator */ - public List getTestBoatLocationMessages(){ - List messages = new ArrayList<>(); - - messages.add(new BoatLocationMessage(1, 1, 100, 200, 231, 23)); - messages.add(new BoatLocationMessage(2, 2, 400, 300, 211, 13)); - - return messages; + private void startRaceSim(){ + serverLog("Starting Race Simulator", 0); + raceSimulator.addObserver(this); + new Thread(raceSimulator).start(); } + /** + * Starts sending heartbeat messages to the client + */ + private void startSendingHeartbeats(){ + serverLog("Sending Heartbeats", 0); + Timer t = new Timer(); - public void run() { + t.schedule(new TimerTask() { + @Override + public void run() { + Message heartbeat = new Heartbeat(server.getSequenceNumber()); + + try { + server.send(heartbeat); + } catch (IOException e) { + System.out.print(""); + } + } + }, 0, HEARTBEAT_PERIOD); + } + + /** + * Start sending race start status messages until race starts + */ + private void startSendingRaceStartStatusMessages(){ + Timer t = new Timer(); + t.schedule(new TimerTask() { + @Override + public void run() { + Message raceStartStatusMessage = new RaceStartStatusMessage(server.getSequenceNumber(), startTime , 1, + RaceStartNotificationType.SET_RACE_START_TIME); + try { + if (startTime < System.currentTimeMillis()/1000 && !raceStarted){ + startRaceSim(); + raceStarted = true; + serverLog("Race Started", 0); + } + else{ + server.send(raceStartStatusMessage); + } + + } catch (IOException e) { + System.out.print(""); + } + } + }, 0, RACE_START_STATUS_PERIOD); + } + + private void startSendingRaceStatusMessages(){ + serverLog("Sending Race Status Messages", 0); + Timer t = new Timer(); + t.schedule(new TimerTask() { + @Override + public void run() { + Message statusMessage = getRaceStatusMessage(); + + try { + server.send(statusMessage); + } catch (IOException e) { + System.out.print(""); + } + } + }, 100, RACE_STATUS_PERIOD); + } + + /** + * Sends the race, boat, and regatta XML files to the client + */ + private void sendXml(){ try{ - server = new StreamingServerSocket(PORT_NUMBER); - } - catch (IOException e){ - System.err.println("Failed to bind socket: " + e.getMessage()); - } - - server.start(); - - try { - // Load and send race XML data - Message raceData = getXmlMessage("/server_config/race.xml", XMLMessageSubType.RACE); - Message boatData = getXmlMessage("/server_config/boats.xml", XMLMessageSubType.BOAT); - Message regatta = getXmlMessage("/server_config/regatta.xml", XMLMessageSubType.REGATTA); + Message raceData = getXmlMessage("server_config/race.xml", XMLMessageSubType.RACE); + Message boatData = getXmlMessage("server_config/boats.xml", XMLMessageSubType.BOAT); + Message regatta = getXmlMessage("server_config/regatta.xml", XMLMessageSubType.REGATTA); if (raceData != null){ server.send(raceData); @@ -106,57 +181,56 @@ public class ServerThread implements Runnable{ server.send(boatData); } - if (regatta != null){ - server.send(regatta); + if (regatta != null){ + server.send(regatta); } - - // Timer to send the heartbeat - Timer t = new Timer(); - t.schedule(new TimerTask() { - @Override - public void run() { - Message hb = new Heartbeat(server.getSequenceNumber()); - try { - server.send(hb); - } catch (IOException e) { - System.out.print(""); - } - } - }, 0, HEARTBEAT_PERIOD); - - // Timer to send the race status messages - Timer t1 = new Timer(); - t1.schedule(new TimerTask() { - @Override - public void run() { - Message statusMessage = getTestRaceStatusMessage(); - - try { - server.send(statusMessage); - } catch (IOException e) { - System.out.print(""); - } - } - }, 100, RACE_STATUS_PERIOD); - - t1.schedule(new TimerTask() { - @Override - public void run() { - List messages = getTestBoatLocationMessages(); - - for (Message m : messages){ - try { - server.send(m); - } catch (IOException e) { - System.out.print(""); - } - } - - } - }, 100, BOAT_LOCATION_PERIOD); - } catch (IOException e) { - System.err.println(e.getMessage()); + serverLog("Couldn't send an XML Message: " + e.getMessage(), 0); + } + } + + public void run() { + try{ + server = new StreamingServerSocket(PORT_NUMBER); + } + catch (IOException e){ + serverLog("Failed to bind socket: " + e.getMessage(), 0); + } + + startTime = (System.currentTimeMillis()/1000) + TIME_TILL_RACE_START; + + // Wait for client to connect + server.start(); + + startSendingHeartbeats(); + sendXml(); + startSendingRaceStartStatusMessages(); + startSendingRaceStatusMessages(); + + } + + /** + * Send a boat location message when they are updated by the simulator + * @param o . + * @param arg . + */ + @Override + public void update(Observable o, Object arg) { + // Only send if server started + if(!server.isStarted()){ + return; + } + + for (Boat b : ((Simulator) o).getBoats()){ + try { + Message m = new BoatLocationMessage(b.getSourceID(), 1, b.getLat(), + b.getLng(), b.getHeadingCorner().getBearingToNextCorner(), + ((long) b.getSpeed())); + + server.send(m); + } catch (IOException e) { + serverLog("Couldn't send a boat status message", 1); + } } } } diff --git a/src/main/java/seng302/server/StreamingServerSocket.java b/src/main/java/seng302/server/StreamingServerSocket.java index d34eae8a..0818bd9f 100644 --- a/src/main/java/seng302/server/StreamingServerSocket.java +++ b/src/main/java/seng302/server/StreamingServerSocket.java @@ -4,35 +4,44 @@ import seng302.server.messages.Message; import java.io.DataOutputStream; import java.io.IOException; +import java.net.InetSocketAddress; import java.net.Socket; +import java.nio.channels.Channels; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; import java.util.ArrayList; import java.util.List; class StreamingServerSocket { - private java.net.ServerSocket socket; - private Socket client; + private ServerSocketChannel socket; + private SocketChannel client; private List clients; private short seqNum; + private boolean isServerStarted; StreamingServerSocket(int port) throws IOException{ - socket = new java.net.ServerSocket(port); + socket = ServerSocketChannel.open(); + socket.socket().bind(new InetSocketAddress("localhost", port)); clients = new ArrayList<>(); - socket.setSoTimeout(10000); + //socket.setSoTimeout(10000); seqNum = 0; + isServerStarted = false; } void start(){ - System.out.println("Listening For Connections"); + ServerThread.serverLog("Listening For Connections",0); try { client = socket.accept(); } catch (IOException e) { e.getMessage(); } - if (client == null){ + if (client.socket() == null){ start(); } else{ - System.out.println("client connected from " + client.getInetAddress()); + isServerStarted = true; + ServerThread.serverLog("client connected from " + client.socket().getInetAddress(),0); } } @@ -41,8 +50,9 @@ class StreamingServerSocket { return; } - DataOutputStream outputStream = new DataOutputStream(client.getOutputStream()); - message.send(outputStream); + //DataOutputStream outputStream = new DataOutputStream(client.getOutputStream()); + //System.out.println(client); + message.send(client); seqNum++; } @@ -50,4 +60,8 @@ class StreamingServerSocket { public short getSequenceNumber(){ return seqNum; } + + public boolean isStarted(){ + return isServerStarted; + } } diff --git a/src/main/java/seng302/server/messages/BoatLocationMessage.java b/src/main/java/seng302/server/messages/BoatLocationMessage.java index 4b914699..45dd3ad5 100644 --- a/src/main/java/seng302/server/messages/BoatLocationMessage.java +++ b/src/main/java/seng302/server/messages/BoatLocationMessage.java @@ -2,6 +2,9 @@ package seng302.server.messages; import java.io.DataOutputStream; import java.io.IOException; +import java.nio.channels.Channels; +import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; public class BoatLocationMessage extends Message { private final int MESSAGE_SIZE = 56; @@ -11,10 +14,10 @@ public class BoatLocationMessage extends Message { private long sourceId; private long sequenceNum; private DeviceType deviceType; - private long latitude; - private long longitude; + private double latitude; + private double longitude; private long altitude; - private long heading; + private Double heading; private long pitch; private long roll; private long boatSpeed; @@ -38,13 +41,13 @@ public class BoatLocationMessage extends Message { * @param heading The boats heading * @param boatSpeed The boats speed */ - public BoatLocationMessage(int sourceId, int sequenceNum, long latitude, long longitude, long heading, long boatSpeed){ + public BoatLocationMessage(int sourceId, int sequenceNum, double latitude, double longitude, double heading, long boatSpeed){ messageVersionNumber = 1; time = System.currentTimeMillis() / 1000L; this.sourceId = sourceId; this.sequenceNum = sequenceNum; this.deviceType = DeviceType.RACING_YACHT; - this.latitude = -latitude; + this.latitude = latitude; this.longitude = longitude; this.altitude = 0; this.heading = heading; @@ -126,19 +129,23 @@ public class BoatLocationMessage extends Message { @Override - public void send(DataOutputStream outputStream) { + public void send(SocketChannel outputStream) throws IOException{ allocateBuffer(); writeHeaderToBuffer(); + heading = (heading + 180.0) % 360.0; + + long headingToSend = (long)((heading/360.0)*65535.0); + putByte((byte) messageVersionNumber); - putInt((int) time, 6); + putInt(time, 6); putInt((int) sourceId, 4); putUnsignedInt((int) sequenceNum, 4); putByte((byte) deviceType.getCode()); - putInt((int) latitude, 4); - putInt((int) longitude, 4); + putInt((int) latLonToBinaryPackedLong(latitude), 4); + putInt((int) latLonToBinaryPackedLong(longitude), 4); putInt((int) altitude, 4); - putUnsignedInt((int) heading, 2); + putInt(headingToSend, 2); putInt((int) pitch, 2); putInt((int) roll, 2); putUnsignedInt((int) boatSpeed, 2); @@ -153,12 +160,9 @@ public class BoatLocationMessage extends Message { putUnsignedInt((int) currentSet, 2); putInt((int) rudderAngle, 2); - writeCRC(); - try { - outputStream.write(getBuffer().array()); - } catch (IOException e) { - System.out.print(""); - } + rewind(); + + outputStream.write(getBuffer()); } } diff --git a/src/main/java/seng302/server/messages/Header.java b/src/main/java/seng302/server/messages/Header.java index 9f1a81e0..c4dc6251 100644 --- a/src/main/java/seng302/server/messages/Header.java +++ b/src/main/java/seng302/server/messages/Header.java @@ -1,6 +1,9 @@ package seng302.server.messages; +import java.math.BigInteger; import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Collections; public class Header { // From API spec @@ -12,6 +15,8 @@ public class Header { private int sourceId; private short messageLength; private static final int MESSAGE_LEN = 15; + private ByteBuffer buff; + private int buffPos; /** * Message Header from section 3.2 of the AC35 Streaming @@ -25,38 +30,34 @@ public class Header { this.sourceId = sourceId; this.messageLength = messageLength; timeStamp = (int) (System.currentTimeMillis() / 1000L); + buff = ByteBuffer.allocate(MESSAGE_LEN); + buffPos = 0; + } + + private void putInBuffer(byte[] bytes, long val){ + byte[] tmp = bytes.clone(); + Message.reverse(tmp); + + buff.put(tmp); + buffPos += tmp.length; + buff.position(buffPos); } /** * @return a ByteBuffer containing the message header */ public ByteBuffer getByteBuffer(){ - ByteBuffer buff = ByteBuffer.allocate(15); + putInBuffer(ByteBuffer.allocate(1).put((byte)syncByte1).array(), syncByte1); - // Sync Byte 1, 1 byte - buff.put(ByteBuffer.allocate(1).put((byte)syncByte1).array()); - buff.position(1); + putInBuffer(ByteBuffer.allocate(1).put((byte)syncByte2).array(), syncByte2); - // Sync Byte 2, 1 byte - buff.put(ByteBuffer.allocate(1).put((byte)syncByte2).array()); - buff.position(2); + putInBuffer(ByteBuffer.allocate(1).put((byte)messageType.getCode()).array(), messageType.getCode()); - // Message Type, 1 byte - buff.put(ByteBuffer.allocate(1).put((byte)messageType.getCode()).array()); - buff.position(3); + putInBuffer(Message.intToByteArray(timeStamp, 6), timeStamp); - // Timestamp, 6 bytes - int x = ((int) Integer.toUnsignedLong(6)); - buff.put(ByteBuffer.allocate(6).putInt(timeStamp).array()); - buff.position(9); + putInBuffer(Message.intToByteArray(sourceId, 4), sourceId); - // Source ID, 4 bytes - buff.put(ByteBuffer.allocate(4).putInt(sourceId).array()); - buff.position(13); - - // Message Length, 2 bytes - buff.put(ByteBuffer.allocate(2).putShort(messageLength).array()); - buff.position(15); + putInBuffer(Message.intToByteArray(messageLength, 2), messageLength); return buff; } diff --git a/src/main/java/seng302/server/messages/Heartbeat.java b/src/main/java/seng302/server/messages/Heartbeat.java index e5815039..3660af23 100644 --- a/src/main/java/seng302/server/messages/Heartbeat.java +++ b/src/main/java/seng302/server/messages/Heartbeat.java @@ -3,6 +3,9 @@ package seng302.server.messages; import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; import java.util.zip.CRC32; public class Heartbeat extends Message { @@ -23,7 +26,7 @@ public class Heartbeat extends Message { } @Override - public void send(DataOutputStream outputStream) { + public void send(SocketChannel outputStream) throws IOException { setHeader(new Header(MessageType.HEARTBEAT, 0x01, (short) getSize())); allocateBuffer(); @@ -33,10 +36,6 @@ public class Heartbeat extends Message { writeCRC(); - try { - outputStream.write(getBuffer().array()); - } catch (IOException e) { - e.printStackTrace(); - } + outputStream.write(getBuffer()); } } \ No newline at end of file diff --git a/src/main/java/seng302/server/messages/MarkRoundingMessage.java b/src/main/java/seng302/server/messages/MarkRoundingMessage.java index 405c46ff..82ef685d 100644 --- a/src/main/java/seng302/server/messages/MarkRoundingMessage.java +++ b/src/main/java/seng302/server/messages/MarkRoundingMessage.java @@ -2,6 +2,9 @@ package seng302.server.messages; import java.io.DataOutputStream; import java.io.IOException; +import java.nio.channels.Channels; +import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; public class MarkRoundingMessage extends Message{ private final long MESSAGE_VERSION_NUMBER = 1; @@ -38,7 +41,7 @@ public class MarkRoundingMessage extends Message{ } @Override - public void send(DataOutputStream outputStream) { + public void send(SocketChannel outputStream) throws IOException { allocateBuffer(); writeHeaderToBuffer(); @@ -53,10 +56,6 @@ public class MarkRoundingMessage extends Message{ writeCRC(); - try { - outputStream.write(getBuffer().array()); - } catch (IOException e) { - e.printStackTrace(); - } + outputStream.write(getBuffer()); } } diff --git a/src/main/java/seng302/server/messages/Message.java b/src/main/java/seng302/server/messages/Message.java index 889a37fa..2ef71afe 100644 --- a/src/main/java/seng302/server/messages/Message.java +++ b/src/main/java/seng302/server/messages/Message.java @@ -1,7 +1,13 @@ package seng302.server.messages; import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Array; import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.SocketChannel; +import java.util.ArrayList; +import java.util.Arrays; import java.util.zip.CRC32; public abstract class Message { @@ -33,13 +39,14 @@ public abstract class Message { /** * Send the message as through the outputStream */ - public abstract void send(DataOutputStream outputStream); + public abstract void send(SocketChannel outputStream) throws IOException; /** * Allocate byte buffer to correct size */ void allocateBuffer(){ buffer = ByteBuffer.allocate(Header.getSize() + getSize() + CRC_SIZE); + buffer.order(ByteOrder.LITTLE_ENDIAN); bufferPosition = 0; } @@ -47,7 +54,7 @@ public abstract class Message { * Write the set header to the byte buffer */ void writeHeaderToBuffer(){ - buffer.put(getHeader().getByteBuffer()); + buffer.put(getHeader().getByteBuffer().array()); bufferPosition += Header.getSize(); buffer.position(bufferPosition); } @@ -89,12 +96,15 @@ public abstract class Message { } else if (size < 4){ // Use short - buffer.put(ByteBuffer.allocate(size).putShort((short) (val & 0xffff)).array()); + byte[] tmp = Message.intToByteArray(val, size); //ByteBuffer.allocate(size).putShort((short) (val & 0xffff)).array(); + reverse(tmp); + buffer.put(tmp); moveBufferPositionBy(size); } else{ // Use int - buffer.put(ByteBuffer.allocate(size).putInt((int) (val & 0xffffffffL)).array()); + byte[] tmp = Message.intToByteArray(val, size); + reverse(tmp); moveBufferPositionBy(size); } } @@ -104,12 +114,16 @@ public abstract class Message { * @param val The integer value to add * @param size The size of the integer to be added to the buffer */ - void putInt(int val, int size){ + void putInt(long val, int size){ if (size < 4){ - buffer.put(ByteBuffer.allocate(size).putShort((short) val).array()); + byte[] tmp = Message.intToByteArray(val, size); + reverse(tmp); + buffer.put(tmp); } else{ - buffer.put(ByteBuffer.allocate(size).putInt((short) val).array()); + byte[] tmp = Message.intToByteArray(val, size); + reverse(tmp); + buffer.put(tmp); } moveBufferPositionBy(size); } @@ -141,7 +155,9 @@ public abstract class Message { crc = new CRC32(); buffer.position(0); - crc.update(buffer.array()); + + byte[] data = Arrays.copyOfRange(buffer.array(), 0, buffer.array().length-CRC_SIZE); + crc.update(data); buffer.position(bufferPosition); putInt((int) crc.getValue(), CRC_SIZE); @@ -154,4 +170,42 @@ public abstract class Message { return buffer; } + + /** + * Rewind the buffer to the beginning + */ + void rewind(){ + buffer.flip(); + } + + /** + * Convert an integer to an array of bytes + * @param val The value to add + * @param len The width of the integer in the buffer + * @return + */ + public static byte[] intToByteArray(long val, int len){ + int index = 0; + byte[] data = new byte[len]; + + for (int i = 0; i < len; i++){ + data[len - index - 1] = (byte) ((val >>> (8 * index))); + index++; + } + + return data; + } + + /** + * Reverse an array of bytes + * @param data The byte[] to reverse + */ + public static void reverse(byte[] data) { + for (int left = 0, right = data.length - 1; left < right; left++, right--) { + byte temp = data[left]; + data[left] = data[right]; + data[right] = temp; + } + } + } diff --git a/src/main/java/seng302/server/messages/MessageType.java b/src/main/java/seng302/server/messages/MessageType.java index be856dac..01bad14b 100644 --- a/src/main/java/seng302/server/messages/MessageType.java +++ b/src/main/java/seng302/server/messages/MessageType.java @@ -9,7 +9,7 @@ public enum MessageType { RACE_STATUS(12), DISPLAY_TEXT_MESSAGE(20), XML_MESSAGE(26), - RACE_START_STATUS(27), + RACE_START_STATUS(20), YACHT_EVENT_CODE(29), YACHT_ACTION_CODE(31), CHATTER_TEXT(36), diff --git a/src/main/java/seng302/server/messages/RaceStartStatusMessage.java b/src/main/java/seng302/server/messages/RaceStartStatusMessage.java index d2878bc2..a89471b8 100644 --- a/src/main/java/seng302/server/messages/RaceStartStatusMessage.java +++ b/src/main/java/seng302/server/messages/RaceStartStatusMessage.java @@ -2,6 +2,9 @@ package seng302.server.messages; import java.io.DataOutputStream; import java.io.IOException; +import java.nio.channels.Channels; +import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; public class RaceStartStatusMessage extends Message { private final int MESSAGE_SIZE = 20; @@ -37,7 +40,7 @@ public class RaceStartStatusMessage extends Message { } @Override - public void send(DataOutputStream outputStream) { + public void send(SocketChannel outputStream) throws IOException { allocateBuffer(); writeHeaderToBuffer(); @@ -50,10 +53,6 @@ public class RaceStartStatusMessage extends Message { writeCRC(); - try { - outputStream.write(getBuffer().array()); - } catch (IOException e) { - e.printStackTrace(); - } + outputStream.write(getBuffer()); } } diff --git a/src/main/java/seng302/server/messages/RaceStatusMessage.java b/src/main/java/seng302/server/messages/RaceStatusMessage.java index 77c0c67a..37aa3fe7 100644 --- a/src/main/java/seng302/server/messages/RaceStatusMessage.java +++ b/src/main/java/seng302/server/messages/RaceStatusMessage.java @@ -3,6 +3,9 @@ package seng302.server.messages; import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; import java.util.List; import java.util.zip.CRC32; @@ -63,7 +66,7 @@ public class RaceStatusMessage extends Message{ * @param outputStream The output stream to send the message */ @Override - public void send(DataOutputStream outputStream) { + public void send(SocketChannel outputStream) throws IOException { allocateBuffer(); writeHeaderToBuffer(); @@ -83,11 +86,6 @@ public class RaceStatusMessage extends Message{ writeCRC(); - // Send - try { - outputStream.write(getBuffer().array()); - } catch (IOException e) { - e.printStackTrace(); - } + outputStream.write(getBuffer()); } } diff --git a/src/main/java/seng302/server/messages/XMLMessage.java b/src/main/java/seng302/server/messages/XMLMessage.java index cc862d2f..a0044ea7 100644 --- a/src/main/java/seng302/server/messages/XMLMessage.java +++ b/src/main/java/seng302/server/messages/XMLMessage.java @@ -3,6 +3,9 @@ package seng302.server.messages; import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; import java.util.zip.CRC32; public class XMLMessage extends Message{ @@ -45,7 +48,7 @@ public class XMLMessage extends Message{ * Send this message as a stream of bytes * @param outputStream The output stream to send the message */ - public void send(DataOutputStream outputStream) { + public void send(SocketChannel outputStream) throws IOException { allocateBuffer(); writeHeaderToBuffer(); @@ -60,11 +63,6 @@ public class XMLMessage extends Message{ writeCRC(); - // Send - try { - outputStream.write(getBuffer().array()); - } catch (IOException e) { - e.printStackTrace(); - } + outputStream.write(getBuffer()); } } diff --git a/src/main/java/seng302/server/simulator/Simulator.java b/src/main/java/seng302/server/simulator/Simulator.java index 1d285884..0bdd9716 100644 --- a/src/main/java/seng302/server/simulator/Simulator.java +++ b/src/main/java/seng302/server/simulator/Simulator.java @@ -47,7 +47,7 @@ public class Simulator extends Observable implements Runnable { for (Boat boat : boats) { numOfFinishedBoats += moveBoat(boat, lapse); } - System.out.println(boats.get(0)); + //System.out.println(boats.get(0)); setChanged(); notifyObservers(boats); @@ -121,4 +121,8 @@ public class Simulator extends Observable implements Runnable { } } + public List getBoats(){ + return boats; + } + } diff --git a/src/main/resources/server_config/boats.xml b/src/main/resources/server_config/boats.xml index df5ddca4..f5e1e1fb 100644 --- a/src/main/resources/server_config/boats.xml +++ b/src/main/resources/server_config/boats.xml @@ -137,50 +137,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -211,24 +167,5 @@ - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/test/java/seng302/server/TestHeader.java b/src/test/java/seng302/server/TestHeader.java index 4fa2bc3d..3655bc03 100644 --- a/src/test/java/seng302/server/TestHeader.java +++ b/src/test/java/seng302/server/TestHeader.java @@ -1,8 +1,7 @@ package seng302.server; import org.junit.Test; -import seng302.server.messages.Header; -import seng302.server.messages.MessageType; +import seng302.server.messages.*; import static junit.framework.TestCase.assertTrue; @@ -23,4 +22,5 @@ public class TestHeader { Header h = new Header(MessageType.DISPLAY_TEXT_MESSAGE, 1, (short) 1); assertTrue(h.getSize() == 15); // Spec specifies 15 bytes } + } diff --git a/src/test/java/seng302/server/TestMessage.java b/src/test/java/seng302/server/TestMessage.java index 71521014..8d8dfa46 100644 --- a/src/test/java/seng302/server/TestMessage.java +++ b/src/test/java/seng302/server/TestMessage.java @@ -17,24 +17,6 @@ public class TestMessage { private static int BOAT_SUB_MESSAGE_LEN = 20; private static int CRC_LEN = 4; - /** - * Test generated output is the same as the expected output - */ - @Test - public void testHeatBetBufferOutputLength(){ - Message m = new Heartbeat(1); - List output = new ArrayList<>(); - - DataOutputStream ds = new DataOutputStream(new OutputStream() { - @Override - public void write(int b) throws IOException { - output.add(b); - } - }); - - m.send(ds); - assertTrue(output.size() == (m.getSize() + CRC_LEN + Header.getSize())); - } /** * Test output expected is the same as the spec @@ -45,92 +27,5 @@ public class TestMessage { assertTrue(m.getSize() == (XML_MESSAGE_LEN + "12345".length())); } - /** - * Ensure that when no boats are in the race, that only the base message is sent - */ - @Test - public void testRaceStatusMessageBufferLenNoBoats(){ - Message m = new RaceStatusMessage(1, RaceStatus.PRESTART,1,WindDirection.EAST,1, - 0,RaceType.MATCH_RACE,1, new ArrayList()); - List output = new ArrayList<>(); - - DataOutputStream ds = new DataOutputStream(new OutputStream() { - @Override - public void write(int b) throws IOException { - output.add(b); - } - }); - - m.send(ds); - assertTrue(output.size() == RACE_STATUS_BASE_LEN + Header.getSize() + CRC_LEN); - } - - /** - * Test that each boat status is added to the message - */ - @Test - public void testRaceStatusMessageBufferLenWithBoats(){ - List boatMessages = new ArrayList<>(); - List output = new ArrayList<>(); - - BoatSubMessage boat1 = new BoatSubMessage(1, BoatStatus.PRESTART, 0, 0, 0, - 10000, 10000); - - BoatSubMessage boat2 = new BoatSubMessage(2, BoatStatus.PRESTART, 0, 0, 0, - 10000, 10000); - - BoatSubMessage boat3 = new BoatSubMessage(3, BoatStatus.PRESTART, 0, 0, 0, - 10000, 10000); - - boatMessages.add(boat1); - boatMessages.add(boat2); - boatMessages.add(boat3); - - Message m = new RaceStatusMessage(1, RaceStatus.PRESTART,1,WindDirection.EAST,1, - 3,RaceType.MATCH_RACE,1, boatMessages); - - DataOutputStream ds = new DataOutputStream(new OutputStream() { - @Override - public void write(int b) throws IOException { - output.add(b); - } - }); - - m.send(ds); - assertTrue(output.size() == (RACE_STATUS_BASE_LEN + (BOAT_SUB_MESSAGE_LEN * 3) + CRC_LEN + Header.getSize())); - } - - /** - * IllegalArgumentException should be thrown when numBoatsInRace is smaller - * than the number of boats actually in the race - */ - @Test(expected = IllegalArgumentException.class) - public void testRaceStatusTooManyBoats(){ - List boatMessages = new ArrayList<>(); - List output = new ArrayList<>(); - - BoatSubMessage boat1 = new BoatSubMessage(1, BoatStatus.PRESTART, 0, 0, 0, - 10000, 10000); - - BoatSubMessage boat2 = new BoatSubMessage(2, BoatStatus.PRESTART, 0, 0, 0, - 10000, 10000); - - BoatSubMessage boat3 = new BoatSubMessage(3, BoatStatus.PRESTART, 0, 0, 0, - 10000, 10000); - - boatMessages.add(boat1); - boatMessages.add(boat2); - boatMessages.add(boat3); - - Message m = new RaceStatusMessage(1, RaceStatus.PRESTART,1,WindDirection.EAST,1, - 1,RaceType.MATCH_RACE,1, boatMessages); - - m.send(new DataOutputStream(new OutputStream() { - @Override - public void write(int b) throws IOException { - System.out.print(""); - } - })); - } }