added boolean takesWind(Wind wind) Method to TrackedRace and did some renaming

This commit is contained in:
Alexander Ries committed 2015-06-14 18:43:17 +02:00
1 parent 4abcc4f907
commit cbaf85766d
9 files changed
+78 -59

No files matched your search

@@ -18,12 +18,12 @@ import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
public abstract class AbstractRaceExecutionOrderProvider implements RaceExecutionOrderProvider, RaceColumnListenerWithDefaultAction {
private static final long serialVersionUID = 4795731834688229568L;
private transient SmartFutureCache<String, Map<TrackedRace, Set<TrackedRace>>, EmptyUpdateInterval> raceOrderCacheMappingRaceToItsPredecessor;
private transient SmartFutureCache<String, Map<TrackedRace, Set<TrackedRace>>, EmptyUpdateInterval> previousRacesByRaceCache;
private final String RACES_ORDER_LIST_CACHE_KEY = "racesOrderCacheKey";
private final String RACES_ORDER_LIST_LOCKS_NAME = getClass().getName();
public AbstractRaceExecutionOrderProvider() {
raceOrderCacheMappingRaceToItsPredecessor = createRacesOrderCache();
previousRacesByRaceCache = createRacesOrderCache();
triggerUpdate();
}
@@ -34,38 +34,38 @@ public abstract class AbstractRaceExecutionOrderProvider implements RaceExecutio
@Override
public void triggerUpdate() {
raceOrderCacheMappingRaceToItsPredecessor.triggerUpdate(RACES_ORDER_LIST_CACHE_KEY, /* update interval */null);
previousRacesByRaceCache.triggerUpdate(RACES_ORDER_LIST_CACHE_KEY, /* update interval */null);
}
private Map<TrackedRace, Set<TrackedRace>> getPredecessorsMap() {
return raceOrderCacheMappingRaceToItsPredecessor.get(RACES_ORDER_LIST_CACHE_KEY, /* waitForLatest */true);
private Map<TrackedRace, Set<TrackedRace>> getPreviousRacesByRace() {
return previousRacesByRaceCache.get(RACES_ORDER_LIST_CACHE_KEY, /* waitForLatest */true);
}
protected abstract Map<Fleet, Iterable<? extends RaceColumn>> getRaceColumnsOfSeries();
private Map<TrackedRace, Set<TrackedRace>> reloadRacesInExecutionOrder() {
final Map<TrackedRace, Set<TrackedRace>> raceIdListInExecutionOrder = new HashMap<>();
private Map<TrackedRace, Set<TrackedRace>> reloadAndGetPreviousRacesByRace() {
final Map<TrackedRace, Set<TrackedRace>> previousRacesByRace = new HashMap<>();
for (Entry<Fleet, Iterable<? extends RaceColumn>> raceColumnsInSeries : getRaceColumnsOfSeries().entrySet()) {
addPredecessors(raceIdListInExecutionOrder, raceColumnsInSeries.getKey(), raceColumnsInSeries.getValue());
addPreviousRaces(previousRacesByRace, raceColumnsInSeries.getKey(), raceColumnsInSeries.getValue());
}
return raceIdListInExecutionOrder;
return previousRacesByRace;
}
private void addPredecessors(final Map<TrackedRace, Set<TrackedRace>> raceIdListInExecutionOrder, Fleet fleet,
private void addPreviousRaces(final Map<TrackedRace, Set<TrackedRace>> previousRacesByRace, Fleet fleet,
final Iterable<? extends RaceColumn> raceColumns) {
TrackedRace predecessor = null;
TrackedRace previousRace = null;
for (RaceColumn currentRaceColumn : raceColumns) {
final TrackedRace trackedRaceInColumnForFleet = currentRaceColumn.getTrackedRace(fleet);
if (trackedRaceInColumnForFleet != null) {
Set<TrackedRace> predecessors = raceIdListInExecutionOrder.get(trackedRaceInColumnForFleet);
if (predecessors == null) {
predecessors = new HashSet<>();
raceIdListInExecutionOrder.put(trackedRaceInColumnForFleet, predecessors);
Set<TrackedRace> previousRaces = previousRacesByRace.get(trackedRaceInColumnForFleet);
if (previousRaces == null) {
previousRaces = new HashSet<>();
previousRacesByRace.put(trackedRaceInColumnForFleet, previousRaces);
}
if (predecessor != null) {
predecessors.add(predecessor);
if (previousRace != null) {
previousRaces.add(previousRace);
}
predecessor = trackedRaceInColumnForFleet;
previousRace = trackedRaceInColumnForFleet;
}
}
}
@@ -77,7 +77,7 @@ public abstract class AbstractRaceExecutionOrderProvider implements RaceExecutio
public Map<TrackedRace, Set<TrackedRace>> computeCacheUpdate(String key,
EmptyUpdateInterval updateInterval) throws Exception {
if (key.equals(RACES_ORDER_LIST_CACHE_KEY)) {
return reloadRacesInExecutionOrder();
return reloadAndGetPreviousRacesByRace();
} else {
final Map<TrackedRace, Set<TrackedRace>> emptyMap = Collections.emptyMap();
return emptyMap;
@@ -88,18 +88,18 @@ public abstract class AbstractRaceExecutionOrderProvider implements RaceExecutio
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
this.raceOrderCacheMappingRaceToItsPredecessor = createRacesOrderCache();
this.previousRacesByRaceCache = createRacesOrderCache();
// don't call triggerUpdate() as of now because the cache's owner may not yet be fully initialized,
// so the getRaceColumnsOfSeries() method may not yet be able to do its work. The owner must call
// triggerUpdate when fully initialized.
}
@Override
public Set<TrackedRace> getPreviousRaceInExecutionOrder(TrackedRace race) {
public Set<TrackedRace> getPreviousRacesInExecutionOrder(TrackedRace race) {
Set<TrackedRace> result = Collections.emptySet();
final Map<TrackedRace, Set<TrackedRace>> predecessorMap = getPredecessorsMap();
if (predecessorMap != null) {
result = predecessorMap.get(race);
final Map<TrackedRace, Set<TrackedRace>> previousRacesByRace = getPreviousRacesByRace();
if (previousRacesByRace != null) {
result = previousRacesByRace.get(race);
}
return result;
}
@@ -5,7 +5,7 @@ import java.util.Set;
import com.sap.sailing.domain.base.Regatta;
/**
* Sometimes {@link TrackedRace}s want to know which {@link TrackedRace} is in front of them in the execution order
* Sometimes {@link TrackedRace}s want to know which {@link DynamicTrackedRace} is in front of them in the execution order
* of a {@link Regatta}. This is i.e interesting to know in the {@link DynamicTrackedRace #recordWind(com.sap.sailing.domain.common.Wind, com.sap.sailing.domain.common.WindSource)}
* method, when the race has to decide whether to record the wind. If a previous {@link TrackedRace}
* is <code>null</code>, the current {@link TrackedRace} would save the wind fixes earlier.
@@ -20,7 +20,7 @@ public interface RaceExecutionOrderProvider {
* {@link TrackedRace}s in the execution order of a {@link Regatta}. This expresses the fact that the races returned
* by this method must all have been finished before <code>race</code> can start.
*/
Set<TrackedRace> getPreviousRaceInExecutionOrder(TrackedRace race);
Set<TrackedRace> getPreviousRacesInExecutionOrder(TrackedRace race);
/**
* When the owner of this cache-like provider has initialized all its structures that this cache requires
@@ -275,6 +275,11 @@ public interface TrackedRace extends Serializable {
* is returned. Otherwise, the center of gravity between the mark positions is computed and returned.
*/
Position getApproximatePosition(Waypoint waypoint, TimePoint timePoint);
/**
* Checks whether the {@link Wind#getTimePoint()} is in range of start and end {@link TimePoint}s plus extra time for wind recording.
*/
boolean takesWindFix(Wind wind);
/**
* Same as {@link #getWind(Position, TimePoint, Set) getWind(p, at, Collections.emptyList())}
@@ -24,7 +24,6 @@ import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.TimingConstants;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
@@ -46,12 +45,10 @@ import com.sap.sailing.domain.tracking.RaceAbortedListener;
import com.sap.sailing.domain.tracking.RaceChangeListener;
import com.sap.sailing.domain.tracking.StartTimeChangedListener;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRaceStatus;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -660,18 +657,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
@Override
public boolean recordWind(Wind wind, WindSource windSource) {
final boolean result;
// TODO check what a good filter is; remember that start/end of tracking may change over time; what if we have discarded valuable wind fixes?
TimePoint startOfRace = getStartOfRace();
TimePoint startOfTracking = getStartOfTracking();
TimePoint endOfRace = getEndOfRace();
TimePoint endOfTracking = getEndOfTracking();
final Duration conditionalTimeBeforeStartToTrackWind = getConditionalTimeBeforeStartToTrackWind(wind.getTimePoint());
if ((startOfTracking == null || !startOfTracking.minus(conditionalTimeBeforeStartToTrackWind).after(wind.getTimePoint()) ||
(startOfRace != null && !startOfRace.minus(conditionalTimeBeforeStartToTrackWind).after(wind.getTimePoint())))
&&
// Caution: don't add to endOfTracking; it may be the end of time, leading to a wrap-around / overflow
(endOfTracking == null || endOfTracking.after(wind.getTimePoint().minus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS)) ||
(endOfRace != null && endOfRace.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).after(wind.getTimePoint())))) {
if(takesWindFix(wind)){
result = getOrCreateWindTrack(windSource).add(wind);
updated(/* time point */null); // wind events shouldn't advance race time
triggerManeuverCacheRecalculationForAllCompetitors();
@@ -681,15 +667,6 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
}
return result;
}
private Duration getConditionalTimeBeforeStartToTrackWind(TimePoint timePointOfWindFix) {
Set<TrackedRace> previousRacesInExecutionOrder = getPreviousRacesFromAttachedRaceExecutionOrderProviders();
if (previousRacesInExecutionOrder == null || !previousRacesInExecutionOrder.stream().filter(tr->tr.getEndOfTracking() != null).findAny().isPresent()) {
return EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS;
} else {
return TIME_BEFORE_START_TO_TRACK_WIND_MILLIS;
}
}
@Override
public void removeWind(Wind wind, WindSource windSource) {
@@ -286,7 +286,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
*/
protected transient ConcurrentHashMap<Serializable, RegattaLog> attachedRegattaLogs;
private transient ConcurrentHashMap<RaceExecutionOrderProvider, RaceExecutionOrderProvider> attachedRaceExecutionOrderProvider;
private transient ConcurrentHashMap<RaceExecutionOrderProvider, RaceExecutionOrderProvider> attachedRaceExecutionOrderProviders;
/**
* The time delay to the current point in time in milliseconds.
@@ -380,7 +380,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
locksForMarkPassings = new IdentityHashMap<>();
attachedRaceLogs = new ConcurrentHashMap<>();
attachedRegattaLogs = new ConcurrentHashMap<>();
attachedRaceExecutionOrderProvider = new ConcurrentHashMap<>();
attachedRaceExecutionOrderProviders = new ConcurrentHashMap<>();
this.status = new TrackedRaceStatusImpl(TrackedRaceStatusEnum.PREPARED, 0.0);
this.statusNotifier = new Object[0];
this.loadingFromWindStoreLock = new NamedReentrantReadWriteLock("Loading from wind store lock for tracked race "
@@ -578,7 +578,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
ois.defaultReadObject();
raceStates = new WeakHashMap<>();
attachedRaceLogs = new ConcurrentHashMap<>();
attachedRaceExecutionOrderProvider = new ConcurrentHashMap<>();
attachedRaceExecutionOrderProviders = new ConcurrentHashMap<>();
markPassingsTimes = new ArrayList<com.sap.sse.common.Util.Pair<Waypoint, com.sap.sse.common.Util.Pair<TimePoint, TimePoint>>>();
// The short time wind cache needs to be there before operations such as maneuver recalculation try to access it
shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2);
@@ -1495,6 +1495,24 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
}
return result;
}
@Override
public boolean takesWindFix(Wind wind) {
boolean result = false;
TimePoint earliestStartTimePoint = Util.getEarliestOfTimePoints(getStartOfRace(), getStartOfTracking());
TimePoint latestEndTimePoint = Util.getLatestOfTimePoints(getStartOfRace(), getStartOfTracking());
if (earliestStartTimePoint != null && latestEndTimePoint != null) {
TimePoint earliestStartTimePointMinusExtra = earliestStartTimePoint.minus(EXTRA_LONG_TIME_BEFORE_START_TO_TRACK_WIND_MILLIS);
TimePoint latestEndTimePointPlusExtra = latestEndTimePoint.plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
if (Util.isTimePointInRangeOfTimePointsAandB(wind.getTimePoint(), /* a */earliestStartTimePointMinusExtra, /* b */latestEndTimePointPlusExtra)) {
Set<TrackedRace> previousRacesInExecutionOrder = getPreviousRacesFromAttachedRaceExecutionOrderProviders();
if(previousRacesInExecutionOrder == null || !previousRacesInExecutionOrder.stream().filter(tr->tr.takesWindFix(wind) == true).findAny().isPresent()){
result = true;
}
}
}
return result;
}
@Override
public Wind getWind(Position p, TimePoint at) {
@@ -3054,15 +3072,15 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
@Override
public void attachRaceExecutionProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
if (raceExecutionOrderProvider != null && !attachedRaceExecutionOrderProvider.containsKey(raceExecutionOrderProvider)) {
attachedRaceExecutionOrderProvider.put(raceExecutionOrderProvider, raceExecutionOrderProvider);
if (raceExecutionOrderProvider != null && !attachedRaceExecutionOrderProviders.containsKey(raceExecutionOrderProvider)) {
attachedRaceExecutionOrderProviders.put(raceExecutionOrderProvider, raceExecutionOrderProvider);
}
}
protected Set<TrackedRace> getPreviousRacesFromAttachedRaceExecutionOrderProviders() {
final Set<TrackedRace> result;
if (attachedRaceExecutionOrderProvider != null) {
result = attachedRaceExecutionOrderProvider.values().stream().map(reop->reop.getPreviousRaceInExecutionOrder(this)).collect(HashSet::new, (r, e)->r.addAll(e), (r, e)->r.addAll(e));
if (attachedRaceExecutionOrderProviders != null) {
result = attachedRaceExecutionOrderProviders.values().stream().map(reop->reop.getPreviousRacesInExecutionOrder(this)).collect(HashSet::new, (r, e)->r.addAll(e), (r, e)->r.addAll(e));
} else {
result = Collections.emptySet();
}
@@ -3072,7 +3090,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
@Override
public void detachRaceExecutionOrderProvider(RaceExecutionOrderProvider raceExecutionOrderProvider) {
if (raceExecutionOrderProvider != null) {
attachedRaceExecutionOrderProvider.remove(raceExecutionOrderProvider);
attachedRaceExecutionOrderProviders.remove(raceExecutionOrderProvider);
}
}