null, no leg details are known yet, the race is not being tracked or the details
@@ -142,9 +142,9 @@ public class LeaderboardEntryDTO implements Serializable {
result = prime * result
+ ((gapToLeaderInOwnTime == null) ? 0 : gapToLeaderInOwnTime.hashCode());
result = prime * result
- + ((correctedTime == null) ? 0 : correctedTime.hashCode());
+ + ((calculatedTime == null) ? 0 : calculatedTime.hashCode());
result = prime * result
- + ((correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) ? 0 : correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.hashCode());
+ + ((calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) ? 0 : calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.hashCode());
result = prime * result
+ ((averageSignedCrossTrackErrorInMeters == null) ? 0 : averageSignedCrossTrackErrorInMeters.hashCode());
result = prime * result + (discarded ? 1231 : 1237);
@@ -179,7 +179,7 @@ public class LeaderboardEntryDTO implements Serializable {
result = prime * result + ((totalPoints == null) ? 0 : totalPoints.hashCode());
result = prime
* result
- + ((windwardDistanceToOverallLeaderInMeters == null) ? 0 : windwardDistanceToOverallLeaderInMeters
+ + ((windwardDistanceToCompetitorFarthestAheadInMeters == null) ? 0 : windwardDistanceToCompetitorFarthestAheadInMeters
.hashCode());
return result;
}
@@ -198,15 +198,15 @@ public class LeaderboardEntryDTO implements Serializable {
return false;
} else if (!gapToLeaderInOwnTime.equals(other.gapToLeaderInOwnTime))
return false;
- if (correctedTime == null) {
- if (other.correctedTime != null)
+ if (calculatedTime == null) {
+ if (other.calculatedTime != null)
return false;
- } else if (!correctedTime.equals(other.correctedTime))
+ } else if (!calculatedTime.equals(other.calculatedTime))
return false;
- if (correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) {
- if (other.correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead != null)
+ if (calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) {
+ if (other.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead != null)
return false;
- } else if (!correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.equals(other.correctedTimeAtEstimatedArrivalAtCompetitorFarthestAhead))
+ } else if (!calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.equals(other.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead))
return false;
if (averageAbsoluteCrossTrackErrorInMeters == null) {
if (other.averageAbsoluteCrossTrackErrorInMeters != null)
@@ -297,10 +297,10 @@ public class LeaderboardEntryDTO implements Serializable {
return false;
} else if (!totalPoints.equals(other.totalPoints))
return false;
- if (windwardDistanceToOverallLeaderInMeters == null) {
- if (other.windwardDistanceToOverallLeaderInMeters != null)
+ if (windwardDistanceToCompetitorFarthestAheadInMeters == null) {
+ if (other.windwardDistanceToCompetitorFarthestAheadInMeters != null)
return false;
- } else if (!windwardDistanceToOverallLeaderInMeters.equals(other.windwardDistanceToOverallLeaderInMeters))
+ } else if (!windwardDistanceToCompetitorFarthestAheadInMeters.equals(other.windwardDistanceToCompetitorFarthestAheadInMeters))
return false;
return true;
}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/ImageSizeImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/ImageSizeImpl.java
index 1c6ef6246d1..fb15291dca8 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/ImageSizeImpl.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/ImageSizeImpl.java
@@ -1,6 +1,6 @@
package com.sap.sailing.domain.common.impl;
-import com.sap.sailing.domain.common.ImageSize;
+import com.sap.sse.common.media.ImageSize;
public class ImageSizeImpl implements ImageSize {
private static final long serialVersionUID = 1170701774852068780L;
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaCategory.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaCategory.java
deleted file mode 100644
index 1419e5bd7c4..00000000000
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaCategory.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.sap.sailing.domain.common.media;
-
-public enum MediaCategory {
- highlight, livestream;
-}
\ No newline at end of file
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java
index f630c43596c..74c855dcba9 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/media/MediaTrack.java
@@ -8,6 +8,8 @@ import java.util.Set;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
+import com.sap.sse.common.media.MediaSubType;
+import com.sap.sse.common.media.MimeType;
/**
* See http://my.opera.com/core/blog/2010/03/03/everything-you-need-to-know-about-html5-video-and-audio-2
diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/MediaDB.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/MediaDB.java
index 284322a59d1..93b272be5e2 100644
--- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/MediaDB.java
+++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/media/MediaDB.java
@@ -6,9 +6,9 @@ import java.util.Set;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.media.MediaTrack;
-import com.sap.sailing.domain.common.media.MimeType;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
+import com.sap.sse.common.media.MimeType;
/**
* Offers CRUD methods for mongo representation of media track objects.
@@ -17,7 +17,7 @@ import com.sap.sse.common.TimePoint;
*
*/
public interface MediaDB {
-
+
/**
* Stores a new track to the database, returning the db-generated id.
*/
@@ -40,7 +40,7 @@ public interface MediaDB {
TimePoint startTime, Duration duration, MimeType mimeType,
Setnull values in {@link ConcurrentHashMap} instances which do not accept
+ * null as key nor value.
+ */
+ private final static Competitor NULL_COMPETITOR = new CompetitorImpl(null, null, null, null, null, null, null, null, null);
+
+ public abstract class AbstractRankingInfo implements RankingMetric.RankingInfo {
+ private static final long serialVersionUID = 6845168655725234325L;
+
/**
* The time point for which this ranking information is valid
*/
private final TimePoint timePoint;
+ /**
+ * Caches, on demand, the results of calls to {@link #getCompetitorFarthestAheadInLeg(Leg, TimePoint, WindLegTypeAndLegBearingCache)}.
+ * null values are encoded as the {@link #NULL_COMPETITOR} and must be translated back to null before returning
+ * to a caller outside of this class.
+ */
+ private final ConcurrentHashMapnull if no competitor has started the leg yet; the first competitor to finish the leg if any
+ * has already finished the leg at timePoint; or the competitor with the greatest windward
+ * distance traveled in the leg at timePoint otherwise
+ */
+ protected Competitor getCompetitorFarthestAheadInLeg(TrackedLeg trackedLeg, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) {
+ Competitor firstAroundMark = getFirstLegFinisherBefore(trackedLeg, timePoint);
+ final Competitor result;
+ if (firstAroundMark != null) {
+ result = firstAroundMark;
+ } else {
+ IterabletrackedLeg at or before timePoint. If
+ * no such competitor exists, null is returned.
+ */
+ private Competitor getFirstLegFinisherBefore(TrackedLeg trackedLeg, TimePoint timePoint) {
+ Iterableleg.
+ * Instead, for those competitors who have already finished the leg, their
+ * {@link TrackedLegOfCompetitor#getFinishTime() finishing time} for the leg is used, and the distance traveled
+ * is normalized to the {@link TrackedLeg#getWindwardDistance() windward distance of the leg} at the
+ * {@link TrackedLeg#getReferenceTimePoint() reference time point}.
+ */
+ Competitor getLeaderInLegByCalculatedTime(Leg leg, WindLegTypeAndLegBearingCache cache);
+
+ Competitor getCompetitorFarthestAheadInLeg(Leg leg, TimePoint timePoint, WindLegTypeAndLegBearingCache cache);
+
+ Duration getActualTimeFromRaceStartToReachFarthestAheadInLeg(Competitor competitor, Leg leg, WindLegTypeAndLegBearingCache cache);
}
public interface LegRankingInfo extends Timed, Serializable {
@@ -178,7 +193,7 @@ public interface RankingMetric extends Serializable {
* @param competitor
* the competitor for which to tell the gap to the leader in competitor's own time
*
- * @see #getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor, TimePoint, WindLegTypeAndLegBearingCache)
+ * @see #getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor, TimePoint, com.sap.sailing.domain.ranking.RankingMetric.CompetitorRankingInfo.RankingInfo, WindLegTypeAndLegBearingCache)
*/
default Duration getGapToLeaderInOwnTime(RankingInfo rankingInfo, Competitor competitor) {
return getGapToLeaderInOwnTime(rankingInfo, competitor, new LeaderboardDTOCalculationReuseCache(rankingInfo.getTimePoint()));
@@ -205,6 +220,10 @@ public interface RankingMetric extends Serializable {
* handicap ranking is in effect) of the leg that the competitor is in at timePoint (or
* the last leg if timePoint is after competitor has finished the race). Returns
* null if timePoint is before competitor has started.
+ *
+ * @param rankingInfo
+ * tells about leader (by calculated time) and boat farthest ahead
*/
- Duration getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor trackedLegOfCompetitor, TimePoint timePoint, WindLegTypeAndLegBearingCache cache);
+ Duration getLegGapToLegLeaderInOwnTime(TrackedLegOfCompetitor trackedLegOfCompetitor, TimePoint timePoint,
+ RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache);
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java
index 5178f0de435..7b7821f117c 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/ranking/TimeOnTimeAndDistanceRankingMetric.java
@@ -2,7 +2,6 @@ package com.sap.sailing.domain.ranking;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -14,7 +13,6 @@ import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.Mile;
import com.sap.sailing.domain.common.Position;
-import com.sap.sailing.domain.common.impl.MeterDistance;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
@@ -106,8 +104,10 @@ public class TimeOnTimeAndDistanceRankingMetric extends AbstractRankingMetric {
// competitors that have not yet started the leg will get a duration based on Long.MAX_VALUE
final Mapnull if no competitor has started the leg yet; the first competitor to finish the leg if any
- * has already finished the leg at timePoint; or the competitor with the greatest windward
- * distance traveled in the leg at timePoint otherwise
- */
- private Competitor getCompetitorFarthestAheadInLeg(TrackedLeg trackedLeg, TimePoint timePoint, WindLegTypeAndLegBearingCache cache) {
- Competitor firstAroundMark = getFirstLegFinisherBefore(trackedLeg, timePoint);
- final Competitor result;
- if (firstAroundMark != null) {
- result = firstAroundMark;
} else {
- IterabletrackedLeg at or before timePoint. If
- * no such competitor exists, null is returned.
- */
- private Competitor getFirstLegFinisherBefore(TrackedLeg trackedLeg, TimePoint timePoint) {
- Iterablenull in case this leg's
* competitor hasn't started the leg yet.
+ * @param rankingInfo TODO
*/
- Duration getGapToLeader(TimePoint timePoint, WindPositionMode windPositionMode);
+ Duration getGapToLeader(TimePoint timePoint, RankingInfo rankingInfo, WindPositionMode windPositionMode);
/**
- * Same as {@link #getGapToLeader(TimePoint, WindPositionMode)}, only that a cache for wind and leg type data is used.
+ * Same as {@link #getGapToLeader(TimePoint, RankingInfo, WindPositionMode)}, only that a cache for wind and leg type data is used.
+ * @param rankingInfo TODO
*/
- Duration getGapToLeader(TimePoint timePoint, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache);
+ Duration getGapToLeader(TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache);
/**
* If a caller already went through the effort of computing the leg's leader at timePoint, it
- * can share this knowledge to speed up computation as compared to {@link #getGapToLeader(TimePoint, WindPositionMode)}.
+ * can share this knowledge to speed up computation as compared to {@link #getGapToLeader(TimePoint, RankingInfo, WindPositionMode)}.
+ * @param rankingInfo TODO
*/
- Duration getGapToLeader(TimePoint timePoint, Competitor leaderInLegAtTimePoint, WindPositionMode windPositionMode) throws NoWindException;
+ Duration getGapToLeader(TimePoint timePoint, Competitor leaderInLegAtTimePoint, RankingInfo rankingInfo, WindPositionMode windPositionMode) throws NoWindException;
/**
- * Same as {@link #getGapToLeader(TimePoint, Competitor, WindPositionMode)}, only that an additional cache is used
+ * Same as {@link #getGapToLeader(TimePoint, Competitor, RankingInfo, WindPositionMode)}, only that an additional cache is used
* to avoid redundant evaluations of leg types and wind field information across various calculations that
* all can use the same basic information.
+ * @param rankingInfo TODO
*/
Duration getGapToLeader(TimePoint timePoint, Competitor leaderInLegAtTimePoint,
- WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache);
+ WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache);
boolean hasStartedLeg(TimePoint timePoint);
@@ -228,14 +233,17 @@ public interface TrackedLegOfCompetitor extends Serializable {
* distance between this leg's competitor and the leader is returned. Note that this can lead to a situation where
* the distance to leader is unrelated to the {@link #getWindwardDistanceToGo(TimePoint, WindPositionMode) distance to go} which is
* used for ranking.
+ *
+ * @param rankingInfo materialized ranking information that is pre-calculated to avoid expensive redundant work
*/
- Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode);
+ Distance getWindwardDistanceToCompetitorFarthestAhead(TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo);
/**
- * Same as {@link #getWindwardDistanceToOverallLeader(TimePoint, WindPositionMode)}, only that a cache for leg type
+ * Same as {@link #getWindwardDistanceToCompetitorFarthestAhead(TimePoint, WindPositionMode, RankingInfo)}, only that a cache for leg type
* calculation is passed.
+ * @param rankingInfo TODO
*/
- Distance getWindwardDistanceToOverallLeader(TimePoint timePoint, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache);
+ Distance getWindwardDistanceToCompetitorFarthestAhead(TimePoint timePoint, WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache);
/**
* Computes the average absolute cross track error for this leg. The cross track error for each fix is taken to be a
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java
index f33ae238f70..c98280a45e8 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java
@@ -41,6 +41,7 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.ranking.RankingMetric;
+import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -515,17 +516,21 @@ public interface TrackedRace extends Serializable {
Distance getDistanceTraveledIncludingGateStart(Competitor competitor, TimePoint timePoint);
/**
- * See {@link TrackedLegOfCompetitor#getWindwardDistanceToOverallLeader(TimePoint, WindPositionMode)}
+ * See {@link TrackedLegOfCompetitor#getWindwardDistanceToCompetitorFarthestAhead(TimePoint, WindPositionMode, RankingInfo)}
*/
- Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode);
+ Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode);
/**
- * Same as {@link #getWindwardDistanceToOverallLeader(Competitor, TimePoint, WindPositionMode)}, only with an additional
- * cache to speed up wind and leg type and leg bearing calculations in case of multiple similar look-ups for the same
- * time point.
+ * Same as {@link #getWindwardDistanceToCompetitorFarthestAhead(Competitor, TimePoint, WindPositionMode)}, only with an
+ * additional cache to speed up wind and leg type and leg bearing calculations in case of multiple similar look-ups
+ * for the same time point.
+ *
+ * @param rankingInfo
+ * materialized ranking information that is expensive to calculate, avoiding redundant calculations
*/
- Distance getWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint, WindPositionMode windPositionMode, WindLegTypeAndLegBearingCache cache);
-
+ Distance getWindwardDistanceToCompetitorFarthestAhead(Competitor competitor, TimePoint timePoint,
+ WindPositionMode windPositionMode, RankingInfo rankingInfo, WindLegTypeAndLegBearingCache cache);
+
/**
* Calls {@link #getWindWithConfidence(Position, TimePoint, Iterable)} and excludes those wind sources listed in
* {@link #getWindSourcesToExclude}.
@@ -818,13 +823,4 @@ public interface TrackedRace extends Serializable {
Duration getEstimatedTimeToComplete(TimePoint timepoint) throws NotEnoughDataHasBeenAddedException, NoWindException;
void setPolarDataService(PolarDataService polarDataService);
-
- /**
- * With a handicap system in place, computes the windward distance to the race's overall leader based on the correction factors
- * introduced by the handicap's ranking and scoring system. For one-design classes, this method returns the same result as
- * {@link #getWindwardDistanceToOverallLeader(Competitor, TimePoint, WindPositionMode)}.
- */
- Distance getCorrectedWindwardDistanceToOverallLeader(Competitor competitor, TimePoint timePoint,
- WindPositionMode windPositionMode) throws NoWindException;
-
}
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java
index 227a8a216f5..e998afc4a5e 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java
@@ -29,8 +29,31 @@ import com.sap.sse.common.TimePoint;
public interface TrackedRegatta extends Serializable {
Regatta getRegatta();
+ /**
+ * Callers must {@link #lockTrackedRacesForRead() acquire the read lock} before calling this method and hold on to the lock
+ * while iterating over the data structure returned. Example:
+ *
+ * trackedRegatta.lockTrackedRacesForRead();
+ * try {
+ * for (TrackedRace trackedRace : trackedRegatta.getTrackedRaces()) {
+ * // do something
+ * }
+ * } finally {
+ * trackedRegatta.unlockTrackedRacesAfterRead();
+ * }
+ *
+ * The method will throw an {@link IllegalArgumentException} if the caller fails to do so.
+ */
Iterable extends TrackedRace> getTrackedRaces();
+ void lockTrackedRacesForRead();
+
+ void unlockTrackedRacesAfterRead();
+
+ void lockTrackedRacesForWrite();
+
+ void unlockTrackedRacesAfterWrite();
+
Iterablenull means "live" and is then replaced by "now" minus the tracked race's
* {@link TrackedRace#getDelayToLiveInMillis() delay}.
*/
- public List