diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java
index a392004fd9e..bb4bf33d18e 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java
@@ -221,7 +221,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
}
@Override
- public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
+ public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
+ boolean notifyAboutGPSFixesAlreadyLoaded) {
// TODO Auto-generated method stub
}
diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java
index 1dc5f78b580..66280733efb 100755
--- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java
+++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRaceWithStartTimeAndRanks.java
@@ -353,7 +353,8 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
}
@Override
- public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
+ public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
+ boolean notifyAboutGPSFixesAlreadyLoaded) {
// TODO Auto-generated method stub
}
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 53c3a2a0a02..807f153e77f 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
@@ -443,9 +443,12 @@ public interface TrackedRace extends Serializable {
* tracked race. This runs synchronized with the otherwise asynchronous loading of wind tracks, triggered by the
* constructor of the {@link TrackedRace} implementation classes. This procedure guarantees that eventually the
* listener will have received a notification for all wind fixes, regardless of whether they were already loaded at
- * the time the listener is registered or they are loaded after the registration has completed.
+ * the time the listener is registered or they are loaded after the registration has completed.
+ *
+ * The same is true for the GPS fixes for marks and competitors.
*/
- void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded);
+ void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
+ boolean notifyAboutGPSFixesAlreadyLoaded);
void removeListener(RaceChangeListener listener);
diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
index 73a875f2c77..83b2e3ecf34 100755
--- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
+++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java
@@ -44,6 +44,7 @@ import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving;
+import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.GPSTrackListener;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceChangeListener;
@@ -249,16 +250,14 @@ DynamicTrackedRace, GPSTrackListener {
}
}
- /**
- * If the listener wants to be notified about the wind fixes already loaded, this method will obtain the read lock
- * of the {@link #getLoadingFromStoresLock() wind loading lock}, locking against the wind loading thread which uses the
- * corresponding write lock. This ensures that either all wind fixes have been loaded already or that wind loading
- * hasn't started yet.
- */
@Override
- public void addListener(RaceChangeListener listener, final boolean notifyAboutWindFixesAlreadyLoaded) {
+ public void addListener(RaceChangeListener listener, final boolean notifyAboutWindFixesAlreadyLoaded,
+ final boolean notifyAboutGPSFixesAlreadyLoaded) {
if (notifyAboutWindFixesAlreadyLoaded) {
- LockUtil.lockForRead(getLoadingFromStoresLock());
+ LockUtil.lockForRead(getLoadingFromWindStoreLock());
+ }
+ if (notifyAboutGPSFixesAlreadyLoaded) {
+ LockUtil.lockForRead(getLoadingFromGPSFixStoreLock());
}
try {
addListener(listener);
@@ -282,9 +281,34 @@ DynamicTrackedRace, GPSTrackListener {
}
}
}
+ if (notifyAboutGPSFixesAlreadyLoaded) {
+ for (Mark mark : getMarks()) {
+ GPSFixTrack markTrack = getOrCreateTrack(mark);
+ markTrack.lockForRead();
+ try {
+ for (GPSFix fix : markTrack.getRawFixes()) {
+ listener.markPositionChanged(fix, mark);
+ }
+ } finally {
+ markTrack.unlockAfterRead();
+ }
+ }
+
+ for (Competitor competitor : getRace().getCompetitors()) {
+ GPSFixTrack competitorTrack = getTrack(competitor);
+ competitorTrack.lockForRead();
+ try {
+ for (GPSFixMoving fix : competitorTrack.getRawFixes()) {
+ listener.competitorPositionChanged(fix, competitor);
+ }
+ } finally {
+ competitorTrack.unlockAfterRead();
+ }
+ }
+ }
} finally {
if (notifyAboutWindFixesAlreadyLoaded) {
- LockUtil.unlockAfterRead(getLoadingFromStoresLock());
+ LockUtil.unlockAfterRead(getLoadingFromWindStoreLock());
}
}
}
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 b492c587e8c..cd1e3607968 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
@@ -230,22 +230,31 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
private enum LoadingFromStoresState { NOT_STARTED, RUNNING, FINISHED };
/**
- * The constructor loads wind fixes from the {@link #windStore} and GPS fixes from the {@link #gpsFixStore}
- * asynchronously. When completed, this flag is set to true, and all threads currently waiting on this
- * object are notified.
+ * The constructor loads wind fixes from the {@link #windStore} asynchronously.
+ * When completed all threads currently waiting on this object are notified.
*/
- private LoadingFromStoresState loadingFromStoresCompleted;
+ private LoadingFromStoresState loadingFromWindStoreState;
+
+ /**
+ * @see #loadingFromWindStoreState but for GPSFixStore
+ */
+ private LoadingFromStoresState loadingFromGPSFixStoreState;
private transient CrossTrackErrorCache crossTrackErrorCache;
private final GPSFixStore gpsFixStore;
/**
- * Wind and GPS fix loading is started in a background thread during object construction. If a client needs to
- * ensure that wind / GPS fix loading either has terminated or has not yet begun, it can obtain the read lock of
- * this lock. The wind / GPS fix loading procedure will obtain the write lock before it starts loading wind fixes.
+ * Wind and loading is started in a background thread during object construction. If a client needs to
+ * ensure that wind loading either has terminated or has not yet begun, it can obtain the read lock of
+ * this lock. The wind loading procedure will obtain the write lock before it starts loading wind fixes.
*/
- private final NamedReentrantReadWriteLock loadingFromStoresLock;
+ private final NamedReentrantReadWriteLock loadingFromWindStoreLock;
+
+ /**
+ * @see #loadingFromWindStoreLock but for GPSFixStore
+ */
+ private final NamedReentrantReadWriteLock loadingFromGPSFixStoreLock;
private final Map, NamedReentrantReadWriteLock> locksForMarkPassings;
@@ -257,7 +266,9 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
attachedRaceLogs = new HashMap<>();
this.status = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.PREPARED, 0.0);
this.statusNotifier = new Object[0];
- this.loadingFromStoresLock = new NamedReentrantReadWriteLock("Loading from stores lock for tracked race "
+ this.loadingFromWindStoreLock = new NamedReentrantReadWriteLock("Loading from wind store lock for tracked race "
+ + race.getName(), /* fair */ false);
+ this.loadingFromGPSFixStoreLock = new NamedReentrantReadWriteLock("Loading from GPSFix store lock for tracked race "
+ race.getName(), /* fair */ false);
this.cacheInvalidationTimerLock = new Object();
this.updateCount = 0;
@@ -314,15 +325,15 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
MarkPassingByTimeComparator.INSTANCE));
}
markPassingsTimes = new ArrayList>>();
- loadingFromStoresCompleted = LoadingFromStoresState.NOT_STARTED;
+ loadingFromWindStoreState = LoadingFromStoresState.NOT_STARTED;
// When this tracked race is to be serialized, wait for the loading from stores to complete.
new Thread("Mongo wind loader for tracked race " + getRace().getName()) {
@Override
public void run() {
LockUtil.lockForRead(getSerializationLock());
- LockUtil.lockForWrite(getLoadingFromStoresLock());
+ LockUtil.lockForWrite(getLoadingFromWindStoreLock());
synchronized (TrackedRaceImpl.this) {
- loadingFromStoresCompleted = LoadingFromStoresState.RUNNING; // indicates that the serialization lock is now safely held
+ loadingFromWindStoreState = LoadingFromStoresState.RUNNING; // indicates that the serialization lock is now safely held
TrackedRaceImpl.this.notifyAll();
}
try {
@@ -335,10 +346,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
} finally {
synchronized (TrackedRaceImpl.this) {
- loadingFromStoresCompleted = LoadingFromStoresState.FINISHED;
+ loadingFromWindStoreState = LoadingFromStoresState.FINISHED;
TrackedRaceImpl.this.notifyAll();
+ loadingFromWindStoreState.notifyAll();
}
- LockUtil.unlockAfterWrite(getLoadingFromStoresLock());
+ LockUtil.unlockAfterWrite(getLoadingFromWindStoreLock());
LockUtil.unlockAfterRead(getSerializationLock());
}
}
@@ -356,7 +368,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
competitorRankingsLocks = new HashMap();
// now wait until wind loading has at least started; then we know that the serialization lock is safely held by the loader
synchronized (this) {
- while (loadingFromStoresCompleted != LoadingFromStoresState.FINISHED) {
+ while (loadingFromWindStoreState != LoadingFromStoresState.FINISHED) {
try {
this.wait();
} catch (InterruptedException e) {
@@ -418,7 +430,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
@Override
public synchronized void waitUntilLoadingFromStoresComplete() throws InterruptedException {
- while (loadingFromStoresCompleted != LoadingFromStoresState.FINISHED) {
+ while (loadingFromWindStoreState != LoadingFromStoresState.FINISHED ||
+ loadingFromGPSFixStoreState != LoadingFromStoresState.FINISHED) {
wait();
}
}
@@ -2349,15 +2362,15 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
if (raceLog != null) {
this.attachedRaceLogs.put(raceLog.getId(), raceLog);
// Use the new race log, that possibly contains device mappings, to load GPSFix tracks from the DB
- loadingFromStoresCompleted = LoadingFromStoresState.NOT_STARTED;
+ loadingFromGPSFixStoreState = LoadingFromStoresState.NOT_STARTED;
// When this tracked race is to be serialized, wait for the loading from stores to complete.
new Thread("Mongo mark and competitor track loader for tracked race " + getRace().getName()) {
@Override
public void run() {
LockUtil.lockForRead(getSerializationLock());
- LockUtil.lockForWrite(getLoadingFromStoresLock());
+ LockUtil.lockForWrite(getLoadingFromWindStoreLock());
synchronized (TrackedRaceImpl.this) {
- loadingFromStoresCompleted = LoadingFromStoresState.RUNNING; // indicates that the serialization
+ loadingFromGPSFixStoreState = LoadingFromStoresState.RUNNING; // indicates that the serialization
// lock is now safely held
TrackedRaceImpl.this.notifyAll();
}
@@ -2378,10 +2391,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
} finally {
synchronized (TrackedRaceImpl.this) {
- loadingFromStoresCompleted = LoadingFromStoresState.FINISHED;
+ loadingFromGPSFixStoreState = LoadingFromStoresState.FINISHED;
TrackedRaceImpl.this.notifyAll();
+ loadingFromGPSFixStoreState.notifyAll();
}
- LockUtil.unlockAfterWrite(getLoadingFromStoresLock());
+ LockUtil.unlockAfterWrite(getLoadingFromWindStoreLock());
LockUtil.unlockAfterRead(getSerializationLock());
}
}
@@ -2544,8 +2558,12 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
return null;
}
- protected NamedReentrantReadWriteLock getLoadingFromStoresLock() {
- return loadingFromStoresLock;
+ protected NamedReentrantReadWriteLock getLoadingFromWindStoreLock() {
+ return loadingFromWindStoreLock;
+ }
+
+ protected NamedReentrantReadWriteLock getLoadingFromGPSFixStoreLock() {
+ return loadingFromGPSFixStoreLock;
}
/**
diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java
index d6543d99646..be3fa9f41ee 100644
--- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java
+++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java
@@ -221,7 +221,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
}
@Override
- public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
+ public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
+ boolean notifyAboutGPSFixesAlreadyLoaded) {
// TODO Auto-generated method stub
}
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
index b63997ae0bf..4c1eab9c8c8 100755
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java
@@ -1159,7 +1159,7 @@ public class RacingEventServiceImpl implements RacingEventServiceWithTestSupport
}
TrackedRaceReplicator trackedRaceReplicator = new TrackedRaceReplicator(trackedRace);
trackedRaceReplicators.put(trackedRace, trackedRaceReplicator);
- trackedRace.addListener(trackedRaceReplicator, /* fire wind already loaded */ true);
+ trackedRace.addListener(trackedRaceReplicator, /* fire wind already loaded */ true, true);
}
}
diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java
index fd5abfa16d5..c8da7fbea47 100644
--- a/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java
+++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/masterdata/DummyTrackedRace.java
@@ -327,7 +327,8 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials {
}
@Override
- public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded) {
+ public void addListener(RaceChangeListener listener, boolean notifyAboutWindFixesAlreadyLoaded,
+ boolean notifyAboutGPSFixesAlreadyLoaded) {
// TODO Auto-generated method stub
}