From f5b9160304475ccd6c5698d53cec2e7183856051 Mon Sep 17 00:00:00 2001 From: Alistair McIntyre Date: Thu, 27 Apr 2017 17:22:46 +1200 Subject: [PATCH 1/7] Started parsing the different types of XML messages to Map objects so that we can extract the relevant data for the visualizer. #story[820] --- .../seng302/models/parsers/StreamPacket.java | 2 +- .../seng302/models/parsers/StreamParser.java | 89 ++++++++++++++++++- .../models/parsers/StreamReceiver.java | 4 +- 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/src/main/java/seng302/models/parsers/StreamPacket.java b/src/main/java/seng302/models/parsers/StreamPacket.java index 80e2936e..85711db2 100644 --- a/src/main/java/seng302/models/parsers/StreamPacket.java +++ b/src/main/java/seng302/models/parsers/StreamPacket.java @@ -19,7 +19,7 @@ public class StreamPacket { this.payload = payload; // System.out.println("type = " + type); //switch the packet type to deal with what ever specific packet you want to deal with - if (this.type == PacketType.AVG_WIND){ + if (this.type == PacketType.XML_MESSAGE){ StreamParser.parsePacket(this); } } diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index 6f526ba3..24c3752a 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -2,6 +2,9 @@ package seng302.models.parsers; import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -13,6 +16,8 @@ import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; /** * Created by kre39 on 23/04/17. @@ -127,6 +132,7 @@ public class StreamParser { while (payloadStream.available() > 0 && (currentChar = payloadStream.read()) != 0) { xmlMessage += (char)currentChar; } + if (xmlMessageSubType == 6) System.out.println(xmlMessage); //Create XML document Object DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); @@ -134,7 +140,12 @@ public class StreamParser { try { db = dbf.newDocumentBuilder(); Document doc = db.parse(new InputSource(new StringReader(xmlMessage))); - // TODO: 25/04/17 ajm412: Check that the object matches expected structure and return Document object. + switch(xmlMessageSubType) { + case 5: parseRegattaXML(doc); + case 6: parseRaceXML(doc); + case 7: parseBoatXML(doc); + } + } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { @@ -145,6 +156,82 @@ public class StreamParser { } + private static void parseRegattaXML(Document doc) { + Element docEle = doc.getDocumentElement(); + String[] regattaElements = {"RegattaID", "RegattaName", "CourseName", "CentralLatitude", "CentralLongitude", + "CentralAltitude", "UtcOffset", "MagneticVariation", "ShorelineName"}; + Map outputMap = parseAtomicElements(docEle, regattaElements); // Regatta contains only atomic elements + + System.out.println(outputMap); + //return outputMap; + } + + private static void parseRaceXML(Document doc) { + Element docEle = doc.getDocumentElement(); + String[] atomicRaceElements = {"RaceID", "RaceType", "CreationTimeDate"}; + Map outputMap = parseAtomicElements(docEle, atomicRaceElements); + + //Race Start Time + Map raceStartMap = new HashMap<>(); + Node raceStartTime = docEle.getElementsByTagName("RaceStartTime").item(0); + raceStartMap.put("Start", getNodeNamedAttribute(raceStartTime, "Start")); + raceStartMap.put("Postpone", getNodeNamedAttribute(raceStartTime, "Postpone")); + outputMap.put("RaceStartTime", raceStartMap); + + //participants + Map participantMap = new HashMap<>(); + NodeList participants = docEle.getElementsByTagName("Participants").item(0).getChildNodes(); + for (int i = 0; i < participants.getLength(); i++) { + Integer sourceID = null; + String entry = null; + Node participant = participants.item(i); + if (participant.getNodeName().equals("Yacht")) { + //sourceID = Integer.parseInt(participant.getAttributes().getNamedItem("SourceID").getTextContent()); + sourceID = Integer.parseInt(getNodeNamedAttribute(participant, "SourceID")); + if (participant.getAttributes().getLength() == 2) { + entry = getNodeNamedAttribute(participant, "Entry"); + } + participantMap.put(sourceID, entry); + } + } + outputMap.put("Participants", participantMap); + + //Course + + System.out.println(outputMap); + } + + private static void parseBoatXML(Document doc) { + // TODO: 27/04/17 ajm412 + } + + private static String getNodeNamedAttribute(Node n, String attr) { + return n.getAttributes().getNamedItem(attr).getTextContent(); + } + + private static Map parseAtomicElements(Element docEle, String[] elements) { + Map outputMap = new HashMap<>(); + for (String element : elements) { + Object elementValue = null; + if (docEle.getElementsByTagName(element).getLength() == 1) { + String elementText = docEle.getElementsByTagName(element).item(0).getTextContent(); + // TODO: 27/04/17 ajm412: this seems messy, trying to parse values as ints/doubles to the map rather than as Strings. Possibly use RegEx. + try { + elementValue = Integer.parseInt(elementText); + } catch (NumberFormatException nfe1) { + try { + elementValue = Double.parseDouble(elementText); + } catch (NumberFormatException nfe2) { + elementValue = elementText; + } + } + } + outputMap.put(element, elementValue); + } + + return outputMap; + } + private static void extractRaceStartStatus(StreamPacket packet){ byte[] payload = packet.getPayload(); int messageVersionNo = payload[0]; diff --git a/src/main/java/seng302/models/parsers/StreamReceiver.java b/src/main/java/seng302/models/parsers/StreamReceiver.java index d5127ce4..128683a3 100644 --- a/src/main/java/seng302/models/parsers/StreamReceiver.java +++ b/src/main/java/seng302/models/parsers/StreamReceiver.java @@ -4,8 +4,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.Socket; -import java.util.ArrayList; -import java.util.Collection; import java.util.Comparator; import java.util.concurrent.PriorityBlockingQueue; import java.util.zip.CRC32; @@ -129,7 +127,7 @@ public class StreamReceiver { } }); StreamReceiver sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, pq); -// StreamReceiver sr = new StreamReceiver("livedata.americascup.com", 4941, pq); + //StreamReceiver sr = new StreamReceiver("livedata.americascup.com", 4941, pq); sr.connect(); } } From e1de5e0989d90d235f511140c8b50ff8a74d1c80 Mon Sep 17 00:00:00 2001 From: Alistair McIntyre Date: Thu, 27 Apr 2017 18:31:13 +1200 Subject: [PATCH 2/7] Parsed more course data from XML messages #story[820] --- .../seng302/models/parsers/StreamParser.java | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index 24c3752a..0c982ec6 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -14,10 +14,7 @@ import javax.xml.parsers.ParserConfigurationException; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.StringReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; +import java.util.*; /** * Created by kre39 on 23/04/17. @@ -130,7 +127,7 @@ public class StreamParser { //Converts XML message to string to be parsed int currentChar; while (payloadStream.available() > 0 && (currentChar = payloadStream.read()) != 0) { - xmlMessage += (char)currentChar; + xmlMessage += (char)currentChar; } if (xmlMessageSubType == 6) System.out.println(xmlMessage); @@ -167,6 +164,7 @@ public class StreamParser { } private static void parseRaceXML(Document doc) { + // TODO: 27/04/17 ajm412 This is an extremely long method. Needs to be broken down. Element docEle = doc.getDocumentElement(); String[] atomicRaceElements = {"RaceID", "RaceType", "CreationTimeDate"}; Map outputMap = parseAtomicElements(docEle, atomicRaceElements); @@ -196,7 +194,37 @@ public class StreamParser { } outputMap.put("Participants", participantMap); - //Course + //Course - Order matters. + Map courseMap = new TreeMap<>(); + NodeList course = docEle.getElementsByTagName("Course").item(0).getChildNodes(); + for (int i = 0; i < course.getLength(); i++) { + Integer compoundMarkID = null; + String name = null; + Map compoundMarkMap = new TreeMap<>(); + Node compoundMark = course.item(i); + if (compoundMark.getNodeName().equals("CompoundMark")) { + compoundMarkID = Integer.parseInt(getNodeNamedAttribute(compoundMark, "CompoundMarkID")); + name = getNodeNamedAttribute(compoundMark, "Name"); + //get marks for compound mark + NodeList marks = compoundMark.getChildNodes(); + for (int j = 0; j < marks.getLength(); j++) { + Map markMap = new TreeMap<>(); + Node mark = marks.item(j); + if (mark.getNodeName().equals("Mark")) { + markMap.put("Name", getNodeNamedAttribute(mark, "Name")); + markMap.put("TargetLat", Double.parseDouble(getNodeNamedAttribute(mark, "TargetLat"))); + markMap.put("TargetLng", Double.parseDouble(getNodeNamedAttribute(mark, "TargetLng"))); + markMap.put("SourceID", Integer.parseInt(getNodeNamedAttribute(mark, "SourceID"))); + + compoundMarkMap.put(Integer.parseInt(getNodeNamedAttribute(mark, "SeqID")), markMap); + + } + } + + } + courseMap.put(compoundMarkID, compoundMarkMap); + } + //outputMap.put("Course", courseMap); System.out.println(outputMap); } From fe480d5cb6c41ff03f50931646806dde29f08e08 Mon Sep 17 00:00:00 2001 From: Alistair McIntyre Date: Fri, 28 Apr 2017 15:41:12 +1200 Subject: [PATCH 3/7] Finished parsing the Race XML data. Began making some optimizations to hopefully make parsing the Boat Data a quicker and simpler task. #story[820] --- .../seng302/models/parsers/StreamParser.java | 84 +++++++++++++++---- .../models/parsers/StreamReceiver.java | 4 +- 2 files changed, 72 insertions(+), 16 deletions(-) diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index 0c982ec6..dff14a7f 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -159,7 +159,7 @@ public class StreamParser { "CentralAltitude", "UtcOffset", "MagneticVariation", "ShorelineName"}; Map outputMap = parseAtomicElements(docEle, regattaElements); // Regatta contains only atomic elements - System.out.println(outputMap); + //System.out.println(outputMap); //return outputMap; } @@ -176,30 +176,56 @@ public class StreamParser { raceStartMap.put("Postpone", getNodeNamedAttribute(raceStartTime, "Postpone")); outputMap.put("RaceStartTime", raceStartMap); - //participants - Map participantMap = new HashMap<>(); + //Race Participants NodeList participants = docEle.getElementsByTagName("Participants").item(0).getChildNodes(); + outputMap.put("Participants", parseRaceParticipants(participants)); + + //Course (CompoundMarks) + NodeList course = docEle.getElementsByTagName("Course").item(0).getChildNodes(); + outputMap.put("Course", parseCourse(course)); + + //CompoundMark Sequence + NodeList markSequence = docEle.getElementsByTagName("CompoundMarkSequence").item(0).getChildNodes(); + outputMap.put("CourseMarkSequence", parseMarkSequence(markSequence)); + + //Course Limits + NodeList courseLimits = docEle.getElementsByTagName("CourseLimit").item(0).getChildNodes(); + outputMap.put("CourseLimit", parseCourseLimits(courseLimits)); + + System.out.println(outputMap.get("Course")); +// for (Map.Entry entry : outputMap.entrySet()) { +// System.out.println(entry); +// } + } + + private static ArrayList parseRaceParticipants(NodeList participants) { + ArrayList participantList = new ArrayList<>(); for (int i = 0; i < participants.getLength(); i++) { + Map participantMap = new HashMap<>(); Integer sourceID = null; String entry = null; Node participant = participants.item(i); if (participant.getNodeName().equals("Yacht")) { - //sourceID = Integer.parseInt(participant.getAttributes().getNamedItem("SourceID").getTextContent()); sourceID = Integer.parseInt(getNodeNamedAttribute(participant, "SourceID")); if (participant.getAttributes().getLength() == 2) { entry = getNodeNamedAttribute(participant, "Entry"); } - participantMap.put(sourceID, entry); + participantMap.put("sourceID", sourceID); + participantMap.put("Entry", entry); + participantList.add(participantMap); } } - outputMap.put("Participants", participantMap); + return participantList; + } - //Course - Order matters. + private static Map parseCourse(NodeList course) { Map courseMap = new TreeMap<>(); - NodeList course = docEle.getElementsByTagName("Course").item(0).getChildNodes(); + ArrayList courseList = new ArrayList<>(); for (int i = 0; i < course.getLength(); i++) { + Integer compoundMarkID = null; String name = null; + //map for an individual CompoundMark Map compoundMarkMap = new TreeMap<>(); Node compoundMark = course.item(i); if (compoundMark.getNodeName().equals("CompoundMark")) { @@ -208,6 +234,7 @@ public class StreamParser { //get marks for compound mark NodeList marks = compoundMark.getChildNodes(); for (int j = 0; j < marks.getLength(); j++) { + //map for individual mark details within a compound mark Map markMap = new TreeMap<>(); Node mark = marks.item(j); if (mark.getNodeName().equals("Mark")) { @@ -215,18 +242,47 @@ public class StreamParser { markMap.put("TargetLat", Double.parseDouble(getNodeNamedAttribute(mark, "TargetLat"))); markMap.put("TargetLng", Double.parseDouble(getNodeNamedAttribute(mark, "TargetLng"))); markMap.put("SourceID", Integer.parseInt(getNodeNamedAttribute(mark, "SourceID"))); - compoundMarkMap.put(Integer.parseInt(getNodeNamedAttribute(mark, "SeqID")), markMap); - } } - + courseMap.put(compoundMarkID, compoundMarkMap); } - courseMap.put(compoundMarkID, compoundMarkMap); } - //outputMap.put("Course", courseMap); - System.out.println(outputMap); + return courseMap; + } + + private static Map parseMarkSequence(NodeList markSequence) { + Map markSequenceMap = new TreeMap<>(); + + for (int i = 0; i < markSequence.getLength(); i++) { + Map cornerMap = new TreeMap<>(); + Node corner = markSequence.item(i); + if (corner.getNodeName().equals("Corner")) { + cornerMap.put("CompoundMarkID", Integer.parseInt(getNodeNamedAttribute(corner, "CompoundMarkID"))); + cornerMap.put("Rounding", getNodeNamedAttribute(corner, "Rounding")); + cornerMap.put("ZoneSize", getNodeNamedAttribute(corner, "ZoneSize")); + markSequenceMap.put(Integer.parseInt(getNodeNamedAttribute(corner, "SeqID")), cornerMap); + } + } + + return markSequenceMap; + } + + private static Map parseCourseLimits(NodeList courseLimits) { + Map courseLimitMap = new TreeMap<>(); + + for (int i = 0; i < courseLimits.getLength(); i++) { + Map limitMap = new HashMap<>(); + Node limit = courseLimits.item(i); + if (limit.getNodeName().equals("Limit")) { + limitMap.put("Lat", Double.parseDouble(getNodeNamedAttribute(limit,"Lat"))); + limitMap.put("Lon", Double.parseDouble(getNodeNamedAttribute(limit,"Lon"))); + courseLimitMap.put(Integer.parseInt(getNodeNamedAttribute(limit, "SeqID")), limitMap); + } + } + + return courseLimitMap; } private static void parseBoatXML(Document doc) { diff --git a/src/main/java/seng302/models/parsers/StreamReceiver.java b/src/main/java/seng302/models/parsers/StreamReceiver.java index 128683a3..31912815 100644 --- a/src/main/java/seng302/models/parsers/StreamReceiver.java +++ b/src/main/java/seng302/models/parsers/StreamReceiver.java @@ -126,8 +126,8 @@ public class StreamReceiver { return (int) (s1.getTimeStamp() - s2.getTimeStamp()); } }); - StreamReceiver sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, pq); - //StreamReceiver sr = new StreamReceiver("livedata.americascup.com", 4941, pq); + //StreamReceiver sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, pq); + StreamReceiver sr = new StreamReceiver("livedata.americascup.com", 4941, pq); sr.connect(); } } From 07bbd7e06d29948fd92f345438edba21d0efe6dd Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Fri, 28 Apr 2017 18:29:35 +1200 Subject: [PATCH 4/7] Added reasonable testing for StreamReciever, further testing would probably need StreamReciever to be rewritten #story[817] --- .../models/parsers/StreamReceiver.java | 12 +- .../models/parsers/StreamReceiverTest.java | 105 ++++++++++++++++++ 2 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 src/test/java/seng302/models/parsers/StreamReceiverTest.java diff --git a/src/main/java/seng302/models/parsers/StreamReceiver.java b/src/main/java/seng302/models/parsers/StreamReceiver.java index 31912815..663f3a8c 100644 --- a/src/main/java/seng302/models/parsers/StreamReceiver.java +++ b/src/main/java/seng302/models/parsers/StreamReceiver.java @@ -19,6 +19,7 @@ public class StreamReceiver { public StreamReceiver(String hostAddress, int hostPort, PriorityBlockingQueue packetBuffer) { try { host = new Socket(hostAddress, hostPort); + } catch (IOException e) { e.printStackTrace(); System.exit(1); @@ -26,6 +27,12 @@ public class StreamReceiver { this.packetBuffer = packetBuffer; } + public StreamReceiver(Socket host, PriorityBlockingQueue packetBuffer){ + this.host=host; + this.packetBuffer = packetBuffer; + } + + public void connect(){ try { stream = host.getInputStream(); @@ -66,7 +73,6 @@ public class StreamReceiver { } catch (Exception e) { moreBytes = false; } - } } @@ -100,8 +106,8 @@ public class StreamReceiver { } /** - * takes an array of up to 7 bytes and returns a positive - * long constructed from the input bytes + * takes an array of up to 7 bytes in little endian format and + * returns a positive long constructed from the input bytes * * @return a positive long if there is less than 7 bytes -1 otherwise */ diff --git a/src/test/java/seng302/models/parsers/StreamReceiverTest.java b/src/test/java/seng302/models/parsers/StreamReceiverTest.java new file mode 100644 index 00000000..c7951e3b --- /dev/null +++ b/src/test/java/seng302/models/parsers/StreamReceiverTest.java @@ -0,0 +1,105 @@ +package seng302.models.parsers; + +import org.junit.Before; +import org.junit.Test; + +import java.io.*; +import java.lang.reflect.Method; +import java.net.Socket; +import java.util.Comparator; +import java.util.concurrent.PriorityBlockingQueue; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Created by ptg19 on 26/04/17. + */ +public class StreamReceiverTest { + + private PriorityBlockingQueue pq; + private byte[] brokenPacket = {0x47, (byte) 0x83, 37, // sync1 sync2 and message type + 0b00000000, 0b01000000, 0b00100010, 0b00100100, 0b00011000, 0b00000000, //timestamp + 0b00000000, 0b00010000, 0b01000000, 0b00000000, //source id + 0b00100010, 0b00101000, // message length + 0b00010010, 0b00010010, 0b00010010}; //random start of payload + + private byte[] workingPacket = {0x47, (byte) 0x83, 37, // sync1 sync2 and message type + 0b00000000, 0b01000000, 0b00100010, 0b00100100, 0b00011000, 0b00000000, //timestamp + 0b00000000, 0b00010000, 0b01000000, 0b00000000, //source id + 0b00000010, 0b00000000, // message length + 0b00010010, 0b00010010, // payload + 0b00100110, (byte)0b10000111, 0b00110101, 0b01111000}; //crc + + private byte[] crcMismatchPacket = {0x47, (byte) 0x83, 37, // sync1 sync2 and message type + 0b00000000, 0b01000000, 0b00100010, 0b00100100, 0b00011000, 0b00000000, //timestamp + 0b00000000, 0b00000000, 0b01000000, 0b00000000, //source id + 0b00000010, 0b00000000, // message length + 0b00010010, 0b00010010, // payload + 0b00100110, (byte)0b10000111, 0b00110101, 0b01111000}; //crc + + + @Before + public void setup(){ + pq = new PriorityBlockingQueue<>(256, new Comparator() { + @Override + public int compare(StreamPacket s1, StreamPacket s2) { + return (int) (s1.getTimeStamp() - s2.getTimeStamp()); + } + }); + } + + @Test + public void connectExitsOnUnexpectedStreamEnd() throws Exception { + Socket host=mock(Socket.class); + InputStream stream = new ByteArrayInputStream(brokenPacket); + when(host.getInputStream()).thenReturn(stream); + StreamReceiver streamReceiver = new StreamReceiver(host, pq); + + streamReceiver.connect(); + assert pq.size() == 0; + } + + @Test + public void connectReadsAPacket() throws Exception { + Socket host=mock(Socket.class); + InputStream stream = new ByteArrayInputStream(workingPacket); + when(host.getInputStream()).thenReturn(stream); + StreamReceiver streamReceiver = new StreamReceiver(host, pq); + + streamReceiver.connect(); + assert pq.size() == 1; + } + + @Test + public void connectDropsAMismatchedCrc() throws Exception { + Socket host=mock(Socket.class); + InputStream stream = new ByteArrayInputStream(crcMismatchPacket); + when(host.getInputStream()).thenReturn(stream); + StreamReceiver streamReceiver = new StreamReceiver(host, pq); + + streamReceiver.connect(); + assert pq.size() == 0; + } + + @Test + public void bytestoLongTest() { + Socket host=mock(Socket.class); + StreamReceiver streamReceiver = new StreamReceiver(host, pq); + try { + Class[] args = new Class[1]; + args[0] = byte[].class; + Method bytesToLong = streamReceiver.getClass().getDeclaredMethod("bytesToLong", args); + bytesToLong.setAccessible(true); + byte[] sevenBtyeNumber = {0b01100100, 0b00110100, 0b00010100, 0b00000000, 0b00000000, 0b00000000, (byte)0b10000000}; + assert bytesToLong.invoke(streamReceiver, sevenBtyeNumber).equals(36028797020288100L); + byte[] eightByteNumber = {0b01100100, 0b00110100, 0b00010100, 0b00000000, 0b00000000, 0b00000000, (byte)0b10000000, 0b00100101}; + assert bytesToLong.invoke(streamReceiver, eightByteNumber).equals(-1L); + byte[] emptyArray = {}; + assert bytesToLong.invoke(streamReceiver, emptyArray).equals(0L); + } catch (Exception e){ + System.out.println(""); + } + } + +} \ No newline at end of file From ab0d4634d67e0bc9c064658427f73f3f323c2804 Mon Sep 17 00:00:00 2001 From: Alistair McIntyre Date: Sat, 29 Apr 2017 19:02:30 +1200 Subject: [PATCH 5/7] Moved XML parsing to non static class to create objects. Changed the abstraction as using generics in maps lead to more headaches than anything. Still not quite completed. Needs documentation and validation for tags too. #story[820] --- .../seng302/models/parsers/StreamParser.java | 180 +--------- .../seng302/models/parsers/XMLParser.java | 335 ++++++++++++++++++ 2 files changed, 340 insertions(+), 175 deletions(-) create mode 100644 src/main/java/seng302/models/parsers/XMLParser.java diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index dff14a7f..d3520cf6 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -129,7 +129,7 @@ public class StreamParser { while (payloadStream.available() > 0 && (currentChar = payloadStream.read()) != 0) { xmlMessage += (char)currentChar; } - if (xmlMessageSubType == 6) System.out.println(xmlMessage); + if (xmlMessageSubType == 7) System.out.println(xmlMessage); //Create XML document Object DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); @@ -137,183 +137,13 @@ public class StreamParser { try { db = dbf.newDocumentBuilder(); Document doc = db.parse(new InputSource(new StringReader(xmlMessage))); - switch(xmlMessageSubType) { - case 5: parseRegattaXML(doc); - case 6: parseRaceXML(doc); - case 7: parseBoatXML(doc); + if (xmlMessageSubType == 7) { + XMLParser x = new XMLParser(); + XMLParser.BoatXMLObject xr = x.createBoatXML(doc); } - - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (SAXException e) { - e.printStackTrace(); - } catch (IOException e) { + } catch (ParserConfigurationException|SAXException|IOException e) { e.printStackTrace(); } - - } - - private static void parseRegattaXML(Document doc) { - Element docEle = doc.getDocumentElement(); - String[] regattaElements = {"RegattaID", "RegattaName", "CourseName", "CentralLatitude", "CentralLongitude", - "CentralAltitude", "UtcOffset", "MagneticVariation", "ShorelineName"}; - Map outputMap = parseAtomicElements(docEle, regattaElements); // Regatta contains only atomic elements - - //System.out.println(outputMap); - //return outputMap; - } - - private static void parseRaceXML(Document doc) { - // TODO: 27/04/17 ajm412 This is an extremely long method. Needs to be broken down. - Element docEle = doc.getDocumentElement(); - String[] atomicRaceElements = {"RaceID", "RaceType", "CreationTimeDate"}; - Map outputMap = parseAtomicElements(docEle, atomicRaceElements); - - //Race Start Time - Map raceStartMap = new HashMap<>(); - Node raceStartTime = docEle.getElementsByTagName("RaceStartTime").item(0); - raceStartMap.put("Start", getNodeNamedAttribute(raceStartTime, "Start")); - raceStartMap.put("Postpone", getNodeNamedAttribute(raceStartTime, "Postpone")); - outputMap.put("RaceStartTime", raceStartMap); - - //Race Participants - NodeList participants = docEle.getElementsByTagName("Participants").item(0).getChildNodes(); - outputMap.put("Participants", parseRaceParticipants(participants)); - - //Course (CompoundMarks) - NodeList course = docEle.getElementsByTagName("Course").item(0).getChildNodes(); - outputMap.put("Course", parseCourse(course)); - - //CompoundMark Sequence - NodeList markSequence = docEle.getElementsByTagName("CompoundMarkSequence").item(0).getChildNodes(); - outputMap.put("CourseMarkSequence", parseMarkSequence(markSequence)); - - //Course Limits - NodeList courseLimits = docEle.getElementsByTagName("CourseLimit").item(0).getChildNodes(); - outputMap.put("CourseLimit", parseCourseLimits(courseLimits)); - - System.out.println(outputMap.get("Course")); -// for (Map.Entry entry : outputMap.entrySet()) { -// System.out.println(entry); -// } - } - - private static ArrayList parseRaceParticipants(NodeList participants) { - ArrayList participantList = new ArrayList<>(); - for (int i = 0; i < participants.getLength(); i++) { - Map participantMap = new HashMap<>(); - Integer sourceID = null; - String entry = null; - Node participant = participants.item(i); - if (participant.getNodeName().equals("Yacht")) { - sourceID = Integer.parseInt(getNodeNamedAttribute(participant, "SourceID")); - if (participant.getAttributes().getLength() == 2) { - entry = getNodeNamedAttribute(participant, "Entry"); - } - participantMap.put("sourceID", sourceID); - participantMap.put("Entry", entry); - participantList.add(participantMap); - } - } - return participantList; - } - - private static Map parseCourse(NodeList course) { - Map courseMap = new TreeMap<>(); - ArrayList courseList = new ArrayList<>(); - for (int i = 0; i < course.getLength(); i++) { - - Integer compoundMarkID = null; - String name = null; - //map for an individual CompoundMark - Map compoundMarkMap = new TreeMap<>(); - Node compoundMark = course.item(i); - if (compoundMark.getNodeName().equals("CompoundMark")) { - compoundMarkID = Integer.parseInt(getNodeNamedAttribute(compoundMark, "CompoundMarkID")); - name = getNodeNamedAttribute(compoundMark, "Name"); - //get marks for compound mark - NodeList marks = compoundMark.getChildNodes(); - for (int j = 0; j < marks.getLength(); j++) { - //map for individual mark details within a compound mark - Map markMap = new TreeMap<>(); - Node mark = marks.item(j); - if (mark.getNodeName().equals("Mark")) { - markMap.put("Name", getNodeNamedAttribute(mark, "Name")); - markMap.put("TargetLat", Double.parseDouble(getNodeNamedAttribute(mark, "TargetLat"))); - markMap.put("TargetLng", Double.parseDouble(getNodeNamedAttribute(mark, "TargetLng"))); - markMap.put("SourceID", Integer.parseInt(getNodeNamedAttribute(mark, "SourceID"))); - compoundMarkMap.put(Integer.parseInt(getNodeNamedAttribute(mark, "SeqID")), markMap); - } - } - courseMap.put(compoundMarkID, compoundMarkMap); - } - } - - return courseMap; - } - - private static Map parseMarkSequence(NodeList markSequence) { - Map markSequenceMap = new TreeMap<>(); - - for (int i = 0; i < markSequence.getLength(); i++) { - Map cornerMap = new TreeMap<>(); - Node corner = markSequence.item(i); - if (corner.getNodeName().equals("Corner")) { - cornerMap.put("CompoundMarkID", Integer.parseInt(getNodeNamedAttribute(corner, "CompoundMarkID"))); - cornerMap.put("Rounding", getNodeNamedAttribute(corner, "Rounding")); - cornerMap.put("ZoneSize", getNodeNamedAttribute(corner, "ZoneSize")); - markSequenceMap.put(Integer.parseInt(getNodeNamedAttribute(corner, "SeqID")), cornerMap); - } - } - - return markSequenceMap; - } - - private static Map parseCourseLimits(NodeList courseLimits) { - Map courseLimitMap = new TreeMap<>(); - - for (int i = 0; i < courseLimits.getLength(); i++) { - Map limitMap = new HashMap<>(); - Node limit = courseLimits.item(i); - if (limit.getNodeName().equals("Limit")) { - limitMap.put("Lat", Double.parseDouble(getNodeNamedAttribute(limit,"Lat"))); - limitMap.put("Lon", Double.parseDouble(getNodeNamedAttribute(limit,"Lon"))); - courseLimitMap.put(Integer.parseInt(getNodeNamedAttribute(limit, "SeqID")), limitMap); - } - } - - return courseLimitMap; - } - - private static void parseBoatXML(Document doc) { - // TODO: 27/04/17 ajm412 - } - - private static String getNodeNamedAttribute(Node n, String attr) { - return n.getAttributes().getNamedItem(attr).getTextContent(); - } - - private static Map parseAtomicElements(Element docEle, String[] elements) { - Map outputMap = new HashMap<>(); - for (String element : elements) { - Object elementValue = null; - if (docEle.getElementsByTagName(element).getLength() == 1) { - String elementText = docEle.getElementsByTagName(element).item(0).getTextContent(); - // TODO: 27/04/17 ajm412: this seems messy, trying to parse values as ints/doubles to the map rather than as Strings. Possibly use RegEx. - try { - elementValue = Integer.parseInt(elementText); - } catch (NumberFormatException nfe1) { - try { - elementValue = Double.parseDouble(elementText); - } catch (NumberFormatException nfe2) { - elementValue = elementText; - } - } - } - outputMap.put(element, elementValue); - } - - return outputMap; } private static void extractRaceStartStatus(StreamPacket packet){ diff --git a/src/main/java/seng302/models/parsers/XMLParser.java b/src/main/java/seng302/models/parsers/XMLParser.java new file mode 100644 index 00000000..03e1c3e2 --- /dev/null +++ b/src/main/java/seng302/models/parsers/XMLParser.java @@ -0,0 +1,335 @@ +package seng302.models.parsers; + +import com.sun.org.apache.xpath.internal.SourceTree; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +class XMLParser { + + RegattaXMLObject createRegattaXML(Document doc) { + return new RegattaXMLObject(doc); + } + + RaceXMLObject createRaceXML(Document doc) { + return new RaceXMLObject(doc); + } + + BoatXMLObject createBoatXML(Document doc) { + return new BoatXMLObject(doc); + } + + // TODO: 29/04/17 ajm412: Data Validation here to return null if a tag somehow doesn't actually exist. + private static Integer getElementInt(Element ele, String tag) { + return Integer.parseInt(ele.getElementsByTagName(tag).item(0).getTextContent()); + } + + private static String getElementString(Element ele, String tag) { + return ele.getElementsByTagName(tag).item(0).getTextContent(); + } + + private static Double getElementDouble(Element ele, String tag) { + return Double.parseDouble(ele.getElementsByTagName(tag).item(0).getTextContent()); + } + + private static String getNodeAttributeString(Node n, String attr) { + return n.getAttributes().getNamedItem(attr).getTextContent(); + } + + private static Integer getNodeAttributeInt(Node n, String attr) { + return Integer.parseInt(n.getAttributes().getNamedItem(attr).getTextContent()); + } + + private static Double getNodeAttributeDouble(Node n, String attr) { + return Double.parseDouble(n.getAttributes().getNamedItem(attr).getTextContent()); + } + + class RegattaXMLObject { + + //Regatta Info + private Integer regattaID; + private String regattaName; + private String courseName; + private Double centralLat; + private Double centralLng; + private Integer utcOffset; + + RegattaXMLObject(Document doc) { + Element docEle = doc.getDocumentElement(); + + this.regattaID = getElementInt(docEle, "RegattaID"); + this.regattaName = getElementString(docEle, "RegattaName"); + this.courseName = getElementString(docEle, "CourseName"); + this.centralLat = getElementDouble(docEle, "CentralLatitude"); + this.centralLng = getElementDouble(docEle, "CentralLongitude"); + this.utcOffset = getElementInt(docEle, "UtcOffset"); + } + + public Integer getRegattaID() { return regattaID; } + public String getRegattaName() { return regattaName; } + public String getCourseName() { return courseName; } + public Double getCentralLat() { return centralLat; } + public Double getCentralLng() { return centralLng; } + public Integer getUtcOffset() { return utcOffset; } + + } + + class RaceXMLObject { + + // Race Info + Integer raceID; + String raceType; + String creationTimeDate; // XML Creation Time + + //Race Start Details + String raceStartTime; + Boolean postponeStatus; + + //Non atomic race attributes + ArrayList participants; + ArrayList course; + ArrayList compoundMarkSequence; + ArrayList courseLimit; + + RaceXMLObject(Document doc) { + Element docEle = doc.getDocumentElement(); + participants = new ArrayList<>(); + + NodeList pList = docEle.getElementsByTagName("Participants").item(0).getChildNodes(); + for (int i = 0; i < pList.getLength(); i++) { + Node pNode = pList.item(i); + String entry; + if (pNode.getNodeName().equals("Yacht")) { + Integer sourceID = getNodeAttributeInt(pNode, "SourceID"); + + if (pNode.getAttributes().getLength() == 2) { + entry = getNodeAttributeString(pNode, "Entry"); + } else { + entry = null; + } + + Participant pa = new Participant(sourceID, entry); + participants.add(pa); + } + } + + course = new ArrayList<>(); + + NodeList cMarkList = docEle.getElementsByTagName("Course").item(0).getChildNodes(); + for (int i = 0; i < cMarkList.getLength(); i++) { + Node cMarkNode = cMarkList.item(i); + if (cMarkNode.getNodeName().equals("CompoundMark")) { + CompoundMark cMark = new CompoundMark(cMarkNode); + course.add(cMark); + } + } + + compoundMarkSequence = new ArrayList<>(); + + NodeList cornerList = docEle.getElementsByTagName("CompoundMarkSequence").item(0).getChildNodes(); + for (int i = 0; i < cornerList.getLength(); i++) { + Node cornerNode = cornerList.item(i); + if (cornerNode.getNodeName().equals("Corner")) { + Corner corner = new Corner(cornerNode); + compoundMarkSequence.add(corner); + } + } + + courseLimit = new ArrayList<>(); + + NodeList limitList = docEle.getElementsByTagName("CourseLimit").item(0).getChildNodes(); + for (int i = 0; i < limitList.getLength(); i++) { + Node limitNode = limitList.item(i); + if (limitNode.getNodeName().equals("Limit")) { + Limit limit = new Limit(limitNode); + courseLimit.add(limit); + } + } + } + + public ArrayList getParticipants() { return participants; } + public ArrayList getCompoundMarks() { return course; } + public ArrayList getCompoundMarkSequence() { return compoundMarkSequence; } + public ArrayList getCourseLimit() { return courseLimit; } + + class Participant { + Integer sourceID; + String entry; + + Participant(Integer sourceID, String entry) { + this.sourceID = sourceID; + this.entry = entry; + } + + public Integer getsourceID() { return sourceID; } + public String getEntry() { return entry; } + } + + class CompoundMark { + private Integer markID; + private String cMarkName; + private ArrayList marks; + + CompoundMark(Node compoundMark) { + marks = new ArrayList<>(); + this.markID = getNodeAttributeInt(compoundMark, "CompoundMarkID"); + this.cMarkName = getNodeAttributeString(compoundMark, "Name"); + NodeList childMarks = compoundMark.getChildNodes(); + for (int i = 0; i < childMarks.getLength(); i++) { + Node markNode = childMarks.item(i); + if (markNode.getNodeName().equals("Mark")) { + Mark mark = new Mark(markNode); + marks.add(mark); + } + } + } + + public Integer getMarkID() { return markID; } + public String getcMarkName() { return cMarkName; } + public ArrayList getMarks() { return marks; } + + class Mark { + private Integer seqID; + private Integer sourceID; + private String markName; + private Double targetLat; + private Double targetLng; + + Mark(Node markNode) { + + this.seqID = getNodeAttributeInt(markNode, "SeqID"); + this.sourceID = getNodeAttributeInt(markNode, "SourceID"); + this.markName = getNodeAttributeString(markNode, "Name"); + this.targetLat = getNodeAttributeDouble(markNode, "TargetLat"); + this.targetLng = getNodeAttributeDouble(markNode, "TargetLng"); + + } + + public Integer getSeqID() { return seqID; } + public Integer getSourceID() { return sourceID; } + public String getMarkName() { return markName; } + public Double getTargetLat() { return targetLat; } + public Double getTargetLng() { return targetLng; } + } + } + + class Corner { + private Integer seqID; + private Integer compoundMarkID; + private String rounding; + private Integer zoneSize; + + Corner(Node cornerNode) { + this.seqID = getNodeAttributeInt(cornerNode, "SeqID"); + this.compoundMarkID = getNodeAttributeInt(cornerNode, "CompoundMarkID"); + this.rounding = getNodeAttributeString(cornerNode, "Rounding"); + this.zoneSize = getNodeAttributeInt(cornerNode, "ZoneSize"); + + } + + public Integer getSeqID() { return seqID; } + public Integer getCompoundMarkID() { return compoundMarkID; } + public String getRounding() { return rounding; } + public Integer getZoneSize() { return zoneSize; } + } + + class Limit { + private Integer seqID; + private Double lat; + private Double lng; + + Limit(Node limitNode) { + this.seqID = getNodeAttributeInt(limitNode, "SeqID"); + this.lat = getNodeAttributeDouble(limitNode, "Lat"); + this.lng = getNodeAttributeDouble(limitNode, "Lon"); + } + + public Integer getSeqID() { return seqID; } + public Double getLat() { return lat; } + public Double getLng() { return lng; } + } + + } + + class BoatXMLObject { + + private String lastModified; + private Integer version; + + //Settings for the boat type in the race. This may end up having to be reworked if multiple boat types compete. + private String boatType; + private Double boatLength; + private Double hullLength; + private Double markZoneSize; + private Double courseZoneSize; + private ArrayList zoneLimits;// will only contain 5 elements. Limits 1-5 + + //Boats + ArrayList boats; + + BoatXMLObject(Document doc) { + + Element docEle = doc.getDocumentElement(); + + this.lastModified = getElementString(docEle, "Modified"); + this.version = getElementInt(docEle, "Version"); + + NodeList settingsList = docEle.getElementsByTagName("Settings").item(0).getChildNodes(); + this.boatType = getNodeAttributeString(settingsList.item(1), "Type"); + this.boatLength = getNodeAttributeDouble(settingsList.item(3), "BoatLength"); + this.hullLength = getNodeAttributeDouble(settingsList.item(3), "HullLength"); + this.markZoneSize = getNodeAttributeDouble(settingsList.item(5), "MarkZoneSize"); + this.courseZoneSize = getNodeAttributeDouble(settingsList.item(5), "CourseZoneSize"); + + Node zoneLimitsList = settingsList.item(7); + this.zoneLimits = new ArrayList<>(); + for (int i = 0; i < zoneLimitsList.getAttributes().getLength(); i++) { + String tag = String.format("Limit%d", i+1); + this.zoneLimits.add(getNodeAttributeDouble(zoneLimitsList, tag)); + } + + } + + public String getLastModified() { return lastModified; } + public Integer getVersion() { return version; } + public String getBoatType() { return boatType; } + public Double getBoatLength() { return boatLength; } + public Double getHullLength() { return hullLength; } + public Double getMarkZoneSize() { return markZoneSize; } + public Double getCourseZoneSize() { return courseZoneSize; } + public ArrayList getZoneLimits() { return zoneLimits; } + public ArrayList getBoats() { return boats; } + + class Boat { + + private String boatType; + private Integer sourceID; + private String hullID; //matches HullNum in the XML spec. + private String shortName; + private String boatName; + private String country; + private String skipper; + + Boat(Node boatNode) { + // TODO: 29/04/17 Actually build the boats. + } + + public String getBoatType() { return boatType; } + public Integer getSourceID() { return sourceID; } + public String getHullID() { return hullID; } + public String getShortName() { return shortName; } + public String getBoatName() { return boatName; } + public String getCountry() { return country; } + public String getSkipper() { return skipper; } + + } + + } + +} \ No newline at end of file From 0b2ef3de0012724a35b7610e2bdc61919be4a877 Mon Sep 17 00:00:00 2001 From: alistairjmcintyre Date: Sun, 30 Apr 2017 00:52:18 +1200 Subject: [PATCH 6/7] XML data types are done. Easily navigated for future use. Some documentation has been done, tests aren't yet completed just yet. #story[820] --- .../seng302/models/parsers/StreamParser.java | 22 ++- .../seng302/models/parsers/XMLParser.java | 138 ++++++++++++++++-- 2 files changed, 131 insertions(+), 29 deletions(-) diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index d3520cf6..2971e6fd 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -2,9 +2,6 @@ package seng302.models.parsers; import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -14,7 +11,8 @@ import javax.xml.parsers.ParserConfigurationException; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.StringReader; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; /** * Created by kre39 on 23/04/17. @@ -110,9 +108,9 @@ public class StreamParser { } static void extractXmlMessage(StreamPacket packet){ - - byte[] payload = packet.getPayload(); - String xmlMessage = ""; + + byte[] payload = packet.getPayload(); //Raw Binary XML Message + String xmlMessage = ""; //Empty xmlMessage String to store XML in ByteArrayInputStream payloadStream = new ByteArrayInputStream(payload); @@ -129,21 +127,19 @@ public class StreamParser { while (payloadStream.available() > 0 && (currentChar = payloadStream.read()) != 0) { xmlMessage += (char)currentChar; } - if (xmlMessageSubType == 7) System.out.println(xmlMessage); //Create XML document Object DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); DocumentBuilder db = null; + Document doc = null; try { db = dbf.newDocumentBuilder(); - Document doc = db.parse(new InputSource(new StringReader(xmlMessage))); - if (xmlMessageSubType == 7) { - XMLParser x = new XMLParser(); - XMLParser.BoatXMLObject xr = x.createBoatXML(doc); - } + doc = db.parse(new InputSource(new StringReader(xmlMessage))); } catch (ParserConfigurationException|SAXException|IOException e) { e.printStackTrace(); } + // TODO: 30/04/2017 (ajm412) Figure out how this will tie into the backend of the visualiser now that the parsing is done. } private static void extractRaceStartStatus(StreamPacket packet){ diff --git a/src/main/java/seng302/models/parsers/XMLParser.java b/src/main/java/seng302/models/parsers/XMLParser.java index 03e1c3e2..aa9e3a46 100644 --- a/src/main/java/seng302/models/parsers/XMLParser.java +++ b/src/main/java/seng302/models/parsers/XMLParser.java @@ -1,57 +1,135 @@ package seng302.models.parsers; -import com.sun.org.apache.xpath.internal.SourceTree; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; +/** + * Class to create an XML object from the XML Packet Messages. + */ class XMLParser { + /** + * Creates a Regatta XML Object from the data in a Regatta XML Message + * @param doc XML Document Object + * @return A new RegattaXMLObject from the input Document. + */ RegattaXMLObject createRegattaXML(Document doc) { return new RegattaXMLObject(doc); } + /** + * Creates a Race XML Object from the data in a Regatta XML Message + * @param doc XML Document Object + * @return A new RaceXMLObject from the input Document. + */ RaceXMLObject createRaceXML(Document doc) { return new RaceXMLObject(doc); } + /** + * Creates a Boat XML Object from the data in a Regatta XML Message + * @param doc XML Document Object + * @return A new BoatXMLObject from the input Document. + */ BoatXMLObject createBoatXML(Document doc) { return new BoatXMLObject(doc); } - // TODO: 29/04/17 ajm412: Data Validation here to return null if a tag somehow doesn't actually exist. + /** + * Returns the text content of a given child element tag, assuming it exists, as an Integer. + * @param ele Document Element with child elements. + * @param tag Tag to find in document elements child elements. + * @return Text content from tag if found, null otherwise. + */ private static Integer getElementInt(Element ele, String tag) { - return Integer.parseInt(ele.getElementsByTagName(tag).item(0).getTextContent()); + NodeList tagList = ele.getElementsByTagName(tag); + if (tagList.getLength() > 0) { + return Integer.parseInt(tagList.item(0).getTextContent()); + } else { + return null; + } } + /** + * Returns the text content of a given child element tag, assuming it exists, as an String. + * @param ele Document Element with child elements. + * @param tag Tag to find in document elements child elements. + * @return Text content from tag if found, null otherwise. + */ private static String getElementString(Element ele, String tag) { - return ele.getElementsByTagName(tag).item(0).getTextContent(); + NodeList tagList = ele.getElementsByTagName(tag); + if (tagList.getLength() > 0) { + return tagList.item(0).getTextContent(); + } else { + return null; + } } + /** + * Returns the text content of a given child element tag, assuming it exists, as a Double. + * @param ele Document Element with child elements. + * @param tag Tag to find in document elements child elements. + * @return Text content from tag if found, null otherwise. + */ private static Double getElementDouble(Element ele, String tag) { - return Double.parseDouble(ele.getElementsByTagName(tag).item(0).getTextContent()); + NodeList tagList = ele.getElementsByTagName(tag); + if (tagList.getLength() > 0) { + return Double.parseDouble(tagList.item(0).getTextContent()); + } else { + return null; + } } + /** + * Returns the text content of an attribute of a given Node, assuming it exists, as a String. + * @param n A node object that should have some attributes + * @param attr The attribute you want to get from the given node. + * @return The String representation of the text content of an attribute in the given node, else returns null. + */ private static String getNodeAttributeString(Node n, String attr) { - return n.getAttributes().getNamedItem(attr).getTextContent(); + Node attrItem = n.getAttributes().getNamedItem(attr); + if (attrItem != null) { + return attrItem.getTextContent(); + } else { + return null; + } } + /** + * Returns the text content of an attribute of a given Node, assuming it exists, as an Integer. + * @param n A node object that should have some attributes + * @param attr The attribute you want to get from the given node. + * @return The Integer representation of the text content of an attribute in the given node, else returns null. + */ private static Integer getNodeAttributeInt(Node n, String attr) { - return Integer.parseInt(n.getAttributes().getNamedItem(attr).getTextContent()); + Node attrItem = n.getAttributes().getNamedItem(attr); + if (attrItem != null) { + return Integer.parseInt(attrItem.getTextContent()); + } else { + return null; + } } + /** + * Returns the text content of an attribute of a given Node, assuming it exists, as a Double. + * @param n A node object that should have some attributes + * @param attr The attribute you want to get from the given node. + * @return The Double representation of the text content of an attribute in the given node, else returns null. + */ private static Double getNodeAttributeDouble(Node n, String attr) { - return Double.parseDouble(n.getAttributes().getNamedItem(attr).getTextContent()); + Node attrItem = n.getAttributes().getNamedItem(attr); + if (attrItem != null) { + return Double.parseDouble(attrItem.getTextContent()); + } else { + return null; + } } class RegattaXMLObject { - //Regatta Info private Integer regattaID; private String regattaName; @@ -60,6 +138,11 @@ class XMLParser { private Double centralLng; private Integer utcOffset; + /** + * Constructor for a RegattaXMLObject. + * Takes the information from a Document object and creates a more usable format. + * @param doc XML Document Object + */ RegattaXMLObject(Document doc) { Element docEle = doc.getDocumentElement(); @@ -97,6 +180,11 @@ class XMLParser { ArrayList compoundMarkSequence; ArrayList courseLimit; + /** + * Constructor for a RaceXMLObject. + * Takes the information from a Document object and creates a more usable format. + * @param doc XML Document Object + */ RaceXMLObject(Document doc) { Element docEle = doc.getDocumentElement(); participants = new ArrayList<>(); @@ -230,7 +318,6 @@ class XMLParser { this.compoundMarkID = getNodeAttributeInt(cornerNode, "CompoundMarkID"); this.rounding = getNodeAttributeString(cornerNode, "Rounding"); this.zoneSize = getNodeAttributeInt(cornerNode, "ZoneSize"); - } public Integer getSeqID() { return seqID; } @@ -273,6 +360,11 @@ class XMLParser { //Boats ArrayList boats; + /** + * Constructor for a BoatXMLObject. + * Takes the information from a Document object and creates a more usable format. + * @param doc XML Document Object + */ BoatXMLObject(Document doc) { Element docEle = doc.getDocumentElement(); @@ -294,6 +386,17 @@ class XMLParser { this.zoneLimits.add(getNodeAttributeDouble(zoneLimitsList, tag)); } + this.boats = new ArrayList<>(); + NodeList boatsList = docEle.getElementsByTagName("Boats").item(0).getChildNodes(); + for (int i = 0; i < boatsList.getLength(); i++) { + Node currentBoat = boatsList.item(i); + if (currentBoat.getNodeName().equals("Boat")) { + Boat boat = new Boat(currentBoat); + this.boats.add(boat); + } + //System.out.println(this.getBoats()); + } + } public String getLastModified() { return lastModified; } @@ -314,10 +417,14 @@ class XMLParser { private String shortName; private String boatName; private String country; - private String skipper; Boat(Node boatNode) { - // TODO: 29/04/17 Actually build the boats. + this.boatType = getNodeAttributeString(boatNode, "Type"); + this.sourceID = getNodeAttributeInt(boatNode, "SourceID"); + this.hullID = getNodeAttributeString(boatNode, "HullNum"); + this.shortName = getNodeAttributeString(boatNode, "ShortName"); + this.boatName = getNodeAttributeString(boatNode, "BoatName"); + this.country = getNodeAttributeString(boatNode, "Country"); } public String getBoatType() { return boatType; } @@ -326,7 +433,6 @@ class XMLParser { public String getShortName() { return shortName; } public String getBoatName() { return boatName; } public String getCountry() { return country; } - public String getSkipper() { return skipper; } } From b597f010dc87ba6e0988a0e468063a92e1fc3872 Mon Sep 17 00:00:00 2001 From: alistairjmcintyre Date: Mon, 1 May 2017 00:36:10 +1200 Subject: [PATCH 7/7] Added some missing fields. Added missing getters. #story[820] --- .../seng302/models/parsers/StreamParser.java | 5 +++ .../seng302/models/parsers/XMLParser.java | 38 ++++++++++++++----- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index 2971e6fd..c4fe3349 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -136,6 +136,11 @@ public class StreamParser { try { db = dbf.newDocumentBuilder(); doc = db.parse(new InputSource(new StringReader(xmlMessage))); + if (xmlMessageSubType == 6) { + System.out.println(xmlMessage); + XMLParser x = new XMLParser(); + XMLParser.RaceXMLObject y = x.createRaceXML(doc); + } } catch (ParserConfigurationException|SAXException|IOException e) { e.printStackTrace(); } diff --git a/src/main/java/seng302/models/parsers/XMLParser.java b/src/main/java/seng302/models/parsers/XMLParser.java index aa9e3a46..ef65ea38 100644 --- a/src/main/java/seng302/models/parsers/XMLParser.java +++ b/src/main/java/seng302/models/parsers/XMLParser.java @@ -166,19 +166,19 @@ class XMLParser { class RaceXMLObject { // Race Info - Integer raceID; - String raceType; - String creationTimeDate; // XML Creation Time + private Integer raceID; + private String raceType; + private String creationTimeDate; // XML Creation Time //Race Start Details - String raceStartTime; - Boolean postponeStatus; + private String raceStartTime; + private Boolean postponeStatus; //Non atomic race attributes - ArrayList participants; - ArrayList course; - ArrayList compoundMarkSequence; - ArrayList courseLimit; + private ArrayList participants; + private ArrayList course; + private ArrayList compoundMarkSequence; + private ArrayList courseLimit; /** * Constructor for a RaceXMLObject. @@ -187,6 +187,17 @@ class XMLParser { */ RaceXMLObject(Document doc) { Element docEle = doc.getDocumentElement(); + + //Atomic and Semi-Atomic Elements + this.raceID = getElementInt(docEle, "RaceID"); + this.raceType = getElementString(docEle, "RaceType"); + this.creationTimeDate = getElementString(docEle, "CreationTimeDate"); + + Node raceStart = docEle.getElementsByTagName("RaceStartTime").item(0); + this.raceStartTime = getNodeAttributeString(raceStart, "Start") ; + this.postponeStatus = Boolean.parseBoolean(getNodeAttributeString(raceStart, "Postpone")); + + //Participants participants = new ArrayList<>(); NodeList pList = docEle.getElementsByTagName("Participants").item(0).getChildNodes(); @@ -207,6 +218,7 @@ class XMLParser { } } + //Course course = new ArrayList<>(); NodeList cMarkList = docEle.getElementsByTagName("Course").item(0).getChildNodes(); @@ -218,6 +230,7 @@ class XMLParser { } } + //Course Mark Sequence compoundMarkSequence = new ArrayList<>(); NodeList cornerList = docEle.getElementsByTagName("CompoundMarkSequence").item(0).getChildNodes(); @@ -229,6 +242,7 @@ class XMLParser { } } + //Course Limits courseLimit = new ArrayList<>(); NodeList limitList = docEle.getElementsByTagName("CourseLimit").item(0).getChildNodes(); @@ -241,6 +255,12 @@ class XMLParser { } } + public Integer getRaceID() { return raceID; } + public String getRaceType() { return raceType; } + public String getCreationTimeDate() { return creationTimeDate; } + public String getRaceStartTime() { return raceStartTime; } + public Boolean getPostponeStatus() { return postponeStatus; } + public ArrayList getParticipants() { return participants; } public ArrayList getCompoundMarks() { return course; } public ArrayList getCompoundMarkSequence() { return compoundMarkSequence; }