work towards a TracTrac simulator

This commit is contained in:
Axel Uhl committed 2012-06-18 20:29:51 +02:00
1 parent ac854bb314
commit 1e01668a69
23 files changed
+209 -73

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, simulateWithStartTimeNow, simulateWithStartTimeNow, 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, simulateWithStartTimeNow, simulateWithStartTimeNow, 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, simulateWithStartTimeNow, simulateWithStartTimeNow, 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, simulateWithStartTimeNow, simulateWithStartTimeNow, 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, simulateWithStartTimeNow, simulateWithStartTimeNow, 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;
@@ -115,15 +116,15 @@ 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 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
* 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, boolean simulateWithStartTimeNow, 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
@@ -155,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
@@ -180,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);
@@ -196,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;
@@ -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,
@@ -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);
}
/**
@@ -67,8 +67,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
@@ -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);
}
}
}
@@ -31,8 +31,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);
}
/**
@@ -21,8 +21,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);
}
/**
@@ -1,5 +1,88 @@
package com.sap.sailing.domain.tractracadapter.impl;
public class Simulator {
import java.util.Map;
import com.sap.sailing.domain.base.Timed;
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.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.WindImpl;
public class Simulator {
private DynamicTrackedRace trackedRace;
private WindStore windStore;
private long advanceInMillis;
/**
* 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 void setTrackedRace(DynamicTrackedRace trackedRace) {
this.trackedRace = trackedRace;
startWindPlayer();
}
/**
* 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);
return new WindImpl(wind.getPosition(), delayedTimePoint, new KnotSpeedWithBearingImpl(wind.getKnots(), wind.getBearing()));
}
private long getAdvanceInMillis() {
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."
*/
private TimePoint delay(Timed timed) {
long now = System.currentTimeMillis();
long then = timed.getTimePoint().asMillis();
long transformedTimed = then + getAdvanceInMillis();
long waitTimeInMillis = transformedTimed - now;
do {
if (waitTimeInMillis > 0) {
try {
Thread.sleep(waitTimeInMillis);
waitTimeInMillis = 0;
} catch (InterruptedException e) {
// try again:
waitTimeInMillis = transformedTimed - System.currentTimeMillis();
}
}
} while (waitTimeInMillis > 0);
return new MillisecondsTimePoint(transformedTimed);
}
}
@@ -148,9 +148,14 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
/**
*
* @param regatta if <code>null</code>, then <code>domainFactory.getOrCreateRegatta(tractracEvent)</code> will be used to
* obtain a default regatta
* @param simulateWithStartTimeNow TODO
* @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,
@@ -193,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);
@@ -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);
@@ -244,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.
@@ -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) {
@@ -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, simulateWithStartTimeNow, new AsyncCallback<Void>() {
+ ":" + TracTracConnectionConstants.PORT_STORED, false, false, /* simulateWithStartTimeNow */ false, new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
@@ -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, simulateWithStartTimeNow, EmptyWindStore.INSTANCE);
liveURI, storedURI, startOfTracking, endOfTracking, /* delayToLiveInMillis */
0l, /* simulateWithStartTimeNow */false, EmptyWindStore.INSTANCE);
}
private void startTracking() throws Exception, InterruptedException {
@@ -145,10 +145,10 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch
* created, with a single default series and a single default fleet. If a valid {@link RegattaIdentifier}
* is specified, a regatta lookup is performed with that identifier; if the regatta is found, it is used
* to add the races to. Otherwise, a default regatta as described above will be created and used.
* @param simulateWithStartTimeNow TODO
*/
RacesHandle addTracTracRace(RegattaIdentifier regattaToAddTo, URL paramURL, URI liveURI, URI storedURI,
TimePoint trackingStartTime, TimePoint trackingEndTime, WindStore windStore, long timeoutForReceivingRaceDefinitionInMilliseconds, boolean simulateWithStartTimeNow)
TimePoint trackingStartTime, TimePoint trackingEndTime, WindStore windStore,
long timeoutForReceivingRaceDefinitionInMilliseconds, boolean simulateWithStartTimeNow)
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
/**