diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/RibDashboardServiceImpl.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/RibDashboardServiceImpl.java index 6a988f36ffd..cc49eb907e9 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/RibDashboardServiceImpl.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/RibDashboardServiceImpl.java @@ -29,6 +29,7 @@ import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.server.RacingEventService; +import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint; @@ -152,8 +153,15 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib for (RaceColumn column : lb.getRaceColumns()) { for (Fleet fleet : column.getFleets()) { TrackedRace race = column.getTrackedRace(fleet); - if (race != null && race.isLive(new MillisecondsTimePoint(new Date()))) { - result = race; + if (race != null) { + TimePoint startOfRace = race.getStartOfRace(); + // not relying on isLive() because the time window is too short + // to retrieve wind information we need to extend the time window + if (startOfRace != null && race.getEndOfRace() == null && + MillisecondsTimePoint.now().after(startOfRace.minus(Duration.ONE_MINUTE.times(20)))) { + result = race; + // no break here as we want to have the last race that is deemed to be live + } } } } @@ -237,14 +245,14 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib String leaderboardName) { List startAnalysisDTOs = new ArrayList(); if (leaderboardName != null) { - Competitor competitor = baseDomainFactory.getCompetitorStore().getExistingCompetitorByIdAsString( - competitorIdAsString); + Competitor competitor = baseDomainFactory.getCompetitorStore().getExistingCompetitorByIdAsString(competitorIdAsString); List trackedRacesForLeaderBoardName = getTrackedRacesFromLeaderboard(leaderboardName); for (TrackedRace trackedRace : trackedRacesForLeaderBoardName) { StartAnalysisDTO startAnalysisDTO = startAnalysisCreationController .checkStartAnalysisForCompetitorInTrackedRace(competitor, trackedRace); - if (startAnalysisDTO != null) + if (startAnalysisDTO != null) { startAnalysisDTOs.add(startAnalysisDTO); + } } } return startAnalysisDTOs; @@ -253,11 +261,11 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib @Override public List getCompetitorsInLeaderboard(String leaderboardName) { logger.log(Level.INFO, "getCompetitorsInLeaderboard(...) Request."); - if(leaderboardName != null){ - Leaderboard lb = getRacingEventService().getLeaderboardByName(leaderboardName); - return baseDomainFactory.getCompetitorDTOList(lb.getCompetitorsFromBestToWorst(new MillisecondsTimePoint( - new Date()))); - }else{ + if (leaderboardName != null) { + Leaderboard lb = getRacingEventService().getLeaderboardByName(leaderboardName); + return baseDomainFactory.getCompetitorDTOList(lb.getCompetitorsFromBestToWorst(new MillisecondsTimePoint( + new Date()))); + } else { return null; } } diff --git a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/StartAnalysisDTOFactory.java b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/StartAnalysisDTOFactory.java index 8a395078acf..9e6c357a341 100644 --- a/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/StartAnalysisDTOFactory.java +++ b/java/com.sap.sailing.dashboards.gwt/src/main/java/com/sap/sailing/dashboards/gwt/server/startanalysis/StartAnalysisDTOFactory.java @@ -53,8 +53,7 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida boolean isCompetitorOneOfFirstThree = false; for (int i = 0; i < MINIMUM_NUMBER_COMPETITORS_FOR_STARTANALYSIS; i++) { - competitors.add(createStartAnalysisCompetitorDTO(trackedRace, i + 1, markPassingsInOrder.get(i) - .getCompetitor())); + competitors.add(createStartAnalysisCompetitorDTO(trackedRace, i + 1, markPassingsInOrder.get(i).getCompetitor())); if (markPassingsInOrder.get(i).getCompetitor().equals(competitor)) { isCompetitorOneOfFirstThree = true; } @@ -75,9 +74,9 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida startAnalysisDTO.racingProcedureType = RacingProcedureType.GateStart; long timePointOfGolfDownTime = trackedRace.getGateStartGolfDownTime(); startAnalysisDTO.timeOfStartInMilliSeconds = trackedRace.getStartOfRace().asMillis(); - if(timePointOfGolfDownTime < trackedRace.getStartOfRace().asMillis() || timePointOfGolfDownTime == 0){ + if (timePointOfGolfDownTime < trackedRace.getStartOfRace().asMillis() || timePointOfGolfDownTime == 0) { startAnalysisDTO.tailLenghtInMilliseconds = DEFAULT_GATE_START_INTERVALL_IN_MILLISECONDS; - }else{ + } else { startAnalysisDTO.tailLenghtInMilliseconds = timePointOfGolfDownTime-trackedRace.getStartOfRace().asMillis(); } } else { @@ -142,19 +141,26 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida private WindAndAdvantagesInfoForStartLineDTO createStartAnalysisWindAndLineData(TrackedRace trackedRace) { WindAndAdvantagesInfoForStartLineDTO startAnalysisWindLineInfoDTO = new WindAndAdvantagesInfoForStartLineDTO(); - LineDetails startline = trackedRace.getStartLine(trackedRace.getStartTimeReceived()); + final TimePoint startOfRace = trackedRace.getStartOfRace(); + final TimePoint timePoint = startOfRace == null ? MillisecondsTimePoint.now() : startOfRace; + LineDetails startline = trackedRace.getStartLine(timePoint); StartLineAdvantageDTO startLineAdvantageDTO = new StartLineAdvantageDTO(); startLineAdvantageDTO.startLineAdvatageType = getStartlineAdvantageType(trackedRace, new MillisecondsTimePoint( new Date())); startLineAdvantageDTO.startLineAdvantage = startline.getAdvantage().getMeters(); startAnalysisWindLineInfoDTO.startLineAdvantage = startLineAdvantageDTO; - Position portMarkPosition = trackedRace.getOrCreateTrack( - trackedRace.getStartLine(trackedRace.getStartTimeReceived()).getStarboardMarkWhileApproachingLine()) - .getEstimatedPosition(trackedRace.getStartTimeReceived(), /* extrapolate */ - false); - Wind windAtStart = trackedRace.getWind(portMarkPosition, trackedRace.getStartTimeReceived()); - startAnalysisWindLineInfoDTO.windDirectionInDegrees = windAtStart.getBearing().getDegrees(); - startAnalysisWindLineInfoDTO.windSpeedInKnots = windAtStart.getKnots(); + if (trackedRace.getStartTimeReceived() != null) { + Position portMarkPosition = trackedRace.getOrCreateTrack( + trackedRace.getStartLine(trackedRace.getStartTimeReceived()).getStarboardMarkWhileApproachingLine()) + .getEstimatedPosition(trackedRace.getStartTimeReceived(), /* extrapolate */ + false); + Wind windAtStart = trackedRace.getWind(portMarkPosition, trackedRace.getStartTimeReceived()); + startAnalysisWindLineInfoDTO.windDirectionInDegrees = windAtStart.getBearing().getDegrees(); + startAnalysisWindLineInfoDTO.windSpeedInKnots = windAtStart.getKnots(); + } else { + startAnalysisWindLineInfoDTO.windDirectionInDegrees = 0.0; + startAnalysisWindLineInfoDTO.windSpeedInKnots = 0.0; + } return startAnalysisWindLineInfoDTO; } 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 6194deacd23..75c6b0978f8 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 @@ -4,6 +4,7 @@ import static junit.framework.Assert.assertEquals; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.mockito.Mockito.mock; import java.util.Arrays; import java.util.Collections; @@ -11,6 +12,7 @@ import java.util.Collections; import org.junit.Test; import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; @@ -80,7 +82,8 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest { 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); + Collections. emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false, + OneDesignRankingMetric::new, mock(RaceLogResolver.class)); trackedRace.attachRaceLog(raceLog); trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog); @@ -125,7 +128,8 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest { 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); + Collections. emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false, + OneDesignRankingMetric::new, mock(RaceLogResolver.class)); trackedRace.addListener(new AbstractRaceChangeListener() { @Override diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParams.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParams.java index 779a177f1d4..1c5c8928bab 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParams.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogConnectivityParams.java @@ -6,6 +6,7 @@ import java.util.UUID; import com.sap.sailing.domain.abstractlog.AbstractLog; import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceInformationFinder; import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer; import com.sap.sailing.domain.base.BoatClass; @@ -51,13 +52,13 @@ public class RaceLogConnectivityParams implements RaceTrackingConnectivityParame @Override public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, - GPSFixStore gpsFixStore) { - return createRaceTracker(regatta, trackedRegattaRegistry, windStore, gpsFixStore); + GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) { + return createRaceTracker(regatta, trackedRegattaRegistry, windStore, gpsFixStore, raceLogResolver); } @Override public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, - WindStore windStore, GPSFixStore gpsFixStore) { + WindStore windStore, GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) { if (regatta == null) { BoatClass boatClass = new RaceInformationFinder(getRaceLog()).analyze().getBoatClass(); regatta = service.getOrCreateDefaultRegatta( @@ -68,7 +69,7 @@ public class RaceLogConnectivityParams implements RaceTrackingConnectivityParame throw new RaceNotCreatedException("No regatta for race-log tracked race"); } DynamicTrackedRegatta trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(regatta); - return new RaceLogRaceTracker(trackedRegatta, this, windStore, gpsFixStore); + return new RaceLogRaceTracker(trackedRegatta, this, windStore, gpsFixStore, raceLogResolver); } @Override diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java index e4a91476b7f..55ed7d8088d 100755 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java @@ -20,6 +20,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.LastPublishedCourseDesignFinder; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.impl.BaseRaceLogEventVisitor; import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent; import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent; @@ -98,24 +99,26 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener { private final WindStore windStore; private final GPSFixStore gpsFixStore; private final DynamicTrackedRegatta regatta; + private final RaceLogResolver raceLogResolver; private final Map, Object> visitors = new HashMap, Object>(); - private ConcurrentHashMap>> competitorMappings = new ConcurrentHashMap<>(); - private ConcurrentHashMap>> markMappings = new ConcurrentHashMap<>(); + private final ConcurrentHashMap>> competitorMappings = new ConcurrentHashMap<>(); + private final ConcurrentHashMap>> markMappings = new ConcurrentHashMap<>(); - private Map>> markMappingsByDevices = new HashMap<>(); - private Map>> competitorMappingsByDevices = new HashMap<>(); + private final Map>> markMappingsByDevices = new HashMap<>(); + private final Map>> competitorMappingsByDevices = new HashMap<>(); private DynamicTrackedRace trackedRace; private static final Logger logger = Logger.getLogger(RaceLogRaceTracker.class.getName()); public RaceLogRaceTracker(DynamicTrackedRegatta regatta, RaceLogConnectivityParams params, WindStore windStore, - GPSFixStore gpsFixStore) { + GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) { this.params = params; this.windStore = windStore; this.gpsFixStore = gpsFixStore; this.regatta = regatta; + this.raceLogResolver = raceLogResolver; // add log listeners for (AbstractLog log : params.getLogHierarchy()) { @@ -445,7 +448,7 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener { trackedRace = regatta.createTrackedRace(raceDef, sidelines, windStore, gpsFixStore, params.getDelayToLiveInMillis(), WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, - boatClass.getApproximateManeuverDurationInMilliseconds(), null, /*useMarkPassingCalculator*/ true); + boatClass.getApproximateManeuverDurationInMilliseconds(), null, /*useMarkPassingCalculator*/ true, raceLogResolver); trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, 0)); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/IsIndividualRecallDisplayedAnalyzer.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/IsIndividualRecallDisplayedAnalyzer.java deleted file mode 100644 index ef15f88cfd0..00000000000 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/IsIndividualRecallDisplayedAnalyzer.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.sap.sailing.domain.abstractlog.race.analyzing.impl; - -import com.sap.sailing.domain.abstractlog.race.RaceLog; -import com.sap.sse.common.TimePoint; - -public class IsIndividualRecallDisplayedAnalyzer extends RaceLogAnalyzer { - - private final IndividualRecallFinder displayedFinder; - private final IndividualRecallFinder removedFinder; - - public IsIndividualRecallDisplayedAnalyzer(RaceLog raceLog) { - this(raceLog, null); - } - - public IsIndividualRecallDisplayedAnalyzer(RaceLog raceLog, TimePoint at) { - this(raceLog, new IndividualRecallDisplayedFinder(raceLog, at), new IndividualRecallRemovedFinder(raceLog, at), at); - } - - public IsIndividualRecallDisplayedAnalyzer(RaceLog raceLog, IndividualRecallDisplayedFinder displayedFinder, - IndividualRecallRemovedFinder removedFinder, TimePoint at) { - super(raceLog); - this.displayedFinder = displayedFinder; - this.removedFinder = removedFinder; - } - - @Override - protected Boolean performAnalysis() { - TimePoint displayedAt = displayedFinder.analyze(); - TimePoint removedAt = removedFinder.analyze(); - if (displayedAt != null) { - if (removedAt == null || displayedAt.after(removedAt)) { - return true; - } - } - return false; - } - -} 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 4099e79d41d..349b0daa495 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 @@ -428,7 +428,7 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL removeChangedListener(racingProcedure); racingProcedure.detach(); } - racingProcedure = procedureFactory.createRacingProcedure(cachedRacingProcedureType, raceLog); + racingProcedure = procedureFactory.createRacingProcedure(cachedRacingProcedureType, raceLog, raceLogResolver); racingProcedure.setStateEventScheduler(scheduler); addChangedListener(racingProcedure); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/RacingProcedureFactory.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/RacingProcedureFactory.java index afa15033192..3654dc22312 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/RacingProcedureFactory.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/RacingProcedureFactory.java @@ -1,12 +1,13 @@ package com.sap.sailing.domain.abstractlog.race.state.racingprocedure; import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.configuration.RegattaConfiguration; import com.sap.sailing.domain.common.racelog.RacingProcedureType; public interface RacingProcedureFactory { - ReadonlyRacingProcedure createRacingProcedure(RacingProcedureType type, RaceLog raceLog); + ReadonlyRacingProcedure createRacingProcedure(RacingProcedureType type, RaceLog raceLog, RaceLogResolver raceLogResolver); RegattaConfiguration getConfiguration(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/ReadonlyRacingProcedure.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/ReadonlyRacingProcedure.java index cc743dfc056..f50c3b936ca 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/ReadonlyRacingProcedure.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/ReadonlyRacingProcedure.java @@ -79,7 +79,9 @@ public interface ReadonlyRacingProcedure extends RaceStateEventProcessor, RaceSt TimePoint getIndividualRecallDisplayedTime(); /** - * Gets the time the individual recall flag was removed (or null). + * Gets the time the individual recall flag was or shall be removed (or null if it hasn't been set or no + * race start time is known). When the flag is currently set, the removal time can either be specified by an explicit + * race log event or is automatically triggered four minutes after the race start time. */ TimePoint getIndividualRecallRemovalTime(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/basic/impl/BasicRacingProcedureImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/basic/impl/BasicRacingProcedureImpl.java index 12c064844a6..909c4f138f7 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/basic/impl/BasicRacingProcedureImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/basic/impl/BasicRacingProcedureImpl.java @@ -7,6 +7,7 @@ import java.util.Collections; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEvents; @@ -25,8 +26,8 @@ import com.sap.sse.common.TimePoint; public class BasicRacingProcedureImpl extends BaseRacingProcedure { public BasicRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory, - RacingProcedureConfiguration configuration) { - super(raceLog, author, factory, configuration); + RacingProcedureConfiguration configuration, RaceLogResolver raceLogResolver) { + super(raceLog, author, factory, configuration, raceLogResolver); } @Override diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/ess/impl/ESSRacingProcedureImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/ess/impl/ESSRacingProcedureImpl.java index 6ffb0b7d881..08cff9f9fdd 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/ess/impl/ESSRacingProcedureImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/ess/impl/ESSRacingProcedureImpl.java @@ -8,6 +8,7 @@ import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.FinishingTimeFinder; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEvents; @@ -37,8 +38,8 @@ public class ESSRacingProcedureImpl extends BaseRacingProcedure implements ESSRa private final ESSConfiguration configuration; public ESSRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, - RaceLogEventFactory factory, ESSConfiguration configuration) { - super(raceLog, author, factory, configuration); + RaceLogEventFactory factory, ESSConfiguration configuration, RaceLogResolver raceLogResolver) { + super(raceLog, author, factory, configuration, raceLogResolver); this.configuration = configuration; update(); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/gate/impl/GateStartRacingProcedureImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/gate/impl/GateStartRacingProcedureImpl.java index 0165aa169cd..2bcafb0f08a 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/gate/impl/GateStartRacingProcedureImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/gate/impl/GateStartRacingProcedureImpl.java @@ -9,6 +9,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; import com.sap.sailing.domain.abstractlog.race.RaceLogGateLineOpeningTimeEvent.GateLineOpeningTimes; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.GateLineOpeningTimeFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.PathfinderFinder; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent; import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl; @@ -43,8 +44,8 @@ public class GateStartRacingProcedureImpl extends BaseRacingProcedure implements private String cachedPathfinder; public GateStartRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory, - GateStartConfiguration configuration) { - super(raceLog, author, factory, configuration); + GateStartConfiguration configuration, RaceLogResolver raceLogResolver) { + super(raceLog, author, factory, configuration, raceLogResolver); this.gateLineOpeningTimeAnalyzer = new GateLineOpeningTimeFinder(raceLog); this.pathfinderAnalyzer = new PathfinderFinder(raceLog); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/BaseRacingProcedure.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/BaseRacingProcedure.java index ea11b0f6666..fc04a76fedf 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/BaseRacingProcedure.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/BaseRacingProcedure.java @@ -15,7 +15,8 @@ import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IndividualRecallDi import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IndividualRecallRemovedFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsFinishedAnalyzer; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsInFinishingPhaseAnalyzer; -import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsIndividualRecallDisplayedAnalyzer; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogChangedVisitor; import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent; import com.sap.sailing.domain.abstractlog.race.state.RaceStateEventScheduler; @@ -27,7 +28,9 @@ import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProce import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedureChangedListener; import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration; import com.sap.sailing.domain.common.racelog.Flags; +import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.impl.MillisecondsTimePoint; /** * Base class for all your {@link RacingProcedure}s. @@ -39,7 +42,10 @@ import com.sap.sse.common.TimePoint; public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener implements RacingProcedure, RaceLogChangedListener { - private final static long individualRecallRemovalTimeout = 4 * 60 * 1000; // minutes * seconds * milliseconds + /** + * The time since race start after which the X-ray flag has to go down + */ + private final static Duration individualRecallRemovalTimeout = Duration.ONE_MINUTE.times(4); private RaceStateEventScheduler scheduler; @@ -49,35 +55,35 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i private final RacingProcedureConfiguration configuration; private final RacingProcedureChangedListeners changedListeners; - private final IsIndividualRecallDisplayedAnalyzer isRecallDisplayedAnalyzer; private final IndividualRecallDisplayedFinder recallDisplayedFinder; private final IndividualRecallRemovedFinder recallRemovedFinder; private final FinishingTimeFinder finishingTimeFinder; private final FinishedTimeFinder finishedTimeFinder; private final RaceLogEventVisitor raceLogListener; + private final StartTimeFinder startTimeFinder; private boolean cachedIsIndividualRecallDisplayed; /** * When calling me, call {@link BaseRacingProcedure#update()} afterwards! + * @param raceLogResolver TODO */ public BaseRacingProcedure(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory, - RacingProcedureConfiguration configuration) { + RacingProcedureConfiguration configuration, RaceLogResolver raceLogResolver) { if (configuration == null) { throw new IllegalArgumentException("configuration must not be null"); } - this.raceLog = raceLog; this.author = author; this.factory = factory; this.configuration = configuration; this.changedListeners = createChangedListenerContainer(); - this.isRecallDisplayedAnalyzer = new IsIndividualRecallDisplayedAnalyzer(raceLog); this.recallDisplayedFinder = new IndividualRecallDisplayedFinder(raceLog); this.recallRemovedFinder = new IndividualRecallRemovedFinder(raceLog); this.finishingTimeFinder = new FinishingTimeFinder(raceLog); this.finishedTimeFinder = new FinishedTimeFinder(raceLog); + this.startTimeFinder = new StartTimeFinder(raceLogResolver, raceLog); this.raceLogListener = new RaceLogChangedVisitor(this); this.raceLog.addListener(raceLogListener); @@ -125,7 +131,7 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i break; case RUNNING: if (isIndividualRecallDisplayed()) { - rescheduleIndividualRecallTimeout(recallDisplayedFinder.analyze()); + rescheduleIndividualRecallTimeout(); } break; default: @@ -133,6 +139,10 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i } } + private TimePoint getStartTime() { + return startTimeFinder.analyze().getStartTime(); + } + @Override public boolean isIndividualRecallDisplayed() { return cachedIsIndividualRecallDisplayed; @@ -140,10 +150,10 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i @Override public boolean isIndividualRecallDisplayed(TimePoint at) { - if (hasIndividualRecall()) { - return new IsIndividualRecallDisplayedAnalyzer(getRaceLog(), at).analyze(); - } - return false; + final TimePoint individualRecallDisplayedTime = getIndividualRecallDisplayedTime(); + final TimePoint individualRecallRemovalTime = getIndividualRecallRemovalTime(); + return (hasIndividualRecall() && individualRecallDisplayedTime != null && !individualRecallDisplayedTime.after(at) && + individualRecallRemovalTime != null && !individualRecallRemovalTime.after(at)); } @Override @@ -156,17 +166,20 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i @Override public TimePoint getIndividualRecallRemovalTime() { - TimePoint displayed = getIndividualRecallDisplayedTime(); - if (hasIndividualRecall()) { - TimePoint removedEvent = recallRemovedFinder.analyze(); - if (removedEvent != null && (displayed == null || removedEvent.after(displayed))) { - return removedEvent; + final TimePoint result; + final TimePoint raceStartTime = getStartTime(); + final TimePoint removedEvent; + if (hasIndividualRecall() && (removedEvent = recallRemovedFinder.analyze()) != null && (raceStartTime == null || removedEvent.after(raceStartTime))) { + result = removedEvent; + } else { + final TimePoint individualRecallDisplayedTime = getIndividualRecallDisplayedTime(); + if (individualRecallDisplayedTime != null && raceStartTime != null) { + result = raceStartTime.plus(individualRecallRemovalTimeout); + } else { + result = null; } } - if (displayed != null) { - return displayed.plus(individualRecallRemovalTimeout); - } - return null; + return result; } @Override @@ -204,18 +217,21 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i } protected void update() { - boolean isRecallDisplayed = isRecallDisplayedAnalyzer.analyze(); - + // TODO an X-ray up event with a time point in the future will not be recognized here because at the current time the flag is not displayed and no other race log event will trigger the update; we'd need to schedule another state event; as long as clocks are set correctly, additional transmission time will make this unlikely + boolean isRecallDisplayed = isIndividualRecallDisplayed(MillisecondsTimePoint.now()); if (cachedIsIndividualRecallDisplayed != isRecallDisplayed) { cachedIsIndividualRecallDisplayed = isRecallDisplayed; - if (cachedIsIndividualRecallDisplayed) { - changedListeners.onIndividualRecallDisplayed(this); - rescheduleIndividualRecallTimeout(recallDisplayedFinder.analyze()); - } else { + if (!cachedIsIndividualRecallDisplayed) { + // individual recall was removed; no need to schedule an event for removal changedListeners.onIndividualRecallRemoved(this); unscheduleStateEvent(RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT); } - } + } + // (re-)schedule the individual recall removal in any case; the removal time may have changed + if (cachedIsIndividualRecallDisplayed) { + changedListeners.onIndividualRecallDisplayed(this); + rescheduleIndividualRecallTimeout(); + } // always call listeners for changed flag, as this does not only affect recall, but also // changes start procedure, for which some text elements need to be updated @@ -223,9 +239,9 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i changedListeners.onActiveFlagsChanged(this); } - private void rescheduleIndividualRecallTimeout(TimePoint displayTime) { + private void rescheduleIndividualRecallTimeout() { unscheduleStateEvent(RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT); - scheduleStateEvents(new RaceStateEventImpl(displayTime.plus(individualRecallRemovalTimeout), RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT)); + scheduleStateEvents(new RaceStateEventImpl(getIndividualRecallRemovalTime(), RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT)); } protected void scheduleStateEvents(RaceStateEvent stateEvent) { diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/RacingProcedureFactoryImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/RacingProcedureFactoryImpl.java index 7f34843b014..06617dd1902 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/RacingProcedureFactoryImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/RacingProcedureFactoryImpl.java @@ -3,6 +3,7 @@ package com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedureFactory; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ReadonlyRacingProcedure; import com.sap.sailing.domain.base.configuration.ConfigurationLoader; @@ -22,7 +23,7 @@ public class RacingProcedureFactoryImpl extends ReadonlyRacingProcedureFactory i } @Override - public ReadonlyRacingProcedure createRacingProcedure(RacingProcedureType type, RaceLog raceLog) { - return createProcedure(type, raceLog, author, factory); + public ReadonlyRacingProcedure createRacingProcedure(RacingProcedureType type, RaceLog raceLog, RaceLogResolver raceLogResolver) { + return createProcedure(type, raceLog, author, factory, raceLogResolver); } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/ReadonlyRacingProcedureFactory.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/ReadonlyRacingProcedureFactory.java index 4062f7a9893..971ac0caaa2 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/ReadonlyRacingProcedureFactory.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/impl/ReadonlyRacingProcedureFactory.java @@ -4,6 +4,7 @@ import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.impl.NoAddingRaceLogWrapper; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedure; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedureFactory; @@ -37,32 +38,32 @@ public class ReadonlyRacingProcedureFactory implements RacingProcedureFactory { } protected ReadonlyRacingProcedure createProcedure(RacingProcedureType type, RaceLog raceLog, - AbstractLogEventAuthor author, RaceLogEventFactory factory) { + AbstractLogEventAuthor author, RaceLogEventFactory factory, RaceLogResolver raceLogResolver) { RegattaConfiguration loadedConfiguration = configuration.load(); switch (type) { case ESS: - return new ESSRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getESSConfiguration()); + return new ESSRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getESSConfiguration(), raceLogResolver); case GateStart: return new GateStartRacingProcedureImpl(raceLog, author, factory, - loadedConfiguration.getGateStartConfiguration()); + loadedConfiguration.getGateStartConfiguration(), raceLogResolver); case RRS26: - return new RRS26RacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getRRS26Configuration()); + return new RRS26RacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getRRS26Configuration(), raceLogResolver); case BASIC: - return new BasicRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getBasicConfiguration()); + return new BasicRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getBasicConfiguration(), raceLogResolver); case LEAGUE: - return new LeagueRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getLeagueConfiguration()); + return new LeagueRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getLeagueConfiguration(), raceLogResolver); default: throw new UnsupportedOperationException("Unknown racing procedure " + type.toString()); } } @Override - public ReadonlyRacingProcedure createRacingProcedure(RacingProcedureType type, RaceLog raceLog) { + public ReadonlyRacingProcedure createRacingProcedure(RacingProcedureType type, RaceLog raceLog, RaceLogResolver raceLogResolver) { // Just a mock author since we will never add anything to the racelog AbstractLogEventAuthor author = new LogEventAuthorImpl("Illegal Author", 128); // Wrap the racelog to disable adding... RaceLog wrappedRaceLog = new NoAddingRaceLogWrapper(raceLog); - return createProcedure(type, wrappedRaceLog, author, RaceLogEventFactory.INSTANCE); + return createProcedure(type, wrappedRaceLog, author, RaceLogEventFactory.INSTANCE, raceLogResolver); } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/league/impl/LeagueRacingProcedureImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/league/impl/LeagueRacingProcedureImpl.java index 2ba9189ad0a..f3e5f2508df 100755 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/league/impl/LeagueRacingProcedureImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/league/impl/LeagueRacingProcedureImpl.java @@ -7,6 +7,7 @@ import java.util.Collections; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEvents; @@ -33,8 +34,8 @@ public class LeagueRacingProcedureImpl extends BaseRacingProcedure implements Le private final static Flags startmodeFlag = Flags.PAPA; public LeagueRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, - RaceLogEventFactory factory, LeagueConfiguration configuration) { - super(raceLog, author, factory, configuration); + RaceLogEventFactory factory, LeagueConfiguration configuration, RaceLogResolver raceLogResolver) { + super(raceLog, author, factory, configuration, raceLogResolver); update(); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/rrs26/impl/RRS26RacingProcedureImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/rrs26/impl/RRS26RacingProcedureImpl.java index 0ffd4522e5a..a89cc6b95d5 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/rrs26/impl/RRS26RacingProcedureImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/racingprocedure/rrs26/impl/RRS26RacingProcedureImpl.java @@ -8,6 +8,7 @@ import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RRS26StartModeFlagFinder; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RacingProcedureTypeAnalyzer; import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl; @@ -39,8 +40,8 @@ public class RRS26RacingProcedureImpl extends BaseRacingProcedure implements RRS private boolean startmodeFlagHasBeenSet; public RRS26RacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, - RaceLogEventFactory factory, RRS26Configuration configuration) { - super(raceLog, author, factory, configuration); + RaceLogEventFactory factory, RRS26Configuration configuration, RaceLogResolver raceLogResolver) { + super(raceLog, author, factory, configuration, raceLogResolver); RacingProcedureTypeAnalyzer procedureAnalyzer = new RacingProcedureTypeAnalyzer(raceLog); if (configuration.getStartModeFlags() != null) { diff --git a/java/com.sap.sailing.domain.swisstimingadapter/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.swisstimingadapter/META-INF/MANIFEST.MF index 8f3cd37b203..ce94c7a2bf0 100644 --- a/java/com.sap.sailing.domain.swisstimingadapter/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.swisstimingadapter/META-INF/MANIFEST.MF @@ -13,7 +13,8 @@ Require-Bundle: com.sap.sailing.domain, com.sap.sailing.xrr.resultimport, com.sap.sse.common, com.sap.sse, - com.sap.sailing.xrr.schema + com.sap.sailing.xrr.schema, + com.sap.sailing.domain.shared.android Export-Package: com.sap.sailing.domain.swisstimingadapter, com.sap.sailing.domain.swisstimingadapter.impl;x-friends:="com.sap.sailing.server.test" Import-Package: com.sap.sailing.xrr.schema, diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java index ec4dfc7bb83..5c1740c625e 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/SwissTimingFactory.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.net.UnknownHostException; import java.text.ParseException; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.racelog.RaceLogStore; @@ -54,13 +55,13 @@ public interface SwissTimingFactory { BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory, - TrackedRegattaRegistry trackedRegattaRegistry) throws InterruptedException, UnknownHostException, + TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws InterruptedException, UnknownHostException, IOException, ParseException; RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription, BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis, WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm, - DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws UnknownHostException, + DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws UnknownHostException, InterruptedException, IOException, ParseException; Race createRace(String raceId, String raceName, String description, BoatClass boatClass); diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java index 3e54a269946..5782c0b7b11 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingFactoryImpl.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.racelog.RaceLogStore; @@ -89,23 +90,24 @@ public class SwissTimingFactoryImpl implements SwissTimingFactory { @Override public SwissTimingRaceTracker createRaceTracker(String raceID, String raceName, String raceDescription, - BoatClass boatClass, String hostname, int port, - StartList startList, long delayToLiveInMillis, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, - WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm, - DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws InterruptedException, - UnknownHostException, IOException, ParseException { + BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis, + RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, + boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory, + TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) + throws InterruptedException, UnknownHostException, IOException, ParseException { return new SwissTimingRaceTrackerImpl(raceID, raceName, raceDescription, boatClass, hostname, port, startList, raceLogStore, regattaLogStore, windStore, gpsFixStore, domainFactory, this, - trackedRegattaRegistry, delayToLiveInMillis, useInternalMarkPassingAlgorithm); + trackedRegattaRegistry, raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm); } @Override - public RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription, BoatClass boatClass, String hostname, - int port, StartList startList, long delayToLiveInMillis, WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm, - DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws UnknownHostException, - InterruptedException, IOException, ParseException { - return new SwissTimingRaceTrackerImpl(regatta, raceID, raceName, raceDescription, boatClass, hostname, port, startList, windStore, gpsFixStore, domainFactory, - this, trackedRegattaRegistry, delayToLiveInMillis, useInternalMarkPassingAlgorithm); + public RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription, + BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis, + WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm, + DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) + throws UnknownHostException, InterruptedException, IOException, ParseException { + return new SwissTimingRaceTrackerImpl(regatta, raceID, raceName, raceDescription, boatClass, hostname, port, + startList, windStore, gpsFixStore, domainFactory, this, trackedRegattaRegistry, raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm); } @Override diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java index 33a1a85c5f1..d450b1651f8 100644 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java @@ -15,6 +15,7 @@ import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CompetitorStore; @@ -105,23 +106,28 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen * tracker by calling {@link #receivedTimingData(String, String, List)}. */ private final TMDMessageQueue tmdMessageQueue; + + private final RaceLogResolver raceLogResolver; protected SwissTimingRaceTrackerImpl(String raceID, String raceName, String raceDescription, BoatClass boatClass, String hostname, int port, StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, DomainFactory domainFactory, SwissTimingFactory factory, - TrackedRegattaRegistry trackedRegattaRegistry, long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm) throws InterruptedException, + TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm) throws InterruptedException, UnknownHostException, IOException, ParseException { this(domainFactory.getOrCreateDefaultRegatta(raceLogStore, regattaLogStore, raceID, boatClass, trackedRegattaRegistry), raceID, raceName, raceDescription, boatClass, hostname, port, startList, windStore, gpsFixStore, domainFactory, factory, trackedRegattaRegistry, - delayToLiveInMillis, useInternalMarkPassingAlgorithm); + raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm); } - protected SwissTimingRaceTrackerImpl(Regatta regatta, String raceID, String raceName, String raceDescription, BoatClass boatClass, String hostname, int port, StartList startList, - WindStore windStore, GPSFixStore gpsFixStore, DomainFactory domainFactory, SwissTimingFactory factory, - TrackedRegattaRegistry trackedRegattaRegistry, long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm) throws InterruptedException, - UnknownHostException, IOException, ParseException { + protected SwissTimingRaceTrackerImpl(Regatta regatta, String raceID, String raceName, String raceDescription, + BoatClass boatClass, String hostname, int port, StartList startList, WindStore windStore, + GPSFixStore gpsFixStore, DomainFactory domainFactory, SwissTimingFactory factory, + TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, + long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm) throws InterruptedException, UnknownHostException, IOException, + ParseException { super(); + this.raceLogResolver = raceLogResolver; this.tmdMessageQueue = new TMDMessageQueue(this); this.regatta = regatta; this.connector = factory.getOrCreateSailMasterConnector(hostname, port, raceID, raceName, raceDescription, boatClass); @@ -475,7 +481,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen // we already know our single RaceDefinition assert SwissTimingRaceTrackerImpl.this.race == race; } - }, useInternalMarkPassingAlgorithm); + }, useInternalMarkPassingAlgorithm, raceLogResolver); logger.info("Created SwissTiming RaceDefinition and TrackedRace for "+race.getName()); } diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java index 7045b444af6..1a558463001 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingTrackingConnectivityParameters.java @@ -1,6 +1,7 @@ package com.sap.sailing.domain.swisstimingadapter.impl; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.racelog.RaceLogStore; @@ -51,18 +52,18 @@ public class SwissTimingTrackingConnectivityParameters implements RaceTrackingCo @Override public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, - GPSFixStore gpsFixStore) throws Exception { + GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) throws Exception { return swissTimingFactory.createRaceTracker(raceID, raceName, raceDescription, boatClass, hostname, port, startList, delayToLiveInMillis, raceLogStore, regattaLogStore, windStore, gpsFixStore, useInternalMarkPassingAlgorithm, - domainFactory, trackedRegattaRegistry); + domainFactory, trackedRegattaRegistry, raceLogResolver); } @Override public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, - WindStore windStore, GPSFixStore gpsFixStore) throws Exception { + WindStore windStore, GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) throws Exception { return swissTimingFactory.createRaceTracker(regatta, raceID, raceName, raceDescription, boatClass, hostname, port, startList, delayToLiveInMillis, windStore, gpsFixStore, useInternalMarkPassingAlgorithm, - domainFactory, trackedRegattaRegistry); + domainFactory, trackedRegattaRegistry, raceLogResolver); } @Override diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.swisstimingreplayadapter.test/META-INF/MANIFEST.MF index b006bd01e0b..ead28dc4b0d 100644 --- a/java/com.sap.sailing.domain.swisstimingreplayadapter.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.swisstimingreplayadapter.test/META-INF/MANIFEST.MF @@ -10,4 +10,5 @@ Import-Package: org.json.simple, org.json.simple.parser Require-Bundle: com.sap.sailing.domain.test, org.junit4;bundle-version="4.8.2", - com.sap.sse.common + com.sap.sse.common, + org.mockito.mockito-core;bundle-version="1.10.14" diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingRaceConfigurationTest.java b/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingRaceConfigurationTest.java index 2f261e29719..0de4deffcde 100644 --- a/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingRaceConfigurationTest.java +++ b/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingRaceConfigurationTest.java @@ -17,6 +17,9 @@ import java.util.Map; import org.junit.Ignore; import org.junit.Test; +import static org.mockito.Mockito.mock; + +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.swisstimingadapter.DomainFactory; import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayRace; import com.sap.sailing.domain.swisstimingreplayadapter.impl.SwissTimingRaceConfig; @@ -30,13 +33,13 @@ public class SwissTimingRaceConfigurationTest { @Test public void testLoadConfigurations() throws IOException, ParseException, org.json.simple.parser.ParseException { InputStream inputStream = getClass().getResourceAsStream(JSON_URL); - List races = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE).parseJSONObject(inputStream , JSON_URL); + List races = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class)).parseJSONObject(inputStream , JSON_URL); Map configsById = new HashMap(); for (SwissTimingReplayRace race : races) { URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, race.getRaceId())); URLConnection connection = configFileURL.openConnection(); InputStream configDataStream = connection.getInputStream(); - SwissTimingRaceConfig raceConfig = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE).loadRaceConfig(configDataStream); + SwissTimingRaceConfig raceConfig = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class)).loadRaceConfig(configDataStream); configsById.put(race.getRaceId(), raceConfig); } } @@ -46,7 +49,7 @@ public class SwissTimingRaceConfigurationTest { URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, "446483")); URLConnection connection = configFileURL.openConnection(); InputStream configDataStream = connection.getInputStream(); - SwissTimingRaceConfig config_446483 = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE).loadRaceConfig(configDataStream); + SwissTimingRaceConfig config_446483 = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class)).loadRaceConfig(configDataStream); assertNotNull(config_446483); assertEquals("GB", config_446483.country_code); assertNull(config_446483.event_name); @@ -63,7 +66,7 @@ public class SwissTimingRaceConfigurationTest { URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, "6260")); URLConnection connection = configFileURL.openConnection(); InputStream configDataStream = connection.getInputStream(); - SwissTimingRaceConfig config_446483 = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE).loadRaceConfig(configDataStream); + SwissTimingRaceConfig config_446483 = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class)).loadRaceConfig(configDataStream); assertNotNull(config_446483); assertEquals("GB", config_446483.country_code); assertEquals("London 2012 Olympic Games", config_446483.event_name); diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingReplayAdapterServiceTest.java b/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingReplayAdapterServiceTest.java index e67c8f56bfd..461f6ed83de 100644 --- a/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingReplayAdapterServiceTest.java +++ b/java/com.sap.sailing.domain.swisstimingreplayadapter.test/src/com/sap/sailing/domain/swisstimingreplayadapter/test/SwissTimingReplayAdapterServiceTest.java @@ -1,6 +1,7 @@ package com.sap.sailing.domain.swisstimingreplayadapter.test; import static org.junit.Assert.assertArrayEquals; +import static org.mockito.Mockito.mock; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; @@ -16,6 +17,7 @@ import java.util.List; import org.junit.Ignore; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.swisstimingadapter.DomainFactory; @@ -33,7 +35,7 @@ public class SwissTimingReplayAdapterServiceTest { public void testLoadRaceJson() throws Exception { String swissTimingUrlText = "/2012_OSG.json"; InputStream inputStream = getClass().getResourceAsStream(swissTimingUrlText); - final SwissTimingReplayServiceImpl swissTimingReplayService = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE); + final SwissTimingReplayServiceImpl swissTimingReplayService = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class)); List races = swissTimingReplayService.parseJSONObject(inputStream , swissTimingUrlText); assertEquals(201, races.size()); assertEquals("446483", races.get(0).getRaceId()); @@ -178,7 +180,7 @@ public class SwissTimingReplayAdapterServiceTest { @Test public void testRaceData_SAW010955_20120802_WithDomainAdapter() throws Exception { SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, DomainFactory.INSTANCE, - new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false); + new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false, mock(RaceLogResolver.class)); new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAW005906.20120805.replay"), replayListener); Iterable trackedRaces = replayListener.getTrackedRaces(); assertFalse(Util.isEmpty(trackedRaces)); @@ -192,7 +194,7 @@ public class SwissTimingReplayAdapterServiceTest { @Test public void testStartPerformanceDetection() throws Exception { SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, DomainFactory.INSTANCE, - new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false); + new DummyTrackedRegattaRegistry(), /* useInternalMarkPassingAlgorithm */ false, mock(RaceLogResolver.class)); new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAW005906.20120805.replay"), replayListener); Iterable trackedRaces = replayListener.getTrackedRaces(); TrackedRace trackedRace = trackedRaces.iterator().next(); diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.swisstimingreplayadapter/META-INF/MANIFEST.MF index cd3c7b4a848..0507cad7850 100644 --- a/java/com.sap.sailing.domain.swisstimingreplayadapter/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.swisstimingreplayadapter/META-INF/MANIFEST.MF @@ -12,7 +12,8 @@ Require-Bundle: com.sap.sailing.domain.common, com.sap.sailing.domain.swisstimingadapter, com.googlecode.java-diff-utils;bundle-version="1.3.0", com.sap.sse, - com.sap.sse.common + com.sap.sse.common, + com.sap.sailing.domain.shared.android Export-Package: com.sap.sailing.domain.swisstimingreplayadapter Import-Package: org.osgi.framework;version="1.7.0" Bundle-Activator: com.sap.sailing.domain.swisstimingreplayadapter.impl.Activator diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayServiceFactory.java b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayServiceFactory.java index 12c40c4908b..34fb5c951e9 100755 --- a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayServiceFactory.java +++ b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/SwissTimingReplayServiceFactory.java @@ -1,10 +1,11 @@ package com.sap.sailing.domain.swisstimingreplayadapter; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.swisstimingadapter.DomainFactory; import com.sap.sailing.domain.swisstimingreplayadapter.impl.SwissTimingReplayServiceFactoryImpl; public interface SwissTimingReplayServiceFactory { static SwissTimingReplayServiceFactory INSTANCE = new SwissTimingReplayServiceFactoryImpl(); - SwissTimingReplayService createSwissTimingReplayService(DomainFactory domainFactory); + SwissTimingReplayService createSwissTimingReplayService(DomainFactory domainFactory, RaceLogResolver raceLogResolver); } diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceFactoryImpl.java b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceFactoryImpl.java index 7adb8b89dbe..5334e7ea2f0 100755 --- a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceFactoryImpl.java +++ b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceFactoryImpl.java @@ -3,6 +3,7 @@ package com.sap.sailing.domain.swisstimingreplayadapter.impl; import java.util.HashMap; import java.util.Map; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.swisstimingadapter.DomainFactory; import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayService; import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayServiceFactory; @@ -15,10 +16,10 @@ public class SwissTimingReplayServiceFactoryImpl implements SwissTimingReplaySer } @Override - public SwissTimingReplayService createSwissTimingReplayService(DomainFactory domainFactory) { + public SwissTimingReplayService createSwissTimingReplayService(DomainFactory domainFactory, RaceLogResolver raceLogResolver) { SwissTimingReplayService result = servicesForDomainFactories.get(domainFactory); if (result == null) { - result = new SwissTimingReplayServiceImpl(domainFactory); + result = new SwissTimingReplayServiceImpl(domainFactory, raceLogResolver); servicesForDomainFactories.put(domainFactory, result); } return result; diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceImpl.java b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceImpl.java index 35215a778d8..3d5fe7ff094 100644 --- a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceImpl.java +++ b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayServiceImpl.java @@ -18,6 +18,7 @@ import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.swisstimingadapter.DomainFactory; import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayListener; @@ -34,9 +35,11 @@ public class SwissTimingReplayServiceImpl implements SwissTimingReplayService { private static final TimeZone DEFAULT_TIMEZONE = TimeZone.getTimeZone("GMT"); private final DomainFactory domainFactory; + private final RaceLogResolver raceLogResolver; - public SwissTimingReplayServiceImpl(DomainFactory domainFactory) { + public SwissTimingReplayServiceImpl(DomainFactory domainFactory, RaceLogResolver raceLogResolver) { this.domainFactory = domainFactory; + this.raceLogResolver = raceLogResolver; } @Override @@ -143,8 +146,10 @@ public class SwissTimingReplayServiceImpl implements SwissTimingReplayService { } @Override - public void loadRaceData(String link, Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm) { - SwissTimingReplayListener listener = new SwissTimingReplayToDomainAdapter(regatta, domainFactory, trackedRegattaRegistry, useInternalMarkPassingAlgorithm); + public void loadRaceData(String link, Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, + boolean useInternalMarkPassingAlgorithm) { + SwissTimingReplayListener listener = new SwissTimingReplayToDomainAdapter(regatta, domainFactory, + trackedRegattaRegistry, useInternalMarkPassingAlgorithm, raceLogResolver); loadRaceData(link, listener); } } diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java index fa87e202b21..096cbb03e87 100755 --- a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java +++ b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java @@ -15,6 +15,7 @@ import java.util.Set; import java.util.TimeZone; import java.util.logging.Logger; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.Course; @@ -136,6 +137,8 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter { private RaceStatus lastRaceStatus; private final boolean useInternalMarkPassingAlgorithm; + + private final RaceLogResolver raceLogResolver; /** * @param regatta @@ -144,7 +147,8 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter { * @param useInternalMarkPassingAlgorithm use our own instead of the SwissTiming-provided mark rounding / split times */ public SwissTimingReplayToDomainAdapter(Regatta regatta, DomainFactory domainFactory, - TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm) { + TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver) { + this.raceLogResolver = raceLogResolver; this.regatta = regatta; this.trackedRegattaRegistry = trackedRegattaRegistry; racePerRaceID = new HashMap<>(); @@ -317,7 +321,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter { createTrackedRace(race, Collections. emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,TrackedRace.DEFAULT_LIVE_DELAY_IN_MILLISECONDS, WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, /* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(), - /* raceDefinitionSetToUpdate */ null, useInternalMarkPassingAlgorithm); + /* raceDefinitionSetToUpdate */ null, useInternalMarkPassingAlgorithm, raceLogResolver); trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, 0)); TimePoint bestStartTimeKnownSoFar = bestStartTimePerRaceID.get(currentRaceID); if (bestStartTimeKnownSoFar != null) { diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/markpassing/impl/WaypointPositionAndDistanceCacheTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/markpassing/impl/WaypointPositionAndDistanceCacheTest.java index 0b1dc175de5..a593a00f766 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/markpassing/impl/WaypointPositionAndDistanceCacheTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/markpassing/impl/WaypointPositionAndDistanceCacheTest.java @@ -12,6 +12,7 @@ import java.util.function.Function; import org.junit.Before; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.ControlPointWithTwoMarks; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.DomainFactory; @@ -77,7 +78,7 @@ public class WaypointPositionAndDistanceCacheTest { trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, Collections.emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 8000, /* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 15000, /* delayForCacheInvalidationOfWindEstimation */ 10000, - /* useInternalMarkPassingAlgorithm */ false, OneDesignRankingMetric::new); + /* useInternalMarkPassingAlgorithm */ false, OneDesignRankingMetric::new, mock(RaceLogResolver.class)); timeRangeResolution = Duration.ONE_MINUTE; now = new MillisecondsTimePoint(MillisecondsTimePoint.now().asMillis() / timeRangeResolution.asMillis() * timeRangeResolution.asMillis()); trackedRace.getOrCreateTrack(pinEnd).addGPSFix(new GPSFixImpl(new DegreePosition(0, -0.0000001), now)); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java index 87040eed61f..c4f9d04ccf2 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/ranking/TestSimpleTimeOnTimeRankingWithOneUpwindLeg.java @@ -2,6 +2,7 @@ package com.sap.sailing.domain.ranking; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; +import static org.mockito.Mockito.mock; import java.util.ArrayList; import java.util.Arrays; @@ -12,6 +13,7 @@ import java.util.function.Function; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.Course; @@ -91,7 +93,7 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg { /* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false, tr->new TimeOnTimeAndDistanceRankingMetric(tr, timeOnTimeFactors, // time-on-time - c->new MillisecondsDurationImpl((long) (1000.*timeOnDistanceFactors.apply(c))))); + c->new MillisecondsDurationImpl((long) (1000.*timeOnDistanceFactors.apply(c)))), mock(RaceLogResolver.class)); // in this simplified artificial course, the top mark is exactly north of the right leeward gate DegreePosition topPosition = new DegreePosition(1, 0); trackedRace.getOrCreateTrack(left).addGPSFix(new GPSFixImpl(new DegreePosition(0, -0.000001), timePointForFixes)); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseTest.java index c58772bfce8..1c09df563f9 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import java.util.ArrayList; import java.util.Arrays; @@ -15,6 +16,7 @@ import java.util.Set; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.DomainFactory; @@ -304,7 +306,8 @@ public class CourseTest { new RaceDefinitionImpl("Test Race", course, new BoatClassImpl("49er", /* upwind start */true), hasso), Collections. emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,/* delayToLiveInMillis */3000, /* millisecondsOverWhichToAverageWind */30000, - /* millisecondsOverWhichToAverageSpeed */8000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); + /* millisecondsOverWhichToAverageSpeed */8000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new, + mock(RaceLogResolver.class)); assertLegStructure(course, trackedRace); course.removeWaypoint(0); assertLegStructure(course, trackedRace); @@ -335,7 +338,8 @@ public class CourseTest { hasso), Collections. emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 3000, /* millisecondsOverWhichToAverageWind */ 30000, - /* millisecondsOverWhichToAverageSpeed */ 8000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); + /* millisecondsOverWhichToAverageSpeed */ 8000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new, + mock(RaceLogResolver.class)); assertLegStructure(course, trackedRace); final WaypointImpl wp1_5 = new WaypointImpl(new MarkImpl("Test Mark 1.5")); assertWaypointIndexes(course); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java index 6d77db7ae2f..a4490ae9bb9 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateDuringNonAtomicSerializationTest.java @@ -3,6 +3,7 @@ package com.sap.sailing.domain.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -19,6 +20,7 @@ import java.util.UUID; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.RaceDefinition; @@ -81,7 +83,7 @@ public class CourseUpdateDuringNonAtomicSerializationTest implements Serializabl trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, Collections. emptySet(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */10000, /* millisecondsOverWhichToAverageWind */30000, /* millisecondsOverWhichToAverageSpeed */ - 7000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new) { + 7000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new, mock(RaceLogResolver.class)) { private static final long serialVersionUID = 9114777576548711763L; @Override diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateTest.java index 07eb229db4a..c777e2d010c 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/CourseUpdateTest.java @@ -20,7 +20,9 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import static org.mockito.Mockito.mock; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.Course; @@ -91,7 +93,8 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest { } }, /* delayToLiveInMillis */0l, /* millisecondsOverWhichToAverageWind */30000, /* simulator */null, /* courseDesignUpdateURI */ - null, /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/false) { + null, /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), + /*ignoreTracTracMarkPassings*/false, mock(RaceLogResolver.class)) { @Override protected void handleEvent(Triple event) { super.handleEvent(event); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardCourseChangeTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardCourseChangeTest.java index 391dbfba65e..62fceea3754 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardCourseChangeTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardCourseChangeTest.java @@ -14,6 +14,7 @@ import java.util.concurrent.ExecutionException; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; @@ -138,7 +139,8 @@ public class LeaderboardCourseChangeTest { TrackedRegatta mockedTrackedRegatta = createMockedTrackedRegatta(regatta); RaceDefinition mockedRace = createMockedRace(course, boatClass); TrackedRace spyedTrackedRace = spy(new DynamicTrackedRaceImpl(mockedTrackedRegatta, mockedRace, - new HashSet(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, 5000, 20000, 20000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new)); + new HashSet(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, 5000, 20000, 20000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new, + mock(RaceLogResolver.class))); return spyedTrackedRace; } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardDTOCalculationReuseCacheTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardDTOCalculationReuseCacheTest.java new file mode 100644 index 00000000000..dcd6db04ab5 --- /dev/null +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardDTOCalculationReuseCacheTest.java @@ -0,0 +1,33 @@ +package com.sap.sailing.domain.test; + +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.common.Position; +import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sailing.domain.common.tracking.GPSFixMoving; +import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache; +import com.sap.sailing.domain.tracking.GPSFixTrack; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sse.common.impl.MillisecondsTimePoint; + +public class LeaderboardDTOCalculationReuseCacheTest { + @Test + public void testNullWindCaching() { + final MillisecondsTimePoint now = MillisecondsTimePoint.now(); + final LeaderboardDTOCalculationReuseCache cache = new LeaderboardDTOCalculationReuseCache(now); + final Competitor competitor = mock(Competitor.class); + @SuppressWarnings("unchecked") + final GPSFixTrack track = mock(GPSFixTrack.class); + final Position p = new DegreePosition(123, 12); + when(track.getEstimatedPosition(now, false)).thenReturn(p); + final TrackedRace trackedRace = mock(TrackedRace.class); + when(trackedRace.getTrack(competitor)).thenReturn(track); + when(trackedRace.getWind(p, now)).thenReturn(null); + assertNull(cache.getWind(trackedRace, competitor, now)); + } +} diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java index f25fe97ef2c..7cbbad0ae5e 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/MultipleClassesInRegattaTest.java @@ -10,10 +10,13 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import static org.mockito.Mockito.mock; + import org.junit.After; import org.junit.Before; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore; import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore; import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore; @@ -61,7 +64,7 @@ public class MultipleClassesInRegattaTest { false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY, - new DummyTrackedRegattaRegistry()); + new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class)); kiwotest2 = domainFactory .createRaceTracker( new URL( @@ -72,7 +75,7 @@ public class MultipleClassesInRegattaTest { false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY, - new DummyTrackedRegattaRegistry()); + new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class)); kiwotest3 = domainFactory .createRaceTracker( new URL( @@ -83,7 +86,7 @@ public class MultipleClassesInRegattaTest { false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY, - new DummyTrackedRegattaRegistry()); + new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class)); weym470may112014_2 = domainFactory .createRaceTracker( new URL( @@ -94,7 +97,7 @@ public class MultipleClassesInRegattaTest { false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword, TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY, - new DummyTrackedRegattaRegistry()); + new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class)); assertEquals("STG", kiwotest1.getRegatta().getBoatClass().getName()); assertEquals("5O5", kiwotest2.getRegatta().getBoatClass().getName()); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java index e354501b1f3..28341dce76c 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OnlineTracTracBasedTest.java @@ -2,6 +2,7 @@ package com.sap.sailing.domain.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; import java.io.FileNotFoundException; import java.io.IOException; @@ -18,6 +19,7 @@ import java.util.regex.Pattern; import org.junit.Before; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.RaceDefinition; @@ -113,8 +115,8 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest { ArrayList receivers = new ArrayList(); for (Receiver r : domainFactory.getUpdateReceivers(trackedRegatta, getTracTracRace(), EmptyWindStore.INSTANCE, /* delayToLiveInMillis */0l, /* simulator */null, createRaceDefinitionSet(), /* trackedRegattaRegistry */null, - /* courseDesignUpdateURI */null, /* tracTracUsername */null, null, /* tracTracPassword */ - getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, receiverTypes)) { + mock(RaceLogResolver.class), /* courseDesignUpdateURI */null, /* tracTracUsername */null, /* tracTracPassword */ + null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, receiverTypes)) { receivers.add(r); } getRaceSubscriber().subscribeConnectionStatus(new IConnectionStatusListener() { diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java index 483614af2a2..d024ee59989 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReachingLegTest.java @@ -2,6 +2,7 @@ package com.sap.sailing.domain.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import java.util.ArrayList; import java.util.Collections; @@ -12,6 +13,7 @@ import java.util.List; import org.junit.Before; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.Course; @@ -109,7 +111,7 @@ public class ReachingLegTest extends TrackBasedTest { EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0, /* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000, /* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false, - OneDesignRankingMetric::new); + OneDesignRankingMetric::new, mock(RaceLogResolver.class)); // in this simplified artificial course, the top mark is exactly north of the right leeward gate, the offset // mark is slightly west of the top mark; wind from the north makes the leg from top to offset a reaching leg Position leftPosition = new DegreePosition(0, -0.00001); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveMarkPassingDataTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveMarkPassingDataTest.java index d86ae9384b8..cb7d6c5a6e0 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveMarkPassingDataTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveMarkPassingDataTest.java @@ -2,6 +2,7 @@ package com.sap.sailing.domain.test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import java.net.MalformedURLException; import java.net.URISyntaxException; @@ -11,6 +12,7 @@ import java.util.List; import org.junit.Before; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl; @@ -106,9 +108,9 @@ public class ReceiveMarkPassingDataTest extends AbstractTracTracLiveTest { public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) { } }, /* trackedRegattaRegistry */null, - /* courseDesignUpdateURI */null, /* tracTracUsername */null, null, /* tracTracPassword */ - getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, ReceiverType.RACECOURSE, ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH, - ReceiverType.RAWPOSITIONS)) { + mock(RaceLogResolver.class), /* courseDesignUpdateURI */null, /* tracTracUsername */null, /* tracTracPassword */ + null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, ReceiverType.RACECOURSE, ReceiverType.MARKPOSITIONS, + ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS)) { receivers.add(r); } addListenersForStoredDataAndStartController(receivers); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java index 649e9e59552..03f9b00753d 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java @@ -1,6 +1,7 @@ package com.sap.sailing.domain.test; import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; import java.net.MalformedURLException; import java.net.URISyntaxException; @@ -8,6 +9,7 @@ import java.net.URISyntaxException; import org.junit.Before; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; @@ -83,8 +85,8 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest { public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) { } }, - /* trackedRegattaRegistry */null, getTracTracRace(), null, /* courseDesignUpdateURI */ - /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false)) { + /* trackedRegattaRegistry */null, mock(RaceLogResolver.class), getTracTracRace(), /* courseDesignUpdateURI */ + null, /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false)) { receiver.subscribe(); getRaceSubscriber().start(); } @@ -95,8 +97,8 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest { @Override public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) { } - }, /* trackedRegattaRegistry */null, getTracTracRace(), null, /* courseDesignUpdateURI */ - /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false)); + }, /* trackedRegattaRegistry */null, mock(RaceLogResolver.class), getTracTracRace(), /* courseDesignUpdateURI */ + null, /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false)); } @Test diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java index 9e257f14e59..5502e58de45 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/StarbordSideOfStartLineRecognitionTest.java @@ -12,6 +12,7 @@ import java.util.Collections; import org.junit.Before; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Mark; @@ -87,7 +88,8 @@ public class StarbordSideOfStartLineRecognitionTest { private static final long serialVersionUID = -8007932232555073829L; public MockedTrackedRaceImpl() { - super(null, null, Collections. emptyList(), null, null, 0, 0, 0, 0, false, OneDesignRankingMetric::new); + super(null, null, Collections. emptyList(), null, null, 0, 0, 0, 0, false, OneDesignRankingMetric::new, + mock(RaceLogResolver.class)); } @Override diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java index ac5a08d55fc..159809279a5 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackBasedTest.java @@ -1,11 +1,14 @@ package com.sap.sailing.domain.test; +import static org.mockito.Mockito.mock; + import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.UUID; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.Course; @@ -119,7 +122,7 @@ public abstract class TrackBasedTest { EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0, /* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000, /* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false, - OneDesignRankingMetric::new); + OneDesignRankingMetric::new, mock(RaceLogResolver.class)); // in this simplified artificial course, the top mark is exactly north of the right leeward gate DegreePosition topPosition = new DegreePosition(54.48, 10.24); TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix timed diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java index de22a3fa28b..6d6652b7772 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UnicodeCharactersInCompetitorNamesTest.java @@ -1,6 +1,7 @@ package com.sap.sailing.domain.test; import java.io.BufferedReader; +import static org.mockito.Mockito.mock; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; @@ -15,6 +16,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.Timeout; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore; import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore; @@ -68,7 +70,7 @@ public class UnicodeCharactersInCompetitorNamesTest { /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, "tracTest", "tracTest", "", "", - new DummyTrackedRegattaRegistry()); + new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class)); Iterable competitors = fourtyninerYellow_2.getRacesHandle().getRace().getCompetitors(); for (Competitor competitor : competitors) { diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UpdateMarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UpdateMarkPassingTest.java index d3a62ff752e..811da5b81ae 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UpdateMarkPassingTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/UpdateMarkPassingTest.java @@ -10,6 +10,7 @@ import java.util.HashSet; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.RaceDefinition; @@ -47,7 +48,7 @@ public class UpdateMarkPassingTest { /* trackedRegatta */new DynamicTrackedRegattaImpl(new RegattaImpl("test", null, null, null, new HashSet(), false, null, "test", null, OneDesignRankingMetric::new)), race, Collections. emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */1000, /* millisecondsOverWhichToAverageWind */30000, - /* millisecondsOverWhichToAverageSpeed */30000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); + /* millisecondsOverWhichToAverageSpeed */30000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new, mock(RaceLogResolver.class)); TimePoint now = MillisecondsTimePoint.now(); TimePoint later = now.plus(1000); trackedRace.updateMarkPassings(competitor, Arrays.asList(new MarkPassing[] { new MarkPassingImpl(now, waypoint, competitor) })); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java index 38ca32b9f38..cf6c06430f3 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/WindTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -16,6 +17,7 @@ import java.util.Set; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; @@ -287,7 +289,8 @@ public class WindTest { boatClass, Collections.singleton(competitor)), Collections. emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 1000, /* millisecondsOverWhichToAverageWind */ 30000, - /* millisecondsOverWhichToAverageSpeed */ 30000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); + /* millisecondsOverWhichToAverageSpeed */ 30000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new, + mock(RaceLogResolver.class)); TimePoint start = MillisecondsTimePoint.now(); TimePoint topMarkRounding = start.plus(30000); TimePoint finish = topMarkRounding.plus(30000); diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java index 469b23d8b39..06e7eedcc3b 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/markpassing/AbstractMockedRaceMarkPassingTest.java @@ -5,6 +5,9 @@ import java.util.Arrays; import java.util.List; import java.util.UUID; +import static org.mockito.Mockito.mock; + +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPointWithTwoMarks; import com.sap.sailing.domain.base.Course; @@ -55,7 +58,6 @@ public class AbstractMockedRaceMarkPassingTest { public AbstractMockedRaceMarkPassingTest() { ControlPointWithTwoMarks cp = new ControlPointWithTwoMarksImpl(gate1, gate2, "cp"); - Waypoint w1 = new WaypointImpl(cp, PassingInstruction.Line); Waypoint w2 = new WaypointImpl(m, PassingInstruction.Port); Waypoint w3 = new WaypointImpl(cp, PassingInstruction.Gate); @@ -68,7 +70,8 @@ public class AbstractMockedRaceMarkPassingTest { new ArrayList(), null)), true, new HighPoint(), "ID", new CourseAreaImpl("area", new UUID(5, 5)), OneDesignRankingMetric::new); Course course = new CourseImpl("course", waypoints); RaceDefinition raceDef = new RaceDefinitionImpl("Performance Race", course, boatClass, Arrays.asList(ron, tom, ben)); - race = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl(r), raceDef, new ArrayList(), new EmptyWindStore(), EmptyGPSFixStore.INSTANCE, 0, 10000, 10000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); + race = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl(r), raceDef, new ArrayList(), new EmptyWindStore(), EmptyGPSFixStore.INSTANCE, 0, 10000, 10000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new, + mock(RaceLogResolver.class)); race.setStartTimeReceived(new MillisecondsTimePoint(10000)); TimePoint t = new MillisecondsTimePoint(30000); List> pos = Arrays.asList(new Util.Pair(m, new DegreePosition(0, 0)), diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java index 481323374f0..943e938d1d7 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java @@ -8,6 +8,7 @@ import java.util.Set; import java.util.TreeSet; import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; @@ -16,6 +17,7 @@ import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.EventFetcher; import com.sap.sailing.domain.base.Leg; import com.sap.sailing.domain.base.Mark; +import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.RaceColumnListener; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; @@ -462,6 +464,11 @@ public class MockedTrackedRace implements DynamicTrackedRace { public Duration getTimeOnDistanceAllowancePerNauticalMile(Competitor competitor) { return null; } + + @Override + public RaceColumn getRaceColumnByName(String raceColumnName) { + return null; + } }; } @@ -510,7 +517,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable sidelines, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, - DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingcalculator) { + DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingcalculator, RaceLogResolver raceLogResolver) { return null; } diff --git a/java/com.sap.sailing.domain.tractracadapter/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.tractracadapter/META-INF/MANIFEST.MF index 9bee601cb0e..ae105762c5f 100644 --- a/java/com.sap.sailing.domain.tractracadapter/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.tractracadapter/META-INF/MANIFEST.MF @@ -12,7 +12,8 @@ Require-Bundle: com.sap.sailing.domain, com.sap.sailing.server.gateway.serialization;bundle-version="1.0.0", com.sap.sse, com.sap.sse.common, - com.sap.sailing.server.gateway.serialization.shared.android + com.sap.sailing.server.gateway.serialization.shared.android, + com.sap.sailing.domain.shared.android Export-Package: com.sap.sailing.domain.tractracadapter, com.sap.sailing.domain.tractracadapter.impl; x-friends:="com.sap.sailing.domain.test, diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java index 502797d0123..24f100d306d 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/DomainFactory.java @@ -11,6 +11,7 @@ import java.text.ParseException; import java.util.List; import java.util.UUID; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Mark; @@ -133,23 +134,25 @@ public interface DomainFactory { * Provides the capability to obtain the {@link WindTrack}s for the different wind sources. A trivial * implementation is {@link EmptyWindStore} which simply provides new, empty tracks. This is always * available but loses track of the wind, e.g., during server restarts. + * @param raceLogResolver TODO */ TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword, - String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry) + String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException, SubscriberInitializationException; /** * Same as {@link #createRaceTracker(URL, URI, URI, URI, TimePoint, TimePoint, WindStore, TrackedRegattaRegistry)}, only that * a predefined {@link Regatta} is used to hold the resulting races. + * @param raceLogResolver TODO */ RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword, - String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry) + String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException, SubscriberInitializationException; @@ -166,15 +169,16 @@ public interface DomainFactory { * must have been created before through * {@link #getOrCreateTrackedRegatta(com.sap.sailing.domain.base.Regatta)} because otherwise the link to * the {@link IEvent} can't be established + * @param raceLogResolver TODO * @param tokenToRetrieveAssociatedRace * used to update the set of{@link RaceDefinition}s received by the {@link RaceCourseReceiver} created by * this call */ Iterable getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, long delayToLiveInMillis, Simulator simulator, WindStore windStore, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, - IRace tractracRace, URI courseDesignUpdateURI, - String tracTracUsername, String tracTracPassword, IEventSubscriber eventSubscriber, - IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm); + RaceLogResolver raceLogResolver, IRace tractracRace, + URI courseDesignUpdateURI, String tracTracUsername, String tracTracPassword, + IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm); /** * Creates a {@link RaceDefinition} from a TracTrac {@link Race} and a domain {@link Course} definition. The @@ -188,17 +192,17 @@ public interface DomainFactory { * already immediately after the notification was sent, and that the {@link RaceDefinition} is already * {@link com.sap.sailing.domain.base.Regatta#getAllRaces() known} by its containing * {@link com.sap.sailing.domain.base.Regatta}. - * * @param raceDefinitionSetToUpdate * if not null, after creating the {@link TrackedRace}, the {@link RaceDefinition} is * {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that * object. + * @param raceLogResolver TODO */ DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(DynamicTrackedRegatta trackedRegatta, UUID raceId, String raceName, Iterable competitors, BoatClass boatClass, Course course, Iterable sidelines, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, - URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword, boolean ignoreTracTracMarkPassings); + URI courseDesignUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword, boolean ignoreTracTracMarkPassings, RaceLogResolver raceLogResolver); /** * The record may be for a single mark or a gate. If for a gate, the @@ -213,11 +217,12 @@ public interface DomainFactory { /** * If the vm argument tractrac.usemarkpassings=false, the RecieverType MARKPASSINGS will not return anything + * @param raceLogResolver TODO */ Iterable getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, IRace tractracRace, WindStore windStore, long delayToLiveInMillis, Simulator simulator, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, - URI courseDesignUpdateURI, String tracTracUsername, - String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean ignoreTracTracMarkPassings, ReceiverType... types); + RaceLogResolver raceLogResolver, URI courseDesignUpdateURI, + String tracTracUsername, String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean ignoreTracTracMarkPassings, ReceiverType... types); JSONService parseJSONURLWithRaceRecords(URL jsonURL, boolean loadClientParams) throws IOException, ParseException, org.json.simple.parser.ParseException, URISyntaxException; 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 c0e19ce6f7a..e514af5dcf9 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 @@ -19,6 +19,7 @@ import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CompetitorStore; @@ -404,18 +405,19 @@ public class DomainFactoryImpl implements DomainFactory { @Override public Iterable getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, IRace tractracRace, WindStore windStore, long delayToLiveInMillis, Simulator simulator, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, - TrackedRegattaRegistry trackedRegattaRegistry, URI courseDesignUpdateURI, - String tracTracUsername, String tracTracPassword, IEventSubscriber eventSubscriber, - IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm, ReceiverType... types) { + TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, + URI courseDesignUpdateURI, String tracTracUsername, String tracTracPassword, + IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm, ReceiverType... types) { IEvent tractracEvent = tractracRace.getEvent(); Collection result = new ArrayList(); for (ReceiverType type : types) { switch (type) { case RACECOURSE: - result.add(new RaceCourseReceiver(this, trackedRegatta, tractracEvent, tractracRace, - windStore, raceDefinitionSetToUpdate, - delayToLiveInMillis, WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, simulator, - courseDesignUpdateURI, tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm)); + result.add(new RaceCourseReceiver(this, trackedRegatta, tractracEvent, tractracRace, windStore, + raceDefinitionSetToUpdate, delayToLiveInMillis, + WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, simulator, courseDesignUpdateURI, + tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber, + useInternalMarkPassingAlgorithm, raceLogResolver)); break; case MARKPOSITIONS: result.add(new MarkPositionReceiver( @@ -442,14 +444,14 @@ public class DomainFactoryImpl implements DomainFactory { @Override public Iterable getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, long delayToLiveInMillis, Simulator simulator, WindStore windStore, - DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, IRace tractracRace, - URI courseDesignUpdateURI, String tracTracUsername, - String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm) { + DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver, + IRace tractracRace, URI courseDesignUpdateURI, + String tracTracUsername, String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm) { return getUpdateReceivers(trackedRegatta, tractracRace, windStore, delayToLiveInMillis, simulator, - raceDefinitionSetToUpdate, trackedRegattaRegistry, courseDesignUpdateURI, tracTracUsername, - tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm, - ReceiverType.RACECOURSE, ReceiverType.MARKPASSINGS, ReceiverType.MARKPOSITIONS, - ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS); + raceDefinitionSetToUpdate, trackedRegattaRegistry, raceLogResolver, courseDesignUpdateURI, + tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber, + useInternalMarkPassingAlgorithm, ReceiverType.RACECOURSE, ReceiverType.MARKPASSINGS, + ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS); } @Override @@ -518,7 +520,7 @@ public class DomainFactoryImpl implements DomainFactory { String raceName, Iterable competitors, BoatClass boatClass, Course course, Iterable sidelines, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, - URI tracTracUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword, boolean ignoreTracTracMarkPassings) { + URI tracTracUpdateURI, UUID tracTracEventUuid, String tracTracUsername, String tracTracPassword, boolean ignoreTracTracMarkPassings, RaceLogResolver raceLogResolver) { synchronized (raceCache) { RaceDefinition raceDefinition = raceCache.get(raceId); if (raceDefinition == null) { @@ -533,7 +535,8 @@ public class DomainFactoryImpl implements DomainFactory { if (raceDefinition.getBoatClass() == trackedRegatta.getRegatta().getBoatClass()) { trackedRegatta.getRegatta().addRace(raceDefinition); trackedRace = createTrackedRace(trackedRegatta, raceDefinition, sidelines, windStore, EmptyGPSFixStore.INSTANCE, - delayToLiveInMillis, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate, ignoreTracTracMarkPassings); + delayToLiveInMillis, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate, ignoreTracTracMarkPassings, + raceLogResolver); logger.info("Added race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta()); addTracTracUpdateHandlers(tracTracUpdateURI, tracTracEventUuid, tracTracUsername, tracTracPassword, raceDefinition, trackedRace); @@ -568,12 +571,14 @@ public class DomainFactoryImpl implements DomainFactory { trackedRace.addRaceAbortedListener(raceAbortedHandler); } - private DynamicTrackedRace createTrackedRace(TrackedRegatta trackedRegatta, RaceDefinition race, Iterable sidelines, WindStore windStore, GPSFixStore gpsFixStore, - long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingCalculator) { + private DynamicTrackedRace createTrackedRace(TrackedRegatta trackedRegatta, RaceDefinition race, + Iterable sidelines, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, + long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, + boolean useMarkPassingCalculator, RaceLogResolver raceLogResolver) { return trackedRegatta.createTrackedRace(race, sidelines, windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, /* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(), - raceDefinitionSetToUpdate, useMarkPassingCalculator); + raceDefinitionSetToUpdate, useMarkPassingCalculator, raceLogResolver); } @Override @@ -648,28 +653,29 @@ public class DomainFactoryImpl implements DomainFactory { @Override public TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, - boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, - WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword, - String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry) - throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException, - SubscriberInitializationException { + boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, + RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, + String tracTracPassword, String raceStatus, String raceVisibility, + TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws MalformedURLException, FileNotFoundException, + URISyntaxException, CreateModelException, SubscriberInitializationException { return new TracTracRaceTrackerImpl(this, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore, - gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry); + gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver); } @Override public RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, - boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, - WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword, - String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry) + boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, + RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, + String tracTracPassword, String raceStatus, String raceVisibility, + TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException, SubscriberInitializationException { return new TracTracRaceTrackerImpl(regatta, this, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, - raceVisibility, trackedRegattaRegistry); + raceVisibility, trackedRegattaRegistry, raceLogResolver); } @Override diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java index a474744717d..9033ba85de2 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java @@ -8,6 +8,7 @@ import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; @@ -61,14 +62,17 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue(); for (Receiver receiver : domainFactory.getUpdateReceivers(getTrackedRegatta(), delayToLiveInMillis, - simulator, windStore, this, trackedRegattaRegistry, tractracRace, tracTracUpdateURI, - tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm)) { + simulator, windStore, this, trackedRegattaRegistry, raceLogResolver, tractracRace, + tracTracUpdateURI, tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm)) { receivers.add(receiver); } addListenersForStoredDataAndStartController(receivers); diff --git a/java/com.sap.sailing.domain/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain/META-INF/MANIFEST.MF index 959694e5909..fbd86b1960a 100755 --- a/java/com.sap.sailing.domain/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain/META-INF/MANIFEST.MF @@ -19,7 +19,6 @@ Export-Package: com.sap.sailing.domain.base, com.sap.sailing.domain.masterdataimport, com.sap.sailing.domain.polars, com.sap.sailing.domain.racelog, - com.sap.sailing.domain.racelog.analyzing, com.sap.sailing.domain.racelog.impl, com.sap.sailing.domain.racelog.tracking, com.sap.sailing.domain.ranking, diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java index e8c17204a89..54f31616d04 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java @@ -196,7 +196,21 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene this.scoringScheme = scoringScheme; this.defaultCourseArea = courseArea; this.configuration = null; - this.regattaLikeHelper = new BaseRegattaLikeImpl(new RegattaAsRegattaLikeIdentifier(this), regattaLogStore); + this.regattaLikeHelper = new BaseRegattaLikeImpl(new RegattaAsRegattaLikeIdentifier(this), regattaLogStore) { + private static final long serialVersionUID = 8546222568682770206L; + + @Override + public RaceColumn getRaceColumnByName(String raceColumnName) { + for (final Series series : getSeries()) { + for (final RaceColumn raceColumn : series.getRaceColumns()) { + if (raceColumn.getName().equals(raceColumnName)) { + return raceColumn; + } + } + } + return null; + } + }; this.raceExecutionOrderCache = new RaceExecutionOrderCache(); } @@ -677,4 +691,9 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene return result; } } + + @Override + public RaceColumn getRaceColumnByName(String raceColumnName) { + return regattaLikeHelper.getRaceColumnByName(raceColumnName); + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCalculationReuseCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCalculationReuseCache.java index b46080d690f..bc113bca457 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCalculationReuseCache.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCalculationReuseCache.java @@ -8,6 +8,10 @@ import com.sap.sailing.domain.common.Bearing; import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.NoWindException; import com.sap.sailing.domain.common.Wind; +import com.sap.sailing.domain.common.impl.DegreeBearingImpl; +import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl; +import com.sap.sailing.domain.common.impl.WindImpl; import com.sap.sailing.domain.leaderboard.impl.AbstractSimpleLeaderboardImpl; import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.TrackedLeg; @@ -16,6 +20,7 @@ import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingCache; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Triple; +import com.sap.sse.common.impl.MillisecondsTimePoint; /** * A cache structure that is used for a single call to @@ -45,16 +50,20 @@ public class LeaderboardDTOCalculationReuseCache implements WindLegTypeAndLegBea */ final ConcurrentHashMap legTypeCache; - /** - * the wind at competitor's position at timePoint + * the wind at competitor's position at timePoint; null values are represented by {@link #NULL_WIND}. */ final ConcurrentHashMap, Wind> windCache; + private static final Wind NULL_WIND = new WindImpl(/* position */ new DegreePosition(0, 0), + /* time point */ MillisecondsTimePoint.now(), /* windSpeedWithBearing */ new KnotSpeedWithBearingImpl(0, new DegreeBearingImpl(0))); + /** - * the leg's bearing at timePoint + * the leg's bearing at timePoint; null values are represented by {@link #NULL_BEARING}. */ final ConcurrentHashMap legBearingCache; + + private static final Bearing NULL_BEARING = new DegreeBearingImpl(0); public LeaderboardDTOCalculationReuseCache(TimePoint timePoint) { legTypeCache = new ConcurrentHashMap<>(); @@ -83,7 +92,9 @@ public class LeaderboardDTOCalculationReuseCache implements WindLegTypeAndLegBea result = legBearingCache.get(trackedLeg.getLeg()); if (result == null) { result = trackedLeg.getLegBearing(timePoint); - legBearingCache.put(trackedLeg.getLeg(), result); + legBearingCache.put(trackedLeg.getLeg(), result == null ? NULL_BEARING : result); + } else if (result == NULL_BEARING) { + result = null; } } else { result = trackedLeg.getLegBearing(timePoint); // different time point; don't cache @@ -100,7 +111,9 @@ public class LeaderboardDTOCalculationReuseCache implements WindLegTypeAndLegBea Wind result = windCache.get(cacheKey); if (result == null) { result = trackedRace.getWind(trackedRace.getTrack(competitor).getEstimatedPosition(timePoint, false), timePoint); - windCache.put(cacheKey, result); + windCache.put(cacheKey, result == null ? NULL_WIND : result); + } else if (result == NULL_WIND) { + result = null; } return result; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java index 3ebbe1e7727..fcf0fdabdca 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/FlexibleLeaderboardImpl.java @@ -84,7 +84,14 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements this.races = new ArrayList<>(); this.raceLogStore = raceLogStore; this.courseArea = courseArea; - this.regattaLikeHelper = new BaseRegattaLikeImpl(new FlexibleLeaderboardAsRegattaLikeIdentifier(this), regattaLogStore); + this.regattaLikeHelper = new BaseRegattaLikeImpl(new FlexibleLeaderboardAsRegattaLikeIdentifier(this), regattaLogStore) { + private static final long serialVersionUID = 4082392360832548953L; + + @Override + public RaceColumn getRaceColumnByName(String raceColumnName) { + return getRaceColumnByName(raceColumnName); + } + }; this.raceExecutionOrderProvider = new RaceExecutionOrderCache(); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/analyzing/ServerSideRaceLogResolver.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/analyzing/ServerSideRaceLogResolver.java deleted file mode 100644 index c5e449a4da6..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/racelog/analyzing/ServerSideRaceLogResolver.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.sap.sailing.domain.racelog.analyzing; - -import com.sap.sailing.domain.abstractlog.race.RaceLog; -import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier; -import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; -import com.sap.sailing.domain.regattalike.HasRegattaLike; - -public class ServerSideRaceLogResolver implements RaceLogResolver { - - private HasRegattaLike regattaLike; - - public ServerSideRaceLogResolver(HasRegattaLike regattaLike) { - this.regattaLike = regattaLike; - } - - @Override - public RaceLog resolve(SimpleRaceLogIdentifier identifier) { - final RaceLog result; - if (regattaLike == null) { - result = null; - } else { - result = regattaLike.getRacelog(identifier.getRaceColumnName(), identifier.getFleetName()); - } - return result; - } -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/BaseRegattaLikeImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/BaseRegattaLikeImpl.java index 7dbef9f0c15..e840bc76bfc 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/BaseRegattaLikeImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/BaseRegattaLikeImpl.java @@ -14,7 +14,7 @@ import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.regattalog.RegattaLogStore; import com.sap.sse.common.Duration; -public class BaseRegattaLikeImpl implements IsRegattaLike { +public abstract class BaseRegattaLikeImpl implements IsRegattaLike { private static final long serialVersionUID = -5629172342837950344L; private final RegattaLog regattaLog; private final RegattaLikeIdentifier identifier; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/IsRegattaLike.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/IsRegattaLike.java index 32da1fa0c62..b7643151fd6 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/IsRegattaLike.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/regattalike/IsRegattaLike.java @@ -4,6 +4,7 @@ import java.io.Serializable; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; @@ -25,6 +26,8 @@ public interface IsRegattaLike extends Serializable { */ RegattaLog getRegattaLog(); + RaceColumn getRaceColumnByName(String raceColumnName); + RegattaLikeIdentifier getRegattaLikeIdentifier(); void addListener(RegattaLikeListener listener); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParameters.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParameters.java index 091a285fe9e..5e2592a956a 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParameters.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParameters.java @@ -1,5 +1,6 @@ package com.sap.sailing.domain.tracking; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Series; @@ -20,16 +21,18 @@ import com.sap.sailing.domain.racelog.tracking.GPSFixStore; public interface RaceTrackingConnectivityParameters { /** * Starts a {@link RaceTracker} using the connectivity parameters provided by this object. + * @param raceLogResolver TODO */ - RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, GPSFixStore gpsFixStore) throws Exception; + RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) throws Exception; /** * Starts a {@link RaceTracker}, associating the resulting races with the {@link Regatta} passed as argument * instead of using the tracker's domain factory to obtain a default {@link Regatta} object for the tracking * parameters. This is particularly useful if a predefined regatta with {@link Series} and {@link Fleet}s * is to be used. + * @param raceLogResolver TODO */ - RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, GPSFixStore gpsFixStore) throws Exception; + RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) throws Exception; /** * Deliver an ID object equal to that of the {@link RaceTracker#getID()} delivered by the {@link RaceTracker} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java index 2a8c9168b16..c560317f7f3 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRace.java @@ -7,6 +7,7 @@ import java.util.Set; import java.util.SortedSet; import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedure; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent; @@ -15,6 +16,7 @@ import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Leg; import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.RaceDefinition; +import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Sideline; import com.sap.sailing.domain.base.SpeedWithConfidence; import com.sap.sailing.domain.base.Waypoint; @@ -42,6 +44,7 @@ import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.ranking.RankingMetric; import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; +import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; @@ -851,4 +854,7 @@ public interface TrackedRace extends Serializable { void setPolarDataService(PolarDataService polarDataService); + default RaceLogResolver getRaceLogResolver() { + return null; + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java index e998afc4a5e..9fa20136bed 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java @@ -2,6 +2,7 @@ package com.sap.sailing.domain.tracking; import java.io.Serializable; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.RaceDefinition; @@ -60,14 +61,14 @@ public interface TrackedRegatta extends Serializable { * Creates a {@link TrackedRace} based on the parameter specified and {@link #addTrackedRace(TrackedRace) adds} it * to this tracked regatta. Afterwards, calling {@link #getTrackedRace(RaceDefinition) getTrackedRace(raceDefinition)} * will return the result of this method call. - * * @param raceDefinitionSetToUpdate * if not null, after creating the {@link TrackedRace}, the raceDefinition is * {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that object. + * @param raceLogResolver TODO */ DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable sidelines, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, - DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm); + DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver); /** * Obtains the tracked race for race. Blocks until the tracked race has been created 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 e1463636149..a1d6796a12f 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 @@ -16,6 +16,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseBase; @@ -77,10 +78,10 @@ DynamicTrackedRace, GPSTrackListener { WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, long delayForCacheInvalidationOfWindEstimation, boolean useInternalMarkPassingAlgorithm, - RankingMetricConstructor rankingMetricConstructor) { + RankingMetricConstructor rankingMetricConstructor, RaceLogResolver raceLogResolver) { super(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, - delayForCacheInvalidationOfWindEstimation, useInternalMarkPassingAlgorithm, rankingMetricConstructor); + delayForCacheInvalidationOfWindEstimation, useInternalMarkPassingAlgorithm, rankingMetricConstructor, raceLogResolver); this.logListener = new DynamicTrackedRaceLogListener(this); if (markPassingCalculator != null) { logListener.setMarkPassingUpdateListener(markPassingCalculator.getListener()); @@ -134,10 +135,10 @@ DynamicTrackedRace, GPSTrackListener { public DynamicTrackedRaceImpl(TrackedRegatta trackedRegatta, RaceDefinition race, Iterable sidelines, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, - boolean useInternalMarkPassingAlgorithm, RankingMetricConstructor rankingMetricConstructor) { + boolean useInternalMarkPassingAlgorithm, RankingMetricConstructor rankingMetricConstructor, RaceLogResolver raceLogResolver) { this(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, - millisecondsOverWhichToAverageWind / 2, useInternalMarkPassingAlgorithm, rankingMetricConstructor); + millisecondsOverWhichToAverageWind / 2, useInternalMarkPassingAlgorithm, rankingMetricConstructor, raceLogResolver); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java index 7da497d2a61..e64d764f230 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRaceLogListener.java @@ -16,9 +16,9 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogWindFixEvent; import com.sap.sailing.domain.abstractlog.race.SuppressedMarkPassingsEvent; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.AbortingFlagFinder; -import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.LastPublishedCourseDesignFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.MarkPassingDataFinder; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.WindFixesFinder; import com.sap.sailing.domain.abstractlog.race.impl.BaseRaceLogEventVisitor; import com.sap.sailing.domain.base.Competitor; @@ -29,7 +29,6 @@ import com.sap.sailing.domain.common.WindSourceType; import com.sap.sailing.domain.common.impl.WindSourceImpl; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.markpassingcalculation.MarkPassingUpdateListener; -import com.sap.sailing.domain.racelog.analyzing.ServerSideRaceLogResolver; import com.sap.sailing.domain.tracking.DynamicTrackedRace; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util.Triple; @@ -69,8 +68,7 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor { trackedRace.invalidateStartTime(); trackedRace.invalidateEndTime(); courseDesignFinder = new LastPublishedCourseDesignFinder(raceLog); - //FIXME: how to get the HasRegattaLike? - startTimeFinder = new StartTimeFinder(new ServerSideRaceLogResolver(null), raceLog); + startTimeFinder = new StartTimeFinder(trackedRace.getRaceLogResolver(), raceLog); abortingFlagFinder = new AbortingFlagFinder(raceLog); initializeWindTrack(raceLog); analyze(); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRegattaImpl.java index 1bf8d0ac359..a299a2b764e 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRegattaImpl.java @@ -1,5 +1,6 @@ package com.sap.sailing.domain.tracking.impl; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Sideline; @@ -35,8 +36,8 @@ public class DynamicTrackedRegattaImpl extends TrackedRegattaImpl implements Dyn @Override public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable sidelines, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, - DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingCalculator) { + DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingCalculator, RaceLogResolver raceLogResolver) { return (DynamicTrackedRace) super.createTrackedRace(raceDefinition, sidelines, windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, - millisecondsOverWhichToAverageSpeed, raceDefinitionSetToUpdate, useMarkPassingCalculator); + millisecondsOverWhichToAverageSpeed, raceDefinitionSetToUpdate, useMarkPassingCalculator, raceLogResolver); } } 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 399d4a7625d..bb5ccfd6455 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 @@ -36,8 +36,11 @@ import java.util.logging.Logger; import com.sap.sailing.domain.abstractlog.AbstractLog; import com.sap.sailing.domain.abstractlog.AbstractLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.RaceLogDependentStartTimeEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogGateLineOpeningTimeEvent; +import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogGateLineOpeningTimeEventImpl; import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; @@ -103,7 +106,7 @@ import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuse import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; -import com.sap.sailing.domain.racelog.analyzing.ServerSideRaceLogResolver; +import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.racelogtracking.DeviceMapping; import com.sap.sailing.domain.ranking.OneDesignRankingMetric; @@ -315,7 +318,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl private transient CrossTrackErrorCache crossTrackErrorCache; - private final GPSFixStore gpsFixStore; + private transient GPSFixStore gpsFixStore; /** * Wind and loading is started in a background thread during object construction. If a client needs to @@ -347,6 +350,14 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl * certificate. */ private final RankingMetric rankingMetric; + + /** + * Required in particular to resolve {@link SimpleRaceLogIdentifier}s that appear in + * {@link RaceLogDependentStartTimeEvent}s. The usual implementation on the server side is + * provided by RacingEventService which is not serializable. Therefore, the reference + * must be established again after de-serialization by invoking {@link #setRaceLogResolver}. + */ + private transient RaceLogResolver raceLogResolver; /** * Constructs the tracked race with one-design ranking. @@ -355,15 +366,14 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl final Iterable sidelines, final WindStore windStore, final GPSFixStore gpsFixStore, long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, long delayForWindEstimationCacheInvalidation, - boolean useInternalMarkPassingAlgorithm) { + boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver) { this(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, - delayForWindEstimationCacheInvalidation, useInternalMarkPassingAlgorithm, OneDesignRankingMetric::new); + delayForWindEstimationCacheInvalidation, useInternalMarkPassingAlgorithm, OneDesignRankingMetric::new, raceLogResolver); } /** * Constructs the tracked race with a configurable ranking metric. - * * @param rankingMetricConstructor * the function that creates the ranking metric, passing this tracked race as argument. Callers may use a * constructor method reference if the {@link RankingMetric} implementation to instantiate takes a single @@ -373,8 +383,10 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl final Iterable sidelines, final WindStore windStore, final GPSFixStore gpsFixStore, long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, long delayForWindEstimationCacheInvalidation, - boolean useInternalMarkPassingAlgorithm, RankingMetricConstructor rankingMetricConstructor) { + boolean useInternalMarkPassingAlgorithm, RankingMetricConstructor rankingMetricConstructor, + RaceLogResolver raceLogResolver) { super(race, trackedRegatta, windStore, millisecondsOverWhichToAverageWind); + this.raceLogResolver = raceLogResolver; rankingMetric = rankingMetricConstructor.apply(this); raceStates = new WeakHashMap<>(); shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2); @@ -585,6 +597,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2); cacheInvalidationTimerLock = new Object(); windStore = EmptyWindStore.INSTANCE; + gpsFixStore = EmptyGPSFixStore.INSTANCE; competitorRankings = createCompetitorRankingsCache(); competitorRankingsLocks = createCompetitorRankingsLockMap(); directionFromStartToNextMarkCache = new HashMap>(); @@ -728,9 +741,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl public TimePoint getStartOfRace() { if (startTime == null) { for (RaceLog raceLog : attachedRaceLogs.values()) { - - //FIXME: how to get the HasRegattaLike? - startTime = new StartTimeFinder(new ServerSideRaceLogResolver(null), raceLog).analyze().getStartTime(); + startTime = new StartTimeFinder(raceLogResolver, raceLog).analyze().getStartTime(); if (startTime != null) { break; } @@ -3138,8 +3149,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl synchronized (raceStates) { result = raceStates.get(raceLog); if (result == null) { - //FIXME: how to get the corresponding RegattaLike? - result = RaceStateImpl.create(new ServerSideRaceLogResolver(null), raceLog); + result = RaceStateImpl.create(raceLogResolver, raceLog); raceStates.put(raceLog, result); } } @@ -3671,4 +3681,16 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl public void setPolarDataService(PolarDataService polarDataService) { this.polarDataService = polarDataService; } + + /** + * Obtains the {@link #raceLogResolver}. + */ + @Override + public RaceLogResolver getRaceLogResolver() { + return raceLogResolver; + } + + public void setRaceLogResolver(RaceLogResolver raceLogResolver) { + this.raceLogResolver = raceLogResolver; + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java index 442ca68ede2..361c2cbfa71 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java @@ -14,6 +14,7 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.RaceDefinition; @@ -244,12 +245,12 @@ public class TrackedRegattaImpl implements TrackedRegatta { public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable sidelines, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, - DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm) { + DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver) { logger.log(Level.INFO, "Creating DynamicTrackedRaceImpl for RaceDefinition " + raceDefinition.getName()); DynamicTrackedRaceImpl result = new DynamicTrackedRaceImpl(this, raceDefinition, sidelines, windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, - /* useMarkPassingCalculator */useInternalMarkPassingAlgorithm, getRegatta().getRankingMetricConstructor()); + /* useMarkPassingCalculator */useInternalMarkPassingAlgorithm, getRegatta().getRankingMetricConstructor(), raceLogResolver); // adding the raceDefinition to the raceDefinitionSetToUpdate BEFORE calling addTrackedRace helps those who // are called back by RaceListener.raceAdded(TrackedRace) and who then expect the update to have happened if (raceDefinitionSetToUpdate != null) { diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java index 9eca28dba48..6656cb1e4d7 100755 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java @@ -9,6 +9,7 @@ import java.util.NavigableSet; import java.util.Set; import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; @@ -313,7 +314,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable sidelines, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, - boolean useMarkPassingCalculator) { + boolean useMarkPassingCalculator, RaceLogResolver raceLogResolver) { return null; } diff --git a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch index a00d6c0ff91..12995338ba2 100755 --- a/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch +++ b/java/com.sap.sailing.gwt.ui/SailingGWT sdm.launch @@ -1,79 +1,77 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss index 308dd6624eb..b919c914c20 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBox.gss @@ -104,6 +104,9 @@ overflow: hidden; text-overflow: ellipsis; } +.updatesbox_item_live { + color: red; +} .updatesbox_item_content_text_boatclass { display: none; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java index 2c98746caa6..32120fdc6fe 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java @@ -8,8 +8,6 @@ import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Node; import com.google.gwt.dom.client.SpanElement; -import com.google.gwt.i18n.client.DateTimeFormat; -import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.Event; @@ -19,9 +17,11 @@ import com.sap.sailing.gwt.common.client.BoatClassImageResolver; import com.sap.sailing.gwt.common.client.LinkUtil; import com.sap.sailing.gwt.home.client.place.event.EventView; import com.sap.sailing.gwt.home.shared.app.PlaceNavigation; +import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.shared.dispatch.news.AbstractRaceNewsEntryDTO; import com.sap.sailing.gwt.ui.shared.dispatch.news.LeaderboardNewsEntryDTO; import com.sap.sailing.gwt.ui.shared.dispatch.news.NewsEntryDTO; +import com.sap.sailing.gwt.ui.shared.util.ConditionalDateTimeFormatter; public class UpdatesBoxItem extends Widget { private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @@ -37,6 +37,7 @@ public class UpdatesBoxItem extends Widget { @UiField DivElement timestampUi; public UpdatesBoxItem(NewsEntryDTO entry, EventView.Presenter presenter) { + UpdatesBoxResources.INSTANCE.css().ensureInjected(); setElement(uiBinder.createAndBindUi(this)); titleUi.setInnerText(entry.getTitle()); @@ -53,11 +54,15 @@ public class UpdatesBoxItem extends Widget { } - Date timestamp = entry.getTimestamp(); - if(timestamp == null) { + Date newsTimestamp = entry.getTimestamp(); + Date currentTimestamp = entry.getCurrentTimestamp(); + if(newsTimestamp == null || currentTimestamp == null) { timestampUi.removeFromParent(); } else { - timestampUi.setInnerText(DateTimeFormat.getFormat(PredefinedFormat.DATE_TIME_MEDIUM).format(timestamp)); + timestampUi.setInnerText(ConditionalDateTimeFormatter.format(newsTimestamp, currentTimestamp, StringMessages.INSTANCE)); + if (currentTimestamp.getTime() - 600000 < newsTimestamp.getTime()) { + timestampUi.addClassName(UpdatesBoxResources.INSTANCE.css().updatesbox_item_live()); + } } String directLink = entry.getExternalURL(); @@ -99,5 +104,4 @@ public class UpdatesBoxItem extends Widget { } } } - } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxResources.java index f0cf86a841c..f436e4ce213 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxResources.java @@ -17,6 +17,7 @@ public interface UpdatesBoxResources extends ClientBundle { String box_content_item(); String updatesbox(); String updatesbox_item(); + String updatesbox_item_live(); String updatesbox_itemlink(); String updatesbox_item_icon(); String updatesbox_item_content(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index 9760e171076..e089c73e226 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -114,7 +114,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component private TextColumn startTimeColumn; private SimplePanel tableHolder = new SimplePanel(); private final long _1_HOUR = 60 /* seconds */* 60 /* minutes */* 60 /* hour */; - private final long HIDE_COL_TIME_THRESHOLD = _1_HOUR * 12; + private final long HIDE_COL_TIME_THRESHOLD = _1_HOUR; private TextColumn lastUpdateColumn; private TextColumn endOfProtestTime; private TextColumn raceAdditionalInformationColumn; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 3a534a2146e..63a2c551de1 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1331,4 +1331,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c String pointsValue(double value); String openLeaderboard(); String resultsStandings(); + String now(); + String minutesAgo(String minutes); + String hoursAgo(String hours); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 9431d9868c4..d61f3aa6a9b 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1199,8 +1199,8 @@ group=Group valueAscending=Value (Ascending) valueDescending=Value (Descending) sortBy=Sort by -dashboardWindBotLoadingText=Loading wind bot data ... -dashboardWindBotLoadingMessage=Depending on your connection this operation might take some minutes to complete the first time. +dashboardWindBotLoadingText=Waiting for wind bot data... +dashboardWindBotLoadingMessage=Depending on your connection this operation might take some minutes to complete the first time. It can also take some time if there is no data available right now. dashboardWindBotNotAvailable=Wind bot not available. dashboardWindBot=Wind Bot dashboardTrueWindSpeed=TWS @@ -1299,4 +1299,7 @@ billionValue={0,number,#0.0} bil noResults=There are no results available yet. pointsValue={0,number,#0.00} openLeaderboard=Open Leaderboard -resultsStandings=Results/Standings \ No newline at end of file +resultsStandings=Results/Standings +now=Now +minutesAgo={0} min ago +hoursAgo={0} h ago \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 6c170ed77cc..48b0bfcc212 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1289,4 +1289,7 @@ billionValue={0,number,#0.0} Mrd noResults=Leider gibt es noch keine Ergebnisse. pointsValue={0,number,#0.00} openLeaderboard=Rangliste öffnen -resultsStandings=Ergbnisse/Platzierungen \ No newline at end of file +resultsStandings=Ergbnisse/Platzierungen +now=Jetzt +minutesAgo=vor {0} min +hoursAgo=vor {0} h \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index e3c01c8c0d5..c04802af79a 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -1236,4 +1236,7 @@ billionValue={0,number,#0.0} млрд noResults=There are no results available yet. pointsValue={0,number,#0.00} openLeaderboard=Open Leaderboard -resultsStandings=Results/Standings \ No newline at end of file +resultsStandings=Results/Standings +now=в настоящее время +minutesAgo={0} минут назад +hoursAgo={0} h часов назад \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 868b91e529e..8ebab6c5c0d 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -232,7 +232,6 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.racelog.RaceLogStore; import com.sap.sailing.domain.racelog.RaceStateOfSameDayHelper; -import com.sap.sailing.domain.racelog.analyzing.ServerSideRaceLogResolver; import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; import com.sap.sailing.domain.racelogtracking.DeviceIdentifierStringSerializationHandler; import com.sap.sailing.domain.racelogtracking.DeviceMapping; @@ -544,7 +543,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S // TODO what about passing on the mongo/domain object factory to obtain an according SwissTimingAdapterPersistence instance similar to how the tractracDomainObjectFactory etc. are created below? swissTimingAdapterPersistence = SwissTimingAdapterPersistence.INSTANCE; swissTimingReplayService = ServiceTrackerFactory.createAndOpen(context, SwissTimingReplayServiceFactory.class) - .getService().createSwissTimingReplayService(getSwissTimingAdapter().getSwissTimingDomainFactory()); + .getService().createSwissTimingReplayService(getSwissTimingAdapter().getSwissTimingDomainFactory(), + /* raceLogResolver */ getService()); scoreCorrectionProviderServiceTracker = ServiceTrackerFactory.createAndOpen(context, ScoreCorrectionProvider.class); tractracDomainObjectFactory = com.sap.sailing.domain.tractracadapter.persistence.PersistenceFactory.INSTANCE @@ -844,18 +844,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S return raceColumnDTOs; } - private RaceInfoDTO createRaceInfoDTO(Leaderboard leaderboard, String seriesName, RaceColumn raceColumn, Fleet fleet) { + private RaceInfoDTO createRaceInfoDTO(String seriesName, RaceColumn raceColumn, Fleet fleet) { RaceInfoDTO raceInfoDTO = new RaceInfoDTO(); RaceLog raceLog = raceColumn.getRaceLog(fleet); if (raceLog != null) { raceInfoDTO.isTracked = raceColumn.getTrackedRace(fleet) != null ? true : false; - final HasRegattaLike regattaLike; - if (leaderboard instanceof HasRegattaLike) { - regattaLike = (HasRegattaLike) leaderboard; - } else { - regattaLike = null; - } - ReadonlyRaceState state = ReadonlyRaceStateImpl.create(new ServerSideRaceLogResolver(regattaLike), raceLog); + ReadonlyRaceState state = ReadonlyRaceStateImpl.create(getService(), raceLog); TimePoint startTime = state.getStartTime(); if (startTime != null) { raceInfoDTO.startTime = startTime.asDate(); @@ -4242,7 +4236,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S entry.boatClassName = boatClassName; entry.regattaDisplayName = regattaName; entry.regattaName = leaderboard.getName(); - entry.raceInfo = createRaceInfoDTO(leaderboard, seriesName, raceColumn, fleet); + entry.raceInfo = createRaceInfoDTO(seriesName, raceColumn, fleet); entry.currentServerTime = new Date(); if (showOnlyRacesOfSameDay) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewNewsAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewNewsAction.java index cdd4edeed26..9b852bf8e36 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewNewsAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/GetEventOverviewNewsAction.java @@ -1,6 +1,7 @@ package com.sap.sailing.gwt.ui.shared.dispatch.event; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.UUID; @@ -50,12 +51,13 @@ public class GetEventOverviewNewsAction implements Action news = new ArrayList<>(newsItems.size()); + Date currentTimestamp = new Date(); for(EventNewsItem newsItem: newsItems) { if(newsItem instanceof InfoEventNewsItem) { - news.add(new InfoNewsEntryDTO((InfoEventNewsItem) newsItem, dispatchContext.getClientLocale())); + news.add(new InfoNewsEntryDTO((InfoEventNewsItem) newsItem, dispatchContext.getClientLocale(), currentTimestamp)); } if(newsItem instanceof LeaderboardUpdateNewsItem) { - news.add(new LeaderboardNewsEntryDTO((LeaderboardUpdateNewsItem) newsItem)); + news.add(new LeaderboardNewsEntryDTO((LeaderboardUpdateNewsItem) newsItem, currentTimestamp)); } } return news; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java index 41c3e35069d..859b4d58abb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java @@ -6,6 +6,7 @@ import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.AbortingFlagFinder; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.WindFixesFinder; import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl; @@ -29,10 +30,7 @@ import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; -import com.sap.sailing.domain.racelog.analyzing.ServerSideRaceLogResolver; -import com.sap.sailing.domain.regattalike.HasRegattaLike; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.WindTrack; import com.sap.sailing.domain.tracking.WindWithConfidence; @@ -59,18 +57,16 @@ public class RaceContext { private final ReadonlyRaceState state; private final Event event; private final long TIME_TO_SHOW_CANCELED_RACES_AS_LIVE = 5 * 60 * 1000; // 5 min - private final LeaderboardGroup leaderboardGroup; - public RaceContext(Event event, LeaderboardGroup leaderboardGroup, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) { + public RaceContext(Event event, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, RaceLogResolver raceLogResolver) { this.event = event; - this.leaderboardGroup = leaderboardGroup; this.leaderboard = leaderboard; this.raceColumn = raceColumn; this.raceDefinition = raceColumn.getRaceDefinition(fleet); this.fleet = fleet; trackedRace = raceColumn.getTrackedRace(fleet); raceLog = raceColumn.getRaceLog(fleet); - state = ReadonlyRaceStateImpl.create(new ServerSideRaceLogResolver((HasRegattaLike) leaderboard), raceLog); + state = ReadonlyRaceStateImpl.create(raceLogResolver, raceLog); } private boolean isShowFleetData() { @@ -339,8 +335,7 @@ public class RaceContext { } else if (finishTime != null && now.after(finishTime)) { raceState = RaceViewState.FINISHED; } else if(raceLog != null) { - AbortingFlagFinder abortingFlagFinder = new AbortingFlagFinder(raceLog); - RaceLogFlagEvent abortingFlagEvent = abortingFlagFinder.analyze(); + RaceLogFlagEvent abortingFlagEvent = checkForAbortFlagEvent(); if (abortingFlagEvent != null) { Flags upperFlag = abortingFlagEvent.getUpperFlag(); if(upperFlag.equals(Flags.AP)) { @@ -387,12 +382,4 @@ public class RaceContext { public RegattaAndRaceIdentifier getRaceIdentifier() { return trackedRace.getRaceIdentifier(); } - - public Leaderboard getLeaderboard() { - return leaderboard; - } - - public LeaderboardGroup getLeaderboardGroup() { - return leaderboardGroup; - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RacesActionUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RacesActionUtil.java index 3ae6565e481..e38c9c3b708 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RacesActionUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RacesActionUtil.java @@ -25,7 +25,7 @@ public final class RacesActionUtil { for (Leaderboard lb : lg.getLeaderboards()) { for(RaceColumn raceColumn : lb.getRaceColumns()) { for(Fleet fleet : raceColumn.getFleets()) { - callback.doForRace(new RaceContext(event, lg, lb, raceColumn, fleet)); + callback.doForRace(new RaceContext(event, lb, raceColumn, fleet, context.getRacingEventService())); } } } @@ -38,8 +38,7 @@ public final class RacesActionUtil { Leaderboard lb = context.getRacingEventService().getLeaderboardByName(regattaName); for(RaceColumn raceColumn : lb.getRaceColumns()) { for(Fleet fleet : raceColumn.getFleets()) { - // TODO LeaderboardGroup - callback.doForRace(new RaceContext(event, null, lb, raceColumn, fleet)); + callback.doForRace(new RaceContext(event, lb, raceColumn, fleet, context.getRacingEventService())); } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java index 0c82cecc687..9128acbefa8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/AbstractRaceNewsEntryDTO.java @@ -14,8 +14,8 @@ public abstract class AbstractRaceNewsEntryDTO extends NewsEntryDTO { } @GwtIncompatible - public AbstractRaceNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp) { - super(raceTitle, timestamp, null); + public AbstractRaceNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp, Date currentTimestamp) { + super(raceTitle, timestamp, currentTimestamp, null); this.regattaName = regattaName; this.trackedRaceName = trackedRaceName; this.boatClass = boatClass; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java index b11c8085268..67ff7e73676 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/InfoNewsEntryDTO.java @@ -1,5 +1,6 @@ package com.sap.sailing.gwt.ui.shared.dispatch.news; +import java.util.Date; import java.util.Locale; import com.google.gwt.core.shared.GwtIncompatible; @@ -14,8 +15,8 @@ public class InfoNewsEntryDTO extends NewsEntryDTO { } @GwtIncompatible - public InfoNewsEntryDTO(InfoEventNewsItem item, Locale locale) { - super(item.getTitle(locale), item.getCreatedAtDate(), item.getRelatedItemLink()); + public InfoNewsEntryDTO(InfoEventNewsItem item, Locale locale, Date currentTimestamp) { + super(item.getTitle(locale), item.getCreatedAtDate(), currentTimestamp, item.getRelatedItemLink()); this.subtitle = item.getMessage(locale); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java index 03ed23fafc1..462978d95ba 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/LeaderboardNewsEntryDTO.java @@ -1,5 +1,7 @@ package com.sap.sailing.gwt.ui.shared.dispatch.news; +import java.util.Date; + import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.news.impl.LeaderboardUpdateNewsItem; @@ -19,8 +21,8 @@ public class LeaderboardNewsEntryDTO extends NewsEntryDTO { } @GwtIncompatible - public LeaderboardNewsEntryDTO(LeaderboardUpdateNewsItem item) { - super(item.getTitle(), item.getCreatedAtDate(), null); + public LeaderboardNewsEntryDTO(LeaderboardUpdateNewsItem item, Date currentTimestamp) { + super(item.getTitle(), item.getCreatedAtDate(), currentTimestamp, null); this.boatClassName = item.getBoatClass(); this.type = Type.RESULTS_UPDATE; this.leaderboardName = item.getLeaderboardName(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java index 314c07eb4fb..dfcec32b85d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/NewsEntryDTO.java @@ -8,7 +8,9 @@ import com.sap.sailing.gwt.ui.shared.dispatch.DTO; public abstract class NewsEntryDTO implements DTO { - private Date timestamp; + private Date newsTimestamp; + + private Date currentTimestamp; private String title; @@ -18,14 +20,15 @@ public abstract class NewsEntryDTO implements DTO { } @GwtIncompatible - public NewsEntryDTO(String title, Date timestamp, URL externalURL) { - this(title, timestamp, externalURL == null ? null : externalURL.toString()); + public NewsEntryDTO(String title, Date timestamp, Date currentTimestamp, URL externalURL) { + this(title, timestamp, currentTimestamp, externalURL == null ? null : externalURL.toString()); } @GwtIncompatible - private NewsEntryDTO(String title, Date timestamp, String externalURL) { + private NewsEntryDTO(String title, Date newsTimestamp, Date currentTimestamp, String externalURL) { this.title = title; - this.timestamp = timestamp; + this.newsTimestamp = newsTimestamp; + this.currentTimestamp = currentTimestamp; this.externalURL = externalURL; } @@ -38,10 +41,14 @@ public abstract class NewsEntryDTO implements DTO { public abstract String getBoatClass(); public Date getTimestamp() { - return timestamp; + return newsTimestamp; } public String getExternalURL() { return externalURL; } + + public Date getCurrentTimestamp() { + return currentTimestamp; + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java index 77d26641128..027233b6ae0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/news/RaceCompetitorNewsEntryDTO.java @@ -17,8 +17,8 @@ public class RaceCompetitorNewsEntryDTO extends AbstractRaceNewsEntryDTO { private RaceCompetitorNewsEntryDTO() { } - public RaceCompetitorNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp, String competitorName, Type type) { - super(regattaName, trackedRaceName, raceTitle, boatClass, timestamp); + public RaceCompetitorNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp, String competitorName, Type type, Date currentTimestamp) { + super(regattaName, trackedRaceName, raceTitle, boatClass, timestamp, currentTimestamp); this.competitorName = competitorName; this.type = type; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/util/ConditionalDateTimeFormatter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/util/ConditionalDateTimeFormatter.java new file mode 100644 index 00000000000..6f81f371dd8 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/util/ConditionalDateTimeFormatter.java @@ -0,0 +1,37 @@ +package com.sap.sailing.gwt.ui.shared.util; + +import java.util.Date; + +import com.google.gwt.i18n.shared.DateTimeFormat; +import com.google.gwt.i18n.shared.DateTimeFormat.PredefinedFormat; +import com.google.gwt.user.datepicker.client.CalendarUtil; +import com.sap.sailing.gwt.ui.client.StringMessages; + +public class ConditionalDateTimeFormatter { + public static String format(Date newsTimestamp, Date currentTimestamp, StringMessages stringMessages) { + String result; + if (newsTimestamp.after(new Date(currentTimestamp.getTime() - 60000))) { + result = stringMessages.now(); + } else { + Date oneHourBeforeCurrent = new Date(currentTimestamp.getTime() - 3600000); + if (newsTimestamp.after(oneHourBeforeCurrent)) { + DateTimeFormat format = DateTimeFormat.getFormat("m"); + Date diffTime = new Date(currentTimestamp.getTime() - newsTimestamp.getTime()); + result = stringMessages.minutesAgo(format.format(diffTime)); + } else { + if (sameDay(newsTimestamp, currentTimestamp)) { + DateTimeFormat format = DateTimeFormat.getFormat("hh:mm"); + Date diffTime = new Date(currentTimestamp.getTime() - newsTimestamp.getTime()); + result = stringMessages.hoursAgo(format.format(diffTime)); + } else { + result = DateTimeFormat.getFormat(PredefinedFormat.DATE_TIME_SHORT).format(newsTimestamp); + } + } + } + return result; + } + + private static boolean sameDay(Date timestamp1, Date timestamp2) { + return CalendarUtil.isSameDate(timestamp1, timestamp2); + } +} diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingWindTracksTest.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingWindTracksTest.java index 3485a2bedd1..770acae35f6 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingWindTracksTest.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingWindTracksTest.java @@ -3,6 +3,7 @@ package com.sap.sailing.mongodb.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import java.net.MalformedURLException; import java.net.URISyntaxException; @@ -16,6 +17,7 @@ import com.mongodb.DB; import com.mongodb.Mongo; import com.mongodb.MongoClient; import com.mongodb.MongoException; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Sideline; @@ -87,7 +89,8 @@ public class TestStoringAndRetrievingWindTracksTest extends AbstractTracTracLive @Override public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) { } - }, /* trackedRegattaRegistry */ null, /*courseDesignUpdateURI*/ null, /*tracTracUsername*/ null, /*tracTracPassword*/ null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, ReceiverType.RACECOURSE); + }, /* trackedRegattaRegistry */ null, mock(RaceLogResolver.class), + /*courseDesignUpdateURI*/ null, /*tracTracUsername*/ null, /*tracTracPassword*/ null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, ReceiverType.RACECOURSE); addListenersForStoredDataAndStartController(typeControllers); RaceDefinition race = domainFactory.getAndWaitForRaceDefinition(getTracTracEvent().getRaces().iterator().next().getId()); DynamicTrackedRace trackedRace = trackedRegatta.createTrackedRace(race, Collections. emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, @@ -95,7 +98,7 @@ public class TestStoringAndRetrievingWindTracksTest extends AbstractTracTracLive @Override public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) { } - }, /*useMarkPassingCalculator*/ false); + }, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class)); WindSource windSource = new WindSourceImpl(WindSourceType.WEB); Mongo myFirstMongo = newMongo(); DB firstDatabase = myFirstMongo.getDB(dbConfiguration.getDatabaseName()); diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFixedMarkPassingEventDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFixedMarkPassingEventDeserializer.java index 246b13ebe93..7c622a08551 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFixedMarkPassingEventDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/RaceLogFixedMarkPassingEventDeserializer.java @@ -25,8 +25,9 @@ public class RaceLogFixedMarkPassingEventDeserializer extends BaseRaceLogEventDe TimePoint timePoint, int passId, List competitors) throws JsonDeserializationException { TimePoint ofPassing = new MillisecondsTimePoint( (Long) object.get(RaceLogFixedMarkPassingEventSerializer.FIELD_TIMEPOINT_OF_MARKPASSING)); - Integer zeroBasedIndexOfPassedWaypoint = (Integer) object + Number zeroBasedIndexOfPassedWaypointObj = (Number) object .get(RaceLogFixedMarkPassingEventSerializer.FIELD_INDEX_OF_PASSED_WAYPOINT); + Integer zeroBasedIndexOfPassedWaypoint = zeroBasedIndexOfPassedWaypointObj != null ? zeroBasedIndexOfPassedWaypointObj.intValue() : null; return factory.createFixedMarkPassingEvent(timePoint, author, id, competitors, passId, ofPassing, zeroBasedIndexOfPassedWaypoint); } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/EventRaceStatesJsonGetServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/EventRaceStatesJsonGetServlet.java index 1897a5ec74a..43ee3eb47f1 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/EventRaceStatesJsonGetServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/EventRaceStatesJsonGetServlet.java @@ -42,7 +42,7 @@ public class EventRaceStatesJsonGetServlet extends AbstractJsonHttpServlet { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Event "+eventIdParam+" not found"); } else { EventRaceStatesSerializer eventRaceStatesSerializer = new EventRaceStatesSerializer(filterByCourseAreaParam, - filterByLeaderboardParam, filterByDayOffsetParam); + filterByLeaderboardParam, filterByDayOffsetParam, getService()); JSONObject result = eventRaceStatesSerializer.serialize(new Pair>(event, getService().getLeaderboards().values())); setJsonResponseHeader(response); result.writeJSONString(response.getWriter()); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventRaceStatesSerializer.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventRaceStatesSerializer.java index aabe500d131..101f820c6db 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventRaceStatesSerializer.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventRaceStatesSerializer.java @@ -6,6 +6,7 @@ import java.util.Date; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; @@ -19,31 +20,30 @@ public class EventRaceStatesSerializer implements JsonSerializer>(event, getService().getLeaderboards().values())); String json = raceStatesJson.toJSONString(); response = Response.ok(json, MediaType.APPLICATION_JSON).build(); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RaceStateSerializer.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RaceStateSerializer.java index 12154bf76ae..b48aae155d1 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RaceStateSerializer.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RaceStateSerializer.java @@ -7,9 +7,10 @@ import org.json.simple.JSONObject; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.AbortingFlagFinder; -import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.FinishedTimeFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.LastFlagsFinder; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder; import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.gate.ReadonlyGateStartRacingProcedure; @@ -17,23 +18,16 @@ import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.common.RaceIdentifier; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; -import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.racelog.RaceStateOfSameDayHelper; -import com.sap.sailing.domain.racelog.analyzing.ServerSideRaceLogResolver; -import com.sap.sailing.domain.regattalike.HasRegattaLike; import com.sap.sailing.server.gateway.serialization.JsonSerializer; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util.Pair; public class RaceStateSerializer implements JsonSerializer> { - private final HasRegattaLike regattaLike; + private final RaceLogResolver raceLogResolver; - public RaceStateSerializer(Leaderboard leaderboard) { - if (leaderboard instanceof HasRegattaLike) { - regattaLike = (HasRegattaLike) leaderboard; - } else { - regattaLike = null; - } + public RaceStateSerializer(RaceLogResolver raceLogResolver) { + this.raceLogResolver = raceLogResolver; } @Override @@ -49,7 +43,7 @@ public class RaceStateSerializer implements JsonSerializer, ReplicationMasterDescriptor> replicationDescriptors = super.basicSetUp( + /* dropDB */true, /* master=null means create a new one */null, + /* replica=null means create a new one */null); + final String boatClassName = "49er"; + // FIXME use master DomainFactory; see bug 592 + final DomainFactory masterDomainFactory = DomainFactory.INSTANCE; + BoatClass boatClass = masterDomainFactory.getOrCreateBoatClass(boatClassName, /* typicallyStartsUpwind */true); + competitor = masterDomainFactory.getCompetitorStore().getOrCreateCompetitor("GER 61", "Tina Lutz", Color.RED, "someone@nowhere.de", null, new TeamImpl("Tina Lutz + Susann Beucke", + (List) Arrays.asList(new PersonImpl[] { new PersonImpl("Tina Lutz", DomainFactory.INSTANCE.getOrCreateNationality("GER"), null, null), + new PersonImpl("Tina Lutz", DomainFactory.INSTANCE.getOrCreateNationality("GER"), null, null) }), + new PersonImpl("Rigo de Mas", DomainFactory.INSTANCE.getOrCreateNationality("NED"), null, null)), + new BoatImpl("GER 61", DomainFactory.INSTANCE.getOrCreateBoatClass("470", /* typicallyStartsUpwind */ true), "GER 61"), + /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null); + final String baseEventName = "Test Event"; + AddDefaultRegatta addEventOperation = new AddDefaultRegatta(RegattaImpl.getDefaultName(baseEventName, boatClassName), boatClassName, + /*startDate*/ null, /*endDate*/ null, UUID.randomUUID()); + Regatta regatta = master.apply(addEventOperation); + final String raceName = "Test Race"; + final CourseImpl masterCourse = new CourseImpl("Test Course", new ArrayList()); + RaceDefinition race = new RaceDefinitionImpl(raceName, masterCourse, boatClass, Collections.singletonList(competitor)); + AddRaceDefinition addRaceOperation = new AddRaceDefinition(new RegattaName(regatta.getName()), race); + master.apply(addRaceOperation); + masterCourse.addWaypoint(0, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateMark("Mark1"), /*passingInstruction*/ null)); + masterCourse.addWaypoint(1, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateMark("Mark2"), /*passingInstruction*/ null)); + masterCourse.addWaypoint(2, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateMark("Mark3"), /*passingInstruction*/ null)); + masterCourse.removeWaypoint(1); + raceIdentifier = new RegattaNameAndRaceName(regatta.getName(), raceName); + trackedRegatta = master.apply(new TrackRegatta(raceIdentifier)); + trackedRace = (DynamicTrackedRace) master.apply(new CreateTrackedRace(raceIdentifier, + MongoWindStoreFactory.INSTANCE.getMongoWindStore(PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(), + PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory()), gpsFixStore, /* delayToLiveInMillis */ 5000, + /* millisecondsOverWhichToAverageWind */ 10000, /* millisecondsOverWhichToAverageSpeed */10000)); + trackedRace.waitUntilLoadingFromWindStoreComplete(); + // set up the tracked race on the master with a non-empty GPS fix store before starting replication; this shall + // test serialization with a non-empty GPS fix store set on the tracked race. See also bug 2986. + replicationDescriptors.getA().startToReplicateFrom(replicationDescriptors.getB()); + } + + protected Competitor getCompetitor() { + return competitor; + } + + protected DynamicTrackedRace getTrackedRace() { + return trackedRace; + } + + protected RegattaNameAndRaceName getRaceIdentifier() { + return raceIdentifier; + } + + protected DynamicTrackedRegatta getTrackedRegatta() { + return trackedRegatta; + } + + @Test + public void testGPSFixReplication() throws InterruptedException { + final GPSFixMovingImpl fix = new GPSFixMovingImpl(new DegreePosition(1, 2), new MillisecondsTimePoint(12345), + new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123))); + trackedRace.recordFix(competitor, fix); + Thread.sleep(1000); + TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier); + Competitor replicaCompetitor = replicaTrackedRace.getRace().getCompetitors().iterator().next(); + assertNotNull(replicaCompetitor); + GPSFixTrack competitorTrack = replicaTrackedRace.getTrack(replicaCompetitor); + competitorTrack.lockForRead(); + try { + assertEquals(1, Util.size(competitorTrack.getRawFixes())); + assertEquals(fix, competitorTrack.getRawFixes().iterator().next()); + assertNotSame(fix, competitorTrack.getRawFixes().iterator().next()); + } finally { + competitorTrack.unlockAfterRead(); + } + } + + +} diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java index b74ea269f82..46b54829df6 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java @@ -6,6 +6,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import java.io.IOException; import java.net.MalformedURLException; @@ -20,6 +21,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.junit.Before; import org.junit.Test; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.DomainFactory; @@ -78,13 +80,13 @@ public class RaceTrackerStartStopTest { raceDef3 = new RaceDefinitionImpl(RACENAME3, new CourseImpl("Course3", new ArrayList()), boatClass, new ArrayList()); regatta.addRace(raceDef1); trackedRegatta1.createTrackedRace(raceDef1, Collections. emptyList(), /* windStore */ EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l, - /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false); + /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class)); regatta.addRace(raceDef2); trackedRegatta1.createTrackedRace(raceDef2, Collections. emptyList(), /* windStore */ EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l, - /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false); + /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class)); regatta.addRace(raceDef3); trackedRegatta1.createTrackedRace(raceDef3, Collections. emptyList(), /* windStore */ EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l, - /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false); + /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class)); Set raceDefinitionSetRace1 = new HashSet(); raceDefinitionSetRace1.add(raceDef1); Set raceDefinitionSetRace2 = new HashSet(); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java index ccfc26062cd..635dd8e93f2 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java @@ -16,6 +16,7 @@ import java.util.concurrent.ConcurrentHashMap; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent; +import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CompetitorStore; import com.sap.sailing.domain.base.CourseArea; @@ -110,7 +111,7 @@ import com.sap.sse.replication.impl.ReplicableWithObjectInputStream; */ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetcher, RegattaRegistry, RaceFetcher, LeaderboardRegistry, EventResolver, LeaderboardGroupResolver, TrackerManager, Searchable, - ReplicableWithObjectInputStream> { + ReplicableWithObjectInputStream>, RaceLogResolver { @Override Regatta getRegatta(RegattaName regattaName); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 8564f2e93f1..6f8ea7c8fda 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -51,6 +51,7 @@ import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl; import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor; +import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier; 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; @@ -130,7 +131,6 @@ import com.sap.sailing.domain.persistence.racelog.tracking.MongoGPSFixStoreFacto import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.racelog.RaceLogIdentifier; import com.sap.sailing.domain.racelog.RaceLogStore; -import com.sap.sailing.domain.racelog.analyzing.ServerSideRaceLogResolver; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.racelogtracking.DeviceIdentifier; import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; @@ -157,6 +157,7 @@ import com.sap.sailing.domain.tracking.WindTrackerFactory; import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener; import com.sap.sailing.domain.tracking.impl.DynamicGPSFixTrackImpl; import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; +import com.sap.sailing.domain.tracking.impl.TrackedRaceImpl; import com.sap.sailing.expeditionconnector.ExpeditionWindTrackerFactory; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.Replicator; @@ -210,6 +211,7 @@ import com.sap.sse.common.TimePoint; import com.sap.sse.common.TypeBasedServiceFinderFactory; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; +import com.sap.sse.common.Util.Triple; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.media.ImageDescriptor; import com.sap.sse.common.media.VideoDescriptor; @@ -1334,10 +1336,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes Regatta regatta = regattaToAddTo == null ? null : getRegatta(regattaToAddTo); if (regatta == null) { // create tracker and use an existing or create a default regatta - tracker = params.createRaceTracker(this, windStore, gpsFixStore); + tracker = params.createRaceTracker(this, windStore, gpsFixStore, /* raceLogResolver */ this); } else { // use the regatta selected by the RaceIdentifier regattaToAddTo - tracker = params.createRaceTracker(regatta, this, windStore, gpsFixStore); + tracker = params.createRaceTracker(regatta, this, windStore, gpsFixStore, /* raceLogResolver */ this); assert tracker.getRegatta() == regatta; } LockUtil.lockForWrite(raceTrackersByRegattaLock); @@ -1480,7 +1482,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes RaceDefinition race = getRace(raceIdentifier); return trackedRegatta.createTrackedRace(race, Collections. emptyList(), windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, - /* raceDefinitionSetToUpdate */null, useMarkPassingCalculator); + /* raceDefinitionSetToUpdate */null, useMarkPassingCalculator, /* raceLogResolver */ this); } private void ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking( @@ -2529,6 +2531,17 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes regattaImpl.initializeSeriesAfterDeserialize(); regattaImpl.addRaceColumnListener(raceLogReplicator); } + // re-establish RaceLogResolver references to this RacingEventService in all TrackedRace instances + for (DynamicTrackedRegatta trackedRegatta : regattaTrackingCache.values()) { + trackedRegatta.lockTrackedRacesForRead(); + try { + for (TrackedRace trackedRace : trackedRegatta.getTrackedRaces()) { + ((TrackedRaceImpl) trackedRace).setRaceLogResolver(this); + } + } finally { + trackedRegatta.unlockTrackedRacesAfterRead(); + } + } logger.info(logoutput.toString()); } @@ -2917,8 +2930,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes Leaderboard leaderboard = getLeaderboardByName(leaderboardName); final TimePoint result; if (leaderboard instanceof HasRegattaLike && raceLog != null) { - RaceState state = RaceStateImpl.create(new ServerSideRaceLogResolver((HasRegattaLike) leaderboard), raceLog, - new LogEventAuthorImpl(authorName, authorPriority)); + RaceState state = RaceStateImpl.create(/* race log resolver */ this, raceLog, new LogEventAuthorImpl(authorName, authorPriority)); if (passId > raceLog.getCurrentPassId()) { state.setAdvancePass(logicalTimePoint); } @@ -2947,22 +2959,16 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes public com.sap.sse.common.Util.Triple getStartTimeAndProcedure( String leaderboardName, String raceColumnName, String fleetName) { RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); - Leaderboard leaderboard = getLeaderboardByName(leaderboardName); - - if (!(leaderboard instanceof HasRegattaLike)){ - return null; - } - - if (raceLog == null) { - return null; - } - - ReadonlyRaceState state = ReadonlyRaceStateImpl.create(new ServerSideRaceLogResolver( - (HasRegattaLike) leaderboard), raceLog); - return new com.sap.sse.common.Util.Triple(state.getStartTime(), + final Triple result; + if (leaderboard instanceof HasRegattaLike && raceLog != null) { + ReadonlyRaceState state = ReadonlyRaceStateImpl.create(/* race log resolver */ this, raceLog); + result = new com.sap.sse.common.Util.Triple(state.getStartTime(), raceLog.getCurrentPassId(), state.getRacingProcedure().getType()); - + } else { + result = null; + } + return result; } private Iterable getWindTrackerFactories() { @@ -3217,4 +3223,46 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes rankingInfo.getCompetitorRankingInfo().apply(c1).getWindwardDistanceSailed())); return result; } + + /** + * A {@link SimpleRaceLogIdentifier} in particular has a {@link SimpleRaceLogIdentifier#getRegattaLikeParentName()} + * which identifies either a regatta by name or a flexible leaderboard by name. Here is why this can luckily be + * resolved unanimously: A regatta leaderboard always uses as its name the regatta name (see + * {@link RegattaImpl#getName()}). Trying to {@link RegattaLeaderboardImpl#setName(String) set} the regatta leaderboard's + * name can only update its {@link Leaderboard#getDisplayName() display name}. Therefore, regatta leaderboards are always + * keyed in {@link #leaderboardsByName} by their regatta's name. Thus, no flexible leaderboard can have a regatta's name + * as its name, and therefore leaderboard names and regatta names are unitedly unique. + */ + @Override + public RaceLog resolve(SimpleRaceLogIdentifier identifier) { + final RaceLog result; + final IsRegattaLike regattaLike; + final Regatta regatta = regattasByName.get(identifier.getRegattaLikeParentName()); + if (regatta != null) { + regattaLike = regatta; + } else { + final Leaderboard leaderboard = leaderboardsByName.get(identifier.getRegattaLikeParentName()); + if (leaderboard != null && leaderboard instanceof FlexibleLeaderboard) { + regattaLike = (FlexibleLeaderboard) leaderboard; + } else { + regattaLike = null; + } + } + if (regattaLike != null) { + final RaceColumn raceColumn = regattaLike.getRaceColumnByName(identifier.getRaceColumnName()); + if (raceColumn != null) { + final Fleet fleet = raceColumn.getFleetByName(identifier.getFleetName()); + if (fleet != null) { + result = raceColumn.getRaceLog(fleet); + } else { + result = null; + } + } else { + result = null; + } + } else { + result = null; + } + return result; + } } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java index 4308830717e..6b1ad50bed0 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.Collection; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -54,7 +53,6 @@ import com.sap.sailing.domain.tracking.DynamicTrackedRace; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.TrackedRegatta; import com.sap.sailing.domain.tracking.WindTrack; -import com.sap.sailing.domain.tracking.impl.EmptyWindStore; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.RacingEventServiceOperation; import com.sap.sailing.server.masterdata.DataImportLockWithProgress; @@ -308,31 +306,6 @@ public class ImportMasterDataOperation extends } } - /** - * Hack adding a dummy tracked race, so that the competitors will be added to the leaderboards - * - * @param leaderboard - * @return the race column and fleet the dummy was attached to - */ - public com.sap.sse.common.Util.Pair addDummyTrackedRace(Leaderboard leaderboard, - Regatta regatta) { - RaceColumn raceColumn = null; - Fleet fleet = null; - Iterable raceColumns = leaderboard.getRaceColumns(); - Iterator raceColumnIterator = raceColumns.iterator(); - if (raceColumnIterator.hasNext()) { - raceColumn = raceColumnIterator.next(); - Iterable fleets = raceColumn.getFleets(); - Iterator fleetIterator = fleets.iterator(); - if (fleetIterator.hasNext()) { - fleet = fleetIterator.next(); - DummyTrackedRace dummy = new DummyTrackedRace(UUID.randomUUID(), leaderboard.getAllCompetitors(), regatta, null, EmptyWindStore.INSTANCE); - raceColumn.setTrackedRace(fleet, dummy); - } - } - return new com.sap.sse.common.Util.Pair(raceColumn, fleet); - } - private void createWindTracks(RacingEventService toState) { int numOfWindTracks = masterData.getWindTrackMasterData().size(); int i = 0; diff --git a/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/PathGeneratorBase.java b/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/PathGeneratorBase.java index e6761c48730..fc2039b5b86 100644 --- a/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/PathGeneratorBase.java +++ b/java/com.sap.sailing.simulator/src/com/sap/sailing/simulator/impl/PathGeneratorBase.java @@ -9,9 +9,11 @@ import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; public class PathGeneratorBase implements PathGenerator { - + // maximum duration of one path generation + private final static long MAX_DURATION_OF_PATH_GENERATION_MILLIS = 40 * 1000; // 40 seconds + protected SimulationParameters parameters; - protected final Duration algorithmMaxDuration = new MillisecondsDurationImpl(20000); // 20 seconds maximum duration of one path generation + protected final Duration algorithmMaxDuration = new MillisecondsDurationImpl(MAX_DURATION_OF_PATH_GENERATION_MILLIS); protected TimePoint algorithmStartTime; protected boolean algorithmTimedOut = false; diff --git a/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTestSetUp.java b/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTestSetUp.java index 137a383d16d..ef32d4e00c7 100644 --- a/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTestSetUp.java +++ b/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerReplicationTestSetUp.java @@ -72,11 +72,33 @@ public abstract class AbstractServerReplicationTestSetUp, ReplicationMasterDescriptor> result = setUpWithoutStartingToReplicateYet(); + result.getA().startToReplicateFrom(result.getB()); + } catch (Exception e) { + tearDown(); + throw e; + } + } + + /** + * Sets up master and replica, starts the JMS message broker and registers the replica with the master. If you want + * to drop the DB in your particular test case first, override {@link #persistenceSetUp(boolean)}. If you don't want + * replication to start right away for your test, override this method, execute only + * {@link #basicSetUp(boolean, Replicable, Replicable)}, do what you need to do and then explicitly call + * {@link ReplicationServiceTestImpl#startToReplicateFrom(ReplicationMasterDescriptor)} or + * {@link ReplicationServiceTestImpl#startToReplicateFromButDontYetFetchInitialLoad(ReplicationMasterDescriptor, boolean)} + * on the first component returned by {@link #basicSetUp(boolean, Replicable, Replicable)}. + * + * @return callers may call result.getA().startToReplicateFrom(result.getB()) on the result to actually + * start replication, e.g., after having done more set-up on the master + */ + protected Pair, ReplicationMasterDescriptor> setUpWithoutStartingToReplicateYet() throws Exception { try { Pair, ReplicationMasterDescriptor> result = basicSetUp( /* dropDB */true, /* master=null means create a new one */null, /* replica=null means create a new one */null); - result.getA().startToReplicateFrom(result.getB()); + return result; } catch (Exception e) { tearDown(); throw e; diff --git a/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerWithSingleServiceReplicationTest.java b/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerWithSingleServiceReplicationTest.java index 2e20ed3ee1c..8d07094f647 100755 --- a/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerWithSingleServiceReplicationTest.java +++ b/java/com.sap.sse.replication.testsupport/src/com/sap/sse/replication/testsupport/AbstractServerWithSingleServiceReplicationTest.java @@ -25,6 +25,10 @@ public abstract class AbstractServerWithSingleServiceReplicationTest, ReplicationMasterDescriptor> basicSetUp(boolean dropDB, ReplicableImpl master, ReplicableImpl replica) throws Exception { - return testSetUp.basicSetUp(dropDB, master, replica); + final Pair, ReplicationMasterDescriptor> result = testSetUp + .basicSetUp(dropDB, master, replica); + setUpDescriptorsFromTestSetup(); + return result; } @After diff --git a/mobile/com.sap.sailing.racecommittee.app/res/layout/race_finishing.xml b/mobile/com.sap.sailing.racecommittee.app/res/layout/race_finishing.xml index 48fce4c2749..a22e4c8a74b 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/layout/race_finishing.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/layout/race_finishing.xml @@ -24,10 +24,19 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:layout_margin="@dimen/default_margin_half" + android:layout_marginTop="@dimen/default_margin_half" android:text="@string/finishing_started" android:textAppearance="?textNormal"/> + + aus %.0f° Durchschnittliche Windgeschwindigkeit Stimme aufzeichnen - Erstes Schiff im Ziel um #TIME# + Erstes Schiff im Ziel um %s + (%s) Jetzt runter Liste bearbeiten Zielliste diff --git a/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml b/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml index f256aa6e85e..3d691358335 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/values/strings.xml @@ -370,7 +370,8 @@ Individual Recalls %s min Record Voice - First vessel in finish at #TIME# + First vessel in finish at %s + (%s) Down now Recording diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/adapters/coursedesign/CourseMarkAdapter.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/adapters/coursedesign/CourseMarkAdapter.java index bfb314eccfd..9459a71de36 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/adapters/coursedesign/CourseMarkAdapter.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/adapters/coursedesign/CourseMarkAdapter.java @@ -1,8 +1,5 @@ package com.sap.sailing.racecommittee.app.ui.adapters.coursedesign; -import java.util.ArrayList; -import java.util.List; - import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -10,17 +7,19 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; - import com.sap.sailing.domain.base.Mark; import com.sap.sailing.racecommittee.app.R; import com.sap.sailing.racecommittee.app.ui.utils.MarkImageHelper; +import java.util.ArrayList; +import java.util.List; + public class CourseMarkAdapter extends RecyclerView.Adapter { private Context mContext; private List mMarks; private MarkImageHelper mImageHelper; - private MarkLongClick mListener; + private MarkClick mListener; public CourseMarkAdapter(Context context, ArrayList marks, MarkImageHelper imageHelper) { mContext = context; @@ -52,15 +51,15 @@ public class CourseMarkAdapter extends RecyclerView.Adapter entries = new ArrayList(); - List entryValues = new ArrayList(); + List entries = new ArrayList<>(); + List entryValues = new ArrayList<>(); for (RacingProcedureType type : RacingProcedureType.validValues()) { entries.add(type.toString()); entryValues.add(type.name()); } - startProcedurePreference.setEntries(entries.toArray(new CharSequence[entries.size()])); - startProcedurePreference.setEntryValues(entryValues.toArray(new CharSequence[entryValues.size()])); + startProcedurePreference.setEntries(entries.toArray(new String[entries.size()])); + startProcedurePreference.setEntryValues(entryValues.toArray(new String[entryValues.size()])); bindPreferenceSummaryToValue(startProcedurePreference); } private void setupCourseDesignerTypePreference() { - final ListPreference courseDesignerPreference = findPreference(R.string.preference_course_designer_override_key); + final ListPreference preference = findPreference(R.string.preference_course_designer_override_key); - List entries = new ArrayList(); - List entryValues = new ArrayList(); + List entries = new ArrayList<>(); + List entryValues = new ArrayList<>(); for (CourseDesignerMode type : CourseDesignerMode.validValues()) { entries.add(type.toString()); entryValues.add(type.name()); } - courseDesignerPreference.setEntries(entries.toArray(new CharSequence[0])); - courseDesignerPreference.setEntryValues(entryValues.toArray(new CharSequence[0])); + preference.setEntries(entries.toArray(new String[entries.size()])); + preference.setEntryValues(entryValues.toArray(new String[entryValues.size()])); - bindPreferenceSummaryToValue(courseDesignerPreference); + bindPreferenceSummaryToValue(preference); } private void setupRRS26StartmodeFlagsList() { - MultiSelectListPreference listPreference = findPreference(R.string.preference_racing_procedure_rrs26_startmode_flags_key); - List flags = new ArrayList(); + MultiSelectListPreference preference = findPreference(R.string.preference_racing_procedure_rrs26_startmode_flags_key); + List flags = new ArrayList<>(); for (Flags flag : Flags.validValues()) { flags.add(flag.name()); } - listPreference.setEntries(flags.toArray(new String[flags.size()])); - listPreference.setEntryValues(flags.toArray(new String[flags.size()])); + + Collections.sort(flags); + preference.setEntries(flags.toArray(new String[flags.size()])); + preference.setEntryValues(flags.toArray(new String[flags.size()])); } private void setupClassFlagList(ListPreference preference) { - List entries = new ArrayList(); - List entryValues = new ArrayList(); + List entries = new ArrayList<>(); + List entryValues = new ArrayList<>(); for (Flags flag : Flags.validValues()) { entries.add(flag.toString()); entryValues.add(flag.name()); } - preference.setEntries(entries.toArray(new CharSequence[entries.size()])); - preference.setEntryValues(entryValues.toArray(new CharSequence[entryValues.size()])); + Collections.sort(entries); + Collections.sort(entryValues); + preference.setEntries(entries.toArray(new String[entries.size()])); + preference.setEntryValues(entryValues.toArray(new String[entryValues.size()])); } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/CourseFragmentMarks.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/CourseFragmentMarks.java index 9b8b0c8321d..26cb3a3ba10 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/CourseFragmentMarks.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/CourseFragmentMarks.java @@ -36,7 +36,7 @@ import com.sap.sailing.racecommittee.app.ui.adapters.coursedesign.CourseElementA import com.sap.sailing.racecommittee.app.ui.adapters.coursedesign.CourseElementAdapter.EventListener; import com.sap.sailing.racecommittee.app.ui.adapters.coursedesign.CourseListDataElement; import com.sap.sailing.racecommittee.app.ui.adapters.coursedesign.CourseMarkAdapter; -import com.sap.sailing.racecommittee.app.ui.adapters.coursedesign.CourseMarkAdapter.MarkLongClick; +import com.sap.sailing.racecommittee.app.ui.adapters.coursedesign.CourseMarkAdapter.MarkClick; import com.sap.sailing.racecommittee.app.ui.comparators.NaturalNamedComparator; import com.sap.sailing.racecommittee.app.ui.utils.ESSMarkImageHelper; import com.sap.sailing.racecommittee.app.utils.BitmapHelper; @@ -48,7 +48,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -public class CourseFragmentMarks extends CourseFragment implements MarkLongClick, ElementLongClick, EventListener { +public class CourseFragmentMarks extends CourseFragment implements MarkClick, ElementLongClick, EventListener { private RecyclerViewDragDropManager mDragDropManager; private RecyclerViewSwipeManager mSwipeManager; @@ -327,7 +327,7 @@ public class CourseFragmentMarks extends CourseFragment implements MarkLongClick } @Override - public void onItemLongClick(Mark mark) { + public void onItemClick(Mark mark) { if (mElements.isEmpty()) { addNewCourseElementToList(mark); } else { diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/RaceFinishingFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/RaceFinishingFragment.java index 6a2775ee360..c97f03dbecc 100755 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/RaceFinishingFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/RaceFinishingFragment.java @@ -1,7 +1,5 @@ package com.sap.sailing.racecommittee.app.ui.fragments.raceinfo; -import java.text.SimpleDateFormat; - import android.os.Bundle; import android.support.annotation.Nullable; import android.view.LayoutInflater; @@ -10,14 +8,21 @@ import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; - import com.sap.sailing.android.shared.util.ViewHolder; import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.racecommittee.app.R; import com.sap.sailing.racecommittee.app.ui.utils.FlagsResources; +import com.sap.sailing.racecommittee.app.utils.TimeUtils; +import com.sap.sse.common.TimePoint; +import com.sap.sse.common.impl.MillisecondsTimePoint; + +import java.text.SimpleDateFormat; public class RaceFinishingFragment extends BaseFragment { + private SimpleDateFormat mDateFormat; + private TextView mFinishingSince; + public static RaceFinishingFragment newInstance() { RaceFinishingFragment fragment = new RaceFinishingFragment(); Bundle args = new Bundle(); @@ -30,6 +35,9 @@ public class RaceFinishingFragment extends BaseFragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.race_finishing, container, false); + mDateFormat = new SimpleDateFormat("HH:mm:ss", getResources().getConfiguration().locale); + mFinishingSince = ViewHolder.get(layout, R.id.first_vessel_since); + ImageView flag = ViewHolder.get(layout, R.id.flag); if (flag != null) { flag.setImageDrawable(FlagsResources.getFlagDrawable(getActivity(), Flags.BLUE.name(), 96)); @@ -55,11 +63,19 @@ public class RaceFinishingFragment extends BaseFragment { if (getView() != null) { TextView first_vessel = ViewHolder.get(getView(), R.id.first_vessel); if (first_vessel != null && getRaceState() != null && getRaceState().getFinishingTime() != null) { - String vessel_time = getString(R.string.finishing_started); - SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss", getResources().getConfiguration().locale); - vessel_time = vessel_time.replace("#TIME#", dateFormat.format(getRaceState().getFinishingTime().asDate())); - first_vessel.setText(vessel_time); + first_vessel.setText(getString(R.string.finishing_started, mDateFormat.format(getRaceState().getFinishingTime().asDate()))); } } + notifyTick(MillisecondsTimePoint.now()); + } + + @Override + public void notifyTick(TimePoint now) { + super.notifyTick(now); + + if (mFinishingSince != null) { + String timeDiff = TimeUtils.formatDurationSince(now.minus(getRaceState().getFinishingTime().asMillis()).asMillis()); + mFinishingSince.setText(getString(R.string.finishing_started_since, timeDiff)); + } } } diff --git a/wiki/kieler-woche-2015.md b/wiki/kieler-woche-2015.md index 54afdcc9d74..19d03533140 100644 --- a/wiki/kieler-woche-2015.md +++ b/wiki/kieler-woche-2015.md @@ -3,38 +3,66 @@ ## Server Landscape We run four servers for the event: -- on EC2: **Master**, **Replika 1** and **2** with an **ELB** in front, +- on EC2: **Master 1**, **Master 2**, **Replica 1** and **Replica 2** with an **ELB** in front, +- ELB canonical name is KW2015-553831863.eu-west-1.elb.amazonaws.com - locally: **Cube-Server** -For fast and available switching. The DB they use is called `KW2015`, and so is the replication channel. The git branch we use to merge the features we want to deploy to the event servers is called `kielerwoche2015` and the git tag used to build a release for it is called `XXX-release`. See http://hudson.sapsailing.com/job/SAPSailingAnalytics-XXX/ and http://hudson.sapsailing.com/job/SAPSailingAnalytics-XXX-release/, respectively, for their Hudson jobs. +for fast and available switching. The DB they use is called `KW2015`, and so is the replication channel. The git branch we use to merge the features we want to deploy to the event servers is called `kielerwoche2015` and the git tag used to build a release for it is called `kielerwoche2015-release`. See http://hudson.sapsailing.com/job/SAPSailingAnalytics-kielerwoche2015/ and http://hudson.sapsailing.com/job/SAPSailingAnalytics-kielerwoche2015-release/, respectively, for their Hudson jobs. -### Master Server +### Master 1 Server - Admin Console at http://ec2-54-154-151-10.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html - External IP: 54.154.151.10 - Internal IP: 172.31.24.187 -### Replika 1 server +### Master 2 Server +- Admin Console at http://ec2-54-76-169-213.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html +- External IP: 54.76.169.213 +- Internal IP: 172.31.30.73 + +### "Current" Master +Whichever master is current, we map the main Apache URL http://kielerwoche2015-master.sapsailing.com to it. This is also the URL to use for Tablet and Smartphone configurations. + +### Replica 1 server - Admin Console at http://ec2-54-72-226-124.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html - External IP: 54.72.226.124 - Internal IP: 172.31.20.11 -### Replika 2 server +### Replica 2 server - Admin Console at http://ec2-54-154-175-180.eu-west-1.compute.amazonaws.com:8888/gwt/AdminConsole.html - External IP: 54.154.175.180 - Internal IP: 172.31.20.12 ## TracTrac URL -- http://xxx.traclive.dk/events/event_xxx/jsonservice.php +- http://event.tractrac.com/events/event_20150616_KielerWoch/jsonservice.php for the Olympic Week ## Replication - RabbitMQ server for replication: 52.16.112.6 (Web: http://52.16.112.6:15672/) - Replication Exchange Name: KW2015 +## Switching from one Master to Another + - switch Cube Replica's Apache server to direct http://kielerwoche2015.sapsailing.com to the cloud by editing its `/etc/apache2/sites-enabled/001-events.conf`, then as user `root` running `service apache2 reload`. + - upgrade the new master to the release you want, using the `refreshInstance.sh` script + - prepare switching in sapsailing.com:/etc/httpd/conf.d/001-events.conf so that in particular http://kielerwoche2015-master.sapsailing.com points to the new master's IP; save the file but don't do `service httpd reload` as yet + - remove the replicas from the ELB + - cleanly stop replication for all replicas currently active on the master you want to take offline. (Exception: if your current master is really broken and cannot serve requests anymore, in order to keep up at least some form of availability you may leave the replicas running until the new master is up.) + - stop replication on the Cube Replica + - start the new master + - track all the races that need to be tracked + - add the new master to the ELB and remove the old master from the ELB + - immediately afterwards do `service httpd reload` as user `root` on sapsailing.com to activate the new master + - validate that you haven't lost any RCApp events, ideally by comparing the RegattaOverview.html page for the old and the new master; in case you lost events, reload the race logs for those leaderboards in the new master's AdminConsole. + - upgrade the replicas (including the Cube Replica) to the new master if the new master runs a different release than the old master, using `refreshInstance.sh` + - adjust the replicas' (including the Cube Replica) `env.sh` to point to the new master with their `REPLICATE_MASTER_SERVLET_HOST` setting + - restart the Java server instance on the replicas (including the Cube Replica), using the usual `./stop; ./start` sequence. This will automatically re-start the replication + - when the replicas have finished their initial load (can be verified by looking at the RabbitMQ queues at http://ec2-52-16-112-6.eu-west-1.compute.amazonaws.com:15672/#/queues which should no longer have any "initialLoad" queues), add them again to the load balancer + - in the Cube server's Apache configuration let http://kielerwoche2015.sapsailing.com point again to the local replica by editing `/etc/apache2/sites-enabled/001-events.conf`, then as user `root` run `service httpd reload` + - shut down the other master server to avoid confusion with database writes + ## Other links -- Regatta Overview: http://kielerwoche2015ro.sapsailing.com -- Manage2Sail Event URL: http://manage2sail.com/api/public/links/event/ID?accesstoken=TOKEN&mediaType=json +- Regatta Overview: http://kielerwoche2015ro.sapsailing.com (currently not yet established) +- Manage2Sail Event URL: http://manage2sail.com/api/public/links/event/d56f7fea-0ca1-4972-83a4-d71d79f26b93?accesstoken=bDAv8CwsTM94ujZ&mediaType=json ## Local network setup basically see [[Set up local network with replication server|wiki/event-network-with-replica]] operating with a Meraki and a local replica server using 1 physical WAN interface on the Meraki. Meraki network config for this event can be found under [[Meraki Dashboard|https://n142.meraki.com/KiWo-TraWo/n/Rzu9tdoc]] -- Accessing replica server from `sailing-demo.sapsailing.com`via ssh or http from `ADMIN` network \ No newline at end of file +- Accessing replica server from `sailing-demo.sapsailing.com` via ssh or http from `ADMIN` network \ No newline at end of file