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
+1032 -516

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