Merge remote-tracking branch 'origin/master'

This commit is contained in:
fmittag committed 2012-06-19 11:02:41 +02:00
commit fe128232d1
37 files changed
+478 -140

No files matched your search

@@ -75,7 +75,7 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
@Override
public void addRaceDefinition(RaceDefinition race) {}
}, /* delayToLiveInMillis */ 0l,
/* millisecondsOverWhichToAverageWind */ 30000) {
/* millisecondsOverWhichToAverageWind */ 30000, /* simulator */ null) {
@Override
protected void handleEvent(Triple<Route, RouteData, Race> event) {
synchronized (routeData) {
@@ -49,25 +49,26 @@ public class MultipleClassesInRegattaTest {
new URL(
httpAndHost+"/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=cce678c8-97e6-11e0-9aed-406186cbf87c"),
new URI(liveURI), new URI(storedURI),
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false,
EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
kiwotest2 = domainFactory
.createRaceTracker(
new URL(
httpAndHost+"/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=11290bd6-97e7-11e0-9aed-406186cbf87c"),
new URI(liveURI), new URI(storedURI),
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
kiwotest3 = domainFactory
.createRaceTracker(
new URL(
httpAndHost+"/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=39635b24-97e7-11e0-9aed-406186cbf87c"),
new URI(liveURI), new URI(storedURI),
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
weym470may112014_2 = domainFactory
.createRaceTracker(
new URL(
httpAndHost+"/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=04498426-7dfd-11e0-8236-406186cbf87c"),
new URI(liveURI), new URI(storedURI),
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
assertEquals("STG", kiwotest1.getRegatta().getBoatClass().getName());
assertEquals("505", kiwotest2.getRegatta().getBoatClass().getName());
@@ -90,7 +90,8 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest {
setStoredDataLoaded(false);
ArrayList<Receiver> receivers = new ArrayList<Receiver>();
for (Receiver r : domainFactory.getUpdateReceivers(trackedRegatta, getTracTracEvent(), EmptyWindStore.INSTANCE,
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, new DynamicRaceDefinitionSet() {
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false,
new DynamicRaceDefinitionSet() {
@Override
public void addRaceDefinition(RaceDefinition race) {
}
@@ -95,11 +95,11 @@ public class ReceiveMarkPassingDataTest extends AbstractTracTracLiveTest {
for (Receiver r : DomainFactory.INSTANCE.getUpdateReceivers(
new DynamicTrackedRegattaImpl(DomainFactory.INSTANCE.getOrCreateDefaultRegatta(getTracTracEvent(), /* trackedRegattaRegistry */ null)),
getTracTracEvent(), EmptyWindStore.INSTANCE, /* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l,
new DynamicRaceDefinitionSet() {
/* simulateWithStartTimeNow */ false, new DynamicRaceDefinitionSet() {
@Override
public void addRaceDefinition(RaceDefinition race) {}
}, /* trackedRegattaRegistry */ null,
ReceiverType.RACECOURSE, ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS)) {
},
/* trackedRegattaRegistry */ null, ReceiverType.RACECOURSE, ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS)) {
receivers.add(r);
}
addListenersForStoredDataAndStartController(receivers);
@@ -78,7 +78,8 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest {
}
});
for (Receiver receiver : domainFactory.getUpdateReceivers(trackedRegatta, getTracTracEvent(), /* start of tracking */ null,
/* end of tracking */ null, /* delayToLiveInMillis */ 0l, EmptyWindStore.INSTANCE, new DynamicRaceDefinitionSet() {
/* end of tracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */false,
EmptyWindStore.INSTANCE, new DynamicRaceDefinitionSet() {
@Override
public void addRaceDefinition(RaceDefinition race) {
}
@@ -88,7 +89,8 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest {
}
}
addListenersForStoredDataAndStartController(domainFactory.getUpdateReceivers(trackedRegatta, getTracTracEvent(),
/* start of tracking */ null, /* end of tracking */ null, /* delayToLiveInMillis */ 0l, EmptyWindStore.INSTANCE, new DynamicRaceDefinitionSet() {
/* start of tracking */null, /* end of tracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */
false, EmptyWindStore.INSTANCE, new DynamicRaceDefinitionSet() {
@Override
public void addRaceDefinition(RaceDefinition race) {
}
@@ -42,12 +42,22 @@ public class UnicodeCharactersInCompetitorNamesTest {
TracTracRaceTracker fourtyninerYellow_2 = domainFactory
.createRaceTracker(
new URL(
"http://" + TracTracConnectionConstants.HOST_NAME + "/events/event_20110609_KielerWoch/clientparams.php?event=event_20110609_KielerWoch&race=5b08a9ee-9933-11e0-85be-406186cbf87c"),
tractracTunnel ? new URI("tcp://"+tractracTunnelHost+":"+TracTracConnectionConstants.PORT_TUNNEL_LIVE) : new URI("tcp://" + TracTracConnectionConstants.HOST_NAME + ":" + TracTracConnectionConstants.PORT_LIVE),
tractracTunnel ? new URI("tcp://"+tractracTunnelHost+":"+TracTracConnectionConstants.PORT_TUNNEL_STORED) : new URI("tcp://" + TracTracConnectionConstants.HOST_NAME + ":" + TracTracConnectionConstants.PORT_STORED),
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
Iterable<Competitor> competitors = fourtyninerYellow_2.getRacesHandle().getRaces().iterator().next().getCompetitors();
"http://"
+ TracTracConnectionConstants.HOST_NAME
+ "/events/event_20110609_KielerWoch/clientparams.php?event=event_20110609_KielerWoch&race=5b08a9ee-9933-11e0-85be-406186cbf87c"),
tractracTunnel ? new URI("tcp://" + tractracTunnelHost + ":"
+ TracTracConnectionConstants.PORT_TUNNEL_LIVE) : new URI("tcp://"
+ TracTracConnectionConstants.HOST_NAME + ":" + TracTracConnectionConstants.PORT_LIVE),
tractracTunnel ? new URI("tcp://" + tractracTunnelHost + ":"
+ TracTracConnectionConstants.PORT_TUNNEL_STORED)
: new URI("tcp://" + TracTracConnectionConstants.HOST_NAME + ":"
+ TracTracConnectionConstants.PORT_STORED),
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l,
/* simulateWithStartTimeNow */ false, EmptyWindStore.INSTANCE,
new DummyTrackedRegattaRegistry());
Iterable<Competitor> competitors = fourtyninerYellow_2.getRacesHandle().getRaces().iterator().next()
.getCompetitors();
for (Competitor competitor : competitors) {
System.out.println(competitor.getName());
}
@@ -23,14 +23,15 @@ import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceTracker;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
@@ -107,7 +108,6 @@ public interface DomainFactory {
* respond with the {@link RaceDefinition} when its {@link DomainFactory#getRaces(Event)} is called with the
* TracTrac {@link Event} as argument that is used for its tracking.
* <p>
*
* @param startOfTracking
* if <code>null</code>, all stored data from the "beginning of time" will be loaded that the event has
* to provide, particularly for the mark positions which are stored per event, not per race; otherwise,
@@ -122,16 +122,18 @@ public interface DomainFactory {
* available but loses track of the wind, e.g., during server restarts.
*/
TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, TimePoint startOfTracking,
TimePoint endOfTracking, long delayToLiveInMillis, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry)
throws MalformedURLException, FileNotFoundException, URISyntaxException;
TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore,
TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException,
URISyntaxException;
/**
* Same as {@link #createRaceTracker(URL, URI, URI, TimePoint, TimePoint, WindStore, TrackedRegattaRegistry)}, only that
* a predefined {@link Regatta} is used to hold the resulting races.
*/
RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI, TimePoint startOfTracking,
TimePoint endOfTracking, long delayToLiveInMillis, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry)
throws MalformedURLException, FileNotFoundException, URISyntaxException;
TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore,
TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException,
URISyntaxException;
BoatClass getOrCreateBoatClass(CompetitorClass competitorClass);
@@ -154,13 +156,14 @@ public interface DomainFactory {
* if <code>null</code>, all stored data until the "end of time" will be loaded that the event has to
* provide, particularly for the mark positions which are stored per event, not per race; otherwise,
* particularly the mark position loading will be constrained to this end time.
* @param simulateWithStartTimeNow TODO
* @param trackedRegattaRegistry 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, Event tractracEvent, TimePoint startOfTracking,
TimePoint endOfTracking, long delayToLiveInMillis, WindStore windStore, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry);
TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry);
/**
* Creates a {@link RaceDefinition} from a TracTrac {@link Race} and a domain {@link Course} definition. The
@@ -179,7 +182,7 @@ public interface DomainFactory {
* if not <code>null</code>, after creating the {@link TrackedRace}, the {@link RaceDefinition} is
* {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition) added} to that object.
*/
void getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta, Race race,
DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta, Race race,
Course course, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate);
@@ -195,7 +198,7 @@ public interface DomainFactory {
MarkPassing createMarkPassing(TimePoint timePoint, Waypoint passed, com.sap.sailing.domain.base.Competitor competitor);
Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, Event tractracEvent, WindStore windStore,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, ReceiverType... types);
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, ReceiverType... types);
JSONService parseJSONURL(URL jsonURL) throws IOException, ParseException, org.json.simple.parser.ParseException, URISyntaxException;
@@ -230,7 +233,7 @@ public interface DomainFactory {
Pair<List<com.sap.sailing.domain.base.Competitor>, BoatClass> getCompetitorsAndDominantBoatClass(Race race);
RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI, URI storedURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, WindStore windStore);
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore);
/**
* Removes all knowledge about <code>tractracRace</code> which includes removing it from the race cache, from the
* {@link com.sap.sailing.domain.base.Regatta} and, if a {@link TrackedRace} for the corresponding
@@ -31,6 +31,7 @@ public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Re
private final DomainFactory domainFactory;
private final com.tractrac.clientmodule.Event tractracEvent;
private final DynamicTrackedRegatta trackedRegatta;
private final Simulator simulator;
private Thread thread;
/**
@@ -40,11 +41,12 @@ public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Re
private boolean receivedEventDuringTimeout;
public AbstractReceiverWithQueue(DomainFactory domainFactory, Event tractracEvent,
DynamicTrackedRegatta trackedRegatta) {
DynamicTrackedRegatta trackedRegatta, Simulator simulator) {
super();
this.tractracEvent = tractracEvent;
this.trackedRegatta = trackedRegatta;
this.domainFactory = domainFactory;
this.simulator = simulator;
this.queue = new LinkedBlockingQueue<Triple<A, B, C>>();
}
@@ -76,6 +78,10 @@ public abstract class AbstractReceiverWithQueue<A, B, C> implements Runnable, Re
queue.add(new Triple<A, B, C>(null, null, null));
}
protected Simulator getSimulator() {
return simulator;
}
@Override
public void stopAfterNotReceivingEventsForSomeTime(final long timeoutInMilliseconds) {
receivedEventDuringTimeout = false;
@@ -42,12 +42,12 @@ import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceTracker;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.WindStore;
@@ -286,7 +286,15 @@ public class DomainFactoryImpl implements DomainFactory {
@Override
public Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta,
com.tractrac.clientmodule.Event tractracEvent, WindStore windStore, TimePoint startOfTracking,
TimePoint endOfTracking, long delayToLiveInMillis, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, ReceiverType... types) {
TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry,
ReceiverType... types) {
Simulator simulator;
if (simulateWithStartTimeNow) {
simulator = new Simulator();
} else {
simulator = null;
}
Collection<Receiver> result = new ArrayList<Receiver>();
for (ReceiverType type : types) {
switch (type) {
@@ -294,23 +302,23 @@ public class DomainFactoryImpl implements DomainFactory {
result.add(new RaceCourseReceiver(
this, trackedRegatta, tractracEvent, windStore,
raceDefinitionSetToUpdate, delayToLiveInMillis,
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND));
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, simulator));
break;
case MARKPOSITIONS:
result.add(new MarkPositionReceiver(
trackedRegatta, tractracEvent, startOfTracking, endOfTracking, this));
trackedRegatta, tractracEvent, startOfTracking, endOfTracking, simulator, this));
break;
case RAWPOSITIONS:
result.add(new RawPositionReceiver(
trackedRegatta, tractracEvent, this));
trackedRegatta, tractracEvent, this, simulator));
break;
case MARKPASSINGS:
result.add(new MarkPassingReceiver(
trackedRegatta, tractracEvent, this));
trackedRegatta, tractracEvent, simulator, this));
break;
case RACESTARTFINISH:
result.add(new RaceStartedAndFinishedReceiver(
trackedRegatta, tractracEvent, this));
trackedRegatta, tractracEvent, simulator, this));
break;
}
}
@@ -320,11 +328,12 @@ public class DomainFactoryImpl implements DomainFactory {
@Override
public Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta,
com.tractrac.clientmodule.Event tractracEvent, TimePoint startOfTracking, TimePoint endOfTracking,
long delayToLiveInMillis, WindStore windStore, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
TrackedRegattaRegistry trackedRegattaRegistry) {
return getUpdateReceivers(trackedRegatta, tractracEvent, windStore, startOfTracking, endOfTracking, delayToLiveInMillis,
raceDefinitionSetToUpdate, trackedRegattaRegistry, ReceiverType.RACECOURSE,
ReceiverType.MARKPASSINGS, ReceiverType.MARKPOSITIONS, ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS);
long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry) {
return getUpdateReceivers(trackedRegatta, tractracEvent, windStore, startOfTracking, endOfTracking,
delayToLiveInMillis, simulateWithStartTimeNow, raceDefinitionSetToUpdate, trackedRegattaRegistry,
ReceiverType.RACECOURSE, ReceiverType.MARKPASSINGS, ReceiverType.MARKPOSITIONS,
ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS);
}
@Override
@@ -379,7 +388,7 @@ public class DomainFactoryImpl implements DomainFactory {
}
@Override
public void getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta,
public DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta,
Race race, Course course, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
synchronized (raceCache) {
@@ -392,19 +401,19 @@ public class DomainFactoryImpl implements DomainFactory {
// add to existing regatta only if boat class matches
if (raceDefinition.getBoatClass() == trackedRegatta.getRegatta().getBoatClass()) {
trackedRegatta.getRegatta().addRace(raceDefinition);
createTrackedRace(trackedRegatta, raceDefinition, windStore,
DynamicTrackedRace trackedRace = createTrackedRace(trackedRegatta, raceDefinition, windStore,
delayToLiveInMillis, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate);
logger.info("Added race "+raceDefinition+" to regatta "+trackedRegatta.getRegatta());
synchronized (raceCache) {
raceCache.put(race, raceDefinition);
raceCache.notifyAll();
}
return trackedRace;
} else {
logger.warning("Not adding race "+raceDefinition+" to regatta "+trackedRegatta.getRegatta()+
" because boat class "+raceDefinition.getBoatClass()+" doesn't match regatta's boat class "+
trackedRegatta.getRegatta().getBoatClass());
return null;
}
} else {
throw new RuntimeException("Race "+race.getName()+" already exists");
@@ -412,7 +421,7 @@ public class DomainFactoryImpl implements DomainFactory {
}
}
private TrackedRace createTrackedRace(TrackedRegatta trackedRegatta, RaceDefinition race, WindStore windStore,
private DynamicTrackedRace createTrackedRace(TrackedRegatta trackedRegatta, RaceDefinition race, WindStore windStore,
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
return trackedRegatta.createTrackedRace(race,
windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
@@ -481,18 +490,20 @@ public class DomainFactoryImpl implements DomainFactory {
@Override
public TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, TimePoint startOfTracking,
TimePoint endOfTracking, long delayToLiveInMillis, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry)
throws MalformedURLException, FileNotFoundException, URISyntaxException {
TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore,
TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException,
URISyntaxException {
return new TracTracRaceTrackerImpl(this, paramURL, liveURI, storedURI, startOfTracking, endOfTracking, delayToLiveInMillis,
windStore, trackedRegattaRegistry);
simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
}
@Override
public RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, WindStore windStore,
TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException, URISyntaxException {
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry)
throws MalformedURLException, FileNotFoundException, URISyntaxException {
return new TracTracRaceTrackerImpl(regatta, this, paramURL, liveURI, storedURI, startOfTracking, endOfTracking, delayToLiveInMillis,
windStore, trackedRegattaRegistry);
simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
}
@Override
@@ -507,8 +518,10 @@ public class DomainFactoryImpl implements DomainFactory {
@Override
public RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI,
URI storedURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, WindStore windStore) {
return new RaceTrackingConnectivityParametersImpl(paramURL, liveURI, storedURI, startOfTracking, endOfTracking, delayToLiveInMillis, windStore, this);
URI storedURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, WindStore windStore) {
return new RaceTrackingConnectivityParametersImpl(paramURL, liveURI, storedURI, startOfTracking, endOfTracking,
delayToLiveInMillis, simulateWithStartTimeNow, windStore, this);
}
}
@@ -30,8 +30,8 @@ public class MarkPassingReceiver extends AbstractReceiverWithQueue<RaceCompetito
private static final Logger logger = Logger.getLogger(MarkPassingReceiver.class.getName());
public MarkPassingReceiver(DynamicTrackedRegatta trackedRegatta, com.tractrac.clientmodule.Event tractracEvent,
DomainFactory domainFactory) {
super(domainFactory, tractracEvent, trackedRegatta);
Simulator simulator, DomainFactory domainFactory) {
super(domainFactory, tractracEvent, trackedRegatta, simulator);
}
/**
@@ -90,8 +90,12 @@ public class MarkPassingReceiver extends AbstractReceiverWithQueue<RaceCompetito
markPassings.add(passing);
}
}
trackedRace.updateMarkPassings(getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor()),
markPassings);
if (getSimulator() != null) {
getSimulator().delayMarkPassings(getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor()), markPassings);
} else {
trackedRace.updateMarkPassings(getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor()),
markPassings);
}
} else {
logger.warning("Couldn't find tracked race for race " + event.getA().getRace().getName()
+ ". Dropping mark passing event " + event);
@@ -7,15 +7,16 @@ import java.util.logging.Logger;
import com.maptrack.client.io.TypeController;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.tractrac.clientmodule.ControlPoint;
import com.tractrac.clientmodule.Race;
@@ -67,8 +68,8 @@ public class MarkPositionReceiver extends AbstractReceiverWithQueue<ControlPoint
* particularly the mark position loading will be constrained to this end time.
*/
public MarkPositionReceiver(final DynamicTrackedRegatta trackedRegatta, com.tractrac.clientmodule.Event tractracEvent,
TimePoint startOfTracking, TimePoint endOfTracking, final DomainFactory domainFactory) {
super(domainFactory, tractracEvent, trackedRegatta);
TimePoint startOfTracking, TimePoint endOfTracking, Simulator simulator, final DomainFactory domainFactory) {
super(domainFactory, tractracEvent, trackedRegatta, simulator);
this.startOfTracking = startOfTracking;
this.endOfTracking = endOfTracking;
// assumption: there is currently only one race per TracTrac Event object
@@ -111,7 +112,12 @@ public class MarkPositionReceiver extends AbstractReceiverWithQueue<ControlPoint
for (Race tractracRace : getTracTracEvent().getRaceList()) {
DynamicTrackedRace trackedRace = getTrackedRace(tractracRace);
if (trackedRace != null) {
trackedRace.recordFix(buoy, getDomainFactory().createGPSFixMoving(event.getB()));
GPSFixMoving markPosition = getDomainFactory().createGPSFixMoving(event.getB());
if (getSimulator() != null) {
getSimulator().scheduleMarkPosition(buoy, markPosition);
} else {
trackedRace.recordFix(buoy, markPosition);
}
} else {
logger.warning("Couldn't find tracked race for race " + tractracRace.getName()
+ ". Dropping mark position event " + event);
@@ -8,10 +8,11 @@ import java.util.logging.Logger;
import com.maptrack.client.io.TypeController;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
@@ -43,11 +44,15 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<Route, RouteDa
public RaceCourseReceiver(DomainFactory domainFactory, DynamicTrackedRegatta trackedRegatta,
com.tractrac.clientmodule.Event tractracEvent, WindStore windStore,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind) {
super(domainFactory, tractracEvent, trackedRegatta);
long millisecondsOverWhichToAverageWind, Simulator simulator) {
super(domainFactory, tractracEvent, trackedRegatta, simulator);
this.millisecondsOverWhichToAverageWind = millisecondsOverWhichToAverageWind;
this.delayToLiveInMillis = delayToLiveInMillis;
this.windStore = windStore;
if (simulator == null) {
this.windStore = windStore;
} else {
this.windStore = simulator.simulatingWindStore(windStore);
}
this.raceDefinitionSetToUpdate = raceDefinitionSetToUpdate;
}
@@ -93,8 +98,12 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<Route, RouteDa
} else {
logger.log(Level.INFO, "Received course for non-existing race "+event.getC().getName()+". Creating RaceDefinition.");
// create race definition and add to event
getDomainFactory().getOrCreateRaceDefinitionAndTrackedRace(getTrackedRegatta(), event.getC(), course,
windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate);
DynamicTrackedRace trackedRace = getDomainFactory().getOrCreateRaceDefinitionAndTrackedRace(
getTrackedRegatta(), event.getC(), course, windStore, delayToLiveInMillis,
millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate);
if (getSimulator() != null) {
getSimulator().setTrackedRace(trackedRace);
}
}
}
@@ -7,12 +7,13 @@ import java.util.logging.Logger;
import com.maptrack.client.io.TypeController;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.Course;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.tractrac.clientmodule.Race;
import com.tractrac.clientmodule.data.ICallbackData;
@@ -31,8 +32,9 @@ import com.tractrac.clientmodule.data.StartStopTimesData;
public class RaceStartedAndFinishedReceiver extends AbstractReceiverWithQueue<Race, StartStopTimesData, Boolean> {
private static final Logger logger = Logger.getLogger(RaceStartedAndFinishedReceiver.class.getName());
public RaceStartedAndFinishedReceiver(DynamicTrackedRegatta trackedRegatta, com.tractrac.clientmodule.Event tractracEvent, DomainFactory domainFactory) {
super(domainFactory, tractracEvent, trackedRegatta);
public RaceStartedAndFinishedReceiver(DynamicTrackedRegatta trackedRegatta,
com.tractrac.clientmodule.Event tractracEvent, Simulator simulator, DomainFactory domainFactory) {
super(domainFactory, tractracEvent, trackedRegatta, simulator);
}
/**
@@ -62,13 +64,19 @@ public class RaceStartedAndFinishedReceiver extends AbstractReceiverWithQueue<Ra
DynamicTrackedRace trackedRace = getTrackedRace(event.getA());
if (trackedRace != null) {
StartStopTimesData startStopTimesData = event.getB();
if(startStopTimesData != null) {
if(startStopTimesData.getStartTime() > 0) {
MillisecondsTimePoint startOfTracking = new MillisecondsTimePoint(startStopTimesData.getStartTime());
if (startStopTimesData != null) {
final long startTime = startStopTimesData.getStartTime();
TimePoint startOfTracking = getSimulator() == null ?
new MillisecondsTimePoint(startTime) :
getSimulator().advance(new MillisecondsTimePoint(startTime));
if (startTime > 0) {
trackedRace.setStartOfTrackingReceived(startOfTracking);
}
if(startStopTimesData.getStopTime() > 0) {
MillisecondsTimePoint endOfTracking = new MillisecondsTimePoint(startStopTimesData.getStopTime());
final long stopTime = startStopTimesData.getStopTime();
TimePoint endOfTracking = getSimulator() == null ?
new MillisecondsTimePoint(stopTime) :
getSimulator().advance(new MillisecondsTimePoint(stopTime));
if (stopTime > 0) {
trackedRace.setEndOfTrackingReceived(endOfTracking);
}
}
@@ -24,9 +24,11 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
private final WindStore windStore;
private final DomainFactory domainFactory;
private final long delayToLiveInMillis;
private final boolean simulateWithStartTimeNow;
public RaceTrackingConnectivityParametersImpl(URL paramURL, URI liveURI, URI storedURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, WindStore windStore, DomainFactory domainFactory) {
public RaceTrackingConnectivityParametersImpl(URL paramURL, URI liveURI, URI storedURI, TimePoint startOfTracking,
TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore,
DomainFactory domainFactory) {
super();
this.paramURL = paramURL;
this.liveURI = liveURI;
@@ -36,13 +38,14 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
this.delayToLiveInMillis = delayToLiveInMillis;
this.windStore = windStore;
this.domainFactory = domainFactory;
this.simulateWithStartTimeNow = simulateWithStartTimeNow;
}
@Override
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException,
FileNotFoundException, URISyntaxException {
RaceTracker tracker = domainFactory.createRaceTracker(paramURL, liveURI, storedURI, startOfTracking,
endOfTracking, delayToLiveInMillis, windStore, trackedRegattaRegistry);
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
return tracker;
}
@@ -50,7 +53,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry)
throws Exception {
RaceTracker tracker = domainFactory.createRaceTracker(regatta, paramURL, liveURI, storedURI, startOfTracking,
endOfTracking, delayToLiveInMillis, windStore, trackedRegattaRegistry);
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
return tracker;
}
@@ -10,6 +10,7 @@ import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.tractrac.clientmodule.Race;
import com.tractrac.clientmodule.RaceCompetitor;
@@ -21,8 +22,9 @@ public class RawPositionReceiver extends AbstractReceiverWithQueue<RaceCompetito
private int received;
public RawPositionReceiver(DynamicTrackedRegatta trackedRegatta, com.tractrac.clientmodule.Event tractracEvent, DomainFactory domainFactory) {
super(domainFactory, tractracEvent, trackedRegatta);
public RawPositionReceiver(DynamicTrackedRegatta trackedRegatta, com.tractrac.clientmodule.Event tractracEvent,
DomainFactory domainFactory, Simulator simulator) {
super(domainFactory, tractracEvent, trackedRegatta, simulator);
}
/**
@@ -58,6 +60,10 @@ public class RawPositionReceiver extends AbstractReceiverWithQueue<RaceCompetito
DynamicTrackedRace trackedRace = getTrackedRace(race);
if (trackedRace != null) {
GPSFixMoving fix = getDomainFactory().createGPSFixMoving(event.getB());
if (getSimulator() != null) {
fix = new GPSFixMovingImpl(fix.getPosition(), getSimulator().delay(
fix.getTimePoint()), fix.getSpeed());
}
Competitor competitor = getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor());
trackedRace.recordFix(competitor, fix);
} else {
@@ -0,0 +1,221 @@
package com.sap.sailing.domain.tractracadapter.impl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
import com.sap.sailing.domain.tracking.impl.WindImpl;
public class Simulator {
private static final Logger logger = Logger.getLogger(Simulator.class.getName());
private DynamicTrackedRace trackedRace;
private WindStore windStore;
private long advanceInMillis = -1;
private Timer timer = new Timer("Timer for TracTrac Simulator");
/**
* Creates a wind store which replays the wind store events against a tracked race, correcting the wind fixes with
* the simulation delay. The wind store returned is an {@link EmptyWindStore}.
*/
public WindStore simulatingWindStore(WindStore windStore) {
this.windStore = windStore;
return EmptyWindStore.INSTANCE;
}
public synchronized void setTrackedRace(DynamicTrackedRace trackedRace) {
this.trackedRace = trackedRace;
startWindPlayer();
}
/**
* This is what everybody is waiting for :-). Notifies all waiters.
*/
public synchronized void setAdvanceInMillis(long advanceInMillis) {
this.advanceInMillis = advanceInMillis;
notifyAll();
}
/**
* Launches a thread which re-plays all wind fixes from {@link #windStore}'s
* {@link WindStore#loadWindTracks(com.sap.sailing.domain.tracking.TrackedRegatta, com.sap.sailing.domain.tracking.TrackedRace, long)
* loaded tracks} on {@link #trackedRace}.
*/
private void startWindPlayer() {
assert this.trackedRace != null;
assert this.windStore != null;
for (final Map.Entry<? extends WindSource, ? extends WindTrack> windSourceAndTrack : windStore.loadWindTracks(
trackedRace.getTrackedRegatta(), trackedRace,
/* millisecondsOverWhichToAverageWind doesn't matter because we only use raw fixes */ 10000).entrySet()) {
new Thread("Wind simulator for wind source "+windSourceAndTrack.getKey()+" for tracked race "+trackedRace.getRace().getName()) {
@Override
public void run() {
for (Wind wind : windSourceAndTrack.getValue().getRawFixes()) {
trackedRace.recordWind(delayWind(wind), windSourceAndTrack.getKey());
}
}
}.start();
}
}
private Wind delayWind(Wind wind) {
TimePoint delayedTimePoint = delay(wind.getTimePoint());
return new WindImpl(wind.getPosition(), delayedTimePoint, new KnotSpeedWithBearingImpl(wind.getKnots(), wind.getBearing()));
}
/**
* Waits until {@link #advanceInMillis} is set to something not equal to -1 which is its initial value. Unblocked by
* {@link #setAdvanceInMillis(long)}.
*/
private synchronized long getAdvanceInMillis() {
while (advanceInMillis == -1) {
try {
wait();
} catch (InterruptedException e) {
logger.throwing(Simulator.class.getName(), "getAdvanceInMillis", e);
// ignore; try again
}
}
return advanceInMillis;
}
/**
* Transforms <code>timed</code>'s time point according to this simulator's delay and waits roughly until this time
* has passed. Then, returns the adjusted time point which therefore should roughly equal "now."
*/
public TimePoint delay(TimePoint timePoint) {
TimePoint transformedTimed = advance(timePoint);
long waitTimeInMillis = getWaitTimeInMillisUntil(transformedTimed);
do {
if (waitTimeInMillis > 0) {
try {
Thread.sleep(waitTimeInMillis);
waitTimeInMillis = 0;
} catch (InterruptedException e) {
// try again:
waitTimeInMillis = transformedTimed.asMillis() - System.currentTimeMillis();
}
}
} while (waitTimeInMillis > 0);
return transformedTimed;
}
private long getWaitTimeInMillisUntil(TimePoint transformedTimepoint) {
long now = System.currentTimeMillis();
long waitTimeInMillis = transformedTimepoint.asMillis() - now;
return waitTimeInMillis;
}
/**
* Like {@link #delay}, only that it doesn't wait until <code>timePoint</code> is reached in wall time.
*/
public TimePoint advance(TimePoint timePoint) {
return new MillisecondsTimePoint(timePoint.asMillis()+getAdvanceInMillis());
}
/**
* If {@link #advanceInMillis} is already set to a non-negative value, it is left alone, and {@link #delay(TimePoint)} is called.
* Otherwise, <code>time</code> is taken to be the original start time of the race which is then used to compute
* {@link #advanceInMillis} such that <code>time.asMillis() + advanceInMillis == System.currentTimeMillis()</code>.
*/
public TimePoint advanceMarkPassingTimePoint(TimePoint time) {
if (isAdvanceInMilliseSet()) {
return advance(time);
} else {
setAdvanceInMillis(System.currentTimeMillis() - time.asMillis());
return advance(time);
}
}
private boolean isAdvanceInMilliseSet() {
return advanceInMillis != -1;
}
/**
* Delivers those mark passings for which we don't have to wait as a single list to the {@link #trackedRace} now.
* The remaining mark passings are delayed as long as it takes for the first mark passing with a positive wait time
* to match "now." The whole list is then re-submitted to this same method.
*/
public void delayMarkPassings(final Competitor competitor, List<MarkPassing> markPassings) {
List<MarkPassing> deliverTransformedNow = new ArrayList<MarkPassing>();
final List<MarkPassing> deliverLater = new ArrayList<MarkPassing>();
Iterator<MarkPassing> i = markPassings.iterator();
if (i.hasNext()) {
MarkPassing markPassing = i.next();
deliverLater.add(markPassing);
TimePoint transformedTimepoint = advanceMarkPassingTimePoint(markPassing.getTimePoint());
while (getWaitTimeInMillisUntil(transformedTimepoint) <= 0 && markPassing != null) {
MarkPassing transformedMarkPassing = new MarkPassingImpl(transformedTimepoint,
markPassing.getWaypoint(), markPassing.getCompetitor());
deliverTransformedNow.add(transformedMarkPassing);
if (i.hasNext()) {
markPassing = i.next();
transformedTimepoint = advanceMarkPassingTimePoint(markPassing.getTimePoint());
deliverLater.add(markPassing);
} else {
markPassing = null;
}
}
trackedRace.updateMarkPassings(competitor, deliverTransformedNow);
if (markPassing != null) {
// not consumed and delivered all mark passings now
while (i.hasNext()) {
deliverLater.add(i.next());
}
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
delayMarkPassings(competitor, deliverLater);
} catch (Throwable t) {
logger.throwing(Simulator.class.getName(), "scheduleMarkPosition", t);
}
}
}, transformedTimepoint.asDate());
}
} else {
// deliver an empty list now
trackedRace.updateMarkPassings(competitor, markPassings);
}
}
public void scheduleMarkPosition(final Buoy buoy, GPSFixMoving markFix) {
final TimePoint transformedTimepoint = advance(markFix.getTimePoint());
final GPSFixMoving transformedMarkFix = new GPSFixMovingImpl(markFix.getPosition(), transformedTimepoint, markFix.getSpeed());
long waitTime = getWaitTimeInMillisUntil(transformedMarkFix.getTimePoint());
if (waitTime <= 0) {
trackedRace.recordFix(buoy, transformedMarkFix);
} else {
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
trackedRace.recordFix(buoy, transformedMarkFix);
} catch (Throwable t) {
logger.throwing(Simulator.class.getName(), "scheduleMarkPosition", t);
}
}
}, transformedTimepoint.asDate());
}
}
}
@@ -100,7 +100,6 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
* respond with the {@link RaceDefinition} when its {@link DomainFactory#getRaces(Event)} is called with the
* TracTrac {@link Event} as argument that is used for its tracking.
* <p>
*
* @param startOfTracking
* if <code>null</code>, all stored data from the "beginning of time" will be loaded that the event has
* to provide, particularly for the mark positions which are stored per event, not per race; otherwise,
@@ -109,6 +108,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
* if <code>null</code>, all stored data until the "end of time" will be loaded that the event has to
* provide, particularly for the mark positions which are stored per event, not per race; otherwise,
* particularly the mark position loading will be constrained to this end time.
* @param simulateWithStartTimeNow TODO
* @param windStore
* 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
@@ -117,19 +117,19 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
* used to create the {@link TrackedRegatta} for the domain event
*/
protected TracTracRaceTrackerImpl(DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, WindStore windStore,
TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException,
FileNotFoundException {
this(KeyValue.setup(paramURL), domainFactory, paramURL, liveURI, storedURI, startOfTracking, endOfTracking, delayToLiveInMillis, windStore,
trackedRegattaRegistry);
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry)
throws URISyntaxException, MalformedURLException, FileNotFoundException {
this(KeyValue.setup(paramURL), domainFactory, paramURL, liveURI, storedURI, startOfTracking, endOfTracking,
delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
}
private TracTracRaceTrackerImpl(Event tractracEvent, DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, WindStore windStore,
TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow,
WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException,
FileNotFoundException {
this(tractracEvent, null, domainFactory, paramURL, liveURI, storedURI,
startOfTracking, endOfTracking, delayToLiveInMillis, windStore, trackedRegattaRegistry);
startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
}
/**
@@ -139,21 +139,27 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
* always be what you want.
*/
protected TracTracRaceTrackerImpl(Regatta regatta, DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, WindStore windStore,
TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow,
WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException,
FileNotFoundException {
this(KeyValue.setup(paramURL), regatta, domainFactory, paramURL, liveURI, storedURI, startOfTracking,
endOfTracking, delayToLiveInMillis, windStore, trackedRegattaRegistry);
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
}
/**
*
* @param regatta if <code>null</code>, then <code>domainFactory.getOrCreateRegatta(tractracEvent)</code> will be used to
* obtain a default regatta
* @param regatta
* if <code>null</code>, then <code>domainFactory.getOrCreateRegatta(tractracEvent)</code> will be used
* to obtain a default regatta
* @param simulateWithStartTimeNow
* if <code>true</code>, the connector will adjust the time stamps of all events received such that the
* 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.
*/
private TracTracRaceTrackerImpl(Event tractracEvent, final Regatta regatta, DomainFactory domainFactory,
URL paramURL, URI liveURI, URI storedURI, TimePoint startOfTracking, TimePoint endOfTracking,
long delayToLiveInMillis, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry)
long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry)
throws URISyntaxException, MalformedURLException, FileNotFoundException {
super();
this.tractracEvent = tractracEvent;
@@ -192,7 +198,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
receivers = new HashSet<Receiver>();
Set<TypeController> typeControllers = new HashSet<TypeController>();
for (Receiver receiver : domainFactory.getUpdateReceivers(getTrackedRegatta(), tractracEvent, startOfTracking,
endOfTracking, delayToLiveInMillis, windStore, this, trackedRegattaRegistry)) {
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, this, trackedRegattaRegistry)) {
receivers.add(receiver);
for (TypeController typeController : receiver.getTypeControllersAndStart()) {
typeControllers.add(typeController);
@@ -33,11 +33,11 @@ import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
*/
public interface RaceTracker {
/**
* By default, wait five minutes for race data; sometimes, a tracking provider's server may be under heavy load and
* By default, wait half a minute for race data; sometimes, a tracking provider's server may be under heavy load and
* may serve races one after another. If many races are requested concurrently, this can lead to a queue
* of several minutes length.
*/
static long TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS = 300000;
static long TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS = 30000;
/**
* Stops tracking the races.
@@ -39,7 +39,7 @@ public interface TrackedRegatta extends Serializable {
* if not <code>null</code>, after creating the {@link TrackedRace}, the <code>raceDefinition</code> is
* {@link DynamicRaceDefinitionSet#addRaceDefinition(RaceDefinition) added} to that object.
*/
TrackedRace createTrackedRace(RaceDefinition raceDefinition, WindStore windStore,
DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, WindStore windStore,
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate);
@@ -232,7 +232,7 @@ public class TrackBasedEstimationWindTrackImpl extends VirtualWindTrackImpl impl
if (!scheduledInvalidationInterval.isSet()) {
// according to the invariant this implies [1]==null
scheduledInvalidationInterval.set(startOfInvalidation, endOfInvalidation);
startSchedulerForInvalidation();
startSchedulerForCacheRefresh();
} else {
// this means that an invalidation is already scheduled; as long as we're synchronized on scheduledInvalidationInterval
// we can safely extend the interval; the invalidation won't start before we release the lock
@@ -274,7 +274,7 @@ public class TrackBasedEstimationWindTrackImpl extends VirtualWindTrackImpl impl
}
}
private void startSchedulerForInvalidation() {
private void startSchedulerForCacheRefresh() {
synchronized (scheduledInvalidationInterval) {
if (delayForCacheInvalidationInMilliseconds == 0) {
invalidateCache();
@@ -4,6 +4,7 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -39,13 +40,13 @@ import com.sap.sailing.domain.base.impl.MeterDistance;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NoWindError;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.WindSource;
@@ -66,10 +67,10 @@ import com.sap.sailing.domain.tracking.GPSFixTrack;
import com.sap.sailing.domain.tracking.GPSTrackListener;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
@@ -243,7 +244,9 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
}
markPassingsTimes = new ArrayList<Pair<Waypoint, Pair<TimePoint, TimePoint>>>();
windTracks = new HashMap<WindSource, WindTrack>();
windTracks.putAll(windStore.loadWindTracks(trackedRegatta, this, millisecondsOverWhichToAverageWind));
final Map<? extends WindSource, ? extends WindTrack> loadedWindTracks = windStore.loadWindTracks(
trackedRegatta, this, millisecondsOverWhichToAverageWind);
windTracks.putAll(loadedWindTracks);
// by default, a tracked race offers one course-based wind estimation, one track-based wind estimation track and
// one "WEB" track for manual or REST-based wind reception; other wind tracks may be added as fixes are received
// for them.
@@ -875,7 +878,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
.createWindAverager(timeWeigherThatPretendsToAlsoWeighPositions);
List<WindWithConfidence<Pair<Position, TimePoint>>> windFixesWithConfidences = new ArrayList<WindWithConfidence<Pair<Position, TimePoint>>>();
for (WindSource windSource : getWindSources()) {
// TODO consider parallelizing
// TODO consider parallelizing and consider caching
if (!Util.contains(windSourcesToExclude, windSource)) {
WindTrack track = getOrCreateWindTrack(windSource);
WindWithConfidence<Pair<Position, TimePoint>> windWithConfidence = track.getAveragedWindWithConfidence(p, at);
@@ -1659,8 +1662,12 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
@Override
public Iterable<WindSource> getWindSources() {
synchronized (windTracks) {
return new ArrayList<WindSource>(windTracks.keySet());
while (true) {
try {
return new ArrayList<WindSource>(windTracks.keySet());
} catch (ConcurrentModificationException cme) {
logger.info("Caught " + cme + "; trying again.");
}
}
}
@@ -13,14 +13,15 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.RaceListener;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.WindStore;
public class TrackedRegattaImpl implements TrackedRegatta {
@@ -160,9 +161,10 @@ public class TrackedRegattaImpl implements TrackedRegatta {
}
@Override
public TrackedRace createTrackedRace(RaceDefinition raceDefinition, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
long millisecondsOverWhichToAverageSpeed, DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
logger.log(Level.INFO, "Creating DynamicTrackedRaceImpl for RaceDefinition "+raceDefinition.getName());
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, WindStore windStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
logger.log(Level.INFO, "Creating DynamicTrackedRaceImpl for RaceDefinition " + raceDefinition.getName());
DynamicTrackedRaceImpl result = new DynamicTrackedRaceImpl(this, raceDefinition,
windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed);
if (raceDefinitionSetToUpdate != null) {
@@ -2,6 +2,8 @@ package com.sap.sailing.domain.tracking.impl;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import com.sap.sailing.domain.common.Distance;
@@ -21,10 +23,12 @@ import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
public class WindwardToGoComparator implements Comparator<TrackedLegOfCompetitor> {
private final TrackedLeg trackedLeg;
private final TimePoint timePoint;
private final Map<TrackedLegOfCompetitor, Distance> wwdtgCache;
public WindwardToGoComparator(TrackedLeg trackedLeg, TimePoint timePoint) {
this.trackedLeg = trackedLeg;
this.timePoint = timePoint;
wwdtgCache = new HashMap<TrackedLegOfCompetitor, Distance>();
}
@Override
@@ -45,8 +49,8 @@ public class WindwardToGoComparator implements Comparator<TrackedLegOfCompetitor
// both didn't finish the leg yet; check which one has started:
if (o1.hasStartedLeg(timePoint)) {
if (o2.hasStartedLeg(timePoint)) {
Distance o1d = o1.getWindwardDistanceToGo(timePoint);
Distance o2d = o2.getWindwardDistanceToGo(timePoint);
Distance o1d = getWindwardDistanceToGo(o1);
Distance o2d = getWindwardDistanceToGo(o2);
result = o1d==null?(o2d==null?0:1):o2d==null?1:o1d.compareTo(o2d); // smaller distance to go means smaller rank
} else {
result = -1;
@@ -63,4 +67,13 @@ public class WindwardToGoComparator implements Comparator<TrackedLegOfCompetitor
throw new NoWindError(e);
}
}
private Distance getWindwardDistanceToGo(TrackedLegOfCompetitor o1) throws NoWindException {
Distance result = wwdtgCache.get(o1);
if (result == null) {
result = o1.getWindwardDistanceToGo(timePoint);
wwdtgCache.put(o1, result);
}
return result;
}
}
@@ -85,7 +85,7 @@ public class GwtTestCaseColumnToggling extends GWTTestCase {
+ TracTracConnectionConstants.PORT_TUNNEL_LIVE : "tcp://" + TracTracConnectionConstants.HOST_NAME + ":"
+ TracTracConnectionConstants.PORT_LIVE, tractracTunnel ? "tcp://" + tractracTunnelHost + ":"
+ TracTracConnectionConstants.PORT_TUNNEL_STORED : "tcp://" + TracTracConnectionConstants.HOST_NAME
+ ":" + TracTracConnectionConstants.PORT_STORED, false, false, new AsyncCallback<Void>() {
+ ":" + TracTracConnectionConstants.PORT_STORED, false, false, /* simulateWithStartTimeNow */ false, new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
@@ -346,6 +346,11 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
declinationCheckbox.setValue(true);
trackPanel.add(declinationCheckbox);
final CheckBox simulateWithStartTimeNow = new CheckBox(stringMessages.simulateWithStartTimeNow());
simulateWithStartTimeNow.setWordWrap(false);
simulateWithStartTimeNow.setValue(false);
trackPanel.add(simulateWithStartTimeNow);
trackedRacesPanel.add(trackedRacesListComposite);
HorizontalPanel racesButtonPanel = new HorizontalPanel();
@@ -357,7 +362,7 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
btnTrack.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
trackSelectedRaces(trackWindCheckbox.getValue(), declinationCheckbox.getValue());
trackSelectedRaces(trackWindCheckbox.getValue(), declinationCheckbox.getValue(), simulateWithStartTimeNow.getValue());
}
});
@@ -490,18 +495,18 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
});
}
private void trackSelectedRaces(boolean trackWind, boolean correctWindByDeclination) {
private void trackSelectedRaces(boolean trackWind, boolean correctWindByDeclination, final boolean simulateWithStartTimeNow) {
String liveURI = liveURIBox.getValue();
String storedURI = storedURIBox.getValue();
RegattaDTO selectedRegatta = getSelectedRegatta();
RegattaIdentifier regattaIdentifier = null;
if(selectedRegatta != null) {
if (selectedRegatta != null) {
regattaIdentifier = new RegattaName(selectedRegatta.name);
}
for (final TracTracRaceRecordDTO rr : raceList.getList()) {
if (raceTable.getSelectionModel().isSelected(rr)) {
sailingService.trackWithTracTrac(regattaIdentifier, rr, liveURI, storedURI, trackWind,
correctWindByDeclination, new AsyncCallback<Void>() {
correctWindByDeclination, simulateWithStartTimeNow, new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Error trying to register race " + rr.name + " for tracking: "
@@ -57,7 +57,8 @@ public interface SailingService extends RemoteService {
Pair<String, List<TracTracRaceRecordDTO>> listTracTracRacesInEvent(String eventJsonURL) throws Exception;
void trackWithTracTrac(RegattaIdentifier regattaToAddTo, TracTracRaceRecordDTO rr, String liveURI, String storedURI, boolean trackWind, boolean correctWindByDeclination) throws Exception;
void trackWithTracTrac(RegattaIdentifier regattaToAddTo, TracTracRaceRecordDTO rr, String liveURI,
String storedURI, boolean trackWind, boolean correctWindByDeclination, boolean simulateWithStartTimeNow) throws Exception;
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, SwissTimingRaceRecordDTO rr, String hostname, int port,
boolean canSendRequests, boolean trackWind, boolean correctWindByDeclination) throws Exception;
@@ -64,13 +64,18 @@ public interface SailingServiceAsync {
* @param liveURI
* may be <code>null</code> or the empty string in which case the server will use the
* {@link TracTracRaceRecordDTO#liveURI} from the <code>rr</code> race record.
* @param simulateWithStartTimeNow
* if <code>true</code>, the connector will adjust the time stamps of all events received such that the
* 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 storedURImay
* be <code>null</code> or the empty string in which case the server will use the
* {@link TracTracRaceRecordDTO#storedURI} from the <code>rr</code> race record.
*/
void trackWithTracTrac(RegattaIdentifier regattaToAddTo,
TracTracRaceRecordDTO rr, String liveURI, String storedURI, boolean trackWind, boolean correctWindByDeclination,
AsyncCallback<Void> callback);
boolean simulateWithStartTimeNow, AsyncCallback<Void> callback);
void getPreviousTracTracConfigurations(AsyncCallback<List<TracTracConfigurationDTO>> callback);
@@ -334,4 +334,5 @@ public interface StringMessages extends Messages {
String successfullyUpdatedScores();
String errorUpdatingScoresForLeaderboard(String leaderboardName, String message);
String maneuverTypesToShowWhenCompetitorIsClicked();
String simulateWithStartTimeNow();
}
@@ -330,4 +330,5 @@ selectAll=Select all
apply=Apply
successfullyUpdatedScores=Successfully updated scores
errorUpdatingScoresForLeaderboard=Error updating scores for leaderboard {0}: {1}
maneuverTypesToShowWhenCompetitorIsClicked=Maneuver types to show when competitor is clicked
maneuverTypesToShowWhenCompetitorIsClicked=Maneuver types to show when competitor is clicked
simulateWithStartTimeNow=Simulate with "now" as start time
@@ -331,4 +331,5 @@ selectAll=Alle auswählen
apply=Übernehmen
successfullyUpdatedScores=Ergebnisse erfolgreich aktualisiert
errorUpdatingScoresForLeaderboard=Fehler beim Aktualisieren der Ergebnisse für {0}: {1}
maneuverTypesToShowWhenCompetitorIsClicked=Anzuzeigende Manövertypen für angeklickte Segler
maneuverTypesToShowWhenCompetitorIsClicked=Anzuzeigende Manövertypen für angeklickte Segler
simulateWithStartTimeNow=Simulieren mit "jetzt" als Startzeit
@@ -609,7 +609,7 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
@Override
public void trackWithTracTrac(RegattaIdentifier regattaToAddTo, TracTracRaceRecordDTO rr, String liveURI, String storedURI,
boolean trackWind, final boolean correctWindByDeclination) throws Exception {
boolean trackWind, final boolean correctWindByDeclination, final boolean simulateWithStartTimeNow) throws Exception {
if (liveURI == null || liveURI.trim().length() == 0) {
liveURI = rr.liveURI;
}
@@ -620,7 +620,7 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
new URI(liveURI), new URI(storedURI), new MillisecondsTimePoint(rr.trackingStartTime),
new MillisecondsTimePoint(rr.trackingEndTime),
MongoWindStoreFactory.INSTANCE.getMongoWindStore(mongoObjectFactory, domainObjectFactory),
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, simulateWithStartTimeNow);
if (trackWind) {
new Thread("Wind tracking starter for race "+rr.regattaName+"/"+rr.name) {
public void run() {
@@ -24,7 +24,7 @@ public class ResultListImpl extends AbstractNodeWrapper implements ResultList {
private final String sourceName;
private static final SimpleDateFormat df = new SimpleDateFormat("dd. MMM yyyy hh:mm", Locale.GERMAN);
private static final SimpleDateFormat df = new SimpleDateFormat("dd. MMM yyyy HH:mm", Locale.GERMAN);
public ResultListImpl(Node node, String sourceName) {
super(node);
@@ -73,7 +73,8 @@ public class TestStoringAndRetrievingWindTracksTest extends AbstractTracTracLive
Regatta domainEvent = domainFactory.getOrCreateDefaultRegatta(getTracTracEvent(), /* trackedRegattaRegistry */ null);
DynamicTrackedRegatta trackedRegatta = new RacingEventServiceImpl().getOrCreateTrackedRegatta(domainEvent);
Iterable<Receiver> typeControllers = domainFactory.getUpdateReceivers(trackedRegatta, getTracTracEvent(),
EmptyWindStore.INSTANCE, /* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, new DynamicRaceDefinitionSet() {
EmptyWindStore.INSTANCE, /* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */
0l, /* simulateWithStartTimeNow */false, new DynamicRaceDefinitionSet() {
@Override
public void addRaceDefinition(RaceDefinition race) {
}
@@ -73,7 +73,8 @@ public class TrackRaceReplicationTest extends AbstractServerReplicationTest {
}
});
trackingParams = com.sap.sailing.domain.tractracadapter.DomainFactory.INSTANCE.createTrackingConnectivityParameters(paramURL,
liveURI, storedURI, startOfTracking, endOfTracking, /* delayToLiveInMillis */ 0l, EmptyWindStore.INSTANCE);
liveURI, storedURI, startOfTracking, endOfTracking, /* delayToLiveInMillis */
0l, /* simulateWithStartTimeNow */false, EmptyWindStore.INSTANCE);
}
private void startTracking() throws Exception, InterruptedException {
@@ -147,7 +147,8 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
* to add the races to. Otherwise, a default regatta as described above will be created and used.
*/
RacesHandle addTracTracRace(RegattaIdentifier regattaToAddTo, URL paramURL, URI liveURI, URI storedURI,
TimePoint trackingStartTime, TimePoint trackingEndTime, WindStore windStore, long timeoutForReceivingRaceDefinitionInMilliseconds)
TimePoint trackingStartTime, TimePoint trackingEndTime, WindStore windStore,
long timeoutForReceivingRaceDefinitionInMilliseconds, boolean simulateWithStartTimeNow)
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
/**
@@ -577,10 +577,10 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
public synchronized RacesHandle addTracTracRace(URL paramURL, URI liveURI, URI storedURI, WindStore windStore,
long timeoutInMilliseconds) throws Exception {
return addRace(
/* regattaToAddTo */ null,
getDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI,
/* startOfTracking */ null,
/* endOfTracking */null, delayToLiveInMillis, windStore), windStore, timeoutInMilliseconds);
/* regattaToAddTo */null, getDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI,
/* startOfTracking */null,
/* endOfTracking */null, delayToLiveInMillis, /* simulateWithStartTimeNow */false, windStore), windStore,
timeoutInMilliseconds);
}
@Override
@@ -726,9 +726,9 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
@Override
public synchronized RacesHandle addTracTracRace(RegattaIdentifier regattaToAddTo, URL paramURL, URI liveURI,
URI storedURI, TimePoint startOfTracking, TimePoint endOfTracking,
WindStore windStore, long timeoutInMilliseconds) throws Exception {
WindStore windStore, long timeoutInMilliseconds, boolean simulateWithStartTimeNow) throws Exception {
return addRace(regattaToAddTo, getDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI, startOfTracking,
endOfTracking, delayToLiveInMillis, windStore), windStore, timeoutInMilliseconds);
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore), windStore, timeoutInMilliseconds);
}
private void ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking(DynamicTrackedRegatta trackedRegatta) {