Merge branch 'design2015' into design2015-mobile

Conflicts:
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/client/place/event/partials/updatesBox/UpdatesBoxItem.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RaceContext.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/dispatch/event/RacesActionUtil.java
This commit is contained in:
Benjamin Barth committed 2015-06-22 11:27:52 +02:00
commit 6761673e0d
113 files changed
+1113 -597

No files matched your search

@@ -29,6 +29,7 @@ import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.RacingEventService;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -152,8 +153,15 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib
for (RaceColumn column : lb.getRaceColumns()) { for (RaceColumn column : lb.getRaceColumns()) {
for (Fleet fleet : column.getFleets()) { for (Fleet fleet : column.getFleets()) {
TrackedRace race = column.getTrackedRace(fleet); TrackedRace race = column.getTrackedRace(fleet);
if (race != null && race.isLive(new MillisecondsTimePoint(new Date()))) { if (race != null) {
result = race; 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) { String leaderboardName) {
List<StartAnalysisDTO> startAnalysisDTOs = new ArrayList<StartAnalysisDTO>(); List<StartAnalysisDTO> startAnalysisDTOs = new ArrayList<StartAnalysisDTO>();
if (leaderboardName != null) { if (leaderboardName != null) {
Competitor competitor = baseDomainFactory.getCompetitorStore().getExistingCompetitorByIdAsString( Competitor competitor = baseDomainFactory.getCompetitorStore().getExistingCompetitorByIdAsString(competitorIdAsString);
competitorIdAsString);
List<TrackedRace> trackedRacesForLeaderBoardName = getTrackedRacesFromLeaderboard(leaderboardName); List<TrackedRace> trackedRacesForLeaderBoardName = getTrackedRacesFromLeaderboard(leaderboardName);
for (TrackedRace trackedRace : trackedRacesForLeaderBoardName) { for (TrackedRace trackedRace : trackedRacesForLeaderBoardName) {
StartAnalysisDTO startAnalysisDTO = startAnalysisCreationController StartAnalysisDTO startAnalysisDTO = startAnalysisCreationController
.checkStartAnalysisForCompetitorInTrackedRace(competitor, trackedRace); .checkStartAnalysisForCompetitorInTrackedRace(competitor, trackedRace);
if (startAnalysisDTO != null) if (startAnalysisDTO != null) {
startAnalysisDTOs.add(startAnalysisDTO); startAnalysisDTOs.add(startAnalysisDTO);
}
} }
} }
return startAnalysisDTOs; return startAnalysisDTOs;
@@ -253,11 +261,11 @@ public class RibDashboardServiceImpl extends RemoteServiceServlet implements Rib
@Override @Override
public List<CompetitorDTO> getCompetitorsInLeaderboard(String leaderboardName) { public List<CompetitorDTO> getCompetitorsInLeaderboard(String leaderboardName) {
logger.log(Level.INFO, "getCompetitorsInLeaderboard(...) Request."); logger.log(Level.INFO, "getCompetitorsInLeaderboard(...) Request.");
if(leaderboardName != null){ if (leaderboardName != null) {
Leaderboard lb = getRacingEventService().getLeaderboardByName(leaderboardName); Leaderboard lb = getRacingEventService().getLeaderboardByName(leaderboardName);
return baseDomainFactory.getCompetitorDTOList(lb.getCompetitorsFromBestToWorst(new MillisecondsTimePoint( return baseDomainFactory.getCompetitorDTOList(lb.getCompetitorsFromBestToWorst(new MillisecondsTimePoint(
new Date()))); new Date())));
}else{ } else {
return null; return null;
} }
} }
@@ -53,8 +53,7 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida
boolean isCompetitorOneOfFirstThree = false; boolean isCompetitorOneOfFirstThree = false;
for (int i = 0; i < MINIMUM_NUMBER_COMPETITORS_FOR_STARTANALYSIS; i++) { for (int i = 0; i < MINIMUM_NUMBER_COMPETITORS_FOR_STARTANALYSIS; i++) {
competitors.add(createStartAnalysisCompetitorDTO(trackedRace, i + 1, markPassingsInOrder.get(i) competitors.add(createStartAnalysisCompetitorDTO(trackedRace, i + 1, markPassingsInOrder.get(i).getCompetitor()));
.getCompetitor()));
if (markPassingsInOrder.get(i).getCompetitor().equals(competitor)) { if (markPassingsInOrder.get(i).getCompetitor().equals(competitor)) {
isCompetitorOneOfFirstThree = true; isCompetitorOneOfFirstThree = true;
} }
@@ -75,9 +74,9 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida
startAnalysisDTO.racingProcedureType = RacingProcedureType.GateStart; startAnalysisDTO.racingProcedureType = RacingProcedureType.GateStart;
long timePointOfGolfDownTime = trackedRace.getGateStartGolfDownTime(); long timePointOfGolfDownTime = trackedRace.getGateStartGolfDownTime();
startAnalysisDTO.timeOfStartInMilliSeconds = trackedRace.getStartOfRace().asMillis(); 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; startAnalysisDTO.tailLenghtInMilliseconds = DEFAULT_GATE_START_INTERVALL_IN_MILLISECONDS;
}else{ } else {
startAnalysisDTO.tailLenghtInMilliseconds = timePointOfGolfDownTime-trackedRace.getStartOfRace().asMillis(); startAnalysisDTO.tailLenghtInMilliseconds = timePointOfGolfDownTime-trackedRace.getStartOfRace().asMillis();
} }
} else { } else {
@@ -142,19 +141,26 @@ public class StartAnalysisDTOFactory extends AbstractStartAnalysisCreationValida
private WindAndAdvantagesInfoForStartLineDTO createStartAnalysisWindAndLineData(TrackedRace trackedRace) { private WindAndAdvantagesInfoForStartLineDTO createStartAnalysisWindAndLineData(TrackedRace trackedRace) {
WindAndAdvantagesInfoForStartLineDTO startAnalysisWindLineInfoDTO = new WindAndAdvantagesInfoForStartLineDTO(); 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 startLineAdvantageDTO = new StartLineAdvantageDTO();
startLineAdvantageDTO.startLineAdvatageType = getStartlineAdvantageType(trackedRace, new MillisecondsTimePoint( startLineAdvantageDTO.startLineAdvatageType = getStartlineAdvantageType(trackedRace, new MillisecondsTimePoint(
new Date())); new Date()));
startLineAdvantageDTO.startLineAdvantage = startline.getAdvantage().getMeters(); startLineAdvantageDTO.startLineAdvantage = startline.getAdvantage().getMeters();
startAnalysisWindLineInfoDTO.startLineAdvantage = startLineAdvantageDTO; startAnalysisWindLineInfoDTO.startLineAdvantage = startLineAdvantageDTO;
Position portMarkPosition = trackedRace.getOrCreateTrack( if (trackedRace.getStartTimeReceived() != null) {
trackedRace.getStartLine(trackedRace.getStartTimeReceived()).getStarboardMarkWhileApproachingLine()) Position portMarkPosition = trackedRace.getOrCreateTrack(
.getEstimatedPosition(trackedRace.getStartTimeReceived(), /* extrapolate */ trackedRace.getStartLine(trackedRace.getStartTimeReceived()).getStarboardMarkWhileApproachingLine())
false); .getEstimatedPosition(trackedRace.getStartTimeReceived(), /* extrapolate */
Wind windAtStart = trackedRace.getWind(portMarkPosition, trackedRace.getStartTimeReceived()); false);
startAnalysisWindLineInfoDTO.windDirectionInDegrees = windAtStart.getBearing().getDegrees(); Wind windAtStart = trackedRace.getWind(portMarkPosition, trackedRace.getStartTimeReceived());
startAnalysisWindLineInfoDTO.windSpeedInKnots = windAtStart.getKnots(); startAnalysisWindLineInfoDTO.windDirectionInDegrees = windAtStart.getBearing().getDegrees();
startAnalysisWindLineInfoDTO.windSpeedInKnots = windAtStart.getKnots();
} else {
startAnalysisWindLineInfoDTO.windDirectionInDegrees = 0.0;
startAnalysisWindLineInfoDTO.windSpeedInKnots = 0.0;
}
return startAnalysisWindLineInfoDTO; return startAnalysisWindLineInfoDTO;
} }
@@ -4,6 +4,7 @@ import static junit.framework.Assert.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.hamcrest.Matchers.lessThanOrEqualTo;
import static org.mockito.Mockito.mock;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@@ -11,6 +12,7 @@ import java.util.Collections;
import org.junit.Test; import org.junit.Test;
import com.sap.sailing.domain.abstractlog.race.RaceLog; 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.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor; 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 */ EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null)); null, /* endDate */null, null, null, "a", null));
DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race, DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
trackedRace.attachRaceLog(raceLog); trackedRace.attachRaceLog(raceLog);
trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog); trackedRace.waitForLoadingFromGPSFixStoreToFinishRunning(raceLog);
@@ -125,7 +128,8 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */ EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null)); null, /* endDate */null, null, null, "a", null));
DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race, DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, store, 0, 0, 0, /*useMarkPassingCalculator*/ false,
OneDesignRankingMetric::new, mock(RaceLogResolver.class));
trackedRace.addListener(new AbstractRaceChangeListener() { trackedRace.addListener(new AbstractRaceChangeListener() {
@Override @Override
@@ -6,6 +6,7 @@ import java.util.UUID;
import com.sap.sailing.domain.abstractlog.AbstractLog; import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.race.RaceLog; 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.RaceInformationFinder;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer; import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer;
import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.BoatClass;
@@ -51,13 +52,13 @@ public class RaceLogConnectivityParams implements RaceTrackingConnectivityParame
@Override @Override
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
GPSFixStore gpsFixStore) { GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) {
return createRaceTracker(regatta, trackedRegattaRegistry, windStore, gpsFixStore); return createRaceTracker(regatta, trackedRegattaRegistry, windStore, gpsFixStore, raceLogResolver);
} }
@Override @Override
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
WindStore windStore, GPSFixStore gpsFixStore) { WindStore windStore, GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) {
if (regatta == null) { if (regatta == null) {
BoatClass boatClass = new RaceInformationFinder(getRaceLog()).analyze().getBoatClass(); BoatClass boatClass = new RaceInformationFinder(getRaceLog()).analyze().getBoatClass();
regatta = service.getOrCreateDefaultRegatta( regatta = service.getOrCreateDefaultRegatta(
@@ -68,7 +69,7 @@ public class RaceLogConnectivityParams implements RaceTrackingConnectivityParame
throw new RaceNotCreatedException("No regatta for race-log tracked race"); throw new RaceNotCreatedException("No regatta for race-log tracked race");
} }
DynamicTrackedRegatta trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(regatta); DynamicTrackedRegatta trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(regatta);
return new RaceLogRaceTracker(trackedRegatta, this, windStore, gpsFixStore); return new RaceLogRaceTracker(trackedRegatta, this, windStore, gpsFixStore, raceLogResolver);
} }
@Override @Override
@@ -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.RaceLogCourseDesignChangedEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor; 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.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.impl.BaseRaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent; import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDenoteForTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogDeviceCompetitorMappingEvent; 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 WindStore windStore;
private final GPSFixStore gpsFixStore; private final GPSFixStore gpsFixStore;
private final DynamicTrackedRegatta regatta; private final DynamicTrackedRegatta regatta;
private final RaceLogResolver raceLogResolver;
private final Map<AbstractLog<?, ?>, Object> visitors = new HashMap<AbstractLog<?, ?>, Object>(); private final Map<AbstractLog<?, ?>, Object> visitors = new HashMap<AbstractLog<?, ?>, Object>();
private ConcurrentHashMap<Competitor, List<DeviceMapping<Competitor>>> competitorMappings = new ConcurrentHashMap<>(); private final ConcurrentHashMap<Competitor, List<DeviceMapping<Competitor>>> competitorMappings = new ConcurrentHashMap<>();
private ConcurrentHashMap<Mark, List<DeviceMapping<Mark>>> markMappings = new ConcurrentHashMap<>(); private final ConcurrentHashMap<Mark, List<DeviceMapping<Mark>>> markMappings = new ConcurrentHashMap<>();
private Map<DeviceIdentifier, List<DeviceMapping<Mark>>> markMappingsByDevices = new HashMap<>(); private final Map<DeviceIdentifier, List<DeviceMapping<Mark>>> markMappingsByDevices = new HashMap<>();
private Map<DeviceIdentifier, List<DeviceMapping<Competitor>>> competitorMappingsByDevices = new HashMap<>(); private final Map<DeviceIdentifier, List<DeviceMapping<Competitor>>> competitorMappingsByDevices = new HashMap<>();
private DynamicTrackedRace trackedRace; private DynamicTrackedRace trackedRace;
private static final Logger logger = Logger.getLogger(RaceLogRaceTracker.class.getName()); private static final Logger logger = Logger.getLogger(RaceLogRaceTracker.class.getName());
public RaceLogRaceTracker(DynamicTrackedRegatta regatta, RaceLogConnectivityParams params, WindStore windStore, public RaceLogRaceTracker(DynamicTrackedRegatta regatta, RaceLogConnectivityParams params, WindStore windStore,
GPSFixStore gpsFixStore) { GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) {
this.params = params; this.params = params;
this.windStore = windStore; this.windStore = windStore;
this.gpsFixStore = gpsFixStore; this.gpsFixStore = gpsFixStore;
this.regatta = regatta; this.regatta = regatta;
this.raceLogResolver = raceLogResolver;
// add log listeners // add log listeners
for (AbstractLog<?, ?> log : params.getLogHierarchy()) { for (AbstractLog<?, ?> log : params.getLogHierarchy()) {
@@ -445,7 +448,7 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
trackedRace = regatta.createTrackedRace(raceDef, sidelines, windStore, gpsFixStore, trackedRace = regatta.createTrackedRace(raceDef, sidelines, windStore, gpsFixStore,
params.getDelayToLiveInMillis(), WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, 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)); trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, 0));
@@ -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<Boolean> {
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;
}
}
@@ -428,7 +428,7 @@ public class ReadonlyRaceStateImpl implements ReadonlyRaceState, RaceLogChangedL
removeChangedListener(racingProcedure); removeChangedListener(racingProcedure);
racingProcedure.detach(); racingProcedure.detach();
} }
racingProcedure = procedureFactory.createRacingProcedure(cachedRacingProcedureType, raceLog); racingProcedure = procedureFactory.createRacingProcedure(cachedRacingProcedureType, raceLog, raceLogResolver);
racingProcedure.setStateEventScheduler(scheduler); racingProcedure.setStateEventScheduler(scheduler);
addChangedListener(racingProcedure); addChangedListener(racingProcedure);
@@ -1,12 +1,13 @@
package com.sap.sailing.domain.abstractlog.race.state.racingprocedure; package com.sap.sailing.domain.abstractlog.race.state.racingprocedure;
import com.sap.sailing.domain.abstractlog.race.RaceLog; 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.base.configuration.RegattaConfiguration;
import com.sap.sailing.domain.common.racelog.RacingProcedureType; import com.sap.sailing.domain.common.racelog.RacingProcedureType;
public interface RacingProcedureFactory { public interface RacingProcedureFactory {
ReadonlyRacingProcedure createRacingProcedure(RacingProcedureType type, RaceLog raceLog); ReadonlyRacingProcedure createRacingProcedure(RacingProcedureType type, RaceLog raceLog, RaceLogResolver raceLogResolver);
RegattaConfiguration getConfiguration(); RegattaConfiguration getConfiguration();
@@ -79,7 +79,9 @@ public interface ReadonlyRacingProcedure extends RaceStateEventProcessor, RaceSt
TimePoint getIndividualRecallDisplayedTime(); TimePoint getIndividualRecallDisplayedTime();
/** /**
* Gets the time the individual recall flag was removed (or <code>null</code>). * Gets the time the individual recall flag was or shall be removed (or <code>null</code> 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(); TimePoint getIndividualRecallRemovalTime();
@@ -7,6 +7,7 @@ import java.util.Collections;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; 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.RaceStateEvent;
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl;
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEvents; 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 class BasicRacingProcedureImpl extends BaseRacingProcedure {
public BasicRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory, public BasicRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory,
RacingProcedureConfiguration configuration) { RacingProcedureConfiguration configuration, RaceLogResolver raceLogResolver) {
super(raceLog, author, factory, configuration); super(raceLog, author, factory, configuration, raceLogResolver);
} }
@Override @Override
@@ -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.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; 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.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.RaceStateEvent;
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl;
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEvents; 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; private final ESSConfiguration configuration;
public ESSRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, public ESSRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author,
RaceLogEventFactory factory, ESSConfiguration configuration) { RaceLogEventFactory factory, ESSConfiguration configuration, RaceLogResolver raceLogResolver) {
super(raceLog, author, factory, configuration); super(raceLog, author, factory, configuration, raceLogResolver);
this.configuration = configuration; this.configuration = configuration;
update(); update();
} }
@@ -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.RaceLogGateLineOpeningTimeEvent.GateLineOpeningTimes;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.GateLineOpeningTimeFinder; 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.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.RaceStateEvent;
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl;
@@ -43,8 +44,8 @@ public class GateStartRacingProcedureImpl extends BaseRacingProcedure implements
private String cachedPathfinder; private String cachedPathfinder;
public GateStartRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory, public GateStartRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory,
GateStartConfiguration configuration) { GateStartConfiguration configuration, RaceLogResolver raceLogResolver) {
super(raceLog, author, factory, configuration); super(raceLog, author, factory, configuration, raceLogResolver);
this.gateLineOpeningTimeAnalyzer = new GateLineOpeningTimeFinder(raceLog); this.gateLineOpeningTimeAnalyzer = new GateLineOpeningTimeFinder(raceLog);
this.pathfinderAnalyzer = new PathfinderFinder(raceLog); this.pathfinderAnalyzer = new PathfinderFinder(raceLog);
@@ -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.IndividualRecallRemovedFinder;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.IsFinishedAnalyzer; 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.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.impl.RaceLogChangedVisitor;
import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent; import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent;
import com.sap.sailing.domain.abstractlog.race.state.RaceStateEventScheduler; 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.abstractlog.race.state.racingprocedure.RacingProcedureChangedListener;
import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration; import com.sap.sailing.domain.base.configuration.RacingProcedureConfiguration;
import com.sap.sailing.domain.common.racelog.Flags; 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.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
/** /**
* Base class for all your {@link RacingProcedure}s. * 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, public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener implements RacingProcedure,
RaceLogChangedListener { 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; private RaceStateEventScheduler scheduler;
@@ -49,35 +55,35 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
private final RacingProcedureConfiguration configuration; private final RacingProcedureConfiguration configuration;
private final RacingProcedureChangedListeners<? extends RacingProcedureChangedListener> changedListeners; private final RacingProcedureChangedListeners<? extends RacingProcedureChangedListener> changedListeners;
private final IsIndividualRecallDisplayedAnalyzer isRecallDisplayedAnalyzer;
private final IndividualRecallDisplayedFinder recallDisplayedFinder; private final IndividualRecallDisplayedFinder recallDisplayedFinder;
private final IndividualRecallRemovedFinder recallRemovedFinder; private final IndividualRecallRemovedFinder recallRemovedFinder;
private final FinishingTimeFinder finishingTimeFinder; private final FinishingTimeFinder finishingTimeFinder;
private final FinishedTimeFinder finishedTimeFinder; private final FinishedTimeFinder finishedTimeFinder;
private final RaceLogEventVisitor raceLogListener; private final RaceLogEventVisitor raceLogListener;
private final StartTimeFinder startTimeFinder;
private boolean cachedIsIndividualRecallDisplayed; private boolean cachedIsIndividualRecallDisplayed;
/** /**
* When calling me, call {@link BaseRacingProcedure#update()} afterwards! * When calling me, call {@link BaseRacingProcedure#update()} afterwards!
* @param raceLogResolver TODO
*/ */
public BaseRacingProcedure(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory, public BaseRacingProcedure(RaceLog raceLog, AbstractLogEventAuthor author, RaceLogEventFactory factory,
RacingProcedureConfiguration configuration) { RacingProcedureConfiguration configuration, RaceLogResolver raceLogResolver) {
if (configuration == null) { if (configuration == null) {
throw new IllegalArgumentException("configuration must not be null"); throw new IllegalArgumentException("configuration must not be null");
} }
this.raceLog = raceLog; this.raceLog = raceLog;
this.author = author; this.author = author;
this.factory = factory; this.factory = factory;
this.configuration = configuration; this.configuration = configuration;
this.changedListeners = createChangedListenerContainer(); this.changedListeners = createChangedListenerContainer();
this.isRecallDisplayedAnalyzer = new IsIndividualRecallDisplayedAnalyzer(raceLog);
this.recallDisplayedFinder = new IndividualRecallDisplayedFinder(raceLog); this.recallDisplayedFinder = new IndividualRecallDisplayedFinder(raceLog);
this.recallRemovedFinder = new IndividualRecallRemovedFinder(raceLog); this.recallRemovedFinder = new IndividualRecallRemovedFinder(raceLog);
this.finishingTimeFinder = new FinishingTimeFinder(raceLog); this.finishingTimeFinder = new FinishingTimeFinder(raceLog);
this.finishedTimeFinder = new FinishedTimeFinder(raceLog); this.finishedTimeFinder = new FinishedTimeFinder(raceLog);
this.startTimeFinder = new StartTimeFinder(raceLogResolver, raceLog);
this.raceLogListener = new RaceLogChangedVisitor(this); this.raceLogListener = new RaceLogChangedVisitor(this);
this.raceLog.addListener(raceLogListener); this.raceLog.addListener(raceLogListener);
@@ -125,7 +131,7 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
break; break;
case RUNNING: case RUNNING:
if (isIndividualRecallDisplayed()) { if (isIndividualRecallDisplayed()) {
rescheduleIndividualRecallTimeout(recallDisplayedFinder.analyze()); rescheduleIndividualRecallTimeout();
} }
break; break;
default: default:
@@ -133,6 +139,10 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
} }
} }
private TimePoint getStartTime() {
return startTimeFinder.analyze().getStartTime();
}
@Override @Override
public boolean isIndividualRecallDisplayed() { public boolean isIndividualRecallDisplayed() {
return cachedIsIndividualRecallDisplayed; return cachedIsIndividualRecallDisplayed;
@@ -140,10 +150,10 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
@Override @Override
public boolean isIndividualRecallDisplayed(TimePoint at) { public boolean isIndividualRecallDisplayed(TimePoint at) {
if (hasIndividualRecall()) { final TimePoint individualRecallDisplayedTime = getIndividualRecallDisplayedTime();
return new IsIndividualRecallDisplayedAnalyzer(getRaceLog(), at).analyze(); final TimePoint individualRecallRemovalTime = getIndividualRecallRemovalTime();
} return (hasIndividualRecall() && individualRecallDisplayedTime != null && !individualRecallDisplayedTime.after(at) &&
return false; individualRecallRemovalTime != null && !individualRecallRemovalTime.after(at));
} }
@Override @Override
@@ -156,17 +166,20 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
@Override @Override
public TimePoint getIndividualRecallRemovalTime() { public TimePoint getIndividualRecallRemovalTime() {
TimePoint displayed = getIndividualRecallDisplayedTime(); final TimePoint result;
if (hasIndividualRecall()) { final TimePoint raceStartTime = getStartTime();
TimePoint removedEvent = recallRemovedFinder.analyze(); final TimePoint removedEvent;
if (removedEvent != null && (displayed == null || removedEvent.after(displayed))) { if (hasIndividualRecall() && (removedEvent = recallRemovedFinder.analyze()) != null && (raceStartTime == null || removedEvent.after(raceStartTime))) {
return removedEvent; result = removedEvent;
} else {
final TimePoint individualRecallDisplayedTime = getIndividualRecallDisplayedTime();
if (individualRecallDisplayedTime != null && raceStartTime != null) {
result = raceStartTime.plus(individualRecallRemovalTimeout);
} else {
result = null;
} }
} }
if (displayed != null) { return result;
return displayed.plus(individualRecallRemovalTimeout);
}
return null;
} }
@Override @Override
@@ -204,18 +217,21 @@ public abstract class BaseRacingProcedure extends BaseRaceStateChangedListener i
} }
protected void update() { 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) { if (cachedIsIndividualRecallDisplayed != isRecallDisplayed) {
cachedIsIndividualRecallDisplayed = isRecallDisplayed; cachedIsIndividualRecallDisplayed = isRecallDisplayed;
if (cachedIsIndividualRecallDisplayed) { if (!cachedIsIndividualRecallDisplayed) {
changedListeners.onIndividualRecallDisplayed(this); // individual recall was removed; no need to schedule an event for removal
rescheduleIndividualRecallTimeout(recallDisplayedFinder.analyze());
} else {
changedListeners.onIndividualRecallRemoved(this); changedListeners.onIndividualRecallRemoved(this);
unscheduleStateEvent(RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT); 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 // 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 // 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); changedListeners.onActiveFlagsChanged(this);
} }
private void rescheduleIndividualRecallTimeout(TimePoint displayTime) { private void rescheduleIndividualRecallTimeout() {
unscheduleStateEvent(RaceStateEvents.INDIVIDUAL_RECALL_TIMEOUT); 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) { protected void scheduleStateEvents(RaceStateEvent stateEvent) {
@@ -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.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; 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.RacingProcedureFactory;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ReadonlyRacingProcedure; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ReadonlyRacingProcedure;
import com.sap.sailing.domain.base.configuration.ConfigurationLoader; import com.sap.sailing.domain.base.configuration.ConfigurationLoader;
@@ -22,7 +23,7 @@ public class RacingProcedureFactoryImpl extends ReadonlyRacingProcedureFactory i
} }
@Override @Override
public ReadonlyRacingProcedure createRacingProcedure(RacingProcedureType type, RaceLog raceLog) { public ReadonlyRacingProcedure createRacingProcedure(RacingProcedureType type, RaceLog raceLog, RaceLogResolver raceLogResolver) {
return createProcedure(type, raceLog, author, factory); return createProcedure(type, raceLog, author, factory, raceLogResolver);
} }
} }
@@ -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.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; 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.impl.NoAddingRaceLogWrapper;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedure; import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedure;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedureFactory; 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, protected ReadonlyRacingProcedure createProcedure(RacingProcedureType type, RaceLog raceLog,
AbstractLogEventAuthor author, RaceLogEventFactory factory) { AbstractLogEventAuthor author, RaceLogEventFactory factory, RaceLogResolver raceLogResolver) {
RegattaConfiguration loadedConfiguration = configuration.load(); RegattaConfiguration loadedConfiguration = configuration.load();
switch (type) { switch (type) {
case ESS: case ESS:
return new ESSRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getESSConfiguration()); return new ESSRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getESSConfiguration(), raceLogResolver);
case GateStart: case GateStart:
return new GateStartRacingProcedureImpl(raceLog, author, factory, return new GateStartRacingProcedureImpl(raceLog, author, factory,
loadedConfiguration.getGateStartConfiguration()); loadedConfiguration.getGateStartConfiguration(), raceLogResolver);
case RRS26: case RRS26:
return new RRS26RacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getRRS26Configuration()); return new RRS26RacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getRRS26Configuration(), raceLogResolver);
case BASIC: case BASIC:
return new BasicRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getBasicConfiguration()); return new BasicRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getBasicConfiguration(), raceLogResolver);
case LEAGUE: case LEAGUE:
return new LeagueRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getLeagueConfiguration()); return new LeagueRacingProcedureImpl(raceLog, author, factory, loadedConfiguration.getLeagueConfiguration(), raceLogResolver);
default: default:
throw new UnsupportedOperationException("Unknown racing procedure " + type.toString()); throw new UnsupportedOperationException("Unknown racing procedure " + type.toString());
} }
} }
@Override @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 // Just a mock author since we will never add anything to the racelog
AbstractLogEventAuthor author = new LogEventAuthorImpl("Illegal Author", 128); AbstractLogEventAuthor author = new LogEventAuthorImpl("Illegal Author", 128);
// Wrap the racelog to disable adding... // Wrap the racelog to disable adding...
RaceLog wrappedRaceLog = new NoAddingRaceLogWrapper(raceLog); RaceLog wrappedRaceLog = new NoAddingRaceLogWrapper(raceLog);
return createProcedure(type, wrappedRaceLog, author, RaceLogEventFactory.INSTANCE); return createProcedure(type, wrappedRaceLog, author, RaceLogEventFactory.INSTANCE, raceLogResolver);
} }
} }
@@ -7,6 +7,7 @@ import java.util.Collections;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; 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.RaceStateEvent;
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl; import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEventImpl;
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateEvents; 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; private final static Flags startmodeFlag = Flags.PAPA;
public LeagueRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, public LeagueRacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author,
RaceLogEventFactory factory, LeagueConfiguration configuration) { RaceLogEventFactory factory, LeagueConfiguration configuration, RaceLogResolver raceLogResolver) {
super(raceLog, author, factory, configuration); super(raceLog, author, factory, configuration, raceLogResolver);
update(); update();
} }
@@ -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.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; 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.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.analyzing.impl.RacingProcedureTypeAnalyzer;
import com.sap.sailing.domain.abstractlog.race.state.RaceStateEvent; 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.RaceStateEventImpl;
@@ -39,8 +40,8 @@ public class RRS26RacingProcedureImpl extends BaseRacingProcedure implements RRS
private boolean startmodeFlagHasBeenSet; private boolean startmodeFlagHasBeenSet;
public RRS26RacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author, public RRS26RacingProcedureImpl(RaceLog raceLog, AbstractLogEventAuthor author,
RaceLogEventFactory factory, RRS26Configuration configuration) { RaceLogEventFactory factory, RRS26Configuration configuration, RaceLogResolver raceLogResolver) {
super(raceLog, author, factory, configuration); super(raceLog, author, factory, configuration, raceLogResolver);
RacingProcedureTypeAnalyzer procedureAnalyzer = new RacingProcedureTypeAnalyzer(raceLog); RacingProcedureTypeAnalyzer procedureAnalyzer = new RacingProcedureTypeAnalyzer(raceLog);
if (configuration.getStartModeFlags() != null) { if (configuration.getStartModeFlags() != null) {
@@ -13,7 +13,8 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.xrr.resultimport, com.sap.sailing.xrr.resultimport,
com.sap.sse.common, com.sap.sse.common,
com.sap.sse, 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, Export-Package: com.sap.sailing.domain.swisstimingadapter,
com.sap.sailing.domain.swisstimingadapter.impl;x-friends:="com.sap.sailing.server.test" com.sap.sailing.domain.swisstimingadapter.impl;x-friends:="com.sap.sailing.server.test"
Import-Package: com.sap.sailing.xrr.schema, Import-Package: com.sap.sailing.xrr.schema,
@@ -4,6 +4,7 @@ import java.io.IOException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.text.ParseException; 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.BoatClass;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.racelog.RaceLogStore; import com.sap.sailing.domain.racelog.RaceLogStore;
@@ -54,13 +55,13 @@ public interface SwissTimingFactory {
BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis, BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore,
boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory, boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
TrackedRegattaRegistry trackedRegattaRegistry) throws InterruptedException, UnknownHostException, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws InterruptedException, UnknownHostException,
IOException, ParseException; IOException, ParseException;
RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription, RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription,
BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis, BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm, WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm,
DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws UnknownHostException, DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws UnknownHostException,
InterruptedException, IOException, ParseException; InterruptedException, IOException, ParseException;
Race createRace(String raceId, String raceName, String description, BoatClass boatClass); Race createRace(String raceId, String raceName, String description, BoatClass boatClass);
@@ -7,6 +7,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger; 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.BoatClass;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.racelog.RaceLogStore; import com.sap.sailing.domain.racelog.RaceLogStore;
@@ -89,23 +90,24 @@ public class SwissTimingFactoryImpl implements SwissTimingFactory {
@Override @Override
public SwissTimingRaceTracker createRaceTracker(String raceID, String raceName, String raceDescription, public SwissTimingRaceTracker createRaceTracker(String raceID, String raceName, String raceDescription,
BoatClass boatClass, String hostname, int port, BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
StartList startList, long delayToLiveInMillis, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore,
WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm, boolean useInternalMarkPassingAlgorithm, DomainFactory domainFactory,
DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws InterruptedException, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
UnknownHostException, IOException, ParseException { throws InterruptedException, UnknownHostException, IOException, ParseException {
return new SwissTimingRaceTrackerImpl(raceID, raceName, raceDescription, boatClass, hostname, port, startList, return new SwissTimingRaceTrackerImpl(raceID, raceName, raceDescription, boatClass, hostname, port, startList,
raceLogStore, regattaLogStore, windStore, gpsFixStore, domainFactory, this, raceLogStore, regattaLogStore, windStore, gpsFixStore, domainFactory, this,
trackedRegattaRegistry, delayToLiveInMillis, useInternalMarkPassingAlgorithm); trackedRegattaRegistry, raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm);
} }
@Override @Override
public RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription, BoatClass boatClass, String hostname, public RaceTracker createRaceTracker(Regatta regatta, String raceID, String raceName, String raceDescription,
int port, StartList startList, long delayToLiveInMillis, WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm, BoatClass boatClass, String hostname, int port, StartList startList, long delayToLiveInMillis,
DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws UnknownHostException, WindStore windStore, GPSFixStore gpsFixStore, boolean useInternalMarkPassingAlgorithm,
InterruptedException, IOException, ParseException { DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
return new SwissTimingRaceTrackerImpl(regatta, raceID, raceName, raceDescription, boatClass, hostname, port, startList, windStore, gpsFixStore, domainFactory, throws UnknownHostException, InterruptedException, IOException, ParseException {
this, trackedRegattaRegistry, delayToLiveInMillis, useInternalMarkPassingAlgorithm); return new SwissTimingRaceTrackerImpl(regatta, raceID, raceName, raceDescription, boatClass, hostname, port,
startList, windStore, gpsFixStore, domainFactory, this, trackedRegattaRegistry, raceLogResolver, delayToLiveInMillis, useInternalMarkPassingAlgorithm);
} }
@Override @Override
@@ -15,6 +15,7 @@ import java.util.TreeMap;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; 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.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorStore; 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)}. * tracker by calling {@link #receivedTimingData(String, String, List)}.
*/ */
private final TMDMessageQueue tmdMessageQueue; private final TMDMessageQueue tmdMessageQueue;
private final RaceLogResolver raceLogResolver;
protected SwissTimingRaceTrackerImpl(String raceID, String raceName, String raceDescription, BoatClass boatClass, protected SwissTimingRaceTrackerImpl(String raceID, String raceName, String raceDescription, BoatClass boatClass,
String hostname, int port, StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, String hostname, int port, StartList startList, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, DomainFactory domainFactory, SwissTimingFactory factory, 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 { UnknownHostException, IOException, ParseException {
this(domainFactory.getOrCreateDefaultRegatta(raceLogStore, regattaLogStore, raceID, this(domainFactory.getOrCreateDefaultRegatta(raceLogStore, regattaLogStore, raceID,
boatClass, trackedRegattaRegistry), raceID, raceName, boatClass, trackedRegattaRegistry), raceID, raceName,
raceDescription, boatClass, hostname, port, startList, windStore, gpsFixStore, domainFactory, factory, trackedRegattaRegistry, 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, protected SwissTimingRaceTrackerImpl(Regatta regatta, String raceID, String raceName, String raceDescription,
WindStore windStore, GPSFixStore gpsFixStore, DomainFactory domainFactory, SwissTimingFactory factory, BoatClass boatClass, String hostname, int port, StartList startList, WindStore windStore,
TrackedRegattaRegistry trackedRegattaRegistry, long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm) throws InterruptedException, GPSFixStore gpsFixStore, DomainFactory domainFactory, SwissTimingFactory factory,
UnknownHostException, IOException, ParseException { TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver,
long delayToLiveInMillis, boolean useInternalMarkPassingAlgorithm) throws InterruptedException, UnknownHostException, IOException,
ParseException {
super(); super();
this.raceLogResolver = raceLogResolver;
this.tmdMessageQueue = new TMDMessageQueue(this); this.tmdMessageQueue = new TMDMessageQueue(this);
this.regatta = regatta; this.regatta = regatta;
this.connector = factory.getOrCreateSailMasterConnector(hostname, port, raceID, raceName, raceDescription, boatClass); 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 // we already know our single RaceDefinition
assert SwissTimingRaceTrackerImpl.this.race == race; assert SwissTimingRaceTrackerImpl.this.race == race;
} }
}, useInternalMarkPassingAlgorithm); }, useInternalMarkPassingAlgorithm, raceLogResolver);
logger.info("Created SwissTiming RaceDefinition and TrackedRace for "+race.getName()); logger.info("Created SwissTiming RaceDefinition and TrackedRace for "+race.getName());
} }
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.swisstimingadapter.impl; 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.BoatClass;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.racelog.RaceLogStore; import com.sap.sailing.domain.racelog.RaceLogStore;
@@ -51,18 +52,18 @@ public class SwissTimingTrackingConnectivityParameters implements RaceTrackingCo
@Override @Override
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, 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, return swissTimingFactory.createRaceTracker(raceID, raceName, raceDescription, boatClass, hostname, port,
startList, delayToLiveInMillis, raceLogStore, regattaLogStore, windStore, gpsFixStore, useInternalMarkPassingAlgorithm, startList, delayToLiveInMillis, raceLogStore, regattaLogStore, windStore, gpsFixStore, useInternalMarkPassingAlgorithm,
domainFactory, trackedRegattaRegistry); domainFactory, trackedRegattaRegistry, raceLogResolver);
} }
@Override @Override
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, 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, return swissTimingFactory.createRaceTracker(regatta, raceID, raceName, raceDescription, boatClass, hostname,
port, startList, delayToLiveInMillis, windStore, gpsFixStore, useInternalMarkPassingAlgorithm, port, startList, delayToLiveInMillis, windStore, gpsFixStore, useInternalMarkPassingAlgorithm,
domainFactory, trackedRegattaRegistry); domainFactory, trackedRegattaRegistry, raceLogResolver);
} }
@Override @Override
@@ -10,4 +10,5 @@ Import-Package: org.json.simple,
org.json.simple.parser org.json.simple.parser
Require-Bundle: com.sap.sailing.domain.test, Require-Bundle: com.sap.sailing.domain.test,
org.junit4;bundle-version="4.8.2", org.junit4;bundle-version="4.8.2",
com.sap.sse.common com.sap.sse.common,
org.mockito.mockito-core;bundle-version="1.10.14"
@@ -17,6 +17,9 @@ import java.util.Map;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; 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.swisstimingadapter.DomainFactory;
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayRace; import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayRace;
import com.sap.sailing.domain.swisstimingreplayadapter.impl.SwissTimingRaceConfig; import com.sap.sailing.domain.swisstimingreplayadapter.impl.SwissTimingRaceConfig;
@@ -30,13 +33,13 @@ public class SwissTimingRaceConfigurationTest {
@Test @Test
public void testLoadConfigurations() throws IOException, ParseException, org.json.simple.parser.ParseException { public void testLoadConfigurations() throws IOException, ParseException, org.json.simple.parser.ParseException {
InputStream inputStream = getClass().getResourceAsStream(JSON_URL); InputStream inputStream = getClass().getResourceAsStream(JSON_URL);
List<SwissTimingReplayRace> races = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE).parseJSONObject(inputStream , JSON_URL); List<SwissTimingReplayRace> races = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class)).parseJSONObject(inputStream , JSON_URL);
Map<String, SwissTimingRaceConfig> configsById = new HashMap<String, SwissTimingRaceConfig>(); Map<String, SwissTimingRaceConfig> configsById = new HashMap<String, SwissTimingRaceConfig>();
for (SwissTimingReplayRace race : races) { for (SwissTimingReplayRace race : races) {
URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, race.getRaceId())); URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, race.getRaceId()));
URLConnection connection = configFileURL.openConnection(); URLConnection connection = configFileURL.openConnection();
InputStream configDataStream = connection.getInputStream(); 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); configsById.put(race.getRaceId(), raceConfig);
} }
} }
@@ -46,7 +49,7 @@ public class SwissTimingRaceConfigurationTest {
URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, "446483")); URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, "446483"));
URLConnection connection = configFileURL.openConnection(); URLConnection connection = configFileURL.openConnection();
InputStream configDataStream = connection.getInputStream(); 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); assertNotNull(config_446483);
assertEquals("GB", config_446483.country_code); assertEquals("GB", config_446483.country_code);
assertNull(config_446483.event_name); assertNull(config_446483.event_name);
@@ -63,7 +66,7 @@ public class SwissTimingRaceConfigurationTest {
URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, "6260")); URL configFileURL = new URL(MessageFormat.format(SwissTimingReplayServiceImpl.RACE_CONFIG_URL_TEMPLATE, "6260"));
URLConnection connection = configFileURL.openConnection(); URLConnection connection = configFileURL.openConnection();
InputStream configDataStream = connection.getInputStream(); 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); assertNotNull(config_446483);
assertEquals("GB", config_446483.country_code); assertEquals("GB", config_446483.country_code);
assertEquals("London 2012 Olympic Games", config_446483.event_name); assertEquals("London 2012 Olympic Games", config_446483.event_name);
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.swisstimingreplayadapter.test; package com.sap.sailing.domain.swisstimingreplayadapter.test;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.mockito.Mockito.mock;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
@@ -16,6 +17,7 @@ import java.util.List;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; 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.Competitor;
import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.swisstimingadapter.DomainFactory; import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
@@ -33,7 +35,7 @@ public class SwissTimingReplayAdapterServiceTest {
public void testLoadRaceJson() throws Exception { public void testLoadRaceJson() throws Exception {
String swissTimingUrlText = "/2012_OSG.json"; String swissTimingUrlText = "/2012_OSG.json";
InputStream inputStream = getClass().getResourceAsStream(swissTimingUrlText); InputStream inputStream = getClass().getResourceAsStream(swissTimingUrlText);
final SwissTimingReplayServiceImpl swissTimingReplayService = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE); final SwissTimingReplayServiceImpl swissTimingReplayService = new SwissTimingReplayServiceImpl(DomainFactory.INSTANCE, mock(RaceLogResolver.class));
List<SwissTimingReplayRace> races = swissTimingReplayService.parseJSONObject(inputStream , swissTimingUrlText); List<SwissTimingReplayRace> races = swissTimingReplayService.parseJSONObject(inputStream , swissTimingUrlText);
assertEquals(201, races.size()); assertEquals(201, races.size());
assertEquals("446483", races.get(0).getRaceId()); assertEquals("446483", races.get(0).getRaceId());
@@ -178,7 +180,7 @@ public class SwissTimingReplayAdapterServiceTest {
@Test @Test
public void testRaceData_SAW010955_20120802_WithDomainAdapter() throws Exception { public void testRaceData_SAW010955_20120802_WithDomainAdapter() throws Exception {
SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, DomainFactory.INSTANCE, 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); new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAW005906.20120805.replay"), replayListener);
Iterable<? extends TrackedRace> trackedRaces = replayListener.getTrackedRaces(); Iterable<? extends TrackedRace> trackedRaces = replayListener.getTrackedRaces();
assertFalse(Util.isEmpty(trackedRaces)); assertFalse(Util.isEmpty(trackedRaces));
@@ -192,7 +194,7 @@ public class SwissTimingReplayAdapterServiceTest {
@Test @Test
public void testStartPerformanceDetection() throws Exception { public void testStartPerformanceDetection() throws Exception {
SwissTimingReplayToDomainAdapter replayListener = new SwissTimingReplayToDomainAdapter(null, DomainFactory.INSTANCE, 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); new SwissTimingReplayParserImpl().readData(getClass().getResourceAsStream("/SAW005906.20120805.replay"), replayListener);
Iterable<? extends TrackedRace> trackedRaces = replayListener.getTrackedRaces(); Iterable<? extends TrackedRace> trackedRaces = replayListener.getTrackedRaces();
TrackedRace trackedRace = trackedRaces.iterator().next(); TrackedRace trackedRace = trackedRaces.iterator().next();
@@ -12,7 +12,8 @@ Require-Bundle: com.sap.sailing.domain.common,
com.sap.sailing.domain.swisstimingadapter, com.sap.sailing.domain.swisstimingadapter,
com.googlecode.java-diff-utils;bundle-version="1.3.0", com.googlecode.java-diff-utils;bundle-version="1.3.0",
com.sap.sse, com.sap.sse,
com.sap.sse.common com.sap.sse.common,
com.sap.sailing.domain.shared.android
Export-Package: com.sap.sailing.domain.swisstimingreplayadapter Export-Package: com.sap.sailing.domain.swisstimingreplayadapter
Import-Package: org.osgi.framework;version="1.7.0" Import-Package: org.osgi.framework;version="1.7.0"
Bundle-Activator: com.sap.sailing.domain.swisstimingreplayadapter.impl.Activator Bundle-Activator: com.sap.sailing.domain.swisstimingreplayadapter.impl.Activator
@@ -1,10 +1,11 @@
package com.sap.sailing.domain.swisstimingreplayadapter; 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.swisstimingadapter.DomainFactory;
import com.sap.sailing.domain.swisstimingreplayadapter.impl.SwissTimingReplayServiceFactoryImpl; import com.sap.sailing.domain.swisstimingreplayadapter.impl.SwissTimingReplayServiceFactoryImpl;
public interface SwissTimingReplayServiceFactory { public interface SwissTimingReplayServiceFactory {
static SwissTimingReplayServiceFactory INSTANCE = new SwissTimingReplayServiceFactoryImpl(); static SwissTimingReplayServiceFactory INSTANCE = new SwissTimingReplayServiceFactoryImpl();
SwissTimingReplayService createSwissTimingReplayService(DomainFactory domainFactory); SwissTimingReplayService createSwissTimingReplayService(DomainFactory domainFactory, RaceLogResolver raceLogResolver);
} }
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.swisstimingreplayadapter.impl;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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.swisstimingadapter.DomainFactory;
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayService; import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayService;
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayServiceFactory; import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayServiceFactory;
@@ -15,10 +16,10 @@ public class SwissTimingReplayServiceFactoryImpl implements SwissTimingReplaySer
} }
@Override @Override
public SwissTimingReplayService createSwissTimingReplayService(DomainFactory domainFactory) { public SwissTimingReplayService createSwissTimingReplayService(DomainFactory domainFactory, RaceLogResolver raceLogResolver) {
SwissTimingReplayService result = servicesForDomainFactories.get(domainFactory); SwissTimingReplayService result = servicesForDomainFactories.get(domainFactory);
if (result == null) { if (result == null) {
result = new SwissTimingReplayServiceImpl(domainFactory); result = new SwissTimingReplayServiceImpl(domainFactory, raceLogResolver);
servicesForDomainFactories.put(domainFactory, result); servicesForDomainFactories.put(domainFactory, result);
} }
return result; return result;
@@ -18,6 +18,7 @@ import org.json.simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser; 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.base.Regatta;
import com.sap.sailing.domain.swisstimingadapter.DomainFactory; import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayListener; 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 static final TimeZone DEFAULT_TIMEZONE = TimeZone.getTimeZone("GMT");
private final DomainFactory domainFactory; private final DomainFactory domainFactory;
private final RaceLogResolver raceLogResolver;
public SwissTimingReplayServiceImpl(DomainFactory domainFactory) { public SwissTimingReplayServiceImpl(DomainFactory domainFactory, RaceLogResolver raceLogResolver) {
this.domainFactory = domainFactory; this.domainFactory = domainFactory;
this.raceLogResolver = raceLogResolver;
} }
@Override @Override
@@ -143,8 +146,10 @@ public class SwissTimingReplayServiceImpl implements SwissTimingReplayService {
} }
@Override @Override
public void loadRaceData(String link, Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm) { public void loadRaceData(String link, Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
SwissTimingReplayListener listener = new SwissTimingReplayToDomainAdapter(regatta, domainFactory, trackedRegattaRegistry, useInternalMarkPassingAlgorithm); boolean useInternalMarkPassingAlgorithm) {
SwissTimingReplayListener listener = new SwissTimingReplayToDomainAdapter(regatta, domainFactory,
trackedRegattaRegistry, useInternalMarkPassingAlgorithm, raceLogResolver);
loadRaceData(link, listener); loadRaceData(link, listener);
} }
} }
@@ -15,6 +15,7 @@ import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.logging.Logger; 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.Competitor;
import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
@@ -136,6 +137,8 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
private RaceStatus lastRaceStatus; private RaceStatus lastRaceStatus;
private final boolean useInternalMarkPassingAlgorithm; private final boolean useInternalMarkPassingAlgorithm;
private final RaceLogResolver raceLogResolver;
/** /**
* @param regatta * @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 * @param useInternalMarkPassingAlgorithm use our own instead of the SwissTiming-provided mark rounding / split times
*/ */
public SwissTimingReplayToDomainAdapter(Regatta regatta, DomainFactory domainFactory, public SwissTimingReplayToDomainAdapter(Regatta regatta, DomainFactory domainFactory,
TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm) { TrackedRegattaRegistry trackedRegattaRegistry, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver) {
this.raceLogResolver = raceLogResolver;
this.regatta = regatta; this.regatta = regatta;
this.trackedRegattaRegistry = trackedRegattaRegistry; this.trackedRegattaRegistry = trackedRegattaRegistry;
racePerRaceID = new HashMap<>(); racePerRaceID = new HashMap<>();
@@ -317,7 +321,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
createTrackedRace(race, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,TrackedRace.DEFAULT_LIVE_DELAY_IN_MILLISECONDS, createTrackedRace(race, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,TrackedRace.DEFAULT_LIVE_DELAY_IN_MILLISECONDS,
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND,
/* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(), /* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
/* raceDefinitionSetToUpdate */ null, useInternalMarkPassingAlgorithm); /* raceDefinitionSetToUpdate */ null, useInternalMarkPassingAlgorithm, raceLogResolver);
trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, 0)); trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, 0));
TimePoint bestStartTimeKnownSoFar = bestStartTimePerRaceID.get(currentRaceID); TimePoint bestStartTimeKnownSoFar = bestStartTimePerRaceID.get(currentRaceID);
if (bestStartTimeKnownSoFar != null) { if (bestStartTimeKnownSoFar != null) {
@@ -12,6 +12,7 @@ import java.util.function.Function;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; 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.ControlPointWithTwoMarks;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.DomainFactory; 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, trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, Collections.emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,
/* delayToLiveInMillis */ 8000, /* millisecondsOverWhichToAverageWind */ 30000, /* delayToLiveInMillis */ 8000, /* millisecondsOverWhichToAverageWind */ 30000,
/* millisecondsOverWhichToAverageSpeed */ 15000, /* delayForCacheInvalidationOfWindEstimation */ 10000, /* millisecondsOverWhichToAverageSpeed */ 15000, /* delayForCacheInvalidationOfWindEstimation */ 10000,
/* useInternalMarkPassingAlgorithm */ false, OneDesignRankingMetric::new); /* useInternalMarkPassingAlgorithm */ false, OneDesignRankingMetric::new, mock(RaceLogResolver.class));
timeRangeResolution = Duration.ONE_MINUTE; timeRangeResolution = Duration.ONE_MINUTE;
now = new MillisecondsTimePoint(MillisecondsTimePoint.now().asMillis() / timeRangeResolution.asMillis() * timeRangeResolution.asMillis()); now = new MillisecondsTimePoint(MillisecondsTimePoint.now().asMillis() / timeRangeResolution.asMillis() * timeRangeResolution.asMillis());
trackedRace.getOrCreateTrack(pinEnd).addGPSFix(new GPSFixImpl(new DegreePosition(0, -0.0000001), now)); trackedRace.getOrCreateTrack(pinEnd).addGPSFix(new GPSFixImpl(new DegreePosition(0, -0.0000001), now));
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.ranking;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -12,6 +13,7 @@ import java.util.function.Function;
import org.junit.Test; 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.Competitor;
import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
@@ -91,7 +93,7 @@ public class TestSimpleTimeOnTimeRankingWithOneUpwindLeg {
/* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false, /* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false,
tr->new TimeOnTimeAndDistanceRankingMetric(tr, tr->new TimeOnTimeAndDistanceRankingMetric(tr,
timeOnTimeFactors, // time-on-time 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 // in this simplified artificial course, the top mark is exactly north of the right leeward gate
DegreePosition topPosition = new DegreePosition(1, 0); DegreePosition topPosition = new DegreePosition(1, 0);
trackedRace.getOrCreateTrack(left).addGPSFix(new GPSFixImpl(new DegreePosition(0, -0.000001), timePointForFixes)); trackedRace.getOrCreateTrack(left).addGPSFix(new GPSFixImpl(new DegreePosition(0, -0.000001), timePointForFixes));
@@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -15,6 +16,7 @@ import java.util.Set;
import org.junit.Test; 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.ControlPoint;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.DomainFactory; 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), new RaceDefinitionImpl("Test Race", course, new BoatClassImpl("49er", /* upwind start */true), hasso),
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,/* delayToLiveInMillis */3000, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,/* delayToLiveInMillis */3000,
/* millisecondsOverWhichToAverageWind */30000, /* millisecondsOverWhichToAverageWind */30000,
/* millisecondsOverWhichToAverageSpeed */8000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); /* millisecondsOverWhichToAverageSpeed */8000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class));
assertLegStructure(course, trackedRace); assertLegStructure(course, trackedRace);
course.removeWaypoint(0); course.removeWaypoint(0);
assertLegStructure(course, trackedRace); assertLegStructure(course, trackedRace);
@@ -335,7 +338,8 @@ public class CourseTest {
hasso), Collections.<Sideline> emptyList(), hasso), Collections.<Sideline> emptyList(),
EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 3000, EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 3000,
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageWind */ 30000,
/* millisecondsOverWhichToAverageSpeed */ 8000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); /* millisecondsOverWhichToAverageSpeed */ 8000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class));
assertLegStructure(course, trackedRace); assertLegStructure(course, trackedRace);
final WaypointImpl wp1_5 = new WaypointImpl(new MarkImpl("Test Mark 1.5")); final WaypointImpl wp1_5 = new WaypointImpl(new MarkImpl("Test Mark 1.5"));
assertWaypointIndexes(course); assertWaypointIndexes(course);
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@@ -19,6 +20,7 @@ import java.util.UUID;
import org.junit.Test; 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.Competitor;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.RaceDefinition;
@@ -81,7 +83,7 @@ public class CourseUpdateDuringNonAtomicSerializationTest implements Serializabl
trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, Collections.<Sideline> emptySet(), trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, Collections.<Sideline> emptySet(),
EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,
/* delayToLiveInMillis */10000, /* millisecondsOverWhichToAverageWind */30000, /* millisecondsOverWhichToAverageSpeed */ /* delayToLiveInMillis */10000, /* millisecondsOverWhichToAverageWind */30000, /* millisecondsOverWhichToAverageSpeed */
7000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new) { 7000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new, mock(RaceLogResolver.class)) {
private static final long serialVersionUID = 9114777576548711763L; private static final long serialVersionUID = 9114777576548711763L;
@Override @Override
@@ -20,7 +20,9 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; 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.Competitor;
import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
@@ -91,7 +93,8 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
} }
}, },
/* delayToLiveInMillis */0l, /* millisecondsOverWhichToAverageWind */30000, /* simulator */null, /* courseDesignUpdateURI */ /* 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 @Override
protected void handleEvent(Triple<IControlRoute, Long, Void> event) { protected void handleEvent(Triple<IControlRoute, Long, Void> event) {
super.handleEvent(event); super.handleEvent(event);
@@ -14,6 +14,7 @@ import java.util.concurrent.ExecutionException;
import org.junit.Test; 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.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.ControlPoint;
@@ -138,7 +139,8 @@ public class LeaderboardCourseChangeTest {
TrackedRegatta mockedTrackedRegatta = createMockedTrackedRegatta(regatta); TrackedRegatta mockedTrackedRegatta = createMockedTrackedRegatta(regatta);
RaceDefinition mockedRace = createMockedRace(course, boatClass); RaceDefinition mockedRace = createMockedRace(course, boatClass);
TrackedRace spyedTrackedRace = spy(new DynamicTrackedRaceImpl(mockedTrackedRegatta, mockedRace, TrackedRace spyedTrackedRace = spy(new DynamicTrackedRaceImpl(mockedTrackedRegatta, mockedRace,
new HashSet<Sideline>(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, 5000, 20000, 20000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new)); new HashSet<Sideline>(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, 5000, 20000, 20000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class)));
return spyedTrackedRace; return spyedTrackedRace;
} }
@@ -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<Competitor, GPSFixMoving> 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));
}
}
@@ -10,10 +10,13 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import static org.mockito.Mockito.mock;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; 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.impl.EmptyRaceLogStore;
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore; import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore; import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
@@ -61,7 +64,7 @@ public class MultipleClassesInRegattaTest {
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE, false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword, EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY, TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
new DummyTrackedRegattaRegistry()); new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class));
kiwotest2 = domainFactory kiwotest2 = domainFactory
.createRaceTracker( .createRaceTracker(
new URL( new URL(
@@ -72,7 +75,7 @@ public class MultipleClassesInRegattaTest {
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE, false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword, EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY, TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
new DummyTrackedRegattaRegistry()); new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class));
kiwotest3 = domainFactory kiwotest3 = domainFactory
.createRaceTracker( .createRaceTracker(
new URL( new URL(
@@ -83,7 +86,7 @@ public class MultipleClassesInRegattaTest {
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE, false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword, EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY, TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
new DummyTrackedRegattaRegistry()); new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class));
weym470may112014_2 = domainFactory weym470may112014_2 = domainFactory
.createRaceTracker( .createRaceTracker(
new URL( new URL(
@@ -94,7 +97,7 @@ public class MultipleClassesInRegattaTest {
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE, false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword, EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY, TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
new DummyTrackedRegattaRegistry()); new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class));
assertEquals("STG", kiwotest1.getRegatta().getBoatClass().getName()); assertEquals("STG", kiwotest1.getRegatta().getBoatClass().getName());
assertEquals("5O5", kiwotest2.getRegatta().getBoatClass().getName()); assertEquals("5O5", kiwotest2.getRegatta().getBoatClass().getName());
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@@ -18,6 +19,7 @@ import java.util.regex.Pattern;
import org.junit.Before; 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.Competitor;
import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.RaceDefinition;
@@ -113,8 +115,8 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest {
ArrayList<Receiver> receivers = new ArrayList<Receiver>(); ArrayList<Receiver> receivers = new ArrayList<Receiver>();
for (Receiver r : domainFactory.getUpdateReceivers(trackedRegatta, getTracTracRace(), EmptyWindStore.INSTANCE, /* delayToLiveInMillis */0l, /* simulator */null, createRaceDefinitionSet(), for (Receiver r : domainFactory.getUpdateReceivers(trackedRegatta, getTracTracRace(), EmptyWindStore.INSTANCE, /* delayToLiveInMillis */0l, /* simulator */null, createRaceDefinitionSet(),
/* trackedRegattaRegistry */null, /* trackedRegattaRegistry */null,
/* courseDesignUpdateURI */null, /* tracTracUsername */null, null, /* tracTracPassword */ mock(RaceLogResolver.class), /* courseDesignUpdateURI */null, /* tracTracUsername */null, /* tracTracPassword */
getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, receiverTypes)) { null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, receiverTypes)) {
receivers.add(r); receivers.add(r);
} }
getRaceSubscriber().subscribeConnectionStatus(new IConnectionStatusListener() { getRaceSubscriber().subscribeConnectionStatus(new IConnectionStatusListener() {
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -12,6 +13,7 @@ import java.util.List;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; 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.Competitor;
import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
@@ -109,7 +111,7 @@ public class ReachingLegTest extends TrackBasedTest {
EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0,
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000, /* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
/* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false, /* 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 // 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 // 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); Position leftPosition = new DegreePosition(0, -0.00001);
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.test;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@@ -11,6 +12,7 @@ import java.util.List;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; 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.RaceDefinition;
import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl; 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) { public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) {
} }
}, /* trackedRegattaRegistry */null, }, /* trackedRegattaRegistry */null,
/* courseDesignUpdateURI */null, /* tracTracUsername */null, null, /* tracTracPassword */ mock(RaceLogResolver.class), /* courseDesignUpdateURI */null, /* tracTracUsername */null, /* tracTracPassword */
getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, ReceiverType.RACECOURSE, ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH, null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false, ReceiverType.RACECOURSE, ReceiverType.MARKPOSITIONS,
ReceiverType.RAWPOSITIONS)) { ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS)) {
receivers.add(r); receivers.add(r);
} }
addListenersForStoredDataAndStartController(receivers); addListenersForStoredDataAndStartController(receivers);
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.test; package com.sap.sailing.domain.test;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@@ -8,6 +9,7 @@ import java.net.URISyntaxException;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; 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.Competitor;
import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
@@ -83,8 +85,8 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest {
public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) { public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) {
} }
}, },
/* trackedRegattaRegistry */null, getTracTracRace(), null, /* courseDesignUpdateURI */ /* trackedRegattaRegistry */null, mock(RaceLogResolver.class), getTracTracRace(), /* courseDesignUpdateURI */
/* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false)) { null, /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false)) {
receiver.subscribe(); receiver.subscribe();
getRaceSubscriber().start(); getRaceSubscriber().start();
} }
@@ -95,8 +97,8 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest {
@Override @Override
public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) { public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) {
} }
}, /* trackedRegattaRegistry */null, getTracTracRace(), null, /* courseDesignUpdateURI */ }, /* trackedRegattaRegistry */null, mock(RaceLogResolver.class), getTracTracRace(), /* courseDesignUpdateURI */
/* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false)); null, /* tracTracUsername */null, /* tracTracPassword */null, getEventSubscriber(), getRaceSubscriber(), /*ignoreTracTracMarkPassings*/ false));
} }
@Test @Test
@@ -12,6 +12,7 @@ import java.util.Collections;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; 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.Competitor;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.Mark;
@@ -87,7 +88,8 @@ public class StarbordSideOfStartLineRecognitionTest {
private static final long serialVersionUID = -8007932232555073829L; private static final long serialVersionUID = -8007932232555073829L;
public MockedTrackedRaceImpl() { public MockedTrackedRaceImpl() {
super(null, null, Collections.<Sideline> emptyList(), null, null, 0, 0, 0, 0, false, OneDesignRankingMetric::new); super(null, null, Collections.<Sideline> emptyList(), null, null, 0, 0, 0, 0, false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class));
} }
@Override @Override
@@ -1,11 +1,14 @@
package com.sap.sailing.domain.test; package com.sap.sailing.domain.test;
import static org.mockito.Mockito.mock;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.UUID; 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.Competitor;
import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
@@ -119,7 +122,7 @@ public abstract class TrackBasedTest {
EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0,
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000, /* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
/* delay for wind estimation cache invalidation */ 0, /*useMarkPassingCalculator*/ false, /* 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 // in this simplified artificial course, the top mark is exactly north of the right leeward gate
DegreePosition topPosition = new DegreePosition(54.48, 10.24); DegreePosition topPosition = new DegreePosition(54.48, 10.24);
TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix timed TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix timed
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.test; package com.sap.sailing.domain.test;
import java.io.BufferedReader; import java.io.BufferedReader;
import static org.mockito.Mockito.mock;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@@ -15,6 +16,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.Timeout; 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.base.Competitor;
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore; import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore; import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
@@ -68,7 +70,7 @@ public class UnicodeCharactersInCompetitorNamesTest {
/* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/ /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, "tracTest", "tracTest", "", "", EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, "tracTest", "tracTest", "", "",
new DummyTrackedRegattaRegistry()); new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class));
Iterable<Competitor> competitors = fourtyninerYellow_2.getRacesHandle().getRace().getCompetitors(); Iterable<Competitor> competitors = fourtyninerYellow_2.getRacesHandle().getRace().getCompetitors();
for (Competitor competitor : competitors) { for (Competitor competitor : competitors) {
@@ -10,6 +10,7 @@ import java.util.HashSet;
import org.junit.Test; 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.Competitor;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.RaceDefinition; 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<Series>(), false, null, /* trackedRegatta */new DynamicTrackedRegattaImpl(new RegattaImpl("test", null, null, null, new HashSet<Series>(), false, null,
"test", null, OneDesignRankingMetric::new)), race, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, "test", null, OneDesignRankingMetric::new)), race, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,
/* delayToLiveInMillis */1000, /* millisecondsOverWhichToAverageWind */30000, /* delayToLiveInMillis */1000, /* millisecondsOverWhichToAverageWind */30000,
/* millisecondsOverWhichToAverageSpeed */30000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); /* millisecondsOverWhichToAverageSpeed */30000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new, mock(RaceLogResolver.class));
TimePoint now = MillisecondsTimePoint.now(); TimePoint now = MillisecondsTimePoint.now();
TimePoint later = now.plus(1000); TimePoint later = now.plus(1000);
trackedRace.updateMarkPassings(competitor, Arrays.asList(new MarkPassing[] { new MarkPassingImpl(now, waypoint, competitor) })); trackedRace.updateMarkPassings(competitor, Arrays.asList(new MarkPassing[] { new MarkPassingImpl(now, waypoint, competitor) }));
@@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@@ -16,6 +17,7 @@ import java.util.Set;
import org.junit.Test; 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.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.ControlPoint;
@@ -287,7 +289,8 @@ public class WindTest {
boatClass, Collections.singleton(competitor)), Collections.<Sideline> emptyList(), boatClass, Collections.singleton(competitor)), Collections.<Sideline> emptyList(),
EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 1000, EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 1000,
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageWind */ 30000,
/* millisecondsOverWhichToAverageSpeed */ 30000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); /* millisecondsOverWhichToAverageSpeed */ 30000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class));
TimePoint start = MillisecondsTimePoint.now(); TimePoint start = MillisecondsTimePoint.now();
TimePoint topMarkRounding = start.plus(30000); TimePoint topMarkRounding = start.plus(30000);
TimePoint finish = topMarkRounding.plus(30000); TimePoint finish = topMarkRounding.plus(30000);
@@ -5,6 +5,9 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; 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.Competitor;
import com.sap.sailing.domain.base.ControlPointWithTwoMarks; import com.sap.sailing.domain.base.ControlPointWithTwoMarks;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
@@ -55,7 +58,6 @@ public class AbstractMockedRaceMarkPassingTest {
public AbstractMockedRaceMarkPassingTest() { public AbstractMockedRaceMarkPassingTest() {
ControlPointWithTwoMarks cp = new ControlPointWithTwoMarksImpl(gate1, gate2, "cp"); ControlPointWithTwoMarks cp = new ControlPointWithTwoMarksImpl(gate1, gate2, "cp");
Waypoint w1 = new WaypointImpl(cp, PassingInstruction.Line); Waypoint w1 = new WaypointImpl(cp, PassingInstruction.Line);
Waypoint w2 = new WaypointImpl(m, PassingInstruction.Port); Waypoint w2 = new WaypointImpl(m, PassingInstruction.Port);
Waypoint w3 = new WaypointImpl(cp, PassingInstruction.Gate); Waypoint w3 = new WaypointImpl(cp, PassingInstruction.Gate);
@@ -68,7 +70,8 @@ public class AbstractMockedRaceMarkPassingTest {
new ArrayList<String>(), null)), true, new HighPoint(), "ID", new CourseAreaImpl("area", new UUID(5, 5)), OneDesignRankingMetric::new); new ArrayList<String>(), null)), true, new HighPoint(), "ID", new CourseAreaImpl("area", new UUID(5, 5)), OneDesignRankingMetric::new);
Course course = new CourseImpl("course", waypoints); Course course = new CourseImpl("course", waypoints);
RaceDefinition raceDef = new RaceDefinitionImpl("Performance Race", course, boatClass, Arrays.asList(ron, tom, ben)); RaceDefinition raceDef = new RaceDefinitionImpl("Performance Race", course, boatClass, Arrays.asList(ron, tom, ben));
race = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl(r), raceDef, new ArrayList<Sideline>(), new EmptyWindStore(), EmptyGPSFixStore.INSTANCE, 0, 10000, 10000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new); race = new DynamicTrackedRaceImpl(new DynamicTrackedRegattaImpl(r), raceDef, new ArrayList<Sideline>(), new EmptyWindStore(), EmptyGPSFixStore.INSTANCE, 0, 10000, 10000, /*useMarkPassingCalculator*/ false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class));
race.setStartTimeReceived(new MillisecondsTimePoint(10000)); race.setStartTimeReceived(new MillisecondsTimePoint(10000));
TimePoint t = new MillisecondsTimePoint(30000); TimePoint t = new MillisecondsTimePoint(30000);
List<Util.Pair<Mark, Position>> pos = Arrays.asList(new Util.Pair<Mark, Position>(m, new DegreePosition(0, 0)), List<Util.Pair<Mark, Position>> pos = Arrays.asList(new Util.Pair<Mark, Position>(m, new DegreePosition(0, 0)),
@@ -8,6 +8,7 @@ import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import com.sap.sailing.domain.abstractlog.race.RaceLog; 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.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor; 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.EventFetcher;
import com.sap.sailing.domain.base.Leg; import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Mark; 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.RaceColumnListener;
import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
@@ -462,6 +464,11 @@ public class MockedTrackedRace implements DynamicTrackedRace {
public Duration getTimeOnDistanceAllowancePerNauticalMile(Competitor competitor) { public Duration getTimeOnDistanceAllowancePerNauticalMile(Competitor competitor) {
return null; 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<Sideline> sidelines, public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines,
WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingcalculator) { DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingcalculator, RaceLogResolver raceLogResolver) {
return null; return null;
} }
@@ -12,7 +12,8 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sailing.server.gateway.serialization;bundle-version="1.0.0", com.sap.sailing.server.gateway.serialization;bundle-version="1.0.0",
com.sap.sse, com.sap.sse,
com.sap.sse.common, 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, Export-Package: com.sap.sailing.domain.tractracadapter,
com.sap.sailing.domain.tractracadapter.impl; com.sap.sailing.domain.tractracadapter.impl;
x-friends:="com.sap.sailing.domain.test, x-friends:="com.sap.sailing.domain.test,
@@ -11,6 +11,7 @@ import java.text.ParseException;
import java.util.List; import java.util.List;
import java.util.UUID; 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.BoatClass;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Mark; 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 * 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 * 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. * 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, TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword, 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; throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException, SubscriberInitializationException;
/** /**
* Same as {@link #createRaceTracker(URL, URI, URI, URI, TimePoint, TimePoint, WindStore, TrackedRegattaRegistry)}, only that * 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. * 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, RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword, 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, throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException,
SubscriberInitializationException; SubscriberInitializationException;
@@ -166,15 +169,16 @@ public interface DomainFactory {
* must have been created before through * must have been created before through
* {@link #getOrCreateTrackedRegatta(com.sap.sailing.domain.base.Regatta)} because otherwise the link to * {@link #getOrCreateTrackedRegatta(com.sap.sailing.domain.base.Regatta)} because otherwise the link to
* the {@link IEvent} can't be established * the {@link IEvent} can't be established
* @param raceLogResolver TODO
* @param tokenToRetrieveAssociatedRace * @param tokenToRetrieveAssociatedRace
* used to update the set of{@link RaceDefinition}s received by the {@link RaceCourseReceiver} created by * used to update the set of{@link RaceDefinition}s received by the {@link RaceCourseReceiver} created by
* this call * this call
*/ */
Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, long delayToLiveInMillis, Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, long delayToLiveInMillis,
Simulator simulator, WindStore windStore, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, Simulator simulator, WindStore windStore, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry,
IRace tractracRace, URI courseDesignUpdateURI, RaceLogResolver raceLogResolver, IRace tractracRace,
String tracTracUsername, String tracTracPassword, IEventSubscriber eventSubscriber, URI courseDesignUpdateURI, String tracTracUsername, String tracTracPassword,
IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm); IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm);
/** /**
* Creates a {@link RaceDefinition} from a TracTrac {@link Race} and a domain {@link Course} definition. The * 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 * 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#getAllRaces() known} by its containing
* {@link com.sap.sailing.domain.base.Regatta}. * {@link com.sap.sailing.domain.base.Regatta}.
*
* @param raceDefinitionSetToUpdate * @param raceDefinitionSetToUpdate
* if not <code>null</code>, after creating the {@link TrackedRace}, the {@link RaceDefinition} is * if not <code>null</code>, after creating the {@link TrackedRace}, the {@link RaceDefinition} is
* {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that * {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that
* object. * object.
* @param raceLogResolver TODO
*/ */
DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(DynamicTrackedRegatta trackedRegatta, UUID raceId, DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(DynamicTrackedRegatta trackedRegatta, UUID raceId,
String raceName, Iterable<com.sap.sailing.domain.base.Competitor> competitors, BoatClass boatClass, String raceName, Iterable<com.sap.sailing.domain.base.Competitor> competitors, BoatClass boatClass,
Course course, Iterable<Sideline> sidelines, WindStore windStore, long delayToLiveInMillis, Course course, Iterable<Sideline> sidelines, WindStore windStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, 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 * 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 * If the vm argument tractrac.usemarkpassings=false, the RecieverType MARKPASSINGS will not return anything
* @param raceLogResolver TODO
*/ */
Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, IRace tractracRace, WindStore windStore, Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, IRace tractracRace, WindStore windStore,
long delayToLiveInMillis, Simulator simulator, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, long delayToLiveInMillis, Simulator simulator, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry,
URI courseDesignUpdateURI, String tracTracUsername, RaceLogResolver raceLogResolver, URI courseDesignUpdateURI,
String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean ignoreTracTracMarkPassings, ReceiverType... types); 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; JSONService parseJSONURLWithRaceRecords(URL jsonURL, boolean loadClientParams) throws IOException, ParseException, org.json.simple.parser.ParseException, URISyntaxException;
@@ -19,6 +19,7 @@ import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; 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.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorStore; import com.sap.sailing.domain.base.CompetitorStore;
@@ -404,18 +405,19 @@ public class DomainFactoryImpl implements DomainFactory {
@Override @Override
public Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, IRace tractracRace, public Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, IRace tractracRace,
WindStore windStore, long delayToLiveInMillis, Simulator simulator, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, WindStore windStore, long delayToLiveInMillis, Simulator simulator, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
TrackedRegattaRegistry trackedRegattaRegistry, URI courseDesignUpdateURI, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver,
String tracTracUsername, String tracTracPassword, IEventSubscriber eventSubscriber, URI courseDesignUpdateURI, String tracTracUsername, String tracTracPassword,
IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm, ReceiverType... types) { IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm, ReceiverType... types) {
IEvent tractracEvent = tractracRace.getEvent(); IEvent tractracEvent = tractracRace.getEvent();
Collection<Receiver> result = new ArrayList<Receiver>(); Collection<Receiver> result = new ArrayList<Receiver>();
for (ReceiverType type : types) { for (ReceiverType type : types) {
switch (type) { switch (type) {
case RACECOURSE: case RACECOURSE:
result.add(new RaceCourseReceiver(this, trackedRegatta, tractracEvent, tractracRace, result.add(new RaceCourseReceiver(this, trackedRegatta, tractracEvent, tractracRace, windStore,
windStore, raceDefinitionSetToUpdate, raceDefinitionSetToUpdate, delayToLiveInMillis,
delayToLiveInMillis, WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, simulator, WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, simulator, courseDesignUpdateURI,
courseDesignUpdateURI, tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm)); tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber,
useInternalMarkPassingAlgorithm, raceLogResolver));
break; break;
case MARKPOSITIONS: case MARKPOSITIONS:
result.add(new MarkPositionReceiver( result.add(new MarkPositionReceiver(
@@ -442,14 +444,14 @@ public class DomainFactoryImpl implements DomainFactory {
@Override @Override
public Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, public Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta,
long delayToLiveInMillis, Simulator simulator, WindStore windStore, long delayToLiveInMillis, Simulator simulator, WindStore windStore,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, IRace tractracRace, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver,
URI courseDesignUpdateURI, String tracTracUsername, IRace tractracRace, URI courseDesignUpdateURI,
String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm) { String tracTracUsername, String tracTracPassword, IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm) {
return getUpdateReceivers(trackedRegatta, tractracRace, windStore, delayToLiveInMillis, simulator, return getUpdateReceivers(trackedRegatta, tractracRace, windStore, delayToLiveInMillis, simulator,
raceDefinitionSetToUpdate, trackedRegattaRegistry, courseDesignUpdateURI, tracTracUsername, raceDefinitionSetToUpdate, trackedRegattaRegistry, raceLogResolver, courseDesignUpdateURI,
tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm, tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber,
ReceiverType.RACECOURSE, ReceiverType.MARKPASSINGS, ReceiverType.MARKPOSITIONS, useInternalMarkPassingAlgorithm, ReceiverType.RACECOURSE, ReceiverType.MARKPASSINGS,
ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS); ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS);
} }
@Override @Override
@@ -518,7 +520,7 @@ public class DomainFactoryImpl implements DomainFactory {
String raceName, Iterable<Competitor> competitors, BoatClass boatClass, Course course, String raceName, Iterable<Competitor> competitors, BoatClass boatClass, Course course,
Iterable<Sideline> sidelines, WindStore windStore, long delayToLiveInMillis, Iterable<Sideline> sidelines, WindStore windStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, 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) { synchronized (raceCache) {
RaceDefinition raceDefinition = raceCache.get(raceId); RaceDefinition raceDefinition = raceCache.get(raceId);
if (raceDefinition == null) { if (raceDefinition == null) {
@@ -533,7 +535,8 @@ public class DomainFactoryImpl implements DomainFactory {
if (raceDefinition.getBoatClass() == trackedRegatta.getRegatta().getBoatClass()) { if (raceDefinition.getBoatClass() == trackedRegatta.getRegatta().getBoatClass()) {
trackedRegatta.getRegatta().addRace(raceDefinition); trackedRegatta.getRegatta().addRace(raceDefinition);
trackedRace = createTrackedRace(trackedRegatta, raceDefinition, sidelines, windStore, EmptyGPSFixStore.INSTANCE, 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()); logger.info("Added race " + raceDefinition + " to regatta " + trackedRegatta.getRegatta());
addTracTracUpdateHandlers(tracTracUpdateURI, tracTracEventUuid, tracTracUsername, tracTracPassword, addTracTracUpdateHandlers(tracTracUpdateURI, tracTracEventUuid, tracTracUsername, tracTracPassword,
raceDefinition, trackedRace); raceDefinition, trackedRace);
@@ -568,12 +571,14 @@ public class DomainFactoryImpl implements DomainFactory {
trackedRace.addRaceAbortedListener(raceAbortedHandler); trackedRace.addRaceAbortedListener(raceAbortedHandler);
} }
private DynamicTrackedRace createTrackedRace(TrackedRegatta trackedRegatta, RaceDefinition race, Iterable<Sideline> sidelines, WindStore windStore, GPSFixStore gpsFixStore, private DynamicTrackedRace createTrackedRace(TrackedRegatta trackedRegatta, RaceDefinition race,
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingCalculator) { Iterable<Sideline> sidelines, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
boolean useMarkPassingCalculator, RaceLogResolver raceLogResolver) {
return trackedRegatta.createTrackedRace(race, sidelines, return trackedRegatta.createTrackedRace(race, sidelines,
windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
/* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(), /* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
raceDefinitionSetToUpdate, useMarkPassingCalculator); raceDefinitionSetToUpdate, useMarkPassingCalculator, raceLogResolver);
} }
@Override @Override
@@ -648,28 +653,29 @@ public class DomainFactoryImpl implements DomainFactory {
@Override @Override
public TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI, public TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry) String tracTracPassword, String raceStatus, String raceVisibility,
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws MalformedURLException, FileNotFoundException,
SubscriberInitializationException { URISyntaxException, CreateModelException, SubscriberInitializationException {
return new TracTracRaceTrackerImpl(this, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, return new TracTracRaceTrackerImpl(this, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking,
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore,
gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry); gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
} }
@Override @Override
public RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI, public RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI,
URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry) String tracTracPassword, String raceStatus, String raceVisibility,
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException, throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException,
SubscriberInitializationException { SubscriberInitializationException {
return new TracTracRaceTrackerImpl(regatta, this, paramURL, liveURI, storedURI, courseDesignUpdateURI, return new TracTracRaceTrackerImpl(regatta, this, paramURL, liveURI, storedURI, courseDesignUpdateURI,
startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore,
regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus,
raceVisibility, trackedRegattaRegistry); raceVisibility, trackedRegattaRegistry, raceLogResolver);
} }
@Override @Override
@@ -8,6 +8,7 @@ import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; 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.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.ControlPoint;
@@ -61,14 +62,17 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<IControlRoute,
private final IRace tractracRace; private final IRace tractracRace;
private final IControlRouteChangeListener listener; private final IControlRouteChangeListener listener;
private final boolean useInternalMarkPassingAlgorithm; private final boolean useInternalMarkPassingAlgorithm;
private final RaceLogResolver raceLogResolver;
public RaceCourseReceiver(DomainFactory domainFactory, DynamicTrackedRegatta trackedRegatta, IEvent tractracEvent, public RaceCourseReceiver(DomainFactory domainFactory, DynamicTrackedRegatta trackedRegatta, IEvent tractracEvent,
IRace tractracRace, WindStore windStore, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, IRace tractracRace, WindStore windStore, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, Simulator simulator, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, Simulator simulator,
URI courseDesignUpdateURI, String tracTracUsername, String tracTracPassword, URI courseDesignUpdateURI, String tracTracUsername, String tracTracPassword,
IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm) { IEventSubscriber eventSubscriber, IRaceSubscriber raceSubscriber, boolean useInternalMarkPassingAlgorithm,
RaceLogResolver raceLogResolver) {
super(domainFactory, tractracEvent, trackedRegatta, simulator, eventSubscriber, raceSubscriber); super(domainFactory, tractracEvent, trackedRegatta, simulator, eventSubscriber, raceSubscriber);
this.tractracRace = tractracRace; this.tractracRace = tractracRace;
this.raceLogResolver = raceLogResolver;
this.millisecondsOverWhichToAverageWind = millisecondsOverWhichToAverageWind; this.millisecondsOverWhichToAverageWind = millisecondsOverWhichToAverageWind;
this.delayToLiveInMillis = delayToLiveInMillis; this.delayToLiveInMillis = delayToLiveInMillis;
if (simulator == null) { if (simulator == null) {
@@ -156,7 +160,7 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<IControlRoute,
getTrackedRegatta(), tractracRace.getId(), tractracRace.getName(), competitorsAndDominantBoatClass.getA(), getTrackedRegatta(), tractracRace.getId(), tractracRace.getName(), competitorsAndDominantBoatClass.getA(),
competitorsAndDominantBoatClass.getB(), course, sidelines, windStore, delayToLiveInMillis, competitorsAndDominantBoatClass.getB(), course, sidelines, windStore, delayToLiveInMillis,
millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate, tracTracUpdateURI, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate, tracTracUpdateURI,
getTracTracEvent().getId(), tracTracUsername, tracTracPassword, useInternalMarkPassingAlgorithm); getTracTracEvent().getId(), tracTracUsername, tracTracPassword, useInternalMarkPassingAlgorithm, raceLogResolver);
needToUpdateRaceTimes = true; needToUpdateRaceTimes = true;
if (getSimulator() != null) { if (getSimulator() != null) {
getSimulator().setTrackedRace(trackedRace); getSimulator().setTrackedRace(trackedRace);
@@ -221,7 +225,7 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<IControlRoute,
DynamicTrackedRace trackedRace = getTrackedRegatta().createTrackedRace(race, sidelines, DynamicTrackedRace trackedRace = getTrackedRegatta().createTrackedRace(race, sidelines,
windStore, EmptyGPSFixStore.INSTANCE, delayToLiveInMillis, millisecondsOverWhichToAverageWind, windStore, EmptyGPSFixStore.INSTANCE, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
/* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(), /* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
raceDefinitionSetToUpdate, useInternalMarkPassingAlgorithm); raceDefinitionSetToUpdate, useInternalMarkPassingAlgorithm, raceLogResolver);
getDomainFactory().addTracTracUpdateHandlers(tracTracUpdateURI, getTracTracEvent().getId(), tracTracUsername, tracTracPassword, race, trackedRace); getDomainFactory().addTracTracUpdateHandlers(tracTracUpdateURI, getTracTracEvent().getId(), tracTracUsername, tracTracPassword, race, trackedRace);
return trackedRace; return trackedRace;
} }
@@ -6,6 +6,7 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.racelog.RaceLogStore; import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore; import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
@@ -63,22 +64,22 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
@Override @Override
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore, public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
GPSFixStore gpsFixStore) throws MalformedURLException, FileNotFoundException, URISyntaxException, GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) throws MalformedURLException, FileNotFoundException, URISyntaxException,
CreateModelException, SubscriberInitializationException { CreateModelException, SubscriberInitializationException {
RaceTracker tracker = domainFactory.createRaceTracker(paramURL, liveURI, storedURI, courseDesignUpdateURI, RaceTracker tracker = domainFactory.createRaceTracker(paramURL, liveURI, storedURI, courseDesignUpdateURI,
startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore,
regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus,
raceVisibility, trackedRegattaRegistry); raceVisibility, trackedRegattaRegistry, raceLogResolver);
return tracker; return tracker;
} }
@Override @Override
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
WindStore windStore, GPSFixStore gpsFixStore) throws Exception { WindStore windStore, GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) throws Exception {
RaceTracker tracker = domainFactory.createRaceTracker(regatta, paramURL, liveURI, storedURI, RaceTracker tracker = domainFactory.createRaceTracker(regatta, paramURL, liveURI, storedURI,
courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm,
raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus,
raceVisibility, trackedRegattaRegistry); raceVisibility, trackedRegattaRegistry, raceLogResolver);
return tracker; return tracker;
} }
@@ -19,6 +19,7 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; 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.Competitor;
import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.Fleet;
@@ -245,18 +246,19 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
* available but loses track of the wind, e.g., during server restarts. * available but loses track of the wind, e.g., during server restarts.
* @param trackedRegattaRegistry * @param trackedRegattaRegistry
* used to create the {@link TrackedRegatta} for the domain event * used to create the {@link TrackedRegatta} for the domain event
* @param raceLogResolver TODO
*/ */
protected TracTracRaceTrackerImpl(DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI, protected TracTracRaceTrackerImpl(DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI,
URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword,
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry) String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
throws URISyntaxException, MalformedURLException, FileNotFoundException, CreateModelException, throws URISyntaxException, MalformedURLException, FileNotFoundException, CreateModelException,
SubscriberInitializationException { SubscriberInitializationException {
this(ModelLocator.getEventFactory().createRace(new URI(paramURL.toString())), domainFactory, paramURL, liveURI, this(ModelLocator.getEventFactory().createRace(new URI(paramURL.toString())), domainFactory, paramURL, liveURI,
storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis,
simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername,
tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry); tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
} }
private TracTracRaceTrackerImpl(IRace tractracRace, DomainFactory domainFactory, URL paramURL, URI liveURI, private TracTracRaceTrackerImpl(IRace tractracRace, DomainFactory domainFactory, URL paramURL, URI liveURI,
@@ -264,11 +266,11 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
String tracTracPassword, String raceStatus, String raceVisibility, String tracTracPassword, String raceStatus, String raceVisibility,
TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws URISyntaxException, MalformedURLException,
FileNotFoundException, SubscriberInitializationException { FileNotFoundException, SubscriberInitializationException {
this(tractracRace, null, domainFactory, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, this(tractracRace, null, domainFactory, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking,
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore,
gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry); gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
} }
/** /**
@@ -276,18 +278,19 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
* tracker is already known up-front, particularly if it has a specific configuration to use. Other constructors * tracker is already known up-front, particularly if it has a specific configuration to use. Other constructors
* may create a default {@link Regatta} with only a single default {@link Series} and {@link Fleet} which may not * may create a default {@link Regatta} with only a single default {@link Series} and {@link Fleet} which may not
* always be what you want. * always be what you want.
* @param raceLogResolver TODO
*/ */
protected TracTracRaceTrackerImpl(Regatta regatta, DomainFactory domainFactory, URL paramURL, URI liveURI, protected TracTracRaceTrackerImpl(Regatta regatta, DomainFactory domainFactory, URL paramURL, URI liveURI,
URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking,
long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean ignoreTracTracMarkPassings, RaceLogStore raceLogStore, long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean ignoreTracTracMarkPassings, RaceLogStore raceLogStore,
RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
String tracTracPassword, String raceStatus, String raceVisibility, String tracTracPassword, String raceStatus, String raceVisibility,
TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws URISyntaxException,
MalformedURLException, FileNotFoundException, CreateModelException, SubscriberInitializationException { MalformedURLException, FileNotFoundException, CreateModelException, SubscriberInitializationException {
this(ModelLocator.getEventFactory().createRace(new URI(paramURL.toString())), regatta, domainFactory, paramURL, this(ModelLocator.getEventFactory().createRace(new URI(paramURL.toString())), regatta, domainFactory, paramURL,
liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis,
simulateWithStartTimeNow, ignoreTracTracMarkPassings, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername, simulateWithStartTimeNow, ignoreTracTracMarkPassings, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername,
tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry); tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
} }
/** /**
@@ -300,13 +303,14 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
* first mark passing for the first waypoint will be set to "now." It will delay the forwarding of all * first mark passing for the first waypoint will be set to "now." It will delay the forwarding of all
* events received such that they seem to be sent in "real-time." So, more or less the time points * events received such that they seem to be sent in "real-time." So, more or less the time points
* attached to the events sent to the receivers will again approximate the wall time. * attached to the events sent to the receivers will again approximate the wall time.
* @param raceLogResolver TODO
*/ */
private TracTracRaceTrackerImpl(IRace tractracRace, final Regatta regatta, DomainFactory domainFactory, private TracTracRaceTrackerImpl(IRace tractracRace, final Regatta regatta, DomainFactory domainFactory,
URL paramURL, URI liveURI, URI storedURI, URI tracTracUpdateURI, TimePoint startOfTracking, URL paramURL, URI liveURI, URI storedURI, URI tracTracUpdateURI, TimePoint startOfTracking,
TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm,
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore,
String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility, String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility,
TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws URISyntaxException, MalformedURLException,
FileNotFoundException, SubscriberInitializationException { FileNotFoundException, SubscriberInitializationException {
super(); super();
this.trackedRegattaRegistry = trackedRegattaRegistry; this.trackedRegattaRegistry = trackedRegattaRegistry;
@@ -397,8 +401,8 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(this.regatta); trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(this.regatta);
receivers = new HashSet<Receiver>(); receivers = new HashSet<Receiver>();
for (Receiver receiver : domainFactory.getUpdateReceivers(getTrackedRegatta(), delayToLiveInMillis, for (Receiver receiver : domainFactory.getUpdateReceivers(getTrackedRegatta(), delayToLiveInMillis,
simulator, windStore, this, trackedRegattaRegistry, tractracRace, tracTracUpdateURI, simulator, windStore, this, trackedRegattaRegistry, raceLogResolver, tractracRace,
tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm)) { tracTracUpdateURI, tracTracUsername, tracTracPassword, eventSubscriber, raceSubscriber, useInternalMarkPassingAlgorithm)) {
receivers.add(receiver); receivers.add(receiver);
} }
addListenersForStoredDataAndStartController(receivers); addListenersForStoredDataAndStartController(receivers);
@@ -19,7 +19,6 @@ Export-Package: com.sap.sailing.domain.base,
com.sap.sailing.domain.masterdataimport, com.sap.sailing.domain.masterdataimport,
com.sap.sailing.domain.polars, com.sap.sailing.domain.polars,
com.sap.sailing.domain.racelog, com.sap.sailing.domain.racelog,
com.sap.sailing.domain.racelog.analyzing,
com.sap.sailing.domain.racelog.impl, com.sap.sailing.domain.racelog.impl,
com.sap.sailing.domain.racelog.tracking, com.sap.sailing.domain.racelog.tracking,
com.sap.sailing.domain.ranking, com.sap.sailing.domain.ranking,
@@ -196,7 +196,21 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
this.scoringScheme = scoringScheme; this.scoringScheme = scoringScheme;
this.defaultCourseArea = courseArea; this.defaultCourseArea = courseArea;
this.configuration = null; 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(); this.raceExecutionOrderCache = new RaceExecutionOrderCache();
} }
@@ -677,4 +691,9 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
return result; return result;
} }
} }
@Override
public RaceColumn getRaceColumnByName(String raceColumnName) {
return regattaLikeHelper.getRaceColumnByName(raceColumnName);
}
} }
@@ -8,6 +8,10 @@ import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.NoWindException; import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Wind; 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.leaderboard.impl.AbstractSimpleLeaderboardImpl;
import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.TrackedLeg; 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.TimePoint;
import com.sap.sse.common.Util; import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Triple; 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 * A cache structure that is used for a single call to
@@ -45,16 +50,20 @@ public class LeaderboardDTOCalculationReuseCache implements WindLegTypeAndLegBea
*/ */
final ConcurrentHashMap<Leg, LegType> legTypeCache; final ConcurrentHashMap<Leg, LegType> legTypeCache;
/** /**
* the wind at competitor's position at timePoint * the wind at competitor's position at timePoint; <code>null</code> values are represented by {@link #NULL_WIND}.
*/ */
final ConcurrentHashMap<Triple<TrackedRace, Competitor, TimePoint>, Wind> windCache; final ConcurrentHashMap<Triple<TrackedRace, Competitor, TimePoint>, 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; <code>null</code> values are represented by {@link #NULL_BEARING}.
*/ */
final ConcurrentHashMap<Leg, Bearing> legBearingCache; final ConcurrentHashMap<Leg, Bearing> legBearingCache;
private static final Bearing NULL_BEARING = new DegreeBearingImpl(0);
public LeaderboardDTOCalculationReuseCache(TimePoint timePoint) { public LeaderboardDTOCalculationReuseCache(TimePoint timePoint) {
legTypeCache = new ConcurrentHashMap<>(); legTypeCache = new ConcurrentHashMap<>();
@@ -83,7 +92,9 @@ public class LeaderboardDTOCalculationReuseCache implements WindLegTypeAndLegBea
result = legBearingCache.get(trackedLeg.getLeg()); result = legBearingCache.get(trackedLeg.getLeg());
if (result == null) { if (result == null) {
result = trackedLeg.getLegBearing(timePoint); 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 { } else {
result = trackedLeg.getLegBearing(timePoint); // different time point; don't cache result = trackedLeg.getLegBearing(timePoint); // different time point; don't cache
@@ -100,7 +111,9 @@ public class LeaderboardDTOCalculationReuseCache implements WindLegTypeAndLegBea
Wind result = windCache.get(cacheKey); Wind result = windCache.get(cacheKey);
if (result == null) { if (result == null) {
result = trackedRace.getWind(trackedRace.getTrack(competitor).getEstimatedPosition(timePoint, false), timePoint); 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; return result;
} }
@@ -84,7 +84,14 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
this.races = new ArrayList<>(); this.races = new ArrayList<>();
this.raceLogStore = raceLogStore; this.raceLogStore = raceLogStore;
this.courseArea = courseArea; 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(); this.raceExecutionOrderProvider = new RaceExecutionOrderCache();
} }
@@ -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;
}
}
@@ -14,7 +14,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.regattalog.RegattaLogStore; import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sse.common.Duration; import com.sap.sse.common.Duration;
public class BaseRegattaLikeImpl implements IsRegattaLike { public abstract class BaseRegattaLikeImpl implements IsRegattaLike {
private static final long serialVersionUID = -5629172342837950344L; private static final long serialVersionUID = -5629172342837950344L;
private final RegattaLog regattaLog; private final RegattaLog regattaLog;
private final RegattaLikeIdentifier identifier; private final RegattaLikeIdentifier identifier;
@@ -4,6 +4,7 @@ import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.Competitor; 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.base.Regatta;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
@@ -25,6 +26,8 @@ public interface IsRegattaLike extends Serializable {
*/ */
RegattaLog getRegattaLog(); RegattaLog getRegattaLog();
RaceColumn getRaceColumnByName(String raceColumnName);
RegattaLikeIdentifier getRegattaLikeIdentifier(); RegattaLikeIdentifier getRegattaLikeIdentifier();
void addListener(RegattaLikeListener listener); void addListener(RegattaLikeListener listener);
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.tracking; 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.Fleet;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series; import com.sap.sailing.domain.base.Series;
@@ -20,16 +21,18 @@ import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
public interface RaceTrackingConnectivityParameters { public interface RaceTrackingConnectivityParameters {
/** /**
* Starts a {@link RaceTracker} using the connectivity parameters provided by this object. * 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 * 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 * 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 * parameters. This is particularly useful if a predefined regatta with {@link Series} and {@link Fleet}s
* is to be used. * 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} * Deliver an ID object equal to that of the {@link RaceTracker#getID()} delivered by the {@link RaceTracker}
@@ -7,6 +7,7 @@ import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import com.sap.sailing.domain.abstractlog.race.RaceLog; 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.race.state.racingprocedure.RacingProcedure;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.shared.events.DeviceMappingEvent; 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.Leg;
import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition; 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.Sideline;
import com.sap.sailing.domain.base.SpeedWithConfidence; import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.Waypoint; 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.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.ranking.RankingMetric; import com.sap.sailing.domain.ranking.RankingMetric;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; 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.Duration;
import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util; import com.sap.sse.common.Util;
@@ -851,4 +854,7 @@ public interface TrackedRace extends Serializable {
void setPolarDataService(PolarDataService polarDataService); void setPolarDataService(PolarDataService polarDataService);
default RaceLogResolver getRaceLogResolver() {
return null;
}
} }
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.tracking;
import java.io.Serializable; 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.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceDefinition; 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 * 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)} * to this tracked regatta. Afterwards, calling {@link #getTrackedRace(RaceDefinition) getTrackedRace(raceDefinition)}
* will return the result of this method call. * will return the result of this method call.
*
* @param raceDefinitionSetToUpdate * @param raceDefinitionSetToUpdate
* if not <code>null</code>, after creating the {@link TrackedRace}, the <code>raceDefinition</code> is * if not <code>null</code>, after creating the {@link TrackedRace}, the <code>raceDefinition</code> is
* {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that object. * {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition, DynamicTrackedRace) added} to that object.
* @param raceLogResolver TODO
*/ */
DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines, WindStore windStore, DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines, WindStore windStore,
GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm); DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver);
/** /**
* Obtains the tracked race for <code>race</code>. Blocks until the tracked race has been created * Obtains the tracked race for <code>race</code>. Blocks until the tracked race has been created
@@ -16,6 +16,7 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.race.RaceLog; 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.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.CourseBase;
@@ -77,10 +78,10 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
long delayForCacheInvalidationOfWindEstimation, boolean useInternalMarkPassingAlgorithm, long delayForCacheInvalidationOfWindEstimation, boolean useInternalMarkPassingAlgorithm,
RankingMetricConstructor rankingMetricConstructor) { RankingMetricConstructor rankingMetricConstructor, RaceLogResolver raceLogResolver) {
super(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis, super(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis,
millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
delayForCacheInvalidationOfWindEstimation, useInternalMarkPassingAlgorithm, rankingMetricConstructor); delayForCacheInvalidationOfWindEstimation, useInternalMarkPassingAlgorithm, rankingMetricConstructor, raceLogResolver);
this.logListener = new DynamicTrackedRaceLogListener(this); this.logListener = new DynamicTrackedRaceLogListener(this);
if (markPassingCalculator != null) { if (markPassingCalculator != null) {
logListener.setMarkPassingUpdateListener(markPassingCalculator.getListener()); logListener.setMarkPassingUpdateListener(markPassingCalculator.getListener());
@@ -134,10 +135,10 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
public DynamicTrackedRaceImpl(TrackedRegatta trackedRegatta, RaceDefinition race, Iterable<Sideline> sidelines, public DynamicTrackedRaceImpl(TrackedRegatta trackedRegatta, RaceDefinition race, Iterable<Sideline> sidelines,
WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
boolean useInternalMarkPassingAlgorithm, RankingMetricConstructor rankingMetricConstructor) { boolean useInternalMarkPassingAlgorithm, RankingMetricConstructor rankingMetricConstructor, RaceLogResolver raceLogResolver) {
this(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis, this(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis,
millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
millisecondsOverWhichToAverageWind / 2, useInternalMarkPassingAlgorithm, rankingMetricConstructor); millisecondsOverWhichToAverageWind / 2, useInternalMarkPassingAlgorithm, rankingMetricConstructor, raceLogResolver);
} }
@Override @Override
@@ -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.RaceLogWindFixEvent;
import com.sap.sailing.domain.abstractlog.race.SuppressedMarkPassingsEvent; 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.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.LastPublishedCourseDesignFinder;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.MarkPassingDataFinder; 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.analyzing.impl.WindFixesFinder;
import com.sap.sailing.domain.abstractlog.race.impl.BaseRaceLogEventVisitor; import com.sap.sailing.domain.abstractlog.race.impl.BaseRaceLogEventVisitor;
import com.sap.sailing.domain.base.Competitor; 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.impl.WindSourceImpl;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.domain.markpassingcalculation.MarkPassingUpdateListener; 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.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Triple; import com.sap.sse.common.Util.Triple;
@@ -69,8 +68,7 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor {
trackedRace.invalidateStartTime(); trackedRace.invalidateStartTime();
trackedRace.invalidateEndTime(); trackedRace.invalidateEndTime();
courseDesignFinder = new LastPublishedCourseDesignFinder(raceLog); courseDesignFinder = new LastPublishedCourseDesignFinder(raceLog);
//FIXME: how to get the HasRegattaLike? startTimeFinder = new StartTimeFinder(trackedRace.getRaceLogResolver(), raceLog);
startTimeFinder = new StartTimeFinder(new ServerSideRaceLogResolver(null), raceLog);
abortingFlagFinder = new AbortingFlagFinder(raceLog); abortingFlagFinder = new AbortingFlagFinder(raceLog);
initializeWindTrack(raceLog); initializeWindTrack(raceLog);
analyze(); analyze();
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.tracking.impl; 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.RaceDefinition;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Sideline; import com.sap.sailing.domain.base.Sideline;
@@ -35,8 +36,8 @@ public class DynamicTrackedRegattaImpl extends TrackedRegattaImpl implements Dyn
@Override @Override
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines, WindStore windStore, public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines, WindStore windStore,
GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, 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, return (DynamicTrackedRace) super.createTrackedRace(raceDefinition, sidelines, windStore, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
millisecondsOverWhichToAverageSpeed, raceDefinitionSetToUpdate, useMarkPassingCalculator); millisecondsOverWhichToAverageSpeed, raceDefinitionSetToUpdate, useMarkPassingCalculator, raceLogResolver);
} }
} }
@@ -36,8 +36,11 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.AbstractLog; import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent; import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLog; 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.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogGateLineOpeningTimeEvent; 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.analyzing.impl.StartTimeFinder;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogGateLineOpeningTimeEventImpl; import com.sap.sailing.domain.abstractlog.race.impl.RaceLogGateLineOpeningTimeEventImpl;
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; 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.markpassingcalculation.MarkPassingCalculator;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException; import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService; 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.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.racelogtracking.DeviceMapping; import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric; import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
@@ -315,7 +318,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
private transient CrossTrackErrorCache crossTrackErrorCache; 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 * 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. * certificate.
*/ */
private final RankingMetric rankingMetric; 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 <code>RacingEventService</code> 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. * Constructs the tracked race with one-design ranking.
@@ -355,15 +366,14 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
final Iterable<Sideline> sidelines, final WindStore windStore, final GPSFixStore gpsFixStore, final Iterable<Sideline> sidelines, final WindStore windStore, final GPSFixStore gpsFixStore,
long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind, long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind,
long millisecondsOverWhichToAverageSpeed, long delayForWindEstimationCacheInvalidation, long millisecondsOverWhichToAverageSpeed, long delayForWindEstimationCacheInvalidation,
boolean useInternalMarkPassingAlgorithm) { boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver) {
this(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis, this(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis,
millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
delayForWindEstimationCacheInvalidation, useInternalMarkPassingAlgorithm, OneDesignRankingMetric::new); delayForWindEstimationCacheInvalidation, useInternalMarkPassingAlgorithm, OneDesignRankingMetric::new, raceLogResolver);
} }
/** /**
* Constructs the tracked race with a configurable ranking metric. * Constructs the tracked race with a configurable ranking metric.
*
* @param rankingMetricConstructor * @param rankingMetricConstructor
* the function that creates the ranking metric, passing this tracked race as argument. Callers may use a * 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 * 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<Sideline> sidelines, final WindStore windStore, final GPSFixStore gpsFixStore, final Iterable<Sideline> sidelines, final WindStore windStore, final GPSFixStore gpsFixStore,
long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind, long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind,
long millisecondsOverWhichToAverageSpeed, long delayForWindEstimationCacheInvalidation, long millisecondsOverWhichToAverageSpeed, long delayForWindEstimationCacheInvalidation,
boolean useInternalMarkPassingAlgorithm, RankingMetricConstructor rankingMetricConstructor) { boolean useInternalMarkPassingAlgorithm, RankingMetricConstructor rankingMetricConstructor,
RaceLogResolver raceLogResolver) {
super(race, trackedRegatta, windStore, millisecondsOverWhichToAverageWind); super(race, trackedRegatta, windStore, millisecondsOverWhichToAverageWind);
this.raceLogResolver = raceLogResolver;
rankingMetric = rankingMetricConstructor.apply(this); rankingMetric = rankingMetricConstructor.apply(this);
raceStates = new WeakHashMap<>(); raceStates = new WeakHashMap<>();
shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2); shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2);
@@ -585,6 +597,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2); shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2);
cacheInvalidationTimerLock = new Object(); cacheInvalidationTimerLock = new Object();
windStore = EmptyWindStore.INSTANCE; windStore = EmptyWindStore.INSTANCE;
gpsFixStore = EmptyGPSFixStore.INSTANCE;
competitorRankings = createCompetitorRankingsCache(); competitorRankings = createCompetitorRankingsCache();
competitorRankingsLocks = createCompetitorRankingsLockMap(); competitorRankingsLocks = createCompetitorRankingsLockMap();
directionFromStartToNextMarkCache = new HashMap<TimePoint, Future<Wind>>(); directionFromStartToNextMarkCache = new HashMap<TimePoint, Future<Wind>>();
@@ -728,9 +741,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
public TimePoint getStartOfRace() { public TimePoint getStartOfRace() {
if (startTime == null) { if (startTime == null) {
for (RaceLog raceLog : attachedRaceLogs.values()) { for (RaceLog raceLog : attachedRaceLogs.values()) {
startTime = new StartTimeFinder(raceLogResolver, raceLog).analyze().getStartTime();
//FIXME: how to get the HasRegattaLike?
startTime = new StartTimeFinder(new ServerSideRaceLogResolver(null), raceLog).analyze().getStartTime();
if (startTime != null) { if (startTime != null) {
break; break;
} }
@@ -3138,8 +3149,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
synchronized (raceStates) { synchronized (raceStates) {
result = raceStates.get(raceLog); result = raceStates.get(raceLog);
if (result == null) { if (result == null) {
//FIXME: how to get the corresponding RegattaLike? result = RaceStateImpl.create(raceLogResolver, raceLog);
result = RaceStateImpl.create(new ServerSideRaceLogResolver(null), raceLog);
raceStates.put(raceLog, result); raceStates.put(raceLog, result);
} }
} }
@@ -3671,4 +3681,16 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
public void setPolarDataService(PolarDataService polarDataService) { public void setPolarDataService(PolarDataService polarDataService) {
this.polarDataService = polarDataService; this.polarDataService = polarDataService;
} }
/**
* Obtains the {@link #raceLogResolver}.
*/
@Override
public RaceLogResolver getRaceLogResolver() {
return raceLogResolver;
}
public void setRaceLogResolver(RaceLogResolver raceLogResolver) {
this.raceLogResolver = raceLogResolver;
}
} }
@@ -14,6 +14,7 @@ import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; 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.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.RaceDefinition;
@@ -244,12 +245,12 @@ public class TrackedRegattaImpl implements TrackedRegatta {
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines, public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines,
WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm) { DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver) {
logger.log(Level.INFO, "Creating DynamicTrackedRaceImpl for RaceDefinition " + raceDefinition.getName()); logger.log(Level.INFO, "Creating DynamicTrackedRaceImpl for RaceDefinition " + raceDefinition.getName());
DynamicTrackedRaceImpl result = new DynamicTrackedRaceImpl(this, raceDefinition, sidelines, windStore, DynamicTrackedRaceImpl result = new DynamicTrackedRaceImpl(this, raceDefinition, sidelines, windStore,
gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, gpsFixStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
millisecondsOverWhichToAverageSpeed, millisecondsOverWhichToAverageSpeed,
/* useMarkPassingCalculator */useInternalMarkPassingAlgorithm, getRegatta().getRankingMetricConstructor()); /* useMarkPassingCalculator */useInternalMarkPassingAlgorithm, getRegatta().getRankingMetricConstructor(), raceLogResolver);
// adding the raceDefinition to the raceDefinitionSetToUpdate BEFORE calling addTrackedRace helps those who // 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 // are called back by RaceListener.raceAdded(TrackedRace) and who then expect the update to have happened
if (raceDefinitionSetToUpdate != null) { if (raceDefinitionSetToUpdate != null) {
@@ -9,6 +9,7 @@ import java.util.NavigableSet;
import java.util.Set; import java.util.Set;
import com.sap.sailing.domain.abstractlog.race.RaceLog; 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.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
@@ -313,7 +314,7 @@ public class MockedTrackedRace implements DynamicTrackedRace {
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines, WindStore windStore, public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable<Sideline> sidelines, WindStore windStore,
GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, GPSFixStore gpsFixStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
long millisecondsOverWhichToAverageSpeed, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, long millisecondsOverWhichToAverageSpeed, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
boolean useMarkPassingCalculator) { boolean useMarkPassingCalculator, RaceLogResolver raceLogResolver) {
return null; return null;
} }
@@ -1,79 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.google.gdt.eclipse.suite.webapp"> <launchConfiguration type="com.google.gdt.eclipse.suite.webapp">
<booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/> <booleanAttribute key="com.google.gdt.eclipse.core.RUN_SERVER" value="false"/>
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/> <stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/> <booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
<booleanAttribute key="com.google.gwt.eclipse.core.CODE_SERVER_PORT_AUTO" value="true"/> <listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES"> <listEntry value="com.sap.sailing.gwt.ui.RaceBoard"/>
<listEntry value="com.sap.sailing.gwt.ui.RaceBoard"/> <listEntry value="com.sap.sailing.gwt.ui.DataMining"/>
<listEntry value="com.sap.sailing.gwt.ui.DataMining"/> <listEntry value="com.sap.sailing.gwt.ui.LeaderboardEditing"/>
<listEntry value="com.sap.sailing.gwt.ui.LeaderboardEditing"/> <listEntry value="com.sap.sailing.gwt.ui.Spectator"/>
<listEntry value="com.sap.sailing.gwt.ui.Spectator"/> <listEntry value="com.sap.sailing.gwt.regattaoverview.RegattaOverview"/>
<listEntry value="com.sap.sailing.gwt.regattaoverview.RegattaOverview"/> <listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/>
<listEntry value="com.sap.sailing.gwt.ui.PolarSheets"/> <listEntry value="com.sap.sailing.gwt.ui.Leaderboard"/>
<listEntry value="com.sap.sailing.gwt.ui.Leaderboard"/> <listEntry value="com.sap.sailing.gwt.ui.Simulator"/>
<listEntry value="com.sap.sailing.gwt.ui.Simulator"/> <listEntry value="com.sap.sailing.gwt.ui.YoutubePopup"/>
<listEntry value="com.sap.sailing.gwt.ui.YoutubePopup"/> <listEntry value="com.sap.sailing.gwt.AutoPlay"/>
<listEntry value="com.sap.sailing.gwt.AutoPlay"/> <listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
<listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/> <listEntry value="com.sap.sailing.gwt.home.Mobile"/>
<listEntry value="com.sap.sailing.gwt.home.Mobile"/> <listEntry value="com.sap.sailing.gwt.home.Desktop"/>
<listEntry value="com.sap.sailing.gwt.home.Desktop"/> <listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/> </listAttribute>
</listAttribute> <booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
<stringAttribute key="com.google.gwt.eclipse.core.LOG_LEVEL" value="INFO"/> <stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/> <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/> <listEntry value="/com.sap.sailing.gwt.ui"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> </listAttribute>
<listEntry value="/com.sap.sailing.gwt.ui"/> <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
</listAttribute> <listEntry value="4"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> </listAttribute>
<listEntry value="4"/> <listAttribute key="org.eclipse.debug.ui.favoriteGroups">
</listAttribute> <listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups"> <listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> </listAttribute>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/> <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/>
</listAttribute> <listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="false"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; javaProject=&quot;com.sap.sailing.gwt.ui&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6&quot; javaProject=&quot;com.sap.sailing.gwt.ui&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.theme/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.gwt.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.theme/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.googlecode.java-diff-utils/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.googlecode.java-diff-utils/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.json.simple/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.server/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.json.simple/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.server/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.expeditionconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.expeditionconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.udpconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.declination/resources&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.mongodb/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.udpconnector/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.mongodb/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.operationaltransformation/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.swisstimingadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.replication/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.operationaltransformation/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.replication/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.moxieapps.gwt.highcharts/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.domain.tractracadapter.persistence/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.geocoding/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/org.moxieapps.gwt.highcharts/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.geocoding/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sailing.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.datamining.shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-user.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#13;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;com.sap.sailing.gwt.ui&quot;/&gt;&#13;&#10;&lt;/runtimeClasspathEntry&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.google.gwt.osgi/lib/gwt-user.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#13;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;com.sap.sailing.gwt.ui&quot;/&gt;&#13;&#10;&lt;/runtimeClasspathEntry&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.adminconsole/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.ui/src/main/java&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.gwt.adminconsole/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> </listAttribute>
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.security.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/> <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
</listAttribute> <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/> <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Mobile -startupUrl /gwt/HomeDesktop.html com.sap.sailing.gwt.home.Desktop -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Desktop com.sap.sailing.gwt.home.Mobile com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -war &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Mobile -startupUrl /gwt/HomeDesktop.html com.sap.sailing.gwt.home.Desktop -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/PolarSheets.html com.sap.sailing.gwt.ui.PolarSheets -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Desktop com.sap.sailing.gwt.home.Mobile com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.ui.PolarSheets com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/> <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/> </launchConfiguration>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/>
</launchConfiguration>
@@ -104,6 +104,9 @@
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.updatesbox_item_live {
color: red;
}
.updatesbox_item_content_text_boatclass { .updatesbox_item_content_text_boatclass {
display: none; display: none;
} }
@@ -8,8 +8,6 @@ import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Node; import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.SpanElement; 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.UiBinder;
import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Event; 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.common.client.LinkUtil;
import com.sap.sailing.gwt.home.client.place.event.EventView; import com.sap.sailing.gwt.home.client.place.event.EventView;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation; 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.AbstractRaceNewsEntryDTO;
import com.sap.sailing.gwt.ui.shared.dispatch.news.LeaderboardNewsEntryDTO; 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.dispatch.news.NewsEntryDTO;
import com.sap.sailing.gwt.ui.shared.util.ConditionalDateTimeFormatter;
public class UpdatesBoxItem extends Widget { public class UpdatesBoxItem extends Widget {
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
@@ -37,6 +37,7 @@ public class UpdatesBoxItem extends Widget {
@UiField DivElement timestampUi; @UiField DivElement timestampUi;
public UpdatesBoxItem(NewsEntryDTO entry, EventView.Presenter presenter) { public UpdatesBoxItem(NewsEntryDTO entry, EventView.Presenter presenter) {
UpdatesBoxResources.INSTANCE.css().ensureInjected();
setElement(uiBinder.createAndBindUi(this)); setElement(uiBinder.createAndBindUi(this));
titleUi.setInnerText(entry.getTitle()); titleUi.setInnerText(entry.getTitle());
@@ -53,11 +54,15 @@ public class UpdatesBoxItem extends Widget {
} }
Date timestamp = entry.getTimestamp(); Date newsTimestamp = entry.getTimestamp();
if(timestamp == null) { Date currentTimestamp = entry.getCurrentTimestamp();
if(newsTimestamp == null || currentTimestamp == null) {
timestampUi.removeFromParent(); timestampUi.removeFromParent();
} else { } 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(); String directLink = entry.getExternalURL();
@@ -99,5 +104,4 @@ public class UpdatesBoxItem extends Widget {
} }
} }
} }
} }
@@ -17,6 +17,7 @@ public interface UpdatesBoxResources extends ClientBundle {
String box_content_item(); String box_content_item();
String updatesbox(); String updatesbox();
String updatesbox_item(); String updatesbox_item();
String updatesbox_item_live();
String updatesbox_itemlink(); String updatesbox_itemlink();
String updatesbox_item_icon(); String updatesbox_item_icon();
String updatesbox_item_content(); String updatesbox_item_content();
@@ -114,7 +114,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
private TextColumn<RegattaOverviewEntryDTO> startTimeColumn; private TextColumn<RegattaOverviewEntryDTO> startTimeColumn;
private SimplePanel tableHolder = new SimplePanel(); private SimplePanel tableHolder = new SimplePanel();
private final long _1_HOUR = 60 /* seconds */* 60 /* minutes */* 60 /* hour */; 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<RegattaOverviewEntryDTO> lastUpdateColumn; private TextColumn<RegattaOverviewEntryDTO> lastUpdateColumn;
private TextColumn<RegattaOverviewEntryDTO> endOfProtestTime; private TextColumn<RegattaOverviewEntryDTO> endOfProtestTime;
private TextColumn<RegattaOverviewEntryDTO> raceAdditionalInformationColumn; private TextColumn<RegattaOverviewEntryDTO> raceAdditionalInformationColumn;
@@ -1331,4 +1331,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String pointsValue(double value); String pointsValue(double value);
String openLeaderboard(); String openLeaderboard();
String resultsStandings(); String resultsStandings();
String now();
String minutesAgo(String minutes);
String hoursAgo(String hours);
} }
@@ -1199,8 +1199,8 @@ group=Group
valueAscending=Value (Ascending) valueAscending=Value (Ascending)
valueDescending=Value (Descending) valueDescending=Value (Descending)
sortBy=Sort by sortBy=Sort by
dashboardWindBotLoadingText=Loading wind bot data ... dashboardWindBotLoadingText=Waiting for wind bot data...
dashboardWindBotLoadingMessage=Depending on your connection this operation might take some minutes to complete the first time. 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. dashboardWindBotNotAvailable=Wind bot not available.
dashboardWindBot=Wind Bot dashboardWindBot=Wind Bot
dashboardTrueWindSpeed=TWS dashboardTrueWindSpeed=TWS
@@ -1299,4 +1299,7 @@ billionValue={0,number,#0.0} bil
noResults=There are no results available yet. noResults=There are no results available yet.
pointsValue={0,number,#0.00} pointsValue={0,number,#0.00}
openLeaderboard=Open Leaderboard openLeaderboard=Open Leaderboard
resultsStandings=Results/Standings resultsStandings=Results/Standings
now=Now
minutesAgo={0} min ago
hoursAgo={0} h ago
@@ -1289,4 +1289,7 @@ billionValue={0,number,#0.0} Mrd
noResults=Leider gibt es noch keine Ergebnisse. noResults=Leider gibt es noch keine Ergebnisse.
pointsValue={0,number,#0.00} pointsValue={0,number,#0.00}
openLeaderboard=Rangliste öffnen openLeaderboard=Rangliste öffnen
resultsStandings=Ergbnisse/Platzierungen resultsStandings=Ergbnisse/Platzierungen
now=Jetzt
minutesAgo=vor {0} min
hoursAgo=vor {0} h
@@ -1236,4 +1236,7 @@ billionValue={0,number,#0.0} млрд
noResults=There are no results available yet. noResults=There are no results available yet.
pointsValue={0,number,#0.00} pointsValue={0,number,#0.00}
openLeaderboard=Open Leaderboard openLeaderboard=Open Leaderboard
resultsStandings=Results/Standings resultsStandings=Results/Standings
now=в настоящее время
minutesAgo={0} минут назад
hoursAgo={0} h часов назад
@@ -232,7 +232,6 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.racelog.RaceLogStore; import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.racelog.RaceStateOfSameDayHelper; 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.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifierStringSerializationHandler; import com.sap.sailing.domain.racelogtracking.DeviceIdentifierStringSerializationHandler;
import com.sap.sailing.domain.racelogtracking.DeviceMapping; 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? // 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; swissTimingAdapterPersistence = SwissTimingAdapterPersistence.INSTANCE;
swissTimingReplayService = ServiceTrackerFactory.createAndOpen(context, SwissTimingReplayServiceFactory.class) swissTimingReplayService = ServiceTrackerFactory.createAndOpen(context, SwissTimingReplayServiceFactory.class)
.getService().createSwissTimingReplayService(getSwissTimingAdapter().getSwissTimingDomainFactory()); .getService().createSwissTimingReplayService(getSwissTimingAdapter().getSwissTimingDomainFactory(),
/* raceLogResolver */ getService());
scoreCorrectionProviderServiceTracker = ServiceTrackerFactory.createAndOpen(context, scoreCorrectionProviderServiceTracker = ServiceTrackerFactory.createAndOpen(context,
ScoreCorrectionProvider.class); ScoreCorrectionProvider.class);
tractracDomainObjectFactory = com.sap.sailing.domain.tractracadapter.persistence.PersistenceFactory.INSTANCE tractracDomainObjectFactory = com.sap.sailing.domain.tractracadapter.persistence.PersistenceFactory.INSTANCE
@@ -844,18 +844,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
return raceColumnDTOs; 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(); RaceInfoDTO raceInfoDTO = new RaceInfoDTO();
RaceLog raceLog = raceColumn.getRaceLog(fleet); RaceLog raceLog = raceColumn.getRaceLog(fleet);
if (raceLog != null) { if (raceLog != null) {
raceInfoDTO.isTracked = raceColumn.getTrackedRace(fleet) != null ? true : false; raceInfoDTO.isTracked = raceColumn.getTrackedRace(fleet) != null ? true : false;
final HasRegattaLike regattaLike; ReadonlyRaceState state = ReadonlyRaceStateImpl.create(getService(), raceLog);
if (leaderboard instanceof HasRegattaLike) {
regattaLike = (HasRegattaLike) leaderboard;
} else {
regattaLike = null;
}
ReadonlyRaceState state = ReadonlyRaceStateImpl.create(new ServerSideRaceLogResolver(regattaLike), raceLog);
TimePoint startTime = state.getStartTime(); TimePoint startTime = state.getStartTime();
if (startTime != null) { if (startTime != null) {
raceInfoDTO.startTime = startTime.asDate(); raceInfoDTO.startTime = startTime.asDate();
@@ -4242,7 +4236,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
entry.boatClassName = boatClassName; entry.boatClassName = boatClassName;
entry.regattaDisplayName = regattaName; entry.regattaDisplayName = regattaName;
entry.regattaName = leaderboard.getName(); entry.regattaName = leaderboard.getName();
entry.raceInfo = createRaceInfoDTO(leaderboard, seriesName, raceColumn, fleet); entry.raceInfo = createRaceInfoDTO(seriesName, raceColumn, fleet);
entry.currentServerTime = new Date(); entry.currentServerTime = new Date();
if (showOnlyRacesOfSameDay) { if (showOnlyRacesOfSameDay) {
@@ -1,6 +1,7 @@
package com.sap.sailing.gwt.ui.shared.dispatch.event; package com.sap.sailing.gwt.ui.shared.dispatch.event;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@@ -50,12 +51,13 @@ public class GetEventOverviewNewsAction implements Action<ResultWithTTL<ListResu
newsItems = newsItems.subList(0, limit); newsItems = newsItems.subList(0, limit);
} }
List<NewsEntryDTO> news = new ArrayList<>(newsItems.size()); List<NewsEntryDTO> news = new ArrayList<>(newsItems.size());
Date currentTimestamp = new Date();
for(EventNewsItem newsItem: newsItems) { for(EventNewsItem newsItem: newsItems) {
if(newsItem instanceof InfoEventNewsItem) { 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) { if(newsItem instanceof LeaderboardUpdateNewsItem) {
news.add(new LeaderboardNewsEntryDTO((LeaderboardUpdateNewsItem) newsItem)); news.add(new LeaderboardNewsEntryDTO((LeaderboardUpdateNewsItem) newsItem, currentTimestamp));
} }
} }
return news; return news;
@@ -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.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent; 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.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.analyzing.impl.WindFixesFinder;
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState; 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.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.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.Leaderboard; 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.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.TrackedRace;
import com.sap.sailing.domain.tracking.WindTrack; import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.WindWithConfidence; import com.sap.sailing.domain.tracking.WindWithConfidence;
@@ -59,18 +57,16 @@ public class RaceContext {
private final ReadonlyRaceState state; private final ReadonlyRaceState state;
private final Event event; private final Event event;
private final long TIME_TO_SHOW_CANCELED_RACES_AS_LIVE = 5 * 60 * 1000; // 5 min 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.event = event;
this.leaderboardGroup = leaderboardGroup;
this.leaderboard = leaderboard; this.leaderboard = leaderboard;
this.raceColumn = raceColumn; this.raceColumn = raceColumn;
this.raceDefinition = raceColumn.getRaceDefinition(fleet); this.raceDefinition = raceColumn.getRaceDefinition(fleet);
this.fleet = fleet; this.fleet = fleet;
trackedRace = raceColumn.getTrackedRace(fleet); trackedRace = raceColumn.getTrackedRace(fleet);
raceLog = raceColumn.getRaceLog(fleet); raceLog = raceColumn.getRaceLog(fleet);
state = ReadonlyRaceStateImpl.create(new ServerSideRaceLogResolver((HasRegattaLike) leaderboard), raceLog); state = ReadonlyRaceStateImpl.create(raceLogResolver, raceLog);
} }
private boolean isShowFleetData() { private boolean isShowFleetData() {
@@ -339,8 +335,7 @@ public class RaceContext {
} else if (finishTime != null && now.after(finishTime)) { } else if (finishTime != null && now.after(finishTime)) {
raceState = RaceViewState.FINISHED; raceState = RaceViewState.FINISHED;
} else if(raceLog != null) { } else if(raceLog != null) {
AbortingFlagFinder abortingFlagFinder = new AbortingFlagFinder(raceLog); RaceLogFlagEvent abortingFlagEvent = checkForAbortFlagEvent();
RaceLogFlagEvent abortingFlagEvent = abortingFlagFinder.analyze();
if (abortingFlagEvent != null) { if (abortingFlagEvent != null) {
Flags upperFlag = abortingFlagEvent.getUpperFlag(); Flags upperFlag = abortingFlagEvent.getUpperFlag();
if(upperFlag.equals(Flags.AP)) { if(upperFlag.equals(Flags.AP)) {
@@ -387,12 +382,4 @@ public class RaceContext {
public RegattaAndRaceIdentifier getRaceIdentifier() { public RegattaAndRaceIdentifier getRaceIdentifier() {
return trackedRace.getRaceIdentifier(); return trackedRace.getRaceIdentifier();
} }
public Leaderboard getLeaderboard() {
return leaderboard;
}
public LeaderboardGroup getLeaderboardGroup() {
return leaderboardGroup;
}
} }
@@ -25,7 +25,7 @@ public final class RacesActionUtil {
for (Leaderboard lb : lg.getLeaderboards()) { for (Leaderboard lb : lg.getLeaderboards()) {
for(RaceColumn raceColumn : lb.getRaceColumns()) { for(RaceColumn raceColumn : lb.getRaceColumns()) {
for(Fleet fleet : raceColumn.getFleets()) { 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); Leaderboard lb = context.getRacingEventService().getLeaderboardByName(regattaName);
for(RaceColumn raceColumn : lb.getRaceColumns()) { for(RaceColumn raceColumn : lb.getRaceColumns()) {
for(Fleet fleet : raceColumn.getFleets()) { for(Fleet fleet : raceColumn.getFleets()) {
// TODO LeaderboardGroup callback.doForRace(new RaceContext(event, lb, raceColumn, fleet, context.getRacingEventService()));
callback.doForRace(new RaceContext(event, null, lb, raceColumn, fleet));
} }
} }
} }
@@ -14,8 +14,8 @@ public abstract class AbstractRaceNewsEntryDTO extends NewsEntryDTO {
} }
@GwtIncompatible @GwtIncompatible
public AbstractRaceNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp) { public AbstractRaceNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp, Date currentTimestamp) {
super(raceTitle, timestamp, null); super(raceTitle, timestamp, currentTimestamp, null);
this.regattaName = regattaName; this.regattaName = regattaName;
this.trackedRaceName = trackedRaceName; this.trackedRaceName = trackedRaceName;
this.boatClass = boatClass; this.boatClass = boatClass;
@@ -1,5 +1,6 @@
package com.sap.sailing.gwt.ui.shared.dispatch.news; package com.sap.sailing.gwt.ui.shared.dispatch.news;
import java.util.Date;
import java.util.Locale; import java.util.Locale;
import com.google.gwt.core.shared.GwtIncompatible; import com.google.gwt.core.shared.GwtIncompatible;
@@ -14,8 +15,8 @@ public class InfoNewsEntryDTO extends NewsEntryDTO {
} }
@GwtIncompatible @GwtIncompatible
public InfoNewsEntryDTO(InfoEventNewsItem item, Locale locale) { public InfoNewsEntryDTO(InfoEventNewsItem item, Locale locale, Date currentTimestamp) {
super(item.getTitle(locale), item.getCreatedAtDate(), item.getRelatedItemLink()); super(item.getTitle(locale), item.getCreatedAtDate(), currentTimestamp, item.getRelatedItemLink());
this.subtitle = item.getMessage(locale); this.subtitle = item.getMessage(locale);
} }
@@ -1,5 +1,7 @@
package com.sap.sailing.gwt.ui.shared.dispatch.news; package com.sap.sailing.gwt.ui.shared.dispatch.news;
import java.util.Date;
import com.google.gwt.core.shared.GwtIncompatible; import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.news.impl.LeaderboardUpdateNewsItem; import com.sap.sailing.news.impl.LeaderboardUpdateNewsItem;
@@ -19,8 +21,8 @@ public class LeaderboardNewsEntryDTO extends NewsEntryDTO {
} }
@GwtIncompatible @GwtIncompatible
public LeaderboardNewsEntryDTO(LeaderboardUpdateNewsItem item) { public LeaderboardNewsEntryDTO(LeaderboardUpdateNewsItem item, Date currentTimestamp) {
super(item.getTitle(), item.getCreatedAtDate(), null); super(item.getTitle(), item.getCreatedAtDate(), currentTimestamp, null);
this.boatClassName = item.getBoatClass(); this.boatClassName = item.getBoatClass();
this.type = Type.RESULTS_UPDATE; this.type = Type.RESULTS_UPDATE;
this.leaderboardName = item.getLeaderboardName(); this.leaderboardName = item.getLeaderboardName();
@@ -8,7 +8,9 @@ import com.sap.sailing.gwt.ui.shared.dispatch.DTO;
public abstract class NewsEntryDTO implements DTO { public abstract class NewsEntryDTO implements DTO {
private Date timestamp; private Date newsTimestamp;
private Date currentTimestamp;
private String title; private String title;
@@ -18,14 +20,15 @@ public abstract class NewsEntryDTO implements DTO {
} }
@GwtIncompatible @GwtIncompatible
public NewsEntryDTO(String title, Date timestamp, URL externalURL) { public NewsEntryDTO(String title, Date timestamp, Date currentTimestamp, URL externalURL) {
this(title, timestamp, externalURL == null ? null : externalURL.toString()); this(title, timestamp, currentTimestamp, externalURL == null ? null : externalURL.toString());
} }
@GwtIncompatible @GwtIncompatible
private NewsEntryDTO(String title, Date timestamp, String externalURL) { private NewsEntryDTO(String title, Date newsTimestamp, Date currentTimestamp, String externalURL) {
this.title = title; this.title = title;
this.timestamp = timestamp; this.newsTimestamp = newsTimestamp;
this.currentTimestamp = currentTimestamp;
this.externalURL = externalURL; this.externalURL = externalURL;
} }
@@ -38,10 +41,14 @@ public abstract class NewsEntryDTO implements DTO {
public abstract String getBoatClass(); public abstract String getBoatClass();
public Date getTimestamp() { public Date getTimestamp() {
return timestamp; return newsTimestamp;
} }
public String getExternalURL() { public String getExternalURL() {
return externalURL; return externalURL;
} }
public Date getCurrentTimestamp() {
return currentTimestamp;
}
} }
@@ -17,8 +17,8 @@ public class RaceCompetitorNewsEntryDTO extends AbstractRaceNewsEntryDTO {
private RaceCompetitorNewsEntryDTO() { private RaceCompetitorNewsEntryDTO() {
} }
public RaceCompetitorNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp, String competitorName, Type type) { public RaceCompetitorNewsEntryDTO(String regattaName, String trackedRaceName, String raceTitle, String boatClass, Date timestamp, String competitorName, Type type, Date currentTimestamp) {
super(regattaName, trackedRaceName, raceTitle, boatClass, timestamp); super(regattaName, trackedRaceName, raceTitle, boatClass, timestamp, currentTimestamp);
this.competitorName = competitorName; this.competitorName = competitorName;
this.type = type; this.type = type;
} }
@@ -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);
}
}
@@ -3,6 +3,7 @@ package com.sap.sailing.mongodb.test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@@ -16,6 +17,7 @@ import com.mongodb.DB;
import com.mongodb.Mongo; import com.mongodb.Mongo;
import com.mongodb.MongoClient; import com.mongodb.MongoClient;
import com.mongodb.MongoException; 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.RaceDefinition;
import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Sideline; import com.sap.sailing.domain.base.Sideline;
@@ -87,7 +89,8 @@ public class TestStoringAndRetrievingWindTracksTest extends AbstractTracTracLive
@Override @Override
public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) { 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); addListenersForStoredDataAndStartController(typeControllers);
RaceDefinition race = domainFactory.getAndWaitForRaceDefinition(getTracTracEvent().getRaces().iterator().next().getId()); RaceDefinition race = domainFactory.getAndWaitForRaceDefinition(getTracTracEvent().getRaces().iterator().next().getId());
DynamicTrackedRace trackedRace = trackedRegatta.createTrackedRace(race, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, DynamicTrackedRace trackedRace = trackedRegatta.createTrackedRace(race, Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE,
@@ -95,7 +98,7 @@ public class TestStoringAndRetrievingWindTracksTest extends AbstractTracTracLive
@Override @Override
public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) { public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) {
} }
}, /*useMarkPassingCalculator*/ false); }, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class));
WindSource windSource = new WindSourceImpl(WindSourceType.WEB); WindSource windSource = new WindSourceImpl(WindSourceType.WEB);
Mongo myFirstMongo = newMongo(); Mongo myFirstMongo = newMongo();
DB firstDatabase = myFirstMongo.getDB(dbConfiguration.getDatabaseName()); DB firstDatabase = myFirstMongo.getDB(dbConfiguration.getDatabaseName());
@@ -25,8 +25,9 @@ public class RaceLogFixedMarkPassingEventDeserializer extends BaseRaceLogEventDe
TimePoint timePoint, int passId, List<Competitor> competitors) throws JsonDeserializationException { TimePoint timePoint, int passId, List<Competitor> competitors) throws JsonDeserializationException {
TimePoint ofPassing = new MillisecondsTimePoint( TimePoint ofPassing = new MillisecondsTimePoint(
(Long) object.get(RaceLogFixedMarkPassingEventSerializer.FIELD_TIMEPOINT_OF_MARKPASSING)); (Long) object.get(RaceLogFixedMarkPassingEventSerializer.FIELD_TIMEPOINT_OF_MARKPASSING));
Integer zeroBasedIndexOfPassedWaypoint = (Integer) object Number zeroBasedIndexOfPassedWaypointObj = (Number) object
.get(RaceLogFixedMarkPassingEventSerializer.FIELD_INDEX_OF_PASSED_WAYPOINT); .get(RaceLogFixedMarkPassingEventSerializer.FIELD_INDEX_OF_PASSED_WAYPOINT);
Integer zeroBasedIndexOfPassedWaypoint = zeroBasedIndexOfPassedWaypointObj != null ? zeroBasedIndexOfPassedWaypointObj.intValue() : null;
return factory.createFixedMarkPassingEvent(timePoint, author, id, competitors, passId, ofPassing, return factory.createFixedMarkPassingEvent(timePoint, author, id, competitors, passId, ofPassing,
zeroBasedIndexOfPassedWaypoint); zeroBasedIndexOfPassedWaypoint);
} }
@@ -42,7 +42,7 @@ public class EventRaceStatesJsonGetServlet extends AbstractJsonHttpServlet {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Event "+eventIdParam+" not found"); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Event "+eventIdParam+" not found");
} else { } else {
EventRaceStatesSerializer eventRaceStatesSerializer = new EventRaceStatesSerializer(filterByCourseAreaParam, EventRaceStatesSerializer eventRaceStatesSerializer = new EventRaceStatesSerializer(filterByCourseAreaParam,
filterByLeaderboardParam, filterByDayOffsetParam); filterByLeaderboardParam, filterByDayOffsetParam, getService());
JSONObject result = eventRaceStatesSerializer.serialize(new Pair<Event, Iterable<Leaderboard>>(event, getService().getLeaderboards().values())); JSONObject result = eventRaceStatesSerializer.serialize(new Pair<Event, Iterable<Leaderboard>>(event, getService().getLeaderboards().values()));
setJsonResponseHeader(response); setJsonResponseHeader(response);
result.writeJSONString(response.getWriter()); result.writeJSONString(response.getWriter());
@@ -6,6 +6,7 @@ import java.util.Date;
import org.json.simple.JSONArray; import org.json.simple.JSONArray;
import org.json.simple.JSONObject; 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.CourseArea;
import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.Fleet;
@@ -19,31 +20,30 @@ public class EventRaceStatesSerializer implements JsonSerializer<Pair<Event, Ite
public static final String FIELD_EVENT_ID = "id"; public static final String FIELD_EVENT_ID = "id";
public static final String FIELD_RACE_STATES = "raceStates"; public static final String FIELD_RACE_STATES = "raceStates";
private String filterByCourseArea; private final String filterByCourseArea;
private String filterByLeaderboardName; private final String filterByLeaderboardName;
private Calendar filterDay; private final Calendar filterDay;
private final RaceLogResolver raceLogResolver;
public EventRaceStatesSerializer() { public EventRaceStatesSerializer(String filterByCourseArea, String filterByLeaderboard, String filterByDayOffset, RaceLogResolver raceLogResolver) {
this.filterByCourseArea = null;
this.filterByLeaderboardName = null;
this.filterDay = null;
}
public EventRaceStatesSerializer(String filterByCourseArea, String filterByLeaderboard, String filterByDayOffset) {
this.filterByCourseArea = filterByCourseArea; this.filterByCourseArea = filterByCourseArea;
this.filterByLeaderboardName = filterByLeaderboard; this.filterByLeaderboardName = filterByLeaderboard;
this.raceLogResolver = raceLogResolver;
Integer dayOffset = null; Integer dayOffset = null;
if(filterByDayOffset != null) { if (filterByDayOffset != null) {
Calendar myFilterDay;
try { try {
dayOffset = Integer.parseInt(filterByDayOffset); dayOffset = Integer.parseInt(filterByDayOffset);
filterDay = Calendar.getInstance(); myFilterDay = Calendar.getInstance();
filterDay.setTime(new Date()); myFilterDay.setTime(new Date());
filterDay.add(Calendar.DAY_OF_YEAR, dayOffset); myFilterDay.add(Calendar.DAY_OF_YEAR, dayOffset);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// invalid integer // invalid integer
filterDay = null; myFilterDay = null;
} }
filterDay = myFilterDay;
} else {
filterDay = null;
} }
} }
@@ -60,7 +60,7 @@ public class EventRaceStatesSerializer implements JsonSerializer<Pair<Event, Ite
for (CourseArea courseArea : event.getVenue().getCourseAreas()) { for (CourseArea courseArea : event.getVenue().getCourseAreas()) {
if(filterByCourseArea == null || courseArea.getName().equals(filterByCourseArea)) { if(filterByCourseArea == null || courseArea.getName().equals(filterByCourseArea)) {
for (Leaderboard leaderboard : leaderboards) { for (Leaderboard leaderboard : leaderboards) {
RaceStateSerializer raceStateSerializer = new RaceStateSerializer(leaderboard); RaceStateSerializer raceStateSerializer = new RaceStateSerializer(raceLogResolver);
if (filterByLeaderboardName == null || leaderboard.getName().equals(filterByLeaderboardName)) { if (filterByLeaderboardName == null || leaderboard.getName().equals(filterByLeaderboardName)) {
if (leaderboard.getDefaultCourseArea() != null && leaderboard.getDefaultCourseArea().equals(courseArea)) { if (leaderboard.getDefaultCourseArea() != null && leaderboard.getDefaultCourseArea().equals(courseArea)) {
String leaderboardName = leaderboard.getName(); String leaderboardName = leaderboard.getName();
@@ -88,7 +88,7 @@ public class EventsResource extends AbstractSailingServerResource {
response = getBadEventErrorResponse(eventId); response = getBadEventErrorResponse(eventId);
} else { } else {
EventRaceStatesSerializer eventRaceStatesSerializer = new EventRaceStatesSerializer(filterByCourseArea, EventRaceStatesSerializer eventRaceStatesSerializer = new EventRaceStatesSerializer(filterByCourseArea,
filterByLeaderboard, filterByDayOffset); filterByLeaderboard, filterByDayOffset, getService());
JSONObject raceStatesJson = eventRaceStatesSerializer.serialize(new Pair<Event, Iterable<Leaderboard>>(event, getService().getLeaderboards().values())); JSONObject raceStatesJson = eventRaceStatesSerializer.serialize(new Pair<Event, Iterable<Leaderboard>>(event, getService().getLeaderboards().values()));
String json = raceStatesJson.toJSONString(); String json = raceStatesJson.toJSONString();
response = Response.ok(json, MediaType.APPLICATION_JSON).build(); response = Response.ok(json, MediaType.APPLICATION_JSON).build();
@@ -7,9 +7,10 @@ import org.json.simple.JSONObject;
import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent; 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.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.FinishedTimeFinder;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.LastFlagsFinder; 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.ReadonlyRaceState;
import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl; import com.sap.sailing.domain.abstractlog.race.state.impl.ReadonlyRaceStateImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.gate.ReadonlyGateStartRacingProcedure; 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.base.RaceColumn;
import com.sap.sailing.domain.common.RaceIdentifier; import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; 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.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.sailing.server.gateway.serialization.JsonSerializer;
import com.sap.sse.common.TimePoint; import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Pair;
public class RaceStateSerializer implements JsonSerializer<Pair<RaceColumn, Fleet>> { public class RaceStateSerializer implements JsonSerializer<Pair<RaceColumn, Fleet>> {
private final HasRegattaLike regattaLike; private final RaceLogResolver raceLogResolver;
public RaceStateSerializer(Leaderboard leaderboard) { public RaceStateSerializer(RaceLogResolver raceLogResolver) {
if (leaderboard instanceof HasRegattaLike) { this.raceLogResolver = raceLogResolver;
regattaLike = (HasRegattaLike) leaderboard;
} else {
regattaLike = null;
}
} }
@Override @Override
@@ -49,7 +43,7 @@ public class RaceStateSerializer implements JsonSerializer<Pair<RaceColumn, Flee
result.put("trackedRaceId", raceIdentifier != null ? raceIdentifier.toString() : null); result.put("trackedRaceId", raceIdentifier != null ? raceIdentifier.toString() : null);
RaceLog raceLog = raceColumn.getRaceLog(fleet); RaceLog raceLog = raceColumn.getRaceLog(fleet);
if (raceLog != null && !raceLog.isEmpty()) { if (raceLog != null && !raceLog.isEmpty()) {
ReadonlyRaceState state = ReadonlyRaceStateImpl.create(new ServerSideRaceLogResolver(regattaLike),raceLog); ReadonlyRaceState state = ReadonlyRaceStateImpl.create(raceLogResolver, raceLog);
RaceLogRaceStatus status = state.getStatus(); RaceLogRaceStatus status = state.getStatus();
TimePoint startTime = state.getStartTime(); TimePoint startTime = state.getStartTime();
TimePoint finishedTime = state.getFinishedTime(); TimePoint finishedTime = state.getFinishedTime();
@@ -91,7 +85,7 @@ public class RaceStateSerializer implements JsonSerializer<Pair<RaceColumn, Flee
boolean result = false; boolean result = false;
RaceLog raceLog = raceColumn.getRaceLog(fleet); RaceLog raceLog = raceColumn.getRaceLog(fleet);
if (raceLog != null && !raceLog.isEmpty()) { if (raceLog != null && !raceLog.isEmpty()) {
TimePoint startTime = new StartTimeFinder(new ServerSideRaceLogResolver(regattaLike), raceLog).analyze().getStartTime(); TimePoint startTime = new StartTimeFinder(raceLogResolver, raceLog).analyze().getStartTime();
TimePoint finishedTime = new FinishedTimeFinder(raceLog).analyze(); TimePoint finishedTime = new FinishedTimeFinder(raceLog).analyze();
RaceLogFlagEvent abortingFlagEvent = new AbortingFlagFinder(raceLog).analyze(); RaceLogFlagEvent abortingFlagEvent = new AbortingFlagFinder(raceLog).analyze();
TimePoint abortingTime = abortingFlagEvent != null ? abortingFlagEvent.getLogicalTimePoint() : null; TimePoint abortingTime = abortingFlagEvent != null ? abortingFlagEvent.getLogicalTimePoint() : null;
@@ -45,6 +45,7 @@ import com.sap.sailing.domain.persistence.MongoWindStore;
import com.sap.sailing.domain.persistence.MongoWindStoreFactory; import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
import com.sap.sailing.domain.persistence.PersistenceFactory; import com.sap.sailing.domain.persistence.PersistenceFactory;
import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore; import com.sap.sailing.domain.racelog.tracking.EmptyGPSFixStore;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.tracking.DynamicTrackedRace; import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta; import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.GPSFixTrack;
@@ -67,6 +68,11 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
final EmptyGPSFixStore gpsFixStore = EmptyGPSFixStore.INSTANCE;
setUp(gpsFixStore);
}
protected void setUp(final GPSFixStore gpsFixStore) throws Exception, UnknownHostException, InterruptedException {
super.setUp(); super.setUp();
final String boatClassName = "49er"; final String boatClassName = "49er";
// FIXME use master DomainFactory; see bug 592 // FIXME use master DomainFactory; see bug 592
@@ -95,11 +101,27 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
trackedRegatta = master.apply(new TrackRegatta(raceIdentifier)); trackedRegatta = master.apply(new TrackRegatta(raceIdentifier));
trackedRace = (DynamicTrackedRace) master.apply(new CreateTrackedRace(raceIdentifier, trackedRace = (DynamicTrackedRace) master.apply(new CreateTrackedRace(raceIdentifier,
MongoWindStoreFactory.INSTANCE.getMongoWindStore(PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(), MongoWindStoreFactory.INSTANCE.getMongoWindStore(PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(),
PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory()), EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 5000, PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory()), gpsFixStore, /* delayToLiveInMillis */ 5000,
/* millisecondsOverWhichToAverageWind */ 10000, /* millisecondsOverWhichToAverageSpeed */10000)); /* millisecondsOverWhichToAverageWind */ 10000, /* millisecondsOverWhichToAverageSpeed */10000));
trackedRace.waitUntilLoadingFromWindStoreComplete(); trackedRace.waitUntilLoadingFromWindStoreComplete();
} }
protected Competitor getCompetitor() {
return competitor;
}
protected DynamicTrackedRace getTrackedRace() {
return trackedRace;
}
protected RegattaNameAndRaceName getRaceIdentifier() {
return raceIdentifier;
}
protected DynamicTrackedRegatta getTrackedRegatta() {
return trackedRegatta;
}
@Test @Test
public void testGPSFixReplication() throws InterruptedException { public void testGPSFixReplication() throws InterruptedException {
final GPSFixMovingImpl fix = new GPSFixMovingImpl(new DegreePosition(1, 2), new MillisecondsTimePoint(12345), final GPSFixMovingImpl fix = new GPSFixMovingImpl(new DegreePosition(1, 2), new MillisecondsTimePoint(12345),
@@ -0,0 +1,149 @@
package com.sap.sailing.server.replication.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
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.tracking.GPSFixMoving;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
import com.sap.sailing.domain.persistence.PersistenceFactory;
import com.sap.sailing.domain.persistence.racelog.tracking.MongoGPSFixStore;
import com.sap.sailing.domain.persistence.racelog.tracking.MongoGPSFixStoreFactory;
import com.sap.sailing.domain.racelog.tracking.GPSFixStore;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.operationaltransformation.AddDefaultRegatta;
import com.sap.sailing.server.operationaltransformation.AddRaceDefinition;
import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
import com.sap.sailing.server.operationaltransformation.TrackRegatta;
import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.replication.ReplicationMasterDescriptor;
import com.sap.sse.replication.testsupport.AbstractServerReplicationTestSetUp.ReplicationServiceTestImpl;
/**
* Runs the same tests as {@link TrackedRaceContentsReplicationTest}, but with a non-empty {@link MongoGPSFixStore} that
* has special serialization requirements.
*
* @author Axel Uhl (d043530)
*
*/
public class TrackedRaceWithGPSFixStoreContentsReplicationTest extends AbstractServerReplicationTest {
private Competitor competitor;
private DynamicTrackedRace trackedRace;
private RegattaNameAndRaceName raceIdentifier;
private DynamicTrackedRegatta trackedRegatta;
@Before
public void setUp() throws Exception, UnknownHostException, InterruptedException {
final GPSFixStore gpsFixStore = MongoGPSFixStoreFactory.INSTANCE.getMongoGPSFixStore(PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(),
PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory(), /* serviceFinderFactory */ null);
Pair<ReplicationServiceTestImpl<RacingEventService>, 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<PersonImpl>) 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<Waypoint>());
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<Competitor, GPSFixMoving> 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();
}
}
}
@@ -6,6 +6,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
@@ -20,6 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; 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.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory; import com.sap.sailing.domain.base.DomainFactory;
@@ -78,13 +80,13 @@ public class RaceTrackerStartStopTest {
raceDef3 = new RaceDefinitionImpl(RACENAME3, new CourseImpl("Course3", new ArrayList<Waypoint>()), boatClass, new ArrayList<Competitor>()); raceDef3 = new RaceDefinitionImpl(RACENAME3, new CourseImpl("Course3", new ArrayList<Waypoint>()), boatClass, new ArrayList<Competitor>());
regatta.addRace(raceDef1); regatta.addRace(raceDef1);
trackedRegatta1.createTrackedRace(raceDef1, Collections.<Sideline> emptyList(), /* windStore */ EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l, trackedRegatta1.createTrackedRace(raceDef1, Collections.<Sideline> 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); regatta.addRace(raceDef2);
trackedRegatta1.createTrackedRace(raceDef2, Collections.<Sideline> emptyList(), /* windStore */ EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l, trackedRegatta1.createTrackedRace(raceDef2, Collections.<Sideline> 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); regatta.addRace(raceDef3);
trackedRegatta1.createTrackedRace(raceDef3, Collections.<Sideline> emptyList(), /* windStore */ EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l, trackedRegatta1.createTrackedRace(raceDef3, Collections.<Sideline> 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<RaceDefinition> raceDefinitionSetRace1 = new HashSet<RaceDefinition>(); Set<RaceDefinition> raceDefinitionSetRace1 = new HashSet<RaceDefinition>();
raceDefinitionSetRace1.add(raceDef1); raceDefinitionSetRace1.add(raceDef1);
Set<RaceDefinition> raceDefinitionSetRace2 = new HashSet<RaceDefinition>(); Set<RaceDefinition> raceDefinitionSetRace2 = new HashSet<RaceDefinition>();
@@ -16,6 +16,7 @@ import java.util.concurrent.ConcurrentHashMap;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent; 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.Competitor;
import com.sap.sailing.domain.base.CompetitorStore; import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sailing.domain.base.CourseArea; 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, public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetcher, RegattaRegistry, RaceFetcher,
LeaderboardRegistry, EventResolver, LeaderboardGroupResolver, TrackerManager, Searchable<LeaderboardSearchResult, KeywordQuery>, LeaderboardRegistry, EventResolver, LeaderboardGroupResolver, TrackerManager, Searchable<LeaderboardSearchResult, KeywordQuery>,
ReplicableWithObjectInputStream<RacingEventService, RacingEventServiceOperation<?>> { ReplicableWithObjectInputStream<RacingEventService, RacingEventServiceOperation<?>>, RaceLogResolver {
@Override @Override
Regatta getRegatta(RegattaName regattaName); Regatta getRegatta(RegattaName regattaName);
Loaded 100 of 113 files, more files were not shown because too many files have changed in this diff. Show more