Renamed project to xmlexport as this matches the purpose better

This commit is contained in:
Simon Pamies committed 2014-01-02 12:43:34 +02:00
1 parent 16103ce777
commit 6d56eeb43d
14 files changed
+9 -9

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="lib" path="lib/jdom.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
@@ -0,0 +1 @@
bin
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.sap.sailing.xmlexport</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
@@ -0,0 +1,8 @@
#Thu Jan 19 09:59:32 CET 2012
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.7
@@ -0,0 +1,4 @@
#Wed Oct 05 23:23:07 CEST 2011
eclipse.preferences.version=1
pluginProject.extensions=false
resolve.requirebundle=false
+19
View File
@@ -0,0 +1,19 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Leaderboard XML Export
Bundle-SymbolicName: com.sap.sailing.xmlexport
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: javax.servlet;version="2.6.0",
javax.servlet.http;version="2.6.0",
org.osgi.framework;version="1.6.0"
Bundle-ActivationPolicy: lazy
Require-Bundle: com.sap.sailing.server,
com.sap.sailing.server.gateway,
com.sap.sailing.domain,
com.sap.sailing.domain.tractracadapter,
com.sap.sailing.domain.common
Bundle-ClassPath: lib/jdom.jar,
.
Web-ContextPath: /export
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<servlet>
<servlet-name>XmlExportServlet</servlet-name>
<servlet-class>com.sap.sailing.xmlexport.XmlExportServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>XmlExportServlet</servlet-name>
<url-pattern>/xml</url-pattern>
</servlet-mapping>
</web-app>
+6
View File
@@ -0,0 +1,6 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
lib/jdom.jar,\
WEB-INF/
Binary file not shown.
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>root</artifactId>
<groupId>com.sap.sailing</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>com.sap.sailing.xmlexport</artifactId>
<packaging>eclipse-plugin</packaging>
</project>
@@ -0,0 +1,312 @@
package com.sap.sailing.xmlexport;
import java.io.IOException;
import java.util.NavigableSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
public abstract class ExportAction {
private HttpServletRequest req;
private HttpServletResponse res;
private RacingEventService service;
public ExportAction(HttpServletRequest req, HttpServletResponse res, RacingEventService service) {
this.req = req;
this.res = res;
this.service = service;
}
public String getAttribute(String name) {
return this.req.getParameter(name);
}
public RacingEventService getService() {
return service;
}
public Leaderboard getLeaderboard() throws IOException, ServletException {
final String leaderboardName = getAttribute("name");
if (leaderboardName == null) {
throw new ServletException("Use the name= parameter to specify the leaderboard");
}
final Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
if (leaderboard == null) {
throw new ServletException("Leaderboard " + leaderboardName + " not found.");
}
return leaderboard;
}
protected String cleanRaceName(String raceName) {
String newRaceName = raceName;
if (raceName.matches("[A-Za-z ]*\\d")) {
Pattern regex = Pattern.compile("([A-Za-z ]*)(\\d)");
Matcher matcher = regex.matcher(raceName);
String raceNameFirstPart = matcher.replaceAll("$1");
String raceNumber = matcher.replaceAll("$2");
try {
if (Integer.parseInt(raceNumber) < 10) {
raceNumber = "0" + raceNumber;
newRaceName = raceNameFirstPart + raceNumber;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return newRaceName;
}
public Long getTotalTimeSailedInMilliseconds(final Competitor competitor, final TimePoint timePoint, boolean alsoReturnTimeIfCompetitorHasNotFinishedRace) throws IOException, ServletException {
Long result = null;
for (TrackedRace trackedRace : getLeaderboard().getTrackedRaces()) {
if (Util.contains(trackedRace.getRace().getCompetitors(), competitor)) {
NavigableSet<MarkPassing> markPassings = trackedRace.getMarkPassings(competitor);
if (!markPassings.isEmpty()) {
TimePoint from = trackedRace.getStartOfRace(); // start counting at race start, not when the competitor passed the line
if (from != null && !timePoint.before(from)) { // but only if the race started after timePoint
TimePoint to;
if (timePoint.after(markPassings.last().getTimePoint())
&& markPassings.last().getWaypoint() == trackedRace.getRace().getCourse()
.getLastWaypoint()) {
// stop counting when competitor finished the race
to = markPassings.last().getTimePoint();
} else {
// in contrary to AbstractSimpleLeaderboardImpl#getTotalTimeSailedInMilliseconds
// this method will not return null if a competitor did not finish the race but
// will return all data until here
if (!alsoReturnTimeIfCompetitorHasNotFinishedRace) {
if (trackedRace.getEndOfTracking() != null
&& timePoint.after(trackedRace.getEndOfTracking())) {
result = null; // race not finished until end of tracking; no reasonable value can be
// computed for competitor
break;
} else {
to = timePoint;
}
} else {
// count until last mark passing - we can not find
// any time point later than that because the competitor
// could have sailed away from the race course
to = markPassings.last().getTimePoint();
}
}
long timeSpent = to.asMillis() - from.asMillis();
if (result == null) {
result = timeSpent;
} else {
result += timeSpent;
}
}
}
}
}
return result;
}
public Distance getDistanceTraveled(TrackedRace trackedRace, Competitor competitor, TimePoint timePoint, boolean alsoReturnDistanceIfCompetitorHasNotFinishedRace) {
NavigableSet<MarkPassing> markPassings = trackedRace.getMarkPassings(competitor);
if (markPassings.isEmpty()) {
return null;
} else {
TimePoint end = timePoint;
if (markPassings.last().getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint()
&& timePoint.compareTo(markPassings.last().getTimePoint()) > 0) {
// competitor has finished race; use time point of crossing the finish line
end = markPassings.last().getTimePoint();
} else {
if (markPassings.last().getWaypoint() != trackedRace.getRace().getCourse().getLastWaypoint() &&
alsoReturnDistanceIfCompetitorHasNotFinishedRace) {
end = markPassings.last().getTimePoint();
}
}
return trackedRace.getTrack(competitor).getDistanceTraveled(markPassings.first().getTimePoint(), end);
}
}
public Distance getTotalDistanceTraveled(Leaderboard leaderboard, Competitor competitor, TimePoint timePoint) {
Distance result = null;
for (TrackedRace trackedRace : leaderboard.getTrackedRaces()) {
if (Util.contains(trackedRace.getRace().getCompetitors(), competitor)) {
Distance distanceSailedInRace = getDistanceTraveled(trackedRace, competitor, timePoint, true);
if (distanceSailedInRace != null) {
if (result == null) {
result = distanceSailedInRace;
} else {
result = result.add(distanceSailedInRace);
}
}
}
}
return result;
}
public Speed getAverageSpeedOverGround(Leaderboard leaderboard, Competitor competitor, TimePoint timePoint, boolean alsoIncludeNonFinishedRaces) {
Speed result = null;
for (TrackedRace trackedRace : leaderboard.getTrackedRaces()) {
if (Util.contains(trackedRace.getRace().getCompetitors(), competitor)) {
NavigableSet<MarkPassing> markPassings = trackedRace.getMarkPassings(competitor);
if (!markPassings.isEmpty()) {
TimePoint from = markPassings.first().getTimePoint();
TimePoint to;
if (timePoint.after(markPassings.last().getTimePoint()) &&
markPassings.last().getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint()) {
// stop counting when competitor finished the race
to = markPassings.last().getTimePoint();
} else {
if (markPassings.last().getWaypoint() != trackedRace.getRace().getCourse().getLastWaypoint() &&
timePoint.after(markPassings.last().getTimePoint()) &&
!alsoIncludeNonFinishedRaces) {
result = null;
break;
}
to = timePoint;
}
Distance distanceTraveled = trackedRace.getDistanceTraveled(competitor, timePoint);
if (distanceTraveled != null) {
result = distanceTraveled.inTime(to.asMillis()-from.asMillis());
}
}
}
}
return result;
}
protected String cleanSailId(String sailId, Competitor competitor) {
if (sailId.matches("^[A-Z]{3}\\s[0-9]*")) {
Pattern regex = Pattern.compile("(^[A-Z]{3})\\s([0-9]*)");
Matcher regexMatcher = regex.matcher(sailId);
try {
return regexMatcher.replaceAll("$1$2");
} catch (Exception e) {
e.printStackTrace();
}
} else if (sailId.matches("^[A-Z]{3}\\S[0-9]*")) {
return sailId;
} else if (sailId.matches("[0-9]*")){
Nationality nationality = competitor.getTeam().getNationality();
return (nationality==null ? "" : nationality.getThreeLetterIOCAcronym() + sailId);
}
return sailId;
}
public void sendDocument(Element element, String fileName) {
final Format format = Format.getPrettyFormat();
format.setIndent(" ");
format.setExpandEmptyElements(true);
format.setEncoding("UTF-8");
XMLOutputter xmlOutputter = new XMLOutputter(format);
res.setContentType("text/xml");
res.addHeader("Content-Disposition", "attachment; filename=" + fileName);
try {
xmlOutputter.output(element, res.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
protected long handleValue(TimePoint timepoint) {
if (timepoint != null) {
return timepoint.asMillis();
}
return 0;
}
protected String getBoatClassName(final Leaderboard leaderboard) {
String result = null;
if (leaderboard instanceof RegattaLeaderboard) {
result = ((RegattaLeaderboard) leaderboard).getRegatta().getBoatClass().getName();
} else {
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
for (Fleet fleet : raceColumn.getFleets()) {
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
if (trackedRace != null) {
result = trackedRace.getRace().getBoatClass().getName();
break;
}
}
}
}
return result;
}
protected void addNamedElementWithValue(Element parent, String newChildName, Integer i) {
if (i == null) {
addNamedElementWithValue(parent, newChildName, "0");
} else {
addNamedElementWithValue(parent, newChildName, i.toString());
}
}
protected void addNamedElementWithValue(Element parent, String newChildName, Double dbl) {
if (dbl == null) {
addNamedElementWithValue(parent, newChildName, "0");
} else {
addNamedElementWithValue(parent, newChildName, dbl.toString());
}
}
protected void addNamedElementWithValue(Element parent, String newChildName, Long l) {
if (l == null) {
addNamedElementWithValue(parent, newChildName, "0");
} else {
addNamedElementWithValue(parent, newChildName, l.toString());
}
}
protected Element addNamedElementWithValue(Element parent, String newChildName, String value) {
final Element newChild = new Element(newChildName);
newChild.addContent(value);
parent.addContent(newChild);
return newChild;
}
protected Element createNamedElementWithValue(String elementName, String value) {
final Element element = new Element(elementName);
element.addContent(value);
return element;
}
protected Element createNamedElementWithValue(String elementName, int value) {
final Element element = new Element(elementName);
element.addContent(String.valueOf(value));
return element;
}
protected Element createNamedElementWithValue(String elementName, double value) {
final Element element = new Element(elementName);
element.addContent(String.valueOf(value));
return element;
}
protected Element createNamedElementWithValue(String elementName, long value) {
final Element element = new Element(elementName);
element.addContent(String.valueOf(value));
return element;
}
}
@@ -0,0 +1,506 @@
package com.sap.sailing.xmlexport;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.Callable;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jdom.Element;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.impl.SpeedWithConfidenceImpl;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.LineLengthAndAdvantage;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
/**
* Exports all data from a leaderboard into XML format. Format is as follows:
*
* <pre>
* <leaderboard>
* <name>XY</name>
* <competitor>
* <uuid>1234</uuid>
* <sail_id></sail_id>
* </competitor>
*
* <race>
* <name>R1</name>
* <competitor>
* <uuid>1234</uuid>
* <race_final_rank>1</race_final_rank>
* <race_final_score>10</race_final_score>
* </competitor>
* <leg>
* <count>1</count>
* <competitor>
* <uuid>1234</uuid>
* <number_of_jibes>123</number_of_jibes>
* </competitor>
* </leg>
* </race>
* </leaderboard>
* </pre>
*
* @author Simon Marcel Pamies
*/
public class LeaderboardData extends ExportAction {
private static final String VERY_LIGHT_WIND_DESCRIPTION = "Very Light";
private static final String LIGHT_WIND_DESCRIPTION = "Light";
private static final String MEDIUM_WIND_DESCRIPTION = "Medium";
private static final String STRONG_WIND_DESCRIPTION = "Strong";
private static final String VERY_STRONG_WIND_DESCRIPTION = "Very Strong";
public LeaderboardData(HttpServletRequest req, HttpServletResponse res, RacingEventService service) {
super(req, res, service);
}
private Element createLeaderboardXML(Leaderboard leaderboard, List<Element> competitors, List<Element> races, Pair<Double, Vector<String>> leaderboardConfidenceAndErrorMessages) {
Element leaderboardElement = new Element("leaderboard");
addNamedElementWithValue(leaderboardElement, "name", leaderboard.getName());
addNamedElementWithValue(leaderboardElement, "display_name", leaderboard.getDisplayName());
addNamedElementWithValue(leaderboardElement, "delay_to_live_in_millis", leaderboard.getDelayToLiveInMillis());
addNamedElementWithValue(leaderboardElement, "scoring_scheme", leaderboard.getScoringScheme().getType().name());
addNamedElementWithValue(leaderboardElement, "boat_class", getBoatClassName(leaderboard));
leaderboardElement.addContent(createTimedXML("last_modification_", leaderboard.getTimePointOfLatestModification()));
leaderboardElement.addContent(createDataConfidenceXML(leaderboardConfidenceAndErrorMessages));
leaderboardElement.addContent(competitors);
leaderboardElement.addContent(races);
return leaderboardElement;
}
private List<Element> createTimedXML(String prefix, TimePoint timepoint) {
List<Element> timedElements = new ArrayList<Element>();
Calendar timedDate = Calendar.getInstance();
if (timepoint != null) {
timedDate.setTime(timepoint.asDate());
timedElements.add(createNamedElementWithValue(prefix+"year", timedDate.get(Calendar.YEAR)));
timedElements.add(createNamedElementWithValue(prefix+"month", timedDate.get(Calendar.MONTH)));
timedElements.add(createNamedElementWithValue(prefix+"day", timedDate.get(Calendar.DAY_OF_MONTH)));
timedElements.add(createNamedElementWithValue(prefix+"hour", timedDate.get(Calendar.HOUR_OF_DAY)));
timedElements.add(createNamedElementWithValue(prefix+"minute", timedDate.get(Calendar.MINUTE)));
timedElements.add(createNamedElementWithValue(prefix+"second", timedDate.get(Calendar.SECOND)));
SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
timedElements.add(createNamedElementWithValue(prefix+"formatted", dateFormatter.format(timedDate.getTime())));
timedElements.add(createNamedElementWithValue(prefix+"millis_since_epoch", timepoint.asMillis()));
} else {
timedElements.add(createNamedElementWithValue(prefix+"year", ""));
timedElements.add(createNamedElementWithValue(prefix+"month", ""));
timedElements.add(createNamedElementWithValue(prefix+"day", ""));
timedElements.add(createNamedElementWithValue(prefix+"hour", ""));
timedElements.add(createNamedElementWithValue(prefix+"minute", ""));
timedElements.add(createNamedElementWithValue(prefix+"second", ""));
timedElements.add(createNamedElementWithValue(prefix+"formatted", ""));
timedElements.add(createNamedElementWithValue(prefix+"millis_since_epoch", ""));
}
return timedElements;
}
public List<Element> createWindXML(String prefix, SpeedWithConfidence<TimePoint> speedWithConfidence) {
List<Element> windElements = new ArrayList<Element>();
if (speedWithConfidence == null) {
speedWithConfidence = new SpeedWithConfidenceImpl<TimePoint>(new KnotSpeedImpl(0.0), 0, MillisecondsTimePoint.now());
}
windElements.add(createNamedElementWithValue(prefix+"speed_in_knots", speedWithConfidence.getObject().getKnots()));
windElements.add(createNamedElementWithValue(prefix+"speed_in_meters_per_second", speedWithConfidence.getObject().getMetersPerSecond()));
windElements.add(createNamedElementWithValue(prefix+"speed_in_beaufort", speedWithConfidence.getObject().getBeaufort()));
windElements.add(createNamedElementWithValue(prefix+"confidence", speedWithConfidence.getConfidence()));
double speedInKnots = speedWithConfidence.getObject().getKnots();
String windSpeedAsHumanReadableString = "";
String windSpeedAsInterval = "";
if (speedInKnots <= 4) {
windSpeedAsHumanReadableString = VERY_LIGHT_WIND_DESCRIPTION;
windSpeedAsInterval = "0-4kn";
} else if (speedInKnots > 4 && speedInKnots <= 8) {
windSpeedAsHumanReadableString = LIGHT_WIND_DESCRIPTION;
windSpeedAsInterval = "4-8kn";
} else if (speedInKnots > 8 && speedInKnots <= 14) {
windSpeedAsHumanReadableString = MEDIUM_WIND_DESCRIPTION;
windSpeedAsInterval = "8-14kn";
} else if (speedInKnots > 14 && speedInKnots <= 20) {
windSpeedAsHumanReadableString = STRONG_WIND_DESCRIPTION;
windSpeedAsInterval = "14-20kn";
} else if (speedInKnots > 20) {
windSpeedAsHumanReadableString = VERY_STRONG_WIND_DESCRIPTION;
windSpeedAsInterval = "20-"+speedInKnots+"kn";
}
windElements.add(createNamedElementWithValue(prefix+"human_readable", windSpeedAsHumanReadableString));
windElements.add(createNamedElementWithValue(prefix+"knots_interval", windSpeedAsInterval));
return windElements;
}
private Element createRaceXML(TrackedRace race, Fleet fleet, List<Element> legs, RaceColumn column, Leaderboard leaderboard, int sameDayGroupIndex, int raceCounter, Pair<Double, Vector<String>> raceConfidenceAndErrorMessages) throws NoWindException, IOException, ServletException {
Element raceElement = new Element("race");
addNamedElementWithValue(raceElement, "name", cleanRaceName(race.getRace().getName()));
addNamedElementWithValue(raceElement, "race_index_in_leaderboard", raceCounter);
addNamedElementWithValue(raceElement, "fleet_name", fleet.getName());
addNamedElementWithValue(raceElement, "same_day_index", sameDayGroupIndex);
raceElement.addContent(createDataConfidenceXML(raceConfidenceAndErrorMessages));
addNamedElementWithValue(raceElement, "delay_to_live_in_millis", race.getDelayToLiveInMillis());
addNamedElementWithValue(raceElement, "timepoint_of_last_event_as_millis", handleValue(race.getTimePointOfLastEvent()));
addNamedElementWithValue(raceElement, "timepoint_of_newest_event_as_millis", handleValue(race.getTimePointOfNewestEvent()));
addNamedElementWithValue(raceElement, "timepoint_of_oldest_event_as_millis", handleValue(race.getTimePointOfOldestEvent()));
raceElement.addContent(createTimedXML("start_time_", race.getStartOfRace()));
raceElement.addContent(createTimedXML("end_time_", race.getEndOfRace()));
addNamedElementWithValue(raceElement, "start_of_tracking_time_as_millis", handleValue(race.getStartOfTracking()));
addNamedElementWithValue(raceElement, "end_of_tracking_time_as_millis", handleValue(race.getEndOfTracking()));
addNamedElementWithValue(raceElement, "course_length_in_meters", race.getCourseLength().getMeters());
raceElement.addContent(createWindXML("wind_", race.getAverageWindSpeedWithConfidence(/*resolutionInMillis*/ 5*60*1000)));
final List<Competitor> allCompetitors = race.getCompetitorsFromBestToWorst(/*timePoint*/ race.getEndOfRace());
addNamedElementWithValue(raceElement, "race_participant_count", allCompetitors.size());
int raceRank = 0;
for (Competitor competitor : allCompetitors) {
Element competitorElement = createCompetitorXML(competitor, leaderboard, /*shortVersion*/ true, null);
Element competitorRaceDataElement = new Element("competitor_race_data");
LineLengthAndAdvantage start = race.getStartLine(race.getStartOfTracking());
addNamedElementWithValue(competitorRaceDataElement, "distance_to_start_line_on_race_start_in_meters", race.getDistanceToStartLine(competitor, race.getStartOfRace()).getMeters());
addNamedElementWithValue(competitorRaceDataElement, "distance_from_starboard_side_of_start_line_when_passing_start_in_meters", race.getDistanceFromStarboardSideOfStartLineWhenPassingStart(competitor).getMeters());
addNamedElementWithValue(competitorRaceDataElement, "speed_when_crossing_start_line_in_knots", race.getSpeedWhenCrossingStartLine(competitor).getKnots());
addNamedElementWithValue(competitorRaceDataElement, "start_advantage_in_meters", start.getAdvantage().getMeters());
addNamedElementWithValue(competitorRaceDataElement, "speed_on_start_signal_of_race_in_knots", race.getTrack(competitor).getEstimatedSpeed(race.getStartOfRace()).getKnots());
addNamedElementWithValue(competitorRaceDataElement, "advantageous_side_while_approaching_start_line", start.getAdvantageousSideWhileApproachingLine().name());
addNamedElementWithValue(competitorRaceDataElement, "distance_traveled_in_meters", race.getDistanceTraveled(competitor, race.getEndOfRace()).getMeters());
addNamedElementWithValue(competitorRaceDataElement, "final_race_rank", ++raceRank);
addNamedElementWithValue(competitorRaceDataElement, "final_race_score", leaderboard.getScoringScheme().getScoreForRank(column, competitor, raceRank, new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return allCompetitors.size();
}
}));
Distance averageCrossTrackError = race.getAverageCrossTrackError(competitor, race.getEndOfRace(), /*waitForLatestAnalysis*/ false);
addNamedElementWithValue(competitorRaceDataElement, "average_cross_track_error_in_meters", averageCrossTrackError != null ? averageCrossTrackError.getMeters() : -1.0);
addNamedElementWithValue(competitorRaceDataElement, "max_points_reason", leaderboard.getMaxPointsReason(competitor, column, race.getEndOfRace()).toString());
competitorElement.addContent(competitorRaceDataElement);
raceElement.addContent(competitorElement);
}
raceElement.addContent(legs);
return raceElement;
}
private Element createCompetitorXML(Competitor competitor, Leaderboard leaderboard, boolean shortVersion, Pair<Double, Vector<String>> competitorConfidenceAndErrorMessages) throws NoWindException, IOException, ServletException {
Element competitorElement = new Element("competitor");
addNamedElementWithValue(competitorElement, "uuid", competitor.getId().toString());
addNamedElementWithValue(competitorElement, "name", competitor.getName());
if (shortVersion)
return competitorElement;
createDataConfidenceXML(competitorConfidenceAndErrorMessages);
if (competitor.getBoat() != null) {
addNamedElementWithValue(competitorElement, "sail_id", cleanSailId(competitor.getBoat().getSailID(), competitor));
addNamedElementWithValue(competitorElement, "boat_class", competitor.getBoat().getBoatClass().getName());
addNamedElementWithValue(competitorElement, "boat_name", competitor.getBoat().getName());
} else {
addNamedElementWithValue(competitorElement, "sail_id", "");
addNamedElementWithValue(competitorElement, "boat_class", "");
addNamedElementWithValue(competitorElement, "boat_name", "");
}
if (competitor.getTeam() != null && competitor.getTeam().getNationality() != null) {
addNamedElementWithValue(competitorElement, "nationality_name", competitor.getTeam().getNationality().getName());
addNamedElementWithValue(competitorElement, "nationality_ioc", competitor.getTeam().getNationality().getThreeLetterIOCAcronym());
} else {
addNamedElementWithValue(competitorElement, "nationality_name", "");
addNamedElementWithValue(competitorElement, "nationality_ioc", "");
}
if (leaderboard.getTimePointOfLatestModification() != null) {
TimePoint timePointOfLatestModification = leaderboard.getTimePointOfLatestModification();
Long totalTimeSailed = leaderboard.getTotalTimeSailedInMilliseconds(competitor, timePointOfLatestModification);
addNamedElementWithValue(competitorElement, "total_time_sailed_in_milliseconds", totalTimeSailed);
addNamedElementWithValue(competitorElement, "total_time_sailed_including_non_finished_races_in_milliseconds", getTotalTimeSailedInMilliseconds(competitor, timePointOfLatestModification, true));
Distance totalDistanceSailed = leaderboard.getTotalDistanceTraveled(competitor, timePointOfLatestModification);
addNamedElementWithValue(competitorElement, "total_distance_sailed_in_meters", totalDistanceSailed != null ? totalDistanceSailed.getMeters() : 0);
addNamedElementWithValue(competitorElement, "total_distance_sailed_including_non_finished_races_in_meters", getTotalDistanceTraveled(leaderboard, competitor, timePointOfLatestModification).getMeters());
addNamedElementWithValue(competitorElement, "maximum_speed_over_ground_in_knots", leaderboard.getMaximumSpeedOverGround(competitor, timePointOfLatestModification).getB().getKnots());
Speed averageSpeed = leaderboard.getAverageSpeedOverGround(competitor, timePointOfLatestModification);
addNamedElementWithValue(competitorElement, "average_speed_over_ground_from_start_mark_passing_in_knots", averageSpeed != null ? averageSpeed.getKnots() : 0);
addNamedElementWithValue(competitorElement, "average_speed_over_ground_including_non_finished_races_in_knots", getAverageSpeedOverGround(leaderboard, competitor, timePointOfLatestModification, true).getKnots());
addNamedElementWithValue(competitorElement, "overall_rank", leaderboard.getTotalRankOfCompetitor(competitor, timePointOfLatestModification));
addNamedElementWithValue(competitorElement, "overall_score", leaderboard.getTotalPoints(competitor, timePointOfLatestModification));
} else {
TimePoint now = MillisecondsTimePoint.now();
addNamedElementWithValue(competitorElement, "total_time_sailed_in_milliseconds", leaderboard.getTotalTimeSailedInMilliseconds(competitor, now));
addNamedElementWithValue(competitorElement, "total_time_sailed_including_non_finished_races_in_milliseconds", getTotalTimeSailedInMilliseconds(competitor, now, true));
addNamedElementWithValue(competitorElement, "total_distance_sailed_in_meters", leaderboard.getTotalDistanceTraveled(competitor, now).getMeters());
addNamedElementWithValue(competitorElement, "total_distance_sailed_including_non_finished_races_in_meters", getTotalDistanceTraveled(leaderboard, competitor, now).getMeters());
addNamedElementWithValue(competitorElement, "maximum_speed_over_ground_in_knots", leaderboard.getMaximumSpeedOverGround(competitor, now).getB().getKnots());
Speed averageSpeed = leaderboard.getAverageSpeedOverGround(competitor, now);
addNamedElementWithValue(competitorElement, "average_speed_over_ground_from_start_mark_passing_in_knots", averageSpeed != null ? averageSpeed.getKnots() : 0);
addNamedElementWithValue(competitorElement, "average_speed_over_ground_including_non_finished_races_in_knots", getAverageSpeedOverGround(leaderboard, competitor, now, true).getKnots());
addNamedElementWithValue(competitorElement, "overall_rank", leaderboard.getTotalRankOfCompetitor(competitor, now));
addNamedElementWithValue(competitorElement, "overall_score", leaderboard.getTotalPoints(competitor, now));
}
return competitorElement;
}
private Element createLegXML(TrackedLeg trackedLeg, Leaderboard leaderboard, int legCounter, Pair<Double, Vector<String>> raceConfidenceAndErrorMessages, Pair<Double, Vector<String>> legConfidenceAndErrorMessages) throws NoWindException, IOException, ServletException {
Leg leg = trackedLeg.getLeg();
Element legElement = new Element("leg");
legElement.addContent(createDataConfidenceXML(legConfidenceAndErrorMessages));
addNamedElementWithValue(legElement, "position", legCounter);
addNamedElementWithValue(legElement, "mark_from", leg.getFrom().getName());
addNamedElementWithValue(legElement, "mark_to", leg.getTo().getName());
addNamedElementWithValue(legElement, "leg_type", trackedLeg.getLegType(trackedLeg.getTrackedRace().getStartOfRace()).name());
for (Competitor competitor : trackedLeg.getTrackedRace().getCompetitorsFromBestToWorst(/*timePoint*/ trackedLeg.getTrackedRace().getEndOfRace())) {
Element competitorElement = createCompetitorXML(competitor, leaderboard, /*shortVersion*/ true, null);
Element competitorLegDataElement = new Element("competitor_leg_data");
TrackedLegOfCompetitor competitorLeg = trackedLeg.getTrackedLeg(competitor);
/* if there is no start time then ignore all data of this leg */
if (competitorLeg.getStartTime() == null || competitorLeg.getFinishTime() == null) {
competitorElement.addContent(competitorLegDataElement);
continue;
}
TimePoint legFinishTime = competitorLeg.getFinishTime();
competitorLegDataElement.addContent(createTimedXML("leg_started_time_", competitorLeg.getStartTime()));
Pair<GPSFixMoving, Speed> maximumSpeed = competitorLeg.getMaximumSpeedOverGround(legFinishTime);
addNamedElementWithValue(competitorLegDataElement, "maximum_speed_over_ground_in_knots", maximumSpeed != null ? maximumSpeed.getB().getKnots() : -1);
addNamedElementWithValue(competitorLegDataElement, "average_velocity_made_good_in_knots", competitorLeg.getAverageVelocityMadeGood(legFinishTime).getKnots());
addNamedElementWithValue(competitorLegDataElement, "leg_finished_time_as_millis", handleValue(legFinishTime));
addNamedElementWithValue(competitorLegDataElement, "total_race_time_elapsed_as_millis", handleValue(legFinishTime)-handleValue(trackedLeg.getTrackedRace().getStartOfRace()));
addNamedElementWithValue(competitorLegDataElement, "time_spend_in_this_leg_as_millis", competitorLeg.getTimeInMilliSeconds(legFinishTime));
addNamedElementWithValue(competitorLegDataElement, "gap_to_leader_at_finish_in_seconds", competitorLeg.getGapToLeaderInSeconds(legFinishTime));
addNamedElementWithValue(competitorLegDataElement, "windward_distance_to_overall_leader_that_has_finished_this_leg_in_meters", competitorLeg.getWindwardDistanceToOverallLeader(legFinishTime).getMeters());
addNamedElementWithValue(competitorLegDataElement, "distance_traveled_in_meters", competitorLeg.getDistanceTraveled(legFinishTime).getMeters());
addNamedElementWithValue(competitorLegDataElement, "average_speed_over_ground_in_knots", competitorLeg.getAverageSpeedOverGround(legFinishTime).getKnots());
addNamedElementWithValue(competitorLegDataElement, "number_of_jibes", competitorLeg.getNumberOfJibes(legFinishTime));
addNamedElementWithValue(competitorLegDataElement, "number_of_tacks", competitorLeg.getNumberOfTacks(legFinishTime));
addNamedElementWithValue(competitorLegDataElement, "number_of_penalty_circles", competitorLeg.getNumberOfPenaltyCircles(legFinishTime));
addNamedElementWithValue(competitorLegDataElement, "leg_rank_at_leg_start", competitorLeg.getRank(competitorLeg.getStartTime()));
addNamedElementWithValue(competitorLegDataElement, "leg_rank_at_leg_finish", competitorLeg.getRank(legFinishTime));
addNamedElementWithValue(competitorLegDataElement, "rank_gain_for_this_leg_between_start_and_finish", competitorLeg.getRank(competitorLeg.getStartTime())-competitorLeg.getRank(legFinishTime));
List<Maneuver> maneuvers = competitorLeg.getManeuvers(legFinishTime, /*waitForLatest*/false);
addNamedElementWithValue(competitorLegDataElement, "maneuver_count", maneuvers.size());
Element maneuversElement = new Element("maneuvers");
for (Maneuver man : maneuvers) {
Element maneuverInformation = new Element("maneuver");
addNamedElementWithValue(maneuverInformation, "type", man.getType().toString());
addNamedElementWithValue(maneuverInformation, "direction_change_in_degrees", man.getDirectionChangeInDegrees());
Distance maneuverLoss = man.getManeuverLoss();
addNamedElementWithValue(maneuverInformation, "loss_in_meters", maneuverLoss != null ? maneuverLoss.getMeters() : 0.0);
addNamedElementWithValue(maneuverInformation, "speed_before_in_knots", man.getSpeedWithBearingBefore().getKnots());
addNamedElementWithValue(maneuverInformation, "speed_after_in_knots", man.getSpeedWithBearingAfter().getKnots());
maneuversElement.addContent(maneuverInformation);
}
competitorLegDataElement.addContent(maneuversElement);
Distance averageCrossTrackError = competitorLeg.getAverageCrossTrackError(legFinishTime, /*waitForLatestAnalysis*/ false);
addNamedElementWithValue(competitorLegDataElement, "average_cross_track_error_in_meters", averageCrossTrackError != null ? averageCrossTrackError.getMeters() : -1);
competitorElement.addContent(competitorLegDataElement);
legElement.addContent(competitorElement);
}
return legElement;
}
private Element createDataConfidenceXML(Pair<Double, Vector<String>> confidenceAndMessages) {
Element confidenceDataElement = new Element("confidence");
addNamedElementWithValue(confidenceDataElement, "simple_confidence_value", confidenceAndMessages.getA().doubleValue());
Element messagesElement = new Element("messages");
for (String message : confidenceAndMessages.getB()) {
addNamedElementWithValue(messagesElement, "message", message);
}
confidenceDataElement.addContent(messagesElement);
return confidenceDataElement;
}
private Pair<Double, Vector<String>> checkData(TrackedLeg leg) throws Exception {
double simpleConfidence = 1.0; Vector<String> messages = new Vector<String>();
TimePoint now = MillisecondsTimePoint.now();
for (TrackedLegOfCompetitor competitorLeg : leg.getTrackedLegsOfCompetitors()) {
if (!competitorLeg.hasFinishedLeg(now) || competitorLeg.getFinishTime() == null) {
messages.add("Competitor " + competitorLeg.getCompetitor().getName() + " has not finished this leg!");
simpleConfidence -= 0.08;
}
if (!competitorLeg.hasStartedLeg(now) || competitorLeg.getStartTime() == null) {
messages.add("Competitor " + competitorLeg.getCompetitor().getName() + " has not started this leg!");
simpleConfidence -= 0.08;
}
if (competitorLeg.getMaximumSpeedOverGround(now) == null) {
messages.add("Competitor " + competitorLeg.getCompetitor().getName() + " has no maximum speed for this leg!");
simpleConfidence -= 0.05;
}
if (competitorLeg.getAverageCrossTrackError(now, /*waitForLatestAnalysis*/ false) == null) {
messages.add("Competitor " + competitorLeg.getCompetitor().getName() + " has no average cross track error for this leg!");
simpleConfidence -= 0.02;
}
}
return new Pair<Double, Vector<String>>(simpleConfidence, messages);
}
private Pair<Double, Vector<String>> checkData(TrackedRace race) throws Exception {
double simpleConfidence = 1.0; Vector<String> messages = new Vector<String>();
TimePoint dateAtYear2000 = new MillisecondsTimePoint(946681200000l);
if (race.getStartOfRace() == null || race.getStartOfRace().before(dateAtYear2000)) {
messages.add("Start time of race " + race.getRaceIdentifier().getRaceName() + " is either null or not valid!");
simpleConfidence -= 1;
}
if (race.getEndOfRace() == null || race.getEndOfRace().before(dateAtYear2000)) {
messages.add("End time of race " + race.getRaceIdentifier().getRaceName() + " is either null or not valid!");
simpleConfidence -= 1;
}
if (race.getStartOfTracking() == null || race.getStartOfTracking().before(dateAtYear2000)) {
messages.add("Start tracking time of race " + race.getRaceIdentifier().getRaceName() + " is either null or not valid!");
simpleConfidence -= 0.2;
}
if (race.getEndOfTracking() == null || race.getEndOfTracking().before(dateAtYear2000)) {
messages.add("End tracking time of race " + race.getRaceIdentifier().getRaceName() + " is either null or not valid!");
simpleConfidence -= 0.2;
}
return new Pair<Double, Vector<String>>(simpleConfidence, messages);
}
private Pair<Double, Vector<String>> checkData(Competitor competitor) throws Exception {
double simpleConfidence = 1.0; Vector<String> messages = new Vector<String>();
if (competitor.getName() == null || competitor.getName().equals("")) {
messages.add("Competitor " + competitor.getId() + " has no name!");
simpleConfidence -= 1;
}
if (competitor.getBoat() == null || competitor.getBoat().getSailID() == null || competitor.getBoat().getSailID().equals("")) {
messages.add("Competitor " + competitor.getId() + " has no sail id that can be used!");
simpleConfidence -= 1;
}
if (competitor.getTeam() == null || competitor.getTeam().getNationality() == null) {
messages.add("Either team for "+ competitor.getId() + " is null or nationality could not be determined");
simpleConfidence -= 0.2;
}
return new Pair<Double, Vector<String>>(simpleConfidence, messages);
}
private Pair<Double, Vector<String>> checkData(Leaderboard leaderboard) throws Exception {
double simpleConfidence = 1.0; Vector<String> messages = new Vector<String>();
int raceColumnCount = 0; int attachedRaceToColumnCount = 0;
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
if (raceColumn.hasTrackedRaces()) {
attachedRaceToColumnCount++;
}
raceColumnCount++;
}
if (raceColumnCount == 0) {
messages.add("Could not find any race columns or none of the race columns has tracked races attached!");
simpleConfidence -= 1.0;
}
if (attachedRaceToColumnCount < raceColumnCount) {
messages.add("Not all race columns contain attached races! Data being aggregated over all races could be wrong!");
simpleConfidence -= 0.3;
}
int competitorCount = 0;
for (Iterator<Competitor> iterator = leaderboard.getAllCompetitors().iterator(); iterator.hasNext();) {
iterator.next();
competitorCount++;
}
if (competitorCount == 0) {
messages.add("Could not find any competitors in this leaderboard!");
simpleConfidence -= 1.0;
}
TimePoint dateAtYear2000 = new MillisecondsTimePoint(946681200000l);
if (leaderboard.getTimePointOfLatestModification().before(dateAtYear2000)) {
messages.add("The time point of the last modification for this leaderboard is very old.");
simpleConfidence -= 0.4;
}
return new Pair<Double, Vector<String>>(simpleConfidence, messages);
}
private int getSameDayGroupIndex(TrackedRace currentRace, TrackedRace raceBefore) {
if (raceBefore != null && !raceBefore.equals(currentRace)) {
if (currentRace != null && currentRace.getStartOfRace() != null && raceBefore.getStartOfRace() != null) {
Calendar timedDateForCurrentRace = Calendar.getInstance();
timedDateForCurrentRace.setTime(currentRace.getStartOfRace().asDate());
String formattedCurrent = new SimpleDateFormat("dd.MM.yyyy").format(timedDateForCurrentRace.getTime());
Calendar timedDateForRaceBefore = Calendar.getInstance();
timedDateForRaceBefore.setTime(raceBefore.getStartOfRace().asDate());
String formattedBefore = new SimpleDateFormat("dd.MM.yyyy").format(timedDateForRaceBefore.getTime());
if (formattedCurrent.equals(formattedBefore)) {
return 0;
}
}
} else {
return 0;
}
return 1;
}
public void perform() throws Exception {
final Leaderboard leaderboard = getLeaderboard();
Pair<Double, Vector<String>> leaderboardConfidenceAndErrorMessages = checkData(leaderboard);
final List<Element> racesElements = new ArrayList<Element>();
final List<Element> competitorElements = new ArrayList<Element>();
for (Competitor competitor : leaderboard.getAllCompetitors()) {
Pair<Double, Vector<String>> competitorConfidenceAndErrorMessages = checkData(competitor);
competitorElements.add(createCompetitorXML(competitor, leaderboard, /*shortVersion*/ false, competitorConfidenceAndErrorMessages));
}
TrackedRace raceBefore = null; int sameDayGroupIndex = 0;
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
for (Fleet fleet : raceColumn.getFleets()) {
sameDayGroupIndex += getSameDayGroupIndex(raceColumn.getTrackedRace(fleet), raceBefore);
int raceCounter = 0;
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
if (trackedRace != null && trackedRace.hasGPSData()) {
raceCounter++;
Pair<Double, Vector<String>> raceConfidenceAndErrorMessages = checkData(trackedRace);
final List<Element> legs = new ArrayList<Element>();
int legCounter = 0;
for (TrackedLeg leg : trackedRace.getTrackedLegs()) {
Pair<Double, Vector<String>> legConfidenceAndErrorMessages = checkData(leg);
legs.add(createLegXML(leg, leaderboard, ++legCounter, raceConfidenceAndErrorMessages, legConfidenceAndErrorMessages));
}
racesElements.add(createRaceXML(trackedRace, fleet, legs, raceColumn, leaderboard, sameDayGroupIndex, raceCounter, raceConfidenceAndErrorMessages));
raceBefore = trackedRace;
}
}
}
sendDocument(createLeaderboardXML(leaderboard, competitorElements, racesElements, leaderboardConfidenceAndErrorMessages), leaderboard.getName() + ".xml");
}
}
@@ -0,0 +1,31 @@
package com.sap.sailing.xmlexport;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sap.sailing.server.gateway.SailingServerHttpServlet;
public class XmlExportServlet extends SailingServerHttpServlet {
private static final long serialVersionUID = -6849138354942569249L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
final String action = req.getParameter("domain");
try {
if ((action != null) && !"".equals(action)) {
if ("leaderboard".equalsIgnoreCase(action)) {
final LeaderboardData leaderboardData = new LeaderboardData(req, res, getService());
leaderboardData.perform();
return;
}
throw new ServletException("Unknown domain " + action);
}
throw new ServletException("Please use the domain= parameter to specify a domain that'll be exported.");
} catch (Exception e) {
throw (new ServletException(e));
}
}
}