Refactored and moved XMLReader, RaceDataSource, BoatXMLReader, BoatDataSource, RegattaXMLReader to shared/dataInput.
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
package shared.dataInput;
|
||||
|
||||
|
||||
import shared.model.Boat;
|
||||
import shared.model.Mark;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Provides information about the boats and marker boats in a race.
|
||||
*/
|
||||
public interface BoatDataSource {
|
||||
|
||||
/**
|
||||
* Returns a map between source ID and boat for all boats in the race.
|
||||
* @return Map between source ID and boat.
|
||||
*/
|
||||
Map<Integer, Boat> getBoats();
|
||||
|
||||
/**
|
||||
* Returns a map between source ID and mark for all marks in the race.
|
||||
* @return Map between source ID and mark.
|
||||
*/
|
||||
Map<Integer, Mark> getMarkerBoats();
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package shared.dataInput;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import shared.exceptions.XMLReaderException;
|
||||
import shared.model.Boat;
|
||||
import shared.model.GPSCoordinate;
|
||||
import shared.model.Mark;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Xml Reader class for Boat XML used for the race.
|
||||
*/
|
||||
public class BoatXMLReader extends XMLReader implements BoatDataSource {
|
||||
|
||||
/**
|
||||
* A map of source ID to boat for all boats in the race.
|
||||
*/
|
||||
private final Map<Integer, Boat> boatMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* A map of source ID to mark for all marks in the race.
|
||||
*/
|
||||
private final Map<Integer, Mark> markerMap = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for Boat XML
|
||||
*
|
||||
* @param filePath Name/path of file to read. Read as a resource.
|
||||
* @throws XMLReaderException Thrown if the file cannot be parsed.
|
||||
*/
|
||||
public BoatXMLReader(String filePath) throws XMLReaderException {
|
||||
super(filePath);
|
||||
read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the XML
|
||||
*/
|
||||
public void read() {
|
||||
readSettings();
|
||||
readShapes();
|
||||
readBoats();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the Boats
|
||||
*/
|
||||
private void readBoats() {
|
||||
Element nBoats = (Element) doc.getElementsByTagName("Boats").item(0);
|
||||
for (int i = 0; i < nBoats.getChildNodes().getLength(); i++) {
|
||||
Node boat = nBoats.getChildNodes().item(i);
|
||||
if (boat.getNodeName().equals("Boat")) {
|
||||
readBoatNode(boat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignored data
|
||||
*/
|
||||
private void readShapes() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignored data
|
||||
*/
|
||||
private void readSettings() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the node (XMl data node) is a Yacht or not
|
||||
* @param boatNode Node from the XML
|
||||
* @return Whether the node is a yacht node or not
|
||||
*/
|
||||
private boolean isYachtNode(Node boatNode) {
|
||||
return boatNode.getAttributes().getNamedItem("Type").getTextContent().toLowerCase().equals("yacht");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the information about one boat
|
||||
* Ignored values: ShapeID, StoweName, HullNum, Skipper, Type
|
||||
*/
|
||||
private void readBoatNode(Node boatNode) {
|
||||
int sourceID = Integer.parseInt(boatNode.getAttributes().getNamedItem("SourceID").getTextContent());
|
||||
String name = boatNode.getAttributes().getNamedItem("BoatName").getTextContent();
|
||||
|
||||
if (isYachtNode(boatNode)) readYacht(boatNode, sourceID, name);
|
||||
else readMark(boatNode, sourceID, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a Yacht Node
|
||||
* @param boatNode Node to be read
|
||||
* @param sourceID Source ID of the Yacht
|
||||
* @param name Name of the Boat
|
||||
*/
|
||||
private void readYacht(Node boatNode, int sourceID, String name) {
|
||||
String shortName = boatNode.getAttributes().getNamedItem("ShortName").getTextContent();
|
||||
if (exists(boatNode, "Country")) {
|
||||
String country = boatNode.getAttributes().getNamedItem("Country").getTextContent();
|
||||
boatMap.put(sourceID, new Boat(sourceID, name, country));
|
||||
} else {
|
||||
boatMap.put(sourceID, new Boat(sourceID, name, shortName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read Marker Boats
|
||||
* @param boatNode Node to be read
|
||||
* @param sourceID Source ID of the boat
|
||||
* @param name Name of the Marker Boat
|
||||
*/
|
||||
private void readMark(Node boatNode, int sourceID, String name) {
|
||||
Node nCoord = ((Element)boatNode).getElementsByTagName("GPSposition").item(0);
|
||||
double x = Double.parseDouble(nCoord.getAttributes().getNamedItem("X").getTextContent());
|
||||
double y = Double.parseDouble(nCoord.getAttributes().getNamedItem("Y").getTextContent());
|
||||
Mark mark = new Mark(sourceID, name, new GPSCoordinate(y,x));
|
||||
markerMap.put(sourceID, mark);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the boats that are going to participate in this race
|
||||
* @return Dictionary of boats that are to participate in this race indexed by SourceID
|
||||
*/
|
||||
@Override
|
||||
public Map<Integer, Boat> getBoats() {
|
||||
return boatMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the marker BOats that are participating in this race
|
||||
* @return Dictionary of the Markers BOats that are in this race indexed by their Source ID.
|
||||
*/
|
||||
@Override
|
||||
public Map<Integer, Mark> getMarkerBoats() {
|
||||
return markerMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package shared.dataInput;
|
||||
|
||||
import network.Messages.Enums.RaceTypeEnum;
|
||||
import shared.model.Boat;
|
||||
import shared.model.CompoundMark;
|
||||
import shared.model.GPSCoordinate;
|
||||
import shared.model.Leg;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An object that holds relevant data for a race. <br>
|
||||
* Information includes: {@link shared.model.Boat Boat}s,
|
||||
* {@link shared.model.Leg Leg}s, {@link shared.model.CompoundMark CompoundMark}s and
|
||||
* the {@link shared.model.GPSCoordinate GPSCoordinate}s.
|
||||
*/
|
||||
public interface RaceDataSource {
|
||||
/**
|
||||
* Returns the list of boats competing in the race.
|
||||
* @return Boats competing in the race.
|
||||
*/
|
||||
List<Boat> getBoats();
|
||||
|
||||
/**
|
||||
* Returns the list of legs in the race.
|
||||
* @return The list of legs in the race.
|
||||
*/
|
||||
List<Leg> getLegs();
|
||||
|
||||
/**
|
||||
* Returns a list of coordinates representing the boundary of the race.
|
||||
* @return The boundary of the race.
|
||||
*/
|
||||
List<GPSCoordinate> getBoundary();
|
||||
|
||||
/**
|
||||
* Returns a list of CompoundMarks in the race.
|
||||
* @return
|
||||
*/
|
||||
List<CompoundMark> getCompoundMarks();
|
||||
|
||||
/**
|
||||
* Returns the ID of the race.
|
||||
* @return The ID of the race.
|
||||
*/
|
||||
int getRaceId();
|
||||
|
||||
/**
|
||||
* Returns the type of race.
|
||||
* @return The type of race.
|
||||
*/
|
||||
RaceTypeEnum getRaceType();
|
||||
|
||||
/**
|
||||
* Returns the start time/date of the race.
|
||||
* @return The race's start time.
|
||||
*/
|
||||
ZonedDateTime getZonedDateTime();
|
||||
|
||||
/**
|
||||
* Returns the GPS coordinate of the top left of the race map area.
|
||||
* @return Top left GPS coordinate.
|
||||
*/
|
||||
GPSCoordinate getMapTopLeft();
|
||||
|
||||
/**
|
||||
* Returns the GPS coordinate of the bottom right of the race map area.
|
||||
* @return Bottom right GPS coordinate.
|
||||
*/
|
||||
GPSCoordinate getMapBottomRight();
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
package shared.dataInput;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
import shared.dataInput.XMLReader;
|
||||
import shared.exceptions.XMLReaderException;
|
||||
import shared.model.GPSCoordinate;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* XML reader class for regatta xml file.
|
||||
*/
|
||||
public class RegattaXMLReader extends XMLReader {
|
||||
/**
|
||||
* The regatta ID.
|
||||
*/
|
||||
private int regattaID;
|
||||
|
||||
/**
|
||||
* The regatta name.
|
||||
*/
|
||||
private String regattaName;
|
||||
|
||||
/**
|
||||
* The race ID.
|
||||
*/
|
||||
private int raceID = 0;
|
||||
|
||||
/**
|
||||
* The course name.
|
||||
*/
|
||||
private String courseName;
|
||||
|
||||
/**
|
||||
* The central latitude of the course.
|
||||
*/
|
||||
private double centralLatitude;
|
||||
|
||||
/**
|
||||
* The central longitude of the course.
|
||||
*/
|
||||
private double centralLongitude;
|
||||
|
||||
/**
|
||||
* The central altitude of the course.
|
||||
*/
|
||||
private double centralAltitude;
|
||||
|
||||
/**
|
||||
* The UTC offset of the course.
|
||||
*/
|
||||
private float utcOffset;
|
||||
|
||||
/**
|
||||
* The magnetic variation of the course.
|
||||
*/
|
||||
private float magneticVariation;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for Regatta XML
|
||||
*
|
||||
* @param filePath path of the file to read. Read as a resource.
|
||||
* @throws XMLReaderException Thrown if the file cannot be parsed.
|
||||
*/
|
||||
public RegattaXMLReader(String filePath) throws XMLReaderException {
|
||||
super(filePath);
|
||||
read();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Alternate Constructor that takes in an inputstream instead
|
||||
* @param xmlString Input stream of the XML
|
||||
* @throws XMLReaderException Thrown if the input stream cannot be parsed.
|
||||
*/
|
||||
public RegattaXMLReader(InputStream xmlString) throws XMLReaderException {
|
||||
super(xmlString);
|
||||
read();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read the XML
|
||||
*/
|
||||
private void read() {
|
||||
NodeList attributeConfig = doc.getElementsByTagName("RegattaConfig");
|
||||
Element attributes = (Element) attributeConfig.item(0);
|
||||
makeRegatta(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the information from the attributes
|
||||
* @param attributes attributes to extract information form.
|
||||
*/
|
||||
private void makeRegatta(Element attributes) {
|
||||
|
||||
this.regattaID = Integer.parseInt(getTextValueOfNode(attributes, "RegattaID"));
|
||||
this.regattaName = getTextValueOfNode(attributes, "RegattaName");
|
||||
this.courseName = getTextValueOfNode(attributes, "CourseName");
|
||||
|
||||
this.centralLatitude = Double.parseDouble(getTextValueOfNode(attributes, "CentralLatitude"));
|
||||
this.centralLongitude = Double.parseDouble(getTextValueOfNode(attributes, "CentralLongitude"));
|
||||
this.centralAltitude = Double.parseDouble(getTextValueOfNode(attributes, "CentralAltitude"));
|
||||
|
||||
this.utcOffset = Float.parseFloat(getTextValueOfNode(attributes, "UtcOffset"));
|
||||
|
||||
this.magneticVariation = Float.parseFloat(getTextValueOfNode(attributes, "MagneticVariation"));
|
||||
|
||||
}
|
||||
|
||||
public int getRegattaID() {
|
||||
return regattaID;
|
||||
}
|
||||
|
||||
public void setRegattaID(int ID) {
|
||||
this.regattaID = ID;
|
||||
}
|
||||
|
||||
public String getRegattaName() {
|
||||
return regattaName;
|
||||
}
|
||||
|
||||
public void setRegattaName(String regattaName) {
|
||||
this.regattaName = regattaName;
|
||||
}
|
||||
|
||||
public int getRaceID() {
|
||||
return raceID;
|
||||
}
|
||||
|
||||
public void setRaceID(int raceID) {
|
||||
this.raceID = raceID;
|
||||
}
|
||||
|
||||
public String getCourseName() {
|
||||
return courseName;
|
||||
}
|
||||
|
||||
public void setCourseName(String courseName) {
|
||||
this.courseName = courseName;
|
||||
}
|
||||
|
||||
public double getCentralLatitude() {
|
||||
return centralLatitude;
|
||||
}
|
||||
|
||||
public void setCentralLatitude(double centralLatitude) {
|
||||
this.centralLatitude = centralLatitude;
|
||||
}
|
||||
|
||||
public double getCentralLongitude() {
|
||||
return centralLongitude;
|
||||
}
|
||||
|
||||
public void setCentralLongitude(double centralLongitude) {
|
||||
this.centralLongitude = centralLongitude;
|
||||
}
|
||||
|
||||
public double getCentralAltitude() {
|
||||
return centralAltitude;
|
||||
}
|
||||
|
||||
public void setCentralAltitude(double centralAltitude) {
|
||||
this.centralAltitude = centralAltitude;
|
||||
}
|
||||
|
||||
public float getUtcOffset() {
|
||||
return utcOffset;
|
||||
}
|
||||
|
||||
public void setUtcOffset(float utcOffset) {
|
||||
this.utcOffset = utcOffset;
|
||||
}
|
||||
|
||||
public float getMagneticVariation() {
|
||||
return magneticVariation;
|
||||
}
|
||||
|
||||
public void setMagneticVariation(float magneticVariation) {
|
||||
this.magneticVariation = magneticVariation;
|
||||
}
|
||||
|
||||
public GPSCoordinate getGPSCoordinate() {
|
||||
return new GPSCoordinate(centralLatitude, centralLongitude);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package shared.dataInput;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.SAXException;
|
||||
import shared.exceptions.XMLReaderException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* Base Reader for XML Files
|
||||
*/
|
||||
public abstract class XMLReader {
|
||||
|
||||
protected Document doc;
|
||||
|
||||
/**
|
||||
* Read an XML file by name as a resource.
|
||||
* @param filePath filepath for XML file. Loaded as a resource.
|
||||
* @throws XMLReaderException Thrown if the file cannot be parsed.
|
||||
*/
|
||||
public XMLReader(String filePath) throws XMLReaderException {
|
||||
|
||||
//Read file as resource.
|
||||
InputStream xmlInputStream = getClass().getClassLoader().getResourceAsStream(filePath);
|
||||
|
||||
this.doc = parseInputStream(xmlInputStream);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an XML file from an input stream.
|
||||
* @param xmlInputStream The input stream to parse.
|
||||
* @throws XMLReaderException Thrown if the input stream cannot be parsed.
|
||||
*/
|
||||
public XMLReader(InputStream xmlInputStream) throws XMLReaderException {
|
||||
|
||||
this.doc = parseInputStream(xmlInputStream);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses an input stream into a document.
|
||||
* @param inputStream The xml input stream to parse.
|
||||
* @return The parsed document.
|
||||
* @throws XMLReaderException Thrown when a document builder cannot be constructed, or the stream cannot be parsed.
|
||||
*/
|
||||
private Document parseInputStream(InputStream inputStream) throws XMLReaderException {
|
||||
|
||||
//Create document builder.
|
||||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
||||
|
||||
DocumentBuilder dBuilder = null;
|
||||
try {
|
||||
dBuilder = dbFactory.newDocumentBuilder();
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new XMLReaderException("Could not create a DocumentBuilder.", e);
|
||||
}
|
||||
|
||||
//Parse document.
|
||||
Document document = null;
|
||||
try {
|
||||
document = dBuilder.parse(inputStream);
|
||||
} catch (SAXException | IOException e) {
|
||||
throw new XMLReaderException("Could not parse the xml input stream.", e);
|
||||
}
|
||||
document.getDocumentElement().normalize();
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return Document data of the read-in XML
|
||||
* @return XML document
|
||||
*/
|
||||
public Document getDocument() {
|
||||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content of a tag in an element
|
||||
* @param n Element to read tags from
|
||||
* @param tagName Name of the tag
|
||||
* @return Content of the tag
|
||||
*/
|
||||
public String getTextValueOfNode(Element n, String tagName) {
|
||||
return n.getElementsByTagName(tagName).item(0).getTextContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attributes for an element
|
||||
* @param n Element to read attributes from
|
||||
* @param attr Attributes of element
|
||||
* @return Attributes of element
|
||||
*/
|
||||
public String getAttribute(Element n, String attr) {
|
||||
return n.getAttribute(attr);
|
||||
}
|
||||
|
||||
protected boolean exists(Node node, String attribute) {
|
||||
return node.getAttributes().getNamedItem(attribute) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of the XML FILe.
|
||||
* @param document holds all xml information
|
||||
* @return String representation of document
|
||||
* @throws TransformerException when document is malformed, and cannot be turned into a string
|
||||
*/
|
||||
public static String getContents(Document document) throws TransformerException {
|
||||
DOMSource source = new DOMSource(document);
|
||||
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
|
||||
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
StreamResult result = new StreamResult(stringWriter);
|
||||
transformer.transform(source, result);
|
||||
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package shared.exceptions;
|
||||
|
||||
/**
|
||||
* An exception thrown when an XMLReader cannot be constructed for some reason.
|
||||
*/
|
||||
public class XMLReaderException extends Exception {
|
||||
|
||||
public XMLReaderException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public XMLReaderException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user