From 6216843db4a738ed2d2de2655e0adca26ea28c74 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 14 Aug 2015 21:15:17 +0200 Subject: [PATCH 1/6] accept a competitor fix into a tracked race only if it's between start/end of tracking --- .../tracking/impl/DynamicTrackedRaceImpl.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) 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 52718e33165..117fd1cf7fc 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 @@ -143,12 +143,14 @@ DynamicTrackedRace, GPSTrackListener { @Override public void recordFix(Competitor competitor, GPSFixMoving fix) { - DynamicGPSFixTrack track = getTrack(competitor); - if (track != null) { - if (logger != null && logger.getLevel() != null && logger.getLevel().equals(Level.FINEST)) { - logger.finest(""+competitor.getName() + ": " + fix); + if (isFixWithinStartAndEndOfTracking(fix.getTimePoint())) { + DynamicGPSFixTrack track = getTrack(competitor); + if (track != null) { + if (logger != null && logger.getLevel() != null && logger.getLevel().equals(Level.FINEST)) { + logger.finest(""+competitor.getName() + ": " + fix); + } + track.addGPSFix(fix); // the track notifies this tracked race which in turn notifies its listeners } - track.addGPSFix(fix); // the track notifies this tracked race which in turn notifies its listeners } } @@ -161,12 +163,17 @@ DynamicTrackedRace, GPSTrackListener { @Override public void recordFix(Mark mark, GPSFix fix) { - if ((getStartOfTracking() == null || getStartOfTracking().compareTo(fix.getTimePoint()) <= 0) && - (getEndOfTracking() == null || getEndOfTracking().compareTo(fix.getTimePoint()) >= 0)) { + final TimePoint fixTimePoint = fix.getTimePoint(); + if (isFixWithinStartAndEndOfTracking(fixTimePoint)) { getOrCreateTrack(mark).addGPSFix(fix); } } + private boolean isFixWithinStartAndEndOfTracking(final TimePoint fixTimePoint) { + return (getStartOfTracking() == null || getStartOfTracking().compareTo(fixTimePoint) <= 0) && + (getEndOfTracking() == null || getEndOfTracking().compareTo(fixTimePoint) >= 0); + } + @Override public void setMillisecondsOverWhichToAverageSpeed(long millisecondsOverWhichToAverageSpeed) { this.millisecondsOverWhichToAverageSpeed = millisecondsOverWhichToAverageSpeed; From aa0de903edaaaa0b2c8ee6c4ebf0cd36bd5a288b Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 14 Aug 2015 21:22:43 +0200 Subject: [PATCH 2/6] improved Javadoc --- .../sailing/domain/tracking/impl/DynamicTrackedRaceImpl.java | 4 ++++ 1 file changed, 4 insertions(+) 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 117fd1cf7fc..b4e659e86e1 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 @@ -169,6 +169,10 @@ DynamicTrackedRace, GPSTrackListener { } } + /** + * A time point is considered "in" if it is (inclusively) between {@link #getStartOfTracking()} and {@link #getEndOfTracking()}. + * A null value for one of the two interval demarcations means an open-ended interval. + */ private boolean isFixWithinStartAndEndOfTracking(final TimePoint fixTimePoint) { return (getStartOfTracking() == null || getStartOfTracking().compareTo(fixTimePoint) <= 0) && (getEndOfTracking() == null || getEndOfTracking().compareTo(fixTimePoint) >= 0); From 0449203d4a722794ccc192b93c78ab3b903b1507 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 14 Aug 2015 22:05:47 +0200 Subject: [PATCH 3/6] added a failing test case that requires fixes to be filtered when loaded and loaded when tracking times are adjusted --- .../test/AbstractGPSFixStoreTest.java | 2 +- .../test/impl/TrackedRaceLoadsFixesTest.java | 53 +++++++++++++++++-- .../domain/tracking/impl/TrackedRaceImpl.java | 7 +-- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java index ec95fd9d208..679b6b97455 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java @@ -79,7 +79,7 @@ public class AbstractGPSFixStoreTest { mark, 0, new MillisecondsTimePoint(from), new MillisecondsTimePoint(to))); } - protected void testLength(Track track, long expected) { + protected void testNumberOfRawFixes(Track track, long expected) { track.lockForRead(); assertEquals(expected, size(track.getRawFixes())); track.unlockAfterRead(); diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java index 75c6b0978f8..e5f29b09623 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java @@ -40,6 +40,8 @@ import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl; import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; import com.sap.sailing.domain.tracking.impl.EmptyWindStore; import com.sap.sse.common.NoCorrespondingServiceRegisteredException; +import com.sap.sse.common.impl.MillisecondsDurationImpl; +import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.TimeRangeImpl; public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest { @@ -49,6 +51,49 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest { private Integer previouslyLoading = null; private int numFixesReceived = 0; + @Test + public void doesRaceLoadOnlyBetweenStartAndEndOfTracking() throws TransformationException, + NoCorrespondingServiceRegisteredException, InterruptedException { + Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null, + /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null); + Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2"); + DeviceIdentifier markDevice = new SmartphoneImeiIdentifier("imei2"); + Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark), + new WaypointImpl(mark2) })); + RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 })); + map(comp, device, 0, 10000); + map(mark, markDevice, 0, 10000); + + store.storeFix(device, createFix(100, 10, 20, 30, 40)); // before + store.storeFix(device, createFix(1100, 10, 20, 30, 40)); // in + store.storeFix(device, createFix(2100, 10, 20, 30, 40)); // after + store.storeFix(markDevice, createFix(100, 10, 20, 30, 40)); + store.storeFix(markDevice, createFix(1100, 10, 20, 30, 40)); + store.storeFix(markDevice, createFix(2100, 10, 20, 30, 40)); + + TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE, + EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */ + null, /* endDate */null, null, null, "a", null)); + DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race, + Collections. emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false, + OneDesignRankingMetric::new, mock(RaceLogResolver.class)); + trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(1000)); + trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2000)); + + trackedRace.attachRaceLog(raceLog); + trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog); + + testNumberOfRawFixes(trackedRace.getTrack(comp), 1); + testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1); + // now extend the tracking interval of the tracked race and assert that the additional fixes are loaded + trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2500)); + testNumberOfRawFixes(trackedRace.getTrack(comp), 2); + testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 2); + trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(0)); + testNumberOfRawFixes(trackedRace.getTrack(comp), 3); + testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 3); + } + @Test public void areFixesStoredInDb() throws TransformationException, NoCorrespondingServiceRegisteredException, InterruptedException { @@ -88,10 +133,10 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest { trackedRace.attachRaceLog(raceLog); trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog); - testLength(trackedRace.getTrack(comp), 10002); - testLength(trackedRace.getTrack(comp2), 1); - testLength(trackedRace.getOrCreateTrack(mark), 1); - testLength(trackedRace.getOrCreateTrack(mark2), 1); + testNumberOfRawFixes(trackedRace.getTrack(comp), 10002); + testNumberOfRawFixes(trackedRace.getTrack(comp2), 1); + testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1); + testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark2), 1); } @Test 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 3a785160eaa..e5ff6ed848a 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 @@ -3135,9 +3135,10 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl } /** - * Loads the GPS fixes as per the device registrations in the log into this race. The log is added to the - * addLogToMap data structure while holding this object's monitor, and all waiters on this object are notified when done - * with adding the log to addLogToMap. + * Loads the GPS fixes as per the device registrations in the log into this race. The log + * is added to the addLogToMap data structure while holding this object's monitor, and all + * waiters on this object are notified when done with adding the log to + * addLogToMap. */ private , EventT extends AbstractLogEvent, VisitorT> void loadFixesForLog( final LogT log, ConcurrentHashMap addLogToMap) { From 4ab8d5873eac00f2a6614e3a05885f75757aabdf Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 14 Aug 2015 22:25:51 +0200 Subject: [PATCH 4/6] introduced methods on GPSFixStore that handle cropping by start/end of tracking --- .../tracking/impl/MongoGPSFixStoreImpl.java | 26 +++++++++++++++++++ .../test/impl/TrackedRaceLoadsFixesTest.java | 1 - .../racelog/tracking/EmptyGPSFixStore.java | 12 ++++++++- .../domain/racelog/tracking/GPSFixStore.java | 15 +++++++++++ .../domain/tracking/impl/TrackedRaceImpl.java | 5 ++-- 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoGPSFixStoreImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoGPSFixStoreImpl.java index d01b682e045..9fe5ba23215 100755 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoGPSFixStoreImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoGPSFixStoreImpl.java @@ -191,12 +191,38 @@ public class MongoGPSFixStoreImpl implements MongoGPSFixStore { loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/); } + @Override + public void loadCompetitorTrack(DynamicGPSFixTrack track, AbstractLog log, + Competitor competitor, TimePoint start, TimePoint end) throws TransformationException { + List> mappings = new DeviceCompetitorMappingFinder<>(log).analyze().get(competitor); + if (mappings != null) { + for (DeviceMapping mapping : mappings) { + final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from()); + final TimePoint to = Util.getEarliestOfTimePoints(end, mapping.getTimeRange().to()); + loadTrack(track, mapping.getDevice(), from, to, true /*inclusive*/); + } + } + } + @Override public void loadMarkTrack(DynamicGPSFixTrack track, DeviceMapping mapping) throws TransformationException, NoCorrespondingServiceRegisteredException { loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true /*inclusive*/); } + @Override + public void loadMarkTrack(DynamicGPSFixTrack track, AbstractLog log, Mark mark, + TimePoint start, TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException { + List> mappings = new DeviceMarkMappingFinder<>(log).analyze().get(mark); + if (mappings != null) { + for (DeviceMapping mapping : mappings) { + final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from()); + final TimePoint to = Util.getEarliestOfTimePoints(end, mapping.getTimeRange().to()); + loadTrack(track, mapping.getDevice(), from, to, true /*inclusive*/); + } + } + } + @Override public void loadTrack(DynamicGPSFixTrack track, DeviceMapping mapping) throws NoCorrespondingServiceRegisteredException, TransformationException { diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java index e5f29b09623..a00fb29ea08 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java @@ -40,7 +40,6 @@ import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl; import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; import com.sap.sailing.domain.tracking.impl.EmptyWindStore; import com.sap.sse.common.NoCorrespondingServiceRegisteredException; -import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.TimeRangeImpl; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/EmptyGPSFixStore.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/EmptyGPSFixStore.java index af04e4c82a5..a763c559b66 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/EmptyGPSFixStore.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/EmptyGPSFixStore.java @@ -10,6 +10,7 @@ import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; import com.sap.sailing.domain.racelogtracking.DeviceMapping; import com.sap.sailing.domain.tracking.DynamicGPSFixTrack; import com.sap.sse.common.NoCorrespondingServiceRegisteredException; +import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimeRange; import com.sap.sse.common.WithID; @@ -64,6 +65,15 @@ public enum EmptyGPSFixStore implements GPSFixStore { @Override public void loadTrack(DynamicGPSFixTrack track, DeviceMapping mapping) throws NoCorrespondingServiceRegisteredException, TransformationException { - + } + + @Override + public void loadCompetitorTrack(DynamicGPSFixTrack track, AbstractLog log, + Competitor competitor, TimePoint start, TimePoint end) throws TransformationException { + } + + @Override + public void loadMarkTrack(DynamicGPSFixTrack track, AbstractLog log, Mark mark, + TimePoint start, TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException { } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java index 6db39a883c1..5c6c9203774 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java @@ -12,6 +12,7 @@ import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; import com.sap.sailing.domain.racelogtracking.DeviceMapping; import com.sap.sailing.domain.tracking.DynamicGPSFixTrack; import com.sap.sse.common.NoCorrespondingServiceRegisteredException; +import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimeRange; import com.sap.sse.common.WithID; @@ -23,12 +24,26 @@ public interface GPSFixStore { void loadCompetitorTrack(DynamicGPSFixTrack track, AbstractLog log, Competitor competitor) throws TransformationException; + /** + * Load all fixes within the start and end time point (inclusive) that correspond to the + * {@link DeviceCompetitorMappingEvent}s found in the {@code raceLog}. + */ + void loadCompetitorTrack(DynamicGPSFixTrack track, AbstractLog log, + Competitor competitor, TimePoint start, TimePoint end) throws TransformationException; + /** * Load all fixes that correspond to the {@link DeviceMarkMappingEvent}s found in the {@code raceLog}. */ void loadMarkTrack(DynamicGPSFixTrack track, AbstractLog log, Mark mark) throws TransformationException, NoCorrespondingServiceRegisteredException; + /** + * Load all fixes within the start and end time point (inclusive) that correspond to the + * {@link DeviceMarkMappingEvent}s found in the {@code raceLog}. + */ + void loadMarkTrack(DynamicGPSFixTrack track, AbstractLog log, Mark mark, TimePoint start, + TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException; + /** * Load all fixes that correspond to the {@code mapping}. */ 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 e5ff6ed848a..630b9dce918 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 @@ -3162,7 +3162,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl try { gpsFixStore.loadCompetitorTrack( (DynamicGPSFixTrack) tracks.get(competitor), log, - competitor); + competitor, getStartOfTracking(), getEndOfTracking()); } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { logger.log(Level.WARNING, "Could not load track for " + competitor, e); } @@ -3171,7 +3171,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl logger.info("Started loading mark tracks for " + getRace().getName()); for (Mark mark : getMarksFromRaceAndLogs()) { try { - gpsFixStore.loadMarkTrack((DynamicGPSFixTrack) getOrCreateTrack(mark), log, mark); + gpsFixStore.loadMarkTrack((DynamicGPSFixTrack) getOrCreateTrack(mark), + log, mark, getStartOfTracking(), getEndOfTracking()); } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { logger.log(Level.WARNING, "Could not load track for " + mark, e); } From d0ef305fa50d6d08d52404e34713fda63d8c70c4 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 18 Aug 2015 10:46:47 +0200 Subject: [PATCH 5/6] refactored loading of GPS fixes such that it is now also used when extending the tracking time interval --- .../META-INF/MANIFEST.MF | 1 + .../test/impl/TrackedRaceLoadsFixesTest.java | 52 +++++- .../domain/racelog/tracking/GPSFixStore.java | 14 ++ .../domain/tracking/impl/TrackedRaceImpl.java | 151 ++++++++++++------ 4 files changed, 172 insertions(+), 46 deletions(-) diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.racelogtrackingadapter.test/META-INF/MANIFEST.MF index eb7048450f1..3f9cbc1525d 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/META-INF/MANIFEST.MF @@ -18,4 +18,5 @@ Import-Package: com.sap.sailing.domain.abstractlog.regatta.events, com.sap.sailing.domain.persistence.racelog.tracking.impl, com.sap.sailing.domain.tractracadapter, com.sap.sailing.server.impl, + com.sap.sse.concurrent, javax.servlet.http;version="2.5.0" diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java index a00fb29ea08..e335d26b678 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java @@ -73,7 +73,7 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest { TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */ null, /* endDate */null, null, null, "a", null)); - DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race, + final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race, Collections. emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new, mock(RaceLogResolver.class)); trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(1000)); @@ -84,11 +84,61 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest { testNumberOfRawFixes(trackedRace.getTrack(comp), 1); testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1); + final Object mutex = new Object(); + final boolean[] doneLoading = new boolean[1]; + new Thread(() -> { + synchronized (trackedRace) { + while (!trackedRace.isLoadingFromGPSFixStore()) { + try { + trackedRace.wait(); + if (trackedRace.isLoadingFromGPSFixStore()) { + synchronized (mutex) { + doneLoading[0] = true; + mutex.notifyAll(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + }).start(); // now extend the tracking interval of the tracked race and assert that the additional fixes are loaded trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2500)); + // now wait for fixes to finish loading: + while (!doneLoading[0]) { + synchronized (mutex) { + mutex.wait(10000); + } + } + doneLoading[0] = false; testNumberOfRawFixes(trackedRace.getTrack(comp), 2); testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 2); + new Thread(() -> { + synchronized (trackedRace) { + while (!trackedRace.isLoadingFromGPSFixStore()) { + try { + trackedRace.wait(); + if (trackedRace.isLoadingFromGPSFixStore()) { + synchronized (mutex) { + doneLoading[0] = true; + mutex.notifyAll(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + }).start(); trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(0)); + // now wait for fixes to finish loading: + while (!doneLoading[0]) { + synchronized (mutex) { + mutex.wait(10000); + } + } + doneLoading[0] = false; testNumberOfRawFixes(trackedRace.getTrack(comp), 3); testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 3); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java index 5c6c9203774..eedda260a79 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/tracking/GPSFixStore.java @@ -27,6 +27,13 @@ public interface GPSFixStore { /** * Load all fixes within the start and end time point (inclusive) that correspond to the * {@link DeviceCompetitorMappingEvent}s found in the {@code raceLog}. + * + * @param start + * if null, the start of the time range for which to load fixes is only constrained by the + * device mapping intervals + * @param end + * if null, the end of the time range for which to load fixes is only constrained by the + * device mapping intervals */ void loadCompetitorTrack(DynamicGPSFixTrack track, AbstractLog log, Competitor competitor, TimePoint start, TimePoint end) throws TransformationException; @@ -40,6 +47,13 @@ public interface GPSFixStore { /** * Load all fixes within the start and end time point (inclusive) that correspond to the * {@link DeviceMarkMappingEvent}s found in the {@code raceLog}. + * + * @param start + * if null, the start of the time range for which to load fixes is only constrained by the + * device mapping intervals + * @param end + * if null, the end of the time range for which to load fixes is only constrained by the + * device mapping intervals */ void loadMarkTrack(DynamicGPSFixTrack track, AbstractLog log, Mark mark, TimePoint start, TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException; 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 630b9dce918..549610080ac 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 @@ -1795,12 +1795,35 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl return startTimeReceived; } - protected void setStartOfTrackingReceived(TimePoint startOfTracking) { + protected void setStartOfTrackingReceived(final TimePoint startOfTracking) { + final TimePoint oldStartOfTracking = this.startOfTrackingReceived; this.startOfTrackingReceived = startOfTracking; + if (!Util.equalsWithNull(oldStartOfTracking, startOfTracking) && + (startOfTracking == null || (oldStartOfTracking != null && startOfTracking.before(oldStartOfTracking)))) { + logger.info("Loading fixes after start of tracking for "+getRace()+" has been extended from "+oldStartOfTracking+" to "+startOfTracking); + loadGPSFixesForExtendedTimeRange(startOfTracking, oldStartOfTracking); + } } - protected void setEndOfTrackingReceived(TimePoint endOfTracking) { + private void loadGPSFixesForExtendedTimeRange(final TimePoint start, final TimePoint end) { + for (final RaceLog raceLog : attachedRaceLogs.values()) { + loadFixesForLog(raceLog, /* no need to addLogToMap because log has already been added during attachRaceLog */ null, + /* startOfTimeWindowToLoad */ start, /* endOfTimeWindowToLoad */ end); + } + for (final RegattaLog regattaLog : attachedRegattaLogs.values()) { + loadFixesForLog(regattaLog, /* no need to addLogToMap because log has already been added during attachRaceLog */ null, + /* startOfTimeWindowToLoad */ start, /* endOfTimeWindowToLoad */ end); + } + } + + protected void setEndOfTrackingReceived(final TimePoint endOfTracking) { + final TimePoint oldEndOfTracking = this.endOfTrackingReceived; this.endOfTrackingReceived = endOfTracking; + if (!Util.equalsWithNull(oldEndOfTracking, endOfTracking) && + (endOfTracking == null || (oldEndOfTracking != null && endOfTracking.after(oldEndOfTracking)))) { + logger.info("Loading fixes after end of tracking for "+getRace()+" has been extended from "+oldEndOfTracking+" to "+endOfTracking); + loadGPSFixesForExtendedTimeRange(oldEndOfTracking, endOfTracking); + } } /** @@ -3145,54 +3168,92 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl if (log != null) { // Use the new log, that possibly contains device mappings, to load GPSFix tracks from the DB // 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() + ", log " - + log.getId()) { - @Override - public void run() { - LockUtil.lockForRead(getSerializationLock()); - LockUtil.lockForWrite(getLoadingFromGPSFixStoreLock()); - synchronized (TrackedRaceImpl.this) { - loadingFromGPSFixStore = true; // indicates that the serialization lock is now safely held - addLogToMap.put(log.getId(), log); - TrackedRaceImpl.this.notifyAll(); - } - try { - logger.info("Started loading competitor tracks for " + getRace().getName() + " for log " + log.getId()); - for (Competitor competitor : race.getCompetitors()) { - try { - gpsFixStore.loadCompetitorTrack( - (DynamicGPSFixTrack) tracks.get(competitor), log, - competitor, getStartOfTracking(), getEndOfTracking()); - } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { - logger.log(Level.WARNING, "Could not load track for " + competitor, e); - } - } - logger.info("Finished loading competitor tracks for " + getRace().getName()); - logger.info("Started loading mark tracks for " + getRace().getName()); - for (Mark mark : getMarksFromRaceAndLogs()) { - try { - gpsFixStore.loadMarkTrack((DynamicGPSFixTrack) getOrCreateTrack(mark), - log, mark, getStartOfTracking(), getEndOfTracking()); - } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { - logger.log(Level.WARNING, "Could not load track for " + mark, e); - } - } - logger.info("Finished loading mark tracks for " + getRace().getName()); - } finally { - synchronized (TrackedRaceImpl.this) { - loadingFromGPSFixStore = false; - TrackedRaceImpl.this.notifyAll(); - } - LockUtil.unlockAfterWrite(getLoadingFromGPSFixStoreLock()); - LockUtil.unlockAfterRead(getSerializationLock()); - } - } - }.start(); + final TimePoint startOfTimeWindowToLoad = getStartOfTracking(); + final TimePoint endOfTimeWindowToLoad = getEndOfTracking(); + loadFixesForLog(log, addLogToMap, startOfTimeWindowToLoad, endOfTimeWindowToLoad); } else { logger.severe("Got a request to attach log for an empty log!"); } } + /** + * Loads the GPS fixes as per the device registrations in the log into this race, cropped to the time + * interval specified by startOfTimeWindowToLoad and endOfTimeWindowToLoad. The + * log is added to the addLogToMap data structure (if addLogToMap is not + * null) while holding this object's monitor, and all waiters on this object + * are notified when done with adding the log to addLogToMap. + * + * @param addLogToMap + * the log will be added to this map after the {@link #loadingFromGPSFixStore} flag has been set and only when the + * loading thread has successfully acquired the write lock of {@link #getLoadingFromGPSFixStoreLock()}. When done loading, + * all waiters on this object will be notified. If the map is not null, the key used to enter + * the log is the {@link AbstractLog#getId() log's ID}. + * @param startOfTimeWindowToLoad + * the time to use to crop the beginning of the time range for which to load fixes; if null, + * the start of the time range will be restricted only by the device mapping intervals + * @param endOfTimeWindowToLoad + * the time to use to crop the end of the time range for which to load fixes; if null, + * the end of the time range will be restricted only by the device mapping intervals + */ + private , EventT extends AbstractLogEvent, VisitorT> void loadFixesForLog(final LogT log, + ConcurrentHashMap addLogToMap, final TimePoint startOfTimeWindowToLoad, + final TimePoint endOfTimeWindowToLoad) { + new Thread("Mongo mark and competitor track loader for tracked race " + getRace().getName() + ", log " + + log.getId()+" from "+startOfTimeWindowToLoad+" to "+endOfTimeWindowToLoad) { + @Override + public void run() { + LockUtil.lockForRead(getSerializationLock()); + LockUtil.lockForWrite(getLoadingFromGPSFixStoreLock()); + synchronized (TrackedRaceImpl.this) { + loadingFromGPSFixStore = true; // indicates that the serialization lock is now safely held + if (addLogToMap != null) { + addLogToMap.put(log.getId(), log); + } + TrackedRaceImpl.this.notifyAll(); + } + try { + logger.info("Started loading competitor tracks for " + getRace().getName() + " for log " + log.getId()); + for (Competitor competitor : race.getCompetitors()) { + try { + gpsFixStore.loadCompetitorTrack( + (DynamicGPSFixTrack) tracks.get(competitor), log, + competitor, startOfTimeWindowToLoad, endOfTimeWindowToLoad); + } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { + logger.log(Level.WARNING, "Could not load track for " + competitor, e); + } + } + logger.info("Finished loading competitor tracks for " + getRace().getName()); + logger.info("Started loading mark tracks for " + getRace().getName()); + for (Mark mark : getMarksFromRaceAndLogs()) { + try { + gpsFixStore.loadMarkTrack((DynamicGPSFixTrack) getOrCreateTrack(mark), + log, mark, startOfTimeWindowToLoad, endOfTimeWindowToLoad); + } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { + logger.log(Level.WARNING, "Could not load track for " + mark, e); + } + } + logger.info("Finished loading mark tracks for " + getRace().getName()); + } finally { + synchronized (TrackedRaceImpl.this) { + loadingFromGPSFixStore = false; + TrackedRaceImpl.this.notifyAll(); + } + LockUtil.unlockAfterWrite(getLoadingFromGPSFixStoreLock()); + LockUtil.unlockAfterRead(getSerializationLock()); + logger.info("Thread "+getName()+" done."); + } + } + }.start(); + } + + /** + * Tells if currently the race is loading GPS fixes from the {@link GPSFixStore}. Clients may {@link Object#wait()} on this + * object and will be notified whenever a change of this flag's value occurs. + */ + public boolean isLoadingFromGPSFixStore() { + return loadingFromGPSFixStore; + } + /** * This can trigger fixes to be loaded, if there are {@link DeviceMapping}s in the {@code RaceLog}. * If multiple race logs are attached, the threads that are spawned to load fixes will do so one From 9403f904022fef899a719164c1e7c6ab4580416b Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 18 Aug 2015 11:23:08 +0200 Subject: [PATCH 6/6] made test for bug 3236 pass; introduced ways to wait for loading of GPS fixes for extended tracking interval --- .../test/impl/TrackedRaceLoadsFixesTest.java | 54 +------------------ .../tracking/impl/DynamicTrackedRaceImpl.java | 16 +++++- .../domain/tracking/impl/TrackedRaceImpl.java | 36 ++++++++----- 3 files changed, 38 insertions(+), 68 deletions(-) diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java index e335d26b678..501f9f43025 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java @@ -84,61 +84,11 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest { testNumberOfRawFixes(trackedRace.getTrack(comp), 1); testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 1); - final Object mutex = new Object(); - final boolean[] doneLoading = new boolean[1]; - new Thread(() -> { - synchronized (trackedRace) { - while (!trackedRace.isLoadingFromGPSFixStore()) { - try { - trackedRace.wait(); - if (trackedRace.isLoadingFromGPSFixStore()) { - synchronized (mutex) { - doneLoading[0] = true; - mutex.notifyAll(); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } - }).start(); // now extend the tracking interval of the tracked race and assert that the additional fixes are loaded - trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2500)); - // now wait for fixes to finish loading: - while (!doneLoading[0]) { - synchronized (mutex) { - mutex.wait(10000); - } - } - doneLoading[0] = false; + trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(2500), /* wait for fixes to load */ true); testNumberOfRawFixes(trackedRace.getTrack(comp), 2); testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 2); - new Thread(() -> { - synchronized (trackedRace) { - while (!trackedRace.isLoadingFromGPSFixStore()) { - try { - trackedRace.wait(); - if (trackedRace.isLoadingFromGPSFixStore()) { - synchronized (mutex) { - doneLoading[0] = true; - mutex.notifyAll(); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } - }).start(); - trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(0)); - // now wait for fixes to finish loading: - while (!doneLoading[0]) { - synchronized (mutex) { - mutex.wait(10000); - } - } - doneLoading[0] = false; + trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(0), /* wait for fixes to load */ true); testNumberOfRawFixes(trackedRace.getTrack(comp), 3); testNumberOfRawFixes(trackedRace.getOrCreateTrack(mark), 3); } 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 b4e659e86e1..879f70c4de1 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 @@ -624,16 +624,28 @@ DynamicTrackedRace, GPSTrackListener { @Override public void setStartOfTrackingReceived(TimePoint startOfTrackingReceived) { + setStartOfTrackingReceived(startOfTrackingReceived, /* waitForGPSFixesToLoad */ false); + } + + public void setStartOfTrackingReceived(TimePoint startOfTrackingReceived, final boolean waitForGPSFixesToLoad) { if (!Util.equalsWithNull(startOfTrackingReceived, getStartOfTracking())) { - super.setStartOfTrackingReceived(startOfTrackingReceived); + super.setStartOfTrackingReceived(startOfTrackingReceived, waitForGPSFixesToLoad); notifyListenersStartOfTrackingChanged(getStartOfTracking()); } } @Override public void setEndOfTrackingReceived(TimePoint endOfTrackingReceived) { + setEndOfTrackingReceived(endOfTrackingReceived, /* waitForGPSFixesToLoad */ false); + } + + /** + * Non-interface method, mainly for testing purposes; callers can ask to wait for the loading of fixes in the + * potentially extended tracking interval to finish before returning from this method. + */ + public void setEndOfTrackingReceived(final TimePoint endOfTrackingReceived, final boolean waitForGPSFixesToLoad) { if (!Util.equalsWithNull(endOfTrackingReceived, getEndOfTracking())) { - super.setEndOfTrackingReceived(endOfTrackingReceived); + super.setEndOfTrackingReceived(endOfTrackingReceived, waitForGPSFixesToLoad); notifyListenersEndOfTrackingChanged(getEndOfTracking()); } } 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 549610080ac..7ed289d11de 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 @@ -1795,34 +1795,34 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl return startTimeReceived; } - protected void setStartOfTrackingReceived(final TimePoint startOfTracking) { + protected void setStartOfTrackingReceived(final TimePoint startOfTracking, final boolean waitForGPSFixesToLoad) { final TimePoint oldStartOfTracking = this.startOfTrackingReceived; this.startOfTrackingReceived = startOfTracking; if (!Util.equalsWithNull(oldStartOfTracking, startOfTracking) && (startOfTracking == null || (oldStartOfTracking != null && startOfTracking.before(oldStartOfTracking)))) { logger.info("Loading fixes after start of tracking for "+getRace()+" has been extended from "+oldStartOfTracking+" to "+startOfTracking); - loadGPSFixesForExtendedTimeRange(startOfTracking, oldStartOfTracking); + loadGPSFixesForExtendedTimeRange(startOfTracking, oldStartOfTracking, waitForGPSFixesToLoad); } } - private void loadGPSFixesForExtendedTimeRange(final TimePoint start, final TimePoint end) { + private void loadGPSFixesForExtendedTimeRange(final TimePoint start, final TimePoint end, final boolean waitForGPSFixesToLoad) { for (final RaceLog raceLog : attachedRaceLogs.values()) { loadFixesForLog(raceLog, /* no need to addLogToMap because log has already been added during attachRaceLog */ null, - /* startOfTimeWindowToLoad */ start, /* endOfTimeWindowToLoad */ end); + /* startOfTimeWindowToLoad */ start, /* endOfTimeWindowToLoad */ end, waitForGPSFixesToLoad); } for (final RegattaLog regattaLog : attachedRegattaLogs.values()) { loadFixesForLog(regattaLog, /* no need to addLogToMap because log has already been added during attachRaceLog */ null, - /* startOfTimeWindowToLoad */ start, /* endOfTimeWindowToLoad */ end); + /* startOfTimeWindowToLoad */ start, /* endOfTimeWindowToLoad */ end, waitForGPSFixesToLoad); } } - protected void setEndOfTrackingReceived(final TimePoint endOfTracking) { + protected void setEndOfTrackingReceived(final TimePoint endOfTracking, final boolean waitForGPSFixesToLoad) { final TimePoint oldEndOfTracking = this.endOfTrackingReceived; this.endOfTrackingReceived = endOfTracking; if (!Util.equalsWithNull(oldEndOfTracking, endOfTracking) && (endOfTracking == null || (oldEndOfTracking != null && endOfTracking.after(oldEndOfTracking)))) { logger.info("Loading fixes after end of tracking for "+getRace()+" has been extended from "+oldEndOfTracking+" to "+endOfTracking); - loadGPSFixesForExtendedTimeRange(oldEndOfTracking, endOfTracking); + loadGPSFixesForExtendedTimeRange(oldEndOfTracking, endOfTracking, waitForGPSFixesToLoad); } } @@ -3164,13 +3164,13 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl * addLogToMap. */ private , EventT extends AbstractLogEvent, VisitorT> void loadFixesForLog( - final LogT log, ConcurrentHashMap addLogToMap) { + final LogT log, ConcurrentHashMap addLogToMap, final boolean waitForGPSFixesToLoad) { if (log != null) { // Use the new log, that possibly contains device mappings, to load GPSFix tracks from the DB // When this tracked race is to be serialized, wait for the loading from stores to complete. final TimePoint startOfTimeWindowToLoad = getStartOfTracking(); final TimePoint endOfTimeWindowToLoad = getEndOfTracking(); - loadFixesForLog(log, addLogToMap, startOfTimeWindowToLoad, endOfTimeWindowToLoad); + loadFixesForLog(log, addLogToMap, startOfTimeWindowToLoad, endOfTimeWindowToLoad, waitForGPSFixesToLoad); } else { logger.severe("Got a request to attach log for an empty log!"); } @@ -3197,8 +3197,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl */ private , EventT extends AbstractLogEvent, VisitorT> void loadFixesForLog(final LogT log, ConcurrentHashMap addLogToMap, final TimePoint startOfTimeWindowToLoad, - final TimePoint endOfTimeWindowToLoad) { - new Thread("Mongo mark and competitor track loader for tracked race " + getRace().getName() + ", log " + final TimePoint endOfTimeWindowToLoad, final boolean waitForGPSFixesToLoad) { + Thread t = new Thread("Mongo mark and competitor track loader for tracked race " + getRace().getName() + ", log " + log.getId()+" from "+startOfTimeWindowToLoad+" to "+endOfTimeWindowToLoad) { @Override public void run() { @@ -3243,7 +3243,15 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl logger.info("Thread "+getName()+" done."); } } - }.start(); + }; + t.start(); + if (waitForGPSFixesToLoad) { + try { + t.join(); + } catch (InterruptedException e) { + logger.log(Level.WARNING, "Got interrupted while waiting for loading of GPS fixes from log "+log+" to finish", e); + } + } } /** @@ -3261,7 +3269,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl */ @Override public void attachRaceLog(final RaceLog raceLog) { - loadFixesForLog(raceLog, attachedRaceLogs); + loadFixesForLog(raceLog, attachedRaceLogs, /* wait for fixes to load */ false); } @Override @@ -3306,7 +3314,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl @Override public void attachRegattaLog(RegattaLog regattaLog) { - loadFixesForLog(regattaLog, attachedRegattaLogs); + loadFixesForLog(regattaLog, attachedRegattaLogs, /* wait for fixes to load */ false); } @Override