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