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.dashboards.gwt/.project b/java/com.sap.sailing.dashboards.gwt/.project
index 65425ba1398..520fc2bd59d 100644
--- a/java/com.sap.sailing.dashboards.gwt/.project
+++ b/java/com.sap.sailing.dashboards.gwt/.project
@@ -20,16 +20,6 @@
-
- com.google.gdt.eclipse.core.webAppProjectValidator
-
-
-
-
- com.google.gwt.eclipse.core.gwtProjectValidator
-
-
- com.gwtplugins.gdt.eclipse.core.webAppProjectValidator
@@ -44,7 +34,6 @@
org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
- com.google.gwt.eclipse.core.gwtNaturecom.gwtplugins.gwt.eclipse.core.gwtNature
diff --git a/java/com.sap.sailing.dashboards.gwt/GWT Dashboards DevMode.launch b/java/com.sap.sailing.dashboards.gwt/GWT Dashboards DevMode.launch
index 28937ea9e3e..7310aa92bc6 100644
--- a/java/com.sap.sailing.dashboards.gwt/GWT Dashboards DevMode.launch
+++ b/java/com.sap.sailing.dashboards.gwt/GWT Dashboards DevMode.launch
@@ -3,7 +3,10 @@
-
+
+
+
+
@@ -19,84 +22,25 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/java/com.sap.sailing.dashboards.gwt/GWT Dashboards SDM.launch b/java/com.sap.sailing.dashboards.gwt/GWT Dashboards SDM.launch
index 9a058165d0a..c5fc2f809c2 100644
--- a/java/com.sap.sailing.dashboards.gwt/GWT Dashboards SDM.launch
+++ b/java/com.sap.sailing.dashboards.gwt/GWT Dashboards SDM.launch
@@ -3,7 +3,7 @@
-
+
@@ -24,22 +24,24 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT sdm.launch b/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT sdm.launch
deleted file mode 100644
index a9c1dda4f80..00000000000
--- a/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT sdm.launch
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT.launch b/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT.launch
deleted file mode 100644
index 6dc3f4ffd8d..00000000000
--- a/java/com.sap.sailing.dashboards.gwt/SailingDashboardsGWT.launch
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/java/com.sap.sailing.datamining.shared/.project b/java/com.sap.sailing.datamining.shared/.project
index 07fda63ea6f..3e76c7f629f 100644
--- a/java/com.sap.sailing.datamining.shared/.project
+++ b/java/com.sap.sailing.datamining.shared/.project
@@ -21,12 +21,12 @@
- com.google.gdt.eclipse.core.webAppProjectValidator
+ com.gwtplugins.gdt.eclipse.core.webAppProjectValidator
- com.google.gwt.eclipse.core.gwtProjectValidator
+ com.gwtplugins.gwt.eclipse.core.gwtProjectValidator
@@ -34,6 +34,6 @@
org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
- com.google.gwt.eclipse.core.gwtNature
+ com.gwtplugins.gwt.eclipse.core.gwtNature
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/.project b/java/com.sap.sailing.datamining/.project
index 39e695078e3..f40554ff5f4 100644
--- a/java/com.sap.sailing.datamining/.project
+++ b/java/com.sap.sailing.datamining/.project
@@ -21,18 +21,19 @@
- com.google.gdt.eclipse.core.webAppProjectValidator
+ com.gwtplugins.gdt.eclipse.core.webAppProjectValidator
- com.google.gwt.eclipse.core.gwtProjectValidator
+ com.gwtplugins.gwt.eclipse.core.gwtProjectValidator
-
+
+
org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
- com.google.gwt.eclipse.core.gwtNature
+ com.gwtplugins.gwt.eclipse.core.gwtNature
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.common/.project b/java/com.sap.sailing.domain.common/.project
index 8c2ade13ac6..7779c8b14a0 100755
--- a/java/com.sap.sailing.domain.common/.project
+++ b/java/com.sap.sailing.domain.common/.project
@@ -21,12 +21,12 @@
- com.google.gdt.eclipse.core.webAppProjectValidator
+ com.gwtplugins.gdt.eclipse.core.webAppProjectValidator
- com.google.gwt.eclipse.core.gwtProjectValidator
+ com.gwtplugins.gwt.eclipse.core.gwtProjectValidator
@@ -34,6 +34,6 @@
org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
- com.google.gwt.eclipse.core.gwtNature
+ com.gwtplugins.gwt.eclipse.core.gwtNature
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BasicRaceDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BasicRaceDTO.java
index 0af8c31849b..3b8053ea0b5 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BasicRaceDTO.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BasicRaceDTO.java
@@ -18,6 +18,7 @@ public class BasicRaceDTO extends NamedDTO {
public Date startOfRace;
public Date endOfRace;
+ public Date raceFinishedTime;
public TrackedRaceDTO trackedRace;
public BasicRaceDTO() {} // for GWT serialization only
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java
index fd2bb4ca0e7..7f904a4694c 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java
@@ -55,10 +55,6 @@ public class RaceStateImpl extends ReadonlyRaceStateImpl implements RaceState {
private final AbstractLogEventAuthor author;
- public static ReadonlyRaceState create(RaceLogResolver raceLogResolver, RaceLog raceLog) {
- return create(raceLogResolver, raceLog, /* forRaceLogIdentifier */ null, Collections.emptyMap());
- }
-
/**
* Creates a {@link RaceState} with the initial racing procedure type set to a fallback value and an empty configuration.
*/
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java
index 67d7140fbf9..4904be72af4 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java
@@ -44,6 +44,7 @@ import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.Util;
+import com.sap.sse.util.WeakIdentityHashMap;
/**
* Implementation of {@link ReadonlyRaceState}. Use the static factory methods to instantiate your race state.
@@ -55,8 +56,37 @@ import com.sap.sse.common.Util;
* See {@link ReadonlyRaceStateImpl#update()} for the core of the algorithm.
*/
public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedListener {
-
- public static ReadonlyRaceState create(RaceLogResolver raceLogResolver, RaceLog raceLog) {
+ private static final WeakIdentityHashMap> raceStateCache =
+ new WeakIdentityHashMap<>();
+
+ /**
+ * Obtains a race state for the combination of {@code raceLog} and {@code raceLogResolver}. The result is
+ * cache using weak references to the race log and the race log resolver for quick retrieval upon equal
+ * requests, saving memory, saving listeners and thereby avoiding more synchronization issues.
+ *
+ * See also bug4704.
+ */
+ public static ReadonlyRaceState getOrCreate(RaceLogResolver raceLogResolver, RaceLog raceLog) {
+ WeakIdentityHashMap raceStatesForRaceLog;
+ ReadonlyRaceState result = null;
+ synchronized (raceStateCache) {
+ raceStatesForRaceLog = raceStateCache.get(raceLog);
+ if (raceStatesForRaceLog == null) {
+ raceStatesForRaceLog = new WeakIdentityHashMap<>();
+ raceStateCache.put(raceLog, raceStatesForRaceLog);
+ } else {
+ result = raceStatesForRaceLog.get(raceLogResolver);
+ }
+ if (result == null) {
+ result = createInternal(raceLogResolver, raceLog);
+ raceStatesForRaceLog.put(raceLogResolver, result);
+ }
+ }
+ return result;
+ }
+
+
+ private static final ReadonlyRaceState createInternal(RaceLogResolver raceLogResolver, RaceLog raceLog) {
return create(raceLogResolver, raceLog, /* forRaceLogIdentifier */null,
Collections. emptyMap());
}
diff --git a/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/FieldNames.java b/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/FieldNames.java
index d90bffeb0ca..26a4a5053ff 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/FieldNames.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/FieldNames.java
@@ -2,7 +2,8 @@ package com.sap.sailing.domain.swisstimingadapter.persistence.impl;
public enum FieldNames {
// SwissTiming configuration parameters:
- ST_CONFIG_NAME, ST_CONFIG_HOSTNAME, ST_CONFIG_PORT, ST_CONFIG_JSON_URL, ST_ARCHIVE_JSON_URL,
+ ST_CONFIG_NAME, ST_CONFIG_HOSTNAME, ST_CONFIG_PORT, ST_CONFIG_JSON_URL, ST_CONFIG_UPDATE_URL,
+ ST_CONFIG_UPDATE_USERNAME, ST_CONFIG_UPDATE_PASSWORD, ST_ARCHIVE_JSON_URL,
// last message count field:
LAST_MESSAGE_COUNT,
diff --git a/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingAdapterPersistenceImpl.java b/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingAdapterPersistenceImpl.java
index 7d6b0d260f8..71d8b5d3a54 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingAdapterPersistenceImpl.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingAdapterPersistenceImpl.java
@@ -37,8 +37,8 @@ public class SwissTimingAdapterPersistenceImpl implements SwissTimingAdapterPers
DBCollection stConfigs = database.getCollection(CollectionNames.SWISSTIMING_CONFIGURATIONS.name());
for (DBObject o : stConfigs.find()) {
SwissTimingConfiguration stConfig = loadSwissTimingConfiguration(o);
- // the old swisstiming config was not based on a json URL -> ignore such configs
- if(stConfig.getJsonURL() != null) {
+ // the old SwissTiming configuration was not based on a JSON URL -> ignore such configurations
+ if (stConfig.getJsonURL() != null) {
result.add(stConfig);
}
}
@@ -57,8 +57,10 @@ public class SwissTimingAdapterPersistenceImpl implements SwissTimingAdapterPers
String jsonURL = (String) object.get(FieldNames.ST_CONFIG_JSON_URL.name());
String hostname = (String) object.get(FieldNames.ST_CONFIG_HOSTNAME.name());
Integer port = (Integer) object.get(FieldNames.ST_CONFIG_PORT.name());
-
- return swissTimingFactory.createSwissTimingConfiguration(name, jsonURL, hostname, port);
+ String updateURL = (String) object.get(FieldNames.ST_CONFIG_UPDATE_URL.name());
+ String updateUsername = (String) object.get(FieldNames.ST_CONFIG_UPDATE_USERNAME.name());
+ String updatePassword = (String) object.get(FieldNames.ST_CONFIG_UPDATE_PASSWORD.name());
+ return swissTimingFactory.createSwissTimingConfiguration(name, jsonURL, hostname, port, updateURL, updateUsername, updatePassword);
}
@Override
@@ -96,6 +98,9 @@ public class SwissTimingAdapterPersistenceImpl implements SwissTimingAdapterPers
result.put(FieldNames.ST_CONFIG_JSON_URL.name(), swissTimingConfiguration.getJsonURL());
result.put(FieldNames.ST_CONFIG_HOSTNAME.name(), swissTimingConfiguration.getHostname());
result.put(FieldNames.ST_CONFIG_PORT.name(), swissTimingConfiguration.getPort());
+ result.put(FieldNames.ST_CONFIG_UPDATE_URL.name(), swissTimingConfiguration.getUpdateURL());
+ result.put(FieldNames.ST_CONFIG_UPDATE_USERNAME.name(), swissTimingConfiguration.getUpdateUsername());
+ result.put(FieldNames.ST_CONFIG_UPDATE_PASSWORD.name(), swissTimingConfiguration.getUpdatePassword());
stConfigCollection.insert(result);
}
diff --git a/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingConnectivityParamsHandler.java b/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingConnectivityParamsHandler.java
index a034257ea2b..5c8dca04bae 100644
--- a/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingConnectivityParamsHandler.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter.persistence/src/com/sap/sailing/domain/swisstimingadapter/persistence/impl/SwissTimingConnectivityParamsHandler.java
@@ -54,6 +54,9 @@ public class SwissTimingConnectivityParamsHandler extends AbstractRaceTrackingCo
private static final String PORT = "port";
private static final String BOAT_CLASS_NAME = "boatClassName";
private static final String HOSTNAME = "hostname";
+ private static final String UPDATE_URL = "updateURL";
+ private static final String UPDATE_USERNAME = "updateUsername";
+ private static final String UPDATE_PASSWORD = "updatePassword";
private final RaceLogStore raceLogStore;
private final RegattaLogStore regattaLogStore;
private final DomainFactory domainFactory;
@@ -78,6 +81,9 @@ public class SwissTimingConnectivityParamsHandler extends AbstractRaceTrackingCo
result.put(START_LIST, createStartListDBObject(stParams));
result.put(DELAY_TO_LIVE_IN_MILLIS, stParams.getDelayToLiveInMillis());
result.put(USE_INTERNAL_MARK_PASSING_ALGORITHM, stParams.isUseInternalMarkPassingAlgorithm());
+ result.put(UPDATE_URL, stParams.getUpdateURL());
+ result.put(UPDATE_USERNAME, stParams.getUpdateUsername());
+ result.put(UPDATE_PASSWORD, stParams.getUpdatePassword());
addWindTrackingParameters(stParams, result);
return result;
}
@@ -175,7 +181,10 @@ public class SwissTimingConnectivityParamsHandler extends AbstractRaceTrackingCo
map.get(START_LIST) == null ? null : createStartListFromDBObject((String) map.get(RACE_ID), (BasicDBList) map.get(START_LIST)),
((Number) map.get(DELAY_TO_LIVE_IN_MILLIS)).longValue(),
swissTimingFactory, domainFactory, raceLogStore, regattaLogStore,
- (boolean) map.get(USE_INTERNAL_MARK_PASSING_ALGORITHM), isTrackWind(map), isCorrectWindDirectionByMagneticDeclination(map));
+ (boolean) map.get(USE_INTERNAL_MARK_PASSING_ALGORITHM), isTrackWind(map), isCorrectWindDirectionByMagneticDeclination(map),
+ (String) map.get(UPDATE_URL),
+ (String) map.get(UPDATE_USERNAME),
+ (String) map.get(UPDATE_PASSWORD));
}
@Override
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/DomainFactory.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/DomainFactory.java
index b8036a8adc0..c9a4979fa1f 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/DomainFactory.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/DomainFactory.java
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.swisstimingadapter;
import java.io.Serializable;
+import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
@@ -18,6 +19,7 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sailing.domain.swisstimingadapter.impl.DomainFactoryImpl;
+import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
@@ -70,10 +72,17 @@ public interface DomainFactory {
RaceTrackingConnectivityParameters createTrackingConnectivityParameters(String hostname, int port, String raceID,
String raceName, String raceDescription, BoatClass boatClass, StartList startList,
long delayToLiveInMillis, SwissTimingFactory swissTimingFactory, DomainFactory domainFactory,
- RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination);
+ RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, String updateURL, String updateUsername, String updatePassword);
ControlPoint getOrCreateControlPoint(String description, Iterable deviceIds, MarkType markType);
RaceDefinition createRaceDefinition(Regatta regatta, String swissTimingRaceID, Map competitorsAndBoats,
List courseDefinition, String raceName, String raceIdForRaceDefinition);
+
+ /**
+ * Adds update handlers that forward events about a race, such as start time changes, course changes
+ * or postponents, to an update URL using specific REST requests.
+ */
+ void addUpdateHandlers(String updateURL, String username, String password, Serializable eventId,
+ RaceDefinition raceDefinition, DynamicTrackedRace trackedRace) throws URISyntaxException;
}
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SailMasterListener.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SailMasterListener.java
index 10f4669c7f5..cdeaf3a7368 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SailMasterListener.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SailMasterListener.java
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.swisstimingadapter;
+import java.net.URISyntaxException;
import java.util.Collection;
import java.util.List;
@@ -16,9 +17,9 @@ public interface SailMasterListener {
void receivedClockAtMark(String raceID, List> markIndicesTimePointsAndBoatIDs);
- void receivedStartList(String raceID, StartList startList);
+ void receivedStartList(String raceID, StartList startList) throws URISyntaxException;
- void receivedCourseConfiguration(String raceID, Course course);
+ void receivedCourseConfiguration(String raceID, Course course) throws URISyntaxException;
void receivedAvailableRaces(Iterable races);
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingAdapter.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingAdapter.java
index e275b3573c8..bcb05fe84c4 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingAdapter.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingAdapter.java
@@ -26,12 +26,10 @@ public interface SwissTimingAdapter {
* is specified, a regatta lookup is performed with that identifier; if the regatta is found, it is used
* to add the races to. Otherwise, a default regatta as described above will be created and used.
* @param useInternalMarkPassingAlgorithm use our own instead of the SwissTiming-provided mark passing / split times
- * @param trackWind TODO
- * @param correctWindDirectionByMagneticDeclination TODO
*/
RaceHandle addSwissTimingRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, String raceID,
String raceName, String raceDescription, BoatClass boatClass, String hostname, int port,
- StartList startList, RaceLogStore logStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination)
+ StartList startList, RaceLogStore logStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, String updateURL, String updateUsername, String updatePassword)
throws InterruptedException, UnknownHostException, IOException, ParseException, Exception;
StartList readStartListForRace(String raceId, RegattaResults regattaResults);
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingConfiguration.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingConfiguration.java
index 293eff3c8be..09c500c6581 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingConfiguration.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingConfiguration.java
@@ -14,4 +14,10 @@ public interface SwissTimingConfiguration {
String getHostname();
Integer getPort();
+
+ String getUpdateURL();
+
+ String getUpdateUsername();
+
+ String getUpdatePassword();
}
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java
index 8badef20f87..33ea647eaa3 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java
@@ -49,20 +49,14 @@ public interface SwissTimingFactory {
SailMasterTransceiver createSailMasterTransceiver();
- SwissTimingConfiguration createSwissTimingConfiguration(String name, String jsonURL, String hostname, Integer port);
+ SwissTimingConfiguration createSwissTimingConfiguration(String name, String jsonURL, String hostname, Integer port, String updateURL, String updateUsername, String updatePassword);
- SwissTimingRaceTracker createRaceTracker(String raceID, String raceName, String raceDescription,
- BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
- RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore,
- boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
- TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, SwissTimingTrackingConnectivityParameters connectivityParams) throws InterruptedException, UnknownHostException,
- IOException, ParseException;
+ SwissTimingRaceTracker createRaceTracker(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore,
+ DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, SwissTimingTrackingConnectivityParameters connectivityParams)
+ throws InterruptedException, UnknownHostException, IOException, ParseException;
- RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription,
- BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
- WindStore windStore, boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
- TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, RaceLogStore raceLogStore,
- RegattaLogStore regattaLogStore, SwissTimingTrackingConnectivityParameters connectivityParams)
+ RaceTracker createRaceTracker(Regatta regatta, WindStore windStore, DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry,
+ RaceLogResolver raceLogResolver, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, SwissTimingTrackingConnectivityParameters connectivityParams)
throws UnknownHostException, InterruptedException, IOException, ParseException;
Race createRace(String raceId, String raceName, String description, BoatClass boatClass);
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java
index 5c493877887..758369f0b5b 100644
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/DomainFactoryImpl.java
@@ -1,6 +1,8 @@
package com.sap.sailing.domain.swisstimingadapter.impl;
import java.io.Serializable;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
@@ -50,9 +52,14 @@ import com.sap.sailing.domain.swisstimingadapter.RaceType;
import com.sap.sailing.domain.swisstimingadapter.RaceType.OlympicRaceCode;
import com.sap.sailing.domain.swisstimingadapter.StartList;
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
+import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
+import com.sap.sailing.domain.tracking.impl.CourseDesignUpdateHandler;
+import com.sap.sailing.domain.tracking.impl.FinishTimeUpdateHandler;
+import com.sap.sailing.domain.tracking.impl.RaceAbortedHandler;
+import com.sap.sailing.domain.tracking.impl.StartTimeUpdateHandler;
import com.sap.sse.common.Named;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -402,9 +409,29 @@ public class DomainFactoryImpl implements DomainFactory {
String raceID, String raceName, String raceDescription, BoatClass boatClass, StartList startList,
long delayToLiveInMillis, SwissTimingFactory swissTimingFactory, DomainFactory domainFactory,
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm,
- boolean trackWind, boolean correctWindDirectionByMagneticDeclination) {
+ boolean trackWind, boolean correctWindDirectionByMagneticDeclination, String updateURL,
+ String updateUsername, String updatePassword) {
return new SwissTimingTrackingConnectivityParameters(hostname, port, raceID, raceName, raceDescription,
boatClass, startList, delayToLiveInMillis, swissTimingFactory, domainFactory, raceLogStore,
- regattaLogStore, useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination);
+ regattaLogStore, useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination,
+ updateURL, updateUsername, updatePassword);
+ }
+
+ @Override
+ public void addUpdateHandlers(String updateURL, String username, String password, Serializable eventId,
+ RaceDefinition raceDefinition, DynamicTrackedRace trackedRace) throws URISyntaxException {
+ final URI updateURI = new URI(updateURL);
+ CourseDesignUpdateHandler courseDesignHandler = new CourseDesignUpdateHandler(
+ updateURI, username, password, eventId, raceDefinition.getId());
+ StartTimeUpdateHandler startTimeHandler = new StartTimeUpdateHandler(
+ updateURI, username, password, eventId,
+ raceDefinition.getId(), trackedRace.getTrackedRegatta().getRegatta());
+ RaceAbortedHandler raceAbortedHandler = new RaceAbortedHandler(
+ updateURI, username, password, eventId,
+ raceDefinition.getId());
+ final FinishTimeUpdateHandler finishTimeUpdateHandler = new FinishTimeUpdateHandler(updateURI, username, password, eventId,
+ raceDefinition.getId(), trackedRace.getTrackedRegatta().getRegatta());
+ baseDomainFactory.addUpdateHandlers(trackedRace, courseDesignHandler, startTimeHandler, raceAbortedHandler,
+ finishTimeUpdateHandler);
}
}
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingAdapterImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingAdapterImpl.java
index 9d386a29c6b..a7978a8d466 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingAdapterImpl.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingAdapterImpl.java
@@ -69,12 +69,13 @@ public class SwissTimingAdapterImpl implements SwissTimingAdapter {
public RaceHandle addSwissTimingRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, String raceID,
String raceName, String raceDescription, BoatClass boatClass, String hostname, int port,
StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds,
- boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) throws Exception {
+ boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination,
+ String updateURL, String updateUsername, String updatePassword) throws Exception {
return trackerManager.addRace(regattaToAddTo,
swissTimingDomainFactory.createTrackingConnectivityParameters(hostname, port, raceID, raceName,
raceDescription, boatClass, startList, DEFAULT_SWISSTIMING_LIVE_DELAY_IN_MILLISECONDS,
swissTimingFactory, swissTimingDomainFactory, raceLogStore, regattaLogStore,
- useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination),
+ useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination, updateURL, updateUsername, updatePassword),
timeoutInMilliseconds);
}
@@ -118,9 +119,9 @@ public class SwissTimingAdapterImpl implements SwissTimingAdapter {
Person person = persons.get(crewMember.getPersonID());
crew.add(new CrewMemberImpl(
person.getGivenName() + " " + person.getFamilyName(),
- person.getNOC().name(), crewMember.getPosition().name()));
+ (person.getNOC()==null)?null:(person.getNOC().name()), crewMember.getPosition().name()));
}
- String nationality = team.getNOC().name();
+ String nationality = team.getNOC()==null?null:team.getNOC().name();
CompetitorWithID competitor = new CompetitorWithID(team.getTeamID(),
boat.getSailNumber(), nationality, team.getTeamName(), crew);
competitors.add(competitor);
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingConfigurationImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingConfigurationImpl.java
index c16ca7a5b71..8c1087e2d11 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingConfigurationImpl.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingConfigurationImpl.java
@@ -7,13 +7,19 @@ public class SwissTimingConfigurationImpl implements SwissTimingConfiguration {
private final String jsonURL;
private final String hostname;
private final Integer port;
+ private final String updateURL;
+ private final String updateUsername;
+ private final String updatePassword;
- public SwissTimingConfigurationImpl(String name, String jsonURL, String hostname, Integer port) {
+ public SwissTimingConfigurationImpl(String name, String jsonURL, String hostname, Integer port, String updateURL, String updateUsername, String updatePassword) {
super();
this.name = name;
this.jsonURL = jsonURL;
this.hostname = hostname;
this.port = port;
+ this.updateURL = updateURL;
+ this.updateUsername = updateUsername;
+ this.updatePassword = updatePassword;
}
@Override
@@ -36,4 +42,15 @@ public class SwissTimingConfigurationImpl implements SwissTimingConfiguration {
return port;
}
+ public String getUpdateURL() {
+ return updateURL;
+ }
+
+ public String getUpdateUsername() {
+ return updateUsername;
+ }
+
+ public String getUpdatePassword() {
+ return updatePassword;
+ }
}
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java
index 9d7b4b82cb1..70236e46404 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java
@@ -17,7 +17,6 @@ import com.sap.sailing.domain.swisstimingadapter.Race;
import com.sap.sailing.domain.swisstimingadapter.SailMasterConnector;
import com.sap.sailing.domain.swisstimingadapter.SailMasterMessage;
import com.sap.sailing.domain.swisstimingadapter.SailMasterTransceiver;
-import com.sap.sailing.domain.swisstimingadapter.StartList;
import com.sap.sailing.domain.swisstimingadapter.SwissTimingArchiveConfiguration;
import com.sap.sailing.domain.swisstimingadapter.SwissTimingConfiguration;
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
@@ -83,32 +82,27 @@ public class SwissTimingFactoryImpl implements SwissTimingFactory {
}
@Override
- public SwissTimingConfiguration createSwissTimingConfiguration(String name, String jsonURL, String hostname, Integer port) {
- return new SwissTimingConfigurationImpl(name, jsonURL, hostname, port);
+ public SwissTimingConfiguration createSwissTimingConfiguration(String name, String jsonURL, String hostname,
+ Integer port, String updateURL, String updateUsername, String updatePassword) {
+ return new SwissTimingConfigurationImpl(name, jsonURL, hostname, port, updateURL, updateUsername, updatePassword);
}
@Override
- public SwissTimingRaceTracker createRaceTracker(String raceID, String raceName, String raceDescription,
- BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
- RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore,
- boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
- TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, SwissTimingTrackingConnectivityParameters connectivityParams)
+ public SwissTimingRaceTracker createRaceTracker(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
+ WindStore windStore, DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry,
+ RaceLogResolver raceLogResolver, SwissTimingTrackingConnectivityParameters connectivityParams)
throws InterruptedException, UnknownHostException, IOException, ParseException {
- return new SwissTimingRaceTrackerImpl(raceID, raceName, raceDescription, boatClass, hostname, port, startList,
- raceLogStore, regattaLogStore, windStore, domainFactory, this,
- trackedRegattaRegistry, raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm, connectivityParams);
+ return new SwissTimingRaceTrackerImpl(raceLogStore, regattaLogStore, windStore, domainFactory, this,
+ trackedRegattaRegistry, raceLogResolver, connectivityParams);
}
@Override
- public RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription,
- BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
- WindStore windStore, boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
+ public RaceTracker createRaceTracker(Regatta regatta, WindStore windStore, DomainFactory domainFactory,
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, RaceLogStore raceLogStore,
RegattaLogStore regattaLogStore, SwissTimingTrackingConnectivityParameters connectivityParams)
throws UnknownHostException, InterruptedException, IOException, ParseException {
- return new SwissTimingRaceTrackerImpl(regatta, raceID, raceName, raceDescription, boatClass, hostname, port,
- startList, windStore, domainFactory, this, trackedRegattaRegistry, raceLogStore, regattaLogStore,
- raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm, connectivityParams);
+ return new SwissTimingRaceTrackerImpl(regatta, windStore, domainFactory, this, trackedRegattaRegistry,
+ raceLogStore, regattaLogStore, raceLogResolver, connectivityParams);
}
@Override
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java
index e963f7c5033..8b960a35e78 100644
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.swisstimingadapter.impl;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
+import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.Collection;
@@ -63,6 +64,7 @@ import com.sap.sailing.domain.tracking.TrackingDataLoader;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.impl.TrackedRaceStatusImpl;
+import com.sap.sailing.domain.tracking.impl.UpdateHandler;
import com.sap.sse.common.Distance;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -110,23 +112,30 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
private final TMDMessageQueue tmdMessageQueue;
private final RaceLogResolver raceLogResolver;
+
+ /**
+ * If set to a non-{@code null}, non-{@link String#isEmpty() empty} value, updates about start time changes, course
+ * changes, etc. will be sent as REST requests to this URL, using the {@link #updateUsername} /
+ * {@link #updatePassword} as credentials.
+ */
+ private final String updateURL;
+
+ private final String updateUsername;
+
+ private final String updatePassword;
- protected SwissTimingRaceTrackerImpl(String raceID, String raceName, String raceDescription, BoatClass boatClass,
- String hostname, int port, StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
+ protected SwissTimingRaceTrackerImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, DomainFactory domainFactory, SwissTimingFactory factory,
- TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, long delayToLiveInMillis,
- boolean useInternalMarkPassingAlgorithm, SwissTimingTrackingConnectivityParameters connectivityParams) throws InterruptedException,
- UnknownHostException, IOException, ParseException {
- this(/* regatta */ null, raceID, raceName, raceDescription, boatClass, hostname, port, startList, windStore,
- domainFactory, factory, trackedRegattaRegistry, raceLogStore, regattaLogStore, raceLogResolver,
- delayToLiveInMillis, useInternalMarkPassingAlgorithm, connectivityParams);
+ TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver,
+ SwissTimingTrackingConnectivityParameters connectivityParams)
+ throws InterruptedException, UnknownHostException, IOException, ParseException {
+ this(/* regatta */ null, windStore, domainFactory, factory, trackedRegattaRegistry, raceLogStore, regattaLogStore, raceLogResolver, connectivityParams);
}
- protected SwissTimingRaceTrackerImpl(Regatta regatta, String raceID, String raceName, String raceDescription,
- BoatClass boatClass, String hostname, int port, StartList startList, WindStore windStore,
- DomainFactory domainFactory, SwissTimingFactory factory, TrackedRegattaRegistry trackedRegattaRegistry,
- RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, RaceLogResolver raceLogResolver,
- long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm, SwissTimingTrackingConnectivityParameters connectivityParams)
+ protected SwissTimingRaceTrackerImpl(Regatta regatta, WindStore windStore, DomainFactory domainFactory,
+ SwissTimingFactory factory, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogStore raceLogStore,
+ RegattaLogStore regattaLogStore, RaceLogResolver raceLogResolver,
+ SwissTimingTrackingConnectivityParameters connectivityParams)
throws InterruptedException, UnknownHostException, IOException, ParseException {
super(connectivityParams);
this.raceLogResolver = raceLogResolver;
@@ -134,29 +143,33 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
final Regatta effectiveRegatta;
// Try to find a pre-associated event based on the Race ID
if (regatta == null) {
- effectiveRegatta = trackedRegattaRegistry.getRememberedRegattaForRace(raceID);
+ effectiveRegatta = trackedRegattaRegistry.getRememberedRegattaForRace(connectivityParams.getRaceID());
} else {
effectiveRegatta = regatta;
}
// if regatta is still null, no previous assignment of any of the races in this TracTrac event to a Regatta was
// found; in this case, create a default regatta based on the TracTrac event data
this.regatta = effectiveRegatta == null ? domainFactory.getOrCreateDefaultRegatta(raceLogStore, regattaLogStore,
- raceID, boatClass, trackedRegattaRegistry) : effectiveRegatta;
- this.connector = factory.getOrCreateSailMasterConnector(hostname, port, raceID, raceName, raceDescription, boatClass);
+ connectivityParams.getRaceID(), connectivityParams.getBoatClass(), trackedRegattaRegistry) : effectiveRegatta;
+ this.connector = factory.getOrCreateSailMasterConnector(connectivityParams.getHostname(), connectivityParams.getPort(),
+ connectivityParams.getRaceID(), connectivityParams.getRaceName(), connectivityParams.getRaceDescription(), connectivityParams.getBoatClass());
this.domainFactory = domainFactory;
- this.raceID = raceID;
- this.raceName = raceName;
- this.startList = startList;
- this.startListFromManage2Sail = startList != null;
- this.raceDescription = raceDescription;
- this.boatClass = boatClass;
+ this.raceID = connectivityParams.getRaceID();
+ this.raceName = connectivityParams.getRaceName();
+ this.startList = connectivityParams.getStartList();
+ this.startListFromManage2Sail = connectivityParams.getStartList() != null;
+ this.raceDescription = connectivityParams.getRaceDescription();
+ this.boatClass = connectivityParams.getBoatClass();
this.windStore = windStore;
- this.id = createID(raceID, hostname, port);
+ this.id = createID(connectivityParams.getRaceID(), connectivityParams.getHostname(), connectivityParams.getPort());
connector.addSailMasterListener(this);
trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(this.regatta);
- this.delayToLiveInMillis = delayToLiveInMillis;
+ this.delayToLiveInMillis = connectivityParams.getDelayToLiveInMillis();
this.competitorsByBoatId = new HashMap();
- this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
+ this.useInternalMarkPassingAlgorithm = connectivityParams.isUseInternalMarkPassingAlgorithm();
+ this.updateURL = connectivityParams.getUpdateURL();
+ this.updateUsername = connectivityParams.getUpdateUsername();
+ this.updatePassword = connectivityParams.getUpdatePassword();
}
@Override
@@ -406,7 +419,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
}
@Override
- public void receivedStartList(String raceID, StartList startList) {
+ public void receivedStartList(String raceID, StartList startList) throws URISyntaxException {
// ignore STL messages if the startlist has been already provided by Manage2Sail
if (!startListFromManage2Sail && this.raceID.equals(raceID)) {
StartList oldStartList = this.startList;
@@ -435,7 +448,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
}
}
- private void createRaceDefinition(Course course) {
+ private void createRaceDefinition(Course course) throws URISyntaxException {
assert this.raceID.equals(raceID);
assert startList != null;
assert course != null;
@@ -465,9 +478,20 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
}
}, useInternalMarkPassingAlgorithm, raceLogResolver,
/* Not needed because the RaceTracker is not active on a replica */ Optional.empty());
+ addUpdateHandlers();
notifyRaceCreationListeners();
logger.info("Created SwissTiming RaceDefinition and TrackedRace for "+race.getName());
}
+
+ /**
+ * If a non-{@code null}, non-{@link String#isEmpty() empty} {@link #updateURL} is set, adds {@link UpdateHandler}s
+ * to the race that will forward changes to the race such as start time changes or course changes to the URL as REST
+ * requests.
+ */
+ private void addUpdateHandlers() throws URISyntaxException {
+ getDomainFactory().addUpdateHandlers(updateURL, updateUsername, updatePassword,
+ /* TODO using the regatta ID as the "eventId" for now... */ regatta.getId(), trackedRace.getRace(), trackedRace);
+ }
/**
* Checks if {@link #getRegatta()} still contains the {@link RaceDefinition} obtained when calling
@@ -481,7 +505,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl
}
@Override
- public void receivedCourseConfiguration(String raceID, Course course) {
+ public void receivedCourseConfiguration(String raceID, Course course) throws URISyntaxException {
Course oldCourse = this.course;
if (trackedRace == null) {
if (oldCourse == null && startList != null) {
diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java
index de24889e36e..e14df771fa1 100755
--- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java
+++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java
@@ -31,11 +31,15 @@ public class SwissTimingTrackingConnectivityParameters extends AbstractRaceTrack
private final long delayToLiveInMillis;
private final StartList startList;
private final boolean useInternalMarkPassingAlgorithm;
+ private final String updateURL;
+ private final String updateUsername;
+ private final String updatePassword;
public SwissTimingTrackingConnectivityParameters(String hostname, int port, String raceID, String raceName,
String raceDescription, BoatClass boatClass, StartList startList, long delayToLiveInMillis,
SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, RaceLogStore raceLogStore,
- RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) {
+ RegattaLogStore regattaLogStore, boolean useInternalMarkPassingAlgorithm, boolean trackWind,
+ boolean correctWindDirectionByMagneticDeclination, String updateURL, String updateUsername, String updatePassword) {
super(trackWind, correctWindDirectionByMagneticDeclination);
this.hostname = hostname;
this.port = port;
@@ -50,6 +54,9 @@ public class SwissTimingTrackingConnectivityParameters extends AbstractRaceTrack
this.raceLogStore = raceLogStore;
this.regattaLogStore = regattaLogStore;
this.useInternalMarkPassingAlgorithm = useInternalMarkPassingAlgorithm;
+ this.updateURL = updateURL;
+ this.updateUsername = updateUsername;
+ this.updatePassword = updatePassword;
}
@Override
@@ -60,18 +67,15 @@ public class SwissTimingTrackingConnectivityParameters extends AbstractRaceTrack
@Override
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
RaceLogResolver raceLogResolver, LeaderboardGroupResolver leaderboardGroupResolver, long timeoutInMilliseconds) throws Exception {
- return swissTimingFactory.createRaceTracker(raceID, raceName, raceDescription, boatClass, hostname, port,
- startList, delayToLiveInMillis, raceLogStore, regattaLogStore, windStore,
- useInternalMarkPassingAlgorithm,
- domainFactory, trackedRegattaRegistry, raceLogResolver, this);
+ return swissTimingFactory.createRaceTracker(raceLogStore, regattaLogStore, windStore, domainFactory, trackedRegattaRegistry, raceLogResolver,
+ this);
}
@Override
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
WindStore windStore, RaceLogResolver raceLogResolver, LeaderboardGroupResolver leaderboardGroupResolver, long timeoutInMilliseconds) throws Exception {
- return swissTimingFactory.createRaceTracker(regatta, raceID, raceName, raceDescription, boatClass, hostname,
- port, startList, delayToLiveInMillis, windStore, useInternalMarkPassingAlgorithm,
- domainFactory, trackedRegattaRegistry, raceLogResolver, raceLogStore, regattaLogStore, this);
+ return swissTimingFactory.createRaceTracker(regatta, windStore, domainFactory, trackedRegattaRegistry, raceLogResolver, raceLogStore,
+ regattaLogStore, this);
}
@Override
@@ -92,6 +96,18 @@ public class SwissTimingTrackingConnectivityParameters extends AbstractRaceTrack
return port;
}
+ public String getUpdateURL() {
+ return updateURL;
+ }
+
+ public String getUpdateUsername() {
+ return updateUsername;
+ }
+
+ public String getUpdatePassword() {
+ return updatePassword;
+ }
+
public String getRaceID() {
return raceID;
}
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/DomainFactoryImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java
index 1d6ccf2ae2b..da49ca9a085 100755
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java
+++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java
@@ -14,8 +14,8 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import java.util.Map.Entry;
+import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -73,6 +73,9 @@ import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
+import com.sap.sailing.domain.tracking.impl.FinishTimeUpdateHandler;
+import com.sap.sailing.domain.tracking.impl.RaceAbortedHandler;
+import com.sap.sailing.domain.tracking.impl.StartTimeUpdateHandler;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.sap.sailing.domain.tractracadapter.JSONService;
import com.sap.sailing.domain.tractracadapter.MetadataParser;
@@ -677,17 +680,16 @@ public class DomainFactoryImpl implements DomainFactory {
TracTracCourseDesignUpdateHandler courseDesignHandler = new TracTracCourseDesignUpdateHandler(
tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
raceDefinition.getId(), tractracRace, this);
- trackedRace.addCourseDesignChangedListener(courseDesignHandler);
- TracTracStartTimeUpdateHandler startTimeHandler = new TracTracStartTimeUpdateHandler(
+ StartTimeUpdateHandler startTimeHandler = new StartTimeUpdateHandler(
tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
raceDefinition.getId(), trackedRace.getTrackedRegatta().getRegatta());
- trackedRace.addStartTimeChangedListener(startTimeHandler);
- TracTracRaceAbortedHandler raceAbortedHandler = new TracTracRaceAbortedHandler(
+ RaceAbortedHandler raceAbortedHandler = new RaceAbortedHandler(
tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
raceDefinition.getId());
- trackedRace.addRaceAbortedListener(raceAbortedHandler);
- trackedRace.addListener(new TracTracFinishTimeUpdateHandler(tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
- raceDefinition.getId(), trackedRace.getTrackedRegatta().getRegatta()).getListener());
+ final FinishTimeUpdateHandler finishTimeUpdateHandler = new FinishTimeUpdateHandler(tracTracUpdateURI, tracTracUsername, tracTracPassword, tracTracEventUuid,
+ raceDefinition.getId(), trackedRace.getTrackedRegatta().getRegatta());
+ baseDomainFactory.addUpdateHandlers(trackedRace, courseDesignHandler, startTimeHandler, raceAbortedHandler,
+ finishTimeUpdateHandler);
}
private DynamicTrackedRace createTrackedRace(TrackedRegatta trackedRegatta, RaceDefinition race,
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..2efecd731d8 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."
+ }
};
}
@@ -243,17 +251,19 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue sidelines, Consumer runAfterCreatingTrackedRace) {
- DynamicTrackedRace trackedRace = getTrackedRegatta().createTrackedRace(race, sidelines,
- windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
- /* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
+ private DynamicTrackedRace createTrackedRace(RaceDefinition race, Iterable sidelines,
+ Consumer runAfterCreatingTrackedRace) {
+ DynamicTrackedRace trackedRace = getTrackedRegatta().createTrackedRace(race, sidelines, windStore,
+ delayToLiveInMillis, millisecondsOverWhichToAverageWind,
+ /* time over which to average speed: */ race.getBoatClass()
+ .getApproximateManeuverDurationInMilliseconds(),
raceDefinitionSetToUpdate, useInternalMarkPassingAlgorithm, raceLogResolver,
/* Not needed because the RaceTracker is not active on a replica */ Optional.empty());
if (runAfterCreatingTrackedRace != null) {
- runAfterCreatingTrackedRace.accept(trackedRace);
+ runAfterCreatingTrackedRace.accept(trackedRace);
}
- getDomainFactory().addTracTracUpdateHandlers(tracTracUpdateURI, getTracTracEvent().getId(), tracTracUsername, tracTracPassword, race, trackedRace,
- tractracRace);
+ getDomainFactory().addTracTracUpdateHandlers(tracTracUpdateURI, getTracTracEvent().getId(), tracTracUsername,
+ tracTracPassword, race, trackedRace, tractracRace);
return trackedRace;
}
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracCourseDesignUpdateHandler.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracCourseDesignUpdateHandler.java
index c2167e8d888..18984574043 100644
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracCourseDesignUpdateHandler.java
+++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracCourseDesignUpdateHandler.java
@@ -1,86 +1,32 @@
package com.sap.sailing.domain.tractracadapter.impl;
-import java.io.IOException;
import java.io.Serializable;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
import java.net.URI;
-import java.net.URL;
import java.util.Iterator;
-import java.util.logging.Logger;
-
-import org.json.simple.JSONObject;
-import org.json.simple.parser.ParseException;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.CourseBase;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.CourseDataImpl;
-import com.sap.sailing.domain.tracking.CourseDesignChangedListener;
+import com.sap.sailing.domain.tracking.impl.CourseDesignUpdateHandler;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
-import com.sap.sailing.server.gateway.serialization.JsonSerializer;
-import com.sap.sailing.server.gateway.serialization.coursedata.impl.ControlPointJsonSerializer;
-import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseBaseJsonSerializer;
-import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseJsonSerializer;
-import com.sap.sailing.server.gateway.serialization.coursedata.impl.GateJsonSerializer;
-import com.sap.sailing.server.gateway.serialization.coursedata.impl.MarkJsonSerializer;
-import com.sap.sailing.server.gateway.serialization.coursedata.impl.WaypointJsonSerializer;
import com.sap.sse.common.Util;
import com.tractrac.model.lib.api.event.IRace;
import com.tractrac.model.lib.api.route.IControl;
-public class TracTracCourseDesignUpdateHandler extends UpdateHandler implements CourseDesignChangedListener {
-
- private final static String ACTION = "update_course";
-
- private final static Logger logger = Logger.getLogger(TracTracCourseDesignUpdateHandler.class.getName());
- private final JsonSerializer courseSerializer;
+public class TracTracCourseDesignUpdateHandler extends CourseDesignUpdateHandler {
private final IRace tractracRace;
private final DomainFactory domainFactory;
public TracTracCourseDesignUpdateHandler(URI updateURI, String tracTracUsername, String tracTracPassword, Serializable tracTracEventId, Serializable raceId, IRace tractracRace, DomainFactory domainFactory) {
- super(updateURI, ACTION, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
+ super(updateURI, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
this.domainFactory = domainFactory;
this.tractracRace = tractracRace;
- this.courseSerializer = new CourseJsonSerializer(
- new CourseBaseJsonSerializer(
- new WaypointJsonSerializer(
- new ControlPointJsonSerializer(
- new MarkJsonSerializer(),
- new GateJsonSerializer(new MarkJsonSerializer())))));
}
@Override
- public void courseDesignChanged(final CourseBase newCourseDesign) throws MalformedURLException, IOException {
- if (!isActive()) {
- logger.info("Not sending course update to TracTrac because no URL has been provided.");
- return;
- }
- final CourseBase newCourseDesignWithExistingControlPoints = replaceControlPointsByMatchingExistingControlPoints(newCourseDesign);
- JSONObject serializedCourseDesign = courseSerializer.serialize(newCourseDesignWithExistingControlPoints);
- String payload = serializedCourseDesign.toJSONString();
- URL currentCourseDesignURL = buildUpdateURL();
- logger.info("Using " + currentCourseDesignURL.toString() + " for the course update!");
- logger.info("Payload is " + payload);
- HttpURLConnection connection = (HttpURLConnection) currentCourseDesignURL.openConnection();
- try {
- setConnectionPropertiesAndSendWithPayload(connection, payload);
- try {
- checkAndLogUpdateResponse(connection);
- } catch (ParseException e) {
- e.printStackTrace();
- }
- } finally {
- if (connection != null) {
- connection.disconnect();
- } else {
- logger.severe("Connection to TracTrac Course Update URL " + currentCourseDesignURL.toString() + " could not be established");
- }
- }
- }
-
- private CourseBase replaceControlPointsByMatchingExistingControlPoints(CourseBase courseDesign) {
+ protected CourseBase replaceControlPointsByMatchingExistingControlPoints(CourseBase courseDesign) {
final Iterable candidates = domainFactory.getControlsForCourseArea(tractracRace.getEvent(), tractracRace.getCourseArea());
final CourseBase result = new CourseDataImpl(courseDesign.getName());
int zeroBasedPosition = 0;
diff --git a/java/com.sap.sailing.domain/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain/META-INF/MANIFEST.MF
index 6f6d9a68bbe..8d5cf1bb0a9 100755
--- a/java/com.sap.sailing.domain/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.domain/META-INF/MANIFEST.MF
@@ -47,5 +47,12 @@ Require-Bundle: com.googlecode.java-diff-utils;bundle-version="1.3.0",
com.sap.sse.shared.android,
org.apache.commons.math,
com.sap.sailing.declination,
+ com.sap.sailing.server.gateway.serialization.shared.android,
com.sap.sse.datamining.annotations
+Import-Package: org.apache.http,
+ org.apache.http.client;version="[4.2.5,4.3.0)",
+ org.apache.http.client.entity;version="[4.2.5,4.3.0)",
+ org.apache.http.client.methods;version="[4.2.5,4.3.0)",
+ org.apache.http.impl.client;version="[4.2.5,4.3.0)",
+ org.apache.http.message;version="[4.2.5,4.3.0)"
Automatic-Module-Name: com.sap.sailing.domain
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/DomainFactory.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/DomainFactory.java
index b81e8e1b1ff..be6b6a144c7 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/DomainFactory.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/DomainFactory.java
@@ -21,9 +21,14 @@ import com.sap.sailing.domain.common.dto.TrackedRaceStatisticsDTO;
import com.sap.sailing.domain.common.media.MediaTrack;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
+import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
+import com.sap.sailing.domain.tracking.impl.CourseDesignUpdateHandler;
+import com.sap.sailing.domain.tracking.impl.FinishTimeUpdateHandler;
+import com.sap.sailing.domain.tracking.impl.RaceAbortedHandler;
+import com.sap.sailing.domain.tracking.impl.StartTimeUpdateHandler;
import com.sap.sse.common.IsManagedByCache;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair;
@@ -101,4 +106,11 @@ public interface DomainFactory extends SharedDomainFactory {
*/
void updateRaceDTOWithTrackedRaceData(TrackedRace trackedRace, RaceDTO raceDTO);
+ /**
+ * Adds update handlers to a {@link TrackedRace} which can send updates to a REST service about race status
+ * changes such as a start time change, a course change, or a postponement.
+ */
+ void addUpdateHandlers(DynamicTrackedRace trackedRace, CourseDesignUpdateHandler courseDesignHandler,
+ StartTimeUpdateHandler startTimeHandler, RaceAbortedHandler raceAbortedHandler,
+ final FinishTimeUpdateHandler finishTimeUpdateHandler);
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java
index 1d268d47ff9..92807bed0c6 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/AbstractRaceColumn.java
@@ -11,6 +11,8 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -60,15 +62,15 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
private TrackedRaces trackedRaces;
private Map raceIdentifiers;
- private Map raceLogs;
-
+ private ConcurrentMap raceLogs;
+
private transient RaceLogStore raceLogStore;
private RegattaLikeIdentifier regattaLikeParent;
public AbstractRaceColumn() {
this.trackedRaces = new TrackedRaces();
this.raceIdentifiers = new HashMap();
- this.raceLogs = new HashMap();
+ this.raceLogs = new ConcurrentHashMap();
}
@Override
@@ -82,9 +84,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
@Override
public RaceLog getRaceLog(Fleet fleet) {
- synchronized (raceLogs) {
- return raceLogs.get(fleet);
- }
+ return raceLogs.get(fleet);
}
@Override
@@ -197,25 +197,23 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
@Override
public void reloadRaceLog(Fleet fleet) {
- synchronized (raceLogs) {
- RaceLogIdentifier identifier = getRaceLogIdentifier(fleet);
- RaceLog newOrLoadedRaceLog = raceLogStore.getRaceLog(identifier, /* ignoreCache */true);
- RaceLog raceLogAvailable = raceLogs.get(fleet);
- if (raceLogAvailable == null) {
- RaceColumnRaceLogReplicator listener = new RaceColumnRaceLogReplicator(this, identifier);
- // FIXME Wouldn't this skip any listener notifications that a merge below would trigger if the race log already existed?
- // FIXME For example, how about the race log-provided score corrections that need application to the leaderboard and replication?
- newOrLoadedRaceLog.addListener(listener);
- raceLogs.put(fleet, newOrLoadedRaceLog);
- final TrackedRace trackedRace = getTrackedRace(fleet);
- if (trackedRace != null) {
- // need to attach race log
- trackedRace.attachRaceLog(newOrLoadedRaceLog);
- }
- } else {
- // now add all race log events from newOrLoadedRaceLog that are not already in raceLogAvailable
- raceLogAvailable.merge(newOrLoadedRaceLog);
+ RaceLogIdentifier identifier = getRaceLogIdentifier(fleet);
+ RaceLog newOrLoadedRaceLog = raceLogStore.getRaceLog(identifier, /* ignoreCache */true);
+ RaceLog raceLogAvailable = raceLogs.get(fleet);
+ if (raceLogAvailable == null) {
+ RaceColumnRaceLogReplicator listener = new RaceColumnRaceLogReplicator(this, identifier);
+ // FIXME Wouldn't this skip any listener notifications that a merge below would trigger if the race log already existed?
+ // FIXME For example, how about the race log-provided score corrections that need application to the leaderboard and replication?
+ newOrLoadedRaceLog.addListener(listener);
+ raceLogs.put(fleet, newOrLoadedRaceLog);
+ final TrackedRace trackedRace = getTrackedRace(fleet);
+ if (trackedRace != null) {
+ // need to attach race log
+ trackedRace.attachRaceLog(newOrLoadedRaceLog);
}
+ } else {
+ // now add all race log events from newOrLoadedRaceLog that are not already in raceLogAvailable
+ raceLogAvailable.merge(newOrLoadedRaceLog);
}
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java
index 01e73aeacfe..7444495aabc 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/DomainFactoryImpl.java
@@ -64,11 +64,16 @@ import com.sap.sailing.domain.leaderboard.impl.LowPointTieBreakBasedOnLastSeries
import com.sap.sailing.domain.leaderboard.impl.LowPointWinnerGetsZero;
import com.sap.sailing.domain.leaderboard.impl.LowPointWithAutomaticRDG;
import com.sap.sailing.domain.leaderboard.impl.LowPointWithEliminationsAndRoundsWinnerGets07;
+import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
+import com.sap.sailing.domain.tracking.impl.CourseDesignUpdateHandler;
+import com.sap.sailing.domain.tracking.impl.FinishTimeUpdateHandler;
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
+import com.sap.sailing.domain.tracking.impl.RaceAbortedHandler;
+import com.sap.sailing.domain.tracking.impl.StartTimeUpdateHandler;
import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl;
import com.sap.sailing.geocoding.ReverseGeocoder;
import com.sap.sse.common.Distance;
@@ -201,11 +206,12 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
assert trackedRace != null;
raceDTO.startOfRace = trackedRace.getStartOfRace() == null ? null : trackedRace.getStartOfRace().asDate();
raceDTO.endOfRace = trackedRace.getEndOfRace() == null ? null : trackedRace.getEndOfRace().asDate();
+ raceDTO.raceFinishedTime = trackedRace.getFinishedTime() == null ? null : trackedRace.getFinishedTime().asDate();
raceDTO.status = new RaceStatusDTO();
raceDTO.status.status = trackedRace.getStatus() == null ? null : trackedRace.getStatus().getStatus();
raceDTO.status.loadingProgress = trackedRace.getStatus() == null ? 0.0 : trackedRace.getStatus().getLoadingProgress();
}
-
+
@Override
public TrackedRaceDTO createTrackedRaceDTO(TrackedRace trackedRace) {
TrackedRaceDTO trackedRaceDTO = new TrackedRaceDTO();
@@ -394,6 +400,7 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
return result;
}
+ @Override
public List getCompetitorDTOList(List> competitors) {
List result = new ArrayList<>();
for (Pair competitorAndBoat : competitors) {
@@ -401,4 +408,14 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
}
return result;
}
+
+ @Override
+ public void addUpdateHandlers(DynamicTrackedRace trackedRace, CourseDesignUpdateHandler courseDesignHandler,
+ StartTimeUpdateHandler startTimeHandler, RaceAbortedHandler raceAbortedHandler,
+ final FinishTimeUpdateHandler finishTimeUpdateHandler) {
+ trackedRace.addCourseDesignChangedListener(courseDesignHandler);
+ trackedRace.addStartTimeChangedListener(startTimeHandler);
+ trackedRace.addRaceAbortedListener(raceAbortedHandler);
+ trackedRace.addListener(finishTimeUpdateHandler.getListener());
+ }
}
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/CourseDesignUpdateHandler.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CourseDesignUpdateHandler.java
new file mode 100755
index 00000000000..1ad1a82c1c5
--- /dev/null
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/CourseDesignUpdateHandler.java
@@ -0,0 +1,78 @@
+package com.sap.sailing.domain.tracking.impl;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.logging.Logger;
+
+import org.json.simple.JSONObject;
+import org.json.simple.parser.ParseException;
+
+import com.sap.sailing.domain.base.CourseBase;
+import com.sap.sailing.domain.tracking.CourseDesignChangedListener;
+import com.sap.sailing.server.gateway.serialization.JsonSerializer;
+import com.sap.sailing.server.gateway.serialization.coursedata.impl.ControlPointJsonSerializer;
+import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseBaseJsonSerializer;
+import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseJsonSerializer;
+import com.sap.sailing.server.gateway.serialization.coursedata.impl.GateJsonSerializer;
+import com.sap.sailing.server.gateway.serialization.coursedata.impl.MarkJsonSerializer;
+import com.sap.sailing.server.gateway.serialization.coursedata.impl.WaypointJsonSerializer;
+
+public class CourseDesignUpdateHandler extends UpdateHandler implements CourseDesignChangedListener {
+
+ private final static String ACTION = "update_course";
+
+ private final static Logger logger = Logger.getLogger(CourseDesignUpdateHandler.class.getName());
+ private final JsonSerializer courseSerializer;
+
+ public CourseDesignUpdateHandler(URI updateURI, String username, String password, Serializable eventId, Serializable raceId) {
+ super(updateURI, ACTION, username, password, eventId, raceId);
+ this.courseSerializer = new CourseJsonSerializer(
+ new CourseBaseJsonSerializer(
+ new WaypointJsonSerializer(
+ new ControlPointJsonSerializer(
+ new MarkJsonSerializer(),
+ new GateJsonSerializer(new MarkJsonSerializer())))));
+ }
+
+ @Override
+ public void courseDesignChanged(final CourseBase newCourseDesign) throws MalformedURLException, IOException {
+ if (!isActive()) {
+ logger.info("Not sending course update to TracTrac because no URL has been provided.");
+ return;
+ }
+ final CourseBase newCourseDesignWithExistingControlPoints = replaceControlPointsByMatchingExistingControlPoints(newCourseDesign);
+ JSONObject serializedCourseDesign = courseSerializer.serialize(newCourseDesignWithExistingControlPoints);
+ String payload = serializedCourseDesign.toJSONString();
+ URL currentCourseDesignURL = buildUpdateURL();
+ logger.info("Using " + currentCourseDesignURL.toString() + " for the course update!");
+ logger.info("Payload is " + payload);
+ HttpURLConnection connection = (HttpURLConnection) currentCourseDesignURL.openConnection();
+ try {
+ setConnectionPropertiesAndSendWithPayload(connection, payload);
+ try {
+ checkAndLogUpdateResponse(connection);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ } finally {
+ if (connection != null) {
+ connection.disconnect();
+ } else {
+ logger.severe("Connection to TracTrac Course Update URL " + currentCourseDesignURL.toString() + " could not be established");
+ }
+ }
+ }
+
+ /**
+ * This default implementation returns the {@code courseDesign} unchanged. Subclasses have the possibility to
+ * override this method in order to replace individual course marks provided in a detailed course design,
+ * based on the actual course marks available.
+ */
+ protected CourseBase replaceControlPointsByMatchingExistingControlPoints(CourseBase courseDesign) {
+ return courseDesign;
+ }
+}
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.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java
index aaa83b444ec..bcc66c88fa7 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java
@@ -79,7 +79,7 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor {
logger.severe("Trying to add " + this + " as listener to a null race log for tracked race " + trackedRace.getRace());
} else {
raceLog.addListener(this);
- final ReadonlyRaceState raceState = ReadonlyRaceStateImpl.create(trackedRace.getRaceLogResolver(), raceLog);
+ final ReadonlyRaceState raceState = ReadonlyRaceStateImpl.getOrCreate(trackedRace.getRaceLogResolver(), raceLog);
raceLogs.put(raceLog, raceState);
raceState.addChangedListener(new BaseRaceStateChangedListener() {
@Override
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracFinishTimeUpdateHandler.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/FinishTimeUpdateHandler.java
similarity index 84%
rename from java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracFinishTimeUpdateHandler.java
rename to java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/FinishTimeUpdateHandler.java
index dfae3907cfa..e5c027ec562 100644
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracFinishTimeUpdateHandler.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/FinishTimeUpdateHandler.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.tractracadapter.impl;
+package com.sap.sailing.domain.tracking.impl;
import java.io.BufferedReader;
import java.io.IOException;
@@ -20,12 +20,11 @@ import org.json.simple.parser.ParseException;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.tracking.TrackedRace;
-import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
import com.sap.sse.common.TimePoint;
import com.sap.sse.util.LaxRedirectStrategyForAllRedirectResponseCodes;
-public class TracTracFinishTimeUpdateHandler extends UpdateHandler {
- private final static Logger logger = Logger.getLogger(TracTracFinishTimeUpdateHandler.class.getName());
+public class FinishTimeUpdateHandler extends UpdateHandler {
+ private final static Logger logger = Logger.getLogger(FinishTimeUpdateHandler.class.getName());
private final static String ACTION_STOP_TRACKING = "end_tracking";
private final static String FIELD_TRACKING_END_TIME = "tracking_end_time";
@@ -36,9 +35,9 @@ public class TracTracFinishTimeUpdateHandler extends UpdateHandler {
*/
private final Regatta regatta;
- public TracTracFinishTimeUpdateHandler(URI updateURI, String tracTracUsername, String tracTracPassword,
- Serializable tracTracEventId, Serializable raceId, Regatta regatta) {
- super(updateURI, ACTION_STOP_TRACKING, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
+ public FinishTimeUpdateHandler(URI updateURI, String username, String password,
+ Serializable eventId, Serializable raceId, Regatta regatta) {
+ super(updateURI, ACTION_STOP_TRACKING, username, password, eventId, raceId);
this.regatta = regatta;
}
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceAbortedHandler.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/RaceAbortedHandler.java
similarity index 78%
rename from java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceAbortedHandler.java
rename to java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/RaceAbortedHandler.java
index 1963e3f4dc5..50b723a4405 100755
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceAbortedHandler.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/RaceAbortedHandler.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.tractracadapter.impl;
+package com.sap.sailing.domain.tracking.impl;
import java.io.IOException;
import java.io.Serializable;
@@ -15,14 +15,14 @@ import org.json.simple.parser.ParseException;
import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.tracking.RaceAbortedListener;
-public class TracTracRaceAbortedHandler extends UpdateHandler implements RaceAbortedListener {
+public class RaceAbortedHandler extends UpdateHandler implements RaceAbortedListener {
private final static String ACTION = "update_race_status";
- private final static Logger logger = Logger.getLogger(TracTracRaceAbortedHandler.class.getName());
+ private final static Logger logger = Logger.getLogger(RaceAbortedHandler.class.getName());
- public TracTracRaceAbortedHandler(URI updateURI, String tracTracUsername, String tracTracPassword, Serializable tracTracEventId, Serializable raceId) {
- super(updateURI, ACTION, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
+ public RaceAbortedHandler(URI updateURI, String username, String password, Serializable eventId, Serializable raceId) {
+ super(updateURI, ACTION, username, password, eventId, raceId);
}
@Override
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracStartTimeResetHandler.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/StartTimeResetHandler.java
similarity index 73%
rename from java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracStartTimeResetHandler.java
rename to java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/StartTimeResetHandler.java
index dc46e1b23a9..941d74e20ee 100644
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracStartTimeResetHandler.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/StartTimeResetHandler.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.tractracadapter.impl;
+package com.sap.sailing.domain.tracking.impl;
import java.io.IOException;
import java.io.Serializable;
@@ -13,14 +13,14 @@ import org.json.simple.parser.ParseException;
import com.sap.sailing.domain.tracking.StartTimeChangedListener;
import com.sap.sse.common.TimePoint;
-public class TracTracStartTimeResetHandler extends UpdateHandler implements StartTimeChangedListener {
+public class StartTimeResetHandler extends UpdateHandler implements StartTimeChangedListener {
private static final String ACTION = "resetStartTime";
- private final static Logger logger = Logger.getLogger(TracTracStartTimeResetHandler.class.getName());
+ private final static Logger logger = Logger.getLogger(StartTimeResetHandler.class.getName());
- public TracTracStartTimeResetHandler(URI updateURI, String tracTracUsername, String tracTracPassword, Serializable tracTracEventId, Serializable raceId) {
- super(updateURI, ACTION, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
+ public StartTimeResetHandler(URI updateURI, String username, String password, Serializable eventId, Serializable raceId) {
+ super(updateURI, ACTION, username, password, eventId, raceId);
}
@Override
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracStartTimeUpdateHandler.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/StartTimeUpdateHandler.java
similarity index 93%
rename from java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracStartTimeUpdateHandler.java
rename to java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/StartTimeUpdateHandler.java
index eaef290e628..8dab411be13 100644
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracStartTimeUpdateHandler.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/StartTimeUpdateHandler.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.tractracadapter.impl;
+package com.sap.sailing.domain.tracking.impl;
import java.io.BufferedReader;
import java.io.IOException;
@@ -28,8 +28,8 @@ import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.TimePoint;
import com.sap.sse.util.LaxRedirectStrategyForAllRedirectResponseCodes;
-public class TracTracStartTimeUpdateHandler extends UpdateHandler implements StartTimeChangedListener {
- private final static Logger logger = Logger.getLogger(TracTracStartTimeUpdateHandler.class.getName());
+public class StartTimeUpdateHandler extends UpdateHandler implements StartTimeChangedListener {
+ private final static Logger logger = Logger.getLogger(StartTimeUpdateHandler.class.getName());
private final static String ACTION = "update_race_start_time";
private final static String ACTION_START_TRACKING = "start_tracking";
@@ -42,7 +42,7 @@ public class TracTracStartTimeUpdateHandler extends UpdateHandler implements Sta
*/
private final Regatta regatta;
- public TracTracStartTimeUpdateHandler(URI updateURI, String tracTracUsername, String tracTracPassword,
+ public StartTimeUpdateHandler(URI updateURI, String tracTracUsername, String tracTracPassword,
Serializable tracTracEventId, Serializable raceId, Regatta regatta) {
super(updateURI, ACTION, tracTracUsername, tracTracPassword, tracTracEventId, raceId);
this.regatta = regatta;
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java
index 2760bf877ca..86501ccd376 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java
@@ -50,7 +50,7 @@ import com.sap.sailing.domain.abstractlog.race.analyzing.impl.TrackingTimesFinde
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogGateLineOpeningTimeEventImpl;
import com.sap.sailing.domain.abstractlog.race.state.RaceState;
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
-import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl;
+import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ReadonlyRacingProcedure;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDefinedMarkAnalyzer;
@@ -2975,7 +2975,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
synchronized (raceStates) {
result = raceStates.get(raceLog);
if (result == null) {
- result = RaceStateImpl.create(raceLogResolver, raceLog);
+ result = ReadonlyRaceStateImpl.getOrCreate(raceLogResolver, raceLog);
raceStates.put(raceLog, result);
}
}
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateHandler.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateHandler.java
similarity index 83%
rename from java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateHandler.java
rename to java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateHandler.java
index f87d3c8a814..97cd7a4a61d 100644
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateHandler.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateHandler.java
@@ -1,4 +1,4 @@
-package com.sap.sailing.domain.tractracadapter.impl;
+package com.sap.sailing.domain.tracking.impl;
import java.io.BufferedReader;
import java.io.DataOutputStream;
@@ -25,21 +25,28 @@ import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
-import com.sap.sailing.domain.tractracadapter.UpdateResponse;
+import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
import com.sap.sailing.server.gateway.deserialization.impl.Helpers;
import com.sap.sse.common.Duration;
+/**
+ * An update handler can be registered as a listener on a {@link TrackedRace} and can then propagate information to
+ * an external service. This can, e.g., be a tracking partner's system that is interested in receiving race status
+ * updates such as new start times or postponements.
+ *
+ * @author Axel Uhl (d043530)
+ *
+ */
public class UpdateHandler {
-
private final static Logger logger = Logger.getLogger(UpdateHandler.class.getName());
private JsonDeserializer updateDeserializer;
private final URI baseURI;
- private final String tracTracUsername;
- private final String tracTracPassword;
- private final Serializable tracTracEventId;
+ private final String username;
+ private final String password;
+ private final Serializable eventId;
private final Serializable raceId;
private final String action;
private final boolean active;
@@ -53,16 +60,16 @@ public class UpdateHandler {
private final static String ResponseCodeForFailure = "FAILURE";
private final static String UpdateUrlTemplate = "%s%s?eventid=%s&raceid=%s&username=%s&password=%s";
- public UpdateHandler(URI updateURI, String action, String tracTracUsername, String tracTracPassword, Serializable tracTracEventId, Serializable raceId) {
+ public UpdateHandler(URI updateURI, String action, String username, String password, Serializable eventId, Serializable raceId) {
this.baseURI = updateURI;
this.action = action;
- this.tracTracUsername = tracTracUsername;
- this.tracTracPassword = tracTracPassword;
- this.tracTracEventId = tracTracEventId;
+ this.username = username;
+ this.password = password;
+ this.eventId = eventId;
this.raceId = raceId;
this.updateDeserializer = new UpdateResponseDeserializer();
if (updateURI != null && !updateURI.toString().equals("")) {
- logger.info("Activating TracTrac update handler "+this+" for race with ID "+raceId);
+ logger.info("Activating update handler "+this+" for race with ID "+raceId);
this.active = true;
} else {
this.active = false;
@@ -87,10 +94,10 @@ public class UpdateHandler {
*/
protected List getDefaultParametersAsNewList() {
final List result = new ArrayList<>();
- result.add(new BasicNameValuePair("eventid", tracTracEventId.toString()));
+ result.add(new BasicNameValuePair("eventid", eventId.toString()));
result.add(new BasicNameValuePair("raceid", this.raceId.toString()));
- result.add(new BasicNameValuePair("username", tracTracUsername));
- result.add(new BasicNameValuePair("password", tracTracPassword));
+ result.add(new BasicNameValuePair("username", username));
+ result.add(new BasicNameValuePair("password", password));
return result;
}
@@ -103,10 +110,10 @@ public class UpdateHandler {
String url = String.format(UpdateUrlTemplate,
serverUpdateURI.toString(),
this.action,
- URLEncoder.encode(this.tracTracEventId.toString(), EncodingUtf8),
+ URLEncoder.encode(this.eventId.toString(), EncodingUtf8),
URLEncoder.encode(this.raceId.toString(), EncodingUtf8),
- URLEncoder.encode(tracTracUsername, EncodingUtf8),
- URLEncoder.encode(tracTracPassword, EncodingUtf8));
+ URLEncoder.encode(username, EncodingUtf8),
+ URLEncoder.encode(password, EncodingUtf8));
for (Entry entry : additionalParameters.entrySet()) {
url += String.format("&%s=%s",
@@ -123,7 +130,7 @@ public class UpdateHandler {
protected void checkAndLogUpdateResponse(HttpURLConnection connection) throws IOException, ParseException {
connection.setConnectTimeout(10000/*milliseconds*/);
connection.connect();
- BufferedReader reader = getResponseOnUpdateFromTracTrac(connection);
+ BufferedReader reader = getResponseOnUpdateFromProvider(connection);
parseAndLogResponse(reader);
}
@@ -133,13 +140,13 @@ public class UpdateHandler {
JSONObject responseObject = Helpers.toJSONObjectSafe(responseBody);
UpdateResponse updateResponse = updateDeserializer.deserialize(responseObject);
if (updateResponse.getStatus().equals(ResponseCodeForFailure)) {
- logger.severe("Failed to send data to TracTrac, got following response: " + updateResponse.getMessage());
+ logger.severe("Failed to send data to provider, got following response: " + updateResponse.getMessage());
} else {
- logger.info("Successfully sent data to TracTrac with response: " + updateResponse.getMessage());
+ logger.info("Successfully sent data to provider with response: " + updateResponse.getMessage());
}
}
- private BufferedReader getResponseOnUpdateFromTracTrac(HttpURLConnection connection) throws IOException {
+ private BufferedReader getResponseOnUpdateFromProvider(HttpURLConnection connection) throws IOException {
InputStream inputStream = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
return reader;
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/UpdateResponse.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateResponse.java
similarity index 63%
rename from java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/UpdateResponse.java
rename to java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateResponse.java
index 2a3a9193096..49ea7846f60 100644
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/UpdateResponse.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateResponse.java
@@ -1,7 +1,6 @@
-package com.sap.sailing.domain.tractracadapter;
+package com.sap.sailing.domain.tracking.impl;
public interface UpdateResponse {
-
String getStatus();
String getMessage();
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateResponseDeserializer.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateResponseDeserializer.java
similarity index 86%
rename from java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateResponseDeserializer.java
rename to java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateResponseDeserializer.java
index 496f22b4f09..75bd2dabe92 100644
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateResponseDeserializer.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateResponseDeserializer.java
@@ -1,8 +1,7 @@
-package com.sap.sailing.domain.tractracadapter.impl;
+package com.sap.sailing.domain.tracking.impl;
import org.json.simple.JSONObject;
-import com.sap.sailing.domain.tractracadapter.UpdateResponse;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateResponseImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateResponseImpl.java
similarity index 78%
rename from java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateResponseImpl.java
rename to java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateResponseImpl.java
index 9c1eef86ce1..109414350ec 100644
--- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/UpdateResponseImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/UpdateResponseImpl.java
@@ -1,6 +1,4 @@
-package com.sap.sailing.domain.tractracadapter.impl;
-
-import com.sap.sailing.domain.tractracadapter.UpdateResponse;
+package com.sap.sailing.domain.tracking.impl;
public class UpdateResponseImpl implements UpdateResponse {
diff --git a/java/com.sap.sailing.expeditionconnector.common/.project b/java/com.sap.sailing.expeditionconnector.common/.project
index 96ef73399d7..255447215e5 100755
--- a/java/com.sap.sailing.expeditionconnector.common/.project
+++ b/java/com.sap.sailing.expeditionconnector.common/.project
@@ -21,12 +21,12 @@
- com.google.gdt.eclipse.core.webAppProjectValidator
+ com.gwtplugins.gdt.eclipse.core.webAppProjectValidator
- com.google.gwt.eclipse.core.gwtProjectValidator
+ com.gwtplugins.gwt.eclipse.core.gwtProjectValidator
@@ -34,6 +34,6 @@
org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
- com.google.gwt.eclipse.core.gwtNature
+ com.gwtplugins.gwt.eclipse.core.gwtNature
diff --git a/java/com.sap.sailing.gwt.ui.test/.project b/java/com.sap.sailing.gwt.ui.test/.project
index 92bf08afd13..1b5fe668904 100755
--- a/java/com.sap.sailing.gwt.ui.test/.project
+++ b/java/com.sap.sailing.gwt.ui.test/.project
@@ -20,16 +20,6 @@
-
- com.google.gdt.eclipse.core.webAppProjectValidator
-
-
-
-
- com.google.gwt.eclipse.core.gwtProjectValidator
-
-
- com.gwtplugins.gdt.eclipse.core.webAppProjectValidator
@@ -44,7 +34,6 @@
org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
- com.google.gwt.eclipse.core.gwtNaturecom.gwtplugins.gwt.eclipse.core.gwtNature
diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/SailingServiceImplMock.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/SailingServiceImplMock.java
index af633c042ae..74bfa2b601f 100755
--- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/SailingServiceImplMock.java
+++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/SailingServiceImplMock.java
@@ -75,7 +75,7 @@ public class SailingServiceImplMock extends SailingServiceImpl {
public RaceHandle addSwissTimingRace(TrackerManager trackerManager,
RegattaIdentifier regattaToAddTo, String raceID, String raceName, String raceDescription,
BoatClass boatClass, String hostname, int port, StartList startList, RaceLogStore logStore,
- RegattaLogStore regattaLogStore, long timeoutInMilliseconds, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination) throws InterruptedException,
+ RegattaLogStore regattaLogStore, long timeoutInMilliseconds, boolean useInternalMarkPassingAlgorithm, boolean trackWind, boolean correctWindDirectionByMagneticDeclination, String updateURL, String updateUsername, String updatePassword) throws InterruptedException,
UnknownHostException, IOException, ParseException, Exception {
// TODO Auto-generated method stub
return null;
diff --git a/java/com.sap.sailing.gwt.ui/.project b/java/com.sap.sailing.gwt.ui/.project
index 0846e29b8b9..c684e289776 100755
--- a/java/com.sap.sailing.gwt.ui/.project
+++ b/java/com.sap.sailing.gwt.ui/.project
@@ -20,16 +20,6 @@
-
- com.google.gdt.eclipse.core.webAppProjectValidator
-
-
-
-
- com.google.gwt.eclipse.core.gwtProjectValidator
-
-
- com.gwtplugins.gdt.eclipse.core.webAppProjectValidator
@@ -44,7 +34,6 @@
org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
- com.google.gwt.eclipse.core.gwtNatureorg.eclipse.wst.jsdt.core.jsNaturecom.gwtplugins.gwt.eclipse.core.gwtNature
diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT All SDM.launch b/java/com.sap.sailing.gwt.ui/SailingGWT All SDM.launch
deleted file mode 100644
index c1e46d3416d..00000000000
--- a/java/com.sap.sailing.gwt.ui/SailingGWT All SDM.launch
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch
deleted file mode 100755
index 1fd2a0ae702..00000000000
--- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT.launch b/java/com.sap.sailing.gwt.ui/SailingGWT.launch
deleted file mode 100644
index 482871f0a61..00000000000
--- a/java/com.sap.sailing.gwt.ui/SailingGWT.launch
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
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/autoplay/client/utils/AutoplayHelper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/utils/AutoplayHelper.java
index b03b79dc71f..b24e97e74af 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/utils/AutoplayHelper.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/utils/AutoplayHelper.java
@@ -137,12 +137,11 @@ public class AutoplayHelper {
RaceTimesInfoDTO raceTimes = raceTimesInfos.get(raceIdentifier);
boolean notNullInRequiredValues = raceTimes != null && raceTimes.startOfTracking != null
&& raceTimes.getStartOfRace() != null;
-
- boolean raceHasNotEndedOrOnlyRecentlyEnded = raceTimes.endOfRace == null
+ Date endTime = raceTimes.getFinishedTime() != null ? raceTimes.getFinishedTime() : raceTimes.getEndOfRace();
+ boolean raceHasNotEndedOrOnlyRecentlyEnded = endTime == null
|| serverTimeDuringRequest.getTime()
- - raceTimes.delayToLiveInMs < raceTimes.endOfRace.getTime()
+ - raceTimes.delayToLiveInMs < endTime.getTime()
+ waitTimeAfterRaceEndInMillis;
-
if (notNullInRequiredValues && raceHasNotEndedOrOnlyRecentlyEnded) {
long startTimeInMs = raceTimes.getStartOfRace().getTime();
long startIn = startTimeInMs - serverTimeDuringRequest.getTime() - raceTimes.delayToLiveInMs;
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.
\ No newline at end of file
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/partials/regattacompetition/RegattaCompetitionResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/partials/regattacompetition/RegattaCompetitionResources.java
index dd113f3c1de..c669e066169 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/partials/regattacompetition/RegattaCompetitionResources.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/partials/regattacompetition/RegattaCompetitionResources.java
@@ -33,5 +33,6 @@ public interface RegattaCompetitionResources extends SharedHomeResources {
String regattacompetition_phase_fleet_raceplanned();
String regattacompetition_phase_fleet_race_state();
String regattacompetition_phase_fleet_race_date();
+ String regattacompetition_phase_fleet_race_title_big();
}
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/RaceContext.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/RaceContext.java
index 0cda630cbc8..2e313562472 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/RaceContext.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/RaceContext.java
@@ -104,7 +104,7 @@ public class RaceContext {
this.fleet = fleet;
trackedRace = raceColumn.getTrackedRace(fleet);
raceLog = raceColumn.getRaceLog(fleet);
- state = (raceLog == null) ? null : ReadonlyRaceStateImpl.create(raceLogResolver, raceLog);
+ state = (raceLog == null) ? null : ReadonlyRaceStateImpl.getOrCreate(raceLogResolver, raceLog);
}
private boolean isShowFleetData() {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/preferences/UserPreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/preferences/UserPreferencesPresenter.java
index c21bf0daa38..8dbab241479 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/preferences/UserPreferencesPresenter.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/preferences/UserPreferencesPresenter.java
@@ -1,6 +1,5 @@
package com.sap.sailing.gwt.home.shared.places.user.profile.preferences;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
import com.sap.sailing.gwt.home.communication.user.profile.CompetitorSuggestionResult;
@@ -17,6 +16,8 @@ import com.sap.sailing.gwt.home.shared.partials.multiselection.AbstractSuggested
import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionBoatClassDataProvider;
import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionCompetitorDataProvider;
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
+import com.sap.sse.gwt.client.Notification;
+import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.dispatch.shared.commands.VoidResult;
/**
@@ -95,7 +96,7 @@ public class UserPreferencesPresenter() {
@Override
public void onFailure(Throwable caught) {
- Window.alert("Error while loading competitor suggestion");
+ Notification.notify("Error while loading competitor suggestion", NotificationType.ERROR);
}
@Override
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java
index de81d943467..091642b1f28 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java
@@ -6,7 +6,6 @@ import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.UrlBuilder;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
@@ -21,6 +20,8 @@ import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewContex
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings;
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO;
+import com.sap.sse.gwt.client.Notification;
+import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
@@ -60,7 +61,7 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
.deserializeFromCurrentLocation(new RegattaOverviewContextDefinition());
if (regattaOverviewContextDefinition.getEvent() == null) {
- Window.alert("Missing parameter");
+ Notification.notify("Missing parameter", NotificationType.ERROR);
return;
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/leaderboard/MultiRaceLeaderboardSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/leaderboard/MultiRaceLeaderboardSettings.java
index e166d36801b..74232f6c701 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/leaderboard/MultiRaceLeaderboardSettings.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/leaderboard/MultiRaceLeaderboardSettings.java
@@ -63,6 +63,7 @@ public class MultiRaceLeaderboardSettings extends LeaderboardSettings {
newSettings.showAddedScores.setValue(this.isShowAddedScores());
newSettings.showCompetitorShortNameColumn.setValue(this.isShowCompetitorShortNameColumn());
newSettings.showCompetitorFullNameColumn.setValue(this.isShowCompetitorFullNameColumn());
+ newSettings.showCompetitorBoatInfoColumn.setValue(this.isShowCompetitorBoatInfoColumn());
newSettings.isShowCompetitorNationality.setValue(this.isShowCompetitorNationality());
newSettings.namesOfRaceColumnsToShow.setValues(this.getNamesOfRaceColumnsToShow());
newSettings.namesOfRaceColumnsToShow.setDefaultValues(namesOfRaceColumns);
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetBoatPositionsAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetBoatPositionsAction.java
index 7b153fe21e3..84d310a3cfa 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetBoatPositionsAction.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetBoatPositionsAction.java
@@ -20,7 +20,6 @@ public class GetBoatPositionsAction extends AbstractGetMapRelatedDataAction callback) {
Map fromByCompetitorIdAsString = new HashMap();
- System.out.println(fromByCompetitorIdAsString);
for (Map.Entry fromEntry : getFrom().entrySet()) {
fromByCompetitorIdAsString.put(fromEntry.getKey().getIdAsString(), fromEntry.getValue());
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractEventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractEventManagementPanel.java
index d02f523e933..df4261fa983 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractEventManagementPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractEventManagementPanel.java
@@ -22,6 +22,8 @@ import com.sap.sailing.gwt.ui.shared.RaceRecordDTO;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sse.common.Util;
import com.sap.sse.gwt.client.ErrorReporter;
+import com.sap.sse.gwt.client.Notification;
+import com.sap.sse.gwt.client.Notification.NotificationType;
public abstract class AbstractEventManagementPanel extends AbstractRegattaPanel {
protected final TrackedRacesListComposite trackedRacesListComposite;
@@ -121,7 +123,7 @@ public abstract class AbstractEventManagementPanel extends AbstractRegattaPanel
builder.append(")");
builder.append("\n");
}
- Window.alert(builder.toString());
+ Notification.notify(builder.toString(), NotificationType.ERROR);
result = false;
} else {
result = true;
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.java
index 88a48717b39..31862a1dbe1 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.java
@@ -8,7 +8,6 @@ import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
-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;
@@ -25,6 +24,8 @@ import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
import com.sap.sse.gwt.client.ErrorReporter;
+import com.sap.sse.gwt.client.Notification;
+import com.sap.sse.gwt.client.Notification.NotificationType;
public abstract class AbstractFileImportWidget extends Composite {
@@ -89,7 +90,7 @@ public abstract class AbstractFileImportWidget extends Composite {
void onFileImportComplete(SubmitCompleteEvent event) {
SensorDataImportResponse importResponse = SensorDataImportResponse.parse(event.getResults());
if (importResponse == null) {
- Window.alert(StringMessages.INSTANCE.unexpectedErrorDuringFileImport());
+ Notification.notify(StringMessages.INSTANCE.unexpectedErrorDuringFileImport(), NotificationType.ERROR);
} else {
SensorDataImportResultsDialog.showResults(importResponse);
if (importResponse.didSucceedImportingAnyFile()) {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java
index 8a1047d9d48..7af822f63b5 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java
@@ -51,6 +51,8 @@ import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Triple;
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.async.MarkedAsyncCallback;
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
@@ -281,7 +283,7 @@ public abstract class AbstractLeaderboardConfigPanel extends FormPanel implement
refreshRaceLog(column, fleet, false);
}
}
- Window.alert(stringMessages.raceLogReloaded());
+ Notification.notify(stringMessages.raceLogReloaded(), NotificationType.ERROR);
}
});
vPanel.add(reloadAllRaceLogs);
@@ -430,7 +432,7 @@ public abstract class AbstractLeaderboardConfigPanel extends FormPanel implement
@Override
public void onSuccess(Void result) {
if (showAlerts) {
- Window.alert(stringMessages.raceLogReloaded());
+ Notification.notify(stringMessages.raceLogReloaded(), NotificationType.SUCCESS);
}
}
}));
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java
index 808ebdc3e2a..0cc890bac1d 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatTableWrapper.java
@@ -13,7 +13,6 @@ import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.TextColumn;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Label;
import com.sap.sailing.domain.common.dto.BoatDTO;
@@ -24,6 +23,8 @@ import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
import com.sap.sse.common.util.NaturalComparator;
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.celltable.EntityIdentityComparator;
import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
@@ -282,7 +283,7 @@ public class BoatTableWrapper> exte
@Override
public void onSuccess(Void result) {
- Window.alert(stringMessages.successfullyAllowedBoatReset(boats.toString()));
+ Notification.notify(stringMessages.successfullyAllowedBoatReset(boats.toString()), NotificationType.SUCCESS);
}
});
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorInvitationHelper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorInvitationHelper.java
index 7e14ff019c7..cf625080d91 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorInvitationHelper.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorInvitationHelper.java
@@ -3,7 +3,6 @@ package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Set;
import com.google.gwt.i18n.client.LocaleInfo;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
@@ -11,6 +10,8 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sse.common.Util.Pair;
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.dialog.DataEntryDialog.DialogCallback;
public class CompetitorInvitationHelper {
@@ -27,13 +28,13 @@ public class CompetitorInvitationHelper {
public void inviteCompetitors(Set competitors, String leaderboardName) {
if (competitors.size() == 0){
- Window.alert(stringMessages.selectAtLeastOneCompetitorForInvitation());
+ Notification.notify(stringMessages.selectAtLeastOneCompetitorForInvitation(), NotificationType.ERROR);
} else {
boolean emailProvidedForAll = isEmailProvidedForAll(competitors);
if (emailProvidedForAll) {
openChooseEventDialogAndSendMails(competitors, leaderboardName);
} else {
- Window.alert(stringMessages.notAllCompetitorsProvideEmail());
+ Notification.notify(stringMessages.notAllCompetitorsProvideEmail(), NotificationType.ERROR);
}
}
}
@@ -61,12 +62,12 @@ public class CompetitorInvitationHelper {
@Override
public void onFailure(Throwable caught) {
- Window.alert(stringMessages.sendingMailsFailed() + caught.getMessage());
+ Notification.notify(stringMessages.sendingMailsFailed() + caught.getMessage(), NotificationType.ERROR);
}
@Override
public void onSuccess(Void result) {
- Window.alert(stringMessages.sendingMailsSuccessful());
+ Notification.notify(stringMessages.sendingMailsSuccessful(), NotificationType.SUCCESS);
}
});
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java
index 36d8d1ee111..af5ce2fc3cf 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorTableWrapper.java
@@ -14,7 +14,6 @@ import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.TextColumn;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.view.client.CellPreviewEvent;
@@ -32,6 +31,8 @@ import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
import com.sap.sse.common.util.NaturalComparator;
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.celltable.EntityIdentityComparator;
import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
@@ -479,7 +480,7 @@ public class CompetitorTableWrapper competitors) {
if (competitors.isEmpty()) {
- Window.alert(stringMessages.importCanceledNoCompetitorAdded());
+ Notification.notify(stringMessages.importCanceledNoCompetitorAdded(), NotificationType.ERROR);
} else {
sailingService.setCompetitorRegistrationsInRegattaLog(leaderboard.getName(),
competitors, new AsyncCallback() {
@@ -337,7 +338,7 @@ public class ExpeditionAllInOneAfterImportHandler {
@Override
public final void cancel() {
- Window.alert(stringMessages.importCanceledByUser());
+ Notification.notify(stringMessages.importCanceledByUser(), NotificationType.WARNING);
}
}
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExpeditionAllInOneImportPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExpeditionAllInOneImportPanel.java
index eeee4a424a6..cc04ef0440b 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExpeditionAllInOneImportPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ExpeditionAllInOneImportPanel.java
@@ -7,7 +7,6 @@ import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.i18n.client.LocaleInfo;
-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;
@@ -36,6 +35,8 @@ import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
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.BusyIndicator;
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
@@ -153,7 +154,7 @@ public class ExpeditionAllInOneImportPanel extends Composite implements Regattas
busyIndicator.setBusy(false);
final ExpeditionDataImportResponse response = ExpeditionDataImportResponse.parse(event.getResults());
if (response == null) {
- Window.alert(StringMessages.INSTANCE.unexpectedErrorDuringFileImport());
+ Notification.notify(StringMessages.INSTANCE.unexpectedErrorDuringFileImport(), NotificationType.ERROR);
} else if (response.hasEventId()) {
new ExpeditionAllInOneAfterImportHandler(response.getEventId(), response.getRegattaName(),
response.getLeaderboardName(), response.getLeaderboardGroupName(), response.getRaceEntries(),
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java
index 57448b3ee20..01601beec40 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java
@@ -40,6 +40,8 @@ import com.sap.sailing.gwt.ui.client.shared.controls.ImagesBarCell;
import com.sap.sse.common.util.NaturalComparator;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.IconResources;
+import com.sap.sse.gwt.client.Notification;
+import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.celltable.BaseCelltable;
import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
@@ -256,10 +258,10 @@ public class IgtimiAccountsPanel extends FlowPanel {
@Override
public void onSuccess(Boolean result) {
if (result) {
- Window.alert(stringMessages.successfullyAuthorizedAccessToIgtimiUser(editedObject.geteMail()));
+ Notification.notify(stringMessages.successfullyAuthorizedAccessToIgtimiUser(editedObject.geteMail()), NotificationType.SUCCESS);
updateAllAccounts(sailingService, filterAccountsPanel, stringMessages, errorReporter);
} else {
- Window.alert(stringMessages.couldNotAuthorizedAccessToIgtimiUser(editedObject.geteMail()));
+ Notification.notify(stringMessages.couldNotAuthorizedAccessToIgtimiUser(editedObject.geteMail()), NotificationType.ERROR);
}
}
});
@@ -326,7 +328,7 @@ public class IgtimiAccountsPanel extends FlowPanel {
@Override
public void onSuccess(Void result) {
- Window.alert(stringMessages.successfullyRemoveIgtimiAccount(eMailOfAccountToRemove));
+ Notification.notify(stringMessages.successfullyRemoveIgtimiAccount(eMailOfAccountToRemove), NotificationType.INFO);
removeFrom.getList().remove(eMailOfAccountToRemove);
}
});
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java
index f215666b1b3..5d71a179735 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java
@@ -72,6 +72,8 @@ import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.util.NaturalComparator;
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.async.MarkedAsyncCallback;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
import com.sap.sse.gwt.client.shared.components.LinkWithSettingsGenerator;
@@ -380,7 +382,7 @@ TrackedRaceChangedListener, LeaderboardsDisplayer {
otherExistingLeaderboard.addAll(availableLeaderboardList);
otherExistingLeaderboard.remove(leaderboardDTO);
if (leaderboardDTO.type.isMetaLeaderboard()) {
- Window.alert(stringMessages.metaLeaderboardCannotBeChanged());
+ Notification.notify(stringMessages.metaLeaderboardCannotBeChanged(), NotificationType.ERROR);
} else {
AbstractLeaderboardDialog> dialog;
switch (leaderboardDTO.type) {
@@ -437,7 +439,7 @@ TrackedRaceChangedListener, LeaderboardsDisplayer {
leaderboardDTO.scoringScheme));
break;
default:
- Window.alert(stringMessages.unknownLeaderboardType(leaderboardDTO.type.name()));
+ Notification.notify(stringMessages.unknownLeaderboardType(leaderboardDTO.type.name()), NotificationType.ERROR);
}
}
}
@@ -531,7 +533,7 @@ TrackedRaceChangedListener, LeaderboardsDisplayer {
@Override
public void onClick(ClickEvent event) {
if (getSelectedLeaderboard().type.isRegattaLeaderboard()) {
- Window.alert(stringMessages.cannotAddRacesToRegattaLeaderboardButOnlyToRegatta());
+ Notification.notify(stringMessages.cannotAddRacesToRegattaLeaderboardButOnlyToRegatta(), NotificationType.ERROR);
} else {
addRaceColumnsToLeaderboard();
}
@@ -653,7 +655,7 @@ TrackedRaceChangedListener, LeaderboardsDisplayer {
@Override
public void onSuccess(Boolean result) {
if (!result) {
- Window.alert(stringMessages.failedToSetNewStartTime());
+ Notification.notify(stringMessages.failedToSetNewStartTime(), NotificationType.ERROR);
}
}
});
@@ -680,7 +682,7 @@ TrackedRaceChangedListener, LeaderboardsDisplayer {
@Override
public void onSuccess(Pair result) {
if (!result.getA() || !result.getB()) {
- Window.alert(stringMessages.failedToSetNewFinishingAndFinishTime());
+ Notification.notify(stringMessages.failedToSetNewFinishingAndFinishTime(), NotificationType.ERROR);
}
}
});
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java
index fad9c27a9a8..bd427552d62 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java
@@ -54,6 +54,8 @@ import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
import com.sap.sse.common.Util;
import com.sap.sse.common.util.NaturalComparator;
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.URLEncoder;
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
@@ -986,7 +988,7 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel implements
setDescriptionEditable(false);
updateGroup(selectedGroup);
} else {
- Window.alert(stringMessages.pleaseEnterNonEmptyDescription() + ".");
+ Notification.notify(stringMessages.pleaseEnterNonEmptyDescription() + ".", NotificationType.ERROR);
descriptionTextArea.setText(selectedGroup.description);
}
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java
index c960cb2ffc9..1cb7c2cc2db 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java
@@ -59,6 +59,8 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
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.async.MarkedAsyncCallback;
import com.sap.sse.gwt.client.celltable.BaseCelltable;
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
@@ -139,7 +141,7 @@ public class MediaPanel extends FlowPanel implements MediaTracksRefresher {
public void onClick(ClickEvent event) {
Set selected = refreshableSelectionModel.getSelectedSet();
if (selected.isEmpty()) {
- Window.alert(stringMessages.noSelection());
+ Notification.notify(stringMessages.noSelection(), NotificationType.ERROR);
} else {
new MultiURLChangeDialog(mediaService, stringMessages, selected, errorReporter,
new Runnable() {
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/PairingListCreationDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/PairingListCreationDialog.java
index 50d8c0e7c2e..645021bcc64 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/PairingListCreationDialog.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/PairingListCreationDialog.java
@@ -24,6 +24,8 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
import com.sap.sse.common.Util;
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.dialog.DataEntryDialog;
public class PairingListCreationDialog extends DataEntryDialog {
@@ -176,7 +178,7 @@ public class PairingListCreationDialog extends DataEntryDialog() {
@Override
public void onSuccess(Void result) {
- Window.alert(stringMessages.successfullyFilledRaceLogsFromPairingList());
+ Notification.notify(stringMessages.successfullyFilledRaceLogsFromPairingList(), NotificationType.SUCCESS);
}
@Override
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java
index 46b143863fc..2023058b4e2 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java
@@ -13,7 +13,6 @@ import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.resources.client.ImageResource;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
@@ -31,6 +30,8 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sailing.gwt.ui.shared.SeriesDTO;
import com.sap.sse.gwt.client.IconResources;
+import com.sap.sse.gwt.client.Notification;
+import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.controls.IntegerBox;
import com.sap.sse.gwt.client.controls.listedit.GenericStringListInlineEditorComposite;
import com.sap.sse.gwt.client.controls.listedit.StringListEditorComposite;
@@ -418,7 +419,7 @@ public class SeriesEditDialog extends DataEntryDialog {
}
validateAndUpdate();
} else {
- Window.alert(getStringMessages().pleaseSelectASeriesFirst());
+ Notification.notify(getStringMessages().pleaseSelectASeriesFirst(), NotificationType.ERROR);
}
}
});
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java
index d6f2baa6b49..20e494bd823 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java
@@ -67,6 +67,8 @@ import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.Util.Triple;
import com.sap.sse.common.util.NaturalComparator;
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.async.MarkedAsyncCallback;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
@@ -233,7 +235,7 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
}
}).show();
} else {
- Window.alert(stringMessages.canNotRegisterBoats());
+ Notification.notify(stringMessages.canNotRegisterBoats(), NotificationType.ERROR);
}
} else if (RaceLogTrackingEventManagementImagesBarCell.ACTION_MAP_DEVICES.equals(value)) {
new RegattaLogTrackingDeviceMappingsDialog(sailingService, stringMessages, errorReporter,
@@ -755,7 +757,7 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
@Override
public void onSuccess(Void result) {
- Window.alert(stringMessages.notificationRegattaConfigurationUpdatedUsingByMarks());
+ Notification.notify(stringMessages.notificationRegattaConfigurationUpdatedUsingByMarks(), NotificationType.SUCCESS);
}
}));
}
@@ -845,7 +847,7 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
@Override
public void onSuccess(Boolean result) {
if (!result) {
- Window.alert(stringMessages.failedToSetNewStartTime());
+ Notification.notify(stringMessages.failedToSetNewStartTime(), NotificationType.ERROR);
} else {
trackedRacesListComposite.regattaRefresher.fillRegattas();
}
@@ -872,7 +874,7 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
@Override
public void onSuccess(Pair result) {
if (!result.getA() || !result.getB()) {
- Window.alert(stringMessages.failedToSetNewFinishingAndFinishTime());
+ Notification.notify(stringMessages.failedToSetNewFinishingAndFinishTime(), NotificationType.ERROR);
} else {
trackedRacesListComposite.regattaRefresher.fillRegattas();
}
@@ -942,12 +944,12 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
getLocaleInfo(), new AsyncCallback() {
@Override
public void onFailure(Throwable caught) {
- Window.alert(stringMessages.sendingMailsFailed() + caught.getMessage());
+ Notification.notify(stringMessages.sendingMailsFailed() + caught.getMessage(), NotificationType.ERROR);
}
@Override
public void onSuccess(Void result) {
- Window.alert(stringMessages.sendingMailsSuccessful());
+ Notification.notify(stringMessages.sendingMailsSuccessful(), NotificationType.SUCCESS);
}
});
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java
index 99d79268374..e657ca630db 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java
@@ -15,7 +15,6 @@ import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
-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.CaptionPanel;
@@ -48,6 +47,8 @@ import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sailing.gwt.ui.shared.SeriesDTO;
import com.sap.sse.common.util.NaturalComparator;
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.BusyIndicator;
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
@@ -475,7 +476,7 @@ public class StructureImportManagementPanel extends SimplePanel implements Regat
@Override
public void onSuccess(Void result) {
regattaRefresher.fillRegattas();
- Window.alert(stringMessages.successfullyCreatedRegattas());
+ Notification.notify(stringMessages.successfullyCreatedRegattas(), NotificationType.SUCCESS);
}
});
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java
index 54a122e1cce..8f4fd9b38d0 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java
@@ -25,6 +25,7 @@ import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.IntegerBox;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
+import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.view.client.ListDataProvider;
@@ -62,6 +63,9 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
private final ListBox previousConfigurationsComboBox;
private final TextBox eventIdBox;
private final TextBox jsonUrlBox;
+ private final TextBox updateURLBox;
+ private final TextBox updateUsernameBox;
+ private final PasswordTextBox updatePasswordBox;
private final TextBox hostnameTextbox;
private final IntegerBox portIntegerbox;
private final List availableSwissTimingRaces = new ArrayList();
@@ -75,22 +79,16 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
RegattaRefresher regattaRefresher, StringMessages stringConstants) {
super(sailingService, regattaRefresher, errorReporter, true, stringConstants);
this.errorReporter = errorReporter;
-
VerticalPanel mainPanel = new VerticalPanel();
this.setWidget(mainPanel);
mainPanel.setWidth("100%");
-
CaptionPanel captionPanelConnections = new CaptionPanel(stringConstants.connections());
mainPanel.add(captionPanelConnections);
-
VerticalPanel verticalPanel = new VerticalPanel();
-
captionPanelConnections.setContentWidget(verticalPanel);
captionPanelConnections.setStyleName("bold");
-
- Grid connectionsGrid = new Grid(6, 2);
+ Grid connectionsGrid = new Grid(9, 2);
verticalPanel.add(connectionsGrid);
-
previousConfigurations = new HashMap();
previousConfigurationsComboBox = new ListBox();
connectionsGrid.setWidget(0, 1, previousConfigurationsComboBox);
@@ -107,10 +105,6 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
}
});
fillConfigurations();
-
- jsonUrlBox = new TextBox();
- jsonUrlBox.getElement().getStyle().setWidth(50, Unit.EM);
-
connectionsGrid.setWidget(0, 0, new Label(stringMessages.swissTimingEvents() + ":"));
connectionsGrid.setWidget(0, 1, previousConfigurationsComboBox);
@@ -125,6 +119,8 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
}
});
+ jsonUrlBox = new TextBox();
+ jsonUrlBox.getElement().getStyle().setWidth(50, Unit.EM);
connectionsGrid.setWidget(2, 0, new Label(stringMessages.manage2SailEventURLBox() + ":"));
connectionsGrid.setWidget(2, 1, jsonUrlBox);
jsonUrlBox.addChangeHandler(event -> {
@@ -142,8 +138,23 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
connectionsGrid.setWidget(4, 0, new Label(stringMessages.manage2SailPort() + ":"));
connectionsGrid.setWidget(4, 1, portIntegerbox);
+ updateURLBox = new TextBox();
+ updateURLBox.getElement().getStyle().setWidth(50, Unit.EM);
+ connectionsGrid.setWidget(5, 0, new Label(stringMessages.swissTimingUpdateURL() + ":"));
+ connectionsGrid.setWidget(5, 1, updateURLBox);
+
+ updateUsernameBox = new TextBox();
+ updateUsernameBox.getElement().getStyle().setWidth(50, Unit.EM);
+ connectionsGrid.setWidget(6, 0, new Label(stringMessages.swissTimingUpdateUsername() + ":"));
+ connectionsGrid.setWidget(6, 1, updateUsernameBox);
+
+ updatePasswordBox = new PasswordTextBox();
+ updatePasswordBox.getElement().getStyle().setWidth(50, Unit.EM);
+ connectionsGrid.setWidget(7, 0, new Label(stringMessages.swissTimingUpdatePassword() + ":"));
+ connectionsGrid.setWidget(7, 1, updatePasswordBox);
+
Button btnListRaces = new Button(stringConstants.listRaces());
- connectionsGrid.setWidget(5, 1, btnListRaces);
+ connectionsGrid.setWidget(8, 1, btnListRaces);
btnListRaces.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
@@ -459,6 +470,9 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
private void fillRaces(final SailingServiceAsync sailingService) {
final String jsonUrl = jsonUrlBox.getValue();
+ final String updateURL = updateURLBox.getValue();
+ final String updateUsername = updateUsernameBox.getValue();
+ final String updatePassword = updatePasswordBox.getValue();
sailingService.getRacesOfSwissTimingEvent(jsonUrl, new AsyncCallback() {
@Override
public void onFailure(Throwable caught) {
@@ -469,21 +483,18 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
@Override
public void onSuccess(final SwissTimingEventRecordDTO result) {
availableSwissTimingRaces.clear();
- if (result != null)
+ if (result != null) {
availableSwissTimingRaces.addAll(result.races);
-
+ }
raceList.getList().clear();
raceList.getList().addAll(availableSwissTimingRaces);
-
filterablePanelEvents.getTextBox().setText(null);
filterablePanelEvents.updateAll(result.races);
-
// store a successful configuration in the database for later retrieval
final String hostname = result.trackingDataHost;
final Integer port = result.trackingDataPort;
final String configName = result.eventName;
-
- sailingService.storeSwissTimingConfiguration(configName, jsonUrl, hostname, port,
+ sailingService.storeSwissTimingConfiguration(configName, jsonUrl, hostname, port, updateURL, updateUsername, updatePassword,
new AsyncCallback() {
@Override
public void onFailure(Throwable caught) {
@@ -495,10 +506,16 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
public void onSuccess(Void voidResult) {
// refresh list of previous configurations
SwissTimingConfigurationDTO stConfig = new SwissTimingConfigurationDTO(configName, jsonUrl,
- hostname, port);
+ hostname, port, updateURL, updateUsername, updatePassword);
if (previousConfigurations.put(stConfig.getName(), stConfig) == null) {
previousConfigurationsComboBox.addItem(stConfig.getName());
}
+ for (int i=0; i selectedRaces = new ArrayList();
for (final SwissTimingRaceRecordDTO race : this.raceList.getList()) {
if (raceTable.getSelectionModel().isSelected(race)) {
@@ -526,7 +546,7 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
sailingService.trackWithSwissTiming(
/* regattaToAddTo */ regattaIdentifier,
selectedRaces, hostname, port, trackWind, correctWindByDeclination,
- useInternalMarkPassingAlgorithm, new AsyncCallback() {
+ useInternalMarkPassingAlgorithm, updateURL, updateUsername, updatePassword, new AsyncCallback() {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Error trying to register races " + selectedRaces + " for tracking: "
@@ -549,6 +569,9 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
hostnameTextbox.setValue(stConfig.getHostname());
portIntegerbox.setValue(stConfig.getPort());
jsonUrlBox.setValue(stConfig.getJsonURL());
+ updateURLBox.setValue(stConfig.getUpdateURL());
+ updateUsernameBox.setValue(stConfig.getUpdateUsername());
+ updatePasswordBox.setValue(stConfig.getUpdatePassword());
}
}
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TracTracEventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TracTracEventManagementPanel.java
index 5b7069b09a8..9864e5ac78b 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TracTracEventManagementPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TracTracEventManagementPanel.java
@@ -28,6 +28,7 @@ import com.google.gwt.user.client.ui.HTMLTable.ColumnFormatter;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
+import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -79,7 +80,7 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
private TextBox jsonURLTextBox;
private TextBox tracTracUpdateURITextBox;
private TextBox tractracUsernameTextBox;
- private TextBox tractracPasswordTextBox;
+ private PasswordTextBox tractracPasswordTextBox;
private Label loadingMessageLabel;
private LabeledAbstractFilterablePanel racesFilterablePanel;
@@ -199,7 +200,7 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
grid.setWidget(6, 1, tractracUsernameTextBox);
// TracTrac Password
- tractracPasswordTextBox = new TextBox();
+ tractracPasswordTextBox = new PasswordTextBox();
tractracPasswordTextBox.ensureDebugId("TracTracPasswordTextBox");
tractracPasswordTextBox.setVisibleLength(40);
@@ -222,10 +223,8 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
}
});
grid.setWidget(9, 1, listRacesButton);
-
loadingMessageLabel = new Label();
grid.setWidget(9, 2, loadingMessageLabel);
-
return connectionsPanel;
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesManagementPanel.java
index 1432949153e..d7c70fc7ed6 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesManagementPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesManagementPanel.java
@@ -61,15 +61,16 @@ public class TrackedRacesManagementPanel extends AbstractRaceManagementPanel {
controlsPanel.add(setStartTimeButton);
selectedRaceContentPanel.add(controlsPanel);
- raceDataGrid = new Grid(6,2);
+ raceDataGrid = new Grid(7, 2);
this.selectedRaceContentPanel.add(raceDataGrid);
raceDataGrid.setText(0, 0, stringMessages.startTime()+":");
raceDataGrid.setText(1, 0, stringMessages.endTime()+":");
- raceDataGrid.setText(2, 0, stringMessages.duration()+":");
- raceDataGrid.setText(3, 0, stringMessages.startOfTracking()+":");
- raceDataGrid.setText(4, 0, stringMessages.endOfTracking()+":");
- raceDataGrid.setText(5, 0, stringMessages.delayForLiveMode()+" (ms):");
+ raceDataGrid.setText(2, 0, stringMessages.finishingTime()+":");
+ raceDataGrid.setText(3, 0, stringMessages.duration()+":");
+ raceDataGrid.setText(4, 0, stringMessages.startOfTracking()+":");
+ raceDataGrid.setText(5, 0, stringMessages.endOfTracking()+":");
+ raceDataGrid.setText(6, 0, stringMessages.delayForLiveMode()+" (ms):");
}
@Override
@@ -87,26 +88,32 @@ public class TrackedRacesManagementPanel extends AbstractRaceManagementPanel {
} else {
raceDataGrid.setText(1, 1, "");
}
- if(selectedRaceDTO.startOfRace != null && selectedRaceDTO.endOfRace != null) {
- Date duration = new Date(selectedRaceDTO.endOfRace.getTime() - selectedRaceDTO.startOfRace.getTime());
- raceDataGrid.setText(2, 1, durationFormatter.render(duration));
+ if (selectedRaceDTO.raceFinishedTime != null) {
+ raceDataGrid.setText(2, 1, dateFormatter.render(selectedRaceDTO.raceFinishedTime) + " "
+ + timeFormatter.render(selectedRaceDTO.raceFinishedTime));
} else {
raceDataGrid.setText(2, 1, "");
}
- if (selectedRaceDTO.trackedRace != null && selectedRaceDTO.trackedRace.startOfTracking != null) {
- raceDataGrid.setText(3, 1, dateFormatter.render(selectedRaceDTO.trackedRace.startOfTracking) + " "
- + timeFormatter.render(selectedRaceDTO.trackedRace.startOfTracking));
+ if(selectedRaceDTO.startOfRace != null && selectedRaceDTO.endOfRace != null) {
+ Date duration = new Date(selectedRaceDTO.endOfRace.getTime() - selectedRaceDTO.startOfRace.getTime());
+ raceDataGrid.setText(3, 1, durationFormatter.render(duration));
} else {
raceDataGrid.setText(3, 1, "");
}
- if (selectedRaceDTO.trackedRace != null && selectedRaceDTO.trackedRace.endOfTracking != null) {
- raceDataGrid.setText(4, 1, dateFormatter.render(selectedRaceDTO.trackedRace.endOfTracking) + " "
- + timeFormatter.render(selectedRaceDTO.trackedRace.endOfTracking));
+ if (selectedRaceDTO.trackedRace != null && selectedRaceDTO.trackedRace.startOfTracking != null) {
+ raceDataGrid.setText(4, 1, dateFormatter.render(selectedRaceDTO.trackedRace.startOfTracking) + " "
+ + timeFormatter.render(selectedRaceDTO.trackedRace.startOfTracking));
} else {
raceDataGrid.setText(4, 1, "");
}
+ if (selectedRaceDTO.trackedRace != null && selectedRaceDTO.trackedRace.endOfTracking != null) {
+ raceDataGrid.setText(5, 1, dateFormatter.render(selectedRaceDTO.trackedRace.endOfTracking) + " "
+ + timeFormatter.render(selectedRaceDTO.trackedRace.endOfTracking));
+ } else {
+ raceDataGrid.setText(5, 1, "");
+ }
if (selectedRaceDTO.trackedRace != null) {
- raceDataGrid.setText(5, 1, "" + selectedRaceDTO.trackedRace.delayToLiveInMs);
+ raceDataGrid.setText(6, 1, "" + selectedRaceDTO.trackedRace.delayToLiveInMs);
}
}
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/multivideo/MultiURLChangeDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/multivideo/MultiURLChangeDialog.java
index 4da6830a727..521754bde13 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/multivideo/MultiURLChangeDialog.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/multivideo/MultiURLChangeDialog.java
@@ -18,7 +18,6 @@ import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
@@ -34,6 +33,8 @@ import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.media.TimeFormatUtil;
import com.sap.sse.gwt.client.ErrorReporter;
+import com.sap.sse.gwt.client.Notification;
+import com.sap.sse.gwt.client.Notification.NotificationType;
/**
* This dialog allows to change multiple urls for mediatracks at once. It will determine the longest common prefix, that
@@ -135,7 +136,7 @@ public class MultiURLChangeDialog extends DialogBox {
@Override
public void onFailure(Throwable caught) {
- Window.alert(stringMessages.multiUrlChangeCannotSave());
+ Notification.notify(stringMessages.multiUrlChangeCannotSave(), NotificationType.ERROR);
}
});
}
@@ -150,7 +151,7 @@ public class MultiURLChangeDialog extends DialogBox {
final String maxPrefixForAll = maxPrefixForAll();
if (maxPrefixForAll.length() == 0) {
- Window.alert(this.stringMessages.multiUrlNoPrefixWarning());
+ Notification.notify(this.stringMessages.multiUrlNoPrefixWarning(), NotificationType.WARNING);
}
replacePartIn.setText(maxPrefixForAll);
updateUI();
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/multivideo/MultiVideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/multivideo/MultiVideoDialog.java
index 0304382dc9b..8238cda8f2a 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/multivideo/MultiVideoDialog.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/multivideo/MultiVideoDialog.java
@@ -24,7 +24,6 @@ import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.typedarrays.shared.Int8Array;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
@@ -59,6 +58,8 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.MimeType;
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.datetime.DateAndTimeInput;
import com.sap.sse.gwt.client.controls.datetime.DateTimeInput.Accuracy;
@@ -617,7 +618,7 @@ public class MultiVideoDialog extends DialogBox {
@Override
public void noResult() {
- Window.alert(stringMessages.serverURLInvalid());
+ Notification.notify(stringMessages.serverURLInvalid(), NotificationType.ERROR);
}
@Override
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java
index 1530fdfee6e..3abada9ea35 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java
@@ -146,8 +146,9 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
String storedURI, String courseDesignUpdateURI, boolean trackWind, boolean correctWindByDeclination,
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword) throws Exception;
- void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable rrs, String hostname, int port,
- boolean trackWind, boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm) throws Exception;
+ void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable rrs, String hostname,
+ int port, boolean trackWind, boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm,
+ String updateURL, String updateUsername, String updatePassword) throws Exception;
void replaySwissTimingRace(RegattaIdentifier regattaIdentifier, Iterable replayRaces,
boolean trackWind, boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm);
@@ -286,7 +287,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
SwissTimingEventRecordDTO getRacesOfSwissTimingEvent(String eventJsonURL) throws Exception;
- void storeSwissTimingConfiguration(String configName, String jsonURL, String hostname, Integer port);
+ void storeSwissTimingConfiguration(String configName, String jsonURL, String hostname, Integer port, String updateURL, String updateUsername, String updatePassword);
String[] getCountryCodes();
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java
index b3bbe02e0e0..dccdc5a4e1a 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java
@@ -163,7 +163,7 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable rrs,
String hostname, int port, boolean trackWind, boolean correctWindByDeclination,
- boolean useInternalMarkPassingAlgorithm, AsyncCallback asyncCallback);
+ boolean useInternalMarkPassingAlgorithm, String updateURL, String updateUsername, String updatePassword, AsyncCallback asyncCallback);
void replaySwissTimingRace(RegattaIdentifier regattaIdentifier, Iterable replayRaces,
boolean trackWind, boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm,
@@ -334,7 +334,7 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
void getRacesOfSwissTimingEvent(String eventJsonUrl, AsyncCallback asyncCallback);
void storeSwissTimingConfiguration(String configName, String jsonURL, String hostname, Integer port,
- AsyncCallback asyncCallback);
+ String updateURL, String updateUsername, String updatePassword, AsyncCallback asyncCallback);
void getCountryCodes(AsyncCallback callback);
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
index 38a6ea7f575..d427d79208e 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
@@ -2093,6 +2093,9 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String manage2SailEventIdBoxTooltip();
String manage2SailPort();
String windFinderSpotCollectionsList();
+ String swissTimingUpdateURL();
+ String swissTimingUpdateUsername();
+ String swissTimingUpdatePassword();
String tagging();
String tagFilterExplanation();
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
index 8f80a3c3ca1..fc97390e838 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
@@ -2087,6 +2087,9 @@ manage2SailEventIdBox=Manage2Sail Event ID
manage2SailEventURLBox=Manage2Sail EventURL (json)
manage2SailEventIdBoxTooltip=Event ID or a URL that contains the event ID from Manage2Sail
manage2SailPort=Port
+swissTimingUpdateURL=Update URL (e.g., for start time and course change feedback)
+swissTimingUpdateUsername=Username for sending updates
+swissTimingUpdatePassword=Password for sending updates
tagging=Tags
tagFilterExplanation=The filter will show all tags matching the criterias:
username=User name
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
index 48ef82f8c55..50f122fc377 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
@@ -2081,4 +2081,7 @@ gender=Geschlecht
manage2SailEventId=Manage2Sail Event ID
manage2SailEventURL=Manage2Sail Event URL (json)
manage2SailEventIdBoxTooltip=Event ID von Manage 2 Sail oder URL die die Event ID beinhaltet
-manage2SailPort=Port
\ No newline at end of file
+manage2SailPort=Port
+swissTimingUpdateURL=Update URL (z.B. für Startzeit-Übertragung)
+swissTimingUpdateUsername=Benutzername zum Versenden der Updates
+swissTimingUpdatePassword=Passwort zum Versenden der Updates
\ No newline at end of file
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties
index e036c02256c..6cddd2a64fb 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_es.properties
@@ -480,6 +480,8 @@ scoringSchemeHighPointFirstGetsTwelveOrEight=Puntuación alta, el ganador obtien
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Calificación en puntos. El ganador obtiene 12 puntos; el segundo, 11 puntos, etc. Si hay un empate, se resuelve a favor del competidor que tiene la mayor puntuación. Si aún persiste el empate, se resuelve mediante la posición obtenida en la última carrera puntuada.
scoringSchemeHighPointFirstGetsTwelveOrEight2017=Puntuación alta ESS 2017, el ganador obtiene 12 puntos (u 8)
scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Calificación en puntos. El ganador obtiene 12 puntos; el segundo, 11 puntos, etc. Si hay un empate, se resuelve a favor del competidor que tiene la mayor puntuación. Si aún persiste el empate, se resuelve mediante la posición obtenida en la última carrera puntuada.
+scoringSchemeLowPointSystemFirstTwoWins=Sistema de puntuación baja, primero con dos victorias en medallas es ganador
+scoringSchemeLowPointSystemFirstTwoWinsDescription=Sistema de puntuación baja. El primero en la serie de medallas que gane dos carreras, gana la serie de medallas. Ser el mejor en la serie premedallas cuenta como una victoria para este.
scoringSystem=Sistema de puntuación
createFlexibleLeaderboard=Crear tabla de clasificación flexible
createRegattaLeaderboard=Crear tabla de clasificación de regata
@@ -1163,7 +1165,8 @@ racesScoredTooltip=Número de carreras que ha completado un competidor o en las
averageNumberOfOperationsPerMessage=Número promedio de operaciones por mensaje
showUncorrectedTotalPoints=Mostrar puntos totales no corregidos
setStartTimeReceived=Fijar hora de inicio recibida
-setStartTimeReceivedDescription=Fija la HoraInicioRecibida del RegistroRastreado seleccionado que no es persistente. Esto significa que el nuevo valor se ignorará después del reinicio del servidor.
+setStartTimeReceivedDescription=Fija la startTimeReceived de la TrackedRace seleccionada en el valor proporcionado. Deje el valor en blanco para eliminar la startTimeReceived actual.
+setStartTimeReceivedNotice=Esta modificación no es persistente, es decir, el valor nuevo se olvidará cuando se reinicie el servidor.
lastScoreCorrectionsTime=Última hora de corrección de puntuación
lastScoreCorrectionsComment=Último comentario de corrección de puntuación
setTimeToNow=Fijar la hora a "ahora"
@@ -1278,8 +1281,8 @@ showCompetitorBoatColumn=Embarcación del competidor
showCompetitorShortNameColumn=Denominación breve de competidor
showCompetitorShortNameColumnTooltip=Muestra el nombre breve más la bandera del país o imagen del competidor. Si está disponible, se prioriza la imagen de competidor a la bandera del país. Se mostrarán ambos iconos si se fija "{0}".
showCompetitorFullNameColumn=Nombre completo del competidor
-showCompetitorNationalityColumn=Siempre mostrar la nacionalidad del competidor
-showCompetitorNationalityColumnTooltip=Muestra ambos, las banderas de país así como las imágenes de competidor, si están disponibles.
+showCompetitorNationalityColumn=Mostrar adicionalmente la nacionalidad del competidor
+showCompetitorNationalityColumnTooltip=Mostrar las banderas de nacionalidad junto con las imágenes del competidor si están disponibles
loadingDimensionValues=Cargando valores de dimensión
inviteBuoyTenders=Invitar a balizadores
orMultipleEmails=o varios correos electrónicos separados por una coma
@@ -1971,6 +1974,7 @@ windFinderWindSourceTypeTooltip=Viento medido de uno o más puntos de www.windfi
windFinder=Windfinder
enterTagsForTheVideo=Indique las etiquetas para el vídeo
enterIdOfWindFinderReviewedSpotCollection=Indique el ID de una colección de puntos de Windfinder revisada, por ejemplo "schilksee"
+windFinderSpotCollectionsList=Colecciones de puntos de WindFinder
enterTagsForTheImage=Indique las etiquetas para la imagen
unableToResolveWindFinderSpotId=Imposible resolver el punto Windfinder con ID {0}: {1}
windFinderWeatherData=Datos meteorológicos
@@ -2055,6 +2059,9 @@ multiVideoIdle=Cola de trabajo inactiva
multiVideoDoNoAdd=No añadir
multiVideoOffsetInput=Offset de vídeo global en milisegundos:
multiVideoDescription=El servidor web debe proporcionar una lista de índices (subcarpetas compatibles si están indexadas) para permitir la detección de ficheros. Tras un análisis inicial de los metadatos contenidos en los ficheros mp4, los vídeos que deben añadirse, deben seleccionarse mediante la columna de la casilla de selección a la izquierda. El botón "Añadir audio/vídeo" creará pistas multimedia para todos los ficheros seleccionados y los añadirá a todas las carreras seleccionadas en la columna de la derecha.
+jibeAngle=Ángulo de trasluchada
+tackAngle=Ángulo de bordo
+maneuverAngle=Ángulo de maniobra
multiUrlChangeMediaTrack=Ajustar URLs de rastreo múltiple de medios
multiUrlChangeReplace=Reemplazar por
multiUrlChangeFind=Buscar
@@ -2063,5 +2070,16 @@ multiUrlChangeSave=Grabar modificaciones de URL
multiUrlChangeNewURL=URL nuevo
multiUrlNoPrefixWarning=No existe ningún prefijo común, esto significa que normalmente no todos los vídeos seleccionados se alojan actualmente en la misma ubicación. Proceda bajo su propio riesgo.
multiUrlChangeExplain=Este diálogo reemplazará en masa las partes comunes al inicio de los URLs del rastreo de medios. Asegúrate de que todas las URL empiezan con el mismo prefijo. Además, eche un vistazo a la nueva columna del URL, y pruebe los URLs resultantes antes de pulsar Grabar.
+resetZoom=Reinicializar zoom
lastEvent=Último evento: {0}
teaserOverallLinkToolTip=Para visualizar las series generales, haga clic en la esquina amarilla
+middleManeuverAngle=Ángulo medio de maniobra
+extrapolatedManeuverStartPosition=Posición de inicio de maniobra extrapolada
+projectedExtrapolatedManeuverStartPosition=Proyección de posición de inicio de maniobra extrapolada en línea de ángulo medio de maniobra
+projectedManeuverEndPosition=Proyección de posición de fin de maniobra en línea de ángulo medio de maniobra
+bearingAtManeuverEndPosition=Rumbo en posición de fin de maniobra
+gender=Sexo
+manage2SailEventIdBox=ID de evento Manage2Sail
+manage2SailEventURLBox=URL de evento Manage2Sail (json)
+manage2SailEventIdBoxTooltip=ID de evento o URL que contiene el ID de evento de Manage2Sail
+manage2SailPort=Puerto
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties
index 547e5d5823c..4eceacdde57 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_fr.properties
@@ -480,6 +480,8 @@ scoringSchemeHighPointFirstGetsTwelveOrEight=Système de points avec bonus, le v
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Score en points. Le vainqueur totalise 12 points, le deuxième 11, etc. En cas d''égalité, la victoire est accordée au concurrent qui a totalisé le plus de points. Si l''égalité persiste, la victoire est accordée en fonction du classement dans la dernière course.
scoringSchemeHighPointFirstGetsTwelveOrEight2017=Système de points avec bonus - ESS 2017, le vainqueur obtient 12 points (ou 8)
scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Score en points. Le vainqueur totalise 12 points, le deuxième 11, etc. En cas d''égalité, la victoire est accordée au concurrent qui a totalisé le plus de points. Si l''égalité persiste, la victoire est accordée en fonction du classement dans la dernière course.
+scoringSchemeLowPointSystemFirstTwoWins=Système de points a minima. Le premier ayant gagné deux médailles gagne la compétition.
+scoringSchemeLowPointSystemFirstTwoWinsDescription=Système de points a minima. Le premier ayant gagné deux courses gagne la série médaillée. Si un concurrent a été le meilleur dans la série pré-médailles, cela compte comme une victoire pour la série médaillée.
scoringSystem=Système d''attribution des points
createFlexibleLeaderboard=Créer palmarès flexible
createRegattaLeaderboard=Créer palmarès régate
@@ -1163,7 +1165,8 @@ racesScoredTooltip=Nombre de courses que le concurrent a terminées, ou pour les
averageNumberOfOperationsPerMessage=Nombre moyen d''opérations par message
showUncorrectedTotalPoints=Afficher total des points non corrigé
setStartTimeReceived=Afficher heure de départ reçue
-setStartTimeReceivedDescription=Définit l''heure de départ reçue de la course suivie sélectionnée non persistante. Cela signifie que la nouvelle valeur sera oubliée une fois que le serveur sera relancé.
+setStartTimeReceivedDescription=Définit l''heure de départ reçue de la course suivie sélectionnée sur la valeur indiquée. Ne renseignez pas cette valeur si vous voulez supprimer l''actuelle heure de départ reçue définie.
+setStartTimeReceivedNotice=Cette modification n''est pas persistante. Cela signifie que la nouvelle valeur sera oubliée une fois que le serveur sera redémarré.
lastScoreCorrectionsTime=Dernière heure de correction du score
lastScoreCorrectionsComment=Dernier commentaire sur la correction du score
setTimeToNow=Définir heure sur "maintenant"
@@ -1278,8 +1281,8 @@ showCompetitorBoatColumn=Bateau du concurrent
showCompetitorShortNameColumn=Nom court du concurrent
showCompetitorShortNameColumnTooltip=Affiche le nom court ainsi que le drapeau national ou l''image du concurrent. Si les deux sont disponibles, l''image du concurrent aura la priorité sur le drapeau national. Si le code "{0}" est activé, les deux icônes seront affichées.
showCompetitorFullNameColumn=Nom complet du concurrent
-showCompetitorNationalityColumn=Afficher toujours la nationalité du concurrent
-showCompetitorNationalityColumnTooltip=Si disponibles, afficher les deux : le drapeau national ainsi que l''image du concurrent
+showCompetitorNationalityColumn=Afficher en plus la nationalité du concurrent
+showCompetitorNationalityColumnTooltip=Si disponible, afficher le drapeau national en plus de l''image du concurrent.
loadingDimensionValues=Chargement des valeurs de dimension
inviteBuoyTenders=Inviter navire baliseur
orMultipleEmails=ou plusieurs adresses e-mails séparées par des virgules
@@ -1851,7 +1854,7 @@ minDataCount=Nombre de données min.
moreLoginInformationHeadline=Avantages de SAP Sailing Analytics
moreLoginInformationIntroduction=Si vous êtes un utilisateur inscrit sur SAP Sailing Analytics, vous avez accès à des fonctionnalités qui ne sont pas disponibles pour les utilisateurs anonymes. Inscrivez-vous pour accéder à toutes les fonctionnalités indiquées ci-dessous.
moreLoginInformationSectionUserSettingsHeading=Options utilisateur
-moreLoginInformationSectionUserSettingsDescription=Certaines éléments de l''interface utilisateur peuvent être personnalisés. Les fonctionnalités de base sont accessibles à tous les utilisateurs, mais les utilisateurs authentifiés ont la possibilité de modifier leurs options. Celles-ci sont conservées dans leur profil utilisateur et disponibles sur n''importe quel appareil dès que l''utilisateur se connecte.
+moreLoginInformationSectionUserSettingsDescription=Certains éléments de l''interface utilisateur peuvent être personnalisés. Les fonctionnalités de base sont accessibles à tous les utilisateurs, mais les utilisateurs authentifiés ont la possibilité de modifier leurs options. Celles-ci sont conservées dans leur profil utilisateur et disponibles sur n''importe quel appareil dès que l''utilisateur se connecte.
moreLoginInformationSectionStrategySimulatorDescription=Le simulateur permet aux navigateurs de simuler des stratégies sur des portions de parcours grâce à des conditions de vent configurables. Le simulateur se base sur l''ensemble des données historiques disponibles dans SAP Sailing Analytics pour fournir des simulations de comportements de catégories de bateaux spécifiques les plus précises possibles.
moreLoginInformationSectionUserNotificationsHeading=Notifications utilisateur
moreLoginInformationSectionUserNotificationsDescription=Grâce aux notifications utilisateur, vous pouvez rester informé sur votre catégorie de bateau, votre équipe ou votre concurrent favoris. Vous avez la possibilité de vous abonner afin de recevoir des notifications par e-mail sur votre catégorie de bateau, votre équipe ou votre concurrent favoris, ainsi que sur les différentes courses à venir.
@@ -1874,7 +1877,7 @@ maximumSpeedNotFoilingInKnotsTooltip=Vitesse fond maximale en nœuds qu''un bate
minimumSpeedForFoilingInKnots=Vitesse fond minimale pour déjauger (nds)
minimumSpeedForFoilingInKnotsTooltip=Vitesse fond minimale en nœuds qu''un bateau doit atteindre pour pouvoir déjauger. Si la vitesse est inférieure à celle-ci, la hauteur de planing sera ignorée et le bateau ne sera pas considéré comme étant en déjaugeage. Laissez vide ou indiquez 0 si vous souhaitez également vous référer au capteur de hauteur de planing pour les vitesses faibles.
minimumRideHeightInMeters=Hauteur de planing minimale (m)
-minimumRideHeightInMetersTooltip=Hauteur de planing minimale requise en mètres pour qu''une bateau soit considéré comme étant en état de déjaugeage.
+minimumRideHeightInMetersTooltip=Hauteur de planing minimale requise en mètres pour qu''un bateau soit considéré comme étant en état de déjaugeage.
minimumDurationBetweenAdjacentFoilingSegmentsInSeconds=Durée minimum (s) entre deux tronçons en planing adjacents
minimumDurationBetweenAdjacentFoilingSegmentsInSecondsTooltip=Si cette valeur est renseignée et que la durée entre deux tronçons de planing adjacents est inférieure à celle-ci, ces tronçons de planing adjacents seront combinés en un seul.
needToProvideValidMinimumRideHeight=Vous devez fournir une valeur de hauteur de planing minimale valide en mètres.
@@ -1971,6 +1974,7 @@ windFinderWindSourceTypeTooltip=Vent mesuré d''un ou plusieurs endroits de www.
windFinder=WindFinder
enterTagsForTheVideo=Entrez des balises pour la vidéo.
enterIdOfWindFinderReviewedSpotCollection=Entrez l''ID d''un ensemble d''endroits WindFinder révisé, par exemple, "Schilksee".
+windFinderSpotCollectionsList=Ensemble d''endroits WindFinder
enterTagsForTheImage=Entrez des balises pour l''image.
unableToResolveWindFinderSpotId=Impossible de traiter l''endroit WindFinder ayant l''ID {0} : {1}
windFinderWeatherData=Données météo
@@ -2055,6 +2059,9 @@ multiVideoIdle=La réserve de travail est inactive.
multiVideoDoNoAdd=Ne pas ajouter
multiVideoOffsetInput=Décalage vidéo global en millisecondes :
multiVideoDescription=Le serveur Web doit fournir une liste des index (les sous-dossiers sont pris en charge s''ils sont répertoriés) pour permettre la détection de fichier. Après une analyse initiale des métadonnées contenues dans les fichiers MP4, les vidéos à ajouter doivent être sélectionnées en cochant les cases correspondantes dans la colonne de gauche. Le bouton "Ajouter audio/vidéo" va créer des pistes médias pour tous les fichiers sélectionnés, et ajouter ces fichiers à toutes les courses sélectionnées dans la colonne de droite.
+jibeAngle=Angle d''amure
+tackAngle=Angle de virement de bord
+maneuverAngle=Angle de manœuvre
multiUrlChangeMediaTrack=Ajuster plusieurs URL de piste média
multiUrlChangeReplace=Remplacer par
multiUrlChangeFind=Rechercher
@@ -2063,5 +2070,16 @@ multiUrlChangeSave=Sauvegarder modifications apportées aux URL
multiUrlChangeNewURL=Nouvelle URL
multiUrlNoPrefixWarning=Aucun préfixe commun n''a été trouvé. Cela signifie généralement que les vidéos sélectionnées ne sont actuellement pas toutes hébergées au même endroit. Vous assumez les risques liés à leur utilisation.
multiUrlChangeExplain=Cette boîte de dialogue remplacera en masse les éléments communs au début des URL de piste média. Assurez-vous que toutes les URL commencent par le même préfixe. Veuillez également prendre le temps d''observer la nouvelle colonne d''URL, et de tester les URL résultantes avant de sauvegarder.
-lastEvent=Dernier événement : {0}
+resetZoom=Réinitialiser le zoom
+lastEvent=Dernière manifestation : {0}
teaserOverallLinkToolTip=Pour afficher l''ensemble des séries, cliquez sur le coin jaune.
+middleManeuverAngle=Angle de manœuvre (milieu)
+extrapolatedManeuverStartPosition=Position extrapolée du début de la manœuvre
+projectedExtrapolatedManeuverStartPosition=Projection de la position extrapolée du début de la manœuvre sur la ligne de l''angle de manœuvre (milieu)
+projectedManeuverEndPosition=Projection de la position extrapolée de fin de la manœuvre sur la ligne de l''angle de manœuvre (milieu)
+bearingAtManeuverEndPosition=Direction à la position de fin de la manœuvre
+gender=Sexe
+manage2SailEventIdBox=ID de manifestation Manage2Sail
+manage2SailEventURLBox=URL de la manifestation Manage2Sail (json)
+manage2SailEventIdBoxTooltip=ID d''événement ou URL contenant l''ID d''événement issu de Manage2Sail
+manage2SailPort=Bâbord
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties
index 6eab3ac7219..6bcbca3f0b9 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties
@@ -480,6 +480,8 @@ scoringSchemeHighPointFirstGetsTwelveOrEight=高得点方式、1 位が 12 点 (
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=得点数によるスコアです。1 位が 12 点、2 位が 11 点などと得点します。同点となった場合は、(各競技者のレース得点を高い方から比較して) 最多得点の競技者を上位とします。それでも同順位となる場合には、最終レースでの得点でのランクで順位を決定します。
scoringSchemeHighPointFirstGetsTwelveOrEight2017=高得点方式 ESS 2017、1 位が 12 点 (または 8 点)
scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=得点数によるスコアです。1 位が 12 点、2 位が 11 点などと得点します。同点となった場合は、(各競技者のレース得点を高い方から比較して) 最多得点の競技者を上位とします。それでも同順位となる場合には、最終レースでの得点でのランクで順位を決定します。
+scoringSchemeLowPointSystemFirstTwoWins=低得点方式、メダルシリーズで最初に 2 勝した者が勝者
+scoringSchemeLowPointSystemFirstTwoWinsDescription=低得点方式。メダルシリーズで最初に 2 レースに勝利した者をメダルシリーズの勝者とします。プレメダルシリーズでの最上位をメダルシリーズの 1 勝としてカウントします。
scoringSystem=得点方式
createFlexibleLeaderboard=フレキシブルリーダーボード登録
createRegattaLeaderboard=レガッタリーダーボード登録
@@ -1163,7 +1165,8 @@ racesScoredTooltip=このリーダーボードにおいて競技者が完了し
averageNumberOfOperationsPerMessage=メッセージごとの操作の平均数
showUncorrectedTotalPoints=未修正総得点表示
setStartTimeReceived=設定済スタート時刻を受信
-setStartTimeReceivedDescription=これにより、永続的でない選択した TrackedRace の startTimeReceived が設定されます。したがって、サーバが再起動された後は新規の値は忘れられます。
+setStartTimeReceivedDescription=選択した TrackedRace の startTimeReceived が指定した値に設定されます。値を空白のままにすると、現在設定されている startTimeReceived は削除されます。
+setStartTimeReceivedNotice=この変更は永続的なものではありません。つまり、新しい値はサーバが再起動したときに失われます。
lastScoreCorrectionsTime=最終得点修正時刻
lastScoreCorrectionsComment=最終得点修正コメント
setTimeToNow=時刻を ''現在'' に設定
@@ -1278,8 +1281,8 @@ showCompetitorBoatColumn=競技者の艇
showCompetitorShortNameColumn=競技者の名前 (短)
showCompetitorShortNameColumnTooltip=名前 (短) に加えて国旗または競技者画像を表示します。競技者画像が利用可能な場合はそれを国旗よりも優先させます。"{0}" が設定されている場合、両方のアイコンが表示されます。
showCompetitorFullNameColumn=競技者氏名
-showCompetitorNationalityColumn=競技者国籍を常に表示
-showCompetitorNationalityColumnTooltip=国旗と競技者画像 (利用可能な場合) の両方を表示
+showCompetitorNationalityColumn=競技者国籍を追加的に表示
+showCompetitorNationalityColumnTooltip=競技者画像に加え国旗を表示 (利用可能な場合)
loadingDimensionValues=次元値ロード中
inviteBuoyTenders=ブイ入札の招待
orMultipleEmails=または複数の電子メールをカンマで区切り
@@ -1971,6 +1974,7 @@ windFinderWindSourceTypeTooltip=www.windfinder.com の 1 つ以上のスポッ
windFinder=Windfinder
enterTagsForTheVideo=動画のタグを入力
enterIdOfWindFinderReviewedSpotCollection=レビューする Windfinder スポットコレクションの ID を入力 (例: "schilksee")
+windFinderSpotCollectionsList=WindFinder スポットコレクション
enterTagsForTheImage=画像のタグを入力
unableToResolveWindFinderSpotId=ID {0} で Windfinder スポットを決定できませんでした: {1}
windFinderWeatherData=気象データ
@@ -2055,6 +2059,9 @@ multiVideoIdle=ワークキューが無効です
multiVideoDoNoAdd=追加しないでください
multiVideoOffsetInput=グローバル動画オフセット (msec):
multiVideoDescription=Web サーバは、ファイルディスカバリを可能にするため、インデックスリスト (インデックスが作成されている場合はサブフォルダがサポート済) を用意していることが必要です。MP4 ファイルに含まれているメタデータの初期解析後に、追加する動画を左側のチェックボックス列で選択する必要があります。"音声/動画追加" ボタンにより、選択されているすべてのファイルに対してメディアトラックが作成され、右側の列で選択されているすべてのレースに対してそれらのファイルが追加されます。
+jibeAngle=ジャイブ角
+tackAngle=タック角
+maneuverAngle=マニューバー角
multiUrlChangeMediaTrack=複数メディアトラック URL の調整
multiUrlChangeReplace=置換後の文字列
multiUrlChangeFind=検索
@@ -2063,5 +2070,16 @@ multiUrlChangeSave=URL 変更の保存
multiUrlChangeNewURL=新規 URL
multiUrlNoPrefixWarning=共通の接頭辞が見つかりませんでした。これは通常、選択した動画のうち現在同じ場所に置かれていないものがあることを意味します。自身の責任で進めてください。
multiUrlChangeExplain=このダイアログはメディアトラック URL 先頭の共通部分をまとめて置換します。すべての URL が同一の接頭辞で始まっていることを確認してください。また、新規 URL 列を参照し、保存を選択する前に結果として得られる URL を吟味してください。
+resetZoom=拡大/縮小のリセット
lastEvent=最終イベント: {0}
teaserOverallLinkToolTip=シリーズ全体を参照するには、黄色になっている隅の部分をクリックしてください
+middleManeuverAngle=マニューバー角の中心
+extrapolatedManeuverStartPosition=推定マニューバー開始位置
+projectedExtrapolatedManeuverStartPosition=マニューバー角の中心線上に推定マニューバー開始位置を投影
+projectedManeuverEndPosition=マニューバー角の中心線上にマニューバー終了位置を投影
+bearingAtManeuverEndPosition=マニューバー終了位置での方位
+gender=性別
+manage2SailEventIdBox=Manage2Sail イベント ID
+manage2SailEventURLBox=Manage2Sail イベント URL (JSON)
+manage2SailEventIdBoxTooltip=イベント ID または Manage2Sail からのイベント ID が入っている URL
+manage2SailPort=ポート
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties
index 0206d843906..d13909efea6 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_pt.properties
@@ -480,6 +480,8 @@ scoringSchemeHighPointFirstGetsTwelveOrEight=Sistema de bônus, o vencedor receb
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Pontuação em pontos. O vencedor pontua 12 pontos, o 2º - 11 pontos, .... Um desempate é efetuado a favor do competidor com a pontuação mais alta, se o empate continuar, então o desempate é efetuado pela posição na última corrida pontuada.
scoringSchemeHighPointFirstGetsTwelveOrEight2017=Sistema de bônus ESS 2017, o vencedor recebe 12 pontos (ou 8)
scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Pontuação em pontos. O vencedor pontua 12 pontos, o 2º - 11 pontos, .... Um desempate é efetuado a favor do competidor com a pontuação mais alta, se o empate continuar, então o desempate é efetuado pela posição na última corrida pontuada.
+scoringSchemeLowPointSystemFirstTwoWins=Sistema linear, o primeiro com duas vitórias com medalhas é o vencedor.
+scoringSchemeLowPointSystemFirstTwoWinsDescription=Sistema linear. O primeiro na série para medalha a vencer duas corridas vence a série para medalha. Ser o melhor na série prévia para medalha conta como uma vitória para este efeito.
scoringSystem=Sistema de pontuação
createFlexibleLeaderboard=Criar painel de classificação flexível
createRegattaLeaderboard=Criar painel de classificação de regata
@@ -1163,7 +1165,8 @@ racesScoredTooltip=Número de corridas que o competidor concluiu ou nas quais ob
averageNumberOfOperationsPerMessage=Número médio de operações por mensagem
showUncorrectedTotalPoints=Visualizar total de pontos não corrigidos
setStartTimeReceived=Definir hora de partida recebida
-setStartTimeReceivedDescription=Isto define a hora de partida recebida da corrida rastreada selecionada que não é persistente. Isto significa que o novo valor será esquecido após a reinicialização do servidor.
+setStartTimeReceivedDescription=Define a hora de partida recebida da corrida rastreada selecionada para o valor fornecido. Deixe o valor em branco para remover a hora de partida recebida definida atualmente.
+setStartTimeReceivedNotice=Esta modificação não é persistente, ou seja, o novo valor será esquecido quando o servidor for reiniciado.
lastScoreCorrectionsTime=Hora de correção da última pontuação
lastScoreCorrectionsComment=Comentário de correção da última pontuação
setTimeToNow=Definir hora para ''agora''
@@ -1278,8 +1281,8 @@ showCompetitorBoatColumn=Barco do competidor
showCompetitorShortNameColumn=Nome abreviado do competidor
showCompetitorShortNameColumnTooltip=Exibe o nome abreviado mais a bandeira de nacionalidade ou a imagem do competidor. Se disponível, é priorizada uma imagem do competidor em relação a uma bandeira da nacionalidade. Se "{0}" estiver definido, ambos os ícones serão exibidos.
showCompetitorFullNameColumn=Nome completo do competidor
-showCompetitorNationalityColumn=Exibir sempre a nacionalidade do competidor
-showCompetitorNationalityColumnTooltip=Exibir ambos, bandeiras de nacionalidade e imagens do competidor, se disponíveis
+showCompetitorNationalityColumn=Exibir adicionalmente a nacionalidade do competidor
+showCompetitorNationalityColumnTooltip=Exibir bandeiras de nacionalidade além das imagens do competidor, caso estejam disponíveis
loadingDimensionValues=Carregando valores de dimensão
inviteBuoyTenders=Convidar navios-balizadores
orMultipleEmails=ou vários e-mails separados por vírgula
@@ -1971,6 +1974,7 @@ windFinderWindSourceTypeTooltip=Vento medido de um ou mais locais de www.windfin
windFinder=WindFinder
enterTagsForTheVideo=Inserir etiquetas para o vídeo
enterIdOfWindFinderReviewedSpotCollection=Inserir ID de uma coleção revisada de locais do WindFinder, por exemplo, "schilksee"
+windFinderSpotCollectionsList=Coleções de locais do WindFinder
enterTagsForTheImage=Inserir etiquetas para a imagem
unableToResolveWindFinderSpotId=Impossível resolver local do WindFinder com ID {0}: {1}
windFinderWeatherData=Dados metereológicos
@@ -2055,6 +2059,9 @@ multiVideoIdle=A lista de trabalho está inativa
multiVideoDoNoAdd=Não adicionar
multiVideoOffsetInput=Deslocamento de vídeo global em milissegundos:
multiVideoDescription=O servidor da web é necessário para fornecer a lista de índices (subpastas suportadas se indexadas) de modo a permitir a descoberta de arquivos. Após uma análise inicial dos metadados contidos nos arquivos mp4, os vídeos que deviam ser adicionados precisam ser selecionados mediante a coluna do campo de seleção à esquerda. O botão "Adicionar áudio/vídeo" irá criar faixas de mídia para todos os arquivos selecionados e adicionar esses arquivos a todas as corridas selecionadas na coluna à direita.
+jibeAngle=Ângulo de jaibe
+tackAngle=Ângulo de cambada
+maneuverAngle=Ângulo de manobra
multiUrlChangeMediaTrack=Ajustar vários URLs de faixa de mídia
multiUrlChangeReplace=Substituir por
multiUrlChangeFind=Procurar
@@ -2063,5 +2070,16 @@ multiUrlChangeSave=Gravar modificações do URL
multiUrlChangeNewURL=novo URL
multiUrlNoPrefixWarning=Não foi encontrado um prefixo comum. Isso normalmente significa que nem todos os vídeos selecionados estão hospedados atualmente no mesmo local. Continue por sua própria conta e risco!
multiUrlChangeExplain=Este diálogo irá substituir em massa as partes comuns no início dos URLs da faixa de mídia. Assegure que todos os URLs começam com o mesmo prefixo! Veja também a nova coluna do URL e teste os URLs resultantes antes de pressionar Gravar!
+resetZoom=Reinicializar zoom
lastEvent=Último evento: {0}
teaserOverallLinkToolTip=Para ver a série completa, clique no canto amarelo
+middleManeuverAngle=Ângulo médio de manobra
+extrapolatedManeuverStartPosition=Posição inicial de manobra extrapolada
+projectedExtrapolatedManeuverStartPosition=Projeção da posição inicial de manobra extrapolada na linha de ângulo médio de manobra
+projectedManeuverEndPosition=Projeção da posição final de manobra na linha de ângulo médio de manobra
+bearingAtManeuverEndPosition=Rumo na posição final de manobra
+gender=Sexo
+manage2SailEventIdBox=ID de evento Manage2Sail
+manage2SailEventURLBox=URL de evento Manage2Sail (json)
+manage2SailEventIdBoxTooltip=ID de evento ou um URL que contenha o ID de evento do Manage2Sail
+manage2SailPort=Porta
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties
index 6847ca0ef94..4bf82159e3e 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties
@@ -480,6 +480,8 @@ scoringSchemeHighPointFirstGetsTwelveOrEight=Высокий балл, побед
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Оценка в баллах. Победитель получает 12 баллов, 2-й — 11 баллов, .... Равенство разрешается в пользу участника с наивысшей оценкой. Если равенство сохраняется, оно разрешается по рангу в последней гонке.
scoringSchemeHighPointFirstGetsTwelveOrEight2017=Высокий балл ESS 2017, победитель получает 12 баллов (или 8)
scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=Оценка в баллах. Победитель получает 12 баллов, 2-й — 11 баллов, .... Равенство разрешается в пользу участника с наивысшей оценкой. Если равенство сохраняется, оно разрешается по рангу в последней гонке.
+scoringSchemeLowPointSystemFirstTwoWins=Система низких баллов, первый с двумя победами в гонках на медали является победителем
+scoringSchemeLowPointSystemFirstTwoWinsDescription=Система низких баллов. Первый в серии на медали, кто выиграл две гонки, выигрывает серию на медали. Получение статуса "Лучший" в серии, предшествующей медальной, считается одной победой.
scoringSystem=Система оценок
createFlexibleLeaderboard=Создать гибкую таблицу лидеров
createRegattaLeaderboard=Создать таблицу лидеров регаты
@@ -1163,7 +1165,8 @@ racesScoredTooltip=Число гонок, которые участник зав
averageNumberOfOperationsPerMessage=Среднее число операций на сообщение
showUncorrectedTotalPoints=Показать неисправленный общий балл
setStartTimeReceived=Установить полученное время старта
-setStartTimeReceivedDescription=Устанавливает полученное время старта для выбранной отслеживаемой гонки, которое не хранится постоянно. Это значит, что после перезагрузки сервера новое значение будет забыто.
+setStartTimeReceivedDescription=Устанавливает введенное значение для полученного времени старта выбранной отслеживаемой гонки. Оставьте значение пустым, чтобы удалить текущее установленное полученное время старта.
+setStartTimeReceivedNotice=Это изменение не хранится, т.е. новое значение будет забыто после перезагрузки сервера.
lastScoreCorrectionsTime=Время последнего исправления оценки
lastScoreCorrectionsComment=Комментарий последнего исправления оценки
setTimeToNow=Установить время ''сейчас''
@@ -1278,8 +1281,8 @@ showCompetitorBoatColumn=Лодка участника
showCompetitorShortNameColumn=Краткое имя участника
showCompetitorShortNameColumnTooltip=Показывает краткое имя плюс государственный флаг или изображение участника. Изображение участника, при наличии, имеет приоритет над государственным флагом. Если установлен параметр "{0}", будут отображены оба значка.
showCompetitorFullNameColumn=Полное имя участника
-showCompetitorNationalityColumn=Всегда показывать государственную принадлежность участника
-showCompetitorNationalityColumnTooltip=Показывать и флаги государств, и изображения участников (при наличии)
+showCompetitorNationalityColumn=Дополнительно показывать государственную принадлежность участника
+showCompetitorNationalityColumnTooltip=Показывать государственные флаги (если есть) дополнительно к фотографии участника
loadingDimensionValues=Загрузка значений измерения
inviteBuoyTenders=Пригласить лоцманов
orMultipleEmails=или несколько адресов эл. почты через запятую
@@ -1971,6 +1974,7 @@ windFinderWindSourceTypeTooltip=Измерения ветра из одного
windFinder=WindFinder
enterTagsForTheVideo=Введите теги для видео
enterIdOfWindFinderReviewedSpotCollection=Введите ид. просмотренной коллекции мест WindFinder (например, "schilksee")
+windFinderSpotCollectionsList=Коллекции мест WindFinder
enterTagsForTheImage=Введите теги для изображения
unableToResolveWindFinderSpotId=Не удалось разрешить место WindFinder по ид. {0}: {1}
windFinderWeatherData=Данные погоды
@@ -2055,6 +2059,9 @@ multiVideoIdle=Рабочий список неактивен
multiVideoDoNoAdd=Не добавлять
multiVideoOffsetInput=Смещение глобального видео в мс:
multiVideoDescription=Веб-сервер необходим для предоставления списка индекса (подпапки поддерживаются, если проиндексированы) для поиска файлов. После первичного анализа метаданных, содержащихся в файлах mp4, видео, которые должны быть добавлены, необходимо выбрать в столбце с флажками слева. При нажатии кнопки "Добавить аудио/видео" будут созданы медиаканалы для всех выбранных файлов, а файлы будут добавлены ко всем гонкам, выбранным в правом столбце.
+jibeAngle=Поворот фордевинд
+tackAngle=Галсовый угол
+maneuverAngle=Угол маневра
multiUrlChangeMediaTrack=Адаптировать URL объектов мультимедиа
multiUrlChangeReplace=Заменить на
multiUrlChangeFind=Найти
@@ -2063,5 +2070,16 @@ multiUrlChangeSave=Сохранить изменения URL
multiUrlChangeNewURL=Новый URL
multiUrlNoPrefixWarning=Общий префикс не найден, это означает, что не все выбранные видео хранятся в одном и том же месте. Можете продолжить на свой риск!
multiUrlChangeExplain=В этом диалоговом окне можно выполнить массовую замену общих частей в начале URL объектов мультимедиа. Убедитесь, что все URL имеют одинаковый префикс! Проверьте также столбец с новым URL и протестируйте новые URL перед сохранением!
+resetZoom=Сбросить увеличение
lastEvent=Последнее событие: {0}
teaserOverallLinkToolTip=Чтобы увидеть все серии, нажмите желтый треугольник
+middleManeuverAngle=Угол в середине маневра
+extrapolatedManeuverStartPosition=Расширенная начальная позиция маневра
+projectedExtrapolatedManeuverStartPosition=Проекция расширенной начальной позиции маневра на линии угла в середине маневра
+projectedManeuverEndPosition=Проекция конечной позиции маневра на линии угла в середине маневра
+bearingAtManeuverEndPosition=Направление в конечной позиции маневра
+gender=Пол
+manage2SailEventIdBox=Ид. события Manage2Sail
+manage2SailEventURLBox=URL события Manage2Sail (json)
+manage2SailEventIdBoxTooltip=Ид. события или URL, содержащий ид. события из Manage2Sail
+manage2SailPort=Порт
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties
index cb19fde8474..e8e848faa28 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties
@@ -480,6 +480,8 @@ scoringSchemeHighPointFirstGetsTwelveOrEight=高分,获胜者得 12 分(或
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=得分。获胜者得 12 分、第 2 名 11 分、.... 得分最高的参赛队取得胜利,如果仍有平局,则以最后一个比赛轮次的名次打破平局。
scoringSchemeHighPointFirstGetsTwelveOrEight2017=2017 年极限帆船系列赛高分,获胜者得 12 分(或 8 分)
scoringSchemeHighPointFirstGetsTwelveOrEight2017Description=得分。获胜者得 12 分、第 2 名 11 分、.... 得分最高的参赛队取得胜利,如果仍有平局,则以最后一个比赛轮次的名次打破平局。
+scoringSchemeLowPointSystemFirstTwoWins=低分系统,奖牌轮中取得两场胜利的第一名为获胜者
+scoringSchemeLowPointSystemFirstTwoWinsDescription=低分系统。在奖牌轮系列中,在两个比赛轮次中获胜的第一名在奖牌轮系列中获胜。奖牌轮系列预赛中的佼佼者记为获胜。
scoringSystem=记分系统
createFlexibleLeaderboard=创建灵活的积分榜
createRegattaLeaderboard=创建比赛积分榜
@@ -1163,7 +1165,8 @@ racesScoredTooltip=参赛队完成并记录在此积分榜上的比赛轮次数
averageNumberOfOperationsPerMessage=各消息操作的平均数
showUncorrectedTotalPoints=显示未更正的总分
setStartTimeReceived=设置接收的开始时间
-setStartTimeReceivedDescription=设置非持久的所选 TrackedRace 的 startTimeReceived。这意味着,重启服务器后,将忘记新值。
+setStartTimeReceivedDescription=将所选 TrackedRace 的 startTimeReceived 设置为提供的值。将此值留空,以移除当前设置的 startTimeReceived。
+setStartTimeReceivedNotice=此更改并不持久,即重启服务器后,新值将被忘记。
lastScoreCorrectionsTime=上次得分更正时间
lastScoreCorrectionsComment=上次得分更正评论
setTimeToNow=将时间设为“现在”
@@ -1278,8 +1281,8 @@ showCompetitorBoatColumn=参赛队的船只
showCompetitorShortNameColumn=参赛队短名称
showCompetitorShortNameColumnTooltip=显示短名称和国籍旗帜或参赛队图像。如果可用,参赛队图像优先于国籍旗帜。如果设置 "{0}",将显示这两种图标。
showCompetitorFullNameColumn=参赛队全名
-showCompetitorNationalityColumn=始终显示参赛队国籍
-showCompetitorNationalityColumnTooltip=如果可用,显示两者:国籍旗帜和参赛队图像
+showCompetitorNationalityColumn=另外显示参赛队国籍
+showCompetitorNationalityColumnTooltip=除参赛队图像外还显示国籍旗帜(如果有)
loadingDimensionValues=正在加载尺寸值
inviteBuoyTenders=邀请浮标供应船
orMultipleEmails=或使用逗号隔开的多个电子邮件
@@ -1971,6 +1974,7 @@ windFinderWindSourceTypeTooltip=Www.windfinder.com 中一个或多个地点的
windFinder=WindFinder
enterTagsForTheVideo=为视频输入标记
enterIdOfWindFinderReviewedSpotCollection=输入经检查的 WindFinder 地点集合的编号,例如 "schilksee"
+windFinderSpotCollectionsList=WindFinder 地点集合
enterTagsForTheImage=为图像输入标记
unableToResolveWindFinderSpotId=无法解析编号为{0}的 WindFinder 地点:{1}
windFinderWeatherData=天气数据
@@ -2055,6 +2059,9 @@ multiVideoIdle=工作队列空闲
multiVideoDoNoAdd=请勿添加
multiVideoOffsetInput=全球视频偏移量(毫秒):
multiVideoDescription=需要 Web 服务器提供索引清单(如果已编入索引,则支持的子文件夹),以允许发现文件。初始分析 mp4 文件中包含的元数据后,需要通过左侧的复选框列选择应添加的视频。“添加音频/视频”按钮将为所有选择的文件创建媒体轨道,并将这些文件添加到右列中选择的所有比赛轮次中。
+jibeAngle=顺风转向角度
+tackAngle=迎风转向角度
+maneuverAngle=操作角度
multiUrlChangeMediaTrack=调整多个媒体轨道 URL
multiUrlChangeReplace=替换为
multiUrlChangeFind=查找
@@ -2063,5 +2070,16 @@ multiUrlChangeSave=保存 URL 更改
multiUrlChangeNewURL=新 URL
multiUrlNoPrefixWarning=未找到通用前缀,这通常意味着并非所有选定的视频都被托管在当前的相同位置。如继续操作,后果自负!
multiUrlChangeExplain=此对话框将在媒体轨道 URL 的起始处批量替换通用部分。确保所有 URL 都以相同的前缀开头!也请注意新的 URL 列,然后在保存之前测试生成的 URL!
+resetZoom=重置缩放
lastEvent=上次活动:{0}
teaserOverallLinkToolTip=请查看整体系列赛,请点击黄色角落
+middleManeuverAngle=中间操作角度
+extrapolatedManeuverStartPosition=推断的操作开始位置
+projectedExtrapolatedManeuverStartPosition=推断的操作开始位置在中间操作角度线上的投影
+projectedManeuverEndPosition=操作结束位置在中间操作角度线上的投影
+bearingAtManeuverEndPosition=操作结束位置的航向角
+gender=性别
+manage2SailEventIdBox=Manage2Sail 活动编号
+manage2SailEventURLBox=Manage2Sail 活动 URL (json)
+manage2SailEventIdBoxTooltip=包含 Manage2Sail 中活动编号的活动编号或 URL
+manage2SailPort=左舷
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/JSDownloadUtils.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/JSDownloadUtils.java
index 018fdabde91..d11168ed3d4 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/JSDownloadUtils.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/JSDownloadUtils.java
@@ -10,6 +10,7 @@ import com.google.gwt.typedarrays.shared.Int8Array;
*/
public class JSDownloadUtils {
private static final Double REQUIRED_SIZE = 10000000.0;
+ protected static final Double MAX_MEMORY_USAGE_FOR_DL = 1024 * 1024 * 1024 * 2d;
public interface JSDownloadCallback {
void progress(Double current, Double total);
@@ -43,7 +44,7 @@ public class JSDownloadUtils {
getDataFast(url, callback, total, REQUIRED_SIZE);
} else {
//fallback will always work, if cors is supported, does not require any other server configuration
- getDataSlow(url, callback, REQUIRED_SIZE);
+ getDataSlow(url, callback, REQUIRED_SIZE, MAX_MEMORY_USAGE_FOR_DL);
}
}
});
@@ -53,75 +54,77 @@ public class JSDownloadUtils {
* Fast file download method based on range requests, only the first and the last REQUIRED_SIZE is loaded.
*/
private native static void getDataFast(String url, JSDownloadCallback callback, Double length, Double REQUIRED_SIZE) /*-{
- try {
- var xhr = new XMLHttpRequest();
- xhr.open("GET", url, true);
- xhr.setRequestHeader("Range", "bytes=0-" + REQUIRED_SIZE);
- xhr.responseType = "arraybuffer";
- xhr.onprogress = function(evt) {
- callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::progress(Ljava/lang/Double;Ljava/lang/Double;)(evt.loaded, evt.total);
- }
- xhr.error = function(error) {
- callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::error(Ljava/lang/Object;)(error);
- }
-
- xhr.onreadystatechange = function() {
- var state = xhr.readyState;
- if (state == 4) {
- if (xhr.response) {
- var startLength = xhr.response.byteLength;
- var start = new Int8Array(xhr.response);
+ try {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", url, true);
+ xhr.setRequestHeader("Range", "bytes=0-" + REQUIRED_SIZE);
+ xhr.responseType = "arraybuffer";
+ xhr.onprogress = function(evt) {
+ callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::progress(Ljava/lang/Double;Ljava/lang/Double;)(evt.loaded, evt.total);
+ }
+ xhr.error = function(error) {
+ callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::error(Ljava/lang/Object;)(error);
+ }
- try {
- var xhr2 = new XMLHttpRequest();
- xhr2.open("GET", url, true);
- xhr2.setRequestHeader("Range", "bytes=" + (length - REQUIRED_SIZE));
- xhr2.responseType = "arraybuffer";
- xhr2.onprogress = function(evt) {
- callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::progress(Ljava/lang/Double;Ljava/lang/Double;)(evt.loaded, evt.total);
- }
- xhr2.error = function(error) {
+ xhr.onreadystatechange = function() {
+ var state = xhr.readyState;
+ if (state == 4) {
+ if (xhr.response) {
+ var startLength = xhr.response.byteLength;
+ var start = new Int8Array(xhr.response);
+
+ try {
+ var xhr2 = new XMLHttpRequest();
+ xhr2.open("GET", url, true);
+ xhr2.setRequestHeader("Range", "bytes="
+ + (length - REQUIRED_SIZE) + "-");
+ xhr2.responseType = "arraybuffer";
+ xhr2.onprogress = function(evt) {
+ callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::progress(Ljava/lang/Double;Ljava/lang/Double;)(evt.loaded, evt.total);
+ }
+ xhr2.error = function(error) {
+ callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::error(Ljava/lang/Object;)(error);
+ }
+
+ xhr2.onreadystatechange = function() {
+ var state = xhr2.readyState;
+ if (state == 4) {
+ if (xhr2.response) {
+ var endLength = xhr2.response.byteLength;
+ var end = new Int8Array(xhr2.response);
+ var sparse = length - startLength
+ - endLength;
+ callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::complete(Lcom/google/gwt/typedarrays/shared/Int8Array;Lcom/google/gwt/typedarrays/shared/Int8Array;Ljava/lang/Double;)(start, end, sparse);
+ }
+ }
+ };
+ xhr2.send();
+ } catch (error) {
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::error(Ljava/lang/Object;)(error);
}
-
- xhr2.onreadystatechange = function() {
- var state = xhr2.readyState;
- if (state == 4) {
- if (xhr2.response) {
- var endLength = xhr2.response.byteLength;
- var end = new Int8Array(xhr2.response);
- var sparse = length - startLength - endLength;
- callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::complete(Lcom/google/gwt/typedarrays/shared/Int8Array;Lcom/google/gwt/typedarrays/shared/Int8Array;Ljava/lang/Double;)(start, end, sparse);
- }
- }
- };
- xhr2.send();
- } catch (error) {
- callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::error(Ljava/lang/Object;)(error);
}
}
- }
- };
- xhr.send();
- } catch (error) {
- callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::error(Ljava/lang/Object;)(error);
- }
-}-*/;
+ };
+ xhr.send();
+ } catch (error) {
+ callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::error(Ljava/lang/Object;)(error);
+ }
+ }-*/;
/**
* Determines if a server can deliver a file with range requests, and if so returns the size of the file
*/
private native static void getFileSizeIfFastPath(String url, JSSizeCallback callback) /*-{
- try {
+ try {
var xhr = new XMLHttpRequest();
xhr.open("HEAD", url, true);
xhr.responseType = "arraybuffer";
xhr.error = function(error) {
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSSizeCallback::size(Ljava/lang/Double;)(-1.0);
}
-
+
xhr.onreadystatechange = function() {
- var state = xhr.readyState;
+ var state = xhr.readyState;
if (state == 4) {
if (xhr.response) {
var length = xhr.getResponseHeader("Content-Length");
@@ -141,29 +144,36 @@ public class JSDownloadUtils {
/**
* If range requests are not possible, the whole file is downloaded and then slices to the required parts
*/
- private native static void getDataSlow(String url, JSDownloadCallback callback, Double REQUIRED_SIZE) /*-{
+ private native static void getDataSlow(String url, JSDownloadCallback callback, Double REQUIRED_SIZE,
+ Double maxMemoryUsage) /*-{
try {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "arraybuffer";
xhr.onprogress = function(evt) {
+ //ensure not more memory is used by the tab than commonly available in browsers
+ if (evt.total > maxMemoryUsage || evt.loaded > maxMemoryUsage) {
+ xhr.abort();
+ }
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::progress(Ljava/lang/Double;Ljava/lang/Double;)(evt.loaded, evt.total);
}
xhr.error = function(error) {
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::error(Ljava/lang/Object;)(error);
}
-
+
xhr.onreadystatechange = function() {
- var state = xhr.readyState;
+ var state = xhr.readyState;
if (state == 4) {
if (xhr.response) {
var length = xhr.response.byteLength;
- var start = new Int8Array(xhr.response.slice(0, REQUIRED_SIZE));
- var end = new Int8Array(xhr.response.slice(length - REQUIRED_SIZE));
+ var start = new Int8Array(xhr.response.slice(0,
+ REQUIRED_SIZE));
+ var end = new Int8Array(xhr.response.slice(length
+ - REQUIRED_SIZE));
var sparse = length - 2 * REQUIRED_SIZE;
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::complete(Lcom/google/gwt/typedarrays/shared/Int8Array;Lcom/google/gwt/typedarrays/shared/Int8Array;Ljava/lang/Double;)(start, end, sparse);
} else {
- callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::error(Ljava/lang/Object;)("No result");
+ callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback::error(Ljava/lang/Object;)("No result");
}
}
};
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java
index ef40c4c0988..3bb2d03855b 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java
@@ -18,7 +18,6 @@ import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.media.client.Audio;
import com.google.gwt.media.client.MediaBase;
import com.google.gwt.typedarrays.shared.Int8Array;
-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.FlowPanel;
@@ -41,6 +40,8 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.MimeType;
+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.controls.datetime.DateAndTimeInput;
import com.sap.sse.gwt.client.controls.datetime.DateTimeInput.Accuracy;
@@ -400,7 +401,7 @@ public class NewMediaDialog extends DataEntryDialog {
protected void mp4MetadataResult(VideoMetadataDTO result) {
if (!result.isDownloadable()) {
- Window.alert(stringMessages.couldNotDownload(mediaTrack.url));
+ Notification.notify(stringMessages.couldNotDownload(mediaTrack.url), NotificationType.ERROR);
manualMimeTypeSelection(result.getMessage(), mediaTrack);
} else {
mediaTrack.duration = result.getDuration();
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPassingsPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPassingsPanel.java
index bf5be5ca401..f0994abb40a 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPassingsPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/EditMarkPassingsPanel.java
@@ -11,11 +11,11 @@ import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
@@ -43,6 +43,8 @@ import com.sap.sse.common.filter.Filter;
import com.sap.sse.common.filter.FilterSet;
import com.sap.sse.common.settings.AbstractSettings;
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.celltable.BaseCelltable;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.shared.components.AbstractCompositeComponent;
@@ -133,7 +135,7 @@ public class EditMarkPassingsPanel extends AbstractCompositeComponent, SafeHtml>(new AnchorCell()) {
@Override
public SafeHtml getValue(final Pair object) {
@@ -216,7 +218,7 @@ public class EditMarkPassingsPanel extends AbstractCompositeComponent i
private final RaceIdentifierToLeaderboardRaceColumnAndFleetMapper raceIdentifierToLeaderboardRaceColumnAndFleetMapper;
protected boolean nonTrackingWarningWasDisplayed;
+ private final Set marksCurrentlyRequestedViaRemoteCall = new HashSet<>();
+
public EditMarkPositionPanel(Component> parent, ComponentContext> context, final RaceMap raceMap,
final SingleRaceLeaderboardPanel leaderboardPanel,
RegattaAndRaceIdentifier selectedRaceIdentifier, String leaderboardName, final StringMessages stringMessages,
@@ -735,10 +739,7 @@ public class EditMarkPositionPanel extends AbstractRaceChart i
}
raceMap.unregisterAllCourseMarkInfoWindowClickHandlers();
} else {
- if (currentFixPositionChooser != null) {
- currentFixPositionChooser.cancel();
- currentFixPositionChooser = null;
- }
+ cancelFixPositionChooserAndNotification();
marksPanel.deselectMark();
selectedMark = null;
if (sideBySideComponentViewer != null) {
@@ -754,6 +755,17 @@ public class EditMarkPositionPanel extends AbstractRaceChart i
super.setVisible(visible);
}
+ private void cancelFixPositionChooserAndNotification() {
+ if (currentFixPositionChooser != null) {
+ currentFixPositionChooser.cancel();
+ currentFixPositionChooser = null;
+ if (notificationTimer.isRunning()) {
+ notificationTimer.run();
+ notificationTimer.cancel();
+ }
+ }
+ }
+
private void checkIfTracking(Runnable continuation) {
if (nonTrackingWarningWasDisplayed) {
continuation.run();
@@ -761,14 +773,14 @@ public class EditMarkPositionPanel extends AbstractRaceChart i
sailingService.checkIfRaceIsTracking(selectedRaceIdentifier, new AsyncCallback() {
@Override
public void onFailure(Throwable caught) {
- Window.alert(stringMessages.serverError());
+ Notification.notify(stringMessages.serverError(), Notification.NotificationType.ERROR);
continuation.run();
}
@Override
public void onSuccess(Boolean result) {
if (Boolean.FALSE.equals(result)) {
- Window.alert(stringMessages.positionEditOnNonTrackingRace());
+ Notification.notify(stringMessages.positionEditOnNonTrackingRace(), Notification.NotificationType.WARNING);
nonTrackingWarningWasDisplayed = true;
}
continuation.run();
@@ -859,11 +871,10 @@ public class EditMarkPositionPanel extends AbstractRaceChart i
}
private void selectMark(MarkDTO mark) {
- selectedMark = mark;
- if (currentFixPositionChooser != null) {
- currentFixPositionChooser.cancel();
- currentFixPositionChooser = null;
+ if (selectedMark != mark) {
+ cancelFixPositionChooserAndNotification();
}
+ selectedMark = mark;
if (selectedMark != null) {
if (marksFromToTimes.get(selectedMark) != null) {
// For some reason the time slider does not change with this method only if you comment out line 430 and 432 in TimePanel it works
@@ -905,24 +916,43 @@ public class EditMarkPositionPanel extends AbstractRaceChart i
@Override
public void onSelectionChange(SelectionChangeEvent event) {
final MarkDTO mark = marksPanel.getSelectedMark();
+ retrieveAndSelectMarkIfNecessary(mark, null);
+ }
+
+ protected void retrieveAndSelectMarkIfNecessary(final MarkDTO mark, final Runnable callback) {
if (mark != null && (marks.get(mark) == null || marks.get(mark).isEmpty())) {
- if (mark != null) {
- markPositionService.getMarkTrack(raceIdentifierToLeaderboardRaceColumnAndFleetMapper.getLeaderboardNameAndRaceColumnNameAndFleetName(selectedRaceIdentifier),
+
+ if (marksCurrentlyRequestedViaRemoteCall.add(mark)) {
+ markPositionService.getMarkTrack(
+ raceIdentifierToLeaderboardRaceColumnAndFleetMapper
+ .getLeaderboardNameAndRaceColumnNameAndFleetName(selectedRaceIdentifier),
mark.getIdAsString(), new AsyncCallback() {
@Override
public void onFailure(Throwable caught) {
- errorReporter.reportError(stringMessages.errorCommunicatingWithServer()+": "+caught.getMessage());
+ marksCurrentlyRequestedViaRemoteCall.remove(mark);
+ errorReporter.reportError(
+ stringMessages.errorCommunicatingWithServer() + ": " + caught.getMessage());
}
-
+
@Override
public void onSuccess(MarkTrackDTO result) {
+ marksCurrentlyRequestedViaRemoteCall.remove(mark);
createMarkTrackUi(mark, result.getFixes());
selectMark(mark);
+ if (callback != null) {
+ callback.run();
+ }
}
});
}
+ else {
+ // remote call of the same mark already in progress -> ignore this request
+ }
} else {
selectMark(mark);
+ if (callback != null) {
+ callback.run();
+ }
}
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MarksPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MarksPanel.java
index cae1ca24db7..219e12485f8 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MarksPanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/charts/MarksPanel.java
@@ -85,22 +85,27 @@ public class MarksPanel extends AbstractCompositeComponent {
@Override
public void update(int index, final MarkDTO mark, String value) {
final Date timePoint = parent.timer.getTime();
- select(mark);
- if (parent.hasFixAtTimePoint(mark, timePoint)) {
- parent.showNotification(stringMessages.pleaseSelectOtherTimepoint(), NotificationType.ERROR);
- } else {
- parent.createFixPositionChooserToAddFixToMark(mark, new Callback() {
- @Override
- public void onFailure(Exception reason) {
- parent.resetCurrentFixPositionChooser();
+ parent.retrieveAndSelectMarkIfNecessary(mark, new Runnable() {
+
+ @Override
+ public void run() {
+ if (parent.hasFixAtTimePoint(mark, timePoint)) {
+ parent.showNotification(stringMessages.pleaseSelectOtherTimepoint(), NotificationType.ERROR);
+ } else {
+ parent.createFixPositionChooserToAddFixToMark(mark, new Callback() {
+ @Override
+ public void onFailure(final Exception reason) {
+ parent.resetCurrentFixPositionChooser();
+ }
+ @Override
+ public void onSuccess(Position result) {
+ parent.addMarkFix(mark, timePoint, result);
+ parent.resetCurrentFixPositionChooser();
+ }
+ });
}
- @Override
- public void onSuccess(Position result) {
- parent.addMarkFix(mark, timePoint, result);
- parent.resetCurrentFixPositionChooser();
- }
- });
- }
+ }
+ });
}
});
markTable.addColumn(addFixColumn);
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java
index 814aac67e3f..5e7d29b4d3e 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java
@@ -622,116 +622,123 @@ public class RaceMap extends AbstractCompositeComponent impleme
loadLibraries.add(LoadLibrary.GEOMETRY);
Runnable onLoad = new Runnable() {
- @Override
- public void run() {
- MapOptions mapOptions = getMapOptions(showMapControls, /* wind up */ false);
- map = new MapWidget(mapOptions);
- rootPanel.add(map, 0, 0);
- if (showHeaderPanel) {
- Image sapLogo = createSAPLogo();
- rootPanel.add(sapLogo);
- }
-
- map.setControls(ControlPosition.LEFT_TOP, topLeftControlsWrapperPanel);
- adjustLeftControlsIndent();
+ @Override
+ public void run() {
+ MapOptions mapOptions = getMapOptions(showMapControls, /* wind up */ false);
+ map = new MapWidget(mapOptions);
+ rootPanel.add(map, 0, 0);
+ if (showHeaderPanel) {
+ Image sapLogo = createSAPLogo();
+ rootPanel.add(sapLogo);
+ }
- RaceMap.this.raceMapImageManager.loadMapIcons(map);
- map.setSize("100%", "100%");
- map.addZoomChangeHandler(new ZoomChangeMapHandler() {
- @Override
- public void onEvent(ZoomChangeMapEvent event) {
- if (!autoZoomIn && !autoZoomOut && !orientationChangeInProgress) {
- // stop automatic zoom after a manual zoom event; automatic zoom in zoomMapToNewBounds will restore old settings
- final List emptyList = Collections.emptyList();
- RaceMapZoomSettings clearedZoomSettings = new RaceMapZoomSettings(emptyList, settings.getZoomSettings().isZoomToSelectedCompetitors());
- settings = new RaceMapSettings(settings, clearedZoomSettings);
- }
- // TODO bug489 when in wind-up mode, avoid zooming out too far; perhaps zoom back in if zoomed out too far
- }
- });
- map.addDragEndHandler(new DragEndMapHandler() {
- @Override
- public void onEvent(DragEndMapEvent event) {
- // stop automatic zoom after a manual drag event
- autoZoomIn = false;
- autoZoomOut = false;
- final List emptyList = Collections.emptyList();
- RaceMapZoomSettings clearedZoomSettings = new RaceMapZoomSettings(emptyList, settings.getZoomSettings().isZoomToSelectedCompetitors());
- settings = new RaceMapSettings(settings, clearedZoomSettings);
- }
- });
- map.addIdleHandler(new IdleMapHandler() {
- @Override
- public void onEvent(IdleMapEvent event) {
- // the "idle"-event is raised at the end of map-animations
- if (autoZoomIn) {
- // finalize zoom-in that was started with panTo() in zoomMapToNewBounds()
- map.setZoom(autoZoomLevel);
- autoZoomIn = false;
- }
- if (autoZoomOut) {
- // finalize zoom-out that was started with setZoom() in zoomMapToNewBounds()
- map.panTo(autoZoomLatLngBounds.getCenter());
- autoZoomOut = false;
- }
- }
- });
- map.addBoundsChangeHandler(new BoundsChangeMapHandler() {
- @Override
- public void onEvent(BoundsChangeMapEvent event) {
- int newZoomLevel = map.getZoom();
- if (!isAutoZoomInProgress() && (newZoomLevel != currentZoomLevel)) {
- removeTransitions();
- }
- if ((streamletOverlay != null) && !map.getBounds().equals(currentMapBounds)) {
- streamletOverlay.onBoundsChanged(newZoomLevel != currentZoomLevel);
- }
- if ((simulationOverlay != null) && !map.getBounds().equals(currentMapBounds)) {
- simulationOverlay.onBoundsChanged(newZoomLevel != currentZoomLevel);
- }
- currentMapBounds = map.getBounds();
- currentZoomLevel = newZoomLevel;
- headerPanel.getElement().getStyle().setWidth(map.getOffsetWidth(), Unit.PX);
- }
- });
-
- // If there was a time change before the API was loaded, reset the time
- if (lastTimeChangeBeforeInitialization != null) {
- timeChanged(lastTimeChangeBeforeInitialization, null);
- lastTimeChangeBeforeInitialization = null;
- }
- // Initialize streamlet canvas for wind visualization; it shouldn't be doing anything unless it's visible
- streamletOverlay = new WindStreamletsRaceboardOverlay(getMap(), /* zIndex */ 0,
- timer, raceIdentifier, sailingService, asyncActionsExecutor, stringMessages, coordinateSystem);
- streamletOverlay.addToMap();
- if (settings.isShowWindStreamletOverlay()) {
- streamletOverlay.setColors(settings.isShowWindStreamletColors());
- streamletOverlay.setVisible(true);
- }
+ map.setControls(ControlPosition.LEFT_TOP, topLeftControlsWrapperPanel);
+ adjustLeftControlsIndent();
- if (isSimulationEnabled) {
- // determine availability of polar diagram
- setHasPolar();
- // initialize simulation canvas
- simulationOverlay = new RaceSimulationOverlay(getMap(), /* zIndex */ 0, raceIdentifier, sailingService, stringMessages, asyncActionsExecutor, coordinateSystem);
- simulationOverlay.addToMap();
- showSimulationOverlay(settings.isShowSimulationOverlay());
- }
- if (showHeaderPanel) {
- createHeaderPanel(map);
- }
- if (showMapControls) {
- createSettingsButton(map);
- }
- // Data has been initialized
- RaceMap.this.isMapInitialized = true;
- RaceMap.this.redraw();
- trueNorthIndicatorPanel.redraw();
- showAdditionalControls(map);
- RaceMap.this.managedInfoWindow = new ManagedInfoWindow(map);
- }
+ RaceMap.this.raceMapImageManager.loadMapIcons(map);
+ map.setSize("100%", "100%");
+ map.addZoomChangeHandler(new ZoomChangeMapHandler() {
+ @Override
+ public void onEvent(ZoomChangeMapEvent event) {
+ if (!autoZoomIn && !autoZoomOut && !orientationChangeInProgress) {
+ // stop automatic zoom after a manual zoom event; automatic zoom in zoomMapToNewBounds will
+ // restore old settings
+ final List emptyList = Collections.emptyList();
+ RaceMapZoomSettings clearedZoomSettings = new RaceMapZoomSettings(emptyList,
+ settings.getZoomSettings().isZoomToSelectedCompetitors());
+ settings = new RaceMapSettings(settings, clearedZoomSettings);
+ }
+ // TODO bug489 when in wind-up mode, avoid zooming out too far; perhaps zoom back in if zoomed
+ // out too far
+ }
+ });
+ map.addDragEndHandler(new DragEndMapHandler() {
+ @Override
+ public void onEvent(DragEndMapEvent event) {
+ // stop automatic zoom after a manual drag event
+ autoZoomIn = false;
+ autoZoomOut = false;
+ final List emptyList = Collections.emptyList();
+ RaceMapZoomSettings clearedZoomSettings = new RaceMapZoomSettings(emptyList,
+ settings.getZoomSettings().isZoomToSelectedCompetitors());
+ settings = new RaceMapSettings(settings, clearedZoomSettings);
+ }
+ });
+ map.addIdleHandler(new IdleMapHandler() {
+ @Override
+ public void onEvent(IdleMapEvent event) {
+ // the "idle"-event is raised at the end of map-animations
+ if (autoZoomIn) {
+ // finalize zoom-in that was started with panTo() in zoomMapToNewBounds()
+ map.setZoom(autoZoomLevel);
+ autoZoomIn = false;
+ }
+ if (autoZoomOut) {
+ // finalize zoom-out that was started with setZoom() in zoomMapToNewBounds()
+ map.panTo(autoZoomLatLngBounds.getCenter());
+ autoZoomOut = false;
+ }
+ redraw();
+ }
+ });
+ map.addBoundsChangeHandler(new BoundsChangeMapHandler() {
+ @Override
+ public void onEvent(BoundsChangeMapEvent event) {
+ int newZoomLevel = map.getZoom();
+ if (!isAutoZoomInProgress() && (newZoomLevel != currentZoomLevel)) {
+ removeTransitions();
+ }
+ if ((streamletOverlay != null) && !map.getBounds().equals(currentMapBounds)) {
+ streamletOverlay.onBoundsChanged(newZoomLevel != currentZoomLevel);
+ }
+ if ((simulationOverlay != null) && !map.getBounds().equals(currentMapBounds)) {
+ simulationOverlay.onBoundsChanged(newZoomLevel != currentZoomLevel);
+ }
+ currentMapBounds = map.getBounds();
+ currentZoomLevel = newZoomLevel;
+ headerPanel.getElement().getStyle().setWidth(map.getOffsetWidth(), Unit.PX);
+ }
+ });
+
+ // If there was a time change before the API was loaded, reset the time
+ if (lastTimeChangeBeforeInitialization != null) {
+ timeChanged(lastTimeChangeBeforeInitialization, null);
+ lastTimeChangeBeforeInitialization = null;
+ }
+ // Initialize streamlet canvas for wind visualization; it shouldn't be doing anything unless it's
+ // visible
+ streamletOverlay = new WindStreamletsRaceboardOverlay(getMap(), /* zIndex */ 0, timer, raceIdentifier,
+ sailingService, asyncActionsExecutor, stringMessages, coordinateSystem);
+ streamletOverlay.addToMap();
+ if (settings.isShowWindStreamletOverlay()) {
+ streamletOverlay.setColors(settings.isShowWindStreamletColors());
+ streamletOverlay.setVisible(true);
+ }
+
+ if (isSimulationEnabled) {
+ // determine availability of polar diagram
+ setHasPolar();
+ // initialize simulation canvas
+ simulationOverlay = new RaceSimulationOverlay(getMap(), /* zIndex */ 0, raceIdentifier,
+ sailingService, stringMessages, asyncActionsExecutor, coordinateSystem);
+ simulationOverlay.addToMap();
+ showSimulationOverlay(settings.isShowSimulationOverlay());
+ }
+ if (showHeaderPanel) {
+ createHeaderPanel(map);
+ }
+ if (showMapControls) {
+ createSettingsButton(map);
+ }
+ // Data has been initialized
+ RaceMap.this.isMapInitialized = true;
+ RaceMap.this.redraw();
+ trueNorthIndicatorPanel.redraw();
+ showAdditionalControls(map);
+ RaceMap.this.managedInfoWindow = new ManagedInfoWindow(map);
+ }
};
- LoadApi.go(onLoad, loadLibraries, sensor, GoogleMapAPIKey.V3_PARAMS);
+ LoadApi.go(onLoad, loadLibraries, sensor, GoogleMapAPIKey.V3_PARAMS);
}
/**
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/maneuver/ManeuverTableData.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/maneuver/ManeuverTableData.java
index 564f80b57c9..b4506e6d70a 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/maneuver/ManeuverTableData.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/maneuver/ManeuverTableData.java
@@ -12,6 +12,7 @@ import com.sap.sailing.gwt.ui.shared.ManeuverDTO;
class ManeuverTableData {
private final String competitorName;
+ private final String competitorColor;
private final Date timePoint;
private final Date timePointBefore;
private final ManeuverType maneuverType;
@@ -24,8 +25,9 @@ class ManeuverTableData {
private final double directionChange;
private final boolean markPassing;
- ManeuverTableData(final CompetitorDTO competitor, final ManeuverDTO maneuver) {
+ ManeuverTableData(final CompetitorDTO competitor, final String competitorColor, final ManeuverDTO maneuver) {
this.competitorName = competitor.getName();
+ this.competitorColor = competitorColor;
this.timePoint = maneuver.getTimePoint();
this.timePointBefore = maneuver.getTimePointBefore();
this.maneuverType = maneuver.getType();
@@ -43,6 +45,10 @@ class ManeuverTableData {
return competitorName;
}
+ public String getCompetitorColor() {
+ return competitorColor;
+ }
+
public Date getTimePoint() {
return timePoint;
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/maneuver/ManeuverTablePanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/maneuver/ManeuverTablePanel.java
index 5b588fb674f..dc90b3643be 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/maneuver/ManeuverTablePanel.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/maneuver/ManeuverTablePanel.java
@@ -38,8 +38,8 @@ import com.sap.sailing.domain.common.security.Permission;
import com.sap.sailing.domain.common.security.SailingPermissionsForRoleProvider;
import com.sap.sailing.gwt.ui.actions.GetManeuversForCompetitorsAction;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionChangeListener;
-import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider;
import com.sap.sailing.gwt.ui.client.ManeuverTypeFormatter;
+import com.sap.sailing.gwt.ui.client.RaceCompetitorSelectionProvider;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.controls.AbstractSortableColumnWithMinMax;
@@ -47,6 +47,7 @@ import com.sap.sailing.gwt.ui.client.shared.controls.SortableColumn;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel.LeaderBoardStyle;
import com.sap.sailing.gwt.ui.leaderboard.SortedCellTableWithStylableHeaders;
import com.sap.sailing.gwt.ui.shared.ManeuverDTO;
+import com.sap.sse.common.Color;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.Util;
import com.sap.sse.common.filter.Filter;
@@ -75,7 +76,8 @@ public class ManeuverTablePanel extends AbstractCompositeComponent parent, ComponentContext> context,
final SailingServiceAsync sailingService, final AsyncActionsExecutor asyncActionsExecutor,
final RegattaAndRaceIdentifier raceIdentifier, final StringMessages stringMessages,
- final CompetitorSelectionProvider competitorSelectionModel, final ErrorReporter errorReporter,
+ final RaceCompetitorSelectionProvider competitorSelectionModel, final ErrorReporter errorReporter,
final Timer timer, final ManeuverTableSettings initialSettings,
final TimeRangeWithZoomModel timeRangeWithZoomProvider, final LeaderBoardStyle style,
final UserService userService) {
@@ -106,10 +108,11 @@ public class ManeuverTablePanel extends AbstractCompositeComponent createCompetitorColumn() {
+ private SortableColumn createCompetitorColumn() {
InvertibleComparator comparator = new InvertibleComparatorAdapter() {
@Override
public int compare(ManeuverTableData o1, ManeuverTableData o2) {
return o1.getCompetitorName().compareTo(o2.getCompetitorName());
}
};
- return new SortableColumn(new TextCell(), SortingOrder.ASCENDING) {
+ return new SortableColumn(new AbstractCell() {
+ @Override
+ public void render(Context context, ManeuverTableData data, SafeHtmlBuilder sb) {
+ final String color = data.getCompetitorColor();
+ final String divStyle = color == null ? "border: none;" : "border-bottom: 2px solid " + color + ";";
+ sb.appendHtmlConstant("
");
+ }
+ }, SortingOrder.ASCENDING) {
@Override
public InvertibleComparator getComparator() {
return comparator;
@@ -282,8 +294,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));
}
}
}
@@ -429,15 +442,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 d085f7e05c6..2e450a867cd 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 4ac3bbd8d54..16d309f6e26 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 5369edd52fa..d7298f5ae56 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
@@ -1051,7 +1051,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
final TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
raceInfoDTO.isTracked = trackedRace != null ? true : false;
if (raceLog != null) {
- ReadonlyRaceState state = ReadonlyRaceStateImpl.create(getService(), raceLog);
+ ReadonlyRaceState state = ReadonlyRaceStateImpl.getOrCreate(getService(), raceLog);
TimePoint startTime = state.getStartTime();
if (startTime != null) {
raceInfoDTO.startTime = startTime.asDate();
@@ -1508,7 +1508,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;
}
@@ -1847,7 +1847,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
@@ -1860,10 +1859,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);
@@ -1874,18 +1875,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;
@@ -2079,6 +2079,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
raceTimesInfo.newestTrackingEvent = trackedRace.getTimePointOfNewestEvent() == null ? null : trackedRace.getTimePointOfNewestEvent().asDate();
raceTimesInfo.endOfTracking = trackedRace.getEndOfTracking() == null ? null : trackedRace.getEndOfTracking().asDate();
raceTimesInfo.endOfRace = trackedRace.getEndOfRace() == null ? null : trackedRace.getEndOfRace().asDate();
+ raceTimesInfo.raceFinishedTime = trackedRace.getFinishedTime() == null ? null : trackedRace.getFinishedTime().asDate();
raceTimesInfo.delayToLiveInMs = trackedRace.getDelayToLiveInMillis();
Iterable>> markPassingsTimes = trackedRace.getMarkPassingsTimes();
@@ -2833,7 +2834,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
Iterable configs = swissTimingAdapterPersistence.getSwissTimingConfigurations();
List result = new ArrayList();
for (SwissTimingConfiguration stConfig : configs) {
- result.add(new SwissTimingConfigurationDTO(stConfig.getName(), stConfig.getJsonURL(), stConfig.getHostname(), stConfig.getPort()));
+ result.add(new SwissTimingConfigurationDTO(stConfig.getName(), stConfig.getJsonURL(),
+ stConfig.getHostname(), stConfig.getPort(), stConfig.getUpdateURL(), stConfig.getUpdateUsername(),
+ stConfig.getUpdatePassword()));
}
return result;
}
@@ -2871,9 +2874,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
@Override
- public void storeSwissTimingConfiguration(String configName, String jsonURL, String hostname, Integer port) {
+ public void storeSwissTimingConfiguration(String configName, String jsonURL, String hostname, Integer port, String updateURL, String updateUsername, String updatePassword) {
if (!jsonURL.equalsIgnoreCase("test")) {
- swissTimingAdapterPersistence.storeSwissTimingConfiguration(swissTimingFactory.createSwissTimingConfiguration(configName, jsonURL, hostname, port));
+ swissTimingAdapterPersistence.storeSwissTimingConfiguration(swissTimingFactory.createSwissTimingConfiguration(configName, jsonURL, hostname, port, updateURL, updateUsername, updatePassword));
}
}
@@ -2889,7 +2892,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
@Override
public void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable rrs, String hostname, int port,
- boolean trackWind, final boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm) throws Exception {
+ boolean trackWind, final boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm,
+ String updateURL, String updateUsername, String updatePassword) throws InterruptedException, ParseException, Exception {
logger.info("tracWithSwissTiming for regatta " + regattaToAddTo + " for race records " + rrs
+ " with hostname " + hostname + " and port " + port);
Map cachedRegattaEntriesLists = new HashMap();
@@ -2914,7 +2918,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
getSwissTimingAdapter().addSwissTimingRace(getService(), regattaToAddTo,
rr.raceId, rr.getName(), raceDescription, boatClass, hostname, port, startList,
getRaceLogStore(), getRegattaLogStore(),
- RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, useInternalMarkPassingAlgorithm, trackWind, correctWindByDeclination);
+ RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, useInternalMarkPassingAlgorithm, trackWind,
+ correctWindByDeclination, updateURL, updateUsername, updatePassword);
}
}
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceTimesInfoDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceTimesInfoDTO.java
index 8926b48cdd5..eab41710b60 100644
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceTimesInfoDTO.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceTimesInfoDTO.java
@@ -19,6 +19,7 @@ public class RaceTimesInfoDTO implements IsSerializable {
public Date startOfTracking;
public Date endOfTracking;
public Date endOfRace;
+ public Date raceFinishedTime;
public Date newestTrackingEvent;
/**
@@ -83,6 +84,10 @@ public class RaceTimesInfoDTO implements IsSerializable {
public Date getEndOfRace() {
return endOfRace;
}
+
+ public Date getFinishedTime() {
+ return raceFinishedTime;
+ }
public void setEndOfRace(Date endOfRace) {
this.endOfRace = endOfRace;
@@ -118,7 +123,7 @@ public class RaceTimesInfoDTO implements IsSerializable {
+ ", legInfos=" + legInfos + ", markPassingTimes="
+ markPassingTimes + ", startOfRace=" + startOfRace
+ ", startOfTracking=" + startOfTracking + ", endOfTracking="
- + endOfTracking + ", endOfRace=" + endOfRace
+ + endOfTracking + ", endOfRace=" + endOfRace + ", finishedTime=" + raceFinishedTime
+ ", newestTrackingEvent=" + newestTrackingEvent
+ ", currentServerTime=" + currentServerTime
+ ", delayToLiveInMs=" + delayToLiveInMs + "]";
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SwissTimingConfigurationDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SwissTimingConfigurationDTO.java
index 45ebd1fb69b..5d95cc9e2d3 100755
--- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SwissTimingConfigurationDTO.java
+++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/SwissTimingConfigurationDTO.java
@@ -8,14 +8,33 @@ public class SwissTimingConfigurationDTO implements IsSerializable {
private String hostname;
private Integer port;
+ /**
+ * The URL to use for updates fed back to the SwissTiming server, such as changes of race timings
+ * or course updates.
+ */
+ private String updateURL;
+
+ /**
+ * The username to use as part of the credentials for requests to the {@link #updateURL}.
+ */
+ private String updateUsername;
+
+ /**
+ * The password to use as part of the credentials for requests to the {@link #updateURL}.
+ */
+ private String updatePassword;
+
public SwissTimingConfigurationDTO() {}
- public SwissTimingConfigurationDTO(String name, String jsonURL, String hostname, Integer port) {
+ public SwissTimingConfigurationDTO(String name, String jsonURL, String hostname, Integer port, String updateURL, String updateUsername, String updatePassword) {
super();
this.name = name;
this.jsonURL = jsonURL;
this.hostname = hostname;
this.port = port;
+ this.updateURL = updateURL;
+ this.updateUsername = updateUsername;
+ this.updatePassword = updatePassword;
}
public String getName() {
@@ -33,5 +52,16 @@ public class SwissTimingConfigurationDTO implements IsSerializable {
public Integer getPort() {
return port;
}
-
+
+ public String getUpdateURL() {
+ return updateURL;
+ }
+
+ public String getUpdateUsername() {
+ return updateUsername;
+ }
+
+ public String getUpdatePassword() {
+ return updatePassword;
+ }
}
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.mongodb.test/src/com/sap/sailing/mongodb/test/SwissTimingConnectivityParamsLoadAndStoreTest.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/SwissTimingConnectivityParamsLoadAndStoreTest.java
index 9200abde2d4..bb521d61c82 100644
--- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/SwissTimingConnectivityParamsLoadAndStoreTest.java
+++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/SwissTimingConnectivityParamsLoadAndStoreTest.java
@@ -53,7 +53,8 @@ public class SwissTimingConnectivityParamsLoadAndStoreTest extends AbstractConne
final SwissTimingTrackingConnectivityParameters stParams = new SwissTimingTrackingConnectivityParameters(
hostname, port, raceID, raceName, raceDescription, boatClass, startList, delayToLiveInMillis,
SwissTimingFactory.INSTANCE, new SwissTimingAdapterFactoryImpl().getOrCreateSwissTimingAdapter(domainObjectFactory.getBaseDomainFactory()).getSwissTimingDomainFactory(),
- /* raceLogStore */ null, /* regattaLogStore */ null, useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination);
+ /* raceLogStore */ null, /* regattaLogStore */ null, useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination,
+ /* updateURL */ null, /* updateUsername */ null, /* updatePassword */ null);
// store
mongoObjectFactory.addConnectivityParametersForRaceToRestore(stParams);
// load
@@ -103,7 +104,8 @@ public class SwissTimingConnectivityParamsLoadAndStoreTest extends AbstractConne
final SwissTimingTrackingConnectivityParameters stParams = new SwissTimingTrackingConnectivityParameters(
hostname, port, raceID, raceName, raceDescription, boatClass, startList, delayToLiveInMillis,
SwissTimingFactory.INSTANCE, new SwissTimingAdapterFactoryImpl().getOrCreateSwissTimingAdapter(domainObjectFactory.getBaseDomainFactory()).getSwissTimingDomainFactory(),
- /* raceLogStore */ null, /* regattaLogStore */ null, useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination);
+ /* raceLogStore */ null, /* regattaLogStore */ null, useInternalMarkPassingAlgorithm, trackWind, correctWindDirectionByMagneticDeclination,
+ /* updateURL */ null, /* updateUsername */ null, /* updatePassword */ null);
// store
mongoObjectFactory.addConnectivityParametersForRaceToRestore(stParams);
// load
diff --git a/java/com.sap.sailing.polars.datamining.shared/.project b/java/com.sap.sailing.polars.datamining.shared/.project
index b6b59d79740..6dc505ab246 100644
--- a/java/com.sap.sailing.polars.datamining.shared/.project
+++ b/java/com.sap.sailing.polars.datamining.shared/.project
@@ -21,12 +21,12 @@
- com.google.gdt.eclipse.core.webAppProjectValidator
+ com.gwtplugins.gdt.eclipse.core.webAppProjectValidator
- com.google.gwt.eclipse.core.gwtProjectValidator
+ com.gwtplugins.gwt.eclipse.core.gwtProjectValidator
@@ -34,6 +34,6 @@
org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
- com.google.gwt.eclipse.core.gwtNature
+ com.gwtplugins.gwt.eclipse.core.gwtNature
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/.classpath b/java/com.sap.sailing.selenium.test/.classpath
index 39faae28fbe..1bbc2f48e83 100644
--- a/java/com.sap.sailing.selenium.test/.classpath
+++ b/java/com.sap.sailing.selenium.test/.classpath
@@ -5,6 +5,5 @@
-
diff --git a/java/com.sap.sailing.selenium.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.selenium.test/META-INF/MANIFEST.MF
index ede5abfad5a..b76bf165bcc 100644
--- a/java/com.sap.sailing.selenium.test/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.selenium.test/META-INF/MANIFEST.MF
@@ -7,7 +7,7 @@ Bundle-Vendor: SAP
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.hamcrest;bundle-version="1.1.0",
org.junit;bundle-version="4.8.2",
- org.openqa.selenium.osgi;bundle-version="2.40.0",
+ org.openqa.selenium.osgi;bundle-version="3.13.0",
com.sap.sse.mongodb;bundle-version="1.0.0",
org.mongodb.mongo-java-driver;bundle-version="2.13.0",
com.sap.sailing.domain.common,
diff --git a/java/com.sap.sailing.selenium.test/ci-test-environment.xml b/java/com.sap.sailing.selenium.test/ci-test-environment.xml
index 52c20fe0142..6830888dae7 100644
--- a/java/com.sap.sailing.selenium.test/ci-test-environment.xml
+++ b/java/com.sap.sailing.selenium.test/ci-test-environment.xml
@@ -44,12 +44,43 @@
webdriver.enable.native.events true
-
+
+
+
+
+
+
+ -->
+
+ -->
+
+
+
+
+
+
diff --git a/java/com.sap.sailing.selenium.test/com.sap.sailing.selenium.test (No Proxy, GWT Codesvr).launch b/java/com.sap.sailing.selenium.test/com.sap.sailing.selenium.test (No Proxy, GWT Codesvr).launch
index aa09fadd838..b823c8ba200 100644
--- a/java/com.sap.sailing.selenium.test/com.sap.sailing.selenium.test (No Proxy, GWT Codesvr).launch
+++ b/java/com.sap.sailing.selenium.test/com.sap.sailing.selenium.test (No Proxy, GWT Codesvr).launch
@@ -14,13 +14,7 @@
-
-
-
-
-
-
-
+
diff --git a/java/com.sap.sailing.selenium.test/com.sap.sailing.selenium.test (Proxy, GWT Codesvr).launch b/java/com.sap.sailing.selenium.test/com.sap.sailing.selenium.test (Proxy, GWT Codesvr).launch
index 93b80d065c2..64f44cf3a8e 100644
--- a/java/com.sap.sailing.selenium.test/com.sap.sailing.selenium.test (Proxy, GWT Codesvr).launch
+++ b/java/com.sap.sailing.selenium.test/com.sap.sailing.selenium.test (Proxy, GWT Codesvr).launch
@@ -12,5 +12,5 @@
-
+
diff --git a/java/com.sap.sailing.selenium.test/local-test-environment.xml b/java/com.sap.sailing.selenium.test/local-test-environment.xml
old mode 100755
new mode 100644
index a6bc5f0da0a..cedae7bcc1c
--- a/java/com.sap.sailing.selenium.test/local-test-environment.xml
+++ b/java/com.sap.sailing.selenium.test/local-test-environment.xml
@@ -28,22 +28,65 @@
- http://code.google.com/p/selenium/wiki/SafariDriver
- http://code.google.com/p/selenium/wiki/RemoteWebDriverServer
- NOTE: For the Chrome and the InternetExplorer driver an additional "server", which acts as a bridge between the
+ NOTE: For the Chrome, Firefox and InternetExplorer driver an additional "server", which acts as a bridge between the
browser and the driver, is needed.
-->
+
webdriver.chrome.driverC:\apps\ChromeSeleniumDriver\chromedriver.exe
+
+
+ webdriver.gecko.driver
+ /path/to/geckodriver.exe
+
+
+
- c:\Program Files (x86)\Mozilla Firefox 24\firefox.exe
-
-
-
+ /path/to/firefox.exe
+ -->
+
+
@@ -61,4 +104,16 @@
-->
+
+
+
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/ElementSearchCondition.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/ElementSearchCondition.java
index 7012013b1d4..de94d6521bc 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/ElementSearchCondition.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/ElementSearchCondition.java
@@ -1,8 +1,8 @@
package com.sap.sailing.selenium.core;
-import org.openqa.selenium.SearchContext;
+import java.util.function.Function;
-import com.google.common.base.Function;
+import org.openqa.selenium.SearchContext;
/**
*
Models a condition that might reasonably be expected to eventually evaluate to something that is neither
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/HeadlessChromeDriver.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/HeadlessChromeDriver.java
new file mode 100644
index 00000000000..5c916e1fc80
--- /dev/null
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/HeadlessChromeDriver.java
@@ -0,0 +1,26 @@
+package com.sap.sailing.selenium.core;
+
+import org.openqa.selenium.Capabilities;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.chrome.ChromeDriverService;
+import org.openqa.selenium.chrome.ChromeOptions;
+
+/**
+ *Specific {@link ChromeDriver} that is configured to start Chrome in headless mode. In theory, you do not need a
+ * specific subclass of {@link ChromeDriver} but we currently can't apply specific command line options using XML based
+ * configuration using {@link TestEnvironmentConfiguration}. So this is currently just a simple workaround but not a
+ * long-term solution.
+ */
+public class HeadlessChromeDriver extends ChromeDriver {
+
+ public HeadlessChromeDriver(Capabilities capabilities) {
+ super(ChromeDriverService.createDefaultService(), constructChromeOptions(capabilities));
+ }
+
+ private static ChromeOptions constructChromeOptions(Capabilities capabilities) {
+ final ChromeOptions chromeOptions = new ChromeOptions();
+ chromeOptions.merge(capabilities);
+ chromeOptions.addArguments("--headless", "--window-size=1440,900");
+ return chromeOptions;
+ }
+}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/HeadlessFirefoxDriver.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/HeadlessFirefoxDriver.java
new file mode 100644
index 00000000000..0ec19b60ef6
--- /dev/null
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/HeadlessFirefoxDriver.java
@@ -0,0 +1,32 @@
+package com.sap.sailing.selenium.core;
+
+import java.util.Objects;
+
+import org.openqa.selenium.Capabilities;
+import org.openqa.selenium.firefox.FirefoxBinary;
+import org.openqa.selenium.firefox.FirefoxDriver;
+import org.openqa.selenium.firefox.FirefoxOptions;
+
+/**
+ * Specific {@link FirefoxDriver} that is configured to start Firefox in headless mode. In theory, you do not need a
+ * specific subclass of {@link FirefoxDriver} but we currently can't apply specific command line options using XML based
+ * configuration using {@link TestEnvironmentConfiguration}. So this is currently just a simple workaround but not a
+ * long-term solution.
+ */
+public class HeadlessFirefoxDriver extends FirefoxDriver {
+
+ public HeadlessFirefoxDriver(Capabilities desiredCapabilities) {
+ super(constructFirefoxOptions(desiredCapabilities));
+
+ }
+
+ private static FirefoxOptions constructFirefoxOptions(Capabilities desiredCapabilities) {
+ final FirefoxOptions firefoxOptions = new FirefoxOptions(Objects.requireNonNull(desiredCapabilities, "No capabilities seen"));
+ FirefoxBinary firefoxBinary = new FirefoxBinary();
+ // Window size is currently being ignored in headless mode
+ // Documentation says it should work: https://developer.mozilla.org/en-US/Firefox/Headless_mode
+ firefoxBinary.addCommandLineOptions("-headless"/*, "--window-size=1440,900"*/);
+ firefoxOptions.setBinary(firefoxBinary);
+ return firefoxOptions;
+ }
+}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/SeleniumElementLocator.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/SeleniumElementLocator.java
index 2c6a6e28124..df0f01ea71f 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/SeleniumElementLocator.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/SeleniumElementLocator.java
@@ -1,8 +1,9 @@
package com.sap.sailing.selenium.core;
import java.lang.reflect.Field;
+import java.time.Duration;
import java.util.List;
-import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
@@ -11,8 +12,6 @@ import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.pagefactory.ElementLocator;
import org.openqa.selenium.support.ui.FluentWait;
-import com.google.common.base.Function;
-
/**
*
An element locator, which will lazily locate and wait for an element or an element list to appear, by polling the
* UI on a regular basis. It is possible to define the maximum amount of time to wait for the element or the list of
@@ -66,8 +65,8 @@ public class SeleniumElementLocator implements ElementLocator {
this.context = context;
this.wait = new FluentWait<>(this.context);
- this.wait.withTimeout(timeOutSeconds, TimeUnit.SECONDS);
- this.wait.pollingEvery(intervalMillis, TimeUnit.MILLISECONDS);
+ this.wait.withTimeout(Duration.ofSeconds(timeOutSeconds));
+ this.wait.pollingEvery(Duration.ofMillis(intervalMillis));
this.wait.ignoring(NoSuchElementException.class);
Annotations annotations = new Annotations(field);
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/SeleniumFieldDecorator.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/SeleniumFieldDecorator.java
index 2fa72519710..9e0f1c446b6 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/SeleniumFieldDecorator.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/SeleniumFieldDecorator.java
@@ -9,8 +9,7 @@ import java.lang.reflect.Type;
import java.util.List;
import org.openqa.selenium.WebElement;
-
-import org.openqa.selenium.internal.Locatable;
+import org.openqa.selenium.interactions.internal.Locatable;
import org.openqa.selenium.internal.WrapsElement;
import org.openqa.selenium.support.pagefactory.ElementLocator;
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/WindowManager.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/WindowManager.java
index a7edd5ef488..bcc70d59ac2 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/WindowManager.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/WindowManager.java
@@ -1,10 +1,11 @@
package com.sap.sailing.selenium.core;
import java.util.Set;
+import java.util.function.BiConsumer;
+import org.openqa.selenium.Dimension;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebDriver.TargetLocator;
/**
*
@@ -25,20 +26,8 @@ public class WindowManager {
*/
public WindowManager(WebDriver driver) {
this.driver = driver;
- }
-
- /**
- *
- *
- * @param url
- */
- public void switchTo(String url) {
- WebDriverWindow window = findWindow(url);
- if(window == null)
- throw new RuntimeException("Window not found");
-
- window.switchToWindow();
+ setWindowMaximized();
}
/**
@@ -47,60 +36,24 @@ public class WindowManager {
* @return
*
*/
- public WebDriverWindow getCurrentWindow() {
+ private WebDriverWindow getCurrentWindow() {
return new WebDriverWindow(this.driver, this.driver.getWindowHandle());
}
- /**
- *
- *
- *
Note: If no window is found with the specified URL,
- *
- * @param url
- *
- * @return
- *
- */
- public WebDriverWindow findWindow(String url) {
- if(url == null)
- throw new IllegalArgumentException();
-
- TargetLocator locator = this.driver.switchTo();
-
- for(String handle : this.driver.getWindowHandles()) {
- locator.window(handle);
-
- if(url.equals(this.driver.getCurrentUrl()))
- return new WebDriverWindow(this.driver, handle);
- }
-
- return null;
- }
-
/**
*
*
* @return
*/
- public WebDriverWindow openNewWindow() {
+ private WebDriverWindow openNewWindow() {
return openNewWindow(false);
}
- public WebDriverWindow openNewWindow(boolean focus) {
+ private WebDriverWindow openNewWindow(boolean focus) {
return openNewWindow("", focus);
}
- /**
- *
- *
- * @param url
- * @return
- */
- public WebDriverWindow openNewWindow(String url) {
- return openNewWindow(url, false);
- }
-
- public WebDriverWindow openNewWindow(String url, boolean focus) {
+ private WebDriverWindow openNewWindow(String url, boolean focus) {
WebDriverWindow window = new WebDriverWindow(this.driver, createWindow(url));
if(focus) {
@@ -134,4 +87,37 @@ public class WindowManager {
return null;
}
+
+ public void withExtraWindow(BiConsumer defaultAndExtraWindow) {
+ final WebDriverWindow defaultWindow = getCurrentWindow();
+ final WebDriverWindow extraWindow = openNewWindow();
+ extraWindow.switchToWindow();
+ setWindowMaximized();
+ defaultWindow.switchToWindow();
+ try {
+ defaultAndExtraWindow.accept(defaultWindow, extraWindow);
+ } finally {
+ try {
+ extraWindow.close();
+ } catch (Exception e) {
+ // This call may fail depending on the WebDriver being used
+ }
+ defaultWindow.switchToWindow();
+ }
+ }
+
+ private void setWindowMaximized() {
+ try {
+ driver.manage().window().maximize();
+ } catch (Exception e) {
+ // Depending on the combination of OS and WebDriver implementation this may fail
+ // e.g. chrome with xvfb can't do this successfully.
+ try {
+ // Trying to set a proper screen size as fallback that should usable with all modern screens
+ driver.manage().window().setSize(new Dimension(1440, 900));
+ } catch (Exception exc) {
+ // In this case we just can't change the window
+ }
+ }
+ }
}
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..b4c341394c5 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
@@ -3,6 +3,7 @@ package com.sap.sailing.selenium.pages;
import java.net.URI;
import java.net.URISyntaxException;
+import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
/**
@@ -18,9 +19,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 +65,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 {
@@ -80,4 +80,8 @@ public abstract class HostPage extends PageObject {
public String getCurrentUrl() {
return driver.getCurrentUrl();
}
+
+ protected void scrollToTop() {
+ ((JavascriptExecutor) driver).executeScript("window.scrollTo(0, 0);");
+ }
}
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 f5b00515f8e..3809fdd6fcd 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
@@ -1,18 +1,19 @@
package com.sap.sailing.selenium.pages;
import java.text.MessageFormat;
+import java.time.Duration;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.TimeUnit;
import java.util.function.BooleanSupplier;
+import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
-import org.openqa.selenium.NoAlertPresentException;
+import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
@@ -21,8 +22,6 @@ import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.WebDriverWait;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
import com.sap.sailing.selenium.core.AjaxCallsComplete;
import com.sap.sailing.selenium.core.AjaxCallsExecuted;
import com.sap.sailing.selenium.core.BySeleniumId;
@@ -60,7 +59,7 @@ public class PageObject {
public static final int DEFAULT_WAIT_TIMEOUT_SECONDS = 120;
- public static final int DEFAULT_POLLING_INTERVAL = 5;
+ public static final int DEFAULT_POLLING_INTERVAL = 1;
private static final MessageFormat TAB_PANEL_EXPRESSION = new MessageFormat(
".//div[contains(@class, \"gwt-TabBarItem\")]/div[text()=\"{0}\"]/..");
@@ -132,15 +131,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 +167,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(Duration.ofSeconds(timeoutInSeconds));
+ wait.pollingEvery(Duration.ofSeconds(pollingEverySoManySeconds));
wait.ignoreAll(exceptions);
return wait;
@@ -223,7 +222,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 +430,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 +448,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));
}
@@ -484,7 +483,7 @@ public class PageObject {
webDriverWait.until(ExpectedConditions.presenceOfElementLocated(new BySeleniumId(seleniumId)));
}
- protected void waitUntil(Predicate predicate) {
+ protected void waitUntil(Function predicate) {
WebDriverWait webDriverWait = new WebDriverWait(driver, DEFAULT_LOOKUP_TIMEOUT);
webDriverWait.until(predicate);
}
@@ -579,50 +578,85 @@ 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);
+ protected void waitForAlertAndAccept() {
+ 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.
*/
- protected void waitForAlertAndAccept(int timeoutInSeconds) throws InterruptedException {
- int i = 0;
- while (i < timeoutInSeconds) {
- i++;
- try {
- Alert alert = driver.switchTo().alert();
- alert.accept();
- return;
- } catch (NoAlertPresentException e) {
- Thread.sleep(1000);
- }
- }
- throw new NoAlertPresentException();
+ protected void waitForAlertAndAccept(int timeoutInSeconds) {
+ final Alert expectedAlert = new WebDriverWait(driver, timeoutInSeconds).until(ExpectedConditions.alertIsPresent());
+ expectedAlert.accept();
+ }
+
+ /**
+ * Waits for a notification to appear and dismisses the notification by clicking on it. If no notification shows up, an Exception is thrown.
+ */
+ protected void waitForNotificationAndDismiss() {
+ waitForNotificationAndDismiss(DEFAULT_WAIT_TIMEOUT_SECONDS, null);
}
/**
- * Waits for an alert box to appear and dismisses the alert. If no alert shows up, an Exception is thrown.
+ * Waits for a specific 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(String expectedNotificationMessage) {
+ waitForNotificationAndDismiss(DEFAULT_WAIT_TIMEOUT_SECONDS, expectedNotificationMessage);
+ }
+
+ /**
+ * 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 waitForNotificationAndDismiss(int timeoutInSeconds, String expectedNotificationMessage) {
+ WebDriverWait wait = new WebDriverWait(driver, timeoutInSeconds);
+ wait.until(new Function() {
+
+ @Override
+ public Boolean apply(WebDriver t) {
+ boolean clickedNotifications = false;
+ try {
+ List notificationBar = driver.findElements(By.id("notificationBar"));
+ if (!notificationBar.isEmpty()) {
+ // we got the enclosing panel
+ List notifications = notificationBar.get(0).findElements(By.cssSelector("*"));
+ if (!notifications.isEmpty()) {
+ for (WebElement messageElement : notifications) {
+ if (expectedNotificationMessage == null
+ || messageElement.getText().contains(expectedNotificationMessage)) {
+ messageElement.click();
+ clickedNotifications = true;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // This call can fail temporarily while notifications are being updated
+ }
+ return clickedNotifications;
+ }
+ });
}
- /**
- * Waits for an alert box to appear and dismisses the alert. If no alert shows up, an Exception is thrown.
- */
- protected void waitForAlertAndDismiss(int timeoutInSeconds) throws InterruptedException {
- int i = 0;
- while (i < timeoutInSeconds) {
- i++;
- try {
- Alert alert = driver.switchTo().alert();
- alert.accept();
- return;
- } catch (NoAlertPresentException e) {
- Thread.sleep(1000);
+ protected void scrollToView(WebElement webElement) {
+ ((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(false);", webElement);
+ }
+
+ public boolean isElementEntirelyVisible(WebElement element) {
+ try {
+ if (element.isDisplayed()) {
+ final int windowWidth = driver.manage().window().getSize().getWidth();
+ if (windowWidth >= element.getLocation().x
+ + element.getSize().width) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
}
+ } catch (Exception e) {
+ // The element may currently only partially visible which makes some of the calls fail
+ return false;
}
- throw new NoAlertPresentException();
}
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/ActionsHelper.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/ActionsHelper.java
index 1948e54fac6..76528e6bdb0 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/ActionsHelper.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/ActionsHelper.java
@@ -1,5 +1,7 @@
package com.sap.sailing.selenium.pages.adminconsole;
+import java.util.function.Function;
+
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.NoAlertPresentException;
@@ -9,7 +11,6 @@ import org.openqa.selenium.WebDriver.TargetLocator;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.FluentWait;
-import com.google.common.base.Function;
import com.sap.sailing.selenium.pages.PageObject;
public class ActionsHelper {
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..a560c72b046 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();
}
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/RegattaDetailsCompositePO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/RegattaDetailsCompositePO.java
index ff2252823c4..acfa69abe74 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/RegattaDetailsCompositePO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/RegattaDetailsCompositePO.java
@@ -1,15 +1,16 @@
package com.sap.sailing.selenium.pages.adminconsole.regatta;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import com.sap.sailing.selenium.core.BySeleniumId;
import com.sap.sailing.selenium.core.FindBy;
-
import com.sap.sailing.selenium.pages.PageArea;
-
import com.sap.sailing.selenium.pages.adminconsole.ActionsHelper;
-
import com.sap.sailing.selenium.pages.gwt.CellTablePO;
import com.sap.sailing.selenium.pages.gwt.DataEntryPO;
import com.sap.sailing.selenium.pages.gwt.GenericCellTablePO;
@@ -85,4 +86,17 @@ public class RegattaDetailsCompositePO extends PageArea {
private CellTablePO getSeriesTable() {
return new GenericCellTablePO<>(this.driver, this.seriesTable, DataEntryPO.class);
}
+
+ public List getRaceNames(String seriesName) {
+ final DataEntryPO seriesEntry = findSeries(seriesName);
+ final String racesColumnContent = seriesEntry.getColumnContent("Races");
+ if (racesColumnContent != null && ! racesColumnContent.isEmpty()) {
+ return Arrays.asList(racesColumnContent.split(", "));
+ }
+ return Collections.emptyList();
+ }
+
+ public void waitForRacesOfSeries(final String series, final List races) {
+ waitUntil(() -> getRaceNames(series).equals(races));
+ }
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/RegattaStructureManagementPanelPO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/RegattaStructureManagementPanelPO.java
index 10683cc2646..fbfbb3dc18a 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/RegattaStructureManagementPanelPO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/RegattaStructureManagementPanelPO.java
@@ -1,7 +1,10 @@
package com.sap.sailing.selenium.pages.adminconsole.regatta;
+import java.util.function.Function;
+
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.WebDriverWait;
import com.sap.sailing.selenium.core.BySeleniumId;
import com.sap.sailing.selenium.core.FindBy;
@@ -64,7 +67,7 @@ public class RegattaStructureManagementPanelPO extends PageArea {
}
private DefaultRegattaLeaderboardCreateDialogPO createDefaultRegattaLeaderboard() {
- WebElement dialog = findElementBySeleniumId(this.driver, "CreateDefaultRegattaLeaderboardDialog"); //$NON-NLS-1$
+ final WebElement dialog = waitForElementBySeleniumId(this.driver, "CreateDefaultRegattaLeaderboardDialog", 10); //$NON-NLS-1$
return new DefaultRegattaLeaderboardCreateDialogPO(this.driver, dialog);
}
@@ -80,9 +83,14 @@ public class RegattaStructureManagementPanelPO extends PageArea {
}
public RegattaDetailsCompositePO getRegattaDetails() {
- if (this.regattaDetails.isDisplayed()) {
- return new RegattaDetailsCompositePO(this.driver, this.regattaDetails);
- }
- return null;
+ return new WebDriverWait(driver, DEFAULT_WAIT_TIMEOUT_SECONDS).until(new Function() {
+ @Override
+ public RegattaDetailsCompositePO apply(WebDriver t) {
+ if (regattaDetails.isDisplayed()) {
+ return new RegattaDetailsCompositePO(driver, regattaDetails);
+ }
+ return null;
+ }
+ });
}
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/SeriesEditDialogPO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/SeriesEditDialogPO.java
index 911fe9cb730..217c8a43ae8 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/SeriesEditDialogPO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/SeriesEditDialogPO.java
@@ -6,6 +6,7 @@ import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.Select;
import com.sap.sailing.selenium.core.BySeleniumId;
@@ -121,9 +122,12 @@ public class SeriesEditDialogPO extends DataEntryDialogPO {
for(WebElement editorRow : getRaceNameEditors()) {
WebElement valueTextBox = findElementBySeleniumId(editorRow, "ValueTextBox");
- if(races.contains(valueTextBox.getAttribute("value"))) {
+ if (races.contains(valueTextBox.getAttribute("value"))) {
WebElement removeButton = findElementBySeleniumId(editorRow, "RemoveButton");
- removeButton.click();
+ // A simple "removeButton.click();" does not work on GeckoDriver here.
+ // This only presses the button down but a click isn't detected.
+ // It seems that the mouseup event isn't correctly fired, why we use this workaround.
+ new Actions(driver).sendKeys(removeButton, "\13").perform();
}
}
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/tracking/TrackedRacesListPO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/tracking/TrackedRacesListPO.java
index 8767e0b2746..faa3e8c047d 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/tracking/TrackedRacesListPO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/tracking/TrackedRacesListPO.java
@@ -6,13 +6,13 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
+import java.util.function.Function;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.FluentWait;
-import com.google.common.base.Function;
import com.sap.sailing.domain.common.BoatClassMasterdata;
import com.sap.sailing.selenium.core.BySeleniumId;
import com.sap.sailing.selenium.core.FindBy;
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/tractrac/TracTracEventManagementPanelPO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/tractrac/TracTracEventManagementPanelPO.java
index 751a810f612..e811fd9c504 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/tractrac/TracTracEventManagementPanelPO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/tractrac/TracTracEventManagementPanelPO.java
@@ -1,16 +1,17 @@
package com.sap.sailing.selenium.pages.adminconsole.tractrac;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
-import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
-import org.openqa.selenium.support.ui.ExpectedCondition;
-import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.Select;
import com.sap.sailing.domain.common.BoatClassMasterdata;
@@ -45,7 +46,7 @@ public class TracTracEventManagementPanelPO extends PageArea {
@Override
public int hashCode() {
- return Objects.hash(this.boatClass, this.eventName, this.raceName);
+ return Objects.hash(BoatClassMasterdata.resolveBoatClass(this.boatClass), this.eventName, this.raceName);
}
@Override
@@ -228,44 +229,53 @@ public class TracTracEventManagementPanelPO extends PageArea {
}
public void startTrackingForRace(TrackableRaceDescriptor race) {
- //startTrackingForRaces(Arrays.asList(race));
- CellTablePO table = getTrackableRacesTable();
- DataEntryPO entryToSelect = null;
- for (DataEntryPO entry : table.getEntries()) {
- TrackableRaceDescriptor entryDiscribtor = new TrackableRaceDescriptor(entry.getColumnContent("Event"),
- entry.getColumnContent("Race"), entry.getColumnContent("Boat Class"));
- if (race.equals(entryDiscribtor)) {
- entryToSelect = entry;
- break;
- }
- }
- table.selectEntry(entryToSelect);
- startTrackingAndWaitForAjaxRequests();
+ startTrackingForRacesInternal(Collections.singletonList(race), null, false);
}
- public void startTrackingForRaces(List races) {
- List racesToProcess = new ArrayList<>(races);
- CellTablePO table = getTrackableRacesTable();
+ public void startTrackingForRacesAndAcceptDefaultRegattaWarning(TrackableRaceDescriptor race) {
+ startTrackingForRacesInternal(Collections.singletonList(race), null, true);
+ }
+
+ public void startTrackingForRaceAndAwaitBoatClassError(TrackableRaceDescriptor race, String expectedBoatClass) {
+ startTrackingForRacesInternal(Collections.singletonList(race), expectedBoatClass, false);
+ }
+
+ public void startTrackingForRaces(Collection races) {
+ startTrackingForRacesInternal(races, null, false);
+ }
+
+ private void startTrackingForRacesInternal(Collection races,
+ String expectedBoatClassErrorOrNull, boolean awaitDefaultRegattaAlert) {
+ final Set racesToProcess = new HashSet<>(races);
+ final CellTablePO table = getTrackableRacesTable();
table.selectEntries(e -> racesToProcess.remove(new TrackableRaceDescriptor(e.getColumnContent("Event"),
- e.getColumnContent("Race"), e.getColumnContent("Boat Class"))));
- if(!racesToProcess.isEmpty()) {
+ e.getColumnContent("Race"), e.getColumnContent("Boat Class"))), racesToProcess::isEmpty);
+ if (!racesToProcess.isEmpty()) {
throw new IllegalStateException("Not all given races where selected");
}
- startTrackingAndWaitForAjaxRequests();
+ startTrackingForSelectedRaces(expectedBoatClassErrorOrNull, awaitDefaultRegattaAlert);
}
public void startTrackingForAllRaces() {
getTrackableRacesTable().selectAllEntries();
- startTrackingAndWaitForAjaxRequests();
+ startTrackingForSelectedRaces(null, false);
}
- private void startTrackingAndWaitForAjaxRequests() {
- this.startTrackingButton.click();
- ExpectedCondition condition = ExpectedConditions.alertIsPresent();
- if (condition.apply(this.driver) == null) {
+ private void startTrackingForSelectedRaces(String expectedBoatClassErrorOrNull, boolean awaitDefaultRegattaAlert) {
+ this.startTracking();
+
+ if (awaitDefaultRegattaAlert) {
+ waitForAlertAndAccept();
+ } else if (expectedBoatClassErrorOrNull == null) {
waitForAjaxRequests();
+ } else {
+ waitForSelectedRacesContainDifferentBoatClassesError(expectedBoatClassErrorOrNull);
}
}
+
+ private void startTracking() {
+ this.startTrackingButton.click();
+ }
public TrackedRacesListPO getTrackedRacesList() {
return new TrackedRacesListPO(this.driver, this.trackedRacesListComposite);
@@ -281,4 +291,11 @@ public class TracTracEventManagementPanelPO extends PageArea {
if(input.isSelected() != selected)
input.click();
}
+
+ private void waitForSelectedRacesContainDifferentBoatClassesError(String boatClass) {
+ String message = String.format("The selected races contain boat classes which are not the same as "
+ + "the boat class '%s' of the selected regatta.", boatClass);
+
+ waitForNotificationAndDismiss(message);
+ }
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/wind/WindPanelPO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/wind/WindPanelPO.java
index 030bc232771..c6ad80bb74e 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/wind/WindPanelPO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/wind/WindPanelPO.java
@@ -1,11 +1,12 @@
package com.sap.sailing.selenium.pages.adminconsole.wind;
+import java.util.function.Function;
+
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.FluentWait;
-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.PageArea;
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayConfiguration.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayConfiguration.java
index d2842d0ba10..eaf9b5aca8e 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayConfiguration.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayConfiguration.java
@@ -2,9 +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.Predicate;
import com.sap.sailing.selenium.core.BySeleniumId;
import com.sap.sailing.selenium.core.FindBy;
import com.sap.sailing.selenium.pages.PageArea;
@@ -31,15 +29,8 @@ public class AutoPlayConfiguration extends PageArea {
ListBoxPO.create(driver, configurationSelectionBox).selectOptionByLabel(mode);
ListBoxPO.create(driver, eventSelectionBox).selectOptionByLabel(event);
ListBoxPO.create(driver, leaderboardSelectionBox).selectOptionByLabel(leaderboard);
- WebDriverWait wait = new WebDriverWait(driver, 10);
//wait till the page processed the changes
- wait.until(new Predicate() {
-
- @Override
- public boolean apply(WebDriver arg0) {
- return getConfiguredUrl() != null && !getConfiguredUrl().isEmpty();
- }
- });
+ waitUntil(() -> getConfiguredUrl() != null && !getConfiguredUrl().isEmpty());
}
public String getConfiguredUrl() {
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 2dfb1fa7fdd..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,9 +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.sap.sailing.selenium.pages.PageArea;
import com.sap.sailing.selenium.pages.leaderboard.LeaderboardTablePO;
@@ -13,35 +11,9 @@ public class AutoPlayLeaderboardView extends PageArea {
super(driver, element);
}
- public LeaderboardTablePO getLeaderBoard() {
- WebElement leaderboardCellTable = new WebDriverWait(driver, 30).until(new Function() {
- @Override
- public WebElement apply(WebDriver driver) {
- WebElement leaderboardCellTable = findElementOrNullBySeleniumId("LeaderboardCellTable");
- if (leaderboardCellTable != null) {
- try {
- if (leaderboardCellTable.isDisplayed()) {
- final int windowWidth = driver.manage().window().getSize().getWidth();
- if (windowWidth >= leaderboardCellTable.getLocation().x
- + leaderboardCellTable.getSize().width) {
- return leaderboardCellTable;
- } else {
- return null;
- }
- } else {
- return null;
- }
- } catch (Exception e) {
- // The element may currently only partially visible which makes some of the calls fail
- // In this case it is necessary to wait for the next loop
- return null;
- }
- } else {
- return null;
- }
- }
- });
- return new LeaderboardTablePO(this.driver, leaderboardCellTable);
+ public LeaderboardTablePO getLeaderBoardWithData() {
+ LeaderboardTablePO leaderboardTablePO = new LeaderboardTablePO(this.driver, findElementBySeleniumId("LeaderboardCellTable"));
+ leaderboardTablePO.waitForTableToShowData();
+ 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/pages/autoplay/AutoPlayUpcomingView.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayUpcomingView.java
index f36ebdfeb09..d1bb387e61f 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayUpcomingView.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/autoplay/AutoPlayUpcomingView.java
@@ -1,13 +1,13 @@
package com.sap.sailing.selenium.pages.autoplay;
import java.util.List;
+import java.util.function.Function;
import org.openqa.selenium.StaleElementReferenceException;
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.pages.PageArea;
public class AutoPlayUpcomingView extends PageArea {
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/common/DataEntryDialogPO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/common/DataEntryDialogPO.java
index 2fa9d9ec354..0e3859c3e84 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/common/DataEntryDialogPO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/common/DataEntryDialogPO.java
@@ -1,10 +1,14 @@
package com.sap.sailing.selenium.pages.common;
+import java.util.function.BooleanSupplier;
+
import org.openqa.selenium.Alert;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
-import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
import com.sap.sailing.selenium.core.BySeleniumId;
import com.sap.sailing.selenium.core.FindBy;
@@ -25,6 +29,9 @@ public abstract class DataEntryDialogPO extends PageArea {
protected DataEntryDialogPO(WebDriver driver, WebElement element) {
super(driver, element);
+
+ // This ensures that we wait until the dialog is opened and not just attached to the DOM
+ waitUntil(element::isDisplayed);
}
@Override
@@ -52,23 +59,41 @@ public abstract class DataEntryDialogPO extends PageArea {
}
public void pressOk() {
- pressOk(false);
+ pressOk(false, true);
}
- public void pressOk(boolean accept) {
+ public void pressOk(boolean acceptAlert, boolean waitForAjaxRequests) {
+ // This generically triggers revalidation in dialogs to ensure that the ok button gets enabled
+ ((JavascriptExecutor) driver).executeScript("!!document.activeElement ? document.activeElement.blur() : 0");
+
+ scrollToView(this.okButton);
+ // Browsers may use smooth scrolling
+ waitUntil(() -> isElementEntirelyVisible(this.okButton) && this.okButton.isEnabled());
this.okButton.click();
- ExpectedCondition condition = ExpectedConditions.alertIsPresent();
- Alert alert = condition.apply(this.driver);
-
- if(alert != null && accept) {
+ if (acceptAlert) {
+ final Alert alert = new WebDriverWait(driver, DEFAULT_WAIT_TIMEOUT_SECONDS)
+ .until(ExpectedConditions.alertIsPresent());
alert.accept();
}
- if(alert == null || accept) {
+ if (waitForAjaxRequests) {
// Wait, since we do a callback usually
waitForAjaxRequests();
}
+
+ // This waits until the dialog is physically closed to make sure further don't fail because the dialog still covers other elements
+ waitUntil(new BooleanSupplier() {
+ @Override
+ public boolean getAsBoolean() {
+ try {
+ return !((WebElement) context).isDisplayed();
+ } catch (StaleElementReferenceException e) {
+ // When the element was removed from the DOM, it isn't displayed anymore
+ return true;
+ }
+ }
+ });
}
public void pressCancel() {
@@ -78,15 +103,7 @@ public abstract class DataEntryDialogPO extends PageArea {
public void pressMakeDefault() {
WebElement element = findElementBySeleniumId(ID_MAKE_DEFAULT_BUTTON);
element.click();
- ExpectedCondition condition = ExpectedConditions.alertIsPresent();
- Alert alert = condition.apply(this.driver);
-
- if(alert != null) {
- alert.accept();
- } else {
- waitForAjaxRequests();
- }
-
+ waitForNotificationAndDismiss();
}
public boolean isMakeDefaultButtonVisible() {
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/CellTablePO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/CellTablePO.java
index 504c3020a09..f38431dddcd 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/CellTablePO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/CellTablePO.java
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
+import java.util.function.BooleanSupplier;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
@@ -258,13 +259,16 @@ public abstract class CellTablePO extends PageArea {
*
*
Note: If an entry is not contained in the table it will not be selected.
*/
- public void selectEntries(Predicate toSelectPredicate) {
+ public void selectEntries(Predicate toSelectPredicate, BooleanSupplier canAbort) {
for (T entry : getEntries()) {
if(toSelectPredicate.test(entry)) {
entry.appendToSelection();
} else {
entry.deselect();
}
+ if (canAbort.getAsBoolean()) {
+ break;
+ }
}
}
@@ -274,7 +278,7 @@ public abstract class CellTablePO extends PageArea {
*
Note: If an entry is not contained in the table it will not be selected.
*/
public void selectAllEntries() {
- selectEntries(e -> true);
+ selectEntries(e -> true, Boolean.FALSE::booleanValue);
}
/**
@@ -343,4 +347,8 @@ public abstract class CellTablePO extends PageArea {
return LOADING_ANIMATION_IMAGE.equals(image);
}
+
+ public void waitForTableToShowData() {
+ waitUntil(() -> !getRows().isEmpty());
+ }
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/DataEntryPO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/DataEntryPO.java
index c28a34889b7..9f87f0edd8c 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/DataEntryPO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/DataEntryPO.java
@@ -4,16 +4,12 @@ import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.By.ByXPath;
+import org.openqa.selenium.Dimension;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Action;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.interactions.CompositeAction;
-import org.openqa.selenium.interactions.HasInputDevices;
-import org.openqa.selenium.interactions.KeyDownAction;
-import org.openqa.selenium.interactions.KeyUpAction;
-import org.openqa.selenium.interactions.Keyboard;
-import org.openqa.selenium.interactions.Mouse;
import com.sap.sailing.selenium.core.FindBy;
import com.sap.sailing.selenium.pages.common.AttributeHelper;
@@ -82,11 +78,33 @@ public class DataEntryPO extends CellTableRowPO {
}
protected Action getSelectAction() {
- Actions actions = new Actions(this.driver);
- actions.moveToElement(getElementForSelect(), 1, 1);
+ final Actions actions = new Actions(this.driver);
+ final WebElement elementForSelect = getElementForSelect();
+ moveToUpperLeftCorner(actions, elementForSelect);
actions.click();
- return actions.build();
+ final CompositeAction compositeAction = new CompositeAction();
+ compositeAction.addAction(new Action() {
+ @Override
+ public void perform() {
+ scrollToView(elementForSelect);
+ }
+ });
+ compositeAction.addAction(actions.build());
+ return compositeAction;
+ }
+
+ /**
+ * It seems that the JavaDoc of {@link Actions#moveToElement(WebElement, int, int)} is not consistent to the
+ * WebDriver specification. The specification says the int params are relative to the center of the element, while
+ * the JavaDoc says it's relative to the upper-left corner. GeckoDriver implements the specification. This method
+ * ensures consistent behavior no matter if the implementation is a legacy one or one that conforms to the
+ * specification.
+ */
+ private void moveToUpperLeftCorner(Actions actions, WebElement webElement) {
+ actions.moveToElement(webElement);
+ final Dimension size = webElement.getSize();
+ actions.moveByOffset(-size.width / 2 + 1, -size.height / 2 + 1);
}
/**
@@ -110,35 +128,49 @@ public class DataEntryPO extends CellTableRowPO {
protected Action getModifiedSelectAction() {
Actions actions = new Actions(this.driver);
+ final WebElement elementToSelect;
+ final boolean controlClick;
if (table.getColumnHeaders().get(0).equals("\u2713")) {
// it's a checkbox column
- actions.moveToElement(this.columns.isEmpty() ? getWebElement() : this.columns.get(0));
- actions.click();
+ elementToSelect = this.columns.isEmpty() ? getWebElement() : this.columns.get(0);
+ controlClick = false;
} else {
+ elementToSelect = getElementForSelect();
+ controlClick = true;
+ }
+ if (controlClick) {
actions.keyDown(Keys.CONTROL);
- actions.moveToElement(getElementForSelect(), 1, 1);
- actions.click();
+ }
+ moveToUpperLeftCorner(actions, elementToSelect);
+ actions.moveToElement(elementToSelect, 1, 1);
+ actions.click();
+ if (controlClick) {
actions.keyUp(Keys.CONTROL);
}
- return actions.build();
+ final CompositeAction compositeAction = new CompositeAction();
+ compositeAction.addAction(new Action() {
+ @Override
+ public void perform() {
+ scrollToView(elementToSelect);
+ }
+ });
+ compositeAction.addAction(actions.build());
+ return compositeAction;
}
protected CompositeAction getModifiedCompositeActionAction() {
- HasInputDevices devices = (HasInputDevices) this.driver;
-
- final Mouse mouse = devices.getMouse();
- final Keyboard keyboard = devices.getKeyboard();
-
return new CompositeAction() {
@Override
public void perform() {
- Action pressControl = new KeyDownAction(keyboard, mouse, Keys.CONTROL);
- pressControl.perform();
+ Actions actions = new Actions(driver);
+ actions.keyDown(Keys.CONTROL);
+ actions.perform();
super.perform();
- Action releaseControl = new KeyUpAction(keyboard, mouse, Keys.CONTROL);
- releaseControl.perform();
+ actions = new Actions(driver);
+ actions.keyUp(Keys.CONTROL);
+ actions.perform();
}
};
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/DateAndTimeInputPO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/DateAndTimeInputPO.java
index 51e005687f3..54dae6eb885 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/DateAndTimeInputPO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/gwt/DateAndTimeInputPO.java
@@ -4,11 +4,11 @@ import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
+import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import com.sap.sailing.selenium.core.BySeleniumId;
-import com.sap.sailing.selenium.core.FindBy;
import com.sap.sailing.selenium.pages.PageArea;
public class DateAndTimeInputPO extends PageArea {
@@ -16,15 +16,17 @@ public class DateAndTimeInputPO extends PageArea {
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MMM d, y");
private static final DateFormat TIME_FORMAT_MINUTES = new SimpleDateFormat("h:mm a");
private static final DateFormat TIME_FORMAT_SECONDS = new SimpleDateFormat("h:mm:ss a");
+ private static final DateFormat ISO_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+ private static final DateFormat ISO_TIME_FORMAT_MINUTES = new SimpleDateFormat("HH:mm");
+ private static final DateFormat ISO_TIME_FORMAT_SECONDS = new SimpleDateFormat("HH:mm:ss");
+ private static final DateFormat ISO_DATE_TIME_FORMAT_MINUTES = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm");
+ private static final DateFormat ISO_DATE_TIME_FORMAT_SECONDS = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
- @FindBy(how = BySeleniumId.class, using = "dateInput")
- private WebElement dateInput;
-
- @FindBy(how = BySeleniumId.class, using = "timeInput")
- private WebElement timeInput;
+ private final WebElement element;
private DateAndTimeInputPO(WebDriver driver, WebElement element) {
super(driver, element);
+ this.element = element;
}
/**
@@ -39,8 +41,27 @@ public class DateAndTimeInputPO extends PageArea {
* @see WebElement#sendKeys(CharSequence...)
*/
public void setValue(Date date, boolean enterSeconds) {
- this.setValue(dateInput, date, DATE_FORMAT);
- this.setValue(timeInput, date, enterSeconds ? TIME_FORMAT_SECONDS : TIME_FORMAT_MINUTES);
+ if (isFieldOfType(element, "datetime-local")) {
+ this.setValueNative(element, date, enterSeconds ? ISO_DATE_TIME_FORMAT_SECONDS : ISO_DATE_TIME_FORMAT_MINUTES);
+ } else {
+ final WebElement dateInput = element.findElement(new BySeleniumId("dateInput"));
+ final WebElement timeInput = element.findElement(new BySeleniumId("timeInput"));
+ if (isFieldOfType(dateInput, "date")) {
+ this.setValueNative(dateInput, date, ISO_DATE_FORMAT);
+ } else {
+ this.setValue(dateInput, date, DATE_FORMAT);
+ }
+
+ if (isFieldOfType(timeInput, "time")) {
+ this.setValueNative(timeInput, date, enterSeconds ? ISO_TIME_FORMAT_SECONDS : ISO_TIME_FORMAT_MINUTES);
+ } else {
+ this.setValue(timeInput, date, enterSeconds ? TIME_FORMAT_SECONDS : TIME_FORMAT_MINUTES);
+ }
+ }
+ }
+
+ private boolean isFieldOfType(WebElement inputToCheck, String type) {
+ return type.equals(inputToCheck.getAttribute("type"));
}
private void setValue(WebElement input, Date date, DateFormat format) {
@@ -49,6 +70,12 @@ public class DateAndTimeInputPO extends PageArea {
input.sendKeys(value);
input.sendKeys("\t"); // ensure popup closing!
}
+
+ private void setValueNative(WebElement input, Date date, DateFormat format) {
+ final String value = format.format(date);
+ final JavascriptExecutor javascriptExecutor = ((JavascriptExecutor) driver);
+ javascriptExecutor.executeScript("arguments[0].value = arguments[1];", input, value);
+ }
public static DateAndTimeInputPO create(WebDriver driver, WebElement element) {
return new DateAndTimeInputPO(driver, element);
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/leaderboard/LeaderboardPage.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/leaderboard/LeaderboardPage.java
index 3d0ce8d1d63..6f1c51babfb 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/leaderboard/LeaderboardPage.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/leaderboard/LeaderboardPage.java
@@ -129,6 +129,7 @@ public class LeaderboardPage extends HostPage {
}
public LeaderboardSettingsDialogPO getLeaderboardSettings() {
+ scrollToTop();
this.leaderboardSettingsButton.click();
return new LeaderboardSettingsDialogPO(this.driver,
findElementBySeleniumId(this.driver, "LeaderboardSettingsDialog"));
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/leaderboard/LeaderboardTablePO.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/leaderboard/LeaderboardTablePO.java
index dd7a042e728..6adaeb9ec78 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/leaderboard/LeaderboardTablePO.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/leaderboard/LeaderboardTablePO.java
@@ -7,14 +7,10 @@ import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
-import org.openqa.selenium.support.ui.WebDriverWait;
-import com.google.common.base.Predicate;
import com.sap.sailing.selenium.pages.common.CSSHelper;
-
import com.sap.sailing.selenium.pages.gwt.CellTablePO;
import com.sap.sailing.selenium.pages.gwt.DataEntryPO;
-
import com.sap.sailing.selenium.pages.leaderboard.LeaderboardTablePO.LeaderboardEntry;
public class LeaderboardTablePO extends CellTablePO {
@@ -195,13 +191,4 @@ public class LeaderboardTablePO extends CellTablePO {
private WebElement getExpansionButton(WebElement header) {
return header.findElement(By.xpath(EXPANSION_BUTTON_XPATH));
}
-
- public void waitForLeaderboardToHaveData() {
- new WebDriverWait(driver, 30).until(new Predicate() {
- @Override
- public boolean apply(WebDriver driver) {
- return !getRows().isEmpty();
- }
- });
- }
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/raceboard/RaceBoardPage.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/raceboard/RaceBoardPage.java
index ddd9c286b77..f80fbd7f2b5 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/raceboard/RaceBoardPage.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/raceboard/RaceBoardPage.java
@@ -3,9 +3,11 @@ package com.sap.sailing.selenium.pages.raceboard;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.function.BooleanSupplier;
+import java.util.function.Function;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.WebDriverWait;
import com.sap.sailing.selenium.core.BySeleniumId;
import com.sap.sailing.selenium.core.FindBy;
@@ -20,6 +22,7 @@ public class RaceBoardPage extends HostPageWithAuthentication {
@FindBy(how = BySeleniumId.class, using = "raceMapSettingsButton")
private WebElement raceMapSettingsButton;
+ private boolean doneInit;
/**
* Navigates to the given home URL and provides the corresponding {@link PageObject}.
@@ -42,20 +45,60 @@ public class RaceBoardPage extends HostPageWithAuthentication {
private RaceBoardPage(WebDriver driver) {
super(driver);
}
+
+ @Override
+ protected void waitForAjaxRequests(int timeout, int polling) {
+ // since the raceboard continually loads new data, we cannot wait for it to finish initially
+ if (doneInit) {
+ super.waitForAjaxRequests(timeout, polling);
+ }
+ }
+
+ @Override
+ protected void initElements() {
+ super.initElements();
+ doneInit = true;
+
+ // wait untill initial rendering of racemap & compilation ect, as default ajax based wait won't work here
+ WebDriverWait webDriverWait = new WebDriverWait(driver, 300);
+ webDriverWait.until(new Function() {
+ @Override
+ public Boolean apply(WebDriver t) {
+ try {
+ return raceMapSettingsButton.isDisplayed() && raceMapSettingsButton.getLocation().y > 100;
+ } catch (Exception e) {
+ // RaceMap cause multiple reflows and the element may temporarily not be in the viewport
+ return false;
+ }
+ }
+ });
+ }
+
public MapSettingsPO openMapSettings() {
+ waitUntil(new BooleanSupplier() {
+ @Override
+ public boolean getAsBoolean() {
+ try {
+ return raceMapSettingsButton.isDisplayed() && raceMapSettingsButton.getLocation().y > 100;
+ } catch (Exception e) {
+ // RaceMap cause multiple reflows and the element may temporarily not be in the viewport
+ return false;
+ }
+ }
+ });
raceMapSettingsButton.click();
waitUntil(new BooleanSupplier() {
-
@Override
public boolean getAsBoolean() {
WebElement settingsDialog = null;
try {
settingsDialog = findElementBySeleniumId("raceMapSettings");
+ boolean exists = settingsDialog != null;
+ // exists, and was actually rendered (to apply the values)
+ return (exists && settingsDialog.isDisplayed());
} catch(Exception e) {
}
- boolean exists = settingsDialog != null;
- // exists, and was actually rendered (to apply the values)
- return (exists && settingsDialog.getSize().height > 50);
+ return false;
}
});
return new MapSettingsPO(driver, findElementBySeleniumId("raceMapSettings"));
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/AbstractSeleniumTest.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/AbstractSeleniumTest.java
index a77a7f01b37..de34a683102 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/AbstractSeleniumTest.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/AbstractSeleniumTest.java
@@ -18,20 +18,23 @@ import org.junit.Rule;
import org.junit.rules.TestWatchman;
import org.junit.runner.RunWith;
import org.junit.runners.model.FrameworkMethod;
+import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
-import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.Keys;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.html5.WebStorage;
import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.remote.RemoteWebDriver;
-import com.sap.sse.common.Duration;
-import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sailing.selenium.core.Managed;
import com.sap.sailing.selenium.core.SeleniumRunner;
import com.sap.sailing.selenium.core.TestEnvironment;
import com.sap.sailing.selenium.core.WindowManager;
+import com.sap.sailing.selenium.pages.PageObject;
+import com.sap.sse.common.Duration;
+import com.sap.sse.common.impl.MillisecondsTimePoint;
/**
*
Abstract base class for unit tests with Selenium. This class is already annotated as required to get executed
@@ -83,16 +86,37 @@ public abstract class AbstractSeleniumTest {
} catch (IOException exception) {
throw new RuntimeException(exception);
}
- // clear local storage
+
+ // To be able to access LocalStorage we need to load a page having the target origin
getWebDriver().get(contextRoot);
- ((JavascriptExecutor)getWebDriver()).executeScript("window.localStorage.clear();");
+
+ // clear local storage
+ final WebStorage webStorage = (WebStorage)getWebDriver();
+ webStorage.getLocalStorage().clear();
+
+ // extending the timeout of notifications to 100s to prevent timing failures
+ webStorage.getLocalStorage().setItem("sse.notification.customTimeOutInSeconds",
+ Integer.toString(PageObject.DEFAULT_WAIT_TIMEOUT_SECONDS));
+
+ try {
+ // In IE 11 we sometimes see the problem that IE somehow automatically changes the zoom level to 75%.
+ // Selenium tests with InternetExplorerDriver fail if the zoom level is not set to 100% due to the fact that coordinates determined aren't correct.
+ // With this we enforce a zoom level of 100% before running a test.
+ // To make this work correctly you also need to set InternetExplorerDriver.IGNORE_ZOOM_SETTING to true (this should be pre-configured in local-test-environment.xml when activating IE driver)
+ getWebDriver().findElement(By.tagName("html")).sendKeys(Keys.chord(Keys.CONTROL, "0"));
+ } catch (Exception e) {
+ }
}
protected void setUpAuthenticatedSession() {
+ // To be able to set a cookie we need to load a page having the target origin
+ getWebDriver().get(getContextRoot());
+
logger.info("Authenticating session...");
Cookie sessionCookie = authenticate(getContextRoot());
getWebDriver().get(getContextRoot() + "index.html"); // initialize web driver so setting a cookie for the local domain is possible
- getWebDriver().manage().addCookie(sessionCookie);
+ final Cookie cookieWithoutDomain = new Cookie(sessionCookie.getName(), sessionCookie.getValue(), null, sessionCookie.getPath(), sessionCookie.getExpiry(), sessionCookie.isSecure(), sessionCookie.isHttpOnly());
+ getWebDriver().manage().addCookie(cookieWithoutDomain);
logger.info("...obtained session cookie "+sessionCookie);
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestRefreshableSelectionModel.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestRefreshableSelectionModel.java
index 4075640702c..a232724042e 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestRefreshableSelectionModel.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestRefreshableSelectionModel.java
@@ -13,8 +13,6 @@ import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
-import com.sap.sailing.selenium.core.WebDriverWindow;
-import com.sap.sailing.selenium.core.WindowManager;
import com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage;
import com.sap.sailing.selenium.pages.adminconsole.connectors.SmartphoneTrackingEventManagementPanelPO;
import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardConfigurationPanelPO;
@@ -36,10 +34,6 @@ import com.sap.sailing.selenium.pages.gwt.DataEntryPO;
import com.sap.sailing.selenium.test.AbstractSeleniumTest;
public class TestRefreshableSelectionModel extends AbstractSeleniumTest {
- private static WindowManager manager;
- private static WebDriverWindow windowForEdit;
- private static WebDriverWindow windowForSelection;
-
// TestMaintenanceOfSelectionAfterDataChanges
private CompetitorEntry competitorEntry;
private CompetitorEntry competitorEntryToSelect;
@@ -66,9 +60,6 @@ public class TestRefreshableSelectionModel extends AbstractSeleniumTest {
@Before
public void setUp() {
clearState(getContextRoot());
- manager = this.environment.getWindowManager();
- windowForEdit = manager.getCurrentWindow();
- windowForSelection = manager.openNewWindow();
super.setUp();
}
@@ -80,85 +71,87 @@ public class TestRefreshableSelectionModel extends AbstractSeleniumTest {
@Test
public void testMaintenanceOfSelectionAfterDataChanges() {
- windowForEdit.switchToWindow();
- final TrackedRacesCompetitorsPanelPO competitorsPanel = goToCompetitorsPanel();
-
- for (int i = 0; i < 2; i++) {
+ this.environment.getWindowManager().withExtraWindow((windowForSelection, windowForEdit) -> {
+ windowForEdit.switchToWindow();
+ final TrackedRacesCompetitorsPanelPO competitorsPanel = goToCompetitorsPanel();
+
+ for (int i = 0; i < 2; i++) {
+ TrackedRacesCompetitorEditDialogPO dialog = competitorsPanel.pushAddCompetitorButton();
+ dialog.setNameTextBox("" + System.currentTimeMillis());
+ dialog.setShortNameTextBox("" + System.currentTimeMillis());
+ dialog.pressOk();
+ }
+
TrackedRacesCompetitorEditDialogPO dialog = competitorsPanel.pushAddCompetitorButton();
- dialog.setNameTextBox("" + System.currentTimeMillis());
- dialog.setShortNameTextBox("" + System.currentTimeMillis());
+ final String name = "" + System.currentTimeMillis();
+ dialog.setNameTextBox(name);
+ final String shortName = "" + System.currentTimeMillis();
+ dialog.setShortNameTextBox(shortName);
dialog.pressOk();
- }
-
- TrackedRacesCompetitorEditDialogPO dialog = competitorsPanel.pushAddCompetitorButton();
- final String name = "" + System.currentTimeMillis();
- dialog.setNameTextBox(name);
- final String shortName = "" + System.currentTimeMillis();
- dialog.setShortNameTextBox(shortName);
- dialog.pressOk();
-
- boolean found = false;
- for (final CompetitorEntry it : competitorsPanel.getCompetitorTable().getEntries()) {
- String itName = it.getName();
- if (itName.equals(name)) {
- found = true;
- competitorEntry = it;
- break;
+
+ boolean found = false;
+ for (final CompetitorEntry it : competitorsPanel.getCompetitorTable().getEntries()) {
+ String itName = it.getName();
+ if (itName.equals(name)) {
+ found = true;
+ competitorEntry = it;
+ break;
+ }
}
- }
- assertTrue(found);
-
- windowForSelection.switchToWindow();
- TrackedRacesCompetitorsPanelPO competitorPanelForSelection = goToCompetitorsPanel();
- found = false;
- for (final CompetitorEntry it : competitorPanelForSelection.getCompetitorTable().getEntries()) {
- String itName = it.getName();
- if (itName.equals(name)) {
- found = true;
- competitorEntryToSelect = it;
- break;
+ assertTrue(found);
+
+ windowForSelection.switchToWindow();
+ TrackedRacesCompetitorsPanelPO competitorPanelForSelection = goToCompetitorsPanel();
+ found = false;
+ for (final CompetitorEntry it : competitorPanelForSelection.getCompetitorTable().getEntries()) {
+ String itName = it.getName();
+ if (itName.equals(name)) {
+ found = true;
+ competitorEntryToSelect = it;
+ break;
+ }
}
- }
- assertTrue(found);
- competitorPanelForSelection.getCompetitorTable().selectEntry(competitorEntryToSelect);
-
- assertEquals(1, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().size());
- assertEquals(name, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().get(0).getName());
- assertEquals(shortName, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().get(0).getShortName());
- // change competitor
- windowForEdit.switchToWindow();
- dialog = competitorEntry.clickEditButton();
- final String changedName = "" + System.currentTimeMillis();
- dialog.setNameTextBox(changedName);
- final String changedShortName = "" + System.currentTimeMillis();
- dialog.setShortNameTextBox(changedShortName);
- dialog.pressOk();
-
- // assert selection
- windowForSelection.switchToWindow();
-
- competitorPanelForSelection.pushRefreshButton();
- WebDriverWait waitTimer = new WebDriverWait(competitorPanelForSelection.driver, 10);
- ExpectedCondition condition = new ExpectedCondition() {
- @Override
- public Boolean apply(WebDriver arg0) {
- return competitorPanelForSelection.getCompetitorTable().getSelectedEntries().size() == 1;
+ assertTrue(found);
+ competitorPanelForSelection.getCompetitorTable().selectEntry(competitorEntryToSelect);
+
+ assertEquals(1, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().size());
+ assertEquals(name, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().get(0).getName());
+ assertEquals(shortName, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().get(0).getShortName());
+ // change competitor
+ windowForEdit.switchToWindow();
+ dialog = competitorEntry.clickEditButton();
+ final String changedName = "" + System.currentTimeMillis();
+ dialog.setNameTextBox(changedName);
+ final String changedShortName = "" + System.currentTimeMillis();
+ dialog.setShortNameTextBox(changedShortName);
+ dialog.pressOk();
+
+ // assert selection
+ windowForSelection.switchToWindow();
+
+ competitorPanelForSelection.pushRefreshButton();
+ WebDriverWait waitTimer = new WebDriverWait(competitorPanelForSelection.driver, 10);
+ ExpectedCondition condition = new ExpectedCondition() {
+ @Override
+ public Boolean apply(WebDriver arg0) {
+ return competitorPanelForSelection.getCompetitorTable().getSelectedEntries().size() == 1;
+ }
+ };
+ waitTimer.until(condition);
+
+ assertEquals(1, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().size());
+ for (final CompetitorEntry it : competitorPanelForSelection.getCompetitorTable().getEntries()) {
+ String itName = it.getName();
+ if (itName.equals(changedName)) {
+ found = true;
+ competitorEntryToSelect = it;
+ break;
+ }
}
- };
- waitTimer.until(condition);
-
- assertEquals(1, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().size());
- for (final CompetitorEntry it : competitorPanelForSelection.getCompetitorTable().getEntries()) {
- String itName = it.getName();
- if (itName.equals(changedName)) {
- found = true;
- competitorEntryToSelect = it;
- break;
- }
- }
- assertTrue(found);
- assertEquals(changedName, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().get(0).getName());
- assertEquals(changedShortName, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().get(0).getShortName());
+ assertTrue(found);
+ assertEquals(changedName, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().get(0).getName());
+ assertEquals(changedShortName, competitorPanelForSelection.getCompetitorTable().getSelectedEntries().get(0).getShortName());
+ });
}
private void setUpTestRefreshOfDependingUIElements() {
@@ -201,62 +194,63 @@ public class TestRefreshableSelectionModel extends AbstractSeleniumTest {
@Test
public void testRefreshOfDependingUIElements() {
- windowForSelection.switchToWindow();
- setUpTestRefreshOfDependingUIElements();
- AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
- SmartphoneTrackingEventManagementPanelPO smartphoneTrackingPanel = adminConsole.goToSmartphoneTrackingPanel();
- CellTablePO leaderboards = smartphoneTrackingPanel.getLeaderboardTable();
- // select leaderboard
- DataEntryPO entryToSelect = null;
- for(DataEntryPO entry : leaderboards.getEntries()) {
- if(entry.getColumnContent("Name").equals(LEADERBOARD)) {
- entryToSelect = entry;
- break;
+ this.environment.getWindowManager().withExtraWindow((windowForSelection, windowForEdit) -> {
+ windowForSelection.switchToWindow();
+ setUpTestRefreshOfDependingUIElements();
+ AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
+ SmartphoneTrackingEventManagementPanelPO smartphoneTrackingPanel = adminConsole.goToSmartphoneTrackingPanel();
+ CellTablePO leaderboards = smartphoneTrackingPanel.getLeaderboardTable();
+ // select leaderboard
+ DataEntryPO entryToSelect = null;
+ for(DataEntryPO entry : leaderboards.getEntries()) {
+ if(entry.getColumnContent("Name").equals(LEADERBOARD)) {
+ entryToSelect = entry;
+ break;
+ }
}
- }
- assertNotNull(entryToSelect);
- leaderboards.selectEntry(entryToSelect);
-
- RaceColumnTableWrapperPO raceColumnTableWrapper = smartphoneTrackingPanel.getRaceColumnTableWrapper();
- CellTablePO raceColumnTable = raceColumnTableWrapper.getRaceColumnTable();
- final int anzRaceColumns = raceColumnTable.getEntries().size();
- assertEquals(5, anzRaceColumns);
-
- // Open a second window & setup second window
- windowForEdit.switchToWindow();
-
- AdminConsolePage adminConsoleForEdit = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
- RegattaStructureManagementPanelPO regattaStructure = adminConsoleForEdit.goToRegattaStructure();
-
- RegattaDetailsCompositePO regattaDetails = regattaStructure.getRegattaDetails(this.regatta);
- SeriesEditDialogPO seriesDialog = regattaDetails.editSeries(RegattaStructureManagementPanelPO.DEFAULT_SERIES_NAME);
- seriesDialog.addRaces(6, 7);
- seriesDialog.pressOk();
-
- windowForSelection.switchToWindow();
- adminConsole.goToTracTracEvents();
- smartphoneTrackingPanel = adminConsole.goToSmartphoneTrackingPanel();
- leaderboards = smartphoneTrackingPanel.getLeaderboardTable();
- // select leaderboard
- entryToSelect = null;
- for(DataEntryPO entry : leaderboards.getEntries()) {
- if(entry.getColumnContent("Name").equals(LEADERBOARD)) {
- entryToSelect = entry;
- break;
+ assertNotNull(entryToSelect);
+ leaderboards.selectEntry(entryToSelect);
+
+ RaceColumnTableWrapperPO raceColumnTableWrapper = smartphoneTrackingPanel.getRaceColumnTableWrapper();
+ CellTablePO raceColumnTable = raceColumnTableWrapper.getRaceColumnTable();
+ final int anzRaceColumns = raceColumnTable.getEntries().size();
+ assertEquals(5, anzRaceColumns);
+
+ // Open a second window & setup second window
+ windowForEdit.switchToWindow();
+
+ AdminConsolePage adminConsoleForEdit = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
+ RegattaStructureManagementPanelPO regattaStructure = adminConsoleForEdit.goToRegattaStructure();
+
+ RegattaDetailsCompositePO regattaDetails = regattaStructure.getRegattaDetails(this.regatta);
+ SeriesEditDialogPO seriesDialog = regattaDetails.editSeries(RegattaStructureManagementPanelPO.DEFAULT_SERIES_NAME);
+ seriesDialog.addRaces(6, 7);
+ seriesDialog.pressOk();
+
+ windowForSelection.switchToWindow();
+ adminConsole.goToTracTracEvents();
+ smartphoneTrackingPanel = adminConsole.goToSmartphoneTrackingPanel();
+ leaderboards = smartphoneTrackingPanel.getLeaderboardTable();
+ // select leaderboard
+ entryToSelect = null;
+ for(DataEntryPO entry : leaderboards.getEntries()) {
+ if(entry.getColumnContent("Name").equals(LEADERBOARD)) {
+ entryToSelect = entry;
+ break;
+ }
}
- }
- assertNotNull(entryToSelect);
- leaderboards.selectEntry(entryToSelect);
-
- raceColumnTableWrapper = smartphoneTrackingPanel.getRaceColumnTableWrapper();
- raceColumnTable = raceColumnTableWrapper.getRaceColumnTable();
- final int newAnzRaceColumns = raceColumnTable.getEntries().size();
- assertEquals(7, newAnzRaceColumns);
+ assertNotNull(entryToSelect);
+ leaderboards.selectEntry(entryToSelect);
+
+ raceColumnTableWrapper = smartphoneTrackingPanel.getRaceColumnTableWrapper();
+ raceColumnTable = raceColumnTableWrapper.getRaceColumnTable();
+ final int newAnzRaceColumns = raceColumnTable.getEntries().size();
+ assertEquals(7, newAnzRaceColumns);
+ });
}
@Test
public void testMaintenanceOfSelectionAfterFilteringTrackedracesOnLeaderboardConfigPanel() {
- windowForSelection.switchToWindow();
setUpTestRefreshOfDependingUIElements();
AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
LeaderboardConfigurationPanelPO leaderboardConfiguration = adminConsole.goToLeaderboardConfiguration();
@@ -267,12 +261,7 @@ public class TestRefreshableSelectionModel extends AbstractSeleniumTest {
tracTracEvents.listTrackableRaces(IDM_5O5_2013_JSON_URL);
tracTracEvents.setReggataForTracking(this.regatta);
tracTracEvents.setTrackSettings(false, false, false);
- // TODO: There exists a bug in Selenium with key modifiers (Issue 3734 and 6817), so we can't use multi
- // selection (Firefox on Windows)
- //tracTracEvents.startTrackingForRaces(this.trackableRaces);
- for(int i =0; i<2;i++) {
- tracTracEvents.startTrackingForRace(trackableRaces.get(i));
- }
+ tracTracEvents.startTrackingForRaces(this.trackableRaces);
leaderboardConfiguration = adminConsole.goToLeaderboardConfiguration();
LeaderboardDetailsPanelPO leaderboardDetails = leaderboardConfiguration.getLeaderboardDetails(this.regatta.toString());
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestSmartphoneTrackingEventManagementPanel.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestSmartphoneTrackingEventManagementPanel.java
index e401c6f74ab..75b6bb44e61 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestSmartphoneTrackingEventManagementPanel.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestSmartphoneTrackingEventManagementPanel.java
@@ -15,9 +15,9 @@ import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardConfig
import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardDetailsPanelPO;
import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardDetailsPanelPO.RaceDescriptor;
import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaDetailsCompositePO;
+import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaListCompositePO.RegattaDescriptor;
import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaStructureManagementPanelPO;
import com.sap.sailing.selenium.pages.adminconsole.regatta.SeriesEditDialogPO;
-import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaListCompositePO.RegattaDescriptor;
import com.sap.sailing.selenium.pages.adminconsole.tracking.RaceColumnTableWrapperPO;
import com.sap.sailing.selenium.pages.adminconsole.tracking.TrackedRacesListPO;
import com.sap.sailing.selenium.pages.adminconsole.tracking.TrackedRacesListPO.TrackedRaceDescriptor;
@@ -132,11 +132,6 @@ public class TestSmartphoneTrackingEventManagementPanel extends AbstractSelenium
tracTracEvents.listTrackableRaces(IDM_5O5_2013_JSON_URL);
tracTracEvents.setReggataForTracking(this.regatta);
tracTracEvents.setTrackSettings(false, false, false);
- // TODO: There exists a bug in Selenium with key modifiers (Issue 3734 and 6817), so we can't use multi
- // selection (Firefox on Windows)
- //tracTracEvents.startTrackingForRaces(this.trackableRaces);
- for(TrackableRaceDescriptor race : this.trackableRaces) {
- tracTracEvents.startTrackingForRace(race);
- }
+ tracTracEvents.startTrackingForRaces(this.trackableRaces);
}
}
\ No newline at end of file
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..509bb5d6a98 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
@@ -1,13 +1,10 @@
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 org.junit.Before;
import org.junit.Test;
-import org.openqa.selenium.Alert;
-import org.openqa.selenium.WebDriver.TargetLocator;
import com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage;
import com.sap.sailing.selenium.pages.adminconsole.regatta.RegattaListCompositePO.RegattaDescriptor;
@@ -87,13 +84,7 @@ public class TestStartAndStopTrackingForTracTracEvents extends AbstractSeleniumT
tracTracEvents.listTrackableRaces(BMW_CUP_JSON_URL);
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();
- alert.dismiss();
- String message = "There is at least one regatta for the selected boat classes.";
- assertThat(text, containsString(message));
+ tracTracEvents.startTrackingForRacesAndAcceptDefaultRegattaWarning(this.trackableRace);
}
@Test
@@ -108,13 +99,6 @@ public class TestStartAndStopTrackingForTracTracEvents extends AbstractSeleniumT
tracTracEvents.listTrackableRaces(BMW_CUP_JSON_URL);
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));
+ tracTracEvents.startTrackingForRaceAndAwaitBoatClassError(this.trackableRace, IDM_2013_BOAT_CLASS);
}
}
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 52db4e94fde..04023ea3ca8 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
@@ -6,12 +6,15 @@ import static org.junit.Assert.assertTrue;
import java.util.Date;
import java.util.List;
+import java.util.function.Function;
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.sap.sailing.selenium.pages.adminconsole.AdminConsolePage;
import com.sap.sailing.selenium.pages.adminconsole.event.EventConfigurationPanelPO;
@@ -117,9 +120,27 @@ public class TestAutoPlay extends AbstractSeleniumTest {
assertTrue("Url does not contain proper title " + url, url.contains("lbwh.saph.title=Leaderboard%3A+BMW+Cup+(J80)"));
assertTrue("Url does not contain proper name " + url, url.contains("name=BMW+Cup+(J80)"));
AutoPlayLeaderboardView autoplayPage = page.goToAutoPlayClassicUrl(getWebDriver(), url);
- LeaderboardTablePO leaderBoard = autoplayPage.getLeaderBoard();
- leaderBoard.waitForLeaderboardToHaveData();
- List races = leaderBoard.getRaceNames();
+ LeaderboardTablePO leaderBoard = autoplayPage.getLeaderBoardWithData();
+ 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/leaderboard/TestLeaderboardConfiguration.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboard/TestLeaderboardConfiguration.java
index 80739d87854..d1099f09de1 100644
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboard/TestLeaderboardConfiguration.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboard/TestLeaderboardConfiguration.java
@@ -11,8 +11,6 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
-import com.sap.sailing.selenium.core.WebDriverWindow;
-import com.sap.sailing.selenium.core.WindowManager;
import com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage;
import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardConfigurationPanelPO;
import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardDetailsPanelPO;
@@ -73,117 +71,113 @@ public class TestLeaderboardConfiguration extends AbstractSeleniumTest {
@Test
public void testDynamicRaceLinking() {
- // Open a second window which we use for the leaderboard later
- WindowManager manager = this.environment.getWindowManager();
- WebDriverWindow leaderboardWindow = manager.getCurrentWindow();
- WebDriverWindow adminConsoleWindow = manager.openNewWindow();
-
- // Open the leaderboard and check for "empty" leaderboard
- LeaderboardPage leaderboard = LeaderboardPage.goToPage(getWebDriver(), getContextRoot(), LEADERBOARD, false);
- LeaderboardTablePO table = leaderboard.getLeaderboardTable();
- List races = table.getRaceNames();
-
- assertThat(races.size(), equalTo(5));
- assertThat(table.getEntries().size(), equalTo(28)); // the regatta already has the races linked; regatta leaderboard obtains competitors from regatta
- adminConsoleWindow.switchToWindow();
- AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
- LeaderboardConfigurationPanelPO leaderboardConfiguration = adminConsole.goToLeaderboardConfiguration();
- LeaderboardDetailsPanelPO leaderboardDetails = leaderboardConfiguration.getLeaderboardDetails(this.regatta.toString());
-
- Integer[] expectedPointsForFindelJens = new Integer[] {2, 18, 12, 4, 7};
- Integer[] expectedRankForFindelJens = new Integer[] {2, 9, 11, 7, 6}; // Bogacki with no score in R1 expected to end up at end of leaderboard
-
- // Link the races and check the leaderboard again
- for (int i = 0; i < 5; i++) {
- leaderboardDetails.linkRace(this.leaderboardRaces.get(i), this.trackedRaces.get(i));
- leaderboardWindow.switchToWindow();
- leaderboard.refresh();
- List allEntries = table.getEntries();
- LeaderboardEntry findelJens = table.getEntry("8875");
- Integer points = findelJens.getPointsForRace(String.format("D%s", i + 1));
- Integer rank = findelJens.getTotalRank();
- // Assertions
- assertThat("Number of competitors does not match",
- allEntries.size(), equalTo(28));
- assertThat("Points for race 'D" + (i + 1) + "' do not match for competitor '8875' (Findel, Jens)",
- points, equalTo(expectedPointsForFindelJens[i]));
- assertThat("Total rank after " + (i + 1) + " race(s) does not match for competitor '8875' (Findel, Jens)",
- rank, equalTo(expectedRankForFindelJens[i]));
+ this.environment.getWindowManager().withExtraWindow((leaderboardWindow, adminConsoleWindow) -> {
+ // Open the leaderboard and check for "empty" leaderboard
+ LeaderboardPage leaderboard = LeaderboardPage.goToPage(getWebDriver(), getContextRoot(), LEADERBOARD, false);
+ LeaderboardTablePO table = leaderboard.getLeaderboardTable();
+ List races = table.getRaceNames();
+
+ assertThat(races.size(), equalTo(5));
+ assertThat(table.getEntries().size(), equalTo(28)); // the regatta already has the races linked; regatta leaderboard obtains competitors from regatta
adminConsoleWindow.switchToWindow();
- }
+ AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
+ LeaderboardConfigurationPanelPO leaderboardConfiguration = adminConsole.goToLeaderboardConfiguration();
+ LeaderboardDetailsPanelPO leaderboardDetails = leaderboardConfiguration.getLeaderboardDetails(this.regatta.toString());
+
+ Integer[] expectedPointsForFindelJens = new Integer[] {2, 18, 12, 4, 7};
+ Integer[] expectedRankForFindelJens = new Integer[] {2, 9, 11, 7, 6}; // Bogacki with no score in R1 expected to end up at end of leaderboard
+
+ // Link the races and check the leaderboard again
+ for (int i = 0; i < 5; i++) {
+ leaderboardDetails.linkRace(this.leaderboardRaces.get(i), this.trackedRaces.get(i));
+ leaderboardWindow.switchToWindow();
+ leaderboard.refresh();
+ List allEntries = table.getEntries();
+ LeaderboardEntry findelJens = table.getEntry("8875");
+ Integer points = findelJens.getPointsForRace(String.format("D%s", i + 1));
+ Integer rank = findelJens.getTotalRank();
+ // Assertions
+ assertThat("Number of competitors does not match",
+ allEntries.size(), equalTo(28));
+ assertThat("Points for race 'D" + (i + 1) + "' do not match for competitor '8875' (Findel, Jens)",
+ points, equalTo(expectedPointsForFindelJens[i]));
+ assertThat("Total rank after " + (i + 1) + " race(s) does not match for competitor '8875' (Findel, Jens)",
+ rank, equalTo(expectedRankForFindelJens[i]));
+ adminConsoleWindow.switchToWindow();
+ }
+ });
}
@Test
public void testDynamicRaceDeletion() {
- WindowManager manager = this.environment.getWindowManager();
- WebDriverWindow adminConsoleWindow = manager.getCurrentWindow();
- WebDriverWindow leaderboardWindow = manager.openNewWindow();
- // Go to the administration console and link all 5 races
- AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
- LeaderboardConfigurationPanelPO leaderboardConfiguration = adminConsole.goToLeaderboardConfiguration();
- LeaderboardDetailsPanelPO leaderboardDetails = leaderboardConfiguration.getLeaderboardDetails(this.regatta.toString());
- leaderboardDetails.linkRace(this.leaderboardRaces.get(0), this.trackedRaces.get(0));
- leaderboardDetails.linkRace(this.leaderboardRaces.get(1), this.trackedRaces.get(1));
- leaderboardDetails.linkRace(this.leaderboardRaces.get(2), this.trackedRaces.get(2));
- leaderboardDetails.linkRace(this.leaderboardRaces.get(3), this.trackedRaces.get(3));
- leaderboardDetails.linkRace(this.leaderboardRaces.get(4), this.trackedRaces.get(4));
- // Open the leaderboard in our second window
- leaderboardWindow.switchToWindow();
- LeaderboardPage leaderboard = LeaderboardPage.goToPage(getWebDriver(), getContextRoot(), LEADERBOARD, false);
- LeaderboardTablePO table = leaderboard.getLeaderboardTable();
- // Go back to the administration console and delete third race
- adminConsoleWindow.switchToWindow();
- RegattaStructureManagementPanelPO regattaStructure = adminConsole.goToRegattaStructure();
- RegattaDetailsCompositePO regattaDetails = regattaStructure.getRegattaDetails(this.regatta);
- SeriesEditDialogPO seriesDialog = regattaDetails.editSeries(RegattaStructureManagementPanelPO.DEFAULT_SERIES_NAME);
- seriesDialog.deleteRace("D3");
- seriesDialog.pressOk(true);
- // Now we can check the result with our expectation
- leaderboardWindow.switchToWindow();
- leaderboard.refresh();
- assertThat("Race names do not match after deletion of race 'D3'",
- table.getRaceNames(), equalTo(Arrays.asList("D1", "D2", "D4", "D5")));
+ this.environment.getWindowManager().withExtraWindow((adminConsoleWindow, leaderboardWindow) -> {
+ // Go to the administration console and link all 5 races
+ AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
+ LeaderboardConfigurationPanelPO leaderboardConfiguration = adminConsole.goToLeaderboardConfiguration();
+ LeaderboardDetailsPanelPO leaderboardDetails = leaderboardConfiguration.getLeaderboardDetails(this.regatta.toString());
+ leaderboardDetails.linkRace(this.leaderboardRaces.get(0), this.trackedRaces.get(0));
+ leaderboardDetails.linkRace(this.leaderboardRaces.get(1), this.trackedRaces.get(1));
+ leaderboardDetails.linkRace(this.leaderboardRaces.get(2), this.trackedRaces.get(2));
+ leaderboardDetails.linkRace(this.leaderboardRaces.get(3), this.trackedRaces.get(3));
+ leaderboardDetails.linkRace(this.leaderboardRaces.get(4), this.trackedRaces.get(4));
+ // Open the leaderboard in our second window
+ leaderboardWindow.switchToWindow();
+ LeaderboardPage leaderboard = LeaderboardPage.goToPage(getWebDriver(), getContextRoot(), LEADERBOARD, false);
+ LeaderboardTablePO table = leaderboard.getLeaderboardTable();
+ // Go back to the administration console and delete third race
+ adminConsoleWindow.switchToWindow();
+ RegattaStructureManagementPanelPO regattaStructure = adminConsole.goToRegattaStructure();
+ RegattaDetailsCompositePO regattaDetails = regattaStructure.getRegattaDetails(this.regatta);
+ SeriesEditDialogPO seriesDialog = regattaDetails.editSeries(RegattaStructureManagementPanelPO.DEFAULT_SERIES_NAME);
+ seriesDialog.deleteRace("D3");
+ seriesDialog.pressOk(true, false);
+ final List expectedRaces = Arrays.asList("D1", "D2", "D4", "D5");
+ regattaDetails.waitForRacesOfSeries(RegattaStructureManagementPanelPO.DEFAULT_SERIES_NAME, expectedRaces);
+ // Now we can check the result with our expectation
+ leaderboardWindow.switchToWindow();
+ leaderboard.refresh();
+ assertThat("Race names do not match after deletion of race 'D3'", table.getRaceNames(),
+ equalTo(expectedRaces));
+ });
}
@Ignore("This test belongs to bug 1892 and currently fails. It is currently enabled on branch bug1892.")
@Test
public void testDynamicRenamingOfRace() {
- WindowManager manager = this.environment.getWindowManager();
- WebDriverWindow adminConsoleWindow = manager.getCurrentWindow();
- WebDriverWindow leaderboardWindow = manager.openNewWindow();
-
- // Go to the administration console and link all 5 races
- AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
- LeaderboardConfigurationPanelPO leaderboardConfiguration = adminConsole.goToLeaderboardConfiguration();
- LeaderboardDetailsPanelPO leaderboardDetails = leaderboardConfiguration.getLeaderboardDetails(this.regatta.toString());
-
- leaderboardDetails.linkRace(this.leaderboardRaces.get(0), this.trackedRaces.get(0));
- leaderboardDetails.linkRace(this.leaderboardRaces.get(1), this.trackedRaces.get(1));
- leaderboardDetails.linkRace(this.leaderboardRaces.get(2), this.trackedRaces.get(2));
- leaderboardDetails.linkRace(this.leaderboardRaces.get(3), this.trackedRaces.get(3));
- leaderboardDetails.linkRace(this.leaderboardRaces.get(4), this.trackedRaces.get(4));
-
- // Open the leaderboard in our second window
- leaderboardWindow.switchToWindow();
-
- LeaderboardPage leaderboard = LeaderboardPage.goToPage(getWebDriver(), getContextRoot(), LEADERBOARD, false);
- LeaderboardTablePO table = leaderboard.getLeaderboardTable();
-
- // Go back to the administration console and rename the first race
- adminConsoleWindow.switchToWindow();
-
- RegattaStructureManagementPanelPO regattaStructure = adminConsole.goToRegattaStructure();
- RegattaDetailsCompositePO regattaDetails = regattaStructure.getRegattaDetails(this.regatta);
- SeriesEditDialogPO seriesDialog = regattaDetails.editSeries(RegattaStructureManagementPanelPO.DEFAULT_SERIES_NAME);
- seriesDialog.renameRace("D1", "Q");
- seriesDialog.pressOk(true);
-
- // Now we can check the result with our expectation
- leaderboardWindow.switchToWindow();
- leaderboard.refresh();
- List races = table.getRaceNames();
- assertThat("Race names do not match after renaming race 'D1' to 'Q'",
- races, equalTo(Arrays.asList("Q", "D2", "D3", "D4", "D5")));
+ this.environment.getWindowManager().withExtraWindow((adminConsoleWindow, leaderboardWindow) -> {
+ // Go to the administration console and link all 5 races
+ AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot());
+ LeaderboardConfigurationPanelPO leaderboardConfiguration = adminConsole.goToLeaderboardConfiguration();
+ LeaderboardDetailsPanelPO leaderboardDetails = leaderboardConfiguration.getLeaderboardDetails(this.regatta.toString());
+
+ leaderboardDetails.linkRace(this.leaderboardRaces.get(0), this.trackedRaces.get(0));
+ leaderboardDetails.linkRace(this.leaderboardRaces.get(1), this.trackedRaces.get(1));
+ leaderboardDetails.linkRace(this.leaderboardRaces.get(2), this.trackedRaces.get(2));
+ leaderboardDetails.linkRace(this.leaderboardRaces.get(3), this.trackedRaces.get(3));
+ leaderboardDetails.linkRace(this.leaderboardRaces.get(4), this.trackedRaces.get(4));
+
+ // Open the leaderboard in our second window
+ leaderboardWindow.switchToWindow();
+
+ LeaderboardPage leaderboard = LeaderboardPage.goToPage(getWebDriver(), getContextRoot(), LEADERBOARD, false);
+ LeaderboardTablePO table = leaderboard.getLeaderboardTable();
+
+ // Go back to the administration console and rename the first race
+ adminConsoleWindow.switchToWindow();
+
+ RegattaStructureManagementPanelPO regattaStructure = adminConsole.goToRegattaStructure();
+ RegattaDetailsCompositePO regattaDetails = regattaStructure.getRegattaDetails(this.regatta);
+ SeriesEditDialogPO seriesDialog = regattaDetails.editSeries(RegattaStructureManagementPanelPO.DEFAULT_SERIES_NAME);
+ seriesDialog.renameRace("D1", "Q");
+ seriesDialog.pressOk(true, false);
+
+ // Now we can check the result with our expectation
+ leaderboardWindow.switchToWindow();
+ leaderboard.refresh();
+ List races = table.getRaceNames();
+ assertThat("Race names do not match after renaming race 'D1' to 'Q'",
+ races, equalTo(Arrays.asList("Q", "D2", "D3", "D4", "D5")));
+ });
}
private void configureLeaderboard() {
@@ -209,20 +203,10 @@ public class TestLeaderboardConfiguration extends AbstractSeleniumTest {
tracTracEvents.listTrackableRaces(IDM_5O5_2013_JSON_URL);
tracTracEvents.setReggataForTracking(this.regatta);
tracTracEvents.setTrackSettings(false, false, false);
- // TODO: There exists a bug in Selenium with key modifiers (Issue 3734 and 6817), so we can't use multi
- // selection (Firefox on Windows)
- //tracTracEvents.startTrackingForRaces(this.trackableRaces);
- for(TrackableRaceDescriptor race : this.trackableRaces) {
- tracTracEvents.startTrackingForRace(race);
- }
+ tracTracEvents.startTrackingForRaces(trackableRaces);
TrackedRacesListPO trackedRacesList = tracTracEvents.getTrackedRacesList();
trackedRacesList.waitForTrackedRaces(this.trackedRaces, Status.FINISHED); // TracAPI puts REPLAY races into FINISHED mode when done loading
- // TODO: There exists a bug in Selenium with key modifiers (Issue 3734 and 6817), so we can't use multi
- // selection (Firefox on Windows)
- //trackedRacesList.stopTracking(this.trackedRaces);
- for (TrackedRaceDescriptor race : this.trackedRaces) {
- trackedRacesList.stopTracking(race);
- }
+ trackedRacesList.stopTracking(this.trackedRaces);
}
}
diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboard/TestSwitchingOffStartOfRaceInference.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboard/TestSwitchingOffStartOfRaceInference.java
index ce286462c33..6f8a664a726 100755
--- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboard/TestSwitchingOffStartOfRaceInference.java
+++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/leaderboard/TestSwitchingOffStartOfRaceInference.java
@@ -11,8 +11,6 @@ import java.util.List;
import org.junit.Before;
import org.junit.Test;
-import com.sap.sailing.selenium.core.WebDriverWindow;
-import com.sap.sailing.selenium.core.WindowManager;
import com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage;
import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardConfigurationPanelPO;
import com.sap.sailing.selenium.pages.adminconsole.leaderboard.LeaderboardDetailsPanelPO;
@@ -62,33 +60,31 @@ public class TestSwitchingOffStartOfRaceInference extends AbstractSeleniumTest {
@Test
public void testCorrectDisplayOfRaceColumnWithAndWithoutStartTimeInference() {
- WindowManager manager = this.environment.getWindowManager();
- WebDriverWindow adminConsoleWindow = manager.getCurrentWindow();
- WebDriverWindow leaderboardWindow = manager.openNewWindow();
- leaderboardWindow.switchToWindow();
- LeaderboardPage leaderboard = LeaderboardPage.goToPage(getWebDriver(), getContextRoot(), LEADERBOARD, /* race details */ false);
- LeaderboardTablePO leaderboardTable = leaderboard.getLeaderboardTable();
- List races = leaderboardTable.getRaceNames();
- assertThat("Expected only D3", races, equalTo(Arrays.asList("D3")));
- int d3ColumnIndex = leaderboardTable.getColumnIndex("D3");
- for (LeaderboardEntry e : leaderboardTable.getEntries()) {
- String raceColumnContent = e.getColumnContent(d3ColumnIndex);
- assertTrue(Integer.parseInt(raceColumnContent) > 0); // all competitors have a positive score in R3
- }
- adminConsoleWindow.switchToWindow();
- // Go to the administration console and unset the "useStartTimeInference" flag
- RegattaStructureManagementPanelPO regattaManagementPanel = adminConsole.goToRegattaStructure();
- RegattaListCompositePO regattaList = regattaManagementPanel.getRegattaList();
- RegattaEditDialogPO regattaEditDialog = regattaList.editRegatta(regatta);
- regattaEditDialog.setUseStartTimeInference(false);
- regattaEditDialog.pressOk();
- leaderboardWindow.switchToWindow();
- leaderboard.refresh();
- for (LeaderboardEntry e : leaderboardTable.getEntries()) {
- String raceColumnContent = e.getColumnContent(d3ColumnIndex);
- assertEquals("", raceColumnContent); // all competitors have an empty score because there is no start time anymore
- }
- leaderboardWindow.close();
+ this.environment.getWindowManager().withExtraWindow((adminConsoleWindow, leaderboardWindow) -> {
+ leaderboardWindow.switchToWindow();
+ LeaderboardPage leaderboard = LeaderboardPage.goToPage(getWebDriver(), getContextRoot(), LEADERBOARD, /* race details */ false);
+ LeaderboardTablePO leaderboardTable = leaderboard.getLeaderboardTable();
+ List races = leaderboardTable.getRaceNames();
+ assertThat("Expected only D3", races, equalTo(Arrays.asList("D3")));
+ int d3ColumnIndex = leaderboardTable.getColumnIndex("D3");
+ for (LeaderboardEntry e : leaderboardTable.getEntries()) {
+ String raceColumnContent = e.getColumnContent(d3ColumnIndex);
+ assertTrue(Integer.parseInt(raceColumnContent) > 0); // all competitors have a positive score in R3
+ }
+ adminConsoleWindow.switchToWindow();
+ // Go to the administration console and unset the "useStartTimeInference" flag
+ RegattaStructureManagementPanelPO regattaManagementPanel = adminConsole.goToRegattaStructure();
+ RegattaListCompositePO regattaList = regattaManagementPanel.getRegattaList();
+ RegattaEditDialogPO regattaEditDialog = regattaList.editRegatta(regatta);
+ regattaEditDialog.setUseStartTimeInference(false);
+ regattaEditDialog.pressOk();
+ leaderboardWindow.switchToWindow();
+ leaderboard.refresh();
+ for (LeaderboardEntry e : leaderboardTable.getEntries()) {
+ String raceColumnContent = e.getColumnContent(d3ColumnIndex);
+ assertEquals("", raceColumnContent); // all competitors have an empty score because there is no start time anymore
+ }
+ });
}
private AdminConsolePage configureRegattaAndLeaderboard() {
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..46c078b499e 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
@@ -77,7 +77,6 @@ public class SettingsTest extends AbstractSeleniumTest {
// Modes settings were formerly patched on the user defaults but are now patched on top of the system defaults.
// In addition, there are now different settigns keys per mode so that settigns for one mode do not have an effect on other modes.
// To verify this, there are new tests below but these do not test ReceBoard's embedded Leaderboard.
- // FIXME uncomment leaderboard test code when selenium infrastructure gets an upgrade
/**
* Verifies the settings storage of the raceboard. Checks the precedences of url, context specific settings, mode
* settings and global settings.
@@ -95,35 +94,29 @@ public class SettingsTest extends AbstractSeleniumTest {
RaceBoardPage raceboard = RaceBoardPage.goToRaceboardUrl(getWebDriver(), getContextRoot(), BMW_CUP_REGATTA,
BMW_CUP_REGATTA, String.format(BMW_RACE, 1), "PLAYER");
- //FIXME uncomment the leaderboard code when selenium on remote build server displays the raceboard properly
+ DetailCheckboxInfo[] detailsToSelect = new DetailCheckboxInfo[] {
+ // Overall details
-// DetailCheckboxInfo[] detailsToSelect = new DetailCheckboxInfo[] {
-// // Overall details
-//
-// // Race details
-// DetailCheckboxInfo.RACE_GAP_TO_LEADER,
-// DetailCheckboxInfo.RACE_CURRENT_SPEED_OVER_GROUND,
-// DetailCheckboxInfo.DISPLAY_LEGS,
-//
-// // Race Start Analysis
-//
-// // Leg Details
-// DetailCheckboxInfo.AVERAGE_SPEED_OVER_GROUND, DetailCheckboxInfo.DISTANCE, DetailCheckboxInfo.RANK_GAIN,
-//
-// // Maneuvers
-// DetailCheckboxInfo.TACK, DetailCheckboxInfo.JIBE,
-// DetailCheckboxInfo.PENALTY_CIRCLE
-//
-// };
-//
-// LeaderboardSettingsDialogPO leaderboardSettingsDialog = raceboard.openLeaderboardSettingsDialog();
-// LeaderboardSettingsPanelPO leaderboardSettingsPanelPO =
-// leaderboardSettingsDialog.getLeaderboardSettingsPanelPO();
-// DetailCheckboxInfo[] selectedDetails = leaderboardSettingsPanelPO.getSelectedDetails();
-// Assert.assertArrayEquals(detailsToSelect, selectedDetails);
-// leaderboardSettingsPanelPO.setRefreshInterval(2);
-// leaderboardSettingsDialog.pressMakeDefault();
-// leaderboardSettingsDialog.pressCancel();
+ // Race details
+ DetailCheckboxInfo.RACE_GAP_TO_LEADER, DetailCheckboxInfo.RACE_CURRENT_SPEED_OVER_GROUND,
+ DetailCheckboxInfo.DISPLAY_LEGS,
+
+ // Leg Details
+ DetailCheckboxInfo.AVERAGE_SPEED_OVER_GROUND, DetailCheckboxInfo.DISTANCE, DetailCheckboxInfo.RANK_GAIN,
+
+ // Maneuvers
+ DetailCheckboxInfo.TACK, DetailCheckboxInfo.JIBE, DetailCheckboxInfo.PENALTY_CIRCLE
+
+ };
+
+ LeaderboardSettingsDialogPO leaderboardSettingsDialog = raceboard.openLeaderboardSettingsDialog();
+ LeaderboardSettingsPanelPO leaderboardSettingsPanelPO = leaderboardSettingsDialog
+ .getLeaderboardSettingsPanelPO();
+ DetailCheckboxInfo[] selectedDetails = leaderboardSettingsPanelPO.getSelectedDetails();
+ Assert.assertArrayEquals(detailsToSelect, selectedDetails);
+ leaderboardSettingsPanelPO.setRefreshInterval(2);
+ leaderboardSettingsDialog.pressMakeDefault();
+ leaderboardSettingsDialog.pressCancel();
MapSettingsPO mapSettings = raceboard.openMapSettings();
// Verify initial mode settings
@@ -136,58 +129,38 @@ public class SettingsTest extends AbstractSeleniumTest {
raceboard = RaceBoardPage.goToRaceboardUrl(getWebDriver(), getContextRoot(), BMW_CUP_REGATTA, BMW_CUP_REGATTA,
String.format(BMW_RACE, 1), "WINNING_LANES");
-// detailsToSelect = new DetailCheckboxInfo[] {
-// // Overall details
-//
-// // Race details
-// DetailCheckboxInfo.RACE_GAP_TO_LEADER, //merged from user settings
-// DetailCheckboxInfo.RACE_DISTANCE,
-// DetailCheckboxInfo.RACE_TIME,
-// DetailCheckboxInfo.RACE_CURRENT_SPEED_OVER_GROUND, //merged from user settings
-// DetailCheckboxInfo.RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR,
-// DetailCheckboxInfo.RACE_AVERAGE_SIGNED_CROSS_TRACK_ERROR,
-//
-// // Race Start Analysis
-//
-// // Leg Details
-// DetailCheckboxInfo.AVERAGE_SPEED_OVER_GROUND, DetailCheckboxInfo.DISTANCE, DetailCheckboxInfo.RANK_GAIN,
-//
-// // Maneuvers
-// DetailCheckboxInfo.TACK, DetailCheckboxInfo.JIBE,
-// DetailCheckboxInfo.PENALTY_CIRCLE
-//
-// };
-//
-//
-// leaderboardSettingsDialog = raceboard.openLeaderboardSettingsDialog();
-// leaderboardSettingsPanelPO = leaderboardSettingsDialog.getLeaderboardSettingsPanelPO();
-// selectedDetails = leaderboardSettingsPanelPO.getSelectedDetails();
-// Assert.assertArrayEquals(detailsToSelect, selectedDetails);
-//
-// detailsToSelect = new DetailCheckboxInfo[] {
-// // Overall details
-//
-// // Race details
-// DetailCheckboxInfo.RACE_GAP_TO_LEADER,
-// DetailCheckboxInfo.RACE_DISTANCE,
-// DetailCheckboxInfo.RACE_TIME,
-// DetailCheckboxInfo.RACE_CURRENT_SPEED_OVER_GROUND,
-// DetailCheckboxInfo.RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL, //new value
-// DetailCheckboxInfo.DISPLAY_LEGS, //new value which should override mode settings
-//
-// // Race Start Analysis
-//
-// // Leg Details
-// DetailCheckboxInfo.AVERAGE_SPEED_OVER_GROUND, DetailCheckboxInfo.DISTANCE, DetailCheckboxInfo.RANK_GAIN,
-//
-// // Maneuvers
-// DetailCheckboxInfo.TACK, DetailCheckboxInfo.JIBE,
-// DetailCheckboxInfo.PENALTY_CIRCLE
-//
-// };
-// leaderboardSettingsPanelPO.selectDetailsAndDeselectOther(detailsToSelect);
-// leaderboardSettingsPanelPO.setRefreshInterval(1);
-// leaderboardSettingsDialog.pressOk();
+ detailsToSelect = new DetailCheckboxInfo[] {
+ // Race details
+ DetailCheckboxInfo.RACE_DISTANCE, DetailCheckboxInfo.RACE_TIME,
+ DetailCheckboxInfo.RACE_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR,
+ DetailCheckboxInfo.RACE_AVERAGE_SIGNED_CROSS_TRACK_ERROR,
+ // Leg Details
+ DetailCheckboxInfo.AVERAGE_SPEED_OVER_GROUND, DetailCheckboxInfo.DISTANCE, DetailCheckboxInfo.RANK_GAIN,
+ // Maneuvers
+ DetailCheckboxInfo.TACK, DetailCheckboxInfo.JIBE, DetailCheckboxInfo.PENALTY_CIRCLE
+
+ };
+
+ leaderboardSettingsDialog = raceboard.openLeaderboardSettingsDialog();
+ leaderboardSettingsPanelPO = leaderboardSettingsDialog.getLeaderboardSettingsPanelPO();
+ selectedDetails = leaderboardSettingsPanelPO.getSelectedDetails();
+ Assert.assertArrayEquals(detailsToSelect, selectedDetails);
+
+ detailsToSelect = new DetailCheckboxInfo[] {
+ // Race details
+ DetailCheckboxInfo.RACE_GAP_TO_LEADER, DetailCheckboxInfo.RACE_DISTANCE, DetailCheckboxInfo.RACE_TIME,
+ DetailCheckboxInfo.RACE_CURRENT_SPEED_OVER_GROUND,
+ DetailCheckboxInfo.RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL,
+ DetailCheckboxInfo.DISPLAY_LEGS,
+ // Leg Details
+ DetailCheckboxInfo.AVERAGE_SPEED_OVER_GROUND, DetailCheckboxInfo.DISTANCE, DetailCheckboxInfo.RANK_GAIN,
+ // Maneuvers
+ DetailCheckboxInfo.TACK, DetailCheckboxInfo.JIBE, DetailCheckboxInfo.PENALTY_CIRCLE
+
+ };
+ leaderboardSettingsPanelPO.selectDetailsAndDeselectOther(detailsToSelect);
+ leaderboardSettingsPanelPO.setRefreshInterval(1);
+ leaderboardSettingsDialog.pressOk(false, false);
mapSettings = raceboard.openMapSettings();
// verify default mode settings override custom user settings
@@ -198,21 +171,22 @@ public class SettingsTest extends AbstractSeleniumTest {
Assert.assertFalse(mapSettings.isTransparentHoverlines());
mapSettings.setWindUp(false);
mapSettings.setTransparentHoverlines(false);
- mapSettings.pressOk();
+
+ mapSettings.pressOk(false, false);
raceboard = RaceBoardPage.goToRaceboardUrl(getWebDriver(), getContextRoot(), BMW_CUP_REGATTA, BMW_CUP_REGATTA,
String.format(BMW_RACE, 1), "WINNING_LANES");
-// leaderboardSettingsDialog = raceboard.openLeaderboardSettingsDialog();
-// leaderboardSettingsPanelPO = leaderboardSettingsDialog.getLeaderboardSettingsPanelPO();
-// selectedDetails = leaderboardSettingsPanelPO.getSelectedDetails();
-//
-// //verify highest precedence of document settings
-// Assert.assertArrayEquals(detailsToSelect, selectedDetails);
-// //verify that document settings are able to override custom user settings by a system default value
-// Assert.assertEquals(1, leaderboardSettingsPanelPO.getRefreshInterval());
-//
-// leaderboardSettingsDialog.pressCancel();
+ leaderboardSettingsDialog = raceboard.openLeaderboardSettingsDialog();
+ leaderboardSettingsPanelPO = leaderboardSettingsDialog.getLeaderboardSettingsPanelPO();
+ selectedDetails = leaderboardSettingsPanelPO.getSelectedDetails();
+
+ // verify highest precedence of document settings
+ Assert.assertArrayEquals(detailsToSelect, selectedDetails);
+ // verify that document settings are able to override custom user settings by a system default value
+ Assert.assertEquals(1, leaderboardSettingsPanelPO.getRefreshInterval());
+
+ leaderboardSettingsDialog.pressCancel();
mapSettings = raceboard.openMapSettings();
// Verify that mode settings are overridden by document settings
@@ -222,35 +196,29 @@ public class SettingsTest extends AbstractSeleniumTest {
//FIXME uncomment when START_ANALYSIS mode can be handled by remote CI server
// verify that custom document settings override mode settings of other modes
-// raceboard = RaceBoardPage.goToRaceboardUrl(getWebDriver(), getContextRoot(), BMW_CUP_REGATTA,
-// BMW_CUP_REGATTA,
-// String.format(BMW_RACE, 1), "START_ANALYSIS");
-// leaderboardSettingsDialog = raceboard.openLeaderboardSettingsDialog();
-// leaderboardSettingsPanelPO = leaderboardSettingsDialog.getLeaderboardSettingsPanelPO();
-// selectedDetails = leaderboardSettingsPanelPO.getSelectedDetails();
-//
-// detailsToSelect = new DetailCheckboxInfo[] {
-// DetailCheckboxInfo.RACE_GAP_TO_LEADER, //start analysis mode
-// DetailCheckboxInfo.RACE_CURRENT_SPEED_OVER_GROUND, //user settings
-// DetailCheckboxInfo.DISPLAY_LEGS, //document settings which override mode settings
-// DetailCheckboxInfo.RACE_RATIO_BETWEEN_TIME_SINCE_LAST_POSITION_FIX_AND_AVERAGE_SAMPLING_INTERVAL, //document settings
-// DetailCheckboxInfo.RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_START, //start analysis mode
-// DetailCheckboxInfo.RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START, //start analysis mode
-// DetailCheckboxInfo.DISTANCE_TO_START_AT_RACE_START, //start analysis mode
-// DetailCheckboxInfo.SPEED_OVER_GROUND_AT_RACE_START, //start analysis mode
-// DetailCheckboxInfo.SPEED_OVER_GROUND_WHEN_STARTING, //start analysis mode
-// DetailCheckboxInfo.DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_STARTING, //start analysis mode
-// DetailCheckboxInfo.START_TACK, //start analysis mode
-//
-// DetailCheckboxInfo.AVERAGE_SPEED_OVER_GROUND, DetailCheckboxInfo.DISTANCE, DetailCheckboxInfo.RANK_GAIN,
-//
-// DetailCheckboxInfo.TACK, DetailCheckboxInfo.JIBE, DetailCheckboxInfo.PENALTY_CIRCLE
-// };
-// Assert.assertArrayEquals(detailsToSelect, selectedDetails);
-// leaderboardSettingsDialog.pressCancel();
-//
-// mapSettings = raceboard.openMapSettings();
-// Assert.assertFalse(mapSettings.isWindUp());
+ raceboard = RaceBoardPage.goToRaceboardUrl(getWebDriver(), getContextRoot(), BMW_CUP_REGATTA, BMW_CUP_REGATTA,
+ String.format(BMW_RACE, 1), "START_ANALYSIS");
+ leaderboardSettingsDialog = raceboard.openLeaderboardSettingsDialog();
+ leaderboardSettingsPanelPO = leaderboardSettingsDialog.getLeaderboardSettingsPanelPO();
+ selectedDetails = leaderboardSettingsPanelPO.getSelectedDetails();
+
+ detailsToSelect = new DetailCheckboxInfo[] { DetailCheckboxInfo.RACE_GAP_TO_LEADER, // start analysis mode
+ DetailCheckboxInfo.RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_START, // start analysis mode
+ DetailCheckboxInfo.RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START, // start analysis mode
+ DetailCheckboxInfo.DISTANCE_TO_START_AT_RACE_START, // start analysis mode
+ DetailCheckboxInfo.SPEED_OVER_GROUND_AT_RACE_START, // start analysis mode
+ DetailCheckboxInfo.SPEED_OVER_GROUND_WHEN_STARTING, // start analysis mode
+ DetailCheckboxInfo.DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_STARTING, // start analysis mode
+ DetailCheckboxInfo.START_TACK, // start analysis mode
+
+ DetailCheckboxInfo.AVERAGE_SPEED_OVER_GROUND, DetailCheckboxInfo.DISTANCE, DetailCheckboxInfo.RANK_GAIN,
+
+ DetailCheckboxInfo.TACK, DetailCheckboxInfo.JIBE, DetailCheckboxInfo.PENALTY_CIRCLE };
+ Assert.assertArrayEquals(detailsToSelect, selectedDetails);
+ leaderboardSettingsDialog.pressCancel();
+
+ mapSettings = raceboard.openMapSettings();
+ Assert.assertTrue(mapSettings.isWindUp());
}
/**
@@ -687,7 +655,7 @@ public class SettingsTest extends AbstractSeleniumTest {
// open settings dialog of configurated leaderboard with default values
LeaderboardSettingsDialogPO leaderboardSettingsDialog = leaderboardPage.getLeaderboardSettings();
- LeaderboardSettingsPanelPO leaderboardSettingsPanel = leaderboardPage.getLeaderboardSettings()
+ LeaderboardSettingsPanelPO leaderboardSettingsPanel = leaderboardSettingsDialog
.getLeaderboardSettingsPanelPO();
// store default values for checks later
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 a4dbff6c389..684004762c7 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
@@ -62,7 +62,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);
@@ -71,8 +73,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.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/RaceStateSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/RaceStateSerializer.java
index 5ad592fbc2b..0b87b9c86e4 100644
--- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/RaceStateSerializer.java
+++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/RaceStateSerializer.java
@@ -45,7 +45,7 @@ public class RaceStateSerializer implements JsonSerializer result;
if (leaderboard instanceof HasRegattaLike && raceLog != null) {
- ReadonlyRaceState state = ReadonlyRaceStateImpl.create(/* race log resolver */ this, raceLog);
+ ReadonlyRaceState state = ReadonlyRaceStateImpl.getOrCreate(/* race log resolver */ this, raceLog);
result = new com.sap.sse.common.Util.Triple(state.getStartTime(),
raceLog.getCurrentPassId(), state.getRacingProcedure().getType());
} else {
@@ -3652,7 +3652,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
Leaderboard leaderboard = getLeaderboardByName(leaderboardName);
final Triple result;
if (leaderboard instanceof HasRegattaLike && raceLog != null) {
- ReadonlyRaceState state = ReadonlyRaceStateImpl.create(/* race log resolver */ this, raceLog);
+ ReadonlyRaceState state = ReadonlyRaceStateImpl.getOrCreate(/* race log resolver */ this, raceLog);
result = new com.sap.sse.common.Util.Triple<>(state.getFinishingTime(), state.getFinishedTime(),
raceLog.getCurrentPassId());
} else {
diff --git a/java/com.sap.sailing.simulator.test/.project b/java/com.sap.sailing.simulator.test/.project
index 348d1ccbb59..6e91001fe19 100644
--- a/java/com.sap.sailing.simulator.test/.project
+++ b/java/com.sap.sailing.simulator.test/.project
@@ -22,12 +22,12 @@
- com.google.gdt.eclipse.core.webAppProjectValidator
+ com.gwtplugins.gdt.eclipse.core.webAppProjectValidator
- com.google.gwt.eclipse.core.gwtProjectValidator
+ com.gwtplugins.gwt.eclipse.core.gwtProjectValidator
@@ -35,6 +35,6 @@
org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
- com.google.gwt.eclipse.core.gwtNature
+ com.gwtplugins.gwt.eclipse.core.gwtNature
diff --git a/java/com.sap.sailing.simulator/.project b/java/com.sap.sailing.simulator/.project
index 3f09d9050b0..f86820f24df 100644
--- a/java/com.sap.sailing.simulator/.project
+++ b/java/com.sap.sailing.simulator/.project
@@ -21,12 +21,12 @@
- com.google.gdt.eclipse.core.webAppProjectValidator
+ com.gwtplugins.gdt.eclipse.core.webAppProjectValidator
- com.google.gwt.eclipse.core.gwtProjectValidator
+ com.gwtplugins.gwt.eclipse.core.gwtProjectValidator
@@ -34,6 +34,6 @@
org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
- com.google.gwt.eclipse.core.gwtNature
+ com.gwtplugins.gwt.eclipse.core.gwtNature
diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html
index daafe6c3709..f5a4d1f5b0d 100755
--- a/java/com.sap.sailing.www/release_notes_admin.html
+++ b/java/com.sap.sailing.www/release_notes_admin.html
@@ -22,6 +22,15 @@
Release Notes - Administration Console
+
July 2018
+
+
The mark passing editor now uses a full date/time format for the mark passing time points.
+
The TracTrac connector panel no longer shows a password visibly but uses a password text field.
+
The SwissTiming connector can now handle an "Update URL" together with username/password access
+ credentials which are used, if present, to send feedback requests about start times, race status
+ and course changes to that URL.
+
+
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 +41,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.common/.project b/java/com.sap.sse.common/.project
index 8aff8541cda..c28bb7a5e5a 100644
--- a/java/com.sap.sse.common/.project
+++ b/java/com.sap.sse.common/.project
@@ -21,12 +21,12 @@
- com.google.gdt.eclipse.core.webAppProjectValidator
+ com.gwtplugins.gdt.eclipse.core.webAppProjectValidator
- com.google.gwt.eclipse.core.gwtProjectValidator
+ com.gwtplugins.gwt.eclipse.core.gwtProjectValidator
@@ -34,6 +34,6 @@
org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
- com.google.gwt.eclipse.core.gwtNature
+ com.gwtplugins.gwt.eclipse.core.gwtNature
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