diff --git a/configuration/sailing b/configuration/sailing
index 2764e008d49..82d4c09b9a4 100755
--- a/configuration/sailing
+++ b/configuration/sailing
@@ -4,6 +4,18 @@
#
# chkconfig: 2345 95 10
# description: Sailing contains all sailing services
+#
+### BEGIN INIT INFO
+# Provides: sailing
+# Required-Start: $local_fs $network $named $remote_fs
+# Should-Start:
+# Required-Stop:
+# Should-Stop:
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: The sailing service
+# Description: Start all sailing services required for this instance
+### END INIT INFO
# Source function library.
. /etc/init.d/functions
@@ -14,8 +26,8 @@ JAVA_START_INSTANCES="server"
SERVERS_DIR=/home/sailing/servers
GIT_REPOSITORY=/home/sailing/code
APACHE_CONFIG_DIR=/etc/httpd/conf.d
-rm /var/log/sailing.out
-rm /var/log/sailing.err
+
+echo "Executing with $1" >>/var/log/sailing.out
start_tmux() {
su - sailing -c "/home/sailing/bin/tmuxConsole.sh unattended"
@@ -63,13 +75,21 @@ start_servers() {
stop_servers() {
for conf in $JAVA_START_INSTANCES; do
- echo "Stopping Java server $conf"
+ echo "Stopping Java server $conf" >> /var/log/sailing.out
su - sailing -c "cd $SERVERS_DIR/$conf && ./stop"
RETVAL=$?
[ $RETVAL -eq 0 ] && success || failure
+ stop_httpd
+ sync_logs
done
}
+sync_logs() {
+ echo "Executing logrotate followed by a sync to ensure that logs are synchronized" >> /var/log/sailing.out
+ logrotate -f /etc/logrotate.conf
+ sync
+}
+
# launch_httpd(server_name, port, event_id)
launch_httpd() {
echo "Will try to launch httpd so this replica can work with an ELB easily." >>/var/log/sailing.out
@@ -78,7 +98,7 @@ launch_httpd() {
source $SERVERS_DIR/$FIRST_SERVER/env.sh
# Append Apache macro invocation for /internal-server-status based on mod_status and INSTANCE_DNS to $APACHE_CONFIG_DIR/001-events.conf
echo "Appending macro usage for $INSTANCE_DNS/internal-server-status URL for mod_status based Apache monitoring to $APACHE_CONFIG_DIR/001-events.conf" >>/var/log/sailing.out
- echo "## SERVER STATUS" >>$APACHE_CONFIG_DIR/001-events.conf
+ echo "## SERVER STATUS" >>$APACHE_CONFIG_DIR/001-events.conf
echo "Use Status $INSTANCE_DNS internal-server-status" >>$APACHE_CONFIG_DIR/001-events.conf
echo "Launching httpd..." >>/var/log/sailing.out
service httpd start
@@ -87,13 +107,23 @@ launch_httpd() {
fi
}
+stop_httpd() {
+ if [ -x /etc/init.d/httpd ]; then
+ service httpd stop
+ echo "Stopped httpd..." >>/var/log/sailing.out
+ fi
+}
+
# See how we were called.
case "$1" in
start)
+ /usr/sbin/update-motd
start_servers
+ touch /var/lock/subsys/sailing
;;
stop)
stop_servers
+ rm -f /var/lock/subsys/sailing
;;
status)
status java
diff --git a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupRetrievalProcessor.java b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupRetrievalProcessor.java
index 190b38265a6..cd565ac9a20 100644
--- a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupRetrievalProcessor.java
@@ -15,7 +15,7 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
-import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
+import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
import com.sap.sailing.datamining.test.util.ConcurrencyTestsUtil;
import com.sap.sailing.datamining.test.util.NullProcessor;
import com.sap.sailing.domain.leaderboard.Leaderboard;
@@ -27,7 +27,7 @@ import com.sap.sse.datamining.components.Processor;
public class TestLeaderboardGroupRetrievalProcessor {
private RacingEventService service;
- private Processor retriever;
+ private Processor retriever;
private Collection retrievedGroups;
@@ -37,14 +37,14 @@ public class TestLeaderboardGroupRetrievalProcessor {
stub(service.getLeaderboardGroups()).toReturn(getGroupsInService());
retrievedGroups = new HashSet<>();
- Processor receiver = new NullProcessor(LeaderboardGroupWithContext.class, Void.class) {
+ Processor receiver = new NullProcessor(HasLeaderboardGroupContext.class, Void.class) {
@Override
- public void processElement(LeaderboardGroupWithContext element) {
+ public void processElement(HasLeaderboardGroupContext element) {
retrievedGroups.add(element.getLeaderboardGroup());
}
};
- Collection> resultReceivers = new ArrayList<>();
+ Collection> resultReceivers = new ArrayList<>();
resultReceivers.add(receiver);
retriever = new LeaderboardGroupRetrievalProcessor(ConcurrencyTestsUtil.getExecutor(), resultReceivers, 0);
}
diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties
index 65084d8084a..c67e1bcfb75 100644
--- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties
+++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties
@@ -188,7 +188,7 @@ AbsRelativeBearingToNextMarkAfterManeuver=Abs. relative bearing to the next mark
RatioBetweenDistanceSailedWithAndWithoutManeuver=Ratio between distance sailed with and without maneuver
RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver=Ratio between distance sailed toward middle angle projection with and without maneuver
DurationLostByManeuver=Duration lost by maneuver
-DurationLostByManeuverTowardMiddleAngleProjection=duration lost by maneuver toward middle angle projection
+DurationLostByManeuverTowardMiddleAngleProjection=Duration lost by maneuver toward middle angle projection
JibingCount=Jibing count
TackingCount=Tacking count
AbsTwaAtMaxTurningRate=Abs. TWA at max. turning rate
@@ -198,4 +198,5 @@ PercentageOfMainCurveProgressUntilLowestSpeed=Percentage of main curve progress
PercentageOfMainCurveProgressUntilHighestSpeed=Percentage of main curve progress until highest speed
PercentageOfMainCurveProgressUntilMaxTurningRate=Percentage of main curve progress until max. turning rate speed
AbsTwaAtManeuverMiddle=Abs. TWA at maneuver middle
-GpsSamplingRate=GPS sampling rate
\ No newline at end of file
+GpsSamplingRate=GPS sampling rate
+RaceDuration=Race duration
\ No newline at end of file
diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties
index 2ef0edf2761..82c4ad2377d 100644
--- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties
+++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties
@@ -201,4 +201,5 @@ PercentageOfMainCurveProgressUntilHighestSpeed=Prozentualer Fortschritt der Haup
PercentageOfMainCurveProgressUntilMaxTurningRate=Prozentualer Fortschritt der Hauptkurve bis zum Erreichen von max. Drehrate
ManeuverTypeForCompleteManeuverCurve=Manövertyp für komplette Manöverkurve
AbsTwaAtManeuverMiddle=Abs. TWA während Manövermitte
-GpsSamplingRate=GPS-Samplingrate
\ No newline at end of file
+GpsSamplingRate=GPS-Samplingrate
+RaceDuration=Renndauer
\ No newline at end of file
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java
index df083c132e0..0cedaa8921f 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/SailingDataRetrievalChainDefinitions.java
@@ -5,12 +5,13 @@ import java.util.Collection;
import com.sap.sailing.datamining.data.HasBravoFixContext;
import com.sap.sailing.datamining.data.HasBravoFixTrackContext;
+import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext;
import com.sap.sailing.datamining.data.HasFoilingSegmentContext;
import com.sap.sailing.datamining.data.HasGPSFixContext;
import com.sap.sailing.datamining.data.HasLeaderboardContext;
+import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
import com.sap.sailing.datamining.data.HasManeuverContext;
import com.sap.sailing.datamining.data.HasManeuverSpeedDetailsContext;
-import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext;
import com.sap.sailing.datamining.data.HasMarkPassingContext;
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
import com.sap.sailing.datamining.data.HasRaceResultOfCompetitorContext;
@@ -22,13 +23,13 @@ import com.sap.sailing.datamining.data.HasWindTrackContext;
import com.sap.sailing.datamining.impl.components.BravoFixRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.BravoFixTrackRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.CompetitorOfRaceInLeaderboardRetrievalProcessor;
+import com.sap.sailing.datamining.impl.components.CompleteManeuverCurveWithEstimationDataRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.FoilingSegmentRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.GPSFixRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.LeaderboardGroupRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.LeaderboardRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.ManeuverRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.ManeuverSpeedDetailsRetrievalProcessor;
-import com.sap.sailing.datamining.impl.components.CompleteManeuverCurveWithEstimationDataRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.MarkPassingRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.RaceOfCompetitorRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.TrackedLegOfCompetitorRetrievalProcessor;
@@ -36,7 +37,6 @@ import com.sap.sailing.datamining.impl.components.TrackedLegRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.TrackedRaceRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.WindFixRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.WindTrackRetrievalProcessor;
-import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
import com.sap.sailing.datamining.shared.FoilingSegmentsDataMiningSettings;
import com.sap.sailing.datamining.shared.ManeuverSettings;
import com.sap.sailing.datamining.shared.ManeuverSettingsImpl;
@@ -55,7 +55,7 @@ public class SailingDataRetrievalChainDefinitions {
final DataRetrieverChainDefinition leaderboardRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
RacingEventService.class, HasLeaderboardContext.class, "LeaderboardSailingDomainRetrieverChain");
- leaderboardRetrieverChainDefinition.startWith(LeaderboardGroupRetrievalProcessor.class, LeaderboardGroupWithContext.class, "LeaderboardGroup");
+ leaderboardRetrieverChainDefinition.startWith(LeaderboardGroupRetrievalProcessor.class, HasLeaderboardGroupContext.class, "LeaderboardGroup");
leaderboardRetrieverChainDefinition.endWith(LeaderboardGroupRetrievalProcessor.class, LeaderboardRetrievalProcessor.class,
HasLeaderboardContext.class, "Leaderboard");
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasBravoFixContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasBravoFixContext.java
index f733d6f9bb4..a5d2afce531 100755
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasBravoFixContext.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasBravoFixContext.java
@@ -16,7 +16,7 @@ public interface HasBravoFixContext {
@Connector(ordinal=1)
BravoFix getBravoFix();
- @Connector(messageKey="Speed")
+ @Connector(messageKey="")
SpeedWithBearing getSpeed();
@Connector(messageKey="Wind")
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java
index d063b5eef97..06705c310dd 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java
@@ -2,7 +2,6 @@ package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.leaderboard.Leaderboard;
-import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
@@ -12,8 +11,6 @@ public interface HasLeaderboardContext {
Leaderboard getLeaderboard();
- PolarDataService getPolarDataService();
-
@Dimension(messageKey="Leaderboard", ordinal=1)
String getName();
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceOfCompetitorContext.java
index 3fbcd143d7e..5ed03ec38b1 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceOfCompetitorContext.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceOfCompetitorContext.java
@@ -4,6 +4,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Tack;
import com.sap.sse.common.Distance;
+import com.sap.sse.common.Duration;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.Speed;
import com.sap.sse.datamining.annotations.Connector;
@@ -14,74 +15,74 @@ import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
public interface HasRaceOfCompetitorContext {
@Connector(scanForStatistics=false)
- public HasTrackedRaceContext getTrackedRaceContext();
+ HasTrackedRaceContext getTrackedRaceContext();
@Connector(messageKey="Competitor")
- @Statistic(messageKey="")
- public Competitor getCompetitor();
+ @Statistic(messageKey="Competitor")
+ Competitor getCompetitor();
@Dimension(messageKey="TackAtStart", ordinal=12)
- public Tack getTackAtStart() throws NoWindException;
+ Tack getTackAtStart() throws NoWindException;
@Dimension(messageKey="DistanceToStarboardSideAtStartOfCompetitor", ordinal=13)
- public ClusterDTO getPercentageClusterForDistanceToStarboardSideAtStart();
+ ClusterDTO getPercentageClusterForDistanceToStarboardSideAtStart();
@Dimension(messageKey="RelativeScoreInPercent", ordinal=14)
- public ClusterDTO getPercentageClusterForRelativeScore();
+ ClusterDTO getPercentageClusterForRelativeScore();
@Statistic(messageKey="DistanceAtStart", resultDecimals=2, ordinal=0)
- public Distance getDistanceToStartLineAtStart();
+ Distance getDistanceToStartLineAtStart();
@Statistic(messageKey="DistanceToStarboardSideAtStartOfCompetitor", resultDecimals=2, ordinal=1)
- public Double getNormalizedDistanceToStarboardSideAtStartOfCompetitor();
+ Double getNormalizedDistanceToStarboardSideAtStartOfCompetitor();
@Statistic(messageKey="DistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark", resultDecimals=2, ordinal=1)
- public Pair getNormalizedDistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark();
+ Pair getNormalizedDistanceToStarboardSideAtStartOfCompetitorVsRankAtFirstMark();
@Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLineAtStartOfRace", resultDecimals=2, ordinal=2)
- public Distance getWindwardDistanceToAdvantageousLineEndAtStartofRace();
+ Distance getWindwardDistanceToAdvantageousLineEndAtStartofRace();
@Statistic(messageKey="WindwardDistanceToAdvantageousEndOfLineAtStartOfCompetitor", resultDecimals=2, ordinal=2)
- public Distance getWindwardDistanceToAdvantageousLineEndAtStartofCompetitor();
+ Distance getWindwardDistanceToAdvantageousLineEndAtStartofCompetitor();
@Connector(messageKey="SpeedWhenStarting", ordinal=3)
- public Speed getSpeedWhenStarting();
+ Speed getSpeedWhenStarting();
@Connector(messageKey="SpeedTenSecondsBeforeStart", ordinal=4)
- public Speed getSpeedTenSecondsBeforeStart();
+ Speed getSpeedTenSecondsBeforeStart();
@Connector(messageKey="SpeedTenSecondsAfterStart", ordinal=5)
- public Speed getSpeedTenSecondsAfterStartOfRace();
+ Speed getSpeedTenSecondsAfterStartOfRace();
@Statistic(messageKey="RankThirtySecondsAfterStart", resultDecimals=2, ordinal=6)
- public Double getRankThirtySecondsAfterStartOfRace();
+ Double getRankThirtySecondsAfterStartOfRace();
@Statistic(messageKey="RankAfterHalfOfTheFirstLeg", resultDecimals=2, ordinal=7)
- public Double getRankAfterHalfOfTheFirstLeg();
+ Double getRankAfterHalfOfTheFirstLeg();
@Statistic(messageKey="RankAtFirstMark", resultDecimals=2, ordinal=8)
- public Double getRankAtFirstMark();
+ Double getRankAtFirstMark();
@Statistic(messageKey="RankGainsOrLossesBetweenFirstMarkAndFinish", resultDecimals=2, ordinal=9)
- public Double getRankGainsOrLossesBetweenFirstMarkAndFinish();
+ Double getRankGainsOrLossesBetweenFirstMarkAndFinish();
@Statistic(messageKey="NumberOfManeuvers", resultDecimals=0, ordinal=10)
- public int getNumberOfManeuvers();
+ int getNumberOfManeuvers();
@Statistic(messageKey="NumberOfTacks", resultDecimals=0, ordinal=11)
- public int getNumberOfTacks();
+ int getNumberOfTacks();
@Statistic(messageKey="NumberOfJibes", resultDecimals=0, ordinal=12)
- public int getNumberOfJibes();
+ int getNumberOfJibes();
@Statistic(messageKey="NumberOfPenaltyCircles", resultDecimals=0, ordinal=13)
- public int getNumberOfPenaltyCircles();
+ int getNumberOfPenaltyCircles();
@Statistic(messageKey="DistanceTraveled", resultDecimals=1)
- public Distance getDistanceTraveled();
+ Distance getDistanceTraveled();
@Statistic(messageKey="LineLengthAtStart", resultDecimals=1)
- public Distance getLineLengthAtStart();
+ Distance getLineLengthAtStart();
@Statistic(messageKey="AbsoluteWindwardDistanceToStarboardSideAtStartOfCompetitor", resultDecimals=2)
Distance getAbsoluteWindwardDistanceToStarboardSideAtStartOfCompetitor();
@@ -94,4 +95,8 @@ public interface HasRaceOfCompetitorContext {
@Statistic(messageKey="RelativeDistanceToAdvantageousEndOfLineAtStartOfRace", resultDecimals=2)
Double getRelativeDistanceToAdvantageousEndOfLineAtStartOfRace();
+
+ @Statistic(messageKey="RaceDuration")
+ Duration getDuration();
+
}
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java
index 138f4b7788f..b5a77441a5a 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java
@@ -8,6 +8,7 @@ import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.tracking.TrackedRace;
+import com.sap.sse.common.Duration;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
@@ -46,10 +47,13 @@ public interface HasTrackedRaceContext {
@Dimension(messageKey="IsTracked", ordinal=9)
public Boolean isTracked();
- @Statistic(messageKey="NumberOfCompetitorFixes", resultDecimals=0, ordinal=0)
+ @Statistic(messageKey="RaceDuration", ordinal=0)
+ public Duration getDuration();
+
+ @Statistic(messageKey="NumberOfCompetitorFixes", resultDecimals=0, ordinal=1)
public int getNumberOfCompetitorFixes();
- @Statistic(messageKey="NumberOfMarkFixes", resultDecimals=0, ordinal=1)
+ @Statistic(messageKey="NumberOfMarkFixes", resultDecimals=0, ordinal=2)
public int getNumberOfMarkFixes();
// Convenience methods for race dependent calculation to avoid code duplication
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasWindFixContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasWindFixContext.java
index 39168a6cc3c..ba4cbe091e1 100755
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasWindFixContext.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasWindFixContext.java
@@ -11,7 +11,7 @@ public interface HasWindFixContext extends HasWind {
@Connector(scanForStatistics=false)
public HasTrackedRaceContext getTrackedRaceContext();
- @Statistic(messageKey="", ordinal=0)
+ @Statistic(messageKey="WindFix", ordinal=0)
public Wind getWind();
@Statistic(messageKey="windFrom", resultDecimals=1, ordinal=1)
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/BravoFixRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/BravoFixRetrievalProcessor.java
index 3370ffc238c..73dfb14ceb3 100755
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/BravoFixRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/BravoFixRetrievalProcessor.java
@@ -24,21 +24,24 @@ public class BravoFixRetrievalProcessor extends AbstractRetrievalProcessor retrieveData(HasTrackedLegOfCompetitorContext element) {
Collection bravoFixesWithContext = new ArrayList<>();
- BravoFixTrack bravoFixTrack = element.getTrackedLegContext().getTrackedRaceContext().getTrackedRace().getSensorTrack(element.getCompetitor(), BravoFixTrack.TRACK_NAME);
- if (bravoFixTrack != null) {
- bravoFixTrack.lockForRead();
- try {
- TrackedLegOfCompetitor trackedLegOfCompetitor = element.getTrackedLegOfCompetitor();
- if (trackedLegOfCompetitor.getStartTime() != null && trackedLegOfCompetitor.getFinishTime() != null) {
+ TrackedLegOfCompetitor trackedLegOfCompetitor = element.getTrackedLegOfCompetitor();
+ if (trackedLegOfCompetitor.getStartTime() != null && trackedLegOfCompetitor.getFinishTime() != null) {
+ BravoFixTrack bravoFixTrack = element.getTrackedLegContext().getTrackedRaceContext().getTrackedRace().getSensorTrack(element.getCompetitor(), BravoFixTrack.TRACK_NAME);
+ if (bravoFixTrack != null) {
+ bravoFixTrack.lockForRead();
+ try {
for (BravoFix bravoFix : bravoFixTrack.getFixes(trackedLegOfCompetitor.getStartTime(), true, trackedLegOfCompetitor.getFinishTime(), true)) {
+ if (isAborted()) {
+ break;
+ }
BravoFixWithContext gpsFixWithContext = new BravoFixWithContext(
new TrackedLegOfCompetitorWithSpecificTimePointWithContext(
element.getTrackedLegContext(), element.getTrackedLegOfCompetitor(), bravoFix.getTimePoint()), bravoFix);
bravoFixesWithContext.add(gpsFixWithContext);
}
+ } finally {
+ bravoFixTrack.unlockAfterRead();
}
- } finally {
- bravoFixTrack.unlockAfterRead();
}
}
return bravoFixesWithContext;
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/BravoFixTrackRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/BravoFixTrackRetrievalProcessor.java
index 0905ce48aef..87e4b42e4c1 100755
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/BravoFixTrackRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/BravoFixTrackRetrievalProcessor.java
@@ -1,7 +1,7 @@
package com.sap.sailing.datamining.impl.components;
-import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.datamining.data.HasBravoFixTrackContext;
@@ -28,13 +28,9 @@ public class BravoFixTrackRetrievalProcessor extends AbstractRetrievalProcessor<
@Override
protected Iterable retrieveData(HasRaceOfCompetitorContext element) {
- Collection bravoTracksWithContext = new ArrayList<>();
final TrackedRace trackedRace = element.getTrackedRaceContext().getTrackedRace();
final BravoFixTrack bravoFixTrack = trackedRace.getSensorTrack(element.getCompetitor(), BravoFixTrack.TRACK_NAME);
- if (bravoFixTrack != null) {
- bravoTracksWithContext.add(new BravoFixTrackWithContext(element, bravoFixTrack));
- }
- return bravoTracksWithContext;
+ return bravoFixTrack == null ? Collections.emptySet() : Collections.singleton(new BravoFixTrackWithContext(element, bravoFixTrack));
}
}
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompetitorOfRaceInLeaderboardRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompetitorOfRaceInLeaderboardRetrievalProcessor.java
index 5d81bac8881..15ed1eeca2f 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompetitorOfRaceInLeaderboardRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompetitorOfRaceInLeaderboardRetrievalProcessor.java
@@ -24,9 +24,15 @@ public class CompetitorOfRaceInLeaderboardRetrievalProcessor extends
protected Iterable retrieveData(HasLeaderboardContext element) {
Collection raceResultsOfCompetitor = new ArrayList<>();
for (RaceColumn raceColumn : element.getLeaderboard().getRaceColumns()) {
+ if (isAborted()) {
+ break;
+ }
for (Competitor competitor : element.getLeaderboard().getCompetitors()) {
+ if (isAborted()) {
+ break;
+ }
HasRaceResultOfCompetitorContext raceResultOfCompetitorContext = new RaceResultOfCompetitorWithContext(element, raceColumn, competitor,
- element.getPolarDataService());
+ element.getLeaderboardGroupContext().getPolarDataService());
raceResultsOfCompetitor.add(raceResultOfCompetitorContext);
}
}
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompleteManeuverCurveWithEstimationDataRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompleteManeuverCurveWithEstimationDataRetrievalProcessor.java
index eff334d61f5..01659c4ac04 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompleteManeuverCurveWithEstimationDataRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/CompleteManeuverCurveWithEstimationDataRetrievalProcessor.java
@@ -48,15 +48,27 @@ public class CompleteManeuverCurveWithEstimationDataRetrievalProcessor extends
Competitor competitor = element.getCompetitor();
ManeuverDetectorWithEstimationDataSupport maneuverDetector = new ManeuverDetectorWithEstimationDataSupportDecoratorImpl(
new ManeuverDetectorImpl(trackedRace, competitor),
- element.getTrackedRaceContext().getLeaderboardContext().getPolarDataService());
+ element.getTrackedRaceContext().getLeaderboardContext().getLeaderboardGroupContext().getPolarDataService());
+
Iterable maneuvers = trackedRace.getManeuvers(competitor, false);
+ if (isAborted()) {
+ return result;
+ }
+
Iterable maneuverCurves = maneuverDetector.getCompleteManeuverCurves(maneuvers);
+ if (isAborted()) {
+ return result;
+ }
+
Iterable maneuversWithEstimationData = maneuverDetector
.getCompleteManeuverCurvesWithEstimationData(maneuverCurves);
-
CompleteManeuverCurveWithEstimationData previousManeuver = null;
CompleteManeuverCurveWithEstimationData currentManeuver = null;
for (CompleteManeuverCurveWithEstimationData nextManeuver : maneuversWithEstimationData) {
+ if (isAborted()) {
+ break;
+ }
+
if (currentManeuver != null) {
CompleteManeuverCurveWithEstimationDataWithContext maneuverWithContext = new CompleteManeuverCurveWithEstimationDataWithContext(
element, currentManeuver, settings, previousManeuver, nextManeuver);
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/FoilingSegmentRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/FoilingSegmentRetrievalProcessor.java
index fbfa62cd126..bbc21f56c33 100755
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/FoilingSegmentRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/FoilingSegmentRetrievalProcessor.java
@@ -50,6 +50,9 @@ public class FoilingSegmentRetrievalProcessor extends AbstractRetrievalProcessor
bravoFixTrack.lockForRead();
try {
for (final BravoFix bravoFix : bravoFixTrack.getFixes(startOfRace, /* fromInclusive */ true, end, /* toInclusive */ false)) {
+ if (isAborted()) {
+ break;
+ }
final boolean currentFixIsFoiling =
(bravoFix.isFoiling(settings.getMinimumRideHeight()) &&
(settings.getMinimumSpeedForFoiling() == null || settings.getMinimumSpeedForFoiling().compareTo(
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java
index 19161c9d6f3..f9ee2372d1d 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java
@@ -30,6 +30,9 @@ public class GPSFixRetrievalProcessor extends AbstractRetrievalProcessor {
+public class LeaderboardGroupRetrievalProcessor extends AbstractRetrievalProcessor {
public LeaderboardGroupRetrievalProcessor(ExecutorService executor,
- Collection> resultReceivers, int retrievalLevel) {
- super(RacingEventService.class, LeaderboardGroupWithContext.class, executor, resultReceivers, retrievalLevel);
+ Collection> resultReceivers, int retrievalLevel) {
+ super(RacingEventService.class, HasLeaderboardGroupContext.class, executor, resultReceivers, retrievalLevel);
}
@Override
- protected Iterable retrieveData(RacingEventService element) {
- final PolarDataService polarDataService = element.getPolarDataService();
- return element.getLeaderboardGroups()
- .values()
- .stream()
- .map(lg -> new LeaderboardGroupWithContext(lg, polarDataService))
- .collect(Collectors.toSet());
+ protected Iterable retrieveData(RacingEventService element) {
+ Set data = new HashSet<>();
+ PolarDataService polarDataService = element.getPolarDataService();
+ for (LeaderboardGroup leaderboardGroup : element.getLeaderboardGroups().values()) {
+ if (isAborted()) {
+ break;
+ }
+ data.add(new LeaderboardGroupWithContext(leaderboardGroup, polarDataService));
+ }
+ return data;
}
}
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardRetrievalProcessor.java
index 09062609cfb..6feee91098b 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardRetrievalProcessor.java
@@ -5,24 +5,27 @@ import java.util.Collection;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.datamining.data.HasLeaderboardContext;
-import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContext;
+import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
import com.sap.sailing.datamining.impl.data.LeaderboardWithContext;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
-public class LeaderboardRetrievalProcessor extends AbstractRetrievalProcessor {
+public class LeaderboardRetrievalProcessor extends AbstractRetrievalProcessor {
public LeaderboardRetrievalProcessor(ExecutorService executor,
Collection> resultReceivers, int retrievalLevel) {
- super(LeaderboardGroupWithContext.class, HasLeaderboardContext.class, executor, resultReceivers, retrievalLevel);
+ super(HasLeaderboardGroupContext.class, HasLeaderboardContext.class, executor, resultReceivers, retrievalLevel);
}
@Override
- protected Iterable retrieveData(LeaderboardGroupWithContext element) {
+ protected Iterable retrieveData(HasLeaderboardGroupContext element) {
Collection leaderboardsWithContext = new ArrayList<>();
for (Leaderboard leaderboard : element.getLeaderboardGroup().getLeaderboards()) {
- leaderboardsWithContext.add(new LeaderboardWithContext(leaderboard, element, element.getPolarDataService()));
+ if (isAborted()) {
+ break;
+ }
+ leaderboardsWithContext.add(new LeaderboardWithContext(leaderboard, element));
}
return leaderboardsWithContext;
}
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverRetrievalProcessor.java
index 097e191fba4..c2a683b3423 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverRetrievalProcessor.java
@@ -9,6 +9,7 @@ import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
import com.sap.sailing.datamining.impl.data.ManeuverWithContext;
import com.sap.sailing.datamining.impl.data.TrackedLegOfCompetitorWithSpecificTimePointWithContext;
import com.sap.sailing.datamining.shared.ManeuverSettings;
+import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries;
@@ -36,6 +37,9 @@ public class ManeuverRetrievalProcessor
TimePoint finishTime = element.getTrackedLegOfCompetitor().getFinishTime();
if (finishTime != null) {
Iterable maneuvers = null;
+ if (!isLastLeg(element)) {
+ finishTime = finishTime.minus(1);
+ }
try {
maneuvers = element.getTrackedLegOfCompetitor().getManeuvers(finishTime, false);
} catch (NoWindException e) {
@@ -44,6 +48,10 @@ public class ManeuverRetrievalProcessor
Maneuver previousManeuver = null;
Maneuver currentManeuver = null;
for (Maneuver nextManeuver : maneuvers) {
+ if (isAborted()) {
+ break;
+ }
+
if (currentManeuver != null) {
ManeuverWithContext maneuverWithContext = new ManeuverWithContext(new TrackedLegOfCompetitorWithSpecificTimePointWithContext(
element.getTrackedLegContext(), element.getTrackedLegOfCompetitor(), currentManeuver.getTimePoint()), currentManeuver,
@@ -66,6 +74,12 @@ public class ManeuverRetrievalProcessor
return maneuversWithContext;
}
+ private boolean isLastLeg(HasTrackedLegOfCompetitorContext element) {
+ Waypoint finishWaypoint = element.getTrackedLegContext().getTrackedRaceContext().getRace().getCourse().getLastWaypoint();
+ Waypoint toWaypoint = element.getTrackedLegOfCompetitor().getLeg().getTo();
+ return finishWaypoint.equals(toWaypoint);
+ }
+
private boolean isManeuverCompliantWithSettings(Maneuver previousManeuver,
ManeuverWithContext currentManeuverWithContext, Maneuver nextManeuver) {
boolean mainCurveAnalysis = settings.isMainCurveAnalysis();
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverSpeedDetailsRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverSpeedDetailsRetrievalProcessor.java
index 04dc15d7f7d..b7cb426f9d2 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverSpeedDetailsRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/ManeuverSpeedDetailsRetrievalProcessor.java
@@ -87,6 +87,10 @@ public class ManeuverSpeedDetailsRetrievalProcessor
double directionChangeForAnalysisSignum = Math.signum(directionChangeInDegreesForAnalysis);
for (SpeedWithBearingStep bearingStep : maneuverBearingSteps) {
+ if (isAborted()) {
+ break;
+ }
+
currentDirectionChangeSumInDegrees += bearingStep.getCourseChangeInDegrees();
if (previousRoundedTWA != -1
&& Math.signum(currentDirectionChangeSumInDegrees) != directionChangeForAnalysisSignum
@@ -123,6 +127,9 @@ public class ManeuverSpeedDetailsRetrievalProcessor
for (int step = 1, fillingTWA = twaIterationFunction
.apply(previousRoundedTWA); fillingTWA != roundedTWA; fillingTWA = twaIterationFunction
.apply(fillingTWA), ++step) {
+ if (isAborted()) {
+ break;
+ }
if (speedPerTWA[fillingTWA] == 0) {
speedPerTWA[fillingTWA] = previousSpeed
+ diffWithPreviousSpeed * step / diffWithPreviousTWA;
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/MarkPassingRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/MarkPassingRetrievalProcessor.java
index 62ce35b65b2..a3da6e980ad 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/MarkPassingRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/MarkPassingRetrievalProcessor.java
@@ -29,6 +29,9 @@ public class MarkPassingRetrievalProcessor extends AbstractRetrievalProcessor maneuvers = element.getTrackedLegOfCompetitor().getManeuvers(finishTime, false);
for (Maneuver maneuver : maneuvers) {
+ if (isAborted()) {
+ break;
+ }
if (maneuver.isMarkPassing()) {
maneuversWithContext.add(new MarkPassingWithContext(new TrackedLegOfCompetitorWithSpecificTimePointWithContext(
element.getTrackedLegContext(), element.getTrackedLegOfCompetitor(), maneuver.getTimePoint()), maneuver));
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RaceOfCompetitorRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RaceOfCompetitorRetrievalProcessor.java
index d88833c883e..822b73ee064 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RaceOfCompetitorRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RaceOfCompetitorRetrievalProcessor.java
@@ -22,6 +22,9 @@ public class RaceOfCompetitorRetrievalProcessor extends AbstractRetrievalProcess
protected Iterable retrieveData(HasTrackedRaceContext element) {
Collection raceOfCompetitorsWithContext = new ArrayList<>();
for (Competitor competitor : element.getTrackedRace().getRace().getCompetitors()) {
+ if (isAborted()) {
+ break;
+ }
HasRaceOfCompetitorContext raceOfCompetitorWithContext = new RaceOfCompetitorWithContext(element, competitor);
raceOfCompetitorsWithContext.add(raceOfCompetitorWithContext);
}
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorRetrievalProcessor.java
index 9e8ea01aaff..82e87d42dca 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorRetrievalProcessor.java
@@ -22,6 +22,9 @@ public class TrackedLegOfCompetitorRetrievalProcessor extends AbstractRetrievalP
protected Iterable retrieveData(HasTrackedLegContext element) {
Collection trackedLegOfCompetitorsWithContext = new ArrayList<>();
for (Competitor competitor : element.getTrackedRaceContext().getTrackedRace().getRace().getCompetitors()) {
+ if (isAborted()) {
+ break;
+ }
HasTrackedLegOfCompetitorContext trackedLegOfCompetitorWithContext = new TrackedLegOfCompetitorWithContext(element, element.getTrackedLeg().getTrackedLeg(competitor));
trackedLegOfCompetitorsWithContext.add(trackedLegOfCompetitorWithContext);
}
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegRetrievalProcessor.java
index b20f1f62fb5..50cb80cc85f 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegRetrievalProcessor.java
@@ -23,6 +23,9 @@ public class TrackedLegRetrievalProcessor extends AbstractRetrievalProcessor trackedLegsWithContext = new ArrayList<>();
int legNumber = 1;
for (TrackedLeg trackedLeg : element.getTrackedRace().getTrackedLegs()) {
+ if (isAborted()) {
+ break;
+ }
HasTrackedLegContext trackedLegWithContext = new TrackedLegWithContext(element, trackedLeg, legNumber);
trackedLegsWithContext.add(trackedLegWithContext);
legNumber++;
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceRetrievalProcessor.java
index 12c2b9fbbe1..71fa5e11b76 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceRetrievalProcessor.java
@@ -25,7 +25,13 @@ public class TrackedRaceRetrievalProcessor extends AbstractRetrievalProcessor retrieveData(HasLeaderboardContext element) {
Collection trackedRacesWithContext = new ArrayList<>();
for (RaceColumn raceColumn : element.getLeaderboard().getRaceColumns()) {
+ if (isAborted()) {
+ break;
+ }
for (Fleet fleet : raceColumn.getFleets()) {
+ if (isAborted()) {
+ break;
+ }
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
if (trackedRace != null) {
Regatta regatta = trackedRace.getTrackedRegatta().getRegatta();
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/WindFixRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/WindFixRetrievalProcessor.java
index ae337f4561d..fe023f79b92 100755
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/WindFixRetrievalProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/WindFixRetrievalProcessor.java
@@ -33,6 +33,9 @@ public class WindFixRetrievalProcessor extends AbstractRetrievalProcessor windTracksWithContext = new ArrayList<>();
final TrackedRace trackedRace = element.getTrackedRace();
for (final WindSource windSource : trackedRace.getWindSources()) {
+ if (isAborted()) {
+ break;
+ }
if (!trackedRace.getWindSourcesToExclude().contains(windSource)) {
final WindTrack windTrack = trackedRace.getOrCreateWindTrack(windSource);
windTracksWithContext.add(new WindTrackWithContext(element, windTrack, windSource));
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/AbstractParallelAverageAggregationProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/AbstractParallelAverageAggregationProcessor.java
index 18cd52840b7..b1226dd579b 100755
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/AbstractParallelAverageAggregationProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/AbstractParallelAverageAggregationProcessor.java
@@ -64,6 +64,9 @@ public abstract class AbstractParallelAverageAggregationProcessor minAggregation = minAggregationProcessor.getResult();
Map maxAggregation = maxAggregationProcessor.getResult();
for (Entry sumAggregationEntry : sumAggregation.entrySet()) {
+ if (isAborted()) {
+ break;
+ }
GroupKey key = sumAggregationEntry.getKey();
result.put(key, new AverageWithStatsImpl<>(
/* average */ divide(sumAggregationEntry.getValue(), elementAmountPerKey.get(key).longValue()),
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/AbstractParallelSumAggregationProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/AbstractParallelSumAggregationProcessor.java
index a2a9f27cdc6..debe1785c53 100755
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/AbstractParallelSumAggregationProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/AbstractParallelSumAggregationProcessor.java
@@ -19,8 +19,6 @@ public abstract class AbstractParallelSumAggregationProcessor extends
super(executor, resultReceivers, "Sum");
results = new HashMap<>();
}
-
- protected abstract T add(T t1, T t2);
@Override
protected void handleElement(GroupedDataEntry element) {
@@ -31,6 +29,8 @@ public abstract class AbstractParallelSumAggregationProcessor extends
results.put(key, add(results.get(key), element.getDataEntry()));
}
}
+
+ protected abstract T add(T t1, T t2);
@Override
protected Map getResult() {
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/ParallelBearingAverageDegreesAggregationProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/ParallelBearingAverageDegreesAggregationProcessor.java
index 9ed6ac09b6b..cabff7897b4 100755
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/ParallelBearingAverageDegreesAggregationProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/ParallelBearingAverageDegreesAggregationProcessor.java
@@ -47,6 +47,9 @@ public class ParallelBearingAverageDegreesAggregationProcessor
protected Map aggregateResult() {
Map result = new HashMap<>();
for (Entry clusterEntry : results.entrySet()) {
+ if (isAborted()) {
+ break;
+ }
GroupKey key = clusterEntry.getKey();
result.put(key, clusterEntry.getValue().getAverage().getDegrees());
}
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/ParallelDistanceMedianAggregationProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/ParallelDistanceMedianAggregationProcessor.java
index b208c2e5e85..0147a22c63c 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/ParallelDistanceMedianAggregationProcessor.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/aggregators/ParallelDistanceMedianAggregationProcessor.java
@@ -50,6 +50,9 @@ public class ParallelDistanceMedianAggregationProcessor
protected Map aggregateResult() {
Map result = new HashMap<>();
for (Entry> groupedValuesEntry : groupedValues.entrySet()) {
+ if (isAborted()) {
+ break;
+ }
result.put(groupedValuesEntry.getKey(), getMedianOf(groupedValuesEntry.getValue()));
}
return result;
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardWithContext.java
index a0c6dc0d2b8..9ee53091241 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardWithContext.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardWithContext.java
@@ -4,17 +4,14 @@ import com.sap.sailing.datamining.data.HasLeaderboardContext;
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.leaderboard.Leaderboard;
-import com.sap.sailing.domain.polars.PolarDataService;
public class LeaderboardWithContext implements HasLeaderboardContext {
private final Leaderboard leaderboard;
private final HasLeaderboardGroupContext leaderboardGroupContext;
- private final PolarDataService polarDataService;
- public LeaderboardWithContext(Leaderboard leaderboard, HasLeaderboardGroupContext leaderboardGroupContext, PolarDataService polarDataService) {
+ public LeaderboardWithContext(Leaderboard leaderboard, HasLeaderboardGroupContext leaderboardGroupContext) {
this.leaderboard = leaderboard;
this.leaderboardGroupContext = leaderboardGroupContext;
- this.polarDataService = polarDataService;
}
public HasLeaderboardGroupContext getLeaderboardGroupContext() {
@@ -31,11 +28,6 @@ public class LeaderboardWithContext implements HasLeaderboardContext {
return getLeaderboard().getBoatClass();
}
- @Override
- public PolarDataService getPolarDataService() {
- return polarDataService;
- }
-
@Override
public String getName() {
return getLeaderboard().getName();
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceOfCompetitorWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceOfCompetitorWithContext.java
index e3258e846e6..a49907755db 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceOfCompetitorWithContext.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceOfCompetitorWithContext.java
@@ -1,5 +1,9 @@
package com.sap.sailing.datamining.impl.data;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import com.sap.sailing.datamining.Activator;
@@ -25,9 +29,12 @@ import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindPositionMode;
import com.sap.sse.common.Distance;
+import com.sap.sse.common.Duration;
import com.sap.sse.common.Speed;
import com.sap.sse.common.TimePoint;
+import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
+import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.datamining.data.Cluster;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
@@ -240,50 +247,56 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
@Override
public int getNumberOfManeuvers() {
- return getNumberOfTacks() + getNumberOfJibes();
+ Set maneuverTypes = new HashSet<>();
+ maneuverTypes.add(ManeuverType.TACK);
+ maneuverTypes.add(ManeuverType.JIBE);
+ return getNumberOf(maneuverTypes);
}
@Override
public int getNumberOfTacks() {
- return getNumberOf(ManeuverType.TACK);
+ return getNumberOf(Collections.singleton(ManeuverType.TACK));
}
@Override
public int getNumberOfJibes() {
- return getNumberOf(ManeuverType.JIBE);
+ return getNumberOf(Collections.singleton(ManeuverType.JIBE));
}
@Override
public int getNumberOfPenaltyCircles() {
- return getNumberOf(ManeuverType.PENALTY_CIRCLE);
+ return getNumberOf(Collections.singleton(ManeuverType.PENALTY_CIRCLE));
}
- private int getNumberOf(ManeuverType maneuverType) {
+ private int getNumberOf(Set maneuverTypes) {
int number = 0;
TrackedRace trackedRace = getTrackedRace();
if (trackedRace != null) {
+ TimePoint from = null;
+ TimePoint to = null;
+ Competitor competitor = getCompetitor();
Course course = trackedRace.getRace().getCourse();
- Waypoint startWaypoint = course.getFirstWaypoint();
- MarkPassing startPassing = trackedRace.getMarkPassing(getCompetitor(), startWaypoint);
- TimePoint start = startPassing != null ? startPassing.getTimePoint() : trackedRace.getStartOfRace();
+ List waypoints = Util.createList(course.getWaypoints());
- Waypoint finishWaypoint = course.getLastWaypoint();
- MarkPassing finishPassing = trackedRace.getMarkPassing(getCompetitor(), finishWaypoint);
- TimePoint end;
- if (finishPassing != null) {
- end = finishPassing.getTimePoint();
- } else {
- end = trackedRace.getEndOfRace();
- if (end == null) {
- TimePoint endOfTracking = trackedRace.getEndOfTracking();
- TimePoint now = MillisecondsTimePoint.now();
- end = endOfTracking != null && endOfTracking.before(now) ? endOfTracking : now;
+ int fromIndex = 0;
+ while (fromIndex < waypoints.size()) {
+ MarkPassing markPassing = trackedRace.getMarkPassing(competitor, waypoints.get(fromIndex));
+ TimePoint passingTime = markPassing != null ? markPassing.getTimePoint() : null;
+ if (passingTime != null) {
+ if (from == null) {
+ from = passingTime;
+ } else {
+ to = passingTime;
+ }
}
+ fromIndex++;
}
- for (Maneuver maneuver : trackedRace.getManeuvers(getCompetitor(), start, end, false)) {
- if (maneuver.getType() == maneuverType) {
- number++;
+ if (from != null && to != null) {
+ for (Maneuver maneuver : trackedRace.getManeuvers(getCompetitor(), from, to, false)) {
+ if (maneuverTypes.contains(maneuver.getType())) {
+ number++;
+ }
}
}
}
@@ -346,4 +359,18 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext {
return distance / length;
}
+ @Override
+ public Duration getDuration() {
+ Duration duration = null;
+ TrackedRace race = getTrackedRace();
+ Course course = race.getRace().getCourse();
+ MarkPassing startPassing = race.getMarkPassing(competitor, course.getFirstWaypoint());
+ MarkPassing finishPassing = race.getMarkPassing(competitor, course.getLastWaypoint());
+ if (startPassing != null && finishPassing != null) {
+ long durationMillis = finishPassing.getTimePoint().asMillis() - startPassing.getTimePoint().asMillis();
+ duration = new MillisecondsDurationImpl(durationMillis);
+ }
+ return duration;
+ }
+
}
\ No newline at end of file
diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java
index 89de0e2091e..445e93d1d39 100644
--- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java
+++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java
@@ -17,8 +17,10 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.LineDetails;
import com.sap.sailing.domain.tracking.TrackedRace;
+import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
+import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class TrackedRaceWithContext implements HasTrackedRaceContext {
@@ -113,6 +115,26 @@ public class TrackedRaceWithContext implements HasTrackedRaceContext {
public Boolean isTracked() {
return getTrackedRace().hasStarted(MillisecondsTimePoint.now());
}
+
+ @Override
+ public Duration getDuration() {
+ Duration duration = null;
+ TrackedRace race = getTrackedRace();
+ TimePoint start = race.getStartOfRace();
+ if (start == null) {
+ start = race.getStartOfTracking();
+ }
+ if (start != null) {
+ TimePoint end = race.getEndOfRace();
+ if (end == null) {
+ end = race.getEndOfTracking();
+ }
+ if (end != null) {
+ duration = new MillisecondsDurationImpl(end.asMillis() - start.asMillis());
+ }
+ }
+ return duration;
+ }
@Override
public int getNumberOfCompetitorFixes() {
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/maneuverdetection/impl/IncrementalManeuverComputationTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/maneuverdetection/impl/IncrementalManeuverComputationTest.java
index a7aceba5379..572727bfa3b 100644
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/maneuverdetection/impl/IncrementalManeuverComputationTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/maneuverdetection/impl/IncrementalManeuverComputationTest.java
@@ -130,11 +130,14 @@ public class IncrementalManeuverComputationTest extends AbstractManeuverDetectio
performanceMeasurementStartedAt = System.currentTimeMillis();
List normallyDetectedManeuvers = normalManeuverDetector.detectManeuvers();
long millisForNormalManeuverDetection = System.currentTimeMillis() - performanceMeasurementStartedAt;
+ int performanceBenefitOfIncrementalManeuverDetectionInPercent = (int) ((1.0 * (millisForNormalManeuverDetection - millisForIncrementalManeuverDetection)
+ / millisForNormalManeuverDetection) * 100);
assertEquals("Incrementally calculated maneuvers differ from normally calculated maneuvers",
normallyDetectedManeuvers, incrementallyDetectedManeuvers);
assertTrue(
- "Incremental maneuver detection was not 30% faster in detecting maneuvers incrementally, than the full maneuver detection",
- millisForIncrementalManeuverDetection * 1.3 < millisForNormalManeuverDetection);
+ "Incremental maneuver detection was not 20% faster in detecting maneuvers incrementally, than the full maneuver detection. The actual performance benefit was: "
+ + performanceBenefitOfIncrementalManeuverDetectionInPercent + "%",
+ performanceBenefitOfIncrementalManeuverDetectionInPercent >= 20);
}
}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RouteAssemblyTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RouteAssemblyTest.java
index 9906f341350..5983e1f4f22 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RouteAssemblyTest.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/RouteAssemblyTest.java
@@ -15,6 +15,7 @@ import com.sap.sailing.domain.tractracadapter.LoadingQueueDoneCallBack;
import com.sap.sailing.domain.tractracadapter.Receiver;
import com.sap.sse.common.Util;
import com.tractrac.model.lib.api.route.IControlRoute;
+import com.tractrac.model.lib.api.route.IPathRoute;
import com.tractrac.subscription.lib.api.control.IControlRouteChangeListener;
public class RouteAssemblyTest extends AbstractTracTracLiveTest {
@@ -66,6 +67,11 @@ public class RouteAssemblyTest extends AbstractTracTracLiveTest {
first = false;
}
}
+
+ @Override
+ public void gotRouteChange(IPathRoute pathRoute, long timeStamp) {
+ // will never be invoked for sailing events
+ }
});
}
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java
index 8f6a279789b..bb816ebb05c 100755
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java
+++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java
@@ -37,6 +37,7 @@ import com.tractrac.model.lib.api.event.IEvent;
import com.tractrac.model.lib.api.event.IRace;
import com.tractrac.model.lib.api.route.IControl;
import com.tractrac.model.lib.api.route.IControlRoute;
+import com.tractrac.model.lib.api.route.IPathRoute;
import com.tractrac.model.lib.api.route.IRoute;
import com.tractrac.subscription.lib.api.IEventSubscriber;
import com.tractrac.subscription.lib.api.IRaceSubscriber;
@@ -97,6 +98,13 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue(controlRoute, timeStamp, null));
}
+
+ @Override
+ public void gotRouteChange(IPathRoute pathRoute, long timeStamp) {
+ // will never be invoked for sailing events; Jorge Llodra (2018-07-30):
+ // "The IControlRouteChangeListener has been extended adding a new method to get updates of a
+ // IPathRoute. If you are managing "sailing events" this method will never be invoked."
+ }
};
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/CompleteManeuverCurveWithEstimationData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/CompleteManeuverCurveWithEstimationData.java
index 9738718cca4..35ee095e22f 100644
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/CompleteManeuverCurveWithEstimationData.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/CompleteManeuverCurveWithEstimationData.java
@@ -100,9 +100,9 @@ public interface CompleteManeuverCurveWithEstimationData extends Timed, Position
Distance getDistanceToClosestMark();
- Double getDeviationOfManeuverAngleFromTargetTackAngleInDegrees();
+ Double getTargetTackAngleInDegrees();
- Double getDeviationOfManeuverAngleFromTargetJibeAngleInDegrees();
+ Double getTargetJibeAngleInDegrees();
/**
* Gets whether a mark was crossed within the maneuver curve.
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/CompleteManeuverCurveWithEstimationDataImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/CompleteManeuverCurveWithEstimationDataImpl.java
index 89c43715903..89459a483a5 100644
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/CompleteManeuverCurveWithEstimationDataImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/CompleteManeuverCurveWithEstimationDataImpl.java
@@ -27,14 +27,15 @@ public class CompleteManeuverCurveWithEstimationDataImpl implements CompleteMane
private final boolean markPassing;
private final Position position;
private final Distance distanceToClosestMark;
- private final Double deviationOfManeuverAngleFromTargetTackAngleInDegrees;
- private final Double deviationOfManeuverAngleFromTargetJibeAngleInDegrees;
+ private final Double targetTackAngleInDegrees;
+ private final Double targetJibeAngleInDegrees;
public CompleteManeuverCurveWithEstimationDataImpl(Position position, ManeuverMainCurveWithEstimationData mainCurve,
ManeuverCurveWithUnstableCourseAndSpeedWithEstimationData curveWithUnstableCourseAndSpeed, Wind wind,
int tackingCount, int jibingCount, boolean maneuverStartsByRunningAwayFromWind,
Bearing relativeBearingToNextMarkBeforeManeuver, Bearing relativeBearingToNextMarkAfterManeuver,
- boolean markPassing, Distance distanceToClosestMark, Double deviationOfManeuverAngleFromTargetTackAngleInDegrees, Double deviationOfManeuverAngleFromTargetJibeAngleInDegrees) {
+ boolean markPassing, Distance distanceToClosestMark, Double targetTackAngleInDegrees,
+ Double targetJibeAngleInDegrees) {
this.position = position;
this.mainCurve = mainCurve;
this.curveWithUnstableCourseAndSpeed = curveWithUnstableCourseAndSpeed;
@@ -46,8 +47,8 @@ public class CompleteManeuverCurveWithEstimationDataImpl implements CompleteMane
this.relativeBearingToNextMarkAfterManeuver = relativeBearingToNextMarkAfterManeuver;
this.markPassing = markPassing;
this.distanceToClosestMark = distanceToClosestMark;
- this.deviationOfManeuverAngleFromTargetTackAngleInDegrees = deviationOfManeuverAngleFromTargetTackAngleInDegrees;
- this.deviationOfManeuverAngleFromTargetJibeAngleInDegrees = deviationOfManeuverAngleFromTargetJibeAngleInDegrees;
+ this.targetTackAngleInDegrees = targetTackAngleInDegrees;
+ this.targetJibeAngleInDegrees = targetJibeAngleInDegrees;
}
@Override
@@ -99,20 +100,20 @@ public class CompleteManeuverCurveWithEstimationDataImpl implements CompleteMane
public Position getPosition() {
return position;
}
-
+
@Override
public Distance getDistanceToClosestMark() {
return distanceToClosestMark;
}
-
+
@Override
- public Double getDeviationOfManeuverAngleFromTargetTackAngleInDegrees() {
- return deviationOfManeuverAngleFromTargetTackAngleInDegrees;
+ public Double getTargetTackAngleInDegrees() {
+ return targetTackAngleInDegrees;
}
-
+
@Override
- public Double getDeviationOfManeuverAngleFromTargetJibeAngleInDegrees() {
- return deviationOfManeuverAngleFromTargetJibeAngleInDegrees;
+ public Double getTargetJibeAngleInDegrees() {
+ return targetJibeAngleInDegrees;
}
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorWithEstimationDataSupportDecoratorImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorWithEstimationDataSupportDecoratorImpl.java
index 14d8b767aea..8e13e8fe62e 100644
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorWithEstimationDataSupportDecoratorImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorWithEstimationDataSupportDecoratorImpl.java
@@ -278,7 +278,8 @@ public class ManeuverDetectorWithEstimationDataSupportDecoratorImpl
stepWithHighestSpeed.getSpeedWithBearing(), stepWithHighestSpeed.getTimePoint(),
maneuverCurve.getMainCurveBoundaries().getTimePoint(),
maneuverCurve.getMainCurveBoundaries().getMaxTurningRateInDegreesPerSecond(), courseAtMaxTurningRate,
- distanceSailedWithinManeuver, projectedManeuverLoss.getDistanceSailedProjectedOnMiddleManeuverAngle(), distanceSailedIfNotManeuvering,
+ distanceSailedWithinManeuver, projectedManeuverLoss.getDistanceSailedProjectedOnMiddleManeuverAngle(),
+ distanceSailedIfNotManeuvering,
projectedManeuverLoss.getDistanceSailedIfNotManeuveringProjectedOnMiddleManeuverAngle(),
Math.abs(maneuverCurve.getMainCurveBoundaries().getDirectionChangeInDegrees())
/ maneuverCurve.getMainCurveBoundaries().getDuration().asSeconds(),
@@ -338,9 +339,9 @@ public class ManeuverDetectorWithEstimationDataSupportDecoratorImpl
gpsFixesCountFromPreviousManeuver, durationAndAvgSpeedWithBearingAfter.getB(),
durationAndAvgSpeedWithBearingAfter.getA(), gpsFixesCountToNextManeuver, distanceSailedWithinManeuver,
projectedManeuverLoss.getDistanceSailedProjectedOnMiddleManeuverAngle(), distanceSailedIfNotManeuvering,
- projectedManeuverLoss.getDistanceSailedIfNotManeuveringProjectedOnMiddleManeuverAngle(), gpsFixCountWithinWholeCurve,
- longestGpsFixIntervalBetweenTwoFixes, intervalBetweenLastFixOfCurveAndNextFix,
- intervalBetweenFirstFixOfCurveAndPreviousFix);
+ projectedManeuverLoss.getDistanceSailedIfNotManeuveringProjectedOnMiddleManeuverAngle(),
+ gpsFixCountWithinWholeCurve, longestGpsFixIntervalBetweenTwoFixes,
+ intervalBetweenLastFixOfCurveAndNextFix, intervalBetweenFirstFixOfCurveAndPreviousFix);
TimePoint maneuverTimePoint = maneuverCurve.getMainCurveBoundaries().getTimePoint();
Position maneuverPosition = maneuverDetector.track.getEstimatedPosition(maneuverTimePoint,
/* extrapolate */false);
@@ -357,8 +358,8 @@ public class ManeuverDetectorWithEstimationDataSupportDecoratorImpl
.getManeuverCurveWithStableSpeedAndCourseBoundaries().getSpeedWithBearingAfter().getBearing());
BoatClass boatClass = maneuverDetector.trackedRace.getRace().getBoatOfCompetitor(maneuverDetector.competitor)
.getBoatClass();
- Double deviationFromTackAngle = null;
- Double deviationFromJibeAngle = null;
+ Double targetTackAngle = null;
+ Double targetJibeAngle = null;
Speed boatSpeed = curveWithUnstableCourseAndSpeed.getSpeedWithBearingBefore()
.compareTo(curveWithUnstableCourseAndSpeed.getSpeedWithBearingAfter()) < 0
? curveWithUnstableCourseAndSpeed.getSpeedWithBearingBefore()
@@ -369,11 +370,11 @@ public class ManeuverDetectorWithEstimationDataSupportDecoratorImpl
SpeedWithBearingWithConfidence closestJibeTwa = polarDataService.getClosestTwaTws(ManeuverType.JIBE,
boatSpeed, curveWithUnstableCourseAndSpeed.getDirectionChangeInDegrees(), boatClass);
if (closestTackTwa != null) {
- deviationFromTackAngle = polarDataService.getManeuverAngleInDegreesFromTwa(
+ targetTackAngle = polarDataService.getManeuverAngleInDegreesFromTwa(
closestTackTwa.getObject().getBearing().getDegrees(), ManeuverType.TACK);
}
if (closestJibeTwa != null) {
- deviationFromJibeAngle = polarDataService.getManeuverAngleInDegreesFromTwa(
+ targetJibeAngle = polarDataService.getManeuverAngleInDegreesFromTwa(
closestJibeTwa.getObject().getBearing().getDegrees(), ManeuverType.JIBE);
}
}
@@ -383,7 +384,7 @@ public class ManeuverDetectorWithEstimationDataSupportDecoratorImpl
curveWithUnstableCourseAndSpeed, wind, numberOfTacks, numberOfJibes,
maneuverStartsByRunningAwayFromWind, relativeBearingToNextMarkPassingBeforeManeuver,
relativeBearingToNextMarkPassingAfterManeuver, maneuverCurve.isMarkPassing(), closestDistanceToMark,
- deviationFromTackAngle, deviationFromJibeAngle);
+ targetTackAngle, targetJibeAngle);
}
public Distance getClosestDistanceToMark(TimePoint timePoint) {
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/CandidateFinder.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/CandidateFinder.java
index a587a968b97..b67baa44004 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/CandidateFinder.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/CandidateFinder.java
@@ -53,6 +53,13 @@ public interface CandidateFinder {
*/
Map, Iterable>> getCandidateDeltasAfterRaceStartTimeChange();
+ /**
+ * Notifies this finder about the race's start of tracking time having changed. In case of a race that infers
+ * the race start time from the start mark passings, a change in start of tracking needs to adjust the time range
+ * in which candidates are considered valid.
+ */
+ Map, Iterable>> getCandidateDeltasAfterStartOfTrackingChange();
+
/**
* Notifies this finder about the race's finished time having changed. The candidates collections are adjusted
* accordingly: new candidates may be added if the finished time was moved to a later point in time and therefore
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingUpdateListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingUpdateListener.java
index 185d153b6d6..00b1a8be99f 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingUpdateListener.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingUpdateListener.java
@@ -195,6 +195,25 @@ public class MarkPassingUpdateListener extends AbstractRaceChangeListener {
});
}
+ @Override
+ public void startOfTrackingChanged(TimePoint oldStartOfTracking, TimePoint newStartOfTracking) {
+ markPassingCalculator.enqueueUpdate(new StorePositionUpdateStrategy() {
+ @Override
+ public void storePositionUpdate(Map> competitorFixes,
+ Map> markFixes, List addedWaypoints, List removedWaypoints,
+ IntHolder smallestChangedWaypointIndex,
+ List> fixedMarkPassings,
+ List> removedMarkPassings,
+ List> suppressedMarkPassings, List unSuppressedMarkPassings, CandidateFinder candidateFinder, CandidateChooser candidateChooser) {
+ final Map, Iterable>> newAndRemovedCandidatesPerCompetitor =
+ candidateFinder.getCandidateDeltasAfterStartOfTrackingChange();
+ for (final Entry, Iterable>> i : newAndRemovedCandidatesPerCompetitor.entrySet()) {
+ candidateChooser.calculateMarkPassDeltas(i.getKey(), i.getValue().getA(), i.getValue().getB());
+ }
+ }
+ });
+ }
+
@Override
public void finishedTimeChanged(TimePoint oldFinishedTime, TimePoint newFinishedTime) {
markPassingCalculator.enqueueUpdate(new StorePositionUpdateStrategy() {
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/impl/CandidateFinderImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/impl/CandidateFinderImpl.java
index 3d7a67bb366..171ddb82cf9 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/impl/CandidateFinderImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/impl/CandidateFinderImpl.java
@@ -37,6 +37,7 @@ import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.MarkPositionAtTimePointCache;
+import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.MarkPositionAtTimePointCacheImpl;
import com.sap.sailing.domain.tracking.impl.TimedComparator;
import com.sap.sse.common.Bearing;
@@ -1455,12 +1456,26 @@ public class CandidateFinderImpl implements CandidateFinder {
/**
* If the {@link #race}'s regatta is configured to infer the start times from start mark passings then {@code null}
* must be tolerated as a value for {@code from}, leading to an open interval starting at the
- * {@link TimePoint#BeginningOfTime beginning of time}. However, if the start time is expected to be set and not
- * inferred, mark passings need to be detected only from the start minus some tolerance interval. In this case,
- * an interval that has {@code null} as its {@code from} time point and thus is considered empty will be returned.
- * It hence returns {@code null} from its {@link TimeRangeWithNullStartMeaningEmpty#getTimeRangeOrNull()} method.
+ * {@link TrackedRace#getStartOfTracking()} or, if not set, the {@link TimePoint#BeginningOfTime beginning of time}.
+ * However, if the start time is expected to be set and not inferred, mark passings need to be detected only from
+ * the start minus some tolerance interval. In this case, an interval that has {@code null} as its {@code from} time
+ * point and thus is considered empty will be returned. It hence returns {@code null} from its
+ * {@link TimeRangeWithNullStartMeaningEmpty#getTimeRangeOrNull()} method.
*/
private TimeRangeWithNullStartMeaningEmpty getTimeRangeOrNull(TimePoint from, TimePoint to) {
+ final TimePoint effectiveFrom = getEffectiveFrom(from);
+ return new TimeRangeWithNullStartMeaningEmpty(effectiveFrom, to);
+ }
+
+ /**
+ * If the {@link #race}'s regatta is configured to infer the start times from start mark passings then {@code null}
+ * must be tolerated as a value for {@code from}, leading to an open interval starting at the
+ * {@link TrackedRace#getStartOfTracking()} or, if not set, the {@link TimePoint#BeginningOfTime beginning of time}.
+ * However, if the start time is expected to be set and not inferred, mark passings need to be detected only from
+ * the start minus some tolerance interval. In this case, for an interval that has {@code null} as its {@code from} time
+ * point and thus is considered empty, {@code null} will be returned.
+ */
+ private TimePoint getEffectiveFrom(TimePoint from) {
final TimePoint effectiveFrom;
if (from == null && race.getTrackedRegatta().getRegatta().useStartTimeInference()) {
// need to check the whole track to be able to find start mark passings
@@ -1470,15 +1485,22 @@ public class CandidateFinderImpl implements CandidateFinder {
} else {
effectiveFrom = from;
}
- return new TimeRangeWithNullStartMeaningEmpty(effectiveFrom, to);
+ return effectiveFrom;
}
@Override
public Map, Iterable>> getCandidateDeltasAfterRaceStartTimeChange() {
- final Map, Iterable>> result;
final TimePoint newNonInferredStartTime = race.getStartOfRace(/* inferred */ false);
final TimePoint newTimePointWhenToStartConsideringCandidates = getTimePointWhenToStartConsideringCandidates(newNonInferredStartTime);
- final TimeRangeWithNullStartMeaningEmpty newTimeRange = timeRangeForValidCandidates.getWithNewFrom(newTimePointWhenToStartConsideringCandidates);
+ final TimePoint newEffectiveTimePointWhenToStartConsideringCandidates = getEffectiveFrom(newTimePointWhenToStartConsideringCandidates);
+ final TimeRangeWithNullStartMeaningEmpty newTimeRange = timeRangeForValidCandidates.getWithNewFrom(newEffectiveTimePointWhenToStartConsideringCandidates);
+ return getCandidateDeltasAfterTimingChange(newEffectiveTimePointWhenToStartConsideringCandidates, newTimeRange);
+ }
+
+ private Map, Iterable>> getCandidateDeltasAfterTimingChange(
+ final TimePoint newTimePointWhenToStartConsideringCandidates,
+ final TimeRangeWithNullStartMeaningEmpty newTimeRange) {
+ final Map, Iterable>> result;
if (!Util.equalsWithNull(newTimeRange, timeRangeForValidCandidates)) {
if (newTimeRange.getTimeRangeOrNull() == null) {
result = clearAllCandidates();
@@ -1499,6 +1521,15 @@ public class CandidateFinderImpl implements CandidateFinder {
return result;
}
+ @Override
+ public Map, Iterable>> getCandidateDeltasAfterStartOfTrackingChange() {
+ final TimePoint newNonInferredStartTime = race.getStartOfRace(/* inferred */ false);
+ final TimePoint newTimePointWhenToStartConsideringCandidates = getTimePointWhenToStartConsideringCandidates(newNonInferredStartTime);
+ final TimePoint newEffectiveTimePointWhenToStartConsideringCandidates = getEffectiveFrom(newTimePointWhenToStartConsideringCandidates);
+ final TimeRangeWithNullStartMeaningEmpty newTimeRange = timeRangeForValidCandidates.getWithNewFrom(newEffectiveTimePointWhenToStartConsideringCandidates);
+ return getCandidateDeltasAfterTimingChange(newEffectiveTimePointWhenToStartConsideringCandidates, newTimeRange);
+ }
+
@Override
public Map, Iterable>> getCandidateDeltasAfterRaceFinishedTimeChange(
TimePoint oldFinishedTime, TimePoint newFinishedTime) {
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CrossTrackErrorCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CrossTrackErrorCache.java
index 850dcb7ed62..572a27ff89a 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CrossTrackErrorCache.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CrossTrackErrorCache.java
@@ -205,6 +205,7 @@ public class CrossTrackErrorCache extends AbstractRaceChangeListener {
owner.addListener(this);
}
+ @FunctionalInterface
private interface CrossTrackErrorMeterRetriever {
double getDistanceInMetersSumFromStart(CrossTrackErrorSumAndNumberOfFixes cacheEntry);
}
@@ -220,12 +221,7 @@ public class CrossTrackErrorCache extends AbstractRaceChangeListener {
*/
public Distance getAverageAbsoluteCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, boolean upwindOnly,
boolean waitForLatest) throws NoWindException {
- CrossTrackErrorMeterRetriever absoluteMetersRetriever = new CrossTrackErrorMeterRetriever() {
- @Override
- public double getDistanceInMetersSumFromStart(CrossTrackErrorSumAndNumberOfFixes cacheEntry) {
- return cacheEntry.getAbsoluteDistanceInMetersSumFromStart();
- }
- };
+ CrossTrackErrorMeterRetriever absoluteMetersRetriever = cacheEntry->cacheEntry.getAbsoluteDistanceInMetersSumFromStart();
return getAbsoluteOrSignedAverageCrossTrackError(competitor, from, to, upwindOnly, waitForLatest, absoluteMetersRetriever);
}
@@ -240,20 +236,15 @@ public class CrossTrackErrorCache extends AbstractRaceChangeListener {
*/
public Distance getAverageSignedCrossTrackError(Competitor competitor, TimePoint from, TimePoint to, boolean upwindOnly,
boolean waitForLatest) throws NoWindException {
- CrossTrackErrorMeterRetriever signedMetersRetriever = new CrossTrackErrorMeterRetriever() {
- @Override
- public double getDistanceInMetersSumFromStart(CrossTrackErrorSumAndNumberOfFixes cacheEntry) {
- return cacheEntry.getSignedDistanceInMetersSumFromStart();
- }
- };
+ CrossTrackErrorMeterRetriever signedMetersRetriever = cacheEntry->cacheEntry.getSignedDistanceInMetersSumFromStart();
return getAbsoluteOrSignedAverageCrossTrackError(competitor, from, to, upwindOnly, waitForLatest, signedMetersRetriever);
}
/**
- * @param absoluteMetersRetriever determines whether the absolute or signed cross track error will be aggregated
+ * @param absoluteOrSignedMetersRetriever determines whether the absolute or signed cross track error will be aggregated
*/
private Distance getAbsoluteOrSignedAverageCrossTrackError(Competitor competitor, TimePoint from, TimePoint to,
- boolean upwindOnly, boolean waitForLatest, CrossTrackErrorMeterRetriever absoluteMetersRetriever)
+ boolean upwindOnly, boolean waitForLatest, CrossTrackErrorMeterRetriever absoluteOrSignedMetersRetriever)
throws NoWindException {
Track cacheForCompetitor = cachePerCompetitor.get(competitor, waitForLatest);
double distanceInMeters = 0;
@@ -268,7 +259,7 @@ public class CrossTrackErrorCache extends AbstractRaceChangeListener {
final MarkPassing legStartMarkPassing = owner.getMarkPassing(competitor, leg.getFrom());
if (legStartMarkPassing != null) {
if (!upwindOnly || trackedLeg.getLegType(legStartMarkPassing.getTimePoint()) == LegType.UPWIND) {
- TimePoint start;
+ final TimePoint start;
final TimePoint legStart = legStartMarkPassing.getTimePoint();
if (legStart.compareTo(from) < 0) {
// the interval requested starts after this leg's start:
@@ -277,7 +268,7 @@ public class CrossTrackErrorCache extends AbstractRaceChangeListener {
start = legStart;
}
final MarkPassing legEndMarkPassing = owner.getMarkPassing(competitor, leg.getTo());
- TimePoint end;
+ final TimePoint end;
if (legEndMarkPassing == null || legEndMarkPassing.getTimePoint().compareTo(to) >= 0) {
// no next mark passing, or next mark passing is beyond the "to" time point; aggregate up to "to"
end = to;
@@ -294,7 +285,7 @@ public class CrossTrackErrorCache extends AbstractRaceChangeListener {
}
CrossTrackErrorSumAndNumberOfFixes endAggregate = cacheForCompetitor.getLastFixAtOrBefore(end);
if (endAggregate != null) {
- distanceInMeters += absoluteMetersRetriever.getDistanceInMetersSumFromStart(endAggregate) - absoluteMetersRetriever.getDistanceInMetersSumFromStart(startAggregate);
+ distanceInMeters += absoluteOrSignedMetersRetriever.getDistanceInMetersSumFromStart(endAggregate) - absoluteOrSignedMetersRetriever.getDistanceInMetersSumFromStart(startAggregate);
count += endAggregate.getFixCountFromStart() - startAggregate.getFixCountFromStart();
startAggregate = endAggregate;
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/AutoPlayConfiguration.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/AutoPlayConfiguration.java
index 349d9ba9ac7..b4cbfeaf8cb 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/AutoPlayConfiguration.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/configs/AutoPlayConfiguration.java
@@ -1,10 +1,11 @@
package com.sap.sailing.gwt.autoplay.client.configs;
import com.google.gwt.http.client.UrlBuilder;
-import com.google.gwt.user.client.Window;
import com.sap.sailing.gwt.autoplay.client.app.AutoPlayClientFactory;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
+import com.sap.sse.gwt.client.Notification;
+import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
import com.sap.sse.gwt.settings.UrlBuilderUtil;
@@ -21,7 +22,7 @@ public abstract class AutoPlayConfiguration {
public void openSettingsDialog(EventDTO selectedEvent, StrippedLeaderboardDTO leaderboard,
OnSettingsCallback holder, PerspectiveCompositeSettings> settings, AutoPlayContextDefinition apcd,
UserService userService) {
- Window.alert("This configuration does not have settings");
+ Notification.notify("This configuration does not have settings", NotificationType.WARNING);
}
/**
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html
index fa28a560f40..aa3858de21b 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html
@@ -6,8 +6,13 @@
July 2018
-
In RaceBoard.html there is a new feature for maneuver loss visualization. There is a setting in the map settings and in the maneuver pop up.
+
The Maneuver Table now uses the same color coding for competitors as the leaderboard to help
+ recognize competitor tracks for selected maneuvers more easily.
+
In RaceBoard.html there is a new feature for maneuver loss visualization. There is a setting in the map settings and in the maneuver pop up.
In RaceBoard.html when zooming into a specific time range, the time slider will provide a "reset zoom" button in expanded mode.
+
Issues with sporadic incorrect zoom/pan states in the Race Board / race viewer have been fixed.
+
Fixed an issue with the "Winning Lanes" mode for large races that could lead to full tails for
+ all competitors to be loaded instead of only the ones for the podium competitors.
");
+ }
+ }, SortingOrder.ASCENDING) {
@Override
public InvertibleComparator getComparator() {
return comparator;
@@ -280,8 +292,8 @@ public class ManeuverTablePanel extends AbstractCompositeComponent> entry : cachedData.entrySet()) {
for (ManeuverDTO maneuver : entry.getValue()) {
if (settings.getSelectedManeuverTypes().contains(maneuver.getType())) {
- data.add(new ManeuverTableData(entry.getKey(), maneuver));
+ final Color competitorColor = competitorSelectionModel.getColor(entry.getKey(), raceIdentifier);
+ data.add(new ManeuverTableData(entry.getKey(), competitorColor.getAsHtml(), maneuver));
}
}
}
@@ -427,15 +440,12 @@ public class ManeuverTablePanel extends AbstractCompositeComponent {
private final AsyncActionsExecutor asyncActionsExecutor;
- private final RegattaAndRaceIdentifier raceIdentifier;
private final SailingServiceAsync sailingService;
private CachedManeuverTableDataProvider(final TimeRangeProvider timeRangeProvider, final Timer timer,
- final RegattaAndRaceIdentifier raceIdentifier, final SailingServiceAsync sailingService,
- final AsyncActionsExecutor asyncActionsExecutor) {
+ final SailingServiceAsync sailingService, final AsyncActionsExecutor asyncActionsExecutor) {
super(timeRangeProvider, timer, m -> m.getTimePoint(), LOADING_OFFSET_TO_NEXT_MANEUVER_PROVIDER, true);
this.asyncActionsExecutor = asyncActionsExecutor;
- this.raceIdentifier = raceIdentifier;
this.sailingService = sailingService;
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboardedit/EditableLeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboardedit/EditableLeaderboardPanel.java
index da72ccf8fb1..df0f5cc9023 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboardedit/EditableLeaderboardPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboardedit/EditableLeaderboardPanel.java
@@ -31,7 +31,6 @@ import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.Header;
import com.google.gwt.user.cellview.client.SafeHtmlHeader;
import com.google.gwt.user.cellview.client.TextHeader;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.Anchor;
@@ -633,7 +632,7 @@ public class EditableLeaderboardPanel extends MultiRaceLeaderboardPanel {
@Override
public void onSuccess(Void noarg) {
updateScoreCorrectionInformation(lastScoreCorrectionComment, lastScoreCorrectionTime);
- Window.alert(stringMessages.successfullyUpdatedScores());
+ Notification.notify(stringMessages.successfullyUpdatedScores(), NotificationType.SUCCESS);
}
@Override
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/masterdataimport/MasterDataImportPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/masterdataimport/MasterDataImportPanel.java
index cacc5f7fc61..65b9705bddd 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/masterdataimport/MasterDataImportPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/masterdataimport/MasterDataImportPanel.java
@@ -15,7 +15,6 @@ import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
@@ -35,6 +34,8 @@ import com.sap.sailing.gwt.ui.client.MediaTracksRefresher;
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
+import com.sap.sse.gwt.client.Notification;
+import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.controls.progressbar.CustomProgressBar;
public class MasterDataImportPanel extends VerticalPanel {
@@ -268,7 +269,7 @@ public class MasterDataImportPanel extends VerticalPanel {
buffer.append(regattaName + "\n");
}
}
- Window.alert(buffer.toString());
+ Notification.notify(buffer.toString(), NotificationType.SUCCESS);
}
@@ -319,7 +320,7 @@ public class MasterDataImportPanel extends VerticalPanel {
}
private void showErrorAlert(String string) {
- Window.alert(string);
+ Notification.notify(string, NotificationType.ERROR);
}
private void addContentToLeftPanel(VerticalPanel contentPanel) {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/WinningLanesMode.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/WinningLanesMode.java
index e8621d61e5d..4b0d76037bf 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/WinningLanesMode.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/WinningLanesMode.java
@@ -49,12 +49,10 @@ public class WinningLanesMode extends RaceBoardModeWithPerRaceCompetitors {
raceDetailsToShow.add(DetailType.RACE_TIME_TRAVELED);
final SingleRaceLeaderboardSettings additiveSettings = LeaderboardSettingsFactory.getInstance().createNewSettingsWithCustomRaceDetails(raceDetailsToShow);
((RaceBoardComponentContext) leaderboardPanel.getComponentContext()).addModesPatching(leaderboardPanel, additiveSettings, new OnSettingsReloadedCallback() {
-
@Override
public void onSettingsReloaded(SingleRaceLeaderboardSettings patchedSettings) {
leaderboardPanel.updateSettings(patchedSettings);
}
-
});
}
@@ -79,14 +77,11 @@ public class WinningLanesMode extends RaceBoardModeWithPerRaceCompetitors {
defaultSettings.isShowEstimatedDuration(),
defaultSettings.getStartCountDownFontSizeScaling(),
defaultSettings.isShowManeuverLossVisualization());
-
((RaceBoardComponentContext) raceMap.getComponentContext()).addModesPatching(raceMap, additiveSettings, new OnSettingsReloadedCallback() {
-
@Override
public void onSettingsReloaded(RaceMapSettings patchedSettings) {
raceMap.updateSettings(patchedSettings);
}
-
});
}
@@ -129,17 +124,16 @@ public class WinningLanesMode extends RaceBoardModeWithPerRaceCompetitors {
stopReceivingLeaderboard();
adjustLeaderboardSettings();
}
- if (adjustedLeaderboardSettings && tailLength != null) {
- adjustMapSettings();
- }
if (getLeaderboardForSpecificTimePoint() == null && tailLength != null && getLeaderboard() != null && getRaceColumn() != null) {
loadLeaderboardForSpecificTimePoint(getLeaderboard().name, getRaceColumn().getName(), getTimer().getTime());
}
if (!adjustedCompetitorSelection && getLeaderboardForSpecificTimePoint() != null && getCompetitorsInRace() != null) {
stopReceivingCompetitorsInRace();
adjustedCompetitorSelection = true;
+ updateCompetitorSelection();
+ }
+ if (adjustedLeaderboardSettings && tailLength != null && adjustedCompetitorSelection) {
+ adjustMapSettings();
}
- updateCompetitorSelection();
}
-
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/MediaServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/MediaServiceImpl.java
index 430fd4b7e49..3e0f1ee4e74 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/MediaServiceImpl.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/MediaServiceImpl.java
@@ -17,6 +17,7 @@ import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.DateFormat;
@@ -221,13 +222,22 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
private VideoMetadataDTO checkMetadataByFullFileDownload(URL input)
throws ParserConfigurationException, SAXException, IOException {
- try (IsoFile isof = new IsoFile(Channels.newChannel(input.openStream()))) {
- boolean canDownload = true;
- Date recordStartedTimer = determineRecordingStart(isof);
- Duration duration = determineDuration(isof);
- boolean spherical = determine360(isof);
- removeTempFiles(isof);
- return new VideoMetadataDTO(canDownload, duration, spherical, recordStartedTimer, "");
+ final File tmp = File.createTempFile("upload", "metadataCheck");
+ try {
+ final ReadableByteChannel rbc = Channels.newChannel(input.openStream());
+ try (FileOutputStream fos = new FileOutputStream(tmp)) {
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+ try (IsoFile isof = new IsoFile(tmp)) {
+ final boolean canDownload = true;
+ final Date recordStartedTimer = determineRecordingStart(isof);
+ final Duration duration = determineDuration(isof);
+ final boolean spherical = determine360(isof);
+ removeTempFiles(isof);
+ return new VideoMetadataDTO(canDownload, duration, spherical, recordStartedTimer, "");
+ }
+ }
+ } finally {
+ Files.delete(tmp.toPath());
}
}
@@ -276,8 +286,9 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
Field field = box.getClass().getDeclaredField("dataFile");
field.setAccessible(true);
File data = (File) field.get(box);
- data.delete();
- } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ Files.delete(data.toPath());
+ } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException
+ | IOException e) {
logger.log(Level.WARNING, "Could not delete mp4 temp files", e);
}
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
index acd7b91b0c2..9b94c78e5de 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java
@@ -1514,7 +1514,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
assert from != null;
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
WindInfoForRaceDTO result = getAveragedWindInfo(new MillisecondsTimePoint(from), millisecondsStepWidth, numberOfFixes,
- windSourceTypeNames, trackedRace, /* onlyUpToNewestEvent */ true, includeCombinedWindForAllLegMiddles);
+ windSourceTypeNames, trackedRace, /* onlyUpToNewestEvent FIXME why not pass through onlyUpToNewestEvent here??? */ true, includeCombinedWindForAllLegMiddles);
return result;
}
@@ -1853,7 +1853,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
boolean extrapolate, LegIdentifier simulationLegIdentifier,
byte[] md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID,
Date timeToGetTheEstimatedDurationFor, boolean estimatedDurationRequired) throws NoWindException {
- Duration estimatedDuration = null;
final HashSet raceCompetitorIdsAsStrings;
final TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
// if md5OfIdsAsStringOfCompetitorParticipatingInRaceInAlphanumericOrderOfTheirID is null, Arrays.equals will return false, and the
@@ -1866,10 +1865,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
raceCompetitorIdsAsStrings.add(c.getId().toString());
}
}
- if(estimatedDurationRequired){
- estimatedDuration = getEstimationForTargetTime(timeToGetTheEstimatedDurationFor, estimatedDuration, trackedRace);
+ final Duration estimatedDuration;
+ if (estimatedDurationRequired) {
+ estimatedDuration = getEstimationForTargetTime(timeToGetTheEstimatedDurationFor, trackedRace);
+ } else {
+ estimatedDuration = null;
}
-
final Map> boatPositions = getBoatPositionsInternal(raceIdentifier,
fromPerCompetitorIdAsString, toPerCompetitorIdAsString, extrapolate);
final CoursePositionsDTO coursePositions = getCoursePositions(raceIdentifier, date);
@@ -1880,18 +1881,17 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
SimulationService simulationService = getService().getSimulationService();
simulationResultVersion = simulationService.getSimulationResultsVersion(simulationLegIdentifier);
}
-
return new CompactRaceMapDataDTO(boatPositions, coursePositions, courseSidelines, quickRanks,
simulationResultVersion, raceCompetitorIdsAsStrings, estimatedDuration);
}
- private Duration getEstimationForTargetTime(Date time, Duration estimatedDuration, final TrackedRace trackedRace) {
- if(trackedRace != null){
+ private Duration getEstimationForTargetTime(Date time, final TrackedRace trackedRace) {
+ Duration estimatedDuration = null;
+ if (trackedRace != null) {
try {
estimatedDuration = trackedRace.getEstimatedTimeToComplete(new MillisecondsTimePoint(time)).getExpectedDuration();
} catch (NotEnoughDataHasBeenAddedException | NoWindException e) {
- e.printStackTrace();
- } finally{
+ logger.log(Level.WARNING, "Problem computing the estimated race duration", e);
}
}
return estimatedDuration;
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/SimulatorMap.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/SimulatorMap.java
index fc7852d9dcf..9407c7cae94 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/SimulatorMap.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/simulator/SimulatorMap.java
@@ -58,6 +58,8 @@ import com.sap.sailing.gwt.ui.simulator.windpattern.WindPatternDisplay;
import com.sap.sailing.simulator.util.SailingSimulatorConstants;
import com.sap.sse.common.impl.RGBColor;
import com.sap.sse.gwt.client.ErrorReporter;
+import com.sap.sse.gwt.client.Notification;
+import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
import com.sap.sse.gwt.client.player.Timer;
@@ -998,7 +1000,7 @@ public class SimulatorMap extends AbsolutePanel implements RequiresDataInitializ
}
} else {
- Window.alert("No course set, please initialize the course with Start-End input");
+ Notification.notify("No course set, please initialize the course with Start-End input", NotificationType.ERROR);
}
}
diff --git a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/BackendPolarsBoatClassRetrievalProcessor.java b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/BackendPolarsBoatClassRetrievalProcessor.java
index 420be5961ba..9d37dbd8d94 100644
--- a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/BackendPolarsBoatClassRetrievalProcessor.java
+++ b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/BackendPolarsBoatClassRetrievalProcessor.java
@@ -1,9 +1,11 @@
package com.sap.sailing.polars.datamining.components;
import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
-import java.util.stream.Collectors;
+import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.polars.datamining.data.HasBackendPolarBoatClassContext;
import com.sap.sailing.polars.datamining.data.impl.BoatClassWithBackendPolarContext;
@@ -20,11 +22,15 @@ public class BackendPolarsBoatClassRetrievalProcessor extends AbstractRetrievalP
@Override
protected Iterable retrieveData(RacingEventService element) {
+ Set data = new HashSet<>();
PolarDataService polarDataService = element.getPolarDataService();
- return polarDataService.getAllBoatClassesWithPolarSheetsAvailable()
- .stream()
- .map(bc -> new BoatClassWithBackendPolarContext(bc, polarDataService))
- .collect(Collectors.toSet());
+ for (BoatClass boatClass : polarDataService.getAllBoatClassesWithPolarSheetsAvailable()) {
+ if (isAborted()) {
+ break;
+ }
+ data.add(new BoatClassWithBackendPolarContext(boatClass, polarDataService));
+ }
+ return data;
}
}
diff --git a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarCompetitorRetrievalProcessor.java b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarCompetitorRetrievalProcessor.java
index 76303f5dff1..537fe2ab383 100644
--- a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarCompetitorRetrievalProcessor.java
+++ b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarCompetitorRetrievalProcessor.java
@@ -25,6 +25,9 @@ public class PolarCompetitorRetrievalProcessor extends AbstractRetrievalProcesso
TrackedRace trackedRace = element.getTrackedRace();
Set competitorWithContext = new HashSet<>();
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
+ if (isAborted()) {
+ break;
+ }
competitorWithContext.add(new CompetitorWithPolarContext(competitor, trackedRace, element.getLeg(), element));
}
return competitorWithContext;
diff --git a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarFleetRetrievalProcessor.java b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarFleetRetrievalProcessor.java
index c0dda64feab..9cd650c4a61 100644
--- a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarFleetRetrievalProcessor.java
+++ b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarFleetRetrievalProcessor.java
@@ -25,6 +25,9 @@ public class PolarFleetRetrievalProcessor extends AbstractRetrievalProcessor fleetWithContext = new HashSet<>();
RaceColumn raceColumn = element.getRaceColumn();
for (Fleet fleet : raceColumn.getFleets()) {
+ if (isAborted()) {
+ break;
+ }
fleetWithContext.add(new FleetWithPolarContext(fleet, raceColumn, element));
}
return fleetWithContext;
diff --git a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarGPSFixRetrievalProcessor.java b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarGPSFixRetrievalProcessor.java
index 7ff4a486859..29668562f42 100644
--- a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarGPSFixRetrievalProcessor.java
+++ b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarGPSFixRetrievalProcessor.java
@@ -59,6 +59,9 @@ public class PolarGPSFixRetrievalProcessor extends AbstractRetrievalProcessor fixes = track.getFixes(startTime, true, finishTime, false);
for (GPSFixMoving fix : fixes) {
+ if (isAborted()) {
+ break;
+ }
WindWithConfidence> wind = trackedRace.getWindWithConfidence(
fix.getPosition(),
fix.getTimePoint(),
diff --git a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLeaderboardGroupRetrievalProcessor.java b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLeaderboardGroupRetrievalProcessor.java
index f825b0c536d..2c5af8790ad 100644
--- a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLeaderboardGroupRetrievalProcessor.java
+++ b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLeaderboardGroupRetrievalProcessor.java
@@ -1,9 +1,11 @@
package com.sap.sailing.polars.datamining.components;
import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
-import java.util.stream.Collectors;
+import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.polars.datamining.data.HasLeaderboardGroupPolarContext;
import com.sap.sailing.polars.datamining.data.impl.LeaderboardGroupWithPolarContext;
import com.sap.sailing.server.RacingEventService;
@@ -19,11 +21,14 @@ public class PolarLeaderboardGroupRetrievalProcessor extends AbstractRetrievalPr
@Override
protected Iterable retrieveData(RacingEventService element) {
- return element.getLeaderboardGroups()
- .values()
- .stream()
- .map(lg -> new LeaderboardGroupWithPolarContext(lg))
- .collect(Collectors.toSet());
+ Set data = new HashSet<>();
+ for (LeaderboardGroup leaderboardGroup : element.getLeaderboardGroups().values()) {
+ if (isAborted()) {
+ break;
+ }
+ data.add(new LeaderboardGroupWithPolarContext(leaderboardGroup));
+ }
+ return data;
}
}
diff --git a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLeaderboardRetrievalProcessor.java b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLeaderboardRetrievalProcessor.java
index 12e94917ff6..6e0e591fe7c 100644
--- a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLeaderboardRetrievalProcessor.java
+++ b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLeaderboardRetrievalProcessor.java
@@ -23,6 +23,9 @@ public class PolarLeaderboardRetrievalProcessor extends AbstractRetrievalProcess
protected Iterable retrieveData(HasLeaderboardGroupPolarContext element) {
Set leaderboardsWithContext = new HashSet<>();
for (Leaderboard leaderboard : element.getLeaderboardGroup().getLeaderboards()) {
+ if (isAborted()) {
+ break;
+ }
leaderboardsWithContext.add(new LeaderboardWithPolarContext(leaderboard, element));
}
return leaderboardsWithContext;
diff --git a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLegRetrievalProcessor.java b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLegRetrievalProcessor.java
index 84350cc7c47..b6107d19d45 100644
--- a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLegRetrievalProcessor.java
+++ b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/PolarLegRetrievalProcessor.java
@@ -35,6 +35,9 @@ public class PolarLegRetrievalProcessor extends AbstractRetrievalProcessor raceColumnWithContext = new HashSet<>();
Leaderboard leaderboard = element.getLeaderboard();
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
+ if (isAborted()) {
+ break;
+ }
raceColumnWithContext.add(new RaceColumnWithPolarContext(raceColumn, element));
}
return raceColumnWithContext;
diff --git a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/aggregators/PolarBackendDataAggregationProcessor.java b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/aggregators/PolarBackendDataAggregationProcessor.java
index 10a9e8eceef..86a3216bc25 100644
--- a/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/aggregators/PolarBackendDataAggregationProcessor.java
+++ b/java/com.sap.sailing.polars.datamining/src/com/sap/sailing/polars/datamining/components/aggregators/PolarBackendDataAggregationProcessor.java
@@ -100,10 +100,17 @@ public class PolarBackendDataAggregationProcessor extends AbstractParallelGroupe
} catch (NotEnoughDataHasBeenAddedException e) {
hasDownwindAngleData = false;
}
+
for (int angleInDeg = 0; angleInDeg < 360; angleInDeg++) {
+ if (isAborted()) {
+ break;
+ }
int convertedAngle = angleInDeg > 180 ? angleInDeg - 360 : angleInDeg ;
try {
for (int x = 0; x < 30; x++) {
+ if (isAborted()) {
+ break;
+ }
SpeedWithConfidence speed = polarDataService.getSpeed(boatClass, new KnotSpeedImpl(x), new DegreeBearingImpl(convertedAngle));
if (speed.getConfidence() > 0.1) {
hasDataForAngle[angleInDeg] = true;
@@ -127,6 +134,9 @@ public class PolarBackendDataAggregationProcessor extends AbstractParallelGroupe
private void setArrayValuesForFunction(PolynomialFunction function, double[] yOverWindSpeed) {
for (int x = 0; x < 30; x++) {
+ if (isAborted()) {
+ break;
+ }
yOverWindSpeed[x] = function.value(x);
}
}
diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java
index a6b97c92076..7ac6063042a 100755
--- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java
+++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java
@@ -170,8 +170,10 @@ public class PolarDataServiceImpl implements ReplicablePolarService, ClearStateT
if (closestTwsTwa == null) {
result = new Pair<>(0.0, null);
} else {
- double minDiffDeg = Math.abs(Math.abs(Math.abs(closestTwsTwa.getObject().getBearing().getDegrees() * 2)
- - Math.abs(courseChangeDeg)));
+ double targetManeuverAngle = getManeuverAngleInDegreesFromTwa(
+ closestTwsTwa.getObject().getBearing().getDegrees(), maneuverType);
+ double minDiffDeg = Math.abs(Math.abs(targetManeuverAngle)
+ - Math.abs(courseChangeDeg));
result = new Pair<>(1. / (1. + (minDiffDeg / 10.) * (minDiffDeg / 10.)), closestTwsTwa);
}
return result;
@@ -189,7 +191,7 @@ public class PolarDataServiceImpl implements ReplicablePolarService, ClearStateT
: courseChangeDeg >= 0 ? Tack.STARBOARD : Tack.PORT)) {
double targetManeuverAngle = getManeuverAngleInDegreesFromTwa(
trueWindSpeedAndAngle.getObject().getBearing().getDegrees(), type);
- double diff = Math.abs(targetManeuverAngle) - Math.abs(courseChangeDeg);
+ double diff = Math.abs(Math.abs(targetManeuverAngle) - Math.abs(courseChangeDeg));
if (diff < minDiff) {
minDiff = diff;
closestTwsTwa = trueWindSpeedAndAngle;
diff --git a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java
index 81f77630d00..f867c318c06 100755
--- a/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java
+++ b/java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java
@@ -288,7 +288,7 @@ public class PolarDataMiner {
} else if (legType.equals(LegType.DOWNWIND)) {
CubicEquation downWindEquation = new CubicEquation(0.0003, -0.0373, 1.5213, -2.1309
- speedOverGround.getKnots());
- int angle = 30 * tackFactor;
+ int angle = 150 * tackFactor;
solveAndAddResults(resultSet, downWindEquation, angle);
}
return resultSet;
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/HostPage.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/HostPage.java
index c928a649578..92430adbf17 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/HostPage.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/HostPage.java
@@ -18,9 +18,9 @@ public abstract class HostPage extends PageObject {
protected static final String NO_CODE_SERVER_PARAMTER_VALUE = ""; //$NON-NLS-1$
/**
- *
The default timeout of 60 seconds for the initialization of the page object.
+ * The default timeout of 120 seconds for the initialization of the page object.
*/
- protected static final int DEFAULT_PAGE_LOAD_TIMEOUT = 120;
+ protected static final int DEFAULT_PAGE_LOAD_TIMEOUT_IN_SECONDS = 120;
public static final String getGWTCodeServerAndLocale() {
StringBuilder queryBuilder = new StringBuilder("locale=en");
@@ -64,13 +64,12 @@ public abstract class HostPage extends PageObject {
*/
@Override
protected void initElements() {
- waitForAjaxRequests(getPageLoadTimeOut(), 5);
-
+ waitForAjaxRequests(getPageLoadTimeOutInSeconds(), 5 /* seconds */);
super.initElements();
}
- protected int getPageLoadTimeOut() {
- return DEFAULT_PAGE_LOAD_TIMEOUT;
+ protected int getPageLoadTimeOutInSeconds() {
+ return DEFAULT_PAGE_LOAD_TIMEOUT_IN_SECONDS;
}
protected interface HostPageSupplier {
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/PageObject.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/PageObject.java
index 130258175d1..41a0c2b85df 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/PageObject.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/PageObject.java
@@ -132,15 +132,15 @@ public class PageObject {
*
* @param input
*
- * @param timeout
+ * @param timeoutInSeconds
*
- * @param polling
+ * @param pollingEverySoManySeconds
*
* @return
*
*/
- public static FluentWait createFluentWait(T input, int timeout, int polling) {
- return createFluentWait(input, timeout, polling, Collections.>emptyList());
+ public static FluentWait createFluentWait(T input, int timeoutInSeconds, int pollingEverySoManySeconds) {
+ return createFluentWait(input, timeoutInSeconds, pollingEverySoManySeconds, Collections.>emptyList());
}
/**
@@ -168,20 +168,20 @@ public class PageObject {
*
* @param input
*
- * @param timeout
+ * @param timeoutInSeconds
*
- * @param polling
+ * @param pollingEverySoManySeconds
*
* @param exceptions
*
* @return
*
*/
- public static FluentWait createFluentWait(T input, int timeout, int polling,
+ public static FluentWait createFluentWait(T input, int timeoutInSeconds, int pollingEverySoManySeconds,
Collection> exceptions) {
FluentWait wait = new FluentWait<>(input);
- wait.withTimeout(timeout, TimeUnit.SECONDS);
- wait.pollingEvery(polling, TimeUnit.SECONDS);
+ wait.withTimeout(timeoutInSeconds, TimeUnit.SECONDS);
+ wait.pollingEvery(pollingEverySoManySeconds, TimeUnit.SECONDS);
wait.ignoreAll(exceptions);
return wait;
@@ -223,7 +223,7 @@ public class PageObject {
/**
*
Initialize the page object. The default implementation use a factory to lazily initialize the elements
- * (annotated fields) of the page object using the timeout duration returned by {@link #getPageLoadTimeOut()}.
+ * (annotated fields) of the page object using the timeout duration returned by {@link #getPageLoadTimeOutInSeconds()}.
* To get a field lazily initialized you have to annotate the field either with {@link FindBy} or with
* {@link FindBys}. If the element never changes (that is, that the same instance in the DOM can always be used)
* it is also possible to use a cache for the lookup by using the annotation {@code CacheLookup} in addition.
@@ -431,15 +431,15 @@ public class PageObject {
* and polling interval. In reality, the interval may be greater as the cost of actually evaluating the condition
* is not factored in.
*
- * @param timeout
- * The timeout duration for the waiting.
- * @param polling
- * The interval in which the check should be performed.
+ * @param timeoutInSeconds
+ * The timeout duration for the waiting in seconds.
+ * @param pollingEverySoManySeconds
+ * The interval in seconds in which the check should be performed.
* @throws org.openqa.selenium.TimeoutException
* if the timeout expires.
*/
- protected void waitForAjaxRequests(int timeout, int polling) {
- waitForAjaxRequests(AjaxCallsComplete.CATEGORY_GLOBAL, timeout, polling);
+ protected void waitForAjaxRequests(int timeoutInSeconds, int pollingEverySoManySeconds) {
+ waitForAjaxRequests(AjaxCallsComplete.CATEGORY_GLOBAL, timeoutInSeconds, pollingEverySoManySeconds);
}
/**
@@ -449,15 +449,15 @@ public class PageObject {
*
* @param category
* The category of Ajax requests to wait for.
- * @param timeout
- * The timeout duration for the waiting.
- * @param polling
- * The interval in which the check should be performed.
+ * @param timeoutInSeconds
+ * The timeout duration for the waiting in seconds.
+ * @param pollingEverySoManySeconds
+ * The interval in seconds in which the check should be performed.
* @throws org.openqa.selenium.TimeoutException
* if the timeout expires.
*/
- protected void waitForAjaxRequests(String category, int timeout, int polling) {
- FluentWait wait = createFluentWait(this.driver, timeout, polling);
+ protected void waitForAjaxRequests(String category, int timeoutInSeconds, int pollingEverySoManySeconds) {
+ FluentWait wait = createFluentWait(this.driver, timeoutInSeconds, pollingEverySoManySeconds);
wait.until(new AjaxCallsComplete(category));
}
@@ -580,9 +580,9 @@ public class PageObject {
* Waits for an alert box to appear and accepts the alert. If no alert shows up, an Exception is thrown.
*/
protected void waitForAlertAndAccept() throws InterruptedException {
- waitForAlertAndAccept(DEFAULT_WAIT_TIMEOUT_SECONDS);
+ waitForAlertAndAccept(DEFAULT_WAIT_TIMEOUT_SECONDS);
}
-
+
/**
* Waits for an alert box to appear and accepts the alert. If no alert shows up, an Exception is thrown.
*/
@@ -600,25 +600,31 @@ public class PageObject {
}
throw new NoAlertPresentException();
}
-
+
/**
- * Waits for an alert box to appear and dismisses the alert. If no alert shows up, an Exception is thrown.
+ * Waits for an notification to appear and dismisses the notification by clicking on it. If no notification shows up, an Exception is thrown.
*/
- protected void waitForAlertAndDismiss() throws InterruptedException {
- waitForAlertAndDismiss(DEFAULT_WAIT_TIMEOUT_SECONDS);
+ protected void waitForNotificationAndDismiss() throws InterruptedException {
+ waitForNotificationAndDismiss(DEFAULT_WAIT_TIMEOUT_SECONDS);
}
-
+
/**
- * Waits for an alert box to appear and dismisses the alert. If no alert shows up, an Exception is thrown.
+ * Waits for an notification to appear and dismisses the notification by clicking on it. If no notification shows up, an Exception is thrown.
*/
- protected void waitForAlertAndDismiss(int timeoutInSeconds) throws InterruptedException {
+ protected void waitForNotificationAndDismiss(int timeoutInSeconds) throws InterruptedException {
int i = 0;
while (i < timeoutInSeconds) {
i++;
try {
- Alert alert = driver.switchTo().alert();
- alert.accept();
- return;
+ List notifications = driver.findElements(By.id("notificationBar"));
+ if (notifications.size() > 0) {
+ notifications.get(0).findElements(By.cssSelector("*"))
+ .forEach(notification -> notification.click());
+ ;
+ return;
+ } else {
+ throw new NoAlertPresentException();
+ }
} catch (NoAlertPresentException e) {
Thread.sleep(1000);
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/advanced/MasterDataImportPO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/advanced/MasterDataImportPO.java
index 17c266a9053..2c31036b3b7 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/advanced/MasterDataImportPO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/advanced/MasterDataImportPO.java
@@ -55,6 +55,6 @@ public class MasterDataImportPO extends PageArea {
}
new Select(leaderBoardGroupListBox).selectByValue(eventName);
importBtn.click();
- waitForAlertAndDismiss();
+ waitForNotificationAndDismiss();
}
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/igtimi/IgtimiAccountsManagementPanelPO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/igtimi/IgtimiAccountsManagementPanelPO.java
index cced2f9086d..f1080d617b1 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/igtimi/IgtimiAccountsManagementPanelPO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/igtimi/IgtimiAccountsManagementPanelPO.java
@@ -41,6 +41,6 @@ public class IgtimiAccountsManagementPanelPO extends PageArea {
addIgtimiAccountDialog.setPassword(password);
addIgtimiAccountDialog.pressOk();
- waitForAlertAndAccept(10);
+ waitForNotificationAndDismiss(10);
}
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayLeaderboardView.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayLeaderboardView.java
index 4b2680b08b4..6eb5e109618 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayLeaderboardView.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayLeaderboardView.java
@@ -2,10 +2,7 @@ package com.sap.sailing.selenium.pages.autoplay;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
-import org.openqa.selenium.support.ui.WebDriverWait;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
import com.sap.sailing.selenium.pages.PageArea;
import com.sap.sailing.selenium.pages.leaderboard.LeaderboardTablePO;
@@ -15,32 +12,8 @@ public class AutoPlayLeaderboardView extends PageArea {
}
public LeaderboardTablePO getLeaderBoardWithData() {
- WebElement leaderboardCellTable = new WebDriverWait(driver, 30).until(new Function() {
- @Override
- public WebElement apply(WebDriver driver) {
- WebElement leaderboardCellTable = findElementOrNullBySeleniumId("LeaderboardCellTable");
- if (leaderboardCellTable != null) {
- if (isElementEntirelyVisible(leaderboardCellTable)) {
- return leaderboardCellTable;
- } else {
- return null;
- }
- } else {
- return null;
- }
- }
- });
- LeaderboardTablePO leaderboardTablePO = new LeaderboardTablePO(this.driver, leaderboardCellTable);
+ LeaderboardTablePO leaderboardTablePO = new LeaderboardTablePO(this.driver, findElementBySeleniumId("LeaderboardCellTable"));
leaderboardTablePO.waitForTableToShowData();
-
- // After the data is loaded it could be possible that the table isn't completely visible anymore
- new WebDriverWait(driver, 30).until(new Predicate() {
- @Override
- public boolean apply(WebDriver arg0) {
- return isElementEntirelyVisible(leaderboardCellTable);
- }
- });
return leaderboardTablePO;
}
-
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayPage.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayPage.java
index c37d75e80f6..d06aa9931e9 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayPage.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayPage.java
@@ -4,7 +4,9 @@ import java.io.UnsupportedEncodingException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import com.google.common.base.Function;
import com.sap.sailing.selenium.core.BySeleniumId;
import com.sap.sailing.selenium.core.FindBy;
import com.sap.sailing.selenium.pages.HostPage;
@@ -21,9 +23,6 @@ public class AutoPlayPage extends HostPage {
@FindBy(how = BySeleniumId.class, using = "AutoPlayStartView")
private WebElement autoPlayStartView;
- @FindBy(how = BySeleniumId.class, using = "LeaderboardView")
- private WebElement autoPlayLeaderboardView;
-
@FindBy(how = BySeleniumId.class, using = "IdleNextUpView")
private WebElement idleNextUpView;
@@ -76,7 +75,22 @@ public class AutoPlayPage extends HostPage {
public AutoPlayLeaderboardView goToAutoPlayClassicUrl(WebDriver driver, String url) {
driver.get(url); //$NON-NLS-1$
- return new AutoPlayLeaderboardView(driver, autoPlayLeaderboardView);
+ final WebElement leaderboardViewElement = new WebDriverWait(driver, 30).until(new Function() {
+ @Override
+ public WebElement apply(WebDriver driver) {
+ final WebElement leaderboardViewElement = findElementOrNullBySeleniumId("LeaderboardView");
+ if (leaderboardViewElement != null) {
+ if (isElementEntirelyVisible(leaderboardViewElement)) {
+ return leaderboardViewElement;
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+ });
+ return new AutoPlayLeaderboardView(driver, leaderboardViewElement);
}
public AutoPlayUpcomingView goToAutoPlaySixtyInchUrl(WebDriver webDriver, String url) {
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestStartAndStopTrackingForTracTracEvents.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestStartAndStopTrackingForTracTracEvents.java
index 76f8cadf204..b68892e0ba1 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestStartAndStopTrackingForTracTracEvents.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestStartAndStopTrackingForTracTracEvents.java
@@ -3,11 +3,14 @@ package com.sap.sailing.selenium.test.adminconsole;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.Alert;
+import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver.TargetLocator;
+import org.openqa.selenium.WebElement;
import com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage;
import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaListCompositePO.RegattaDescriptor;
@@ -88,6 +91,7 @@ public class TestStartAndStopTrackingForTracTracEvents extends AbstractSeleniumT
tracTracEvents.setReggataForTracking(DEFAULT_REGATTA);
tracTracEvents.setTrackSettings(false, false, false);
tracTracEvents.startTrackingForRace(this.trackableRace);
+
TargetLocator locator = getWebDriver().switchTo();
Alert alert = locator.alert();
String text = alert.getText();
@@ -109,12 +113,16 @@ public class TestStartAndStopTrackingForTracTracEvents extends AbstractSeleniumT
tracTracEvents.setReggataForTracking(idm2013Descriptor);
tracTracEvents.setTrackSettings(false, false, false);
tracTracEvents.startTrackingForRace(this.trackableRace);
- TargetLocator locator = getWebDriver().switchTo();
- Alert alert = locator.alert();
- String text = alert.getText();
- alert.dismiss();
- String message = String.format("The selected races contain boat classes which are not the same as " +
- "the boat class '%s' of the selected regatta.", IDM_2013_BOAT_CLASS);
- assertThat(text, containsString(message));
+
+ String message = String.format("The selected races contain boat classes which are not the same as "
+ + "the boat class '%s' of the selected regatta.", IDM_2013_BOAT_CLASS);
+ for (WebElement element : getWebDriver().findElement(By.id("notificationBar")).findElements(By.cssSelector("*"))) {
+ if (element.getText().contains(message)) {
+ element.click();
+ assertTrue(true);
+ return;
+ }
+ }
+ assertTrue("Could not find error notification.", false);
}
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/autoplay/TestAutoPlay.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/autoplay/TestAutoPlay.java
index f79a99f3baf..7ed39aa5877 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/autoplay/TestAutoPlay.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/autoplay/TestAutoPlay.java
@@ -12,7 +12,10 @@ import javax.xml.bind.DatatypeConverter;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import com.google.common.base.Function;
import com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage;
import com.sap.sailing.selenium.pages.adminconsole.event.EventConfigurationPanelPO;
import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardConfigurationPanelPO;
@@ -118,7 +121,26 @@ public class TestAutoPlay extends AbstractSeleniumTest {
assertTrue("Url does not contain proper name " + url, url.contains("name=BMW+Cup+(J80)"));
AutoPlayLeaderboardView autoplayPage = page.goToAutoPlayClassicUrl(getWebDriver(), url);
LeaderboardTablePO leaderBoard = autoplayPage.getLeaderBoardWithData();
- List races = leaderBoard.getRaceNames();
+ final List races = new WebDriverWait(getWebDriver(), 20).until(new Function>() {
+ @Override
+ public List apply(WebDriver arg0) {
+ try {
+ final List races = leaderBoard.getRaceNames();
+ final List result;
+ if (races != null && !races.isEmpty()) {
+ result = races;
+ } else {
+ // The table may seem to be empty while the leaderboard updates itself
+ result = null;
+ }
+ return result;
+ } catch (Exception e) {
+ // While the leaderboard updates its contents, errors may occur while reading data via selenium
+ // In this case we need to try this in the next loop again
+ return null;
+ }
+ }
+ });
Assert.assertTrue(races.contains("R1"));
Assert.assertTrue(races.contains("R2"));
Assert.assertTrue(races.contains("R3"));
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/raceboard/SettingsTest.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/raceboard/SettingsTest.java
index 79070cb3237..76b884e193e 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/raceboard/SettingsTest.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/raceboard/SettingsTest.java
@@ -10,6 +10,7 @@ import javax.xml.bind.DatatypeConverter;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage;
@@ -83,6 +84,7 @@ public class SettingsTest extends AbstractSeleniumTest {
* settings and global settings.
*/
@Test
+ @Ignore
public void testRaceBoardPageSettingsStorage() throws InterruptedException, UnsupportedEncodingException {
AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
EventConfigurationPanelPO events = adminConsole.goToEvents();
@@ -257,6 +259,7 @@ public class SettingsTest extends AbstractSeleniumTest {
* Verifies that settings for different modes are distinct and do not have an effect on other modes.
*/
@Test
+ @Ignore
public void testThatUserDefaultsForOneModeDoNotHaveAnEffectOnAnotherMode() throws InterruptedException, UnsupportedEncodingException {
AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
EventConfigurationPanelPO events = adminConsole.goToEvents();
@@ -337,6 +340,7 @@ public class SettingsTest extends AbstractSeleniumTest {
* Verifies that settings are stored for raceboard.
*/
@Test
+ @Ignore
public void testThatModeDependentSettingsAreStoredForOneMode() throws InterruptedException, UnsupportedEncodingException {
AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
EventConfigurationPanelPO events = adminConsole.goToEvents();
diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EstimationDataSerializationDeserializationTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EstimationDataSerializationDeserializationTest.java
index fa01070bb1b..b82873b29dc 100644
--- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EstimationDataSerializationDeserializationTest.java
+++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EstimationDataSerializationDeserializationTest.java
@@ -130,14 +130,14 @@ public class EstimationDataSerializationDeserializationTest {
Bearing relativeBearingToNextMarkAfterManeuver = new DegreeBearingImpl(10.01);
boolean markPassing = true;
Distance closestDistanceToMark = new MeterDistance(3.0);
- Double deviationFromTargetTackAngle = 23.30;
- Double deviationFromTargetJibeAngle = 22.30;
+ Double targetTackAngle = 23.30;
+ Double targetJibeAngle = 22.30;
CompleteManeuverCurveWithEstimationData toSerialize = new CompleteManeuverCurveWithEstimationDataImpl(
maneuverPosition, mainCurve, curve, wind, tackingCount, jibingCount,
maneuverStartsByRunningAwayFromWind, relativeBearingToNextMarkBeforeManeuver,
- relativeBearingToNextMarkAfterManeuver, markPassing, closestDistanceToMark,
- deviationFromTargetTackAngle, deviationFromTargetJibeAngle);
+ relativeBearingToNextMarkAfterManeuver, markPassing, closestDistanceToMark, targetTackAngle,
+ targetJibeAngle);
CompleteManeuverCurveWithEstimationDataJsonSerializer serializer = new CompleteManeuverCurveWithEstimationDataJsonSerializer(
new ManeuverMainCurveWithEstimationDataJsonSerializer(),
new ManeuverCurveWithUnstableCourseAndSpeedWithEstimationDataJsonSerializer(),
@@ -149,10 +149,8 @@ public class EstimationDataSerializationDeserializationTest {
new ManeuverWindJsonDeserializer(), new PositionJsonDeserializer());
CompleteManeuverCurveWithEstimationData deserialized = deserializer.deserialize(json);
- assertEquals(deviationFromTargetJibeAngle,
- deserialized.getDeviationOfManeuverAngleFromTargetJibeAngleInDegrees());
- assertEquals(deviationFromTargetTackAngle,
- deserialized.getDeviationOfManeuverAngleFromTargetTackAngleInDegrees());
+ assertEquals(targetJibeAngle, deserialized.getTargetJibeAngleInDegrees());
+ assertEquals(targetTackAngle, deserialized.getTargetTackAngleInDegrees());
assertEquals(closestDistanceToMark, deserialized.getDistanceToClosestMark());
assertEquals(maneuverPosition, deserialized.getPosition());
assertEquals(tackingCount, deserialized.getTackingCount());
@@ -310,14 +308,14 @@ public class EstimationDataSerializationDeserializationTest {
boolean markPassing = false;
DegreePosition maneuverPosition = new DegreePosition(50.325246, 11.148556);
Distance closestDistanceToMark = null;
- Double deviationFromTargetTackAngle = null;
- Double deviationFromTargetJibeAngle = null;
+ Double targetTackAngle = null;
+ Double targetJibeAngle = null;
CompleteManeuverCurveWithEstimationData toSerialize = new CompleteManeuverCurveWithEstimationDataImpl(
maneuverPosition, mainCurve, curve, wind, tackingCount, jibingCount,
maneuverStartsByRunningAwayFromWind, relativeBearingToNextMarkBeforeManeuver,
- relativeBearingToNextMarkAfterManeuver, markPassing, closestDistanceToMark,
- deviationFromTargetTackAngle, deviationFromTargetJibeAngle);
+ relativeBearingToNextMarkAfterManeuver, markPassing, closestDistanceToMark, targetTackAngle,
+ targetJibeAngle);
CompleteManeuverCurveWithEstimationDataJsonSerializer serializer = new CompleteManeuverCurveWithEstimationDataJsonSerializer(
new ManeuverMainCurveWithEstimationDataJsonSerializer(),
new ManeuverCurveWithUnstableCourseAndSpeedWithEstimationDataJsonSerializer(),
@@ -329,10 +327,8 @@ public class EstimationDataSerializationDeserializationTest {
new ManeuverWindJsonDeserializer(), new PositionJsonDeserializer());
CompleteManeuverCurveWithEstimationData deserialized = deserializer.deserialize(json);
- assertEquals(deviationFromTargetJibeAngle,
- deserialized.getDeviationOfManeuverAngleFromTargetJibeAngleInDegrees());
- assertEquals(deviationFromTargetTackAngle,
- deserialized.getDeviationOfManeuverAngleFromTargetTackAngleInDegrees());
+ assertEquals(targetJibeAngle, deserialized.getTargetJibeAngleInDegrees());
+ assertEquals(targetTackAngle, deserialized.getTargetTackAngleInDegrees());
assertEquals(closestDistanceToMark, deserialized.getDistanceToClosestMark());
assertEquals(maneuverPosition, deserialized.getPosition());
assertEquals(tackingCount, deserialized.getTackingCount());
diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/impl/CompleteManeuverCurveWithEstimationDataJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/impl/CompleteManeuverCurveWithEstimationDataJsonDeserializer.java
index 886f0e3c745..fb80f6228cd 100644
--- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/impl/CompleteManeuverCurveWithEstimationDataJsonDeserializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/impl/CompleteManeuverCurveWithEstimationDataJsonDeserializer.java
@@ -67,16 +67,15 @@ public class CompleteManeuverCurveWithEstimationDataJsonDeserializer
CompleteManeuverCurveWithEstimationDataJsonSerializer.RELATIVE_BEARING_TO_NEXT_MARK_AFTER_MANEUVER);
Double closestDistanceToMarkInMeters = (Double) object
.get(CompleteManeuverCurveWithEstimationDataJsonSerializer.CLOSEST_DISTANCE_TO_MARK);
- Double deviationFromTargetTackAngle = (Double) object
- .get(CompleteManeuverCurveWithEstimationDataJsonSerializer.DEVIATION_FROM_TARGET_TACK_ANGLE);
- Double deviationFromTargetJibeAngle = (Double) object
- .get(CompleteManeuverCurveWithEstimationDataJsonSerializer.DEVIATION_FROM_TARGET_JIBE_ANGLE);
+ Double targetTackAngle = (Double) object
+ .get(CompleteManeuverCurveWithEstimationDataJsonSerializer.TARGET_TACK_ANGLE);
+ Double targetJibeAngle = (Double) object
+ .get(CompleteManeuverCurveWithEstimationDataJsonSerializer.TARGET_JIBE_ANGLE);
return new CompleteManeuverCurveWithEstimationDataImpl(position, mainCurve, curveWithUnstableCourseAndSpeed,
wind, tackingCount, jibingCount, maneuverStartsByRunningAwayFromWind,
convertBearing(relativeBearingToNextMarkBeforeManeuver),
convertBearing(relativeBearingToNextMarkAfterManeuver), markPassing,
- convertDistance(closestDistanceToMarkInMeters), deviationFromTargetTackAngle,
- deviationFromTargetJibeAngle);
+ convertDistance(closestDistanceToMarkInMeters), targetTackAngle, targetJibeAngle);
}
private Bearing convertBearing(Double degrees) {
diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/CompetitorTrackWithEstimationDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/CompetitorTrackWithEstimationDataJsonSerializer.java
index eb2089ea0d5..7b7d9032416 100644
--- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/CompetitorTrackWithEstimationDataJsonSerializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/CompetitorTrackWithEstimationDataJsonSerializer.java
@@ -26,7 +26,7 @@ import com.sap.sse.common.impl.MillisecondsDurationImpl;
*
*/
public class CompetitorTrackWithEstimationDataJsonSerializer extends AbstractTrackedRaceDataJsonSerializer {
- public static final String elements = "elements";
+ public static final String ELEMENTS = "elements";
public static final String BOAT_CLASS = "boatClass";
public static final String COMPETITOR_NAME = "competitorName";
public static final String AVG_INTERVAL_BETWEEN_FIXES_IN_SECONDS = "avgIntervalBetweenFixesInSeconds";
@@ -67,27 +67,27 @@ public class CompetitorTrackWithEstimationDataJsonSerializer extends AbstractTra
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
ManeuverDetectorImpl maneuverDetector = new ManeuverDetectorImpl(trackedRace, competitor);
TrackTimeInfo trackTimeInfo = maneuverDetector.getTrackTimeInfo();
- TimePoint from = null;
- TimePoint to = null;
- if (startBeforeStartLineInSeconds != null) {
- from = trackTimeInfo.getTrackStartTimePoint()
- .minus(new MillisecondsDurationImpl(startBeforeStartLineInSeconds * 1000L));
- } else if (startAfterFinishLineInSeconds != null) {
- from = trackTimeInfo.getTrackEndTimePoint()
- .plus(new MillisecondsDurationImpl(startAfterFinishLineInSeconds * 1000L));
- } else {
- from = trackTimeInfo.getTrackStartTimePoint();
- }
- if (endAfterFinishLineInSeconds != null) {
- to = trackTimeInfo.getTrackEndTimePoint()
- .plus(new MillisecondsDurationImpl(endAfterFinishLineInSeconds * 1000L));
- } else if (endBeforeStartLineInSeconds != null) {
- to = trackTimeInfo.getTrackStartTimePoint()
- .minus(new MillisecondsDurationImpl(endBeforeStartLineInSeconds * 1000L));
- } else {
- to = trackTimeInfo.getTrackEndTimePoint();
- }
if (trackTimeInfo != null) {
+ TimePoint from = null;
+ TimePoint to = null;
+ if (startBeforeStartLineInSeconds != null) {
+ from = trackTimeInfo.getTrackStartTimePoint()
+ .minus(new MillisecondsDurationImpl(startBeforeStartLineInSeconds * 1000L));
+ } else if (startAfterFinishLineInSeconds != null) {
+ from = trackTimeInfo.getTrackEndTimePoint()
+ .plus(new MillisecondsDurationImpl(startAfterFinishLineInSeconds * 1000L));
+ } else {
+ from = trackTimeInfo.getTrackStartTimePoint();
+ }
+ if (endAfterFinishLineInSeconds != null) {
+ to = trackTimeInfo.getTrackEndTimePoint()
+ .plus(new MillisecondsDurationImpl(endAfterFinishLineInSeconds * 1000L));
+ } else if (endBeforeStartLineInSeconds != null) {
+ to = trackTimeInfo.getTrackStartTimePoint()
+ .minus(new MillisecondsDurationImpl(endBeforeStartLineInSeconds * 1000L));
+ } else {
+ to = trackTimeInfo.getTrackEndTimePoint();
+ }
final JSONObject forCompetitorJson = new JSONObject();
byCompetitorJson.add(forCompetitorJson);
forCompetitorJson.put(COMPETITOR_NAME, competitor.getName());
@@ -111,7 +111,7 @@ public class CompetitorTrackWithEstimationDataJsonSerializer extends AbstractTra
: trackTimeInfo.getTrackEndTimePoint().asMillis());
forCompetitorJson.put(MARK_PASSINGS_COUNT, getMarkPassingsCount(trackedRace, competitor));
forCompetitorJson.put(WAYPOINTS_COUNT, getWaypointsCount(trackedRace));
- forCompetitorJson.put(elements,
+ forCompetitorJson.put(ELEMENTS,
elementsJsonSerializer.serialize(trackedRace, competitor, from, to, trackTimeInfo));
}
}
diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/CompleteManeuverCurveWithEstimationDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/CompleteManeuverCurveWithEstimationDataJsonSerializer.java
index e1b807cf388..a00ac2d01b8 100644
--- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/CompleteManeuverCurveWithEstimationDataJsonSerializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/CompleteManeuverCurveWithEstimationDataJsonSerializer.java
@@ -24,8 +24,8 @@ public class CompleteManeuverCurveWithEstimationDataJsonSerializer
public static final String RELATIVE_BEARING_TO_NEXT_MARK_BEFORE_MANEUVER = "relativeBearingToNextMarkBeforeManeuver";
public static final String RELATIVE_BEARING_TO_NEXT_MARK_AFTER_MANEUVER = "relativeBearingToNextMarkAfterManeuver";
public static final String CLOSEST_DISTANCE_TO_MARK = "closestDistanceToMarkInMeters";
- public static final String DEVIATION_FROM_TARGET_TACK_ANGLE = "deviationFromTargetTackAngleInDegrees";
- public static final String DEVIATION_FROM_TARGET_JIBE_ANGLE = "deviationFromTargetJibeAngleInDegrees";
+ public static final String TARGET_TACK_ANGLE = "targetTackAngleInDegrees";
+ public static final String TARGET_JIBE_ANGLE = "targetJibeAngleInDegrees";
private final ManeuverCurveBoundariesJsonSerializer mainCurveSerializer;
private final ManeuverCurveBoundariesJsonSerializer curveWithUnstableCourseAndSpeedSerializer;
@@ -64,10 +64,8 @@ public class CompleteManeuverCurveWithEstimationDataJsonSerializer
: maneuverWithEstimationData.getRelativeBearingToNextMarkAfterManeuver().getDegrees());
result.put(CLOSEST_DISTANCE_TO_MARK, maneuverWithEstimationData.getDistanceToClosestMark() == null ? null
: maneuverWithEstimationData.getDistanceToClosestMark().getMeters());
- result.put(DEVIATION_FROM_TARGET_TACK_ANGLE,
- maneuverWithEstimationData.getDeviationOfManeuverAngleFromTargetTackAngleInDegrees());
- result.put(DEVIATION_FROM_TARGET_JIBE_ANGLE,
- maneuverWithEstimationData.getDeviationOfManeuverAngleFromTargetJibeAngleInDegrees());
+ result.put(TARGET_TACK_ANGLE, maneuverWithEstimationData.getTargetTackAngleInDegrees());
+ result.put(TARGET_JIBE_ANGLE, maneuverWithEstimationData.getTargetJibeAngleInDegrees());
return result;
}
diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/GPSFixMovingJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/GPSFixMovingJsonSerializer.java
index 9abbbd260c0..7cbdef8ecb1 100644
--- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/GPSFixMovingJsonSerializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/GPSFixMovingJsonSerializer.java
@@ -2,19 +2,25 @@ package com.sap.sailing.server.gateway.serialization.impl;
import org.json.simple.JSONObject;
+import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.server.gateway.deserialization.TypeBasedJsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.GPSFixMovingJsonDeserializer;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
public class GPSFixMovingJsonSerializer implements JsonSerializer {
+
@Override
public JSONObject serialize(GPSFixMoving object) {
+ return serialize(object, object.getSpeed());
+ }
+
+ public JSONObject serialize(GPSFixMoving object, SpeedWithBearing speedWithCourse) {
JSONObject result = new GPSFixJsonSerializer().serialize(object);
result.put(TypeBasedJsonDeserializer.FIELD_TYPE, GPSFixMovingJsonDeserializer.TYPE);
- result.put(GPSFixMovingJsonDeserializer.FIELD_BEARING_DEG, object.getSpeed().getBearing().getDegrees());
- result.put(GPSFixMovingJsonDeserializer.FIELD_SPEED_KNOTS, object.getSpeed().getKnots());
+ result.put(GPSFixMovingJsonDeserializer.FIELD_BEARING_DEG, speedWithCourse.getBearing().getDegrees());
+ result.put(GPSFixMovingJsonDeserializer.FIELD_SPEED_KNOTS, speedWithCourse.getKnots());
return result;
}
diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/GpsFixesWithEstimationDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/GpsFixesWithEstimationDataJsonSerializer.java
index a2148acf2fe..e301bf29faf 100644
--- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/GpsFixesWithEstimationDataJsonSerializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/GpsFixesWithEstimationDataJsonSerializer.java
@@ -60,7 +60,9 @@ public class GpsFixesWithEstimationDataJsonSerializer implements CompetitorTrack
track.lockForRead();
try {
for (GPSFixMoving gpsFix : track.getFixes(from, true, to, true)) {
- JSONObject serializedGpsFix = gpsFixMovingJsonSerializer.serialize(gpsFix);
+ SpeedWithBearing speedWithBearing = smoothFixes ? track.getEstimatedSpeed(gpsFix.getTimePoint())
+ : gpsFix.getSpeed();
+ JSONObject serializedGpsFix = gpsFixMovingJsonSerializer.serialize(gpsFix, speedWithBearing);
if (addWind) {
Wind wind = trackedRace.getWind(gpsFix.getPosition(), gpsFix.getTimePoint());
JSONObject serializedWind = wind == null ? null : windJsonSerializer.serialize(wind);
@@ -69,8 +71,6 @@ public class GpsFixesWithEstimationDataJsonSerializer implements CompetitorTrack
if (addNextWaypoint) {
Distance closestDistanceToMark = estimationDataSupportDecoratorImpl
.getClosestDistanceToMark(gpsFix.getTimePoint());
- SpeedWithBearing speedWithBearing = smoothFixes ? track.getEstimatedSpeed(gpsFix.getTimePoint())
- : gpsFix.getSpeed();
Bearing relativeBearingToNextMark = speedWithBearing == null ? null
: estimationDataSupportDecoratorImpl.getRelativeBearingToNextMark(gpsFix.getTimePoint(),
speedWithBearing.getBearing());
diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html
index 23ab8d659ab..d6bc7b0e350 100755
--- a/java/com.sap.sailing.www/release_notes_admin.html
+++ b/java/com.sap.sailing.www/release_notes_admin.html
@@ -22,6 +22,11 @@
Release Notes - Administration Console
+
July 2018
+
+
The mark passing editor now uses a full date/time format for the mark passing time points.
+
+
July 2018
When adding a YouTube video for tracked races ("Manage Media" in RaceBoard.html or "Tracked Races > Audio & Video" in AdminConsole.html) the respective video metadata is now read using YouTube API v3.
@@ -32,6 +37,23 @@
leaving the value empty and confirming the dialog.
Up to 15 discards can now be configured for series and leaderboards. This enables, e.g., "Wednesday Night" scenarios
where over the season, say, 20 races are run but due to changing participation only, say, the five best ones shall be scored.
+
There is a new scoring scheme available to be selected upon regatta creation.
+ The scoring scheme is named "Low Point System, First with two wins in medals is winner" and introduces the following specifics compared to the standard low point scheme:
+
+
Medal series does not feature doubling of points in the medal series by default.
+
A competitor having two wins in the medal series is treated as overall winner.
+ If there is a carry forward column in the medal series, having one point there also counts as a win which means the best competitor in the qualification needs a win less than any other finalist to be the overall winner.
+
If the medal series isn't started yet or no competitor has collected two wins, scoring by points is used.
+ This also applies if the regatta is aborted (e.g. due to weather conditions) before any competitor could win two races in the medal series.
+
If two competitors have the same amount of points in the medal series the tie breaking criteria is the carry forward column of the medal series.
+ If there is no carry forward column in the medal series, the last medal race is used as tie breaking criteria.
+ For any non-medal series, the standard low point rules apply.
+
+
+
A TracAPI upgrade from version 3.10.1 to 3.11.0 unifies the handling of course updates and solves an issue
+ observed with updating mark passing instructions.
+
Bug fix for mark position editor, now providing consistent behavior during adding of new mark fixes
+
Data Mining now more aggressively terminates running queries if needed.
June 2018
diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestAbortingHeavyLoadQuery.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestAbortingHeavyLoadQuery.java
new file mode 100644
index 00000000000..3e6a5494596
--- /dev/null
+++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestAbortingHeavyLoadQuery.java
@@ -0,0 +1,524 @@
+package com.sap.sse.datamining.impl;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Method;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.RunnableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.sap.sse.datamining.Query;
+import com.sap.sse.datamining.QueryState;
+import com.sap.sse.datamining.components.AdditionalResultDataBuilder;
+import com.sap.sse.datamining.components.Processor;
+import com.sap.sse.datamining.components.ProcessorInstruction;
+import com.sap.sse.datamining.components.ProcessorInstructionHandler;
+import com.sap.sse.datamining.data.QueryResult;
+import com.sap.sse.datamining.impl.components.AbstractParallelProcessor;
+import com.sap.sse.datamining.impl.components.AbstractProcessorInstruction;
+import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
+import com.sap.sse.datamining.impl.components.GroupedDataEntry;
+import com.sap.sse.datamining.impl.components.ProcessorInstructionPriority;
+import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedDataCollectingAsSetProcessor;
+import com.sap.sse.datamining.shared.GroupKey;
+import com.sap.sse.datamining.shared.data.QueryResultState;
+import com.sap.sse.datamining.shared.impl.GenericGroupKey;
+import com.sap.sse.datamining.test.util.components.StatefulBlockingInstruction;
+import com.sap.sse.datamining.test.util.components.StatefulProcessorInstruction;
+
+/**
+ * Integration test aborting a query with simulated heavy load instructions. Uses a highly customized processor chain
+ * (based on the processors/instructions used in production) that allows detailed introspection and logging of the
+ * execution process. The test is used to verify the behavior of processors, if such a heavy load query is aborted
+ * during the process. For example that no instructions are scheduled after the query was aborted and the behavior of
+ * already scheduled instructions that may or may not have been started.
+ *
+ * The test is configurable regarding the number of threads for the executor, the number of data elements/heavy load
+ * instructions, the duration of heavy load instructions, the time to wait before the query is aborted and the time
+ * given to the executor to finish the remaining instructions. Note that the test can fail for some configurations, due
+ * to race conditions that would be very hard to check for.
+ *
+ * The test optionally records the process in order of the execution (using a concurrent message queue), which is
+ * printed to the console before assertions are performed. This isn't used by the assertions, but can be used to get a
+ * better understanding of what happens during the execution.
+ *
+ * See {@link #initialize()} for more details about the processor chain.
+ *
+ * @author Lennart Hensler
+ */
+public class TestAbortingHeavyLoadQuery {
+
+ // Test Configuration ----------------------------------------------------------------------------------------
+ /**
+ * Number of threads in the executor. Determines the number of elements (and thus heavy load instructions)
+ * retrieved for each group. This means that each group should have a runtime of {@value #HeavyLoadInstructionTotalDuration}ms,
+ * since the single instructions are executed concurrently.
+ */
+ private static final int ExecutorPoolSize = Math.max(3, Runtime.getRuntime().availableProcessors());
+
+ /** The number of groups contained in the initial data source. */
+ private static final int DataSourceSize = 2000;
+ private static final String GroupKeyPrefix = "G";
+
+ /** The time a step of a heavy load instruction blocks the executing thread (using {@link Thread#sleep(long)}). */
+ private static final long HeavyLoadInstructionStepDuration = 50;
+ /** The number of steps a heavy load instruction performs */
+ private static final int HeavyLoadInstructionNumberOfSteps = 10;
+ /** The total time a heavy load instruction blocks the executing thread (using {@link Thread#sleep(long)}). */
+ private static final long HeavyLoadInstructionTotalDuration = HeavyLoadInstructionStepDuration * HeavyLoadInstructionNumberOfSteps;
+
+ /** The number of milliseconds to wait before {@link Query#abort()} is called. */
+ private static final long AbortQueryDelay = (long) (HeavyLoadInstructionTotalDuration * 5.45);
+ /** The time given to the executor to complete all unfinished instructions */
+ private static final long TerminationTimeout = HeavyLoadInstructionStepDuration * 2;
+ //------------------------------------------------------------------------------------------------------------
+
+ // Execution Recording Configuration -------------------------------------------------------------------------
+ /** Enables concurrent logging of the query execution and prints the current record before assertions. */
+ private static final boolean RecordExecution = true;
+ private static final SimpleDateFormat DateFormatter = new SimpleDateFormat("HH:mm:ss.SSS");
+ private ConcurrentLinkedQueue executionRecord;
+ //------------------------------------------------------------------------------------------------------------
+
+ // Test State - Initialized in initialize() ------------------------------------------------------------------
+ private ExecutorService executor;
+ private Query> query;
+ private Collection> processors;
+ private Set> unfinishedInstructions;
+ //------------------------------------------------------------------------------------------------------------
+
+ @Test
+ public void testAbortingHeavyLoadQuery() throws InterruptedException, ExecutionException {
+ // Executing query in separate thread
+ RunnableFuture>> queryTask = new FutureTask<>(() -> {
+ logExecution("Starting query execution");
+ long start = System.currentTimeMillis();
+ QueryResult> result = query.run();
+ long duration = System.currentTimeMillis() - start;
+ logExecution("Finished query in " + duration + "ms");
+ return result;
+ });
+ Thread worker = new Thread(queryTask, "Worker");
+ worker.start();
+ do {
+ Thread.sleep(10);
+ } while (query.getState() != QueryState.RUNNING);
+
+ // Aborting query and waiting for completion
+ Thread.sleep(AbortQueryDelay);
+ logExecution("Aborting query");
+ query.abort();
+ QueryResult> result = queryTask.get();
+
+ // The query execution returned, so all processors are aborted (checked below).
+ // The number of unfinished instructions mustn't change after this point
+ int unfinishedInstructionsCount = unfinishedInstructions.size();
+ boolean unfinishedInstructionWasFinished = false;
+ Set> runningInstructions = new HashSet<>();
+ Set> notStartedInstructions = new HashSet<>();
+ for (StatefulProcessorInstruction> instruction : unfinishedInstructions) {
+ if (instruction.runWasCalled()) {
+ runningInstructions.add(instruction);
+ } else {
+ notStartedInstructions.add(instruction);
+ }
+ unfinishedInstructionWasFinished |= instruction.computeResultWasFinished();
+ }
+ logExecution(unfinishedInstructionsCount + " unfinished instructions left - " +
+ runningInstructions.size() + " running, " + notStartedInstructions.size() + " not started");
+ printExecutionRecord();
+ assertThat("Number of unfinished instructions changed", runningInstructions.size() + notStartedInstructions.size(), is(unfinishedInstructionsCount));
+ assertFalse("Unfinished instructions expected, but at least one was completed", unfinishedInstructionWasFinished);
+
+ // Checking query, result and processor chain state
+ assertThat(query.getState(), is(QueryState.ABORTED));
+ assertThat(result.getState(), is(QueryResultState.ABORTED));
+ assertTrue("The result is not empty", result.isEmpty());
+ for (Processor, ?> processor : processors) {
+ assertTrue("Processor wasn't aborted", processor.isAborted());
+ }
+
+ // Execution of unfinished instructions
+ executor.shutdown();
+ boolean terminated = executor.awaitTermination(TerminationTimeout, TimeUnit.MILLISECONDS);
+ printExecutionRecord();
+ assertTrue("The executor didn't terminate in the given time", terminated);
+
+ // Verify that the collection of unfinished instructions didn't change
+ assertThat("Number of unfinished instructions changed", unfinishedInstructions.size(), is(unfinishedInstructionsCount));
+ for (StatefulProcessorInstruction> instruction : unfinishedInstructions) {
+ boolean previouslyContained = runningInstructions.contains(instruction) || notStartedInstructions.contains(instruction);
+ assertTrue("A new instruction has been scheduled after aborting the query", previouslyContained);
+ }
+ for (StatefulProcessorInstruction> instruction : runningInstructions) {
+ assertTrue("A previously running instruction was removed from unfinished instructions", unfinishedInstructions.contains(instruction));
+ }
+ for (StatefulProcessorInstruction> instruction : notStartedInstructions) {
+ assertTrue("A previously unstarted instruction was removed from unfinished instructions", unfinishedInstructions.contains(instruction));
+ }
+
+ // Checking state of unfinished instructions
+ for (StatefulProcessorInstruction> instruction : runningInstructions) {
+ assertTrue("computeResult() of a running unfinished instruction wasn't called", instruction.computeResultWasCalled());
+ assertTrue("computeResult() of a running unfinished instruction didn't finish", instruction.computeResultWasFinished());
+ if (instruction instanceof StatefulBlockingInstruction) {
+ StatefulBlockingInstruction> blockingInstruction = (StatefulBlockingInstruction>) instruction;
+ assertTrue("computeResult() of a running heavy load instruction wasn't aborted", blockingInstruction.computeResultWasAborted());
+ }
+ }
+ for (StatefulProcessorInstruction> instruction : notStartedInstructions) {
+ assertTrue("run() of an unstarted unfinished instruction wasn't called", instruction.runWasCalled());
+
+ assertFalse("computeResult() of an unstarted unfinished instruction was called", instruction.computeResultWasCalled());
+ assertFalse("computeResult() of an unstarted unfinished instruction was finished", instruction.computeResultWasFinished());
+ }
+ }
+
+ private void printExecutionRecord() {
+ if (RecordExecution) {
+ Collection snapshot = new ArrayList<>(executionRecord);
+ executionRecord.clear();
+ for (String string : snapshot) {
+ System.out.println(string);
+ }
+ }
+ }
+
+ private void logExecution(String message) {
+ if (RecordExecution) {
+ String timeString = DateFormatter.format(new Date());
+ executionRecord.add(timeString + " - " + Thread.currentThread().getName() + ": " + message);
+ }
+ }
+
+ /**
+ * Initializes the {@link ExecutorService}, the execution record, helper collections (e.g. the processors in the
+ * chain or the unfinished instructions) and most importantly the processor chain for the query, which works as
+ * follows:
+ *
+ *
+ * The initial data source is a collection of strings from {@value #GroupKeyPrefix}n to
+ * {@value #GroupKeyPrefix}n-1, denoting a group. n is specified in {@link #DataSourceSize}.
+ *
+ *
+ * x (specified by {@link #ExecutorPoolSize}) {@link Element elements} are retrieved for each
+ * group, where the elements name is set to the received string and the elements value is the current value
+ * of x.
+ *
+ *
+ * A heavy load instruction for each element is scheduled, which blocks the running thread for
+ * {@value #HeavyLoadInstructionTotalDuration}ms.
+ *
+ *
+ * Each element is grouped by its name and its value is used as value for the {@link GroupedDataEntry}.
+ *
+ *
The grouped data is collected as set.
+ *
+ * This results in n * x data elements (and heavy load instructions), with x instructions
+ * executed concurrently.
+ *
+ * Each processor creates {@link StatefulProcessorInstruction} or uses {@link StatefulInstructionWrapper}, which allows
+ * to verify if instruction.run() was called, its computation started and its computation finished.
+ *
+ * A concurrent set ({@link ConcurrentHashMap#newKeySet()}) is used to track the unfinished instructions. An instruction
+ * is added to the set upon its construction and is removed when the instruction finished callback method is called.
+ */
+ @Before
+ @SuppressWarnings("unchecked")
+ public void initialize() {
+ if (RecordExecution) {
+ executionRecord = new ConcurrentLinkedQueue<>();
+ }
+
+ executor = new DataMiningExecutorService(ExecutorPoolSize);
+// executor = new ThreadPoolExecutor(ExecutorPoolSize, ExecutorPoolSize, 0, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<>());
+// executor = new ThreadPoolExecutor(ExecutorPoolSize, ExecutorPoolSize, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
+ processors = new ArrayList<>();
+ unfinishedInstructions = ConcurrentHashMap.newKeySet();
+
+ Class> dataSourceType = (Class>)(Class>) Iterable.class;
+ Class> groupedType = (Class>)(Class>) GroupedDataEntry.class;
+ Class> resultType = (Class>)(Class>) HashSet.class;
+
+ Collection dataSource = new ArrayList<>(DataSourceSize);
+ for (int i = 0; i < DataSourceSize; i++) {
+ dataSource.add(GroupKeyPrefix + i);
+ }
+ query = new ProcessorQuery, Iterable>(dataSource, resultType) {
+ @Override
+ protected Processor, ?> createChainAndReturnFirstProcessor(Processor