Move updateStartAndEndOfTracking to TrackedRaceImpl and set up some more handlers in DynamicTrackedRaceLogListener

This commit is contained in:
Jan Broß committed 2016-03-21 17:13:16 +01:00
1 parent 5da62f3b86
commit 6b135f7978
10 files changed
+175 -49

No files matched your search

@@ -75,9 +75,7 @@ import com.sap.sailing.domain.tracking.impl.TrackedRaceStatusImpl;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.WithID;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import difflib.PatchFailedException;
@@ -239,50 +237,6 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
return new RegattaLogDeviceMarkMappingFinder(params.getRegattaLog()).analyze();
}
/**
* Use mapping time ranges to set time start and end of tracking time for race
*/
private void updateStartAndEndOfTracking() {
// TODO bug 3196: this would need to be evaluated lazily in TrackedRaceImpl.getStartOfTracking / getEndOfTracking
final Pair<TimePoint, TimePoint> trackingTimesFromRaceLog = trackedRace.getTrackingTimesFromRaceLogs();
if (trackingTimesFromRaceLog == null) {
TimePoint earliestMappingStart = new MillisecondsTimePoint(Long.MAX_VALUE);
TimePoint latestMappingEnd = new MillisecondsTimePoint(Long.MIN_VALUE);
for (List<? extends DeviceMapping<?>> list : competitorMappings.values()) {
for (DeviceMapping<?> mapping : list) {
earliestMappingStart = getUpdatedEarliestMappingStart(earliestMappingStart, mapping.getTimeRange().from());
latestMappingEnd = getUpdatedLatestMappingEnd(latestMappingEnd, mapping.getTimeRange().to());
}
}
for (List<? extends DeviceMapping<?>> list : markMappings.values()) {
for (DeviceMapping<?> mapping : list) {
earliestMappingStart = getUpdatedEarliestMappingStart(earliestMappingStart, mapping.getTimeRange().from());
latestMappingEnd = getUpdatedLatestMappingEnd(latestMappingEnd, mapping.getTimeRange().to());
}
}
trackedRace.setStartOfTrackingReceived(earliestMappingStart == null ? TimePoint.BeginningOfTime : earliestMappingStart);
trackedRace.setEndOfTrackingReceived(latestMappingEnd == null ? TimePoint.EndOfTime : latestMappingEnd);
}
}
private TimePoint getUpdatedEarliestMappingStart(TimePoint earliestMappingStart, final TimePoint from) {
if (from == null) {
earliestMappingStart = null; // no further updates; one open interval means startOfTracking shall be the beginning of time
} else if (earliestMappingStart != null && from.before(earliestMappingStart)) {
earliestMappingStart = from;
}
return earliestMappingStart;
}
private TimePoint getUpdatedLatestMappingEnd(TimePoint latestMappingEnd, final TimePoint to) {
if (to == null) {
latestMappingEnd = null; // no further updates; one open interval means startOfTracking shall be the beginning of time
} else if (latestMappingEnd != null && to.after(latestMappingEnd)) {
latestMappingEnd = to;
}
return latestMappingEnd;
}
private <ItemT extends WithID, FixT extends GPSFix> boolean hasMappingAlreadyBeenLoaded(
DeviceMapping<ItemT> newMapping, List<DeviceMapping<ItemT>> oldMappings) {
if (oldMappings == null) {
@@ -355,7 +309,7 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
markMappingsByDevices.clear();
markMappingsByDevices.putAll(transformToMappingsByDevice(markMappings));
updateStartAndEndOfTracking();
trackedRace.updateStartAndEndOfTracking();
}
private void onDeviceMarkMappingEvent(RegattaLogDeviceMarkMappingEvent event) {
@@ -429,7 +383,7 @@ public class RaceLogRaceTracker implements RaceTracker, GPSFixReceivedListener {
competitorMappings.putAll(newMappings);
competitorMappingsByDevices.clear();
competitorMappingsByDevices.putAll(transformToMappingsByDevice(competitorMappings));
updateStartAndEndOfTracking();
trackedRace.updateStartAndEndOfTracking();
}
private void onStartTrackingEvent(RaceLogStartTrackingEvent event) {
@@ -1029,4 +1029,12 @@ public class MockedTrackedRace implements DynamicTrackedRace {
@Override
public void updateMarkPassingsAfterRaceLogChanges() {
}
@Override
public void updateStartAndEndOfTracking() {
}
@Override
public void onFinishedTimeChangedByRaceCommittee(TimePoint newFinishedTime) {
}
}
@@ -649,4 +649,8 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
public IsManagedByCache<SharedDomainFactory> resolve(SharedDomainFactory domainFactory) {
return this;
}
@Override
public void updateStartAndEndOfTracking() {
}
}
@@ -128,6 +128,7 @@ public interface DynamicTrackedRace extends TrackedRace {
void onCourseDesignChangedByRaceCommittee(CourseBase courseDesign);
void onStartTimeChangedByRaceCommittee(TimePoint newStartTime);
void onFinishedTimeChangedByRaceCommittee(TimePoint newFinishedTime);
void onAbortedByRaceCommittee(Flags flag);
@@ -865,6 +865,10 @@ public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomain
default Pair<TimePoint, TimePoint> getTrackingTimesFromRaceLogs() {
return null;
}
default Pair<TimePoint, TimePoint> getStartAndFinishedTimeFromRaceLogs() {
return null;
}
/**
* Returns all marks found in the {@link #markTracks} map and the mark device mappings and mark
@@ -875,4 +879,15 @@ public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomain
default Iterable<Mark> getMarksFromRegattaLogs() {
return getMarks();
}
/**
* Forces update of start and end of tracking.
* Adheres to the following precedence order
*
* 1) RaceLogStartOfTrackingEvent/RaceLogEndOfTrackingEvent
* 2) RaceLogStartTimeEvent - x Minutes, Race finished + x Minutes
* 3) Earliest Mapping, Latest Mapping (of Marks and Competitors)
* 4) Leave previously (manually set start/end of tracking)
*/
public void updateStartAndEndOfTracking();
}
@@ -978,6 +978,13 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
} catch (IOException e) {
logger.log(Level.INFO, "Exception trying to notify race status change listeners about start time change", e);
}
updateStartAndEndOfTracking();
}
@Override
public void onFinishedTimeChangedByRaceCommittee(TimePoint newFinishedTime) {
logger.info("Finished time of race "+getRace().getName()+" updated by race committee to "+newFinishedTime);
updateStartAndEndOfTracking();
}
@Override
@@ -1010,5 +1017,4 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
public DynamicGPSFixTrack<Mark, GPSFix> getTrack(Mark mark) {
return (DynamicGPSFixTrack<Mark, GPSFix>) super.getTrack(mark);
}
}
@@ -13,6 +13,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmed
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogPassChangeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartTimeEvent;
@@ -31,6 +32,7 @@ import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.WindSource;
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.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.RaceLogWindFixDeclinationHelper;
@@ -309,6 +311,14 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor {
markPassingUpdateListener.removeFixedPassing(revokedEvent.getInvolvedBoats().get(0),
((RaceLogFixedMarkPassingEvent) revokedEvent).getZeroBasedIndexOfPassedWaypoint());
}
if (revokedEvent instanceof RaceLogDependentStartTimeEvent || revokedEvent instanceof RaceLogStartTimeEvent){
analyzeStartTime(null);
}
if (revokedEvent instanceof RaceLogRaceStatusEvent){
if (((RaceLogRaceStatusEvent) revokedEvent).getNextStatus().equals(RaceLogRaceStatus.FINISHED)){
trackedRace.invalidateEndTime();
}
}
}
}
@@ -326,4 +336,11 @@ public class DynamicTrackedRaceLogListener extends BaseRaceLogEventVisitor {
public void visit(RaceLogEndOfTrackingEvent event) {
trackedRace.setEndOfTrackingReceived(event.getLogicalTimePoint());
}
@Override
public void visit(RaceLogRaceStatusEvent event) {
if (event.getNextStatus().equals(RaceLogRaceStatus.FINISHED)){
trackedRace.invalidateEndTime();
}
}
}
@@ -40,6 +40,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogGateLineOpeningTimeEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogStartOfTrackingEvent;
import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.FinishedTimeFinder;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinder;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.TrackingTimesFinder;
@@ -49,6 +50,8 @@ import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.ReadonlyRacingProcedure;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDefinedMarkAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceCompetitorMappingFinder;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMarkMappingFinder;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
@@ -111,6 +114,7 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
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;
import com.sap.sailing.domain.ranking.RankingMetric;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
@@ -156,6 +160,8 @@ import difflib.Patch;
import difflib.PatchFailedException;
public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials implements CourseListener {
private static final int TRACKING_BUFFER_IN_MINUTES = 5;
private static final long serialVersionUID = -4825546964220003507L;
private static final Logger logger = Logger.getLogger(TrackedRaceImpl.class.getName());
@@ -722,11 +728,100 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
@Override
public TimePoint getStartOfTracking() {
updateStartAndEndOfTracking();//FIXME: unclear whether change listeners etc similar to DynamicTrackedRace can be used here for caching and invalidation
return startOfTrackingReceived;
}
/**
* Use mapping time ranges to set time start and end of tracking time for race
*/
public void updateStartAndEndOfTracking() {
final Pair<TimePoint, TimePoint> trackingTimesFromRaceLog = this.getTrackingTimesFromRaceLogs();
final Pair<TimePoint, TimePoint> startAndFinishedTimesFromRaceLog = this.getStartAndFinishedTimeFromRaceLogs();
boolean startOfTrackingFound = false;
boolean endOfTrackingFound = false;
if (trackingTimesFromRaceLog != null){
if (trackingTimesFromRaceLog.getA() != null){
setStartOfTrackingReceived(trackingTimesFromRaceLog.getA(), false);
startOfTrackingFound = true;
}
if (trackingTimesFromRaceLog.getB() != null){
setEndOfTrackingReceived(trackingTimesFromRaceLog.getB(), false);
endOfTrackingFound = true;
}
}
if(!startOfTrackingFound || !endOfTrackingFound){
if (startAndFinishedTimesFromRaceLog != null){
if (!startOfTrackingFound && startAndFinishedTimesFromRaceLog.getA() != null){
setStartOfTrackingReceived(startAndFinishedTimesFromRaceLog.getA().minus(Duration.ONE_MINUTE.times(TRACKING_BUFFER_IN_MINUTES)), false);
startOfTrackingFound = true;
}
if (!endOfTrackingFound && startAndFinishedTimesFromRaceLog.getB() != null){
setEndOfTrackingReceived(startAndFinishedTimesFromRaceLog.getB().plus(Duration.ONE_MINUTE.times(TRACKING_BUFFER_IN_MINUTES)), false);
endOfTrackingFound = true;
}
}
}
if(!startOfTrackingFound || !endOfTrackingFound){
TimePoint earliestMappingStart = new MillisecondsTimePoint(Long.MAX_VALUE);
TimePoint latestMappingEnd = new MillisecondsTimePoint(Long.MIN_VALUE);
Map<Mark, List<DeviceMapping<Mark>>> markMappings = new HashMap<Mark, List<DeviceMapping<Mark>>>();
Map<Competitor, List<DeviceMapping<Competitor>>> competitorMappings = new HashMap<Competitor, List<DeviceMapping<Competitor>>>();
for (RegattaLog regattaLog: attachedRegattaLogs.values()){
competitorMappings.putAll(new RegattaLogDeviceCompetitorMappingFinder(regattaLog).analyze());
markMappings.putAll(new RegattaLogDeviceMarkMappingFinder(regattaLog).analyze());
}
for (List<? extends DeviceMapping<?>> list : competitorMappings.values()) {
for (DeviceMapping<?> mapping : list) {
earliestMappingStart = getUpdatedEarliestMappingStart(earliestMappingStart, mapping.getTimeRange().from());
latestMappingEnd = getUpdatedLatestMappingEnd(latestMappingEnd, mapping.getTimeRange().to());
}
}
for (List<? extends DeviceMapping<?>> list : markMappings.values()) {
for (DeviceMapping<?> mapping : list) {
earliestMappingStart = getUpdatedEarliestMappingStart(earliestMappingStart, mapping.getTimeRange().from());
latestMappingEnd = getUpdatedLatestMappingEnd(latestMappingEnd, mapping.getTimeRange().to());
}
}
if (!startOfTrackingFound && earliestMappingStart != null){
setStartOfTrackingReceived(earliestMappingStart, false);
}
if (!endOfTrackingFound && latestMappingEnd != null){
setEndOfTrackingReceived(latestMappingEnd, false);
}
}
}
private TimePoint getUpdatedEarliestMappingStart(TimePoint earliestMappingStart, final TimePoint from) {
if (from == null) {
earliestMappingStart = null; // no further updates; one open interval means startOfTracking shall be the beginning of time
} else if (earliestMappingStart != null && from.before(earliestMappingStart)) {
earliestMappingStart = from;
}
return earliestMappingStart;
}
private TimePoint getUpdatedLatestMappingEnd(TimePoint latestMappingEnd, final TimePoint to) {
if (to == null) {
latestMappingEnd = null; // no further updates; one open interval means startOfTracking shall be the beginning of time
} else if (latestMappingEnd != null && to.after(latestMappingEnd)) {
latestMappingEnd = to;
}
return latestMappingEnd;
}
@Override
public TimePoint getEndOfTracking() {
updateStartAndEndOfTracking();//FIXME: unclear whether change listeners etc similar to DynamicTrackedRace can be used here for caching and invalidation
return endOfTrackingReceived;
}
@@ -762,6 +857,20 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
}
return null;
}
@Override
public Pair<TimePoint, TimePoint> getStartAndFinishedTimeFromRaceLogs() {
//Only one of the RaceLogs should have valid data, so one doesn't have to compare all the
//start/finished time values in order to find the earliest startTime/latestFinishedTime
for (final RaceLog raceLog : attachedRaceLogs.values()) {
TimePoint startTime = new StartTimeFinder(raceLogResolver, raceLog).analyze().getStartTime();
TimePoint finishedTime = new FinishedTimeFinder(raceLog).analyze();
if (startTime != null || finishedTime != null){
return new Util.Pair<TimePoint, TimePoint>(startTime, finishedTime);
}
}
return null;
}
/**
* Calculates the start time of the race from various sources. The highest precedence take the {@link #attachedRaceLogs race logs},
@@ -790,4 +790,12 @@ public class MockedTrackedRace implements DynamicTrackedRace {
@Override
public void updateMarkPassingsAfterRaceLogChanges() {
}
@Override
public void updateStartAndEndOfTracking() {
}
@Override
public void onFinishedTimeChangedByRaceCommittee(TimePoint newFinishedTime) {
}
}
@@ -624,4 +624,8 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials {
public IsManagedByCache<SharedDomainFactory> resolve(SharedDomainFactory domainFactory) {
return this;
}
@Override
public void updateStartAndEndOfTracking() {
}
}