694cd0c463ae265593ec33a8afa34bf1e0dcd1a3
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackedRaceStartTimeUpdateForDependentStartTimeTest.java
| ... | ... | @@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; |
| 6 | 6 | |
| 7 | 7 | import java.io.IOException; |
| 8 | 8 | import java.net.MalformedURLException; |
| 9 | +import java.util.List; |
|
| 9 | 10 | |
| 10 | 11 | import org.junit.jupiter.api.Test; |
| 11 | 12 | |
| ... | ... | @@ -19,11 +20,17 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl; |
| 19 | 20 | import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl; |
| 20 | 21 | import com.sap.sailing.domain.abstractlog.race.impl.SimpleRaceLogIdentifierImpl; |
| 21 | 22 | import com.sap.sailing.domain.base.CompetitorWithBoat; |
| 23 | +import com.sap.sailing.domain.base.Fleet; |
|
| 24 | +import com.sap.sailing.domain.base.RaceColumn; |
|
| 25 | +import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; |
|
| 26 | +import com.sap.sailing.domain.leaderboard.Leaderboard; |
|
| 22 | 27 | import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver; |
| 23 | 28 | import com.sap.sailing.domain.tracking.StartTimeChangedListener; |
| 24 | 29 | import com.sap.sailing.domain.tracking.TrackedRace; |
| 25 | 30 | import com.sap.sse.common.Duration; |
| 26 | 31 | import com.sap.sse.common.TimePoint; |
| 32 | +import com.sap.sse.common.Util.Pair; |
|
| 33 | +import com.sap.sse.common.Util.Triple; |
|
| 27 | 34 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 28 | 35 | |
| 29 | 36 | public class TrackedRaceStartTimeUpdateForDependentStartTimeTest extends TrackBasedTest { |
| ... | ... | @@ -47,6 +54,13 @@ public class TrackedRaceStartTimeUpdateForDependentStartTimeTest extends TrackBa |
| 47 | 54 | public TrackedRace resolveTrackedRace(SimpleRaceLogIdentifier identifier) { |
| 48 | 55 | return null; |
| 49 | 56 | } |
| 57 | + |
|
| 58 | + @Override |
|
| 59 | + public List<Triple<Leaderboard, RaceColumn, Fleet>> getColumnsWithRaceLogForTrackedRace( |
|
| 60 | + RegattaAndRaceIdentifier trackedRaceIdentifier) { |
|
| 61 | + // TODO Auto-generated method stub |
|
| 62 | + return null; |
|
| 63 | + } |
|
| 50 | 64 | }; |
| 51 | 65 | final TrackedRace r1 = createTestTrackedRace("Regatta", "R1", "J/70", createCompetitorAndBoatsMap(hasso), |
| 52 | 66 | MillisecondsTimePoint.now(), /* useMarkPassingCalculator */ false, raceLogResolver); |
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/TestTracTracRaceAndCompetitorStatusReconciler.java
| ... | ... | @@ -9,6 +9,7 @@ import static org.mockito.Mockito.mock; |
| 9 | 9 | import static org.mockito.Mockito.when; |
| 10 | 10 | |
| 11 | 11 | import java.util.Collections; |
| 12 | +import java.util.List; |
|
| 12 | 13 | import java.util.UUID; |
| 13 | 14 | |
| 14 | 15 | import org.junit.jupiter.api.BeforeEach; |
| ... | ... | @@ -27,6 +28,8 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFlagEventImpl; |
| 27 | 28 | import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl; |
| 28 | 29 | import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl; |
| 29 | 30 | import com.sap.sailing.domain.base.Competitor; |
| 31 | +import com.sap.sailing.domain.base.Fleet; |
|
| 32 | +import com.sap.sailing.domain.base.RaceColumn; |
|
| 30 | 33 | import com.sap.sailing.domain.base.RaceDefinition; |
| 31 | 34 | import com.sap.sailing.domain.base.impl.BoatClassImpl; |
| 32 | 35 | import com.sap.sailing.domain.base.impl.BoatImpl; |
| ... | ... | @@ -38,10 +41,12 @@ import com.sap.sailing.domain.base.impl.RaceDefinitionImpl; |
| 38 | 41 | import com.sap.sailing.domain.base.impl.TeamImpl; |
| 39 | 42 | import com.sap.sailing.domain.common.LeaderboardNameConstants; |
| 40 | 43 | import com.sap.sailing.domain.common.MaxPointsReason; |
| 44 | +import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; |
|
| 41 | 45 | import com.sap.sailing.domain.common.impl.DegreePosition; |
| 42 | 46 | import com.sap.sailing.domain.common.impl.MeterDistance; |
| 43 | 47 | import com.sap.sailing.domain.common.racelog.Flags; |
| 44 | 48 | import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; |
| 49 | +import com.sap.sailing.domain.leaderboard.Leaderboard; |
|
| 45 | 50 | import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl; |
| 46 | 51 | import com.sap.sailing.domain.leaderboard.impl.LowPoint; |
| 47 | 52 | import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl; |
| ... | ... | @@ -55,6 +60,7 @@ import com.sap.sse.common.Color; |
| 55 | 60 | import com.sap.sse.common.Duration; |
| 56 | 61 | import com.sap.sse.common.TimePoint; |
| 57 | 62 | import com.sap.sse.common.Util.Pair; |
| 63 | +import com.sap.sse.common.Util.Triple; |
|
| 58 | 64 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 59 | 65 | import com.sap.sse.metering.CPUMeter; |
| 60 | 66 | import com.tractrac.model.lib.api.event.ICompetitor; |
| ... | ... | @@ -112,6 +118,14 @@ public class TestTracTracRaceAndCompetitorStatusReconciler { |
| 112 | 118 | public TrackedRace resolveTrackedRace(SimpleRaceLogIdentifier identifier) { |
| 113 | 119 | return null; |
| 114 | 120 | } |
| 121 | + |
|
| 122 | + @Override |
|
| 123 | + public List<Triple<Leaderboard, RaceColumn, Fleet>> getColumnsWithRaceLogForTrackedRace( |
|
| 124 | + RegattaAndRaceIdentifier trackedRaceIdentifier) { |
|
| 125 | + // TODO Auto-generated method stub |
|
| 126 | + return null; |
|
| 127 | + } |
|
| 128 | + |
|
| 115 | 129 | }); |
| 116 | 130 | tractracCompetitor = mock(ICompetitor.class); |
| 117 | 131 | tractracRaceCompetitor = mock(IRaceCompetitor.class); |
| ... | ... | @@ -243,6 +257,13 @@ public class TestTracTracRaceAndCompetitorStatusReconciler { |
| 243 | 257 | public TrackedRace resolveTrackedRace(SimpleRaceLogIdentifier identifier) { |
| 244 | 258 | return null; |
| 245 | 259 | } |
| 260 | + |
|
| 261 | + @Override |
|
| 262 | + public List<Triple<Leaderboard, RaceColumn, Fleet>> getColumnsWithRaceLogForTrackedRace( |
|
| 263 | + RegattaAndRaceIdentifier trackedRaceIdentifier) { |
|
| 264 | + // TODO Auto-generated method stub |
|
| 265 | + return null; |
|
| 266 | + } |
|
| 246 | 267 | }); |
| 247 | 268 | final TimePoint noneStatusTimePoint = manualAbortTimePoint.plus(Duration.ONE_MINUTE.times(1)); |
| 248 | 269 | when(tractracRace.getStatusLastChangedTime()).thenReturn(noneStatusTimePoint.asMillis()); |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/DomainFactory.java
| ... | ... | @@ -34,6 +34,8 @@ import com.sap.sailing.domain.tracking.impl.RaceAbortedHandler; |
| 34 | 34 | import com.sap.sailing.domain.tracking.impl.StartTimeUpdateHandler; |
| 35 | 35 | import com.sap.sse.common.IsManagedByCache; |
| 36 | 36 | import com.sap.sse.common.TimePoint; |
| 37 | +import com.sap.sse.common.Util.Pair; |
|
| 38 | +import com.sap.sse.common.Util.Triple; |
|
| 37 | 39 | import com.sap.sse.util.ObjectInputStreamResolvingAgainstCache; |
| 38 | 40 | import com.sap.sse.util.ObjectInputStreamResolvingAgainstCache.ResolveListener; |
| 39 | 41 | |
| ... | ... | @@ -48,6 +50,16 @@ public interface DomainFactory extends SharedDomainFactory<RaceLogAndTrackedRace |
| 48 | 50 | public TrackedRace resolveTrackedRace(SimpleRaceLogIdentifier identifier) { |
| 49 | 51 | return null; |
| 50 | 52 | } |
| 53 | + |
|
| 54 | + @Override |
|
| 55 | + public List<Triple<Leaderboard, RaceColumn, Fleet>> getColumnsWithRaceLogForTrackedRace( |
|
| 56 | + RegattaAndRaceIdentifier trackedRaceIdentifier) { |
|
| 57 | + // TODO Auto-generated method stub |
|
| 58 | + return null; |
|
| 59 | + } |
|
| 60 | + |
|
| 61 | + |
|
| 62 | + |
|
| 51 | 63 | }; |
| 52 | 64 | |
| 53 | 65 | /** |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/RegattaRegistry.java
| ... | ... | @@ -3,7 +3,9 @@ package com.sap.sailing.domain.base; |
| 3 | 3 | import java.util.ConcurrentModificationException; |
| 4 | 4 | |
| 5 | 5 | import com.sap.sailing.domain.common.RegattaIdentifier; |
| 6 | +import com.sap.sailing.domain.tracking.TrackedRace; |
|
| 6 | 7 | import com.sap.sailing.domain.tracking.TrackedRegattaListener; |
| 8 | +import com.sap.sse.common.Util.Pair; |
|
| 7 | 9 | |
| 8 | 10 | public interface RegattaRegistry { |
| 9 | 11 | /** |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuverCacheDelegate.java
| ... | ... | @@ -65,9 +65,9 @@ public class ManeuverCacheDelegate implements ManeuverCache<Competitor, List<Man |
| 65 | 65 | public void resume() { |
| 66 | 66 | |
| 67 | 67 | // richtigen Ort bestimmen |
| 68 | - if (triggerManeuverCacheInvalidationForAllCompetitors) { |
|
| 69 | - triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 70 | - } |
|
| 68 | +// if (triggerManeuverCacheInvalidationForAllCompetitors) { |
|
| 69 | +// triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 70 | +// } |
|
| 71 | 71 | |
| 72 | 72 | ManeuverRaceFingerprint fingerprint; |
| 73 | 73 | race.getRace().getCourse().lockForRead(); |
| ... | ... | @@ -137,7 +137,7 @@ public class ManeuverCacheDelegate implements ManeuverCache<Competitor, List<Man |
| 137 | 137 | try { |
| 138 | 138 | synchronized (this) { |
| 139 | 139 | |
| 140 | - cacheToUse.suspend(); |
|
| 140 | + cacheToUse.triggerUpdate(competitor, updateInterval); |
|
| 141 | 141 | } |
| 142 | 142 | } finally { |
| 143 | 143 | race.getRace().getCourse().unlockAfterRead(); |
| ... | ... | @@ -147,26 +147,26 @@ public class ManeuverCacheDelegate implements ManeuverCache<Competitor, List<Man |
| 147 | 147 | } |
| 148 | 148 | |
| 149 | 149 | |
| 150 | - public void triggerManeuverCacheRecalculationForAllCompetitors() { |
|
| 151 | - if (cachesSuspended) { |
|
| 152 | - triggerManeuverCacheInvalidationForAllCompetitors = true; |
|
| 153 | - } else { |
|
| 154 | - final List<Competitor> shuffledCompetitors = new ArrayList<>(); |
|
| 155 | - for (Competitor competitor : (race.getRace().getCompetitors())) { |
|
| 156 | - shuffledCompetitors.add(competitor); |
|
| 157 | - } |
|
| 158 | - Collections.shuffle(shuffledCompetitors); |
|
| 159 | - for (Competitor competitor : shuffledCompetitors) { |
|
| 160 | - triggerManeuverCacheRecalculation(competitor); |
|
| 161 | - } |
|
| 162 | - } |
|
| 163 | - } |
|
| 164 | - |
|
| 165 | - public void triggerManeuverCacheRecalculation(final Competitor competitor) { |
|
| 166 | - if (cachesSuspended) { |
|
| 167 | - triggerManeuverCacheInvalidationForAllCompetitors = true; |
|
| 168 | - } else { |
|
| 169 | - triggerUpdate(competitor, /* updateInterval */null); |
|
| 170 | - } |
|
| 171 | - } |
|
| 150 | +// public void triggerManeuverCacheRecalculationForAllCompetitors() { |
|
| 151 | +// if (cachesSuspended) { |
|
| 152 | +// triggerManeuverCacheInvalidationForAllCompetitors = true; |
|
| 153 | +// } else { |
|
| 154 | +// final List<Competitor> shuffledCompetitors = new ArrayList<>(); |
|
| 155 | +// for (Competitor competitor : (race.getRace().getCompetitors())) { |
|
| 156 | +// shuffledCompetitors.add(competitor); |
|
| 157 | +// } |
|
| 158 | +// Collections.shuffle(shuffledCompetitors); |
|
| 159 | +// for (Competitor competitor : shuffledCompetitors) { |
|
| 160 | +// triggerManeuverCacheRecalculation(competitor); |
|
| 161 | +// } |
|
| 162 | +// } |
|
| 163 | +// } |
|
| 164 | +// |
|
| 165 | +// public void triggerManeuverCacheRecalculation(final Competitor competitor) { |
|
| 166 | +// if (cachesSuspended) { |
|
| 167 | +// triggerManeuverCacheInvalidationForAllCompetitors = true; |
|
| 168 | +// } else { |
|
| 169 | +// triggerUpdate(competitor, /* updateInterval */null); |
|
| 170 | +// } |
|
| 171 | +// } |
|
| 172 | 172 | } |
| ... | ... | \ No newline at end of file |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuverFromSmartFutureCache.java
| ... | ... | @@ -68,13 +68,7 @@ public class ManeuverFromSmartFutureCache implements ManeuverCache<Competitor, L |
| 68 | 68 | } |
| 69 | 69 | },//.computeCacheUpdate(competitor, null), |
| 70 | 70 | /* nameForLocks */ "Maneuver cache for race " + race.getRace().getName()); |
| 71 | - } |
|
| 72 | - |
|
| 73 | - |
|
| 74 | - |
|
| 75 | - |
|
| 76 | - |
|
| 77 | - |
|
| 71 | + } |
|
| 78 | 72 | |
| 79 | 73 | @Override |
| 80 | 74 | public void resume() { |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuverRaceFingerprintImpl.java
| ... | ... | @@ -2,6 +2,7 @@ package com.sap.sailing.domain.maneuverhash.impl; |
| 2 | 2 | |
| 3 | 3 | |
| 4 | 4 | import java.util.Map; |
| 5 | +import java.util.Set; |
|
| 5 | 6 | import java.util.stream.Collectors; |
| 6 | 7 | |
| 7 | 8 | import org.json.simple.JSONObject; |
| ... | ... | @@ -11,6 +12,7 @@ import com.sap.sailing.domain.abstractlog.race.analyzing.impl.MarkPassingDataFin |
| 11 | 12 | import com.sap.sailing.domain.base.Competitor; |
| 12 | 13 | import com.sap.sailing.domain.base.Mark; |
| 13 | 14 | import com.sap.sailing.domain.base.Waypoint; |
| 15 | +import com.sap.sailing.domain.common.Wind; |
|
| 14 | 16 | import com.sap.sailing.domain.common.WindSource; |
| 15 | 17 | import com.sap.sailing.domain.common.tracking.GPSFix; |
| 16 | 18 | import com.sap.sailing.domain.common.tracking.GPSFixMoving; |
| ... | ... | @@ -221,19 +223,39 @@ public class ManeuverRaceFingerprintImpl implements ManeuverRaceFingerprint { |
| 221 | 223 | } |
| 222 | 224 | |
| 223 | 225 | private int calculateWindHash(TrackedRace trackedRace) { |
| 224 | -// Set<WindSource> windSoure = trackedRace.getWindSources(); |
|
| 226 | + Set<WindSource> windSoures = trackedRace.getWindSources(); |
|
| 225 | 227 | int res = 0; |
| 226 | - String regattaName = trackedRace.getTrackedRegatta().getRegatta().getName(); |
|
| 227 | - Map<? extends WindSource, ? extends WindTrack> windTrack = trackedRace.getWindStore().loadWindTracks(regattaName, trackedRace, 10000); |
|
| 228 | - Map<WindSource, WindTrack> gefilterteMap = windTrack.entrySet() |
|
| 229 | - .stream().filter(entry -> entry.getKey().getType().isObserved()) |
|
| 230 | - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); |
|
| 231 | - for (Map.Entry<? extends WindSource, ? extends WindTrack> w : gefilterteMap.entrySet() ) { |
|
| 232 | - int k = w.getKey().hashCode(); |
|
| 233 | - int v = w.getValue().hashCode(); |
|
| 234 | - res = res ^ k; |
|
| 235 | - res = res ^ v; |
|
| 228 | +// String regattaName = trackedRace.getTrackedRegatta().getRegatta().getName(); |
|
| 229 | + Set<WindSource> windSouresToExclude = trackedRace.getWindSourcesToExclude(); |
|
| 230 | + |
|
| 231 | + for(WindSource w : windSoures) { |
|
| 232 | + if(w.getType().isObserved() && !windSouresToExclude.contains(w)) { |
|
| 233 | + WindTrack windTrack = trackedRace.getOrCreateWindTrack(w); |
|
| 234 | + windTrack.lockForRead(); |
|
| 235 | + try { |
|
| 236 | + int k = w.getId().hashCode(); |
|
| 237 | + int v = 0; |
|
| 238 | + for(Wind wf : trackedRace.getOrCreateWindTrack(w).getFixes()) { |
|
| 239 | + v = v + (int) ( wf.getPosition().getLatDeg() + wf.getPosition().getLngDeg() + wf.getKilometersPerHour()); |
|
| 240 | + } |
|
| 241 | + res = res ^ k; |
|
| 242 | + res = res ^ v; |
|
| 243 | + } finally { |
|
| 244 | + windTrack.unlockAfterRead(); |
|
| 245 | + } |
|
| 246 | + |
|
| 247 | + } |
|
| 236 | 248 | } |
| 249 | +// Map<? extends WindSource, ? extends WindTrack> windTrack = trackedRace.getOrCreateWindTrack(null) |
|
| 250 | +// Map<WindSource, WindTrack> gefilterteMap = windTrack.entrySet() |
|
| 251 | +// .stream().filter(entry -> entry.getKey().getType().isObserved()) |
|
| 252 | +// .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); |
|
| 253 | +// for (Map.Entry<? extends WindSource, ? extends WindTrack> w : gefilterteMap.entrySet() ) { |
|
| 254 | +// int k = w.getKey().hashCode(); |
|
| 255 | +// int v = w.getValue().hashCode(); |
|
| 256 | +// res = res ^ k; |
|
| 257 | +// res = res ^ v; |
|
| 258 | +// } |
|
| 237 | 259 | return res; |
| 238 | 260 | } |
| 239 | 261 |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/RaceLogAndTrackedRaceResolver.java
| ... | ... | @@ -1,11 +1,17 @@ |
| 1 | 1 | package com.sap.sailing.domain.racelog; |
| 2 | 2 | |
| 3 | +import java.util.List; |
|
| 4 | + |
|
| 5 | +import com.sap.sailing.domain.abstractlog.race.RaceLog; |
|
| 3 | 6 | import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier; |
| 4 | 7 | import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; |
| 5 | 8 | import com.sap.sailing.domain.base.Fleet; |
| 6 | 9 | import com.sap.sailing.domain.base.RaceColumn; |
| 10 | +import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; |
|
| 11 | +import com.sap.sailing.domain.leaderboard.Leaderboard; |
|
| 7 | 12 | import com.sap.sailing.domain.regattalike.IsRegattaLike; |
| 8 | 13 | import com.sap.sailing.domain.tracking.TrackedRace; |
| 14 | +import com.sap.sse.common.Util.Triple; |
|
| 9 | 15 | |
| 10 | 16 | /** |
| 11 | 17 | * In addition to being able to resolve a race log from a {@link SimpleRaceLogIdentifier}, this |
| ... | ... | @@ -22,4 +28,10 @@ public interface RaceLogAndTrackedRaceResolver extends RaceLogResolver { |
| 22 | 28 | * With this, both, the {@link RaceLog} as well as a {@link TrackedRace} can be looked up. |
| 23 | 29 | */ |
| 24 | 30 | TrackedRace resolveTrackedRace(SimpleRaceLogIdentifier identifier); |
| 31 | + |
|
| 32 | + // could be implemtet as dafault |
|
| 33 | + |
|
| 34 | + List<Triple<Leaderboard, RaceColumn, Fleet>> getColumnsWithRaceLogForTrackedRace( |
|
| 35 | + RegattaAndRaceIdentifier trackedRaceIdentifier); |
|
| 36 | + |
|
| 25 | 37 | } |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
| ... | ... | @@ -339,7 +339,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> { |
| 339 | 339 | } |
| 340 | 340 | } |
| 341 | 341 | updated(/* time point */null); |
| 342 | - maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 342 | + triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 343 | 343 | } |
| 344 | 344 | |
| 345 | 345 | @Override |
| ... | ... | @@ -350,7 +350,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> { |
| 350 | 350 | getOrCreateWindTrack(windSource).setMillisecondsOverWhichToAverage(millisecondsOverWhichToAverageWind); |
| 351 | 351 | } |
| 352 | 352 | updated(/* time point */null); |
| 353 | - maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 353 | + triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 354 | 354 | notifyListenersWindAveragingChanged(oldMillisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageWind); |
| 355 | 355 | } |
| 356 | 356 | |
| ... | ... | @@ -407,7 +407,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> { |
| 407 | 407 | final GPSFix firstFixAfter = result.getFirstFixAfter(fixTimePoint); |
| 408 | 408 | invalidateDistancesFromStarboardSideOfStartLineProjectedOntoLineCache(TimeRange.create(lastFixBefore==null?null:lastFixBefore.getTimePoint(), |
| 409 | 409 | firstFixAfter==null?null:firstFixAfter.getTimePoint())); |
| 410 | - maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 410 | + triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 411 | 411 | notifyListeners(fix, mark, firstFixInTrack, addedOrReplaced); |
| 412 | 412 | } |
| 413 | 413 | |
| ... | ... | @@ -924,7 +924,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> { |
| 924 | 924 | getRace().getCourse().unlockAfterRead(); |
| 925 | 925 | } |
| 926 | 926 | updated(timePointOfLatestEvent); |
| 927 | - maneuverCache.triggerManeuverCacheRecalculation(competitor); |
|
| 927 | + triggerManeuverCacheRecalculation(competitor); |
|
| 928 | 928 | // update the race times like start, end and the leg times |
| 929 | 929 | if (requiresStartTimeUpdate) { |
| 930 | 930 | invalidateStartTime(); |
| ... | ... | @@ -1214,7 +1214,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> { |
| 1214 | 1214 | invalidateDistancesFromStarboardSideOfStartLineProjectedOntoLineCache(TimeRange.create( |
| 1215 | 1215 | fix.getTimePoint().minus(getMillisecondsOverWhichToAverageSpeed()), |
| 1216 | 1216 | fix.getTimePoint().plus(getMillisecondsOverWhichToAverageSpeed()))); |
| 1217 | - maneuverCache.triggerManeuverCacheRecalculation(competitor); |
|
| 1217 | + triggerManeuverCacheRecalculation(competitor); |
|
| 1218 | 1218 | notifyListeners(fix, competitor, addedOrReplaced); |
| 1219 | 1219 | // getAndSet call is atomic which means, that it can be ensured that the listeners are notified only once |
| 1220 | 1220 | final boolean oldGPSFixReceived = gpsFixReceived.getAndSet(true); |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java
| ... | ... | @@ -32,6 +32,7 @@ import java.util.concurrent.Callable; |
| 32 | 32 | import java.util.concurrent.ConcurrentHashMap; |
| 33 | 33 | import java.util.concurrent.ConcurrentMap; |
| 34 | 34 | import java.util.concurrent.ConcurrentSkipListSet; |
| 35 | +import java.util.concurrent.CountDownLatch; |
|
| 35 | 36 | import java.util.concurrent.ExecutionException; |
| 36 | 37 | import java.util.concurrent.Future; |
| 37 | 38 | import java.util.concurrent.FutureTask; |
| ... | ... | @@ -40,6 +41,7 @@ import java.util.function.Consumer; |
| 40 | 41 | import java.util.logging.Level; |
| 41 | 42 | import java.util.logging.Logger; |
| 42 | 43 | import java.util.stream.Collectors; |
| 44 | +import java.util.stream.StreamSupport; |
|
| 43 | 45 | |
| 44 | 46 | import org.apache.commons.math.FunctionEvaluationException; |
| 45 | 47 | import org.apache.commons.math.MaxIterationsExceededException; |
| ... | ... | @@ -70,8 +72,10 @@ import com.sap.sailing.domain.base.ControlPoint; |
| 70 | 72 | import com.sap.sailing.domain.base.Course; |
| 71 | 73 | import com.sap.sailing.domain.base.CourseListener; |
| 72 | 74 | import com.sap.sailing.domain.base.DomainFactory; |
| 75 | +import com.sap.sailing.domain.base.Fleet; |
|
| 73 | 76 | import com.sap.sailing.domain.base.Leg; |
| 74 | 77 | import com.sap.sailing.domain.base.Mark; |
| 78 | +import com.sap.sailing.domain.base.RaceColumn; |
|
| 75 | 79 | import com.sap.sailing.domain.base.RaceDefinition; |
| 76 | 80 | import com.sap.sailing.domain.base.Regatta; |
| 77 | 81 | import com.sap.sailing.domain.base.RegattaListener; |
| ... | ... | @@ -125,6 +129,7 @@ import com.sap.sailing.domain.common.tracking.GPSFixMoving; |
| 125 | 129 | import com.sap.sailing.domain.common.tracking.SensorFix; |
| 126 | 130 | import com.sap.sailing.domain.confidence.ConfidenceBasedWindAverager; |
| 127 | 131 | import com.sap.sailing.domain.confidence.ConfidenceFactory; |
| 132 | +import com.sap.sailing.domain.leaderboard.Leaderboard; |
|
| 128 | 133 | import com.sap.sailing.domain.leaderboard.Leaderboard.RankComparableRank; |
| 129 | 134 | import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache; |
| 130 | 135 | import com.sap.sailing.domain.leaderboard.impl.CompetitorAndRankComparable; |
| ... | ... | @@ -133,6 +138,7 @@ import com.sap.sailing.domain.maneuverdetection.IncrementalManeuverDetector; |
| 133 | 138 | import com.sap.sailing.domain.maneuverdetection.ManeuverDetector; |
| 134 | 139 | import com.sap.sailing.domain.maneuverdetection.ShortTimeAfterLastHitCache; |
| 135 | 140 | import com.sap.sailing.domain.maneuverdetection.impl.IncrementalManeuverDetectorImpl; |
| 141 | +import com.sap.sailing.domain.maneuverhash.ManeuverCache; |
|
| 136 | 142 | import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprintRegistry; |
| 137 | 143 | import com.sap.sailing.domain.maneuverhash.impl.ManeuverCacheDelegate; |
| 138 | 144 | import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator; |
| ... | ... | @@ -185,6 +191,7 @@ import com.sap.sse.common.TimeRange; |
| 185 | 191 | import com.sap.sse.common.Timed; |
| 186 | 192 | import com.sap.sse.common.Util; |
| 187 | 193 | import com.sap.sse.common.Util.Pair; |
| 194 | +import com.sap.sse.common.Util.Triple; |
|
| 188 | 195 | import com.sap.sse.common.impl.DegreeBearingImpl; |
| 189 | 196 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 190 | 197 | import com.sap.sse.concurrent.LockUtil; |
| ... | ... | @@ -192,6 +199,7 @@ import com.sap.sse.concurrent.NamedReentrantReadWriteLock; |
| 192 | 199 | import com.sap.sse.shared.util.impl.ApproximateTime; |
| 193 | 200 | import com.sap.sse.shared.util.impl.ArrayListNavigableSet; |
| 194 | 201 | import com.sap.sse.util.IdentityWrapper; |
| 202 | +import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval; |
|
| 195 | 203 | //import com.sap.sse.util.SmartFutureCache; |
| 196 | 204 | //import com.sap.sse.util.SmartFutureCache.AbstractCacheUpdater; |
| 197 | 205 | //import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval; |
| ... | ... | @@ -342,7 +350,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 342 | 350 | * computed. Clients wanting to know maneuvers for the competitor outside of this time interval need to (re-)compute |
| 343 | 351 | * them. |
| 344 | 352 | */ |
| 345 | - public transient ManeuverCacheDelegate maneuverCache; |
|
| 353 | + public transient ManeuverCache<Competitor, List<Maneuver>, EmptyUpdateInterval> maneuverCache; |
|
| 346 | 354 | |
| 347 | 355 | private transient ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry; |
| 348 | 356 | |
| ... | ... | @@ -690,7 +698,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 690 | 698 | result = windTrack.add(wind); |
| 691 | 699 | if (result) { |
| 692 | 700 | updated(wind.getTimePoint()); |
| 693 | - maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 701 | + triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 694 | 702 | } |
| 695 | 703 | } else { |
| 696 | 704 | result = false; |
| ... | ... | @@ -702,7 +710,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 702 | 710 | public void removeWind(Wind wind, WindSource windSource) { |
| 703 | 711 | getOrCreateWindTrack(windSource).remove(wind); |
| 704 | 712 | updated(/* time point */null); // wind events shouldn't advance race time |
| 705 | - maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 713 | + triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 706 | 714 | } |
| 707 | 715 | |
| 708 | 716 | @Override |
| ... | ... | @@ -809,7 +817,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 809 | 817 | } catch (PatchFailedException e) { |
| 810 | 818 | throw new RuntimeException(e); |
| 811 | 819 | } // a bit unclean: this also tries to work on the DynamicTrackedRaceImpl which isn't fully initialized yet; see also bug6039 |
| 812 | - maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors(); // a bit unclean: this also tries to work on the DynamicTrackedRaceImpl which isn't fully initialized yet; see also bug6039 |
|
| 820 | + triggerManeuverCacheRecalculationForAllCompetitors(); // a bit unclean: this also tries to work on the DynamicTrackedRaceImpl which isn't fully initialized yet; see also bug6039 |
|
| 813 | 821 | } |
| 814 | 822 | |
| 815 | 823 | /** |
| ... | ... | @@ -1105,6 +1113,10 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 1105 | 1113 | */ |
| 1106 | 1114 | private final String updateStartOfRaceCacheFieldsMonitor = ""+new Random().nextDouble(); |
| 1107 | 1115 | |
| 1116 | + private boolean triggerManeuverCacheInvalidationForAllCompetitors; |
|
| 1117 | + |
|
| 1118 | + protected int attachedRaceLogsCount; |
|
| 1119 | + |
|
| 1108 | 1120 | protected void updateStartOfRaceCacheFields() { |
| 1109 | 1121 | synchronized (updateStartOfRaceCacheFieldsMonitor) { |
| 1110 | 1122 | TimePoint newStartTime = null; |
| ... | ... | @@ -2130,7 +2142,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 2130 | 2142 | } |
| 2131 | 2143 | if (!old.equals(new HashSet<>(getWindSourcesToExclude()))) { |
| 2132 | 2144 | clearAllCachesExceptManeuvers(); |
| 2133 | - maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 2145 | + triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 2134 | 2146 | } |
| 2135 | 2147 | } |
| 2136 | 2148 | |
| ... | ... | @@ -2479,7 +2491,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 2479 | 2491 | } finally { |
| 2480 | 2492 | LockUtil.unlockAfterWrite(getMarkPassingsLock(markPassingsForOneCompetitor)); |
| 2481 | 2493 | } |
| 2482 | - maneuverCache.triggerManeuverCacheRecalculation(competitor); |
|
| 2494 | + triggerManeuverCacheRecalculation(competitor); |
|
| 2483 | 2495 | } |
| 2484 | 2496 | } |
| 2485 | 2497 | logger.info("done updating tracked race "+this+"'s data structures..."); |
| ... | ... | @@ -2893,28 +2905,28 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 2893 | 2905 | return maneuverApproximators.get(competitor).approximate(from, to); |
| 2894 | 2906 | } |
| 2895 | 2907 | |
| 2896 | -// protected void triggerManeuverCacheRecalculationForAllCompetitors() { |
|
| 2897 | -// if (cachesSuspended) { |
|
| 2898 | -// triggerManeuverCacheInvalidationForAllCompetitors = true; |
|
| 2899 | -// } else { |
|
| 2900 | -// final List<Competitor> shuffledCompetitors = new ArrayList<>(); |
|
| 2901 | -// for (Competitor competitor : (getRace().getCompetitors())) { |
|
| 2902 | -// shuffledCompetitors.add(competitor); |
|
| 2903 | -// } |
|
| 2904 | -// Collections.shuffle(shuffledCompetitors); |
|
| 2905 | -// for (Competitor competitor : shuffledCompetitors) { |
|
| 2906 | -// triggerManeuverCacheRecalculation(competitor); |
|
| 2907 | -// } |
|
| 2908 | -// } |
|
| 2909 | -// } |
|
| 2910 | -// |
|
| 2911 | -// public void triggerManeuverCacheRecalculation(final Competitor competitor) { |
|
| 2912 | -// if (cachesSuspended) { |
|
| 2913 | -// triggerManeuverCacheInvalidationForAllCompetitors = true; |
|
| 2914 | -// } else { |
|
| 2915 | -// maneuverCache.triggerUpdate(competitor, /* updateInterval */null); |
|
| 2916 | -// } |
|
| 2917 | -// } |
|
| 2908 | + protected void triggerManeuverCacheRecalculationForAllCompetitors() { |
|
| 2909 | + if (cachesSuspended) { |
|
| 2910 | + triggerManeuverCacheInvalidationForAllCompetitors = true; |
|
| 2911 | + } else { |
|
| 2912 | + final List<Competitor> shuffledCompetitors = new ArrayList<>(); |
|
| 2913 | + for (Competitor competitor : (getRace().getCompetitors())) { |
|
| 2914 | + shuffledCompetitors.add(competitor); |
|
| 2915 | + } |
|
| 2916 | + Collections.shuffle(shuffledCompetitors); |
|
| 2917 | + for (Competitor competitor : shuffledCompetitors) { |
|
| 2918 | + triggerManeuverCacheRecalculation(competitor); |
|
| 2919 | + } |
|
| 2920 | + } |
|
| 2921 | + } |
|
| 2922 | + |
|
| 2923 | + public void triggerManeuverCacheRecalculation(final Competitor competitor) { |
|
| 2924 | + if (cachesSuspended) { |
|
| 2925 | + triggerManeuverCacheInvalidationForAllCompetitors = true; |
|
| 2926 | + } else { |
|
| 2927 | + maneuverCache.triggerUpdate(competitor, /* updateInterval */null); |
|
| 2928 | + } |
|
| 2929 | + } |
|
| 2918 | 2930 | |
| 2919 | 2931 | public List<Maneuver> computeManeuvers(Competitor competitor, ManeuverDetector maneuverDetector) |
| 2920 | 2932 | throws NoWindException { |
| ... | ... | @@ -2941,7 +2953,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 2941 | 2953 | */ |
| 2942 | 2954 | @Override |
| 2943 | 2955 | public Iterable<Maneuver> getManeuvers(Competitor competitor, TimePoint from, TimePoint to, boolean waitForLatest) { |
| 2944 | - List<Maneuver> allManeuvers = maneuverCache.get(competitor, waitForLatest); |
|
| 2956 | + List<Maneuver> allManeuvers = (List<Maneuver>) maneuverCache.get(competitor, waitForLatest); |
|
| 2945 | 2957 | List<Maneuver> result; |
| 2946 | 2958 | if (allManeuvers == null) { |
| 2947 | 2959 | result = Collections.emptyList(); |
| ... | ... | @@ -2953,7 +2965,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 2953 | 2965 | |
| 2954 | 2966 | @Override |
| 2955 | 2967 | public Iterable<Maneuver> getManeuvers(Competitor competitor, boolean waitForLatest) { |
| 2956 | - List<Maneuver> allManeuvers = maneuverCache.get(competitor, waitForLatest); |
|
| 2968 | + List<Maneuver> allManeuvers = (List<Maneuver>) maneuverCache.get(competitor, waitForLatest); |
|
| 2957 | 2969 | List<Maneuver> result; |
| 2958 | 2970 | if (allManeuvers == null) { |
| 2959 | 2971 | result = Collections.emptyList(); |
| ... | ... | @@ -3132,6 +3144,46 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 3132 | 3144 | crossTrackErrorCache.suspend(); |
| 3133 | 3145 | maneuverCache.suspend(); |
| 3134 | 3146 | } |
| 3147 | + |
|
| 3148 | + |
|
| 3149 | + |
|
| 3150 | + |
|
| 3151 | + |
|
| 3152 | + |
|
| 3153 | + private void waitForAllRaceLogAttacehd() { |
|
| 3154 | + final CountDownLatch latchForRaceLogs = new CountDownLatch(1); // alternative schauen |
|
| 3155 | + |
|
| 3156 | + final Iterable<Triple<Leaderboard, RaceColumn, Fleet>> ecpextedLinks = TrackedRaceImpl.this.getRaceLogResolver() |
|
| 3157 | + .getColumnsWithRaceLogForTrackedRace(getRaceIdentifier()); //Namen |
|
| 3158 | + final int numberOfExpecteddRaceLogs = Util.size(ecpextedLinks); // Namen ändern |
|
| 3159 | + |
|
| 3160 | + AbstractRaceChangeListener raceLogAttachedListener = new AbstractRaceChangeListener() { |
|
| 3161 | + |
|
| 3162 | + @Override |
|
| 3163 | + public void raceLogAttached(RaceLog raceLog) { |
|
| 3164 | + int numberOfAttachedRaceLogs = Util.size(getAttachedRaceLogs()); |
|
| 3165 | + if(numberOfAttachedRaceLogs >=numberOfExpecteddRaceLogs) { |
|
| 3166 | + latchForRaceLogs.countDown(); |
|
| 3167 | + } |
|
| 3168 | + } |
|
| 3169 | + }; |
|
| 3170 | + |
|
| 3171 | + this.addListener(raceLogAttachedListener); |
|
| 3172 | + |
|
| 3173 | + final int numberOfAttachedRaceLogs = Util.size(getAttachedRaceLogs()); |
|
| 3174 | + |
|
| 3175 | + try { |
|
| 3176 | + if (numberOfAttachedRaceLogs < numberOfExpecteddRaceLogs) { |
|
| 3177 | + latchForRaceLogs.await(); |
|
| 3178 | + } |
|
| 3179 | + } catch (InterruptedException e) { |
|
| 3180 | + // TODO Auto-generated catch block |
|
| 3181 | + //Logging hinzufügen |
|
| 3182 | + e.printStackTrace(); |
|
| 3183 | + } finally { |
|
| 3184 | + removeListener(raceLogAttachedListener); |
|
| 3185 | + } |
|
| 3186 | + } |
|
| 3135 | 3187 | |
| 3136 | 3188 | private void resumeAllCachesNotUpdatingWhileLoading() { |
| 3137 | 3189 | cachesSuspended = false; |
| ... | ... | @@ -3147,10 +3199,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 3147 | 3199 | } |
| 3148 | 3200 | crossTrackErrorCache.resume(); |
| 3149 | 3201 | |
| 3150 | -// if (triggerManeuverCacheInvalidationForAllCompetitors) { |
|
| 3151 | -// maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 3152 | -// } |
|
| 3202 | + if (triggerManeuverCacheInvalidationForAllCompetitors) { |
|
| 3203 | + triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 3204 | + } |
|
| 3153 | 3205 | |
| 3206 | + waitForAllRaceLogAttacehd(); |
|
| 3154 | 3207 | maneuverCache.resume(); |
| 3155 | 3208 | } |
| 3156 | 3209 | |
| ... | ... | @@ -3211,6 +3264,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 3211 | 3264 | attachedRaceLogs.put(raceLog.getId(), raceLog); |
| 3212 | 3265 | notifyAll(); |
| 3213 | 3266 | invalidateStartTime(); |
| 3267 | + |
|
| 3214 | 3268 | } |
| 3215 | 3269 | notifyListenersWhenAttachingRaceLog(raceLog); |
| 3216 | 3270 | } |
| ... | ... | @@ -4100,7 +4154,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl |
| 4100 | 4154 | // complete maneuver curves can be fed directly into the windEstimation. |
| 4101 | 4155 | maneuverDetectorPerCompetitorCache.clearCache(); |
| 4102 | 4156 | shortTimeWindCache.clearCache(); |
| 4103 | - maneuverCache.triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 4157 | + triggerManeuverCacheRecalculationForAllCompetitors(); |
|
| 4104 | 4158 | } |
| 4105 | 4159 | |
| 4106 | 4160 | /** |
java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
| ... | ... | @@ -2717,21 +2717,35 @@ Replicator { |
| 2717 | 2717 | * {@link RaceColumn#getTrackedRace(Fleet) tracked race assigned} and whose |
| 2718 | 2718 | * {@link RaceColumn#getRaceIdentifier(Fleet) race identifier} equals that of <code>trackedRace</code>. |
| 2719 | 2719 | */ |
| 2720 | - private void linkRaceToConfiguredLeaderboardColumns(TrackedRace trackedRace) { |
|
| 2721 | - RegattaAndRaceIdentifier trackedRaceIdentifier = trackedRace.getRaceIdentifier(); |
|
| 2720 | + private List<Triple<Leaderboard, RaceColumn, Fleet>> linkRaceToConfiguredLeaderboardColumns(TrackedRace trackedRace) { |
|
| 2721 | + final RegattaAndRaceIdentifier trackedRaceIdentifier = trackedRace.getRaceIdentifier(); |
|
| 2722 | + final List<Triple<Leaderboard, RaceColumn, Fleet>> trackedRaceLink = getColumnsWithRaceLogForTrackedRace(trackedRaceIdentifier); |
|
| 2723 | + for (final Triple<Leaderboard, RaceColumn, Fleet> leaderboardRaceColumnAndFleet : trackedRaceLink) { |
|
| 2724 | + leaderboardRaceColumnAndFleet.getB().setTrackedRace(leaderboardRaceColumnAndFleet.getC(), trackedRace); |
|
| 2725 | + replicate(new ConnectTrackedRaceToLeaderboardColumn(leaderboardRaceColumnAndFleet.getA().getName(), leaderboardRaceColumnAndFleet.getB().getName(), |
|
| 2726 | + leaderboardRaceColumnAndFleet.getC().getName(), trackedRaceIdentifier)); |
|
| 2727 | + } |
|
| 2728 | + return trackedRaceLink; |
|
| 2729 | + } |
|
| 2730 | + |
|
| 2731 | + @Override |
|
| 2732 | + public List<Triple<Leaderboard, RaceColumn, Fleet>> getColumnsWithRaceLogForTrackedRace( |
|
| 2733 | + final RegattaAndRaceIdentifier trackedRaceIdentifier) { |
|
| 2734 | + final List<Triple<Leaderboard, RaceColumn, Fleet>> trackedRaceLink = new ArrayList<>(); |
|
| 2722 | 2735 | for (Leaderboard leaderboard : getLeaderboards().values()) { |
| 2723 | 2736 | for (RaceColumn column : leaderboard.getRaceColumns()) { |
| 2724 | 2737 | for (Fleet fleet : column.getFleets()) { |
| 2725 | 2738 | if (trackedRaceIdentifier.equals(column.getRaceIdentifier(fleet)) |
| 2726 | 2739 | && column.getTrackedRace(fleet) == null) { |
| 2727 | - column.setTrackedRace(fleet, trackedRace); |
|
| 2728 | - replicate(new ConnectTrackedRaceToLeaderboardColumn(leaderboard.getName(), column.getName(), |
|
| 2729 | - fleet.getName(), trackedRaceIdentifier)); |
|
| 2740 | + trackedRaceLink.add(new Triple<>(leaderboard, column, fleet)); |
|
| 2730 | 2741 | } |
| 2731 | 2742 | } |
| 2732 | 2743 | } |
| 2733 | 2744 | } |
| 2745 | + return trackedRaceLink; |
|
| 2734 | 2746 | } |
| 2747 | + |
|
| 2748 | + |
|
| 2735 | 2749 | |
| 2736 | 2750 | @Override |
| 2737 | 2751 | public void stopTracking(Regatta regatta, boolean willBeRemoved) throws MalformedURLException, IOException, InterruptedException { |