From 5e63483d77bfd16d964e33e4a318acc6630f02a5 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 11 Jan 2021 18:35:57 +0100 Subject: [PATCH 1/7] bug5477: initial implementation producing a RaceLogResultsAreOfficialEvent when TracTrac reports OFFICIAL race status --- .../impl/DomainObjectFactoryImpl.java | 10 ++++++ .../impl/MongoObjectFactoryImpl.java | 16 +++++++++ .../impl/MongoRaceLogStoreVisitor.java | 7 ++++ .../test/ResultsAreOfficialFinderTest.java | 35 +++++++++++++++++++ .../racelog/state/test/RaceStateTest.java | 8 +++-- .../abstractlog/race/RaceLogEventVisitor.java | 2 ++ .../race/RaceLogResultsAreOfficialEvent.java | 5 +++ .../impl/ResultsAreOfficialFinder.java | 30 ++++++++++++++++ .../impl/AbstractRaceLogChangedVisitor.java | 6 ++++ .../race/impl/BaseRaceLogEventVisitor.java | 6 ++++ .../RaceLogResultsAreOfficialEventImpl.java | 32 +++++++++++++++++ .../abstractlog/race/state/RaceState.java | 12 ++++++- .../race/state/RaceStateChangedListener.java | 2 +- .../race/state/ReadonlyRaceState.java | 5 +++ .../impl/BaseRaceStateChangedListener.java | 4 +++ .../state/impl/RaceStateChangedListeners.java | 7 ++++ .../race/state/impl/RaceStateImpl.java | 6 ++++ .../state/impl/ReadonlyRaceStateImpl.java | 18 ++++++++-- ...CompetitorStatusWithRaceLogReconciler.java | 9 +++-- .../impl/RaceColumnRaceLogReplicator.java | 6 ++++ .../test/StoreAndLoadRaceLogEventsTest.java | 11 ++++++ .../racelog/impl/RaceLogEventSerializer.java | 14 ++++++-- ...eLogResultsAreOfficialEventSerializer.java | 33 +++++++++++++++++ .../racelog/RaceLogEventSerializerTest.java | 4 ++- 24 files changed, 277 insertions(+), 11 deletions(-) create mode 100755 java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ResultsAreOfficialFinderTest.java create mode 100755 java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogResultsAreOfficialEvent.java create mode 100755 java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ResultsAreOfficialFinder.java create mode 100755 java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogResultsAreOfficialEventImpl.java create mode 100755 java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogResultsAreOfficialEventSerializer.java diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 721b992d996..09c01d9210d 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -72,6 +72,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent; @@ -95,6 +96,7 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPathfinderEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogProtestStartTimeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventImpl; +import com.sap.sailing.domain.abstractlog.race.impl.RaceLogResultsAreOfficialEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRevokeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartOfTrackingEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartProcedureChangedEventImpl; @@ -1661,6 +1663,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { resultEvent = loadRaceLogORCScratchBoatEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); } else if (eventClass.equals(RaceLogORCImpliedWindSourceEvent.class.getSimpleName())) { resultEvent = loadRaceLogORCSetImpliedWindEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); + } else if (eventClass.equals(RaceLogResultsAreOfficialEvent.class.getSimpleName())) { + resultEvent = loadRaceLogResultsAreOfficialEvent(createdAt, author, logicalTimePoint, id, passId, competitors, dbObject); } else { throw new IllegalStateException(String.format("Unknown RaceLogEvent type %s", eventClass)); } @@ -1686,6 +1690,12 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { } return new RaceLogORCImpliedWindSourceEventImpl(createdAt, logicalTimePoint, author, id, passId, impliedWindSource); } + + private RaceLogEvent loadRaceLogResultsAreOfficialEvent(TimePoint createdAt, + AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, + List competitors, Document dbObject) throws JsonDeserializationException, ParseException { + return new RaceLogResultsAreOfficialEventImpl(createdAt, logicalTimePoint, author, id, passId); + } private RaceLogEvent loadRaceLogUseCompetitorsFromRaceLogEvent(TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id, Integer passId, List competitors, diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java index 29ae0712349..49d32dddc92 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java @@ -53,6 +53,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent; @@ -940,6 +941,13 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogWindFix(event)); return result; } + + public Document storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogResultsAreOfficialEvent event) { + Document result = new Document(); + storeRaceLogIdentifier(raceLogIdentifier, result); + result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogResultsAreOfficialEvent(event)); + return result; + } public Document storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogDenoteForTrackingEvent event) { Document result = new Document(); @@ -1143,6 +1151,14 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { storeTimePoint(event.getToInclusive(), result, toField); } } + + private Object storeRaceLogResultsAreOfficialEvent(RaceLogResultsAreOfficialEvent event) { + Document result = new Document(); + storeRaceLogEventProperties(event, result); + result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogResultsAreOfficialEvent.class.getSimpleName()); + // currently there are no further properties; the event speaks for itself + return result; + } private Object storeRaceLogDenoteForTrackingEvent(RaceLogDenoteForTrackingEvent event) { Document result = new Document(); diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRaceLogStoreVisitor.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRaceLogStoreVisitor.java index a6065185571..684e4a7be04 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRaceLogStoreVisitor.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoRaceLogStoreVisitor.java @@ -21,6 +21,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent; @@ -216,4 +217,10 @@ public class MongoRaceLogStoreVisitor implements RaceLogEventVisitor { Document object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event); mongoObjectFactory.storeRaceLogEventEvent(object); } + + @Override + public void visit(RaceLogResultsAreOfficialEvent event) { + Document object = mongoObjectFactory.storeRaceLogEntry(raceLogIdentifier, event); + mongoObjectFactory.storeRaceLogEventEvent(object); + } } diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ResultsAreOfficialFinderTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ResultsAreOfficialFinderTest.java new file mode 100755 index 00000000000..d13970cfbe9 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ResultsAreOfficialFinderTest.java @@ -0,0 +1,35 @@ +package com.sap.sailing.domain.racelog.analyzing.test; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; + +import org.junit.Test; + +import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.ResultsAreOfficialFinder; + +public class ResultsAreOfficialFinderTest extends RaceLogAnalyzerTest { + @Override + protected ResultsAreOfficialFinder createAnalyzer(RaceLog raceLog) { + return new ResultsAreOfficialFinder(raceLog); + } + + @Test + public void testFalseForNoResultsAreOfficialEvent() { + RaceLogEvent event1 = createEvent(RaceLogEvent.class, 1); + raceLog.add(event1); + assertNull(analyzer.analyze()); + } + + @Test + public void testSingleLast() { + RaceLogResultsAreOfficialEvent event1 = createEvent(RaceLogResultsAreOfficialEvent.class, 1); + RaceLogResultsAreOfficialEvent event2 = createEvent(RaceLogResultsAreOfficialEvent.class, 2); + raceLog.add(event1); + raceLog.add(event2); + RaceLogResultsAreOfficialEvent result = analyzer.analyze(); + assertSame(event2, result); + } +} diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java index 43652c07516..2d88711f5b5 100644 --- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java +++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/state/test/RaceStateTest.java @@ -197,11 +197,15 @@ public class RaceStateTest { @Test public void testGetRacingProcedure() throws InterruptedException { - state.setRacingProcedure(nowMock, RacingProcedureType.RRS26); - GateStartRacingProcedure procedure = state.getTypedRacingProcedure(GateStartRacingProcedure.class); assertNull(procedure); } + @Test + public void testResultsAreOfficial() { + assertFalse(state.isResultsAreOfficial()); + state.setResultsAreOfficial(TimePoint.now()); + assertTrue(state.isResultsAreOfficial()); + } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogEventVisitor.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogEventVisitor.java index 287d30bd4dc..efa80b58559 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogEventVisitor.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogEventVisitor.java @@ -66,4 +66,6 @@ public interface RaceLogEventVisitor { void visit(RaceLogORCScratchBoatEvent event); void visit(RaceLogORCImpliedWindSourceEvent event); + + void visit(RaceLogResultsAreOfficialEvent event); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogResultsAreOfficialEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogResultsAreOfficialEvent.java new file mode 100755 index 00000000000..6914cef5719 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/RaceLogResultsAreOfficialEvent.java @@ -0,0 +1,5 @@ +package com.sap.sailing.domain.abstractlog.race; + +public interface RaceLogResultsAreOfficialEvent extends RaceLogEvent { + +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ResultsAreOfficialFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ResultsAreOfficialFinder.java new file mode 100755 index 00000000000..ae62f0db26c --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ResultsAreOfficialFinder.java @@ -0,0 +1,30 @@ +package com.sap.sailing.domain.abstractlog.race.analyzing.impl; + +import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; + +/** + * Analysis returns the most recent {@link RaceLogResultsAreOfficialEvent}. + *

+ * + * If there is no {@link RaceLogResultsAreOfficialEvent} in log, null is returned. Otherwise a single + * {@link RaceLogResultsAreOfficialEvent} is returned. + * + */ +public class ResultsAreOfficialFinder extends RaceLogAnalyzer { + + public ResultsAreOfficialFinder(RaceLog raceLog) { + super(raceLog); + } + + @Override + protected RaceLogResultsAreOfficialEvent performAnalysis() { + for (final RaceLogEvent e : getAllEventsDescending()) { + if (e instanceof RaceLogResultsAreOfficialEvent) { + return (RaceLogResultsAreOfficialEvent) e; + } + } + return null; + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/AbstractRaceLogChangedVisitor.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/AbstractRaceLogChangedVisitor.java index 3335971c022..29cc30666e5 100755 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/AbstractRaceLogChangedVisitor.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/AbstractRaceLogChangedVisitor.java @@ -18,6 +18,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent; @@ -168,4 +169,9 @@ public abstract class AbstractRaceLogChangedVisitor implements RaceLogEventVisit public void visit(RaceLogORCImpliedWindSourceEvent event) { notifyListenerAboutEventAdded(event); } + + @Override + public void visit(RaceLogResultsAreOfficialEvent event) { + notifyListenerAboutEventAdded(event); + } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/BaseRaceLogEventVisitor.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/BaseRaceLogEventVisitor.java index 733d2542567..2f1fbe543d5 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/BaseRaceLogEventVisitor.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/BaseRaceLogEventVisitor.java @@ -17,6 +17,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent; @@ -174,4 +175,9 @@ public abstract class BaseRaceLogEventVisitor implements RaceLogEventVisitor { public void visit(RaceLogORCImpliedWindSourceEvent event) { } + + @Override + public void visit(RaceLogResultsAreOfficialEvent event) { + + } } \ No newline at end of file diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogResultsAreOfficialEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogResultsAreOfficialEventImpl.java new file mode 100755 index 00000000000..886ceaea083 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/RaceLogResultsAreOfficialEventImpl.java @@ -0,0 +1,32 @@ +package com.sap.sailing.domain.abstractlog.race.impl; + +import java.io.Serializable; + +import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; +import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; +import com.sap.sse.common.TimePoint; + +public class RaceLogResultsAreOfficialEventImpl extends RaceLogEventImpl implements RaceLogResultsAreOfficialEvent { + private static final long serialVersionUID = -1796278009919318553L; + + public RaceLogResultsAreOfficialEventImpl(TimePoint createdAt, TimePoint logicalTimePoint, + AbstractLogEventAuthor author, Serializable pId, int pPassId) { + super(createdAt, logicalTimePoint, author, pId, pPassId); + } + + public RaceLogResultsAreOfficialEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author, int pPassId) { + this(now(), logicalTimePoint, author, randId(), pPassId); + } + + + @Override + public void accept(RaceLogEventVisitor visitor) { + visitor.visit(this); + } + + @Override + public String getShortInfo() { + return "Indicates that the results of this race are now official"; + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java index d38448c1b17..6d1d16676ad 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceState.java @@ -4,6 +4,7 @@ import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.CompetitorResults; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier; import com.sap.sailing.domain.abstractlog.race.scoring.AdditionalScoringInformationType; import com.sap.sailing.domain.abstractlog.race.scoring.RaceLogAdditionalScoringInformationEvent; @@ -146,7 +147,6 @@ public interface RaceState extends ReadonlyRaceState { /** * Enters a new wind fix for this race. - * @param isMagnetic TODO */ void setWindFix(TimePoint now, Wind wind, boolean isMagnetic); @@ -162,4 +162,14 @@ public interface RaceState extends ReadonlyRaceState { * forces a RaceStateUpdate */ void forceUpdate(); + + /** + * Marks the results of the race to which this state belongs as official, using a + * {@link RaceLogResultsAreOfficialEvent}. + * + * @param timePoint + * the time point at which the results were declared official + * @see #isResultsAreOfficial() + */ + void setResultsAreOfficial(TimePoint timePoint); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceStateChangedListener.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceStateChangedListener.java index 8a9551a0fd0..0c2272dd3b8 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceStateChangedListener.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/RaceStateChangedListener.java @@ -18,5 +18,5 @@ public interface RaceStateChangedListener { void onCourseDesignChanged(ReadonlyRaceState state); void onWindFixChanged(ReadonlyRaceState state); void onTagEventsChanged(ReadonlyRaceState state); - + void onResultsAreOfficialChanged(ReadonlyRaceState state); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/ReadonlyRaceState.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/ReadonlyRaceState.java index 9cd979abd0a..ad052497d8a 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/ReadonlyRaceState.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/ReadonlyRaceState.java @@ -102,6 +102,11 @@ public interface ReadonlyRaceState extends RaceStateEventProcessor { * Gets the races overall status. */ RaceLogRaceStatus getStatus(); + + /** + * Tells if the results found for this race have been confirmed officially. + */ + boolean isResultsAreOfficial(); /** * If there is a start time set for the current pass, returns it. Otherwise null. diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/BaseRaceStateChangedListener.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/BaseRaceStateChangedListener.java index 3dc7a0fc842..462dba13ff5 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/BaseRaceStateChangedListener.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/BaseRaceStateChangedListener.java @@ -68,4 +68,8 @@ public abstract class BaseRaceStateChangedListener implements RaceStateChangedLi } + @Override + public void onResultsAreOfficialChanged(ReadonlyRaceState state) { + + } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateChangedListeners.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateChangedListeners.java index c9bbd7dcc7c..0bd67ff6ee5 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateChangedListeners.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateChangedListeners.java @@ -118,4 +118,11 @@ public class RaceStateChangedListeners extends HashSet listener.onTagEventsChanged(state); } } + + @Override + public void onResultsAreOfficialChanged(ReadonlyRaceState state) { + for (RaceStateChangedListener listener : getWorkingCopyOfListeners()) { + listener.onResultsAreOfficialChanged(state); + } + } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java index 1fab6dffd8c..3145fbaa783 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java @@ -20,6 +20,7 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFlagEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogProtestStartTimeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventImpl; +import com.sap.sailing.domain.abstractlog.race.impl.RaceLogResultsAreOfficialEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartProcedureChangedEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogWindFixEventImpl; @@ -135,6 +136,11 @@ public class RaceStateImpl extends ReadonlyRaceStateImpl implements RaceState { // ensure caches are synched forceUpdate(); } + + @Override + public void setResultsAreOfficial(TimePoint timePoint) { + raceLog.add(new RaceLogResultsAreOfficialEventImpl(timePoint, author, raceLog.getCurrentPassId())); + } @Override public void setProtestTime(TimePoint now, TimeRange protestTime) { diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java index aa85034cc1d..1ef7657569a 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/ReadonlyRaceStateImpl.java @@ -13,6 +13,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogChangedListener; import com.sap.sailing.domain.abstractlog.race.RaceLogDependentStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogTagEvent; import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier; @@ -27,6 +28,7 @@ import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceStatusAnalyzer; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceStatusAnalyzer.Clock; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RacingProcedureTypeAnalyzer; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.ResultsAreOfficialFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinderResult; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.TagFinder; @@ -165,6 +167,7 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL private final FinishingTimeFinder finishingTimeAnalyzer; private final FinishedTimeFinder finishedTimeAnalyzer; private final ProtestTimeFinder protestTimeAnalyzer; + private final ResultsAreOfficialFinder resultsAreOfficialAnalyzer; private final FinishPositioningListFinder finishPositioningListAnalyzer; private final ConfirmedFinishPositioningListFinder confirmedFinishPositioningListAnalyzer; @@ -205,6 +208,8 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL private Iterable cachedTagEvents; + private boolean cachedResultsAreOfficial; + private int cachedPassId; private StartTimeFinderResult cachedStartTimeFinderResult; private TimePoint cachedFinishingTime; @@ -250,19 +255,18 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL this.finishingTimeAnalyzer = new FinishingTimeFinder(raceLog); this.finishedTimeAnalyzer = new FinishedTimeFinder(raceLog); this.protestTimeAnalyzer = new ProtestTimeFinder(raceLog); + this.resultsAreOfficialAnalyzer = new ResultsAreOfficialFinder(raceLog); this.finishPositioningListAnalyzer = new FinishPositioningListFinder(raceLog); this.confirmedFinishPositioningListAnalyzer = new ConfirmedFinishPositioningListFinder(raceLog); this.courseDesignerAnalyzer = new LastPublishedCourseDesignFinder(raceLog, /* onlyCoursesWithValidWaypointList */ false); this.lastWindFixAnalyzer = new LastWindFixFinder(raceLog); this.tagAnalyzer = new TagFinder(raceLog); - this.raceStateToObserveListener = new BaseRaceStateChangedListener() { @Override public void onStartTimeChanged(ReadonlyRaceState state) { update(); } }; - this.cachedRacingProcedureTypeNoFallback = determineInitialProcedureType(); if (this.cachedRacingProcedureTypeNoFallback == null || this.cachedRacingProcedureTypeNoFallback == RacingProcedureType.UNKNOWN) { @@ -368,6 +372,11 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL return cachedRaceStatus; } + @Override + public boolean isResultsAreOfficial() { + return cachedResultsAreOfficial; + } + /** * Finds out whether any of the time points in {@link #timePointsWhenRaceStatusMayChange} falls into the time range * provided. In this case we assume that a race status update may have happened between the time point when the @@ -581,6 +590,11 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL cachedTagEvents = tagEvents; changedListeners.onTagEventsChanged(this); } + final RaceLogResultsAreOfficialEvent resultsAreOfficialEvent = resultsAreOfficialAnalyzer.analyze(); + if ((resultsAreOfficialEvent != null) != cachedResultsAreOfficial) { + cachedResultsAreOfficial = resultsAreOfficialEvent != null; + changedListeners.onResultsAreOfficialChanged(this); + } } /** diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceAndCompetitorStatusWithRaceLogReconciler.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceAndCompetitorStatusWithRaceLogReconciler.java index bd36f9836e2..c0e4d0007d0 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceAndCompetitorStatusWithRaceLogReconciler.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceAndCompetitorStatusWithRaceLogReconciler.java @@ -28,6 +28,7 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFinishPositioningConf import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFlagEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl; import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; +import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl; import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CompetitorWithBoat; @@ -207,7 +208,7 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler { */ public void reconcileRaceStatus(IRace tractracRace, TrackedRace trackedRace) { final RaceStatusType raceStatus = tractracRace.getStatus(); - final MillisecondsTimePoint raceStatusUpdateTime = new MillisecondsTimePoint(tractracRace.getStatusTime()); + final TimePoint raceStatusUpdateTime = TimePoint.of(tractracRace.getStatusTime()); RaceLogFlagEvent abortingFlagEvent = null; for (final RaceLog raceLog : trackedRace.getAttachedRaceLogs()) { if (abortingFlagEvent == null) { @@ -216,6 +217,10 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler { } } final RaceLog defaultRaceLog = getDefaultRaceLog(trackedRace); + if (raceStatus == RaceStatusType.OFFICIAL && !ReadonlyRaceStateImpl.getOrCreate(raceLogResolver, defaultRaceLog).isResultsAreOfficial()) { + // FIXME bug5477: synchronize this with any pending competitor updates providing official results which are managed in a queue with a separate thread processing it + RaceStateImpl.create(raceLogResolver, defaultRaceLog, raceLogEventAuthor).setResultsAreOfficial(raceStatusUpdateTime); + } if (abortingFlagEvent != null && !isAbortedState(raceStatus) && raceStatusUpdateTime.after(abortingFlagEvent.getLogicalTimePoint())) { startNewPass(raceStatusUpdateTime, defaultRaceLog); } else if (isAbortedState(raceStatus) && @@ -227,7 +232,7 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler { } } - protected void startNewPass(final MillisecondsTimePoint timePointForStartOfNewPass, final RaceLog raceLog) { + protected void startNewPass(final TimePoint timePointForStartOfNewPass, final RaceLog raceLog) { raceLog.add(new RaceLogPassChangeEventImpl(timePointForStartOfNewPass, raceLogEventAuthor, raceLog.getCurrentPassId() + 1)); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java index 5aa49dd6095..7e593ce50a0 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RaceColumnRaceLogReplicator.java @@ -20,6 +20,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent; @@ -192,4 +193,9 @@ public class RaceColumnRaceLogReplicator implements RaceLogEventVisitor, Seriali public void visit(RaceLogORCImpliedWindSourceEvent event) { notifyOnAdd(event); } + + @Override + public void visit(RaceLogResultsAreOfficialEvent event) { + notifyOnAdd(event); + } } diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogEventsTest.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogEventsTest.java index 1a636c2da3e..92f9de63378 100644 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogEventsTest.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/StoreAndLoadRaceLogEventsTest.java @@ -25,11 +25,13 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFlagEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventImpl; +import com.sap.sailing.domain.abstractlog.race.impl.RaceLogResultsAreOfficialEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRevokeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl; import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent; @@ -121,6 +123,15 @@ public class StoreAndLoadRaceLogEventsTest extends AbstractMongoDBTest { assertEquals(lowerFlag, actualEvent.getLowerFlag()); assertEquals(isDisplayed, actualEvent.isDisplayed()); } + + @Test + public void testStoreAndLoadResultsAreOfficialEvent() { + RaceLogResultsAreOfficialEvent expectedEvent = new RaceLogResultsAreOfficialEventImpl(MillisecondsTimePoint.now(), expectedEventTime, + author, expectedId, expectedPassId); + Document dbObject = mongoFactory.storeRaceLogEntry(logIdentifier, expectedEvent); + RaceLogResultsAreOfficialEvent actualEvent = loadEvent(dbObject); + assertBaseFields(expectedEvent, actualEvent); + } @Test public void testStoreAndLoadPassChangeEvent() { diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogEventSerializer.java index ba4e88fd819..ab44fb2cc5b 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogEventSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogEventSerializer.java @@ -20,6 +20,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogPathfinderEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogProtestStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogStartProcedureChangedEvent; @@ -90,7 +91,8 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac new RaceLogORCLegDataEventSerializer(competitorSerializer), new RaceLogORCCertificateAssignmentEventSerializer(competitorSerializer), new RaceLogORCScratchBoatEventSerializer(competitorSerializer), - new RaceLogORCImpliedWindSourceEventSerializer(competitorSerializer)); + new RaceLogORCImpliedWindSourceEventSerializer(competitorSerializer), + new RaceLogResultsAreOfficialEventSerializer(competitorSerializer)); } private final JsonSerializer flagEventSerializer; @@ -121,6 +123,7 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac private final JsonSerializer orcCertificateAssignmentEventSerializer; private final JsonSerializer orcScratchBoatEventSerializer; private final JsonSerializer orcImpliedWindSourceEventSerializer; + private final JsonSerializer resultsAreOfficialEventSerializer; private JsonSerializer chosenSerializer; @@ -153,7 +156,8 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac JsonSerializer orcLegDataEventSerializer, JsonSerializer orcCertificateAssignmentEventSerializer, JsonSerializer orcScratchBoatEventSerializer, - JsonSerializer orcImpliedWindSourceEventSerializer) { + JsonSerializer orcImpliedWindSourceEventSerializer, + JsonSerializer resultsAreOfficialEventSerializer) { this.flagEventSerializer = flagEventSerializer; this.startTimeSerializer = startTimeSerializer; this.raceStatusSerializer = raceStatusSerializer; @@ -182,6 +186,7 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac this.orcCertificateAssignmentEventSerializer = orcCertificateAssignmentEventSerializer; this.orcScratchBoatEventSerializer = orcScratchBoatEventSerializer; this.orcImpliedWindSourceEventSerializer = orcImpliedWindSourceEventSerializer; + this.resultsAreOfficialEventSerializer = resultsAreOfficialEventSerializer; this.chosenSerializer = null; } @@ -338,4 +343,9 @@ public class RaceLogEventSerializer implements JsonSerializer, Rac public void visit(RaceLogORCImpliedWindSourceEvent event) { chosenSerializer = orcImpliedWindSourceEventSerializer; } + + @Override + public void visit(RaceLogResultsAreOfficialEvent event) { + chosenSerializer = resultsAreOfficialEventSerializer; + } } diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogResultsAreOfficialEventSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogResultsAreOfficialEventSerializer.java new file mode 100755 index 00000000000..9907e2dd224 --- /dev/null +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/racelog/impl/RaceLogResultsAreOfficialEventSerializer.java @@ -0,0 +1,33 @@ +package com.sap.sailing.server.gateway.serialization.racelog.impl; + +import org.json.simple.JSONObject; + +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogResultsAreOfficialEvent; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.server.gateway.serialization.JsonSerializer; + +/** + * Serializer for {@link RaceLogResultsAreOfficialEvent}. + * + * @author Axel Uhl (d043530) + */ +public class RaceLogResultsAreOfficialEventSerializer extends BaseRaceLogEventSerializer { + public static final String VALUE_CLASS = RaceLogResultsAreOfficialEvent.class.getSimpleName(); + + public RaceLogResultsAreOfficialEventSerializer(JsonSerializer competitorSerializer) { + super(competitorSerializer); + } + + @Override + public JSONObject serialize(RaceLogEvent object) { + final RaceLogResultsAreOfficialEvent resultsAreOfficialEvent = (RaceLogResultsAreOfficialEvent) object; + final JSONObject result = super.serialize(resultsAreOfficialEvent); + return result; + } + + @Override + protected String getClassFieldValue() { + return VALUE_CLASS; + } +} diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java index b2519e38fbd..f825dd8e740 100644 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/racelog/RaceLogEventSerializerTest.java @@ -76,6 +76,7 @@ public class RaceLogEventSerializerTest { private JsonSerializer orcCertificateAssignmentEventSerializer; private JsonSerializer orcScratchBoatEventSerializer; private JsonSerializer orcSetImpliedWindEventSerializer; + private JsonSerializer resultsAreOfficialEventSerializer; private AbstractLogEventAuthor author = new LogEventAuthorImpl("Test Author", 1); @@ -111,6 +112,7 @@ public class RaceLogEventSerializerTest { orcCertificateAssignmentEventSerializer = mock(JsonSerializer.class); orcScratchBoatEventSerializer = mock(JsonSerializer.class); orcSetImpliedWindEventSerializer = mock(JsonSerializer.class); + resultsAreOfficialEventSerializer = mock(JsonSerializer.class); serializer = new RaceLogEventSerializer(flagEventSerializer, startTimeSerializer, raceStatusSerializer, passChangedSerializer, courseDesignChangedEventSerializer, @@ -124,7 +126,7 @@ public class RaceLogEventSerializerTest { startOfTrackingEventSerializer, useCompetitorsFromRaceLogEventSerializer, endOfTrackingEventSerializer, tagEventSerializer, orcLegDataEventSerializer, orcCertificateAssignmentEventSerializer, orcScratchBoatEventSerializer, - orcSetImpliedWindEventSerializer); + orcSetImpliedWindEventSerializer, resultsAreOfficialEventSerializer); } @Test From fa49dce263dd389990daac84e1ef45f6e52938af Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 11 Jan 2021 20:15:57 +0100 Subject: [PATCH 2/7] bug5477: fixed listener in race manager app --- .../app/ui/fragments/raceinfo/RaceSummaryFragment.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/RaceSummaryFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/RaceSummaryFragment.java index f8142c472ff..a8ba867e6a9 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/RaceSummaryFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/RaceSummaryFragment.java @@ -279,7 +279,10 @@ public class RaceSummaryFragment extends BaseFragment { @Override public void onTagEventsChanged(ReadonlyRaceState state) { - // TODO: add android support for tags + } + + @Override + public void onResultsAreOfficialChanged(ReadonlyRaceState state) { } } From eb839640650e295c36896fce7b351208c6fbdef3 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 11 Jan 2021 23:53:47 +0100 Subject: [PATCH 3/7] bug5477: deferring setting race results to OFFICIAL when there are still competitor updates pending --- .../LoadingQueueDoneCallBack.java | 3 +-- .../impl/CompetitorChangeReceiver.java | 12 +++++++++-- .../OfficialCompetitorUpdateProvider.java | 9 ++++++++ ...CompetitorStatusWithRaceLogReconciler.java | 21 +++++++++++++++++-- 4 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/OfficialCompetitorUpdateProvider.java diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/LoadingQueueDoneCallBack.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/LoadingQueueDoneCallBack.java index 502d6e9f955..ad80d2f5812 100644 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/LoadingQueueDoneCallBack.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/LoadingQueueDoneCallBack.java @@ -15,8 +15,8 @@ import com.sap.sailing.domain.tractracadapter.impl.TracTracRaceTrackerImpl; * @author Frederik Petersen * */ +@FunctionalInterface public interface LoadingQueueDoneCallBack { - /** * Callback method * See {@link AbstractReceiverWithQueue} and {@link TracTracRaceTrackerImpl} for example usage. @@ -24,5 +24,4 @@ public interface LoadingQueueDoneCallBack { * @param receiver Receiver that handled the marked event. */ void loadingQueueDone(Receiver receiver); - } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/CompetitorChangeReceiver.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/CompetitorChangeReceiver.java index 71e82c14b10..24d5be69842 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/CompetitorChangeReceiver.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/CompetitorChangeReceiver.java @@ -32,16 +32,19 @@ import com.tractrac.subscription.lib.api.race.IRaceCompetitorListener; * @author Axel Uhl (d043530) * */ -public class CompetitorChangeReceiver extends AbstractReceiverWithQueue { +public class CompetitorChangeReceiver extends AbstractReceiverWithQueue +implements OfficialCompetitorUpdateProvider { private static final Logger logger = Logger.getLogger(CompetitorChangeReceiver.class.getName()); private final IRaceCompetitorListener listener; private final RaceAndCompetitorStatusWithRaceLogReconciler reconciler; public CompetitorChangeReceiver(DynamicTrackedRegatta trackedRegatta, IEvent tractracEvent, IRace tractracRace, Simulator simulator, DomainFactory domainFactory, - IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, long timeoutInMilliseconds, RaceAndCompetitorStatusWithRaceLogReconciler raceAndCompetitorStatusWithRaceLogReconciler) { + IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, long timeoutInMilliseconds, + RaceAndCompetitorStatusWithRaceLogReconciler raceAndCompetitorStatusWithRaceLogReconciler) { super(domainFactory, tractracEvent, trackedRegatta, simulator, eventSubscriber, raceSubscriber, timeoutInMilliseconds); reconciler = raceAndCompetitorStatusWithRaceLogReconciler; + reconciler.setOfficialCompetitorUpdateProvider(this); listener = new IRaceCompetitorListener() { @Override public void addRaceCompetitor(IRaceCompetitor raceCompetitor) { @@ -99,4 +102,9 @@ public class CompetitorChangeReceiver extends AbstractReceiverWithQueuerunnable.run()); + } } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/OfficialCompetitorUpdateProvider.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/OfficialCompetitorUpdateProvider.java new file mode 100644 index 00000000000..f1d432dd76c --- /dev/null +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/OfficialCompetitorUpdateProvider.java @@ -0,0 +1,9 @@ +package com.sap.sailing.domain.tractracadapter.impl; + +public interface OfficialCompetitorUpdateProvider { + /** + * Runs the {@link Runnable} when all competitor update requests enqueued so far have been + * processed. + */ + void runWhenNoMoreOfficialCompetitorUpdatesPending(Runnable runnable); +} diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceAndCompetitorStatusWithRaceLogReconciler.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceAndCompetitorStatusWithRaceLogReconciler.java index c0e4d0007d0..5899882b883 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceAndCompetitorStatusWithRaceLogReconciler.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceAndCompetitorStatusWithRaceLogReconciler.java @@ -27,6 +27,7 @@ import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFinishPositioningConfirmedEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFlagEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl; +import com.sap.sailing.domain.abstractlog.race.state.RaceState; import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl; import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl; @@ -64,6 +65,7 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler { private final LogEventAuthorImpl raceLogEventAuthor; private final IRace tractracRace; private final Map, RaceLogListener> raceLogListeners; + private OfficialCompetitorUpdateProvider officialCompetitorUpdateProvider; private final static Map flagForRaceStatus; static { @@ -218,8 +220,12 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler { } final RaceLog defaultRaceLog = getDefaultRaceLog(trackedRace); if (raceStatus == RaceStatusType.OFFICIAL && !ReadonlyRaceStateImpl.getOrCreate(raceLogResolver, defaultRaceLog).isResultsAreOfficial()) { - // FIXME bug5477: synchronize this with any pending competitor updates providing official results which are managed in a queue with a separate thread processing it - RaceStateImpl.create(raceLogResolver, defaultRaceLog, raceLogEventAuthor).setResultsAreOfficial(raceStatusUpdateTime); + final Runnable setResultsAreOfficial = ()->RaceStateImpl.create(raceLogResolver, defaultRaceLog, raceLogEventAuthor).setResultsAreOfficial(raceStatusUpdateTime); + if (officialCompetitorUpdateProvider != null) { + officialCompetitorUpdateProvider.runWhenNoMoreOfficialCompetitorUpdatesPending(setResultsAreOfficial); + } else { + setResultsAreOfficial.run(); + } } if (abortingFlagEvent != null && !isAbortedState(raceStatus) && raceStatusUpdateTime.after(abortingFlagEvent.getLogicalTimePoint())) { startNewPass(raceStatusUpdateTime, defaultRaceLog); @@ -389,4 +395,15 @@ public class RaceAndCompetitorStatusWithRaceLogReconciler { } return resultFromRaceLogAndItsCreationTimePoint; } + + /** + * To be called by the object later calling {@link #reconcileCompetitorStatus(IRaceCompetitor, TrackedRace)}. This + * way, this object can tell when the race is to be {@link RaceState#setResultsAreOfficial(TimePoint) moved to + * OFFICIAL state} whether any updates are pending and defer the race state transition to that moment. + * + * @see OfficialCompetitorUpdateProvider#runWhenNoMoreOfficialCompetitorUpdatesPending(Runnable) + */ + public void setOfficialCompetitorUpdateProvider(OfficialCompetitorUpdateProvider officialCompetitorUpdateProvider) { + this.officialCompetitorUpdateProvider = officialCompetitorUpdateProvider; + } } From bf420889fdfdc705fddeb20efa51daaa9dcb83fe Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 12 Jan 2021 00:07:51 +0100 Subject: [PATCH 4/7] bug5477: include resultsAreOfficial in trackedRaceInfo section of /leaderboards API output --- .../GWT Sailing SDM.launch | 154 ++++++++------- .../api/AbstractLeaderboardsResource.java | 12 ++ .../SailingServer (No Proxy, Axel).launch | 177 +++++++++++++++++- 3 files changed, 263 insertions(+), 80 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/GWT Sailing SDM.launch b/java/com.sap.sailing.gwt.ui/GWT Sailing SDM.launch index 63e7e8dc021..280ee214cc8 100755 --- a/java/com.sap.sailing.gwt.ui/GWT Sailing SDM.launch +++ b/java/com.sap.sailing.gwt.ui/GWT Sailing SDM.launch @@ -36,84 +36,82 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java index 3e8a96c2a44..77193e06078 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java @@ -10,6 +10,8 @@ import org.apache.shiro.SecurityUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.ResultsAreOfficialFinder; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CompetitorWithBoat; import com.sap.sailing.domain.base.Fleet; @@ -193,6 +195,7 @@ public abstract class AbstractLeaderboardsResource extends AbstractSailingServer ? MillisecondsTimePoint.now().minus(trackedRace.getDelayToLiveInMillis()) : new MillisecondsTimePoint(resultTimePoint))); trackedRaceInfo.put("delayToLiveInMillis", trackedRace.getDelayToLiveInMillis()); + trackedRaceInfo.put("resultsAreOfficial", isResultsAreOfficial(trackedRace)); if (trackedRace.getStatus() != null) { trackedRaceInfo.put("status", trackedRace.getStatus().getStatus().toString()); trackedRaceInfo.put("loadingProgress", trackedRace.getStatus().getLoadingProgress()); @@ -203,6 +206,15 @@ public abstract class AbstractLeaderboardsResource extends AbstractSailingServer } } + private boolean isResultsAreOfficial(TrackedRace trackedRace) { + for (final RaceLog raceLog : trackedRace.getAttachedRaceLogs()) { + if (new ResultsAreOfficialFinder(raceLog).analyze() != null) { + return true; + } + } + return false; + } + protected TimePoint calculateTimePointForResultState(Leaderboard leaderboard, ResultStates resultState) { TimePoint result = null; switch (resultState) { diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Axel).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Axel).launch index 00088538bd1..1b352663e63 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Axel).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Axel).launch @@ -31,10 +31,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - From fee14a21fb5efce25e1c14f0506377989b603793 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 12 Jan 2021 00:22:16 +0100 Subject: [PATCH 5/7] bug5477: added "resultsAreOfficial" field to /sailingserver/api/v[12]/leaderboards output in the "fleets" section --- .../api/AbstractLeaderboardsResource.java | 12 +- .../SailingServer (No Proxy).launch | 291 ++++++++-------- .../SailingServer (No Proxy, Axel).launch | 24 +- ...gServer (No Proxy, winddbTest Axel).launch | 312 +++++++++--------- 4 files changed, 335 insertions(+), 304 deletions(-) diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java index 77193e06078..932f74fa8dd 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/AbstractLeaderboardsResource.java @@ -180,6 +180,7 @@ public abstract class AbstractLeaderboardsResource extends AbstractSailingServer final JSONObject fleetJson = new JSONObject(); fleetsJson.add(fleetJson); fleetJson.put("name", fleet.getName()); + fleetJson.put("resultsAreOfficial", isResultsAreOfficial(raceColumn, fleet)); final TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); final JSONObject trackedRaceInfo; if (trackedRace == null) { @@ -195,7 +196,6 @@ public abstract class AbstractLeaderboardsResource extends AbstractSailingServer ? MillisecondsTimePoint.now().minus(trackedRace.getDelayToLiveInMillis()) : new MillisecondsTimePoint(resultTimePoint))); trackedRaceInfo.put("delayToLiveInMillis", trackedRace.getDelayToLiveInMillis()); - trackedRaceInfo.put("resultsAreOfficial", isResultsAreOfficial(trackedRace)); if (trackedRace.getStatus() != null) { trackedRaceInfo.put("status", trackedRace.getStatus().getStatus().toString()); trackedRaceInfo.put("loadingProgress", trackedRace.getStatus().getLoadingProgress()); @@ -206,13 +206,9 @@ public abstract class AbstractLeaderboardsResource extends AbstractSailingServer } } - private boolean isResultsAreOfficial(TrackedRace trackedRace) { - for (final RaceLog raceLog : trackedRace.getAttachedRaceLogs()) { - if (new ResultsAreOfficialFinder(raceLog).analyze() != null) { - return true; - } - } - return false; + private boolean isResultsAreOfficial(RaceColumn raceColumn, Fleet fleet) { + final RaceLog raceLog = raceColumn.getRaceLog(fleet); + return new ResultsAreOfficialFinder(raceLog).analyze() != null; } protected TimePoint calculateTimePointForResultState(Leaderboard leaderboard, ResultStates resultState) { diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy).launch b/java/com.sap.sailing.server/SailingServer (No Proxy).launch index 17bf0530e86..4a07c216c14 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy).launch @@ -33,192 +33,195 @@ - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + - - - - - + + + + + + + + + - - - + - - - - - - - - - - - - - - - - - - - + + + + - + + + + + + + + + + + + + + - - - - - - - - - - + + + + + - - - + + + + - - - - - + + + + + + + + + + + + - + + + + - - + - - - - - - - - - - - - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Axel).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Axel).launch index 1b352663e63..7f7dc2ebf79 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Axel).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Axel).launch @@ -11,6 +11,7 @@ + @@ -32,9 +33,8 @@ - - - + + @@ -60,6 +60,7 @@ + @@ -72,12 +73,14 @@ - + + + @@ -91,10 +94,12 @@ + + @@ -107,6 +112,7 @@ + @@ -114,6 +120,7 @@ + @@ -166,6 +173,9 @@ + + + @@ -181,15 +191,19 @@ + - + + + + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest Axel).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest Axel).launch index 32e259aa6a9..0dc10ff5bea 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest Axel).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest Axel).launch @@ -29,179 +29,197 @@ - - - - - - - - - - - - - - - - - - - - - - - + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + - - - + + + + + + + + + + + + + From 6e59f9b07494b3dff81e84c422fa504ebf07298d Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jan 2021 14:24:59 +0100 Subject: [PATCH 6/7] added missing registration for ReceiverType.COMPETITOR to obtain competitor changes from TracTrac --- .../sailing/domain/tractracadapter/impl/DomainFactoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java index 0c0b43e5683..a27823f7a4c 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java @@ -583,7 +583,7 @@ public class DomainFactoryImpl implements DomainFactory { tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm, timeoutInMilliseconds, raceTrackingHandler, raceAndCompetitorStatusWithRaceLogReconciler, ReceiverType.RACECOURSE, ReceiverType.MARKPASSINGS, ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH, - ReceiverType.RAWPOSITIONS, ReceiverType.SENSORDATA); + ReceiverType.RAWPOSITIONS, ReceiverType.SENSORDATA, ReceiverType.COMPETITOR); } @Override From 46fd4a4b4a4bdf2ba39e30ee12036758b4763a43 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jan 2021 14:39:04 +0100 Subject: [PATCH 7/7] fixed TracTrac connector regarding handling of adding/removing of competitors to a race --- .../impl/TracTracRaceTrackerImpl.java | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java index 11d7f234250..791cd6e7260 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/TracTracRaceTrackerImpl.java @@ -58,19 +58,19 @@ import com.sap.sse.common.Util; import com.sap.sse.util.impl.ThreadFactoryWithPriority; import com.tractrac.model.lib.api.event.CreateModelException; import com.tractrac.model.lib.api.event.DataSource; -import com.tractrac.model.lib.api.event.ICompetitor; import com.tractrac.model.lib.api.event.IEvent; import com.tractrac.model.lib.api.event.IRace; +import com.tractrac.model.lib.api.event.IRaceCompetitor; import com.tractrac.model.lib.api.route.IControl; import com.tractrac.subscription.lib.api.IEventSubscriber; import com.tractrac.subscription.lib.api.IRaceSubscriber; import com.tractrac.subscription.lib.api.ISubscriberFactory; import com.tractrac.subscription.lib.api.SubscriberInitializationException; import com.tractrac.subscription.lib.api.SubscriptionLocator; -import com.tractrac.subscription.lib.api.competitor.ICompetitorsListener; import com.tractrac.subscription.lib.api.event.IConnectionStatusListener; import com.tractrac.subscription.lib.api.event.ILiveDataEvent; import com.tractrac.subscription.lib.api.event.IStoredDataEvent; +import com.tractrac.subscription.lib.api.race.IRaceCompetitorListener; import com.tractrac.subscription.lib.api.race.IRacesListener; import com.tractrac.util.lib.api.exceptions.TimeOutException; @@ -199,7 +199,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl private final IEventSubscriber eventSubscriber; private final IRaceSubscriber raceSubscriber; private final IRacesListener racesListener; - private final ICompetitorsListener competitorsListener; + private final IRaceCompetitorListener competitorsListener; private final Set receivers; private final DomainFactory domainFactory; private final WindStore windStore; @@ -351,33 +351,6 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl // Initialize data controller using live and stored data sources ISubscriberFactory subscriberFactory = SubscriptionLocator.getSusbcriberFactory(); eventSubscriber = subscriberFactory.createEventSubscriber(tractracEvent, liveURI, effectiveStoredURI); - competitorsListener = new ICompetitorsListener() { - @Override - public void updateCompetitor(ICompetitor competitor) { - if (!competitor.isNonCompeting()) { - TracTracRaceTrackerImpl.this.domainFactory.updateCompetitor(competitor, raceTrackingHandler); - } - } - - @Override - public void deleteCompetitor(UUID competitorId) { - try { - trackedRegattaRegistry.updateRaceCompetitors(getRegatta(), getRace()); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public void addCompetitor(ICompetitor competitor) { - try { - trackedRegattaRegistry.updateRaceCompetitors(getRegatta(), getRace()); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }; - eventSubscriber.subscribeCompetitors(competitorsListener); if (useOfficialEventsToUpdateRaceLog) { reconciler = new RaceAndCompetitorStatusWithRaceLogReconciler(domainFactory, raceLogResolver, tractracRace); } else { @@ -456,6 +429,37 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl useInternalMarkPassingAlgorithm, timeoutInMilliseconds, raceTrackingHandler, reconciler)) { receivers.add(receiver); } + competitorsListener = new IRaceCompetitorListener() { + @Override + public void addRaceCompetitor(IRaceCompetitor raceCompetitor) { + try { + trackedRegattaRegistry.updateRaceCompetitors(getRegatta(), getRace()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void updateRaceCompetitor(IRaceCompetitor raceCompetitor) { + if (!raceCompetitor.getCompetitor().isNonCompeting()) { + TracTracRaceTrackerImpl.this.domainFactory.updateCompetitor(raceCompetitor.getCompetitor(), raceTrackingHandler); + } + } + + @Override + public void deleteRaceCompetitor(UUID competitorId) { + try { + trackedRegattaRegistry.updateRaceCompetitors(getRegatta(), getRace()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void removeOffsetPositions(UUID competitorId, int offset) { + } + }; + raceSubscriber.subscribeRaceCompetitor(competitorsListener); addListenersForStoredDataAndStartController(receivers); } @@ -598,7 +602,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl if (!stopped) { stopped = true; eventSubscriber.unsubscribeRaces(racesListener); - eventSubscriber.unsubscribeCompetitors(competitorsListener); + raceSubscriber.unsubscribeRaceCompetitor(competitorsListener); raceSubscriber.stop(); eventSubscriber.stop(); raceSubscriber.unsubscribeConnectionStatus(this);