mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-09 13:50:57 +00:00
Extended the TrackedRace Constructor by the RaceCommitteeStore, so that
a RC store has to be given at TrackedRace creation, necessary for replication. All following TrackedRace constructor calls and calling methods are adapted accordingly.
This commit is contained in:
1 parent
7a7d0553c4
commit
6fd712e9de
40 files changed
+1260
-1133
No files matched your search
+365
-362
@@ -1,362 +1,365 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.swisstimingadapter.MessageType;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterConnector;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterTransceiver;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.DomainFactoryImpl;
|
||||
import com.sap.sailing.domain.swisstimingadapter.persistence.StoreAndForward;
|
||||
import com.sap.sailing.domain.swisstimingadapter.persistence.SwissTimingAdapterPersistence;
|
||||
import com.sap.sailing.domain.swisstimingadapter.persistence.impl.CollectionNames;
|
||||
import com.sap.sailing.domain.swisstimingadapter.persistence.impl.FieldNames;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.RacesHandle;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.mongodb.MongoDBService;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
|
||||
public class EndToEndListeningStoreAndFowardTest {
|
||||
private static final Logger logger = Logger.getLogger(EndToEndListeningStoreAndFowardTest.class.getName());
|
||||
|
||||
private static final int RECEIVE_PORT = 6543;
|
||||
private static final int CLIENT_PORT = 6544;
|
||||
|
||||
private DB db;
|
||||
private StoreAndForward storeAndForward;
|
||||
private Socket sendingSocket;
|
||||
private OutputStream sendingStream;
|
||||
private SailMasterTransceiver transceiver;
|
||||
private SailMasterConnector connector;
|
||||
private SwissTimingAdapterPersistence swissTimingAdapterPersistence;
|
||||
private SwissTimingFactory swissTimingFactory;
|
||||
|
||||
private EmptyWindStore emptyWindStore;
|
||||
private RacingEventService racingEventService;
|
||||
|
||||
private List<RacesHandle> raceHandles;
|
||||
|
||||
@Before
|
||||
public void setUp() throws UnknownHostException, IOException, InterruptedException {
|
||||
logger.info("EndToEndListeningStoreAndFowardTest.setUp");
|
||||
MongoDBService mongoDBService = MongoDBService.INSTANCE;
|
||||
db = mongoDBService.getDB();
|
||||
db.getCollection(com.sap.sailing.domain.persistence.impl.CollectionNames.REGATTAS.name()).drop();
|
||||
swissTimingAdapterPersistence = SwissTimingAdapterPersistence.INSTANCE;
|
||||
swissTimingAdapterPersistence.dropAllMessageData();
|
||||
swissTimingAdapterPersistence.dropAllRaceMasterData();
|
||||
storeAndForward = new StoreAndForward(RECEIVE_PORT, CLIENT_PORT, SwissTimingFactory.INSTANCE,
|
||||
swissTimingAdapterPersistence, mongoDBService);
|
||||
sendingSocket = new Socket("localhost", RECEIVE_PORT);
|
||||
sendingStream = sendingSocket.getOutputStream();
|
||||
swissTimingFactory = SwissTimingFactory.INSTANCE;
|
||||
emptyWindStore = EmptyWindStore.INSTANCE;
|
||||
transceiver = swissTimingFactory.createSailMasterTransceiver();
|
||||
DBCollection lastMessageCountCollection = db.getCollection(CollectionNames.LAST_MESSAGE_COUNT.name());
|
||||
lastMessageCountCollection.update(new BasicDBObject(),
|
||||
new BasicDBObject().append(FieldNames.LAST_MESSAGE_COUNT.name(), 0l),
|
||||
/* upsert */true, /* multi */false);
|
||||
// important: construct a new domain factory each time to make sure the competitor cache starts out empty
|
||||
final com.sap.sailing.domain.base.impl.DomainFactoryImpl baseDomainFactory = new com.sap.sailing.domain.base.impl.DomainFactoryImpl();
|
||||
racingEventService = new RacingEventServiceImpl(mongoDBService, SwissTimingFactory.INSTANCE,
|
||||
new DomainFactoryImpl(baseDomainFactory),
|
||||
new com.sap.sailing.domain.tractracadapter.impl.DomainFactoryImpl(baseDomainFactory));
|
||||
raceHandles = new ArrayList<RacesHandle>();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws InterruptedException, IOException {
|
||||
logger.entering(getClass().getName(), "tearDown");
|
||||
for (RacesHandle raceHandle : raceHandles) {
|
||||
racingEventService.stopTracking(raceHandle.getRegatta());
|
||||
}
|
||||
logger.info("Calling StoreAndForward.stop() in tearDown");
|
||||
storeAndForward.stop();
|
||||
logger.exiting(getClass().getName(), "tearDown");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndScenarioWithInitMessages() throws Exception {
|
||||
String[] racesToTrack = new String[] { "4711", "4712" };
|
||||
String scriptName = "/InitMessagesScript.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName);
|
||||
|
||||
Set<TrackedRace> allTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allRegattas = racingEventService.getAllRegattas();
|
||||
for (Regatta regatta : allRegattas) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(regatta);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
assertEquals(2, Util.size(allTrackedRaces));
|
||||
Set<String> raceIDs = new HashSet<String>();
|
||||
for (TrackedRace trackedRace : allTrackedRaces) {
|
||||
RaceDefinition race = trackedRace.getRace();
|
||||
raceIDs.add(race.getName());
|
||||
}
|
||||
Set<String> expectedRaceIDs = new HashSet<String>();
|
||||
for (String raceIDToTrack : new String[] { "4711", "4712" }) {
|
||||
expectedRaceIDs.add(raceIDToTrack);
|
||||
}
|
||||
assertEquals(expectedRaceIDs, raceIDs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongRaceLog() throws Exception {
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
String scriptName1 = "/SailMasterDataInterfaceRACandSTL.txt";
|
||||
String scriptName2 = "/SailMasterDataInterface-ExampleAsText.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName1, scriptName2);
|
||||
coreOfTestLongRaceLog();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongRaceLogNewVersion() throws Exception {
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
String scriptName1 = "/W4702RACandSTLandCCG.txt";
|
||||
String scriptName2 = "/W4702AsText.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName1, scriptName2);
|
||||
coreOfTestLongRaceLog();
|
||||
}
|
||||
|
||||
private void coreOfTestLongRaceLog() {
|
||||
Set<TrackedRace> allTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allRegattas = racingEventService.getAllRegattas();
|
||||
for (Regatta regatta : allRegattas) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(regatta);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
assertEquals(1, Util.size(allTrackedRaces));
|
||||
Set<RaceDefinition> races = raceHandles.iterator().next().getRaceTracker().getRaces();
|
||||
assertEquals(1, races.size());
|
||||
RaceDefinition raceFromTracker = races.iterator().next();
|
||||
assertNotNull(raceFromTracker);
|
||||
Set<String> raceIDs = new HashSet<String>();
|
||||
for (TrackedRace trackedRace : allTrackedRaces) {
|
||||
RaceDefinition race = trackedRace.getRace();
|
||||
raceIDs.add(race.getName());
|
||||
assertEquals(46, Util.size(race.getCompetitors()));
|
||||
assertEquals(7, Util.size(race.getCourse().getWaypoints()));
|
||||
assertEquals(6, Util.size(race.getCourse().getLegs()));
|
||||
for (Competitor competitor : race.getCompetitors()) {
|
||||
if (!competitor.getName().equals("Competitor 35") && !competitor.getName().equals("Competitor 20")
|
||||
&& !competitor.getName().equals("GBR 831") && !competitor.getName().equals("NED 24")) {
|
||||
final GPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
|
||||
track.lockForRead();
|
||||
try {
|
||||
assertTrue("Track of competitor " + competitor + " empty", !Util.isEmpty(track.getRawFixes()));
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<Mark> marks = new HashSet<Mark>();
|
||||
for (Waypoint waypoint : race.getCourse().getWaypoints()) {
|
||||
for (Mark mark : waypoint.getMarks()) {
|
||||
marks.add(mark);
|
||||
}
|
||||
}
|
||||
for (Mark mark : marks) {
|
||||
final GPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
|
||||
track.lockForRead();
|
||||
try {
|
||||
assertTrue("Track of mark " + mark + " empty",
|
||||
!Util.isEmpty(track.getRawFixes()));
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<String> expectedRaceIDs = new HashSet<String>();
|
||||
for (String raceIDToTrack : new String[] { "W4702" }) {
|
||||
expectedRaceIDs.add(raceIDToTrack);
|
||||
}
|
||||
assertEquals(expectedRaceIDs, raceIDs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongLogRaceNewConfig() throws Exception {
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
String scriptName1 = "/SailMasterDataInterfaceRACandSTL.txt";
|
||||
String scriptName2 = "/SailMasterDataInterface-ExampleAsText.txt";
|
||||
String scriptNewCourseConfig = "/SailMasterDataInterfaceNewCourseConfig.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName1, scriptName2, scriptNewCourseConfig);
|
||||
Set<TrackedRace> allNewTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allNewEvents = racingEventService.getAllRegattas();
|
||||
for (Regatta event : allNewEvents) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(event);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allNewTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
assertEquals(1, Util.size(allNewTrackedRaces));
|
||||
Set<RaceDefinition> races = raceHandles.iterator().next().getRaceTracker().getRaces();
|
||||
assertEquals(1, races.size());
|
||||
RaceDefinition raceFromTracker = races.iterator().next();
|
||||
assertNotNull(raceFromTracker);
|
||||
Set<String> raceIDs = new HashSet<String>();
|
||||
for (TrackedRace trackedRace : allNewTrackedRaces) {
|
||||
RaceDefinition race = trackedRace.getRace();
|
||||
raceIDs.add(race.getName());
|
||||
assertEquals(46, Util.size(race.getCompetitors()));
|
||||
assertEquals(3, Util.size(race.getCourse().getWaypoints()));
|
||||
assertEquals(2, Util.size(race.getCourse().getLegs()));
|
||||
for (Competitor competitor : race.getCompetitors()) {
|
||||
if (!competitor.getName().equals("NED 24") && !competitor.getName().equals("Competitor 35")
|
||||
&& !competitor.getName().equals("Competitor 20") && !competitor.getName().equals("GBR 831")) {
|
||||
final GPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
|
||||
track.lockForRead();
|
||||
try {
|
||||
assertTrue("Track of competitor " + competitor + " empty", !Util.isEmpty(track.getRawFixes()));
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<Mark> marks = new HashSet<Mark>();
|
||||
for (Waypoint waypoint : race.getCourse().getWaypoints()) {
|
||||
for (Mark mark : waypoint.getMarks()) {
|
||||
marks.add(mark);
|
||||
}
|
||||
}
|
||||
for (Mark mark : marks) {
|
||||
final GPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
|
||||
track.lockForRead();
|
||||
try {
|
||||
assertTrue("Track of mark " + mark + " empty", !Util.isEmpty(track.getRawFixes()));
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<String> expectedRaceIDs = new HashSet<String>();
|
||||
for (String raceIDToTrack : new String[] { "W4702" }) {
|
||||
expectedRaceIDs.add(raceIDToTrack);
|
||||
}
|
||||
assertEquals(expectedRaceIDs, raceIDs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateCCGMessageAndWaypointUniqueness() throws Exception {
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
setUpUsingScript(racesToTrack, "/DuplicateCCG.txt");
|
||||
|
||||
Set<TrackedRace> allTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allEvents = racingEventService.getAllRegattas();
|
||||
for (Regatta event : allEvents) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(event);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
assertEquals(1, allTrackedRaces.size());
|
||||
TrackedRace trackedRace = allTrackedRaces.iterator().next();
|
||||
List<Waypoint> waypoints = new ArrayList<Waypoint>();
|
||||
for (Waypoint waypoint : trackedRace.getRace().getCourse().getWaypoints()) {
|
||||
waypoints.add(waypoint);
|
||||
}
|
||||
assertEquals(7, Util.size(waypoints));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRongRaceLogRACZero() throws Exception{
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
String scriptName2 = "/SailMasterDataInterfaceRACZero.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName2);
|
||||
Set<TrackedRace> allNewTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allNewEvents = racingEventService.getAllRegattas();
|
||||
for (Regatta event : allNewEvents) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(event);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allNewTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
assertEquals(0, Util.size(allNewTrackedRaces));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndWithSwissTimingData() throws Exception {
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
String scriptName1 = "/SailMasterDataInterfaceRACandSTL.txt";
|
||||
String scriptName2 = "/SailMasterDataInterface-ExampleAsText.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName1, scriptName2);
|
||||
|
||||
Set<TrackedRace> allTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allEvents = racingEventService.getAllRegattas();
|
||||
for (Regatta event : allEvents) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(event);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpUsingScript(String[] racesToTrack, String... scriptNames) throws Exception {
|
||||
for (String raceToTrack : racesToTrack) {
|
||||
RacesHandle raceHandle = racingEventService.addSwissTimingRace(/* regattaToAddTo */ null /* use a default regatta */,
|
||||
raceToTrack, "localhost", /* canSendRequests */
|
||||
CLIENT_PORT, false, emptyWindStore, -1);
|
||||
raceHandles.add(raceHandle);
|
||||
if (connector == null) {
|
||||
connector = racingEventService.getSwissTimingFactory().getOrCreateSailMasterConnector("localhost",
|
||||
CLIENT_PORT, swissTimingAdapterPersistence, /* canSendRequests */false);
|
||||
}
|
||||
}
|
||||
ScriptedMessagesReader scriptedMessagesReader = new ScriptedMessagesReader();
|
||||
for (String scriptName : scriptNames) {
|
||||
InputStream is = getClass().getResourceAsStream(scriptName);
|
||||
scriptedMessagesReader.addMessagesFromTextFile(is);
|
||||
}
|
||||
for (String msg : scriptedMessagesReader.getMessages()) {
|
||||
transceiver.sendMessage(msg, sendingStream);
|
||||
}
|
||||
transceiver.sendMessage(swissTimingFactory.createMessage(MessageType._STOPSERVER.name(), null), sendingStream);
|
||||
synchronized (connector) {
|
||||
while (!connector.isStopped()) {
|
||||
connector.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.sap.sailing.domain.swisstimingadapter.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.MessageType;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterConnector;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterTransceiver;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.DomainFactoryImpl;
|
||||
import com.sap.sailing.domain.swisstimingadapter.persistence.StoreAndForward;
|
||||
import com.sap.sailing.domain.swisstimingadapter.persistence.SwissTimingAdapterPersistence;
|
||||
import com.sap.sailing.domain.swisstimingadapter.persistence.impl.CollectionNames;
|
||||
import com.sap.sailing.domain.swisstimingadapter.persistence.impl.FieldNames;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.RacesHandle;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.mongodb.MongoDBService;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
|
||||
public class EndToEndListeningStoreAndFowardTest {
|
||||
private static final Logger logger = Logger.getLogger(EndToEndListeningStoreAndFowardTest.class.getName());
|
||||
|
||||
private static final int RECEIVE_PORT = 6543;
|
||||
private static final int CLIENT_PORT = 6544;
|
||||
|
||||
private DB db;
|
||||
private StoreAndForward storeAndForward;
|
||||
private Socket sendingSocket;
|
||||
private OutputStream sendingStream;
|
||||
private SailMasterTransceiver transceiver;
|
||||
private SailMasterConnector connector;
|
||||
private SwissTimingAdapterPersistence swissTimingAdapterPersistence;
|
||||
private SwissTimingFactory swissTimingFactory;
|
||||
|
||||
private EmptyWindStore emptyWindStore;
|
||||
private EmptyRaceCommitteeStore emptyRaceCommitteeStore;
|
||||
private RacingEventService racingEventService;
|
||||
|
||||
private List<RacesHandle> raceHandles;
|
||||
|
||||
@Before
|
||||
public void setUp() throws UnknownHostException, IOException, InterruptedException {
|
||||
logger.info("EndToEndListeningStoreAndFowardTest.setUp");
|
||||
MongoDBService mongoDBService = MongoDBService.INSTANCE;
|
||||
db = mongoDBService.getDB();
|
||||
db.getCollection(com.sap.sailing.domain.persistence.impl.CollectionNames.REGATTAS.name()).drop();
|
||||
swissTimingAdapterPersistence = SwissTimingAdapterPersistence.INSTANCE;
|
||||
swissTimingAdapterPersistence.dropAllMessageData();
|
||||
swissTimingAdapterPersistence.dropAllRaceMasterData();
|
||||
storeAndForward = new StoreAndForward(RECEIVE_PORT, CLIENT_PORT, SwissTimingFactory.INSTANCE,
|
||||
swissTimingAdapterPersistence, mongoDBService);
|
||||
sendingSocket = new Socket("localhost", RECEIVE_PORT);
|
||||
sendingStream = sendingSocket.getOutputStream();
|
||||
swissTimingFactory = SwissTimingFactory.INSTANCE;
|
||||
emptyWindStore = EmptyWindStore.INSTANCE;
|
||||
emptyRaceCommitteeStore = EmptyRaceCommitteeStore.INSTANCE;
|
||||
transceiver = swissTimingFactory.createSailMasterTransceiver();
|
||||
DBCollection lastMessageCountCollection = db.getCollection(CollectionNames.LAST_MESSAGE_COUNT.name());
|
||||
lastMessageCountCollection.update(new BasicDBObject(),
|
||||
new BasicDBObject().append(FieldNames.LAST_MESSAGE_COUNT.name(), 0l),
|
||||
/* upsert */true, /* multi */false);
|
||||
// important: construct a new domain factory each time to make sure the competitor cache starts out empty
|
||||
final com.sap.sailing.domain.base.impl.DomainFactoryImpl baseDomainFactory = new com.sap.sailing.domain.base.impl.DomainFactoryImpl();
|
||||
racingEventService = new RacingEventServiceImpl(mongoDBService, SwissTimingFactory.INSTANCE,
|
||||
new DomainFactoryImpl(baseDomainFactory),
|
||||
new com.sap.sailing.domain.tractracadapter.impl.DomainFactoryImpl(baseDomainFactory));
|
||||
raceHandles = new ArrayList<RacesHandle>();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws InterruptedException, IOException {
|
||||
logger.entering(getClass().getName(), "tearDown");
|
||||
for (RacesHandle raceHandle : raceHandles) {
|
||||
racingEventService.stopTracking(raceHandle.getRegatta());
|
||||
}
|
||||
logger.info("Calling StoreAndForward.stop() in tearDown");
|
||||
storeAndForward.stop();
|
||||
logger.exiting(getClass().getName(), "tearDown");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndScenarioWithInitMessages() throws Exception {
|
||||
String[] racesToTrack = new String[] { "4711", "4712" };
|
||||
String scriptName = "/InitMessagesScript.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName);
|
||||
|
||||
Set<TrackedRace> allTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allRegattas = racingEventService.getAllRegattas();
|
||||
for (Regatta regatta : allRegattas) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(regatta);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
assertEquals(2, Util.size(allTrackedRaces));
|
||||
Set<String> raceIDs = new HashSet<String>();
|
||||
for (TrackedRace trackedRace : allTrackedRaces) {
|
||||
RaceDefinition race = trackedRace.getRace();
|
||||
raceIDs.add(race.getName());
|
||||
}
|
||||
Set<String> expectedRaceIDs = new HashSet<String>();
|
||||
for (String raceIDToTrack : new String[] { "4711", "4712" }) {
|
||||
expectedRaceIDs.add(raceIDToTrack);
|
||||
}
|
||||
assertEquals(expectedRaceIDs, raceIDs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongRaceLog() throws Exception {
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
String scriptName1 = "/SailMasterDataInterfaceRACandSTL.txt";
|
||||
String scriptName2 = "/SailMasterDataInterface-ExampleAsText.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName1, scriptName2);
|
||||
coreOfTestLongRaceLog();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongRaceLogNewVersion() throws Exception {
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
String scriptName1 = "/W4702RACandSTLandCCG.txt";
|
||||
String scriptName2 = "/W4702AsText.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName1, scriptName2);
|
||||
coreOfTestLongRaceLog();
|
||||
}
|
||||
|
||||
private void coreOfTestLongRaceLog() {
|
||||
Set<TrackedRace> allTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allRegattas = racingEventService.getAllRegattas();
|
||||
for (Regatta regatta : allRegattas) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(regatta);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
assertEquals(1, Util.size(allTrackedRaces));
|
||||
Set<RaceDefinition> races = raceHandles.iterator().next().getRaceTracker().getRaces();
|
||||
assertEquals(1, races.size());
|
||||
RaceDefinition raceFromTracker = races.iterator().next();
|
||||
assertNotNull(raceFromTracker);
|
||||
Set<String> raceIDs = new HashSet<String>();
|
||||
for (TrackedRace trackedRace : allTrackedRaces) {
|
||||
RaceDefinition race = trackedRace.getRace();
|
||||
raceIDs.add(race.getName());
|
||||
assertEquals(46, Util.size(race.getCompetitors()));
|
||||
assertEquals(7, Util.size(race.getCourse().getWaypoints()));
|
||||
assertEquals(6, Util.size(race.getCourse().getLegs()));
|
||||
for (Competitor competitor : race.getCompetitors()) {
|
||||
if (!competitor.getName().equals("Competitor 35") && !competitor.getName().equals("Competitor 20")
|
||||
&& !competitor.getName().equals("GBR 831") && !competitor.getName().equals("NED 24")) {
|
||||
final GPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
|
||||
track.lockForRead();
|
||||
try {
|
||||
assertTrue("Track of competitor " + competitor + " empty", !Util.isEmpty(track.getRawFixes()));
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<Mark> marks = new HashSet<Mark>();
|
||||
for (Waypoint waypoint : race.getCourse().getWaypoints()) {
|
||||
for (Mark mark : waypoint.getMarks()) {
|
||||
marks.add(mark);
|
||||
}
|
||||
}
|
||||
for (Mark mark : marks) {
|
||||
final GPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
|
||||
track.lockForRead();
|
||||
try {
|
||||
assertTrue("Track of mark " + mark + " empty",
|
||||
!Util.isEmpty(track.getRawFixes()));
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<String> expectedRaceIDs = new HashSet<String>();
|
||||
for (String raceIDToTrack : new String[] { "W4702" }) {
|
||||
expectedRaceIDs.add(raceIDToTrack);
|
||||
}
|
||||
assertEquals(expectedRaceIDs, raceIDs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongLogRaceNewConfig() throws Exception {
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
String scriptName1 = "/SailMasterDataInterfaceRACandSTL.txt";
|
||||
String scriptName2 = "/SailMasterDataInterface-ExampleAsText.txt";
|
||||
String scriptNewCourseConfig = "/SailMasterDataInterfaceNewCourseConfig.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName1, scriptName2, scriptNewCourseConfig);
|
||||
Set<TrackedRace> allNewTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allNewEvents = racingEventService.getAllRegattas();
|
||||
for (Regatta event : allNewEvents) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(event);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allNewTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
assertEquals(1, Util.size(allNewTrackedRaces));
|
||||
Set<RaceDefinition> races = raceHandles.iterator().next().getRaceTracker().getRaces();
|
||||
assertEquals(1, races.size());
|
||||
RaceDefinition raceFromTracker = races.iterator().next();
|
||||
assertNotNull(raceFromTracker);
|
||||
Set<String> raceIDs = new HashSet<String>();
|
||||
for (TrackedRace trackedRace : allNewTrackedRaces) {
|
||||
RaceDefinition race = trackedRace.getRace();
|
||||
raceIDs.add(race.getName());
|
||||
assertEquals(46, Util.size(race.getCompetitors()));
|
||||
assertEquals(3, Util.size(race.getCourse().getWaypoints()));
|
||||
assertEquals(2, Util.size(race.getCourse().getLegs()));
|
||||
for (Competitor competitor : race.getCompetitors()) {
|
||||
if (!competitor.getName().equals("NED 24") && !competitor.getName().equals("Competitor 35")
|
||||
&& !competitor.getName().equals("Competitor 20") && !competitor.getName().equals("GBR 831")) {
|
||||
final GPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
|
||||
track.lockForRead();
|
||||
try {
|
||||
assertTrue("Track of competitor " + competitor + " empty", !Util.isEmpty(track.getRawFixes()));
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<Mark> marks = new HashSet<Mark>();
|
||||
for (Waypoint waypoint : race.getCourse().getWaypoints()) {
|
||||
for (Mark mark : waypoint.getMarks()) {
|
||||
marks.add(mark);
|
||||
}
|
||||
}
|
||||
for (Mark mark : marks) {
|
||||
final GPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
|
||||
track.lockForRead();
|
||||
try {
|
||||
assertTrue("Track of mark " + mark + " empty", !Util.isEmpty(track.getRawFixes()));
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<String> expectedRaceIDs = new HashSet<String>();
|
||||
for (String raceIDToTrack : new String[] { "W4702" }) {
|
||||
expectedRaceIDs.add(raceIDToTrack);
|
||||
}
|
||||
assertEquals(expectedRaceIDs, raceIDs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateCCGMessageAndWaypointUniqueness() throws Exception {
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
setUpUsingScript(racesToTrack, "/DuplicateCCG.txt");
|
||||
|
||||
Set<TrackedRace> allTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allEvents = racingEventService.getAllRegattas();
|
||||
for (Regatta event : allEvents) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(event);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
assertEquals(1, allTrackedRaces.size());
|
||||
TrackedRace trackedRace = allTrackedRaces.iterator().next();
|
||||
List<Waypoint> waypoints = new ArrayList<Waypoint>();
|
||||
for (Waypoint waypoint : trackedRace.getRace().getCourse().getWaypoints()) {
|
||||
waypoints.add(waypoint);
|
||||
}
|
||||
assertEquals(7, Util.size(waypoints));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRongRaceLogRACZero() throws Exception{
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
String scriptName2 = "/SailMasterDataInterfaceRACZero.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName2);
|
||||
Set<TrackedRace> allNewTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allNewEvents = racingEventService.getAllRegattas();
|
||||
for (Regatta event : allNewEvents) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(event);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allNewTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
assertEquals(0, Util.size(allNewTrackedRaces));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndToEndWithSwissTimingData() throws Exception {
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
String scriptName1 = "/SailMasterDataInterfaceRACandSTL.txt";
|
||||
String scriptName2 = "/SailMasterDataInterface-ExampleAsText.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName1, scriptName2);
|
||||
|
||||
Set<TrackedRace> allTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allEvents = racingEventService.getAllRegattas();
|
||||
for (Regatta event : allEvents) {
|
||||
DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(event);
|
||||
Iterable<TrackedRace> trackedRaces = trackedRegatta.getTrackedRaces();
|
||||
for (TrackedRace trackedRace : trackedRaces) {
|
||||
allTrackedRaces.add(trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpUsingScript(String[] racesToTrack, String... scriptNames) throws Exception {
|
||||
for (String raceToTrack : racesToTrack) {
|
||||
RacesHandle raceHandle = racingEventService.addSwissTimingRace(/* regattaToAddTo */ null /* use a default regatta */,
|
||||
raceToTrack, "localhost", /* canSendRequests */
|
||||
CLIENT_PORT, false, emptyWindStore, -1, emptyRaceCommitteeStore);
|
||||
raceHandles.add(raceHandle);
|
||||
if (connector == null) {
|
||||
connector = racingEventService.getSwissTimingFactory().getOrCreateSailMasterConnector("localhost",
|
||||
CLIENT_PORT, swissTimingAdapterPersistence, /* canSendRequests */false);
|
||||
}
|
||||
}
|
||||
ScriptedMessagesReader scriptedMessagesReader = new ScriptedMessagesReader();
|
||||
for (String scriptName : scriptNames) {
|
||||
InputStream is = getClass().getResourceAsStream(scriptName);
|
||||
scriptedMessagesReader.addMessagesFromTextFile(is);
|
||||
}
|
||||
for (String msg : scriptedMessagesReader.getMessages()) {
|
||||
transceiver.sendMessage(msg, sendingStream);
|
||||
}
|
||||
transceiver.sendMessage(swissTimingFactory.createMessage(MessageType._STOPSERVER.name(), null), sendingStream);
|
||||
synchronized (connector) {
|
||||
while (!connector.isStopped()) {
|
||||
connector.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.DomainFactoryImpl;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
@@ -49,7 +50,7 @@ public interface DomainFactory {
|
||||
|
||||
RaceTrackingConnectivityParameters createTrackingConnectivityParameters(String hostname, int port, String raceID,
|
||||
boolean canSendRequests, long delayToLiveInMillis,
|
||||
SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, WindStore windStore,
|
||||
SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, WindStore windStore, RaceCommitteeStore raceCommitteeStore,
|
||||
RaceSpecificMessageLoader messageLoader);
|
||||
|
||||
BoatClass getOrCreateBoatClassFromRaceID(String raceID);
|
||||
|
||||
+3
-2
@@ -6,6 +6,7 @@ import java.text.ParseException;
|
||||
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.impl.SwissTimingFactoryImpl;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
@@ -51,11 +52,11 @@ public interface SwissTimingFactory {
|
||||
|
||||
SwissTimingConfiguration createSwissTimingConfiguration(String name, String hostname, int port, boolean canSendRequests);
|
||||
|
||||
SwissTimingRaceTracker createRaceTracker(String raceID, String hostname, int port, boolean canSendRequests, long delayToLiveInMillis, WindStore windStore, RaceSpecificMessageLoader messageLoader, DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws InterruptedException, UnknownHostException, IOException, ParseException;
|
||||
SwissTimingRaceTracker createRaceTracker(String raceID, String hostname, int port, boolean canSendRequests, long delayToLiveInMillis, WindStore windStore, RaceSpecificMessageLoader messageLoader, DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry, RaceCommitteeStore raceCommitteeStore) throws InterruptedException, UnknownHostException, IOException, ParseException;
|
||||
|
||||
RaceTracker createRaceTracker(Regatta regatta, String raceID, String hostname, int port, boolean canSendRequests, long delayToLiveInMillis,
|
||||
WindStore windStore, RaceSpecificMessageLoader messageLoader, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry) throws UnknownHostException, InterruptedException,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceCommitteeStore raceCommitteeStore) throws UnknownHostException, InterruptedException,
|
||||
IOException, ParseException;
|
||||
|
||||
Race createRace(String raceId, String description, TimePoint startTime);
|
||||
|
||||
+3
-2
@@ -29,6 +29,7 @@ import com.sap.sailing.domain.base.impl.TeamImpl;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Course;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Fix;
|
||||
@@ -301,10 +302,10 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
@Override
|
||||
public RaceTrackingConnectivityParameters createTrackingConnectivityParameters(String hostname, int port, String raceID,
|
||||
boolean canSendRequests, long delayToLiveInMillis,
|
||||
SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, WindStore windStore,
|
||||
SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, WindStore windStore, RaceCommitteeStore raceCommitteeStore,
|
||||
RaceSpecificMessageLoader messageLoader) {
|
||||
return new SwissTimingTrackingConnectivityParameters(hostname, port, raceID, canSendRequests, delayToLiveInMillis,
|
||||
swissTimingFactory, domainFactory, windStore, messageLoader);
|
||||
swissTimingFactory, domainFactory, windStore, raceCommitteeStore, messageLoader);
|
||||
}
|
||||
|
||||
}
|
||||
+6
-4
@@ -9,6 +9,7 @@ import java.util.Map;
|
||||
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.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Race;
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceSpecificMessageLoader;
|
||||
@@ -80,19 +81,20 @@ public class SwissTimingFactoryImpl implements SwissTimingFactory {
|
||||
@Override
|
||||
public SwissTimingRaceTracker createRaceTracker(String raceID, String hostname, int port, boolean canSendRequests, long delayToLiveInMillis,
|
||||
WindStore windStore, RaceSpecificMessageLoader messageLoader, DomainFactory domainFactory,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry) throws InterruptedException, UnknownHostException, IOException,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceCommitteeStore raceCommitteeStore) throws InterruptedException, UnknownHostException, IOException,
|
||||
ParseException {
|
||||
return new SwissTimingRaceTrackerImpl(raceID, hostname, port, windStore, domainFactory, this, messageLoader,
|
||||
trackedRegattaRegistry, canSendRequests, delayToLiveInMillis);
|
||||
trackedRegattaRegistry, canSendRequests, delayToLiveInMillis, raceCommitteeStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(Regatta regatta, String raceID, String hostname, int port,
|
||||
boolean canSendRequests, long delayToLiveInMillis, WindStore windStore, RaceSpecificMessageLoader messageLoader,
|
||||
DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry) throws UnknownHostException,
|
||||
DomainFactory domainFactory, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
RaceCommitteeStore raceCommitteeStore) throws UnknownHostException,
|
||||
InterruptedException, IOException, ParseException {
|
||||
return new SwissTimingRaceTrackerImpl(regatta, raceID, hostname, port, windStore, domainFactory, this,
|
||||
messageLoader, trackedRegattaRegistry, canSendRequests, delayToLiveInMillis);
|
||||
messageLoader, trackedRegattaRegistry, canSendRequests, delayToLiveInMillis, raceCommitteeStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
-4
@@ -22,6 +22,7 @@ import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Course;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Fix;
|
||||
@@ -59,6 +60,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
|
||||
private final Triple<String, String, Integer> id;
|
||||
private final Regatta regatta;
|
||||
private final WindStore windStore;
|
||||
private final RaceCommitteeStore raceCommitteeStore;
|
||||
|
||||
private RaceDefinition race;
|
||||
private Course course;
|
||||
@@ -71,15 +73,17 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
|
||||
|
||||
protected SwissTimingRaceTrackerImpl(String raceID, String hostname, int port, WindStore windStore,
|
||||
DomainFactory domainFactory, SwissTimingFactory factory, RaceSpecificMessageLoader messageLoader,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, boolean canSendRequests, long delayToLiveInMillis) throws InterruptedException,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, boolean canSendRequests, long delayToLiveInMillis,
|
||||
RaceCommitteeStore raceCommitteeStore) throws InterruptedException,
|
||||
UnknownHostException, IOException, ParseException {
|
||||
this(domainFactory.getOrCreateRegatta(raceID, trackedRegattaRegistry), raceID, hostname, port, windStore, domainFactory, factory,
|
||||
messageLoader, trackedRegattaRegistry, canSendRequests, delayToLiveInMillis);
|
||||
messageLoader, trackedRegattaRegistry, canSendRequests, delayToLiveInMillis, raceCommitteeStore);
|
||||
}
|
||||
|
||||
protected SwissTimingRaceTrackerImpl(Regatta regatta, String raceID, String hostname, int port, WindStore windStore,
|
||||
DomainFactory domainFactory, SwissTimingFactory factory, RaceSpecificMessageLoader messageLoader,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, boolean canSendRequests, long delayToLiveInMillis) throws InterruptedException,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, boolean canSendRequests, long delayToLiveInMillis,
|
||||
RaceCommitteeStore raceCommitteeStore) throws InterruptedException,
|
||||
UnknownHostException, IOException, ParseException {
|
||||
super();
|
||||
this.regatta = regatta;
|
||||
@@ -88,6 +92,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
|
||||
this.raceID = raceID;
|
||||
this.messageLoader = messageLoader;
|
||||
this.windStore = windStore;
|
||||
this.raceCommitteeStore = raceCommitteeStore;
|
||||
this.id = createID(raceID, hostname, port);
|
||||
connector.addSailMasterListener(raceID, this);
|
||||
trackedRegatta = trackedRegattaRegistry.getOrCreateTrackedRegatta(regatta);
|
||||
@@ -278,7 +283,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
|
||||
// we already know our single RaceDefinition
|
||||
assert SwissTimingRaceTrackerImpl.this.race == race;
|
||||
}
|
||||
});
|
||||
}, raceCommitteeStore);
|
||||
logger.info("Created SwissTiming RaceDefinition and TrackedRace for "+race.getName());
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceSpecificMessageLoader;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
|
||||
@@ -17,11 +18,12 @@ public class SwissTimingTrackingConnectivityParameters implements RaceTrackingCo
|
||||
private final SwissTimingFactory swissTimingFactory;
|
||||
private final DomainFactory domainFactory;
|
||||
private final WindStore windStore;
|
||||
private final RaceCommitteeStore raceCommitteeStore;
|
||||
private final RaceSpecificMessageLoader messageLoader;
|
||||
private final long delayToLiveInMillis;
|
||||
|
||||
public SwissTimingTrackingConnectivityParameters(String hostname, int port, String raceID, boolean canSendRequests, long delayToLiveInMillis,
|
||||
SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, WindStore windStore,
|
||||
SwissTimingFactory swissTimingFactory, DomainFactory domainFactory, WindStore windStore, RaceCommitteeStore raceCommitteeStore,
|
||||
RaceSpecificMessageLoader messageLoader) {
|
||||
super();
|
||||
this.hostname = hostname;
|
||||
@@ -32,20 +34,21 @@ public class SwissTimingTrackingConnectivityParameters implements RaceTrackingCo
|
||||
this.swissTimingFactory = swissTimingFactory;
|
||||
this.domainFactory = domainFactory;
|
||||
this.windStore = windStore;
|
||||
this.raceCommitteeStore = raceCommitteeStore;
|
||||
this.messageLoader = messageLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry) throws Exception {
|
||||
return swissTimingFactory.createRaceTracker(raceID, hostname, port, canSendRequests, delayToLiveInMillis, windStore, messageLoader,
|
||||
domainFactory, trackedRegattaRegistry);
|
||||
domainFactory, trackedRegattaRegistry, raceCommitteeStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry)
|
||||
throws Exception {
|
||||
return swissTimingFactory.createRaceTracker(regatta, raceID, hostname, port, canSendRequests, delayToLiveInMillis, windStore, messageLoader,
|
||||
domainFactory, trackedRegattaRegistry);
|
||||
domainFactory, trackedRegattaRegistry, raceCommitteeStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-1
@@ -34,6 +34,7 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.CompetitorStatus;
|
||||
import com.sap.sailing.domain.swisstimingreplayadapter.SwissTimingReplayListener;
|
||||
@@ -305,7 +306,7 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter {
|
||||
createTrackedRace(race, EmptyWindStore.INSTANCE, TrackedRace.DEFAULT_LIVE_DELAY_IN_MILLISECONDS,
|
||||
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND,
|
||||
/* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
|
||||
/* raceDefinitionSetToUpdate */ null);
|
||||
/* raceDefinitionSetToUpdate */ null, EmptyRaceCommitteeStore.INSTANCE);
|
||||
TimePoint bestStartTimeKnownSoFar = bestStartTimePerRaceID.get(currentRaceID);
|
||||
if (bestStartTimeKnownSoFar != null) {
|
||||
trackedRace.setStartTimeReceived(bestStartTimeKnownSoFar);
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.sap.sailing.domain.base.impl.MarkImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
|
||||
@@ -243,7 +244,8 @@ public class CourseTest {
|
||||
hasso),
|
||||
EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 3000,
|
||||
/* millisecondsOverWhichToAverageWind */ 30000,
|
||||
/* millisecondsOverWhichToAverageSpeed */ 8000);
|
||||
/* millisecondsOverWhichToAverageSpeed */ 8000,
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
assertLegStructure(course, trackedRace);
|
||||
course.removeWaypoint(0);
|
||||
assertLegStructure(course, trackedRace);
|
||||
@@ -273,7 +275,8 @@ public class CourseTest {
|
||||
hasso),
|
||||
EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 3000,
|
||||
/* millisecondsOverWhichToAverageWind */ 30000,
|
||||
/* millisecondsOverWhichToAverageSpeed */ 8000);
|
||||
/* millisecondsOverWhichToAverageSpeed */ 8000,
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
assertLegStructure(course, trackedRace);
|
||||
final WaypointImpl wp1_5 = new WaypointImpl(new MarkImpl("Test Mark 1.5"));
|
||||
assertWaypointIndexes(course);
|
||||
|
||||
+3
-1
@@ -31,6 +31,7 @@ import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
@@ -76,7 +77,8 @@ public class CourseUpdateTest extends AbstractTracTracLiveTest {
|
||||
@Override
|
||||
public void addRaceDefinition(RaceDefinition race) {}
|
||||
}, /* delayToLiveInMillis */ 0l,
|
||||
/* millisecondsOverWhichToAverageWind */ 30000, /* simulator */ null) {
|
||||
/* millisecondsOverWhichToAverageWind */ 30000, /* simulator */ null,
|
||||
EmptyRaceCommitteeStore.INSTANCE) {
|
||||
@Override
|
||||
protected void handleEvent(Triple<Route, RouteData, Race> event) {
|
||||
super.handleEvent(event);
|
||||
|
||||
+8
-4
@@ -15,6 +15,7 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants;
|
||||
@@ -50,25 +51,28 @@ public class MultipleClassesInRegattaTest {
|
||||
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 */ false,
|
||||
EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
|
||||
EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry(), EmptyRaceCommitteeStore.INSTANCE);
|
||||
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 */ false, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
|
||||
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry(),
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
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 */ false, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
|
||||
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry(),
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
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 */ false, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry());
|
||||
/* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l, /* simulateWithStartTimeNow */ false, EmptyWindStore.INSTANCE, new DummyTrackedRegattaRegistry(),
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
|
||||
assertEquals("STG", kiwotest1.getRegatta().getBoatClass().getName());
|
||||
assertEquals("505", kiwotest2.getRegatta().getBoatClass().getName());
|
||||
|
||||
+2
-1
@@ -26,6 +26,7 @@ import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
@@ -89,7 +90,7 @@ public abstract class OnlineTracTracBasedTest extends AbstractTracTracLiveTest {
|
||||
throws InterruptedException {
|
||||
setStoredDataLoaded(false);
|
||||
ArrayList<Receiver> receivers = new ArrayList<Receiver>();
|
||||
for (Receiver r : domainFactory.getUpdateReceivers(trackedRegatta, getTracTracEvent(), EmptyWindStore.INSTANCE,
|
||||
for (Receiver r : domainFactory.getUpdateReceivers(trackedRegatta, getTracTracEvent(), EmptyWindStore.INSTANCE, EmptyRaceCommitteeStore.INSTANCE,
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulator */ null,
|
||||
new DynamicRaceDefinitionSet() {
|
||||
@Override
|
||||
|
||||
+3
-1
@@ -40,6 +40,7 @@ import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedLeg;
|
||||
@@ -100,7 +101,8 @@ public class ReachingLegTest extends TrackBasedTest {
|
||||
DynamicTrackedRace trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, EmptyWindStore.INSTANCE,
|
||||
/* delayToLiveInMillis */ 0,
|
||||
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
|
||||
/* delay for wind estimation cache invalidation */ 0);
|
||||
/* delay for wind estimation cache invalidation */ 0,
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
// in this simplified artificial course, the top mark is exactly north of the right leeward gate, the offset
|
||||
// mark is slightly west of the top mark; wind from the north makes the leg from top to offset a reaching leg
|
||||
Position leftPosition = new DegreePosition(0, -0.00001);
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ import org.junit.Test;
|
||||
import com.maptrack.client.io.TypeController;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
|
||||
@@ -94,7 +95,7 @@ public class ReceiveMarkPassingDataTest extends AbstractTracTracLiveTest {
|
||||
receivers.add(receiver);
|
||||
for (Receiver r : DomainFactory.INSTANCE.getUpdateReceivers(
|
||||
new DynamicTrackedRegattaImpl(DomainFactory.INSTANCE.getOrCreateDefaultRegatta(getTracTracEvent(), /* trackedRegattaRegistry */ null)),
|
||||
getTracTracEvent(), EmptyWindStore.INSTANCE, /* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l,
|
||||
getTracTracEvent(), EmptyWindStore.INSTANCE, EmptyRaceCommitteeStore.INSTANCE, /* startOfTracking */ null, /* endOfTracking */ null, /* delayToLiveInMillis */ 0l,
|
||||
/* simulator */ null, new DynamicRaceDefinitionSet() {
|
||||
@Override
|
||||
public void addRaceDefinition(RaceDefinition race) {}
|
||||
|
||||
+3
-2
@@ -14,6 +14,7 @@ import com.maptrack.client.io.TypeController;
|
||||
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.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
@@ -83,7 +84,7 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest {
|
||||
@Override
|
||||
public void addRaceDefinition(RaceDefinition race) {
|
||||
}
|
||||
}, /* trackedRegattaRegistry */ null)) {
|
||||
}, /* trackedRegattaRegistry */ null, EmptyRaceCommitteeStore.INSTANCE)) {
|
||||
for (TypeController raceListener : receiver.getTypeControllersAndStart()) {
|
||||
listeners.add(raceListener);
|
||||
}
|
||||
@@ -94,7 +95,7 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest {
|
||||
@Override
|
||||
public void addRaceDefinition(RaceDefinition race) {
|
||||
}
|
||||
}, /* trackedRegattaRegistry */ null));
|
||||
}, /* trackedRegattaRegistry */ null, EmptyRaceCommitteeStore.INSTANCE));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+3
-1
@@ -33,6 +33,7 @@ import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
@@ -110,7 +111,8 @@ public abstract class TrackBasedTest {
|
||||
DynamicTrackedRace trackedRace = new DynamicTrackedRaceImpl(trackedRegatta, race, EmptyWindStore.INSTANCE,
|
||||
/* delayToLiveInMillis */ 0,
|
||||
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
|
||||
/* delay for wind estimation cache invalidation */ 0);
|
||||
/* delay for wind estimation cache invalidation */ 0,
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
// in this simplified artificial course, the top mark is exactly north of the right leeward gate
|
||||
DegreePosition topPosition = new DegreePosition(54.48, 10.24);
|
||||
TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix time
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants;
|
||||
@@ -54,7 +55,7 @@ public class UnicodeCharactersInCompetitorNamesTest {
|
||||
+ TracTracConnectionConstants.PORT_STORED),
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l,
|
||||
/* simulateWithStartTimeNow */ false, EmptyWindStore.INSTANCE,
|
||||
new DummyTrackedRegattaRegistry());
|
||||
new DummyTrackedRegattaRegistry(), EmptyRaceCommitteeStore.INSTANCE);
|
||||
|
||||
Iterable<Competitor> competitors = fourtyninerYellow_2.getRacesHandle().getRaces().iterator().next()
|
||||
.getCompetitors();
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
@@ -268,7 +269,8 @@ public class WindTest {
|
||||
boatClass, Collections.singleton(competitor)),
|
||||
EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 1000,
|
||||
/* millisecondsOverWhichToAverageWind */ 30000,
|
||||
/* millisecondsOverWhichToAverageSpeed */ 30000);
|
||||
/* millisecondsOverWhichToAverageSpeed */ 30000,
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
TimePoint start = MillisecondsTimePoint.now();
|
||||
TimePoint topMarkRounding = start.plus(30000);
|
||||
TimePoint finish = topMarkRounding.plus(30000);
|
||||
|
||||
+1
-1
@@ -445,7 +445,7 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
@Override
|
||||
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, WindStore windStore,
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, RaceCommitteeStore raceCommitteeStore) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
+14
-7
@@ -22,6 +22,7 @@ import com.sap.sailing.domain.base.Team;
|
||||
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.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
@@ -123,19 +124,23 @@ public interface DomainFactory {
|
||||
* Provides the capability to obtain the {@link WindTrack}s for the different wind sources. A trivial
|
||||
* implementation is {@link EmptyWindStore} which simply provides new, empty tracks. This is always
|
||||
* available but loses track of the wind, e.g., during server restarts.
|
||||
* @param raceCommitteeStore
|
||||
* Provides the capability to obtain the {@link RaceCommitteeTrack} for the race. A trivial
|
||||
* implementation is {@link EmptyRaceCommitteeStore} which simply provides new, empty tracks. This is always
|
||||
* available but loses track of race committee events, 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,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceCommitteeStore raceCommitteeStore) throws MalformedURLException, FileNotFoundException,
|
||||
URISyntaxException;
|
||||
|
||||
/**
|
||||
* Same as {@link #createRaceTracker(URL, URI, URI, TimePoint, TimePoint, WindStore, TrackedRegattaRegistry)}, only that
|
||||
* Same as {@link #createRaceTracker(URL, URI, URI, TimePoint, TimePoint, WindStore, TrackedRegattaRegistry, RaceCommitteeStore)}, 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, boolean simulateWithStartTimeNow, WindStore windStore,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceCommitteeStore raceCommitteeStore) throws MalformedURLException, FileNotFoundException,
|
||||
URISyntaxException;
|
||||
|
||||
BoatClass getOrCreateBoatClass(CompetitorClass competitorClass);
|
||||
@@ -165,7 +170,8 @@ public interface DomainFactory {
|
||||
* {@link RaceCourseReceiver} created by this call
|
||||
*/
|
||||
Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, Event tractracEvent, TimePoint startOfTracking,
|
||||
TimePoint endOfTracking, long delayToLiveInMillis, Simulator simulator, WindStore windStore, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry);
|
||||
TimePoint endOfTracking, long delayToLiveInMillis, Simulator simulator, WindStore windStore, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
RaceCommitteeStore raceCommitteeStore);
|
||||
|
||||
/**
|
||||
* Creates a {@link RaceDefinition} from a TracTrac {@link Race} and a domain {@link Course} definition. The
|
||||
@@ -186,7 +192,7 @@ public interface DomainFactory {
|
||||
*/
|
||||
DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta, Race race,
|
||||
Course course, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate);
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, RaceCommitteeStore raceCommitteeStore);
|
||||
|
||||
/**
|
||||
* The record may be for a single mark or a gate. If for a gate, the
|
||||
@@ -199,7 +205,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,
|
||||
Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta, Event tractracEvent, WindStore windStore, RaceCommitteeStore raceCommitteeStore,
|
||||
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, Simulator simulator, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, ReceiverType... types);
|
||||
|
||||
JSONService parseJSONURL(URL jsonURL) throws IOException, ParseException, org.json.simple.parser.ParseException, URISyntaxException;
|
||||
@@ -235,7 +241,8 @@ 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, boolean simulateWithStartTimeNow, WindStore windStore);
|
||||
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore,
|
||||
RaceCommitteeStore raceCommitteeStore);
|
||||
/**
|
||||
* 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
|
||||
|
||||
+17
-14
@@ -45,6 +45,7 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
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.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
@@ -348,7 +349,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
|
||||
@Override
|
||||
public Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta,
|
||||
com.tractrac.clientmodule.Event tractracEvent, WindStore windStore, TimePoint startOfTracking,
|
||||
com.tractrac.clientmodule.Event tractracEvent, WindStore windStore, RaceCommitteeStore raceCommitteeStore, TimePoint startOfTracking,
|
||||
TimePoint endOfTracking, long delayToLiveInMillis, Simulator simulator,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
ReceiverType... types) {
|
||||
@@ -359,7 +360,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
result.add(new RaceCourseReceiver(
|
||||
this, trackedRegatta, tractracEvent, windStore,
|
||||
raceDefinitionSetToUpdate, delayToLiveInMillis,
|
||||
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, simulator));
|
||||
WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, simulator, raceCommitteeStore));
|
||||
break;
|
||||
case MARKPOSITIONS:
|
||||
result.add(new MarkPositionReceiver(
|
||||
@@ -386,8 +387,8 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
public Iterable<Receiver> getUpdateReceivers(DynamicTrackedRegatta trackedRegatta,
|
||||
com.tractrac.clientmodule.Event tractracEvent, TimePoint startOfTracking, TimePoint endOfTracking,
|
||||
long delayToLiveInMillis, Simulator simulator, WindStore windStore,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry) {
|
||||
return getUpdateReceivers(trackedRegatta, tractracEvent, windStore, startOfTracking, endOfTracking,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, TrackedRegattaRegistry trackedRegattaRegistry, RaceCommitteeStore raceCommitteeStore) {
|
||||
return getUpdateReceivers(trackedRegatta, tractracEvent, windStore, raceCommitteeStore, startOfTracking, endOfTracking,
|
||||
delayToLiveInMillis, simulator, raceDefinitionSetToUpdate, trackedRegattaRegistry,
|
||||
ReceiverType.RACECOURSE, ReceiverType.MARKPASSINGS, ReceiverType.MARKPOSITIONS,
|
||||
ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS);
|
||||
@@ -447,7 +448,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
@Override
|
||||
public DynamicTrackedRace getOrCreateRaceDefinitionAndTrackedRace(TrackedRegatta trackedRegatta,
|
||||
Race race, Course course, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, RaceCommitteeStore raceCommitteeStore) {
|
||||
synchronized (raceCache) {
|
||||
RaceDefinition raceDefinition = raceCache.get(race);
|
||||
if (raceDefinition == null) {
|
||||
@@ -459,7 +460,7 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
if (raceDefinition.getBoatClass() == trackedRegatta.getRegatta().getBoatClass()) {
|
||||
trackedRegatta.getRegatta().addRace(raceDefinition);
|
||||
DynamicTrackedRace trackedRace = createTrackedRace(trackedRegatta, raceDefinition, windStore,
|
||||
delayToLiveInMillis, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate);
|
||||
delayToLiveInMillis, millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate, raceCommitteeStore);
|
||||
logger.info("Added race "+raceDefinition+" to regatta "+trackedRegatta.getRegatta());
|
||||
synchronized (raceCache) {
|
||||
raceCache.put(race, raceDefinition);
|
||||
@@ -479,11 +480,12 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
}
|
||||
|
||||
private DynamicTrackedRace createTrackedRace(TrackedRegatta trackedRegatta, RaceDefinition race, WindStore windStore,
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, DynamicRaceDefinitionSet raceDefinitionSetToUpdate,
|
||||
RaceCommitteeStore raceCommitteeStore) {
|
||||
return trackedRegatta.createTrackedRace(race,
|
||||
windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
|
||||
/* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
|
||||
raceDefinitionSetToUpdate);
|
||||
raceDefinitionSetToUpdate, raceCommitteeStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -548,19 +550,20 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
@Override
|
||||
public TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, TimePoint startOfTracking,
|
||||
TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException, FileNotFoundException,
|
||||
TrackedRegattaRegistry trackedRegattaRegistry, RaceCommitteeStore raceCommitteeStore) throws MalformedURLException, FileNotFoundException,
|
||||
URISyntaxException {
|
||||
return new TracTracRaceTrackerImpl(this, paramURL, liveURI, storedURI, startOfTracking, endOfTracking, delayToLiveInMillis,
|
||||
simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
|
||||
simulateWithStartTimeNow, windStore, trackedRegattaRegistry, raceCommitteeStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI,
|
||||
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
boolean simulateWithStartTimeNow, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry)
|
||||
boolean simulateWithStartTimeNow, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
RaceCommitteeStore raceCommitteeStore)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException {
|
||||
return new TracTracRaceTrackerImpl(regatta, this, paramURL, liveURI, storedURI, startOfTracking, endOfTracking, delayToLiveInMillis,
|
||||
simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
|
||||
simulateWithStartTimeNow, windStore, trackedRegattaRegistry, raceCommitteeStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -576,9 +579,9 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
@Override
|
||||
public RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI,
|
||||
URI storedURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
boolean simulateWithStartTimeNow, WindStore windStore) {
|
||||
boolean simulateWithStartTimeNow, WindStore windStore, RaceCommitteeStore raceCommitteeStore) {
|
||||
return new RaceTrackingConnectivityParametersImpl(paramURL, liveURI, storedURI, startOfTracking, endOfTracking,
|
||||
delayToLiveInMillis, simulateWithStartTimeNow, windStore, this);
|
||||
delayToLiveInMillis, simulateWithStartTimeNow, windStore, this, raceCommitteeStore);
|
||||
}
|
||||
|
||||
}
|
||||
+6
-3
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.base.Course;
|
||||
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.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
@@ -39,12 +40,13 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<Route, RouteDa
|
||||
private final long millisecondsOverWhichToAverageWind;
|
||||
private final long delayToLiveInMillis;
|
||||
private final WindStore windStore;
|
||||
private final RaceCommitteeStore raceCommitteeStore;
|
||||
private final DynamicRaceDefinitionSet raceDefinitionSetToUpdate;
|
||||
|
||||
public RaceCourseReceiver(DomainFactory domainFactory, DynamicTrackedRegatta trackedRegatta,
|
||||
com.tractrac.clientmodule.Event tractracEvent, WindStore windStore,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, long delayToLiveInMillis,
|
||||
long millisecondsOverWhichToAverageWind, Simulator simulator) {
|
||||
long millisecondsOverWhichToAverageWind, Simulator simulator, RaceCommitteeStore raceCommitteeStore) {
|
||||
super(domainFactory, tractracEvent, trackedRegatta, simulator);
|
||||
this.millisecondsOverWhichToAverageWind = millisecondsOverWhichToAverageWind;
|
||||
this.delayToLiveInMillis = delayToLiveInMillis;
|
||||
@@ -54,6 +56,7 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<Route, RouteDa
|
||||
this.windStore = simulator.simulatingWindStore(windStore);
|
||||
}
|
||||
this.raceDefinitionSetToUpdate = raceDefinitionSetToUpdate;
|
||||
this.raceCommitteeStore = raceCommitteeStore;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +104,7 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<Route, RouteDa
|
||||
// create race definition and add to event
|
||||
DynamicTrackedRace trackedRace = getDomainFactory().getOrCreateRaceDefinitionAndTrackedRace(
|
||||
getTrackedRegatta(), event.getC(), course, windStore, delayToLiveInMillis,
|
||||
millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate);
|
||||
millisecondsOverWhichToAverageWind, raceDefinitionSetToUpdate, raceCommitteeStore);
|
||||
if (getSimulator() != null) {
|
||||
getSimulator().setTrackedRace(trackedRace);
|
||||
}
|
||||
@@ -112,7 +115,7 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue<Route, RouteDa
|
||||
getTrackedRegatta().createTrackedRace(race,
|
||||
windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
|
||||
/* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(),
|
||||
raceDefinitionSetToUpdate);
|
||||
raceDefinitionSetToUpdate, raceCommitteeStore);
|
||||
}
|
||||
|
||||
}
|
||||
+6
-3
@@ -9,6 +9,7 @@ import java.net.URL;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
|
||||
@@ -22,13 +23,14 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
|
||||
private final TimePoint startOfTracking;
|
||||
private final TimePoint endOfTracking;
|
||||
private final WindStore windStore;
|
||||
private final RaceCommitteeStore raceCommitteeStore;
|
||||
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, boolean simulateWithStartTimeNow, WindStore windStore,
|
||||
DomainFactory domainFactory) {
|
||||
DomainFactory domainFactory, RaceCommitteeStore raceCommitteeStore) {
|
||||
super();
|
||||
this.paramURL = paramURL;
|
||||
this.liveURI = liveURI;
|
||||
@@ -37,6 +39,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
|
||||
this.endOfTracking = endOfTracking;
|
||||
this.delayToLiveInMillis = delayToLiveInMillis;
|
||||
this.windStore = windStore;
|
||||
this.raceCommitteeStore = raceCommitteeStore;
|
||||
this.domainFactory = domainFactory;
|
||||
this.simulateWithStartTimeNow = simulateWithStartTimeNow;
|
||||
}
|
||||
@@ -45,7 +48,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
|
||||
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry) throws MalformedURLException,
|
||||
FileNotFoundException, URISyntaxException {
|
||||
RaceTracker tracker = domainFactory.createRaceTracker(paramURL, liveURI, storedURI, startOfTracking,
|
||||
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
|
||||
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry, raceCommitteeStore);
|
||||
return tracker;
|
||||
}
|
||||
|
||||
@@ -53,7 +56,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, simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
|
||||
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry, raceCommitteeStore);
|
||||
return tracker;
|
||||
}
|
||||
|
||||
|
||||
+13
-10
@@ -33,6 +33,7 @@ import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.AbstractRaceTrackerImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
@@ -118,18 +119,19 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
*/
|
||||
protected TracTracRaceTrackerImpl(DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI,
|
||||
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
|
||||
boolean simulateWithStartTimeNow, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry)
|
||||
boolean simulateWithStartTimeNow, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
RaceCommitteeStore raceCommitteeStore)
|
||||
throws URISyntaxException, MalformedURLException, FileNotFoundException {
|
||||
this(KeyValue.setup(paramURL), domainFactory, paramURL, liveURI, storedURI, startOfTracking, endOfTracking,
|
||||
delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
|
||||
delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry, raceCommitteeStore);
|
||||
}
|
||||
|
||||
private TracTracRaceTrackerImpl(Event tractracEvent, DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI,
|
||||
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow,
|
||||
WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException,
|
||||
FileNotFoundException {
|
||||
WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry, RaceCommitteeStore raceCommitteeStore)
|
||||
throws URISyntaxException, MalformedURLException, FileNotFoundException {
|
||||
this(tractracEvent, null, domainFactory, paramURL, liveURI, storedURI,
|
||||
startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
|
||||
startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry, raceCommitteeStore);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,10 +142,10 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
*/
|
||||
protected TracTracRaceTrackerImpl(Regatta regatta, DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI,
|
||||
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow,
|
||||
WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry) throws URISyntaxException, MalformedURLException,
|
||||
FileNotFoundException {
|
||||
WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry, RaceCommitteeStore raceCommitteeStore)
|
||||
throws URISyntaxException, MalformedURLException, FileNotFoundException {
|
||||
this(KeyValue.setup(paramURL), regatta, domainFactory, paramURL, liveURI, storedURI, startOfTracking,
|
||||
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry);
|
||||
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, trackedRegattaRegistry, raceCommitteeStore);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,7 +161,8 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
*/
|
||||
private TracTracRaceTrackerImpl(Event tractracEvent, final Regatta regatta, DomainFactory domainFactory,
|
||||
URL paramURL, URI liveURI, URI storedURI, TimePoint startOfTracking, TimePoint endOfTracking,
|
||||
long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry)
|
||||
long delayToLiveInMillis, boolean simulateWithStartTimeNow, WindStore windStore, TrackedRegattaRegistry trackedRegattaRegistry,
|
||||
RaceCommitteeStore raceCommitteeStore)
|
||||
throws URISyntaxException, MalformedURLException, FileNotFoundException {
|
||||
super();
|
||||
this.tractracEvent = tractracEvent;
|
||||
@@ -204,7 +207,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, simulator, windStore, this, trackedRegattaRegistry)) {
|
||||
endOfTracking, delayToLiveInMillis, simulator, windStore, this, trackedRegattaRegistry, raceCommitteeStore)) {
|
||||
receivers.add(receiver);
|
||||
for (TypeController typeController : receiver.getTypeControllersAndStart()) {
|
||||
typeControllers.add(typeController);
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.tracking;
|
||||
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
|
||||
public interface DynamicTrackedRegatta extends TrackedRegatta {
|
||||
|
||||
@@ -19,6 +20,6 @@ public interface DynamicTrackedRegatta extends TrackedRegatta {
|
||||
*/
|
||||
DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, WindStore windStore,
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate);
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, RaceCommitteeStore raceCommitteeStore);
|
||||
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
|
||||
/**
|
||||
* Manages a set of {@link TrackedRace} objects that belong to the same {@link Regatta} (regatta, sailing regatta for a
|
||||
@@ -41,7 +42,7 @@ public interface TrackedRegatta extends Serializable {
|
||||
*/
|
||||
DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, WindStore windStore,
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate);
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, RaceCommitteeStore raceCommitteeStore);
|
||||
|
||||
/**
|
||||
* Obtains the tracked race for <code>race</code>. Blocks until the tracked race has been created
|
||||
|
||||
+5
-4
@@ -26,6 +26,7 @@ import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeEvent;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
@@ -56,9 +57,9 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
|
||||
|
||||
public DynamicTrackedRaceImpl(TrackedRegatta trackedRegatta, RaceDefinition race,
|
||||
WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
long delayForCacheInvalidationOfWindEstimation) {
|
||||
long delayForCacheInvalidationOfWindEstimation, RaceCommitteeStore raceCommitteeStore) {
|
||||
super(trackedRegatta, race, windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
|
||||
delayForCacheInvalidationOfWindEstimation);
|
||||
delayForCacheInvalidationOfWindEstimation, raceCommitteeStore);
|
||||
this.raceIsKnownToStartUpwind = race.getBoatClass().typicallyStartsUpwind();
|
||||
if (!raceIsKnownToStartUpwind) {
|
||||
Set<WindSource> windSourcesToExclude = new HashSet<WindSource>();
|
||||
@@ -94,9 +95,9 @@ public class DynamicTrackedRaceImpl extends TrackedRaceImpl implements
|
||||
*/
|
||||
public DynamicTrackedRaceImpl(TrackedRegatta trackedRegatta, RaceDefinition race,
|
||||
WindStore windStore, long delayToLiveInMillis,
|
||||
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed) {
|
||||
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, RaceCommitteeStore raceCommitteeStore) {
|
||||
this(trackedRegatta, race, windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
|
||||
millisecondsOverWhichToAverageWind/2);
|
||||
millisecondsOverWhichToAverageWind/2, raceCommitteeStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
@@ -27,9 +28,9 @@ public class DynamicTrackedRegattaImpl extends TrackedRegattaImpl implements Dyn
|
||||
@Override
|
||||
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, WindStore windStore,
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, RaceCommitteeStore raceCommitteeStore) {
|
||||
DynamicTrackedRace result = (DynamicTrackedRace) super.createTrackedRace(raceDefinition, windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind,
|
||||
millisecondsOverWhichToAverageSpeed, raceDefinitionSetToUpdate);
|
||||
millisecondsOverWhichToAverageSpeed, raceDefinitionSetToUpdate, raceCommitteeStore);
|
||||
addTrackedRace(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
+2
-2
@@ -256,7 +256,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
|
||||
public TrackedRaceImpl(final TrackedRegatta trackedRegatta, RaceDefinition race, final WindStore windStore,
|
||||
long delayToLiveInMillis, final long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
long delayForWindEstimationCacheInvalidation/*, final RaceCommitteeStore raceCommitteeStore*/) {
|
||||
long delayForWindEstimationCacheInvalidation, final RaceCommitteeStore raceCommitteeStore) {
|
||||
super();
|
||||
locksForMarkPassings = new IdentityHashMap<Iterable<MarkPassing>, NamedReentrantReadWriteLock>();
|
||||
this.serializationLock = new NamedReentrantReadWriteLock("Serialization lock for tracked race "+race.getName(), /* fair */ true);
|
||||
@@ -264,7 +264,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
this.updateCount = 0;
|
||||
this.race = race;
|
||||
this.windStore = windStore;
|
||||
//this.raceCommitteeStore = raceCommitteeStore;
|
||||
this.raceCommitteeStore = raceCommitteeStore;
|
||||
this.windSourcesToExclude = new HashSet<WindSource>();
|
||||
this.directionFromStartToNextMarkCache = new HashMap<TimePoint, Future<Wind>>();
|
||||
this.millisecondsOverWhichToAverageSpeed = millisecondsOverWhichToAverageSpeed;
|
||||
|
||||
+3
-2
@@ -18,6 +18,7 @@ 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.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.RaceListener;
|
||||
@@ -169,10 +170,10 @@ public class TrackedRegattaImpl implements TrackedRegatta {
|
||||
@Override
|
||||
public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, WindStore windStore, long delayToLiveInMillis,
|
||||
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate) {
|
||||
DynamicRaceDefinitionSet raceDefinitionSetToUpdate, RaceCommitteeStore raceCommitteeStore) {
|
||||
logger.log(Level.INFO, "Creating DynamicTrackedRaceImpl for RaceDefinition " + raceDefinition.getName());
|
||||
DynamicTrackedRaceImpl result = new DynamicTrackedRaceImpl(this, raceDefinition,
|
||||
windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed);
|
||||
windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, raceCommitteeStore);
|
||||
if (raceDefinitionSetToUpdate != null) {
|
||||
raceDefinitionSetToUpdate.addRaceDefinition(raceDefinition);
|
||||
}
|
||||
|
||||
+5
-2
@@ -100,6 +100,7 @@ import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoRaceCommitteeStoreFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeEvent;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingArchiveConfiguration;
|
||||
@@ -1110,7 +1111,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
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, simulateWithStartTimeNow);
|
||||
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, simulateWithStartTimeNow,
|
||||
MongoRaceCommitteeStoreFactory.INSTANCE.getMongoRaceCommitteeStore(mongoObjectFactory, domainObjectFactory));
|
||||
if (trackWind) {
|
||||
new Thread("Wind tracking starter for race "+rr.regattaName+"/"+rr.name) {
|
||||
public void run() {
|
||||
@@ -2336,7 +2338,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
final RacesHandle raceHandle = getService().addSwissTimingRace(regattaToAddTo, rr.ID, hostname, port,
|
||||
canSendRequests,
|
||||
MongoWindStoreFactory.INSTANCE.getMongoWindStore(mongoObjectFactory, domainObjectFactory),
|
||||
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS);
|
||||
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS,
|
||||
MongoRaceCommitteeStoreFactory.INSTANCE.getMongoRaceCommitteeStore(mongoObjectFactory, domainObjectFactory));
|
||||
if (trackWind) {
|
||||
new Thread("Wind tracking starter for race "+rr.ID+"/"+rr.description) {
|
||||
public void run() {
|
||||
|
||||
+4
-2
@@ -27,6 +27,7 @@ import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.test.AbstractTracTracLiveTest;
|
||||
import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
@@ -73,7 +74,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 */
|
||||
EmptyWindStore.INSTANCE, EmptyRaceCommitteeStore.INSTANCE,
|
||||
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */
|
||||
0l, /* simulator */ null, new DynamicRaceDefinitionSet() {
|
||||
@Override
|
||||
public void addRaceDefinition(RaceDefinition race) {
|
||||
@@ -86,7 +88,7 @@ public class TestStoringAndRetrievingWindTracksTest extends AbstractTracTracLive
|
||||
@Override
|
||||
public void addRaceDefinition(RaceDefinition race) {
|
||||
}
|
||||
});
|
||||
}, EmptyRaceCommitteeStore.INSTANCE);
|
||||
WindSource windSource = new WindSourceImpl(WindSourceType.WEB);
|
||||
Mongo myFirstMongo = newMongo();
|
||||
DB firstDatabase = myFirstMongo.getDB(dbConfiguration.getDatabaseName());
|
||||
|
||||
+29
-6
@@ -38,7 +38,10 @@ import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.persistence.MongoFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoRaceCommitteeStoreFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
@@ -115,9 +118,11 @@ public class AdminApp extends SailingServerHttpServlet {
|
||||
|
||||
private static final String PARAM_NAME_WINDSTORE = "windstore";
|
||||
|
||||
private static final String WIND_STORE_EMPTY = "empty";
|
||||
private static final String STORE_EMPTY = "empty";
|
||||
|
||||
private static final String WIND_STORE_MONGO = "mongo";
|
||||
private static final String STORE_MONGO = "mongo";
|
||||
|
||||
private static final String PARAM_NAME_RACECOMMITTEESTORE = "racecommitteestore";
|
||||
|
||||
public AdminApp() {
|
||||
}
|
||||
@@ -466,15 +471,15 @@ public class AdminApp extends SailingServerHttpServlet {
|
||||
URL jsonURL = new URL(req.getParameter(PARAM_NAME_EVENT_JSON_URL));
|
||||
URI liveURI = new URI(req.getParameter(PARAM_NAME_LIVE_URI));
|
||||
URI storedURI = new URI(req.getParameter(PARAM_NAME_STORED_URI));
|
||||
getService().addRegatta(jsonURL, liveURI, storedURI, getWindStore(req), /* timeoutInMilliseconds */ 60000);
|
||||
getService().addRegatta(jsonURL, liveURI, storedURI, getWindStore(req), /* timeoutInMilliseconds */ 60000, getRaceCommitteeStore(req));
|
||||
}
|
||||
|
||||
private WindStore getWindStore(HttpServletRequest req) throws UnknownHostException, MongoException {
|
||||
String windStore = req.getParameter(PARAM_NAME_WINDSTORE);
|
||||
if (windStore != null) {
|
||||
if (windStore.equals(WIND_STORE_EMPTY)) {
|
||||
if (windStore.equals(STORE_EMPTY)) {
|
||||
return EmptyWindStore.INSTANCE;
|
||||
} else if (windStore.equals(WIND_STORE_MONGO)) {
|
||||
} else if (windStore.equals(STORE_MONGO)) {
|
||||
return MongoWindStoreFactory.INSTANCE.getMongoWindStore(
|
||||
MongoFactory.INSTANCE.getDefaultMongoObjectFactory(),
|
||||
MongoFactory.INSTANCE.getDefaultDomainObjectFactory());
|
||||
@@ -490,7 +495,8 @@ public class AdminApp extends SailingServerHttpServlet {
|
||||
URL paramURL = new URL(req.getParameter(PARAM_NAME_PARAM_URL));
|
||||
URI liveURI = new URI(req.getParameter(PARAM_NAME_LIVE_URI));
|
||||
URI storedURI = new URI(req.getParameter(PARAM_NAME_STORED_URI));
|
||||
getService().addTracTracRace(paramURL, liveURI, storedURI, getWindStore(req), /* timeoutInMilliseconds */ 60000);
|
||||
getService().addTracTracRace(paramURL, liveURI, storedURI, getWindStore(req), /* timeoutInMilliseconds */ 60000,
|
||||
getRaceCommitteeStore(req));
|
||||
}
|
||||
|
||||
private void stopRace(HttpServletRequest req, HttpServletResponse resp) throws MalformedURLException, IOException, InterruptedException {
|
||||
@@ -506,5 +512,22 @@ public class AdminApp extends SailingServerHttpServlet {
|
||||
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Regatta not found");
|
||||
}
|
||||
}
|
||||
|
||||
private RaceCommitteeStore getRaceCommitteeStore(HttpServletRequest req) throws UnknownHostException, MongoException {
|
||||
String raceCommitteStore = req.getParameter(PARAM_NAME_RACECOMMITTEESTORE);
|
||||
if (raceCommitteStore != null) {
|
||||
if (raceCommitteStore.equals(STORE_EMPTY)) {
|
||||
return EmptyRaceCommitteeStore.INSTANCE;
|
||||
} else if (raceCommitteStore.equals(STORE_MONGO)) {
|
||||
return MongoRaceCommitteeStoreFactory.INSTANCE.getMongoRaceCommitteeStore(
|
||||
MongoFactory.INSTANCE.getDefaultMongoObjectFactory(),
|
||||
MongoFactory.INSTANCE.getDefaultDomainObjectFactory());
|
||||
} else {
|
||||
log("Couldn't find race committee store " + raceCommitteStore + ". Using EmptyRaceCommitteeStore instead.");
|
||||
return EmptyRaceCommitteeStore.INSTANCE;
|
||||
}
|
||||
}
|
||||
return EmptyRaceCommitteeStore.INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
+176
-174
@@ -1,174 +1,176 @@
|
||||
package com.sap.sailing.server.replication.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||
import com.sap.sailing.domain.test.AbstractTracTracLiveTest;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.RacesHandle;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.server.OperationExecutionListener;
|
||||
import com.sap.sailing.server.RacingEventServiceOperation;
|
||||
import com.sap.sailing.server.operationaltransformation.AddColumnToLeaderboard;
|
||||
import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn;
|
||||
import com.sap.sailing.server.operationaltransformation.CreateFlexibleLeaderboard;
|
||||
import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
|
||||
|
||||
public class TrackRaceReplicationTest extends AbstractServerReplicationTest {
|
||||
private TrackedRace masterTrackedRace;
|
||||
private RegattaAndRaceIdentifier raceIdentifier;
|
||||
private RacesHandle racesHandle;
|
||||
private final boolean[] notifier = new boolean[1];
|
||||
private RaceTrackingConnectivityParameters trackingParams;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
final String eventID = "event_20110505_SailingTea";
|
||||
final String raceID = "bd8c778e-7c65-11e0-8236-406186cbf87c";
|
||||
URL paramURL = AbstractTracTracLiveTest.getParamURL(eventID, raceID);
|
||||
URI liveURI = AbstractTracTracLiveTest.getLiveURI();
|
||||
URI storedURI = AbstractTracTracLiveTest.getStoredURI();
|
||||
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
||||
cal.set(2011, 05, 23, 13, 14, 31);
|
||||
MillisecondsTimePoint startOfTracking = new MillisecondsTimePoint(cal.getTimeInMillis());
|
||||
cal.set(2011, 05, 23, 15, 14, 31);
|
||||
MillisecondsTimePoint endOfTracking = new MillisecondsTimePoint(cal.getTimeInMillis());
|
||||
master.addOperationExecutionListener(new OperationExecutionListener() {
|
||||
@Override
|
||||
public <T> void executed(RacingEventServiceOperation<T> operation) {
|
||||
if (operation instanceof CreateTrackedRace) {
|
||||
synchronized (notifier) {
|
||||
notifier[0] = true;
|
||||
notifier.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
trackingParams = com.sap.sailing.domain.tractracadapter.DomainFactory.INSTANCE.createTrackingConnectivityParameters(paramURL,
|
||||
liveURI, storedURI, startOfTracking, endOfTracking, /* delayToLiveInMillis */
|
||||
0l, /* simulateWithStartTimeNow */false, EmptyWindStore.INSTANCE);
|
||||
}
|
||||
|
||||
private void startTracking() throws Exception, InterruptedException {
|
||||
startTrackingOnMaster();
|
||||
waitForTrackRaceReplicationTrigger();
|
||||
raceIdentifier = racesHandle.getRaceTracker().getRaceIdentifiers().iterator().next();
|
||||
masterTrackedRace = master.getTrackedRace(raceIdentifier);
|
||||
}
|
||||
|
||||
private void startTrackingOnMaster() throws Exception {
|
||||
racesHandle = master.addRace(/* regattaToAddTo */ null, trackingParams, EmptyWindStore.INSTANCE, /* timeoutInMilliseconds */ 60000);
|
||||
}
|
||||
|
||||
private void waitForTrackRaceReplicationTrigger() throws InterruptedException {
|
||||
while (!notifier[0]) {
|
||||
synchronized (notifier) {
|
||||
notifier.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartTrackingRaceReplication() throws Exception {
|
||||
startTracking();
|
||||
Thread.sleep(1000);
|
||||
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
|
||||
assertNotNull(replicaTrackedRace);
|
||||
assertNotSame(masterTrackedRace, replicaTrackedRace);
|
||||
assertNotSame(masterTrackedRace.getRace(), replicaTrackedRace.getRace());
|
||||
assertEquals(Util.size(masterTrackedRace.getRace().getCompetitors()), Util.size(replicaTrackedRace.getRace().getCompetitors()));
|
||||
Leaderboard replicaDefaultLeaderboard = replica.getLeaderboardByName(LeaderboardNameConstants.DEFAULT_LEADERBOARD_NAME);
|
||||
RaceColumn column = replicaDefaultLeaderboard.getRaceColumnByName(replicaTrackedRace.getRace().getName());
|
||||
assertNotNull(column);
|
||||
assertSame(replicaTrackedRace, column.getTrackedRace(replicaDefaultLeaderboard.getFleet(null)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReassignmentToLeaderboardReplication() throws Exception {
|
||||
final String leaderboardName = "Test Leaderboard";
|
||||
Leaderboard masterLeaderboard = master.apply(new CreateFlexibleLeaderboard(leaderboardName, new int[0], new LowPoint()));
|
||||
final String columnName = "R1";
|
||||
RaceColumn masterColumn = master.apply(new AddColumnToLeaderboard(columnName, leaderboardName, /* medalRace */ false));
|
||||
final Fleet defaultFleet = masterLeaderboard.getFleet(null);
|
||||
master.apply(new ConnectTrackedRaceToLeaderboardColumn(leaderboardName, columnName, defaultFleet.getName(),
|
||||
new RegattaNameAndRaceName("Academy Tracking 2011 (STG)", "weym470may122011")));
|
||||
startTracking();
|
||||
assertNotNull(masterColumn.getTrackedRace(defaultFleet)); // ensure the re-assignment worked on the master
|
||||
Thread.sleep(1000);
|
||||
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
|
||||
assertNotNull(replicaTrackedRace);
|
||||
assertNotSame(masterTrackedRace, replicaTrackedRace);
|
||||
assertNotSame(masterTrackedRace.getRace(), replicaTrackedRace.getRace());
|
||||
assertEquals(Util.size(masterTrackedRace.getRace().getCompetitors()), Util.size(replicaTrackedRace.getRace().getCompetitors()));
|
||||
Leaderboard replicaLeaderboard = replica.getLeaderboardByName(leaderboardName);
|
||||
assertNotNull(replicaLeaderboard);
|
||||
RaceColumn column = replicaLeaderboard.getRaceColumnByName(columnName);
|
||||
assertNotNull(column);
|
||||
assertSame(replicaTrackedRace, column.getTrackedRace(defaultFleet));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRaceTimeReplication() throws InterruptedException, Exception {
|
||||
startTracking();
|
||||
Thread.sleep(1000);
|
||||
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
|
||||
assertEquals(masterTrackedRace.getStartOfTracking(), replicaTrackedRace.getStartOfTracking());
|
||||
assertEquals(masterTrackedRace.getEndOfTracking(), replicaTrackedRace.getEndOfTracking());
|
||||
MillisecondsTimePoint now = MillisecondsTimePoint.now();
|
||||
assertFalse(now.equals(replicaTrackedRace.getStartOfRace()));
|
||||
((DynamicTrackedRace) masterTrackedRace).setStartTimeReceived(now);
|
||||
Thread.sleep(3000);
|
||||
assertEquals(now, replicaTrackedRace.getStartOfRace());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindSourcesToExcludeReplication() throws InterruptedException, Exception {
|
||||
startTracking();
|
||||
Thread.sleep(1000);
|
||||
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
|
||||
assertTrue(Util.isEmpty(masterTrackedRace.getWindSourcesToExclude()));
|
||||
assertTrue(Util.isEmpty(replicaTrackedRace.getWindSourcesToExclude()));
|
||||
masterTrackedRace.setWindSourcesToExclude(Collections.singleton(new WindSourceImpl(WindSourceType.WEB)));
|
||||
assertEquals(1, Util.size(masterTrackedRace.getWindSourcesToExclude()));
|
||||
assertEquals(WindSourceType.WEB, masterTrackedRace.getWindSourcesToExclude().iterator().next().getType());
|
||||
Thread.sleep(1000);
|
||||
assertEquals(1, Util.size(replicaTrackedRace.getWindSourcesToExclude()));
|
||||
assertEquals(WindSourceType.WEB, replicaTrackedRace.getWindSourcesToExclude().iterator().next().getType());
|
||||
}
|
||||
|
||||
@After
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
racesHandle.getRaceTracker().stop();
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.server.replication.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.test.AbstractTracTracLiveTest;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.RacesHandle;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.server.OperationExecutionListener;
|
||||
import com.sap.sailing.server.RacingEventServiceOperation;
|
||||
import com.sap.sailing.server.operationaltransformation.AddColumnToLeaderboard;
|
||||
import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn;
|
||||
import com.sap.sailing.server.operationaltransformation.CreateFlexibleLeaderboard;
|
||||
import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
|
||||
|
||||
public class TrackRaceReplicationTest extends AbstractServerReplicationTest {
|
||||
private TrackedRace masterTrackedRace;
|
||||
private RegattaAndRaceIdentifier raceIdentifier;
|
||||
private RacesHandle racesHandle;
|
||||
private final boolean[] notifier = new boolean[1];
|
||||
private RaceTrackingConnectivityParameters trackingParams;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
final String eventID = "event_20110505_SailingTea";
|
||||
final String raceID = "bd8c778e-7c65-11e0-8236-406186cbf87c";
|
||||
URL paramURL = AbstractTracTracLiveTest.getParamURL(eventID, raceID);
|
||||
URI liveURI = AbstractTracTracLiveTest.getLiveURI();
|
||||
URI storedURI = AbstractTracTracLiveTest.getStoredURI();
|
||||
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
||||
cal.set(2011, 05, 23, 13, 14, 31);
|
||||
MillisecondsTimePoint startOfTracking = new MillisecondsTimePoint(cal.getTimeInMillis());
|
||||
cal.set(2011, 05, 23, 15, 14, 31);
|
||||
MillisecondsTimePoint endOfTracking = new MillisecondsTimePoint(cal.getTimeInMillis());
|
||||
master.addOperationExecutionListener(new OperationExecutionListener() {
|
||||
@Override
|
||||
public <T> void executed(RacingEventServiceOperation<T> operation) {
|
||||
if (operation instanceof CreateTrackedRace) {
|
||||
synchronized (notifier) {
|
||||
notifier[0] = true;
|
||||
notifier.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
trackingParams = com.sap.sailing.domain.tractracadapter.DomainFactory.INSTANCE.createTrackingConnectivityParameters(paramURL,
|
||||
liveURI, storedURI, startOfTracking, endOfTracking, /* delayToLiveInMillis */
|
||||
0l, /* simulateWithStartTimeNow */false, EmptyWindStore.INSTANCE, EmptyRaceCommitteeStore.INSTANCE);
|
||||
}
|
||||
|
||||
private void startTracking() throws Exception, InterruptedException {
|
||||
startTrackingOnMaster();
|
||||
waitForTrackRaceReplicationTrigger();
|
||||
raceIdentifier = racesHandle.getRaceTracker().getRaceIdentifiers().iterator().next();
|
||||
masterTrackedRace = master.getTrackedRace(raceIdentifier);
|
||||
}
|
||||
|
||||
private void startTrackingOnMaster() throws Exception {
|
||||
racesHandle = master.addRace(/* regattaToAddTo */ null, trackingParams, EmptyWindStore.INSTANCE, /* timeoutInMilliseconds */ 60000,
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
}
|
||||
|
||||
private void waitForTrackRaceReplicationTrigger() throws InterruptedException {
|
||||
while (!notifier[0]) {
|
||||
synchronized (notifier) {
|
||||
notifier.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartTrackingRaceReplication() throws Exception {
|
||||
startTracking();
|
||||
Thread.sleep(1000);
|
||||
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
|
||||
assertNotNull(replicaTrackedRace);
|
||||
assertNotSame(masterTrackedRace, replicaTrackedRace);
|
||||
assertNotSame(masterTrackedRace.getRace(), replicaTrackedRace.getRace());
|
||||
assertEquals(Util.size(masterTrackedRace.getRace().getCompetitors()), Util.size(replicaTrackedRace.getRace().getCompetitors()));
|
||||
Leaderboard replicaDefaultLeaderboard = replica.getLeaderboardByName(LeaderboardNameConstants.DEFAULT_LEADERBOARD_NAME);
|
||||
RaceColumn column = replicaDefaultLeaderboard.getRaceColumnByName(replicaTrackedRace.getRace().getName());
|
||||
assertNotNull(column);
|
||||
assertSame(replicaTrackedRace, column.getTrackedRace(replicaDefaultLeaderboard.getFleet(null)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReassignmentToLeaderboardReplication() throws Exception {
|
||||
final String leaderboardName = "Test Leaderboard";
|
||||
Leaderboard masterLeaderboard = master.apply(new CreateFlexibleLeaderboard(leaderboardName, new int[0], new LowPoint()));
|
||||
final String columnName = "R1";
|
||||
RaceColumn masterColumn = master.apply(new AddColumnToLeaderboard(columnName, leaderboardName, /* medalRace */ false));
|
||||
final Fleet defaultFleet = masterLeaderboard.getFleet(null);
|
||||
master.apply(new ConnectTrackedRaceToLeaderboardColumn(leaderboardName, columnName, defaultFleet.getName(),
|
||||
new RegattaNameAndRaceName("Academy Tracking 2011 (STG)", "weym470may122011")));
|
||||
startTracking();
|
||||
assertNotNull(masterColumn.getTrackedRace(defaultFleet)); // ensure the re-assignment worked on the master
|
||||
Thread.sleep(1000);
|
||||
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
|
||||
assertNotNull(replicaTrackedRace);
|
||||
assertNotSame(masterTrackedRace, replicaTrackedRace);
|
||||
assertNotSame(masterTrackedRace.getRace(), replicaTrackedRace.getRace());
|
||||
assertEquals(Util.size(masterTrackedRace.getRace().getCompetitors()), Util.size(replicaTrackedRace.getRace().getCompetitors()));
|
||||
Leaderboard replicaLeaderboard = replica.getLeaderboardByName(leaderboardName);
|
||||
assertNotNull(replicaLeaderboard);
|
||||
RaceColumn column = replicaLeaderboard.getRaceColumnByName(columnName);
|
||||
assertNotNull(column);
|
||||
assertSame(replicaTrackedRace, column.getTrackedRace(defaultFleet));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRaceTimeReplication() throws InterruptedException, Exception {
|
||||
startTracking();
|
||||
Thread.sleep(1000);
|
||||
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
|
||||
assertEquals(masterTrackedRace.getStartOfTracking(), replicaTrackedRace.getStartOfTracking());
|
||||
assertEquals(masterTrackedRace.getEndOfTracking(), replicaTrackedRace.getEndOfTracking());
|
||||
MillisecondsTimePoint now = MillisecondsTimePoint.now();
|
||||
assertFalse(now.equals(replicaTrackedRace.getStartOfRace()));
|
||||
((DynamicTrackedRace) masterTrackedRace).setStartTimeReceived(now);
|
||||
Thread.sleep(3000);
|
||||
assertEquals(now, replicaTrackedRace.getStartOfRace());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWindSourcesToExcludeReplication() throws InterruptedException, Exception {
|
||||
startTracking();
|
||||
Thread.sleep(1000);
|
||||
TrackedRace replicaTrackedRace = replica.getTrackedRace(raceIdentifier);
|
||||
assertTrue(Util.isEmpty(masterTrackedRace.getWindSourcesToExclude()));
|
||||
assertTrue(Util.isEmpty(replicaTrackedRace.getWindSourcesToExclude()));
|
||||
masterTrackedRace.setWindSourcesToExclude(Collections.singleton(new WindSourceImpl(WindSourceType.WEB)));
|
||||
assertEquals(1, Util.size(masterTrackedRace.getWindSourcesToExclude()));
|
||||
assertEquals(WindSourceType.WEB, masterTrackedRace.getWindSourcesToExclude().iterator().next().getType());
|
||||
Thread.sleep(1000);
|
||||
assertEquals(1, Util.size(replicaTrackedRace.getWindSourcesToExclude()));
|
||||
assertEquals(WindSourceType.WEB, replicaTrackedRace.getWindSourcesToExclude().iterator().next().getType());
|
||||
}
|
||||
|
||||
@After
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
racesHandle.getRaceTracker().stop();
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -37,6 +37,7 @@ import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.persistence.MongoFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoRaceCommitteeStoreFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoWindStore;
|
||||
import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
|
||||
@@ -89,7 +90,9 @@ public class TrackedRaceContentsReplicationTest extends AbstractServerReplicatio
|
||||
trackedRace = (DynamicTrackedRace) master.apply(new CreateTrackedRace(raceIdentifier,
|
||||
MongoWindStoreFactory.INSTANCE.getMongoWindStore(MongoFactory.INSTANCE.getDefaultMongoObjectFactory(),
|
||||
MongoFactory.INSTANCE.getDefaultDomainObjectFactory()), /* delayToLiveInMillis */ 5000,
|
||||
/* millisecondsOverWhichToAverageWind */ 10000, /* millisecondsOverWhichToAverageSpeed */10000));
|
||||
/* millisecondsOverWhichToAverageWind */ 10000, /* millisecondsOverWhichToAverageSpeed */10000,
|
||||
MongoRaceCommitteeStoreFactory.INSTANCE.getMongoRaceCommitteeStore(MongoFactory.INSTANCE.getDefaultMongoObjectFactory(),
|
||||
MongoFactory.INSTANCE.getDefaultDomainObjectFactory())));
|
||||
trackedRace.waitUntilWindLoadingComplete();
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -28,6 +28,7 @@ import com.sap.sailing.domain.base.impl.CourseImpl;
|
||||
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
@@ -70,13 +71,13 @@ public class RaceTrackerStartStopTest {
|
||||
raceDef3 = new RaceDefinitionImpl(RACENAME3, new CourseImpl("Course3", new ArrayList<Waypoint>()), boatClass, new ArrayList<Competitor>());
|
||||
regatta.addRace(raceDef1);
|
||||
trackedRegatta1.createTrackedRace(raceDef1, /* windStore */ EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l,
|
||||
/* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null);
|
||||
/* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, EmptyRaceCommitteeStore.INSTANCE);
|
||||
regatta.addRace(raceDef2);
|
||||
trackedRegatta1.createTrackedRace(raceDef2, /* windStore */ EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l,
|
||||
/* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null);
|
||||
/* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, EmptyRaceCommitteeStore.INSTANCE);
|
||||
regatta.addRace(raceDef3);
|
||||
trackedRegatta1.createTrackedRace(raceDef3, /* windStore */ EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l,
|
||||
/* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null);
|
||||
/* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, EmptyRaceCommitteeStore.INSTANCE);
|
||||
Set<RaceDefinition> raceDefinitionSetRace1 = new HashSet<RaceDefinition>();
|
||||
raceDefinitionSetRace1.add(raceDef1);
|
||||
Set<RaceDefinition> raceDefinitionSetRace2 = new HashSet<RaceDefinition>();
|
||||
|
||||
+7
-3
@@ -20,6 +20,7 @@ import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.RaceListener;
|
||||
import com.sap.sailing.domain.tracking.RacesHandle;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
@@ -60,7 +61,8 @@ public class RaceTrackerTest {
|
||||
public void setUp() throws Exception {
|
||||
service = new RacingEventServiceImpl();
|
||||
logger.info("Calling service.addTracTracRace");
|
||||
raceHandle = service.addTracTracRace(paramUrl, liveUri, storedUri, EmptyWindStore.INSTANCE, /* timeoutInMilliseconds */ 60000);
|
||||
raceHandle = service.addTracTracRace(paramUrl, liveUri, storedUri, EmptyWindStore.INSTANCE, /* timeoutInMilliseconds */ 60000,
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
logger.info("Calling raceHandle.getRaces()");
|
||||
Set<RaceDefinition> races = raceHandle.getRaces(); // wait for RaceDefinition to be completely wired in Regatta
|
||||
logger.info("Obtained races: "+races);
|
||||
@@ -116,7 +118,8 @@ public class RaceTrackerTest {
|
||||
RaceDefinition oldRaceDefinition = oldTrackedRace.getRace();
|
||||
assertTrue(!Util.isEmpty(raceHandle.getRegatta().getAllRaces()));
|
||||
service.removeRegatta(raceHandle.getRegatta());
|
||||
RacesHandle myRaceHandle = service.addTracTracRace(paramUrl, liveUri, storedUri, EmptyWindStore.INSTANCE, /* timeoutInMilliseconds */ 60000);
|
||||
RacesHandle myRaceHandle = service.addTracTracRace(paramUrl, liveUri, storedUri, EmptyWindStore.INSTANCE, /* timeoutInMilliseconds */ 60000,
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
TrackedRegatta newTrackedRegatta = myRaceHandle.getTrackedRegatta();
|
||||
assertNotSame(oldTrackedRegatta, newTrackedRegatta);
|
||||
TrackedRace newTrackedRace = getTrackedRace(newTrackedRegatta);
|
||||
@@ -140,7 +143,8 @@ public class RaceTrackerTest {
|
||||
logger.entering(getClass().getName(), "testTrackingSameRaceWithoutStopping");
|
||||
TrackedRegatta oldTrackedRegatta = raceHandle.getTrackedRegatta();
|
||||
TrackedRace oldTrackedRace = getTrackedRace(oldTrackedRegatta);
|
||||
RacesHandle myRaceHandle = service.addTracTracRace(paramUrl, liveUri, storedUri, EmptyWindStore.INSTANCE, /* timeoutInMilliseconds */ 60000);
|
||||
RacesHandle myRaceHandle = service.addTracTracRace(paramUrl, liveUri, storedUri, EmptyWindStore.INSTANCE, /* timeoutInMilliseconds */ 60000,
|
||||
EmptyRaceCommitteeStore.INSTANCE);
|
||||
TrackedRegatta newTrackedEvent = myRaceHandle.getTrackedRegatta();
|
||||
TrackedRace newTrackedRace = getTrackedRace(newTrackedEvent);
|
||||
// expecting a new tracked race to be created when starting over with tracking
|
||||
|
||||
@@ -1,481 +1,487 @@
|
||||
package com.sap.sailing.server;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.SocketException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.text.ParseException;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.RegattaRegistry;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.common.RaceFetcher;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaFetcher;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaName;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardRegistry;
|
||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
|
||||
import com.sap.sailing.domain.tracking.RaceListener;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.RacesHandle;
|
||||
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;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.RaceRecord;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracRaceTracker;
|
||||
import com.sap.sailing.expeditionconnector.ExpeditionListener;
|
||||
|
||||
/**
|
||||
* An OSGi service that can be used to track boat races using a TracTrac connector that pushes
|
||||
* live GPS boat location, waypoint, coarse and mark passing data.<p>
|
||||
*
|
||||
* If a race/regatta is already being tracked, another {@link #addTracTracRace(URL, URI, URI, WindStore, long)} or
|
||||
* {@link #addRegatta(URL, URI, URI, WindStore, long)} call will have no effect, even if a different
|
||||
* {@link WindStore} is requested.<p>
|
||||
*
|
||||
* When the tracking of a race/regatta is {@link #stopTracking(Regatta, RaceDefinition) stopped}, the next
|
||||
* time it's started to be tracked, a new {@link TrackedRace} at least will be constructed. This also
|
||||
* means that when a {@link TrackedRegatta} exists that still holds other {@link TrackedRace}s, the
|
||||
* no longer tracked {@link TrackedRace} will be removed from the {@link TrackedRegatta}.
|
||||
* corresponding information is removed also from the {@link DomainFactory}'s caches to ensure that
|
||||
* clean, fresh data is received should another tracking request be issued later.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetcher, RegattaRegistry, RaceFetcher, LeaderboardRegistry {
|
||||
@Override
|
||||
Regatta getRegatta(RegattaName regattaName);
|
||||
|
||||
@Override
|
||||
RaceDefinition getRace(RegattaAndRaceIdentifier raceIdentifier);
|
||||
|
||||
TrackedRace getTrackedRace(Regatta regatta, RaceDefinition race);
|
||||
|
||||
TrackedRace getTrackedRace(RegattaAndRaceIdentifier raceIdentifier);
|
||||
|
||||
/**
|
||||
* Obtains an unmodifiable map of the leaderboard configured in this service keyed by their names.
|
||||
*/
|
||||
Map<String, Leaderboard> getLeaderboards();
|
||||
|
||||
/**
|
||||
* @return a leaderboard whose {@link Leaderboard#getName()} method returns the value of the <code>name</code>
|
||||
* parameter, or <code>null</code> if no such leaderboard is known to this service
|
||||
*/
|
||||
Leaderboard getLeaderboardByName(String name);
|
||||
|
||||
/**
|
||||
* Defines the regatta and for each race listed in the JSON document that is not already being tracked by this service
|
||||
* creates a {@link TracTracRaceTracker} that starts tracking the respective race. The {@link RaceDefinition}s obtained this
|
||||
* way are all grouped into the single {@link Regatta} produced for the event listed in the JSON response. Note that
|
||||
* the many race trackers will have their TracTrac <code>Event</code> each, all with the same name, meaning the same
|
||||
* event but being distinct.
|
||||
*
|
||||
* @param jsonURL
|
||||
* URL of a JSON response that contains an "event" object telling the event's name and ID, as well as a
|
||||
* JSON array named "races" which tells ID and replay URL for the race. From those replay URLs the
|
||||
* paramURL for the Java client can be derived.
|
||||
* @param timeoutInMilliseconds
|
||||
* if a race definition is not received for a race of this event within this time, the race tracker for
|
||||
* that race is stopped; use -1 to wait forever
|
||||
*/
|
||||
Regatta addRegatta(URL jsonURL, URI liveURI, URI storedURI, WindStore windStore, long timeoutInMilliseconds)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, IOException, ParseException,
|
||||
org.json.simple.parser.ParseException, Exception;
|
||||
|
||||
/**
|
||||
* If not already tracking the URL/URI/URI combination, adds a single race tracker and starts tracking the race,
|
||||
* using the race's parameter URL which delivers the single configuration text file for that race. While the result
|
||||
* of passing this URL to the TracTrac <code>KeyValue.setup</code> is a TracTrac <code>Event</code>, those events
|
||||
* only manage a single race. In our domain model, we group those races into a single instance of our {@link Regatta}
|
||||
* class.
|
||||
* <p>
|
||||
*
|
||||
* If this is the first race of an event, the {@link Regatta} is created as well. If the {@link RaceDefinition} for
|
||||
* the race already exists, it isn't created again. Also, if a {@link TracTracRaceTracker} for the given race already
|
||||
* exists, it is not added again.
|
||||
* <p>
|
||||
*
|
||||
* Note that when the race identified by <code>paramURL</code>, <code>liveURI</code> and <code>storedURI</code> is
|
||||
* already being tracked, then regardless of the <code>windStore</code> selection the existing tracker will be used
|
||||
* and its race handle will be returned. A log message will indicate a potential wind store mismatch (based on
|
||||
* {@link WindStore#equals(Object)}).
|
||||
*
|
||||
* @param timeoutInMilliseconds
|
||||
* if the race definition is not received for the race within this time, the race tracker for
|
||||
* that race is stopped; use -1 to wait forever
|
||||
*/
|
||||
RacesHandle addTracTracRace(URL paramURL, URI liveURI, URI storedURI, WindStore windStore, long timeoutInMilliseconds)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
|
||||
|
||||
/**
|
||||
* Same as {@link #addTracTracRace(URL, URI, URI, WindStore, long)}, only that start and end of tracking are
|
||||
* specified which may help reducing the amount of stored data (particularly mark positions) that needs to be
|
||||
* loaded.
|
||||
*
|
||||
* @param regattaToAddTo
|
||||
* if <code>null</code>, an existing regatta by the name of the TracTrac event with the boat class name
|
||||
* appended in parentheses will be looked up; if not found, a default regatta with that name will be
|
||||
* 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.
|
||||
*/
|
||||
RacesHandle addTracTracRace(RegattaIdentifier regattaToAddTo, URL paramURL, URI liveURI, URI storedURI,
|
||||
TimePoint trackingStartTime, TimePoint trackingEndTime, WindStore windStore,
|
||||
long timeoutForReceivingRaceDefinitionInMilliseconds, boolean simulateWithStartTimeNow)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
|
||||
|
||||
/**
|
||||
* Stops tracking all races of the regatta specified. This will also stop tracking wind for all races of this regatta.
|
||||
* See {@link #stopTrackingWind(Regatta, RaceDefinition)}. If there were multiple calls to
|
||||
* {@link #addTracTracRace(URL, URI, URI, WindStore, long)} with an equal combination of URLs/URIs, the {@link TracTracRaceTracker}
|
||||
* already tracking the race was re-used. The trackers will be stopped by this call regardless of how many calls
|
||||
* were made that ensured they were tracking.
|
||||
*/
|
||||
void stopTracking(Regatta regatta) throws MalformedURLException, IOException, InterruptedException;
|
||||
|
||||
/**
|
||||
* Removes <code>race</code> and any corresponding {@link #getTrackedRace(Regatta, RaceDefinition) tracked race}
|
||||
* from this service. If it was the last {@link RaceDefinition} in its {@link Regatta} and the regatta
|
||||
* {@link Regatta#isPersistent() is not stored persistently}, the <code>regatta</code> is removed as well and will no
|
||||
* longer be returned by {@link #getAllRegattas()}. The wind tracking is stopped for <code>race</code>.
|
||||
* <p>
|
||||
*
|
||||
* Any {@link RaceTracker} for which <code>race</race> is the last race tracked that is still reachable
|
||||
* from {@link #getAllRegattas()} will be {@link RaceTracker#stop() stopped}.
|
||||
*
|
||||
* The <code>race</code> will be also removed from all leaderboards containing a column that has <code>race</code>'s
|
||||
* {@link #getTrackedRace(Regatta, RaceDefinition) corresponding} {@link TrackedRace} as its
|
||||
* {@link RaceColumn#getTrackedRace(Fleet)}.
|
||||
*
|
||||
* @param regatta
|
||||
* the regatta from which to remove the race
|
||||
* @param race
|
||||
* the race to remove
|
||||
*/
|
||||
void removeRace(Regatta regatta, RaceDefinition race) throws MalformedURLException, IOException,InterruptedException;
|
||||
|
||||
/**
|
||||
* Stops all {@link RaceTracker}s currently tracking <code>race</code>. Note that if the same tracker also may have
|
||||
* been tracking other races. Other races of the same event that are currently tracked will continue to be tracked.
|
||||
* If wind tracking for the race is currently running, it will be stopped (see also
|
||||
* {@link #stopTrackingWind(Regatta, RaceDefinition)}). The <code>race</code> (and the other races tracked by the
|
||||
* same tracker) as well as the corresponding {@link TrackedRace}s will continue to exist, e.g., when asking
|
||||
* {@link #getTrackedRace(Regatta, RaceDefinition)}.
|
||||
*/
|
||||
void stopTracking(Regatta regatta, RaceDefinition race) throws MalformedURLException, IOException, InterruptedException;
|
||||
|
||||
/**
|
||||
* @param port
|
||||
* the UDP port on which to listen for incoming messages from Expedition clients
|
||||
* @param correctByDeclination
|
||||
* An optional service to convert the wind bearings (which the receiver may
|
||||
* believe to be true bearings) from magnetic to true bearings.
|
||||
* @throws SocketException
|
||||
* thrown, e.g., in case there is already another listener on the port requested
|
||||
*/
|
||||
void startTrackingWind(Regatta regatta, RaceDefinition race, boolean correctByDeclination) throws SocketException;
|
||||
|
||||
void stopTrackingWind(Regatta regatta, RaceDefinition race) throws SocketException, IOException;
|
||||
|
||||
/**
|
||||
* The {@link Triple#getC() third component} of the triples returned is a wind tracker-specific
|
||||
* comment where a wind tracker may provide information such as its type name or, if applicable,
|
||||
* connectivity information such as the network port on which it receives wind information.
|
||||
*/
|
||||
Iterable<Triple<Regatta, RaceDefinition, String>> getWindTrackedRaces();
|
||||
|
||||
/**
|
||||
* For the JSON URL of an account / event, lists the paramURLs that can be used for {@link #addTracTracRace(URL, URI, URI, WindStore, long)}
|
||||
* calls to individually start tracking races of this event, rather than tracking <em>all</em> races in the event which
|
||||
* is hardly ever useful. The returned pair's first component is the event name.
|
||||
*/
|
||||
Pair<String, List<RaceRecord>> getTracTracRaceRecords(URL jsonURL) throws IOException, ParseException,
|
||||
org.json.simple.parser.ParseException, URISyntaxException;
|
||||
|
||||
List<com.sap.sailing.domain.swisstimingadapter.RaceRecord> getSwissTimingRaceRecords(String hostname, int port, boolean canSendRequests)
|
||||
throws InterruptedException, UnknownHostException, IOException, ParseException;
|
||||
|
||||
boolean isRaceBeingTracked(RaceDefinition r);
|
||||
|
||||
/**
|
||||
* Creates a new leaderboard with the <code>name</code> specified.
|
||||
* @param discardThresholds
|
||||
* Tells the thresholds from which on a next higher number of worst races will be discarded per
|
||||
* competitor. Example: <code>[3, 6]</code> means that starting from three races the single worst race
|
||||
* will be discarded; starting from six races, the two worst races per competitor are discarded.
|
||||
*
|
||||
* @return the leaderboard created
|
||||
*/
|
||||
FlexibleLeaderboard addFlexibleLeaderboard(String name, int[] discardThresholds, ScoringScheme scoringScheme);
|
||||
|
||||
RegattaLeaderboard addRegattaLeaderboard(RegattaIdentifier regattaIdentifier, int[] discardThresholds);
|
||||
|
||||
void removeLeaderboard(String leaderboardName);
|
||||
|
||||
/**
|
||||
* Renames a leaderboard. If a leaderboard by the name <code>oldName</code> does not exist in {@link #getLeaderboards()},
|
||||
* or if a leaderboard with the name <code>newName</code> already exists, an {@link IllegalArgumentException} is thrown.
|
||||
* If the method completes normally, the rename has been successful, and the leaderboard previously obtained by calling
|
||||
* {@link #getLeaderboardByName(String) getLeaderboardByName(oldName)} can now be obtained by calling
|
||||
* {@link #getLeaderboardByName(String) getLeaderboardByName(newName)}.
|
||||
*/
|
||||
void renameLeaderboard(String oldName, String newName);
|
||||
|
||||
RaceColumn addColumnToLeaderboard(String columnName, String leaderboardName, boolean medalRace);
|
||||
|
||||
void moveLeaderboardColumnUp(String leaderboardName, String columnName);
|
||||
|
||||
void moveLeaderboardColumnDown(String leaderboardName, String columnName);
|
||||
|
||||
void removeLeaderboardColumn(String leaderboardName, String columnName);
|
||||
|
||||
void renameLeaderboardColumn(String leaderboardName, String oldColumnName, String newColumnName);
|
||||
|
||||
/**
|
||||
* @see RaceColumn#setFactor(Double)
|
||||
*/
|
||||
void updateLeaderboardColumnFactor(String leaderboardName, String columnName, Double factor);
|
||||
|
||||
/**
|
||||
* Updates the leaderboard data in the persistent store
|
||||
*/
|
||||
void updateStoredLeaderboard(Leaderboard leaderboard);
|
||||
|
||||
void updateStoredRegatta(Regatta regatta);
|
||||
|
||||
long getDelayToLiveInMillis();
|
||||
|
||||
void setDelayToLiveInMillis(long delayToLiveInMillis);
|
||||
|
||||
/**
|
||||
* @param regattaToAddTo
|
||||
* if <code>null</code>, an existing regatta by the name of the TracTrac event with the boat class name
|
||||
* appended in parentheses will be looked up; if not found, a default regatta with that name will be
|
||||
* 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.
|
||||
*/
|
||||
RacesHandle addSwissTimingRace(RegattaIdentifier regattaToAddTo, String raceID, String hostname, int port,
|
||||
boolean canSendRequests, WindStore windStore, long timeoutInMilliseconds) throws InterruptedException, UnknownHostException,
|
||||
IOException, ParseException, Exception;
|
||||
|
||||
SwissTimingFactory getSwissTimingFactory();
|
||||
|
||||
void storeSwissTimingDummyRace(String racMessage, String stlMesssage, String ccgMessage) throws IllegalArgumentException;
|
||||
|
||||
void stopTrackingAndRemove(Regatta regatta) throws MalformedURLException, IOException, InterruptedException;
|
||||
|
||||
void removeRegatta(Regatta regatta) throws MalformedURLException, IOException, InterruptedException;
|
||||
|
||||
TrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier);
|
||||
|
||||
/**
|
||||
* Obtains an unmodifiable map of the leaderboard groups configured in this service keyed by their names.
|
||||
*/
|
||||
Map<String, LeaderboardGroup> getLeaderboardGroups();
|
||||
|
||||
/**
|
||||
* @param groupName The name of the requested leaderboard group
|
||||
* @return The leaderboard group with the name <code>groupName</code>, or <code>null</code> if theres no such group
|
||||
*/
|
||||
LeaderboardGroup getLeaderboardGroupByName(String groupName);
|
||||
|
||||
/**
|
||||
* Creates a new group with the name <code>groupName</code>, the description <code>desciption</code> and the
|
||||
* leaderboards with the names in <code>leaderboardNames</code> and saves it in the database.
|
||||
*
|
||||
* @param groupName
|
||||
* The name of the new group
|
||||
* @param description
|
||||
* The description of the new group
|
||||
* @param displayGroupsInReverseOrder TODO
|
||||
* @param leaderboardNames
|
||||
* The names of the leaderboards, which should be contained by the new group.<br />
|
||||
* If there isn't a leaderboard with one of these names an {@link IllegalArgumentException} is thrown.
|
||||
* @return The new leaderboard group
|
||||
*/
|
||||
LeaderboardGroup addLeaderboardGroup(String groupName, String description, boolean displayGroupsInReverseOrder,
|
||||
List<String> leaderboardNames, int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType);
|
||||
|
||||
/**
|
||||
* Removes the group with the name <code>groupName</code> from the service and the database.
|
||||
* @param groupName The name of the group which shall be removed.
|
||||
*/
|
||||
void removeLeaderboardGroup(String groupName);
|
||||
|
||||
/**
|
||||
* Renames the group with the name <code>oldName</code> to the <code>newName</code>.<br />
|
||||
* If there's no group with the name <code>oldName</code> or there's already a group with the name
|
||||
* <code>newName</code> a {@link IllegalArgumentException} is thrown.
|
||||
*
|
||||
* @param oldName The old name of the group
|
||||
* @param newName The new name of the group
|
||||
*/
|
||||
void renameLeaderboardGroup(String oldName, String newName);
|
||||
|
||||
/**
|
||||
* Updates the group data in the persistant store.
|
||||
*/
|
||||
void updateStoredLeaderboardGroup(LeaderboardGroup leaderboardGroup);
|
||||
|
||||
void addExpeditionListener(ExpeditionListener listener, boolean validMessagesOnly) throws SocketException;
|
||||
|
||||
void removeExpeditionListener(ExpeditionListener listener);
|
||||
|
||||
/**
|
||||
* @param regattaToAddTo
|
||||
* if <code>null</code> or no regatta by that identifier is found, an existing regatta by the name of the
|
||||
* TracTrac event with the boat class name appended in parentheses will be looked up; if not found, a
|
||||
* default regatta with that name will be 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, and
|
||||
* {@link #setRegattaForRace(Regatta, RaceDefinition)} is called to remember the association
|
||||
* persistently. Otherwise, a default regatta as described above will be created and used.
|
||||
* @param windStore
|
||||
* must not be <code>null</code>, but can, e.g., be an {@link EmptyWindStore}
|
||||
*/
|
||||
RacesHandle addRace(RegattaIdentifier regattaToAddTo, RaceTrackingConnectivityParameters params, WindStore windStore, long timeoutInMilliseconds)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
|
||||
|
||||
TrackedRace createTrackedRace(RegattaAndRaceIdentifier raceIdentifier, WindStore windStore,
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed);
|
||||
|
||||
Regatta getOrCreateRegatta(String regattaName, String boatClassName);
|
||||
|
||||
Regatta createRegatta(String baseName, String boatClassName, Iterable<? extends Series> series, boolean persistent, ScoringScheme scoringScheme);
|
||||
|
||||
/**
|
||||
* Adds <code>raceDefinition</code> to the {@link Regatta} such that it will appear in {@link Regatta#getAllRaces()}
|
||||
* and {@link Regatta#getRaceByName(String)}.
|
||||
*
|
||||
* @param addToRegatta identifier of an regatta that must exist already
|
||||
*/
|
||||
void addRace(RegattaIdentifier addToRegatta, RaceDefinition raceDefinition);
|
||||
|
||||
void updateLeaderboardGroup(String oldName, String newName, String description, List<String> leaderboardNames,
|
||||
int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType);
|
||||
|
||||
/**
|
||||
* Executes an operation whose effects need to be replicated to any replica of this service known and
|
||||
* {@link OperationExecutionListener#executed(RacingEventServiceOperation) notifies} all registered
|
||||
* operation execution listeners about the execution of the operation.
|
||||
*/
|
||||
<T> T apply(RacingEventServiceOperation<T> operation);
|
||||
|
||||
void addOperationExecutionListener(OperationExecutionListener listener);
|
||||
|
||||
void removeOperationExecutionListener(OperationExecutionListener listener);
|
||||
|
||||
/**
|
||||
* Produces a one-shot serializable copy of those elements required for replication into <code>oos</code> so that
|
||||
* afterwards the {@link RacingEventServiceOperation}s can be {@link #apply(RacingEventServiceOperation) applied} to
|
||||
* maintain consistency with the master copy of the service. The dual operation is {@link #initiallyFillFrom}.
|
||||
*/
|
||||
void serializeForInitialReplication(ObjectOutputStream oos) throws IOException;
|
||||
|
||||
/**
|
||||
* Dual, reading operation for {@link #serializeForInitialReplication(ObjectOutputStream)}. In other words, when
|
||||
* this operation returns, this service instance is in a state "equivalent" to that of the service instance that
|
||||
* produced the stream contents in its {@link #serializeForInitialReplication(ObjectOutputStream)}. "Equivalent"
|
||||
* here means that a replica will have equal sets of regattas, tracked regattas, leaderboards and leaderboard groups but
|
||||
* will not have any active trackers for wind or positions because it relies on these elements to be sent through
|
||||
* the replication channel.
|
||||
* <p>
|
||||
*
|
||||
* Tracked regattas read from the stream are observed (see {@link RaceListener}) by this object for automatic updates
|
||||
* to the default leaderboard and for automatic linking to leaderboard columns. It is assumed that no explicit
|
||||
* replication of these operations will happen based on the changes performed on the replication master.<p>
|
||||
*
|
||||
* <b>Caution:</b> All relevant contents of this service instance will be replaced by the stream contents.
|
||||
*/
|
||||
void initiallyFillFrom(ObjectInputStream ois) throws IOException, ClassNotFoundException;
|
||||
|
||||
Event getEventByName(String name);
|
||||
|
||||
/**
|
||||
* @return a thread-safe copy of the events currently known by the service; it's safe for callers to iterate over
|
||||
* the iterable returned, and no risk of a {@link ConcurrentModificationException} exists
|
||||
*/
|
||||
Iterable<Event> getAllEvents();
|
||||
|
||||
/**
|
||||
* Creates a new event with the name <code>eventName</code>, the venue<code>venue</code> and the
|
||||
* regattas with the names in <code>regattaNames</code> and saves it in the database.
|
||||
*
|
||||
* @param eventName
|
||||
* The name of the new event
|
||||
* @param venue
|
||||
* The name of the venue of the new event
|
||||
* @param publicationUrl
|
||||
* The publication URL of the new event
|
||||
* @param isPublic
|
||||
* Indicates whether the event is public accessible via the publication URL or not
|
||||
* @param regattaNames
|
||||
* The names of the regattas contained in the new event.<br />
|
||||
* @return The new event
|
||||
*/
|
||||
Event addEvent(String eventName, String venueName, String publicationUrl, boolean isPublic, List<String> regattaNames);
|
||||
|
||||
/**
|
||||
* Updates a sailing event with the name <code>eventName</code>, the venue<code>venue</code> and the
|
||||
* regattas with the names in <code>regattaNames</code> and updates it in the database.
|
||||
*
|
||||
* @param eventName
|
||||
* The name of the event to update
|
||||
* @param venueName
|
||||
* The name of the venue of the event
|
||||
* @param publicationUrl
|
||||
* The publication URL of the event
|
||||
* @param isPublic
|
||||
* Indicates whether the event is public accessible via the publication URL or not
|
||||
* @param regattaNames
|
||||
* The names of the regattas contained in the event.<br />
|
||||
* @return The new event
|
||||
*/
|
||||
void updateEvent(String eventName, String venueName, String publicationUrl, boolean isPublic, List<String> regattaNames);
|
||||
|
||||
/**
|
||||
* Renames a sailing event. If a sailing event by the name <code>oldName</code> does not exist in {@link #getEvents()},
|
||||
* or if a event with the name <code>newName</code> already exists, an {@link IllegalArgumentException} is thrown.
|
||||
* If the method completes normally, the rename has been successful, and the event previously obtained by calling
|
||||
* {@link #getEventByName(String) getEventByName(oldName)} can now be obtained by calling
|
||||
* {@link #getEventByName(String) getEventByName(newName)}.
|
||||
*/
|
||||
void renameEvent(String oldEventName, String newEventName);
|
||||
|
||||
void removeEvent(String eventName);
|
||||
|
||||
com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory();
|
||||
|
||||
com.sap.sailing.domain.swisstimingadapter.DomainFactory getSwissTimingDomainFactory();
|
||||
|
||||
}
|
||||
package com.sap.sailing.server;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.SocketException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.text.ParseException;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.RegattaRegistry;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.common.RaceFetcher;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaFetcher;
|
||||
import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaName;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardRegistry;
|
||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SwissTimingFactory;
|
||||
import com.sap.sailing.domain.tracking.RaceListener;
|
||||
import com.sap.sailing.domain.tracking.RaceTracker;
|
||||
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
|
||||
import com.sap.sailing.domain.tracking.RacesHandle;
|
||||
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;
|
||||
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
|
||||
import com.sap.sailing.domain.tractracadapter.DomainFactory;
|
||||
import com.sap.sailing.domain.tractracadapter.RaceRecord;
|
||||
import com.sap.sailing.domain.tractracadapter.TracTracRaceTracker;
|
||||
import com.sap.sailing.expeditionconnector.ExpeditionListener;
|
||||
|
||||
/**
|
||||
* An OSGi service that can be used to track boat races using a TracTrac connector that pushes
|
||||
* live GPS boat location, waypoint, coarse and mark passing data.<p>
|
||||
*
|
||||
* If a race/regatta is already being tracked, another {@link #addTracTracRace(URL, URI, URI, WindStore, long)} or
|
||||
* {@link #addRegatta(URL, URI, URI, WindStore, long)} call will have no effect, even if a different
|
||||
* {@link WindStore} is requested.<p>
|
||||
*
|
||||
* When the tracking of a race/regatta is {@link #stopTracking(Regatta, RaceDefinition) stopped}, the next
|
||||
* time it's started to be tracked, a new {@link TrackedRace} at least will be constructed. This also
|
||||
* means that when a {@link TrackedRegatta} exists that still holds other {@link TrackedRace}s, the
|
||||
* no longer tracked {@link TrackedRace} will be removed from the {@link TrackedRegatta}.
|
||||
* corresponding information is removed also from the {@link DomainFactory}'s caches to ensure that
|
||||
* clean, fresh data is received should another tracking request be issued later.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetcher, RegattaRegistry, RaceFetcher, LeaderboardRegistry {
|
||||
@Override
|
||||
Regatta getRegatta(RegattaName regattaName);
|
||||
|
||||
@Override
|
||||
RaceDefinition getRace(RegattaAndRaceIdentifier raceIdentifier);
|
||||
|
||||
TrackedRace getTrackedRace(Regatta regatta, RaceDefinition race);
|
||||
|
||||
TrackedRace getTrackedRace(RegattaAndRaceIdentifier raceIdentifier);
|
||||
|
||||
/**
|
||||
* Obtains an unmodifiable map of the leaderboard configured in this service keyed by their names.
|
||||
*/
|
||||
Map<String, Leaderboard> getLeaderboards();
|
||||
|
||||
/**
|
||||
* @return a leaderboard whose {@link Leaderboard#getName()} method returns the value of the <code>name</code>
|
||||
* parameter, or <code>null</code> if no such leaderboard is known to this service
|
||||
*/
|
||||
Leaderboard getLeaderboardByName(String name);
|
||||
|
||||
/**
|
||||
* Defines the regatta and for each race listed in the JSON document that is not already being tracked by this service
|
||||
* creates a {@link TracTracRaceTracker} that starts tracking the respective race. The {@link RaceDefinition}s obtained this
|
||||
* way are all grouped into the single {@link Regatta} produced for the event listed in the JSON response. Note that
|
||||
* the many race trackers will have their TracTrac <code>Event</code> each, all with the same name, meaning the same
|
||||
* event but being distinct.
|
||||
*
|
||||
* @param jsonURL
|
||||
* URL of a JSON response that contains an "event" object telling the event's name and ID, as well as a
|
||||
* JSON array named "races" which tells ID and replay URL for the race. From those replay URLs the
|
||||
* paramURL for the Java client can be derived.
|
||||
* @param timeoutInMilliseconds
|
||||
* if a race definition is not received for a race of this event within this time, the race tracker for
|
||||
* that race is stopped; use -1 to wait forever
|
||||
*/
|
||||
Regatta addRegatta(URL jsonURL, URI liveURI, URI storedURI, WindStore windStore, long timeoutInMilliseconds,
|
||||
RaceCommitteeStore raceCommitteeStore)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, IOException, ParseException,
|
||||
org.json.simple.parser.ParseException, Exception;
|
||||
|
||||
/**
|
||||
* If not already tracking the URL/URI/URI combination, adds a single race tracker and starts tracking the race,
|
||||
* using the race's parameter URL which delivers the single configuration text file for that race. While the result
|
||||
* of passing this URL to the TracTrac <code>KeyValue.setup</code> is a TracTrac <code>Event</code>, those events
|
||||
* only manage a single race. In our domain model, we group those races into a single instance of our {@link Regatta}
|
||||
* class.
|
||||
* <p>
|
||||
*
|
||||
* If this is the first race of an event, the {@link Regatta} is created as well. If the {@link RaceDefinition} for
|
||||
* the race already exists, it isn't created again. Also, if a {@link TracTracRaceTracker} for the given race already
|
||||
* exists, it is not added again.
|
||||
* <p>
|
||||
*
|
||||
* Note that when the race identified by <code>paramURL</code>, <code>liveURI</code> and <code>storedURI</code> is
|
||||
* already being tracked, then regardless of the <code>windStore</code> selection the existing tracker will be used
|
||||
* and its race handle will be returned. A log message will indicate a potential wind store mismatch (based on
|
||||
* {@link WindStore#equals(Object)}).
|
||||
*
|
||||
* @param timeoutInMilliseconds
|
||||
* if the race definition is not received for the race within this time, the race tracker for
|
||||
* that race is stopped; use -1 to wait forever
|
||||
*/
|
||||
RacesHandle addTracTracRace(URL paramURL, URI liveURI, URI storedURI, WindStore windStore, long timeoutInMilliseconds,
|
||||
RaceCommitteeStore raceCommitteeStore)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
|
||||
|
||||
/**
|
||||
* Same as {@link #addTracTracRace(URL, URI, URI, WindStore, long)}, only that start and end of tracking are
|
||||
* specified which may help reducing the amount of stored data (particularly mark positions) that needs to be
|
||||
* loaded.
|
||||
*
|
||||
* @param regattaToAddTo
|
||||
* if <code>null</code>, an existing regatta by the name of the TracTrac event with the boat class name
|
||||
* appended in parentheses will be looked up; if not found, a default regatta with that name will be
|
||||
* 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.
|
||||
*/
|
||||
RacesHandle addTracTracRace(RegattaIdentifier regattaToAddTo, URL paramURL, URI liveURI, URI storedURI,
|
||||
TimePoint trackingStartTime, TimePoint trackingEndTime, WindStore windStore,
|
||||
long timeoutForReceivingRaceDefinitionInMilliseconds, boolean simulateWithStartTimeNow, RaceCommitteeStore raceCommitteeStore)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
|
||||
|
||||
/**
|
||||
* Stops tracking all races of the regatta specified. This will also stop tracking wind for all races of this regatta.
|
||||
* See {@link #stopTrackingWind(Regatta, RaceDefinition)}. If there were multiple calls to
|
||||
* {@link #addTracTracRace(URL, URI, URI, WindStore, long)} with an equal combination of URLs/URIs, the {@link TracTracRaceTracker}
|
||||
* already tracking the race was re-used. The trackers will be stopped by this call regardless of how many calls
|
||||
* were made that ensured they were tracking.
|
||||
*/
|
||||
void stopTracking(Regatta regatta) throws MalformedURLException, IOException, InterruptedException;
|
||||
|
||||
/**
|
||||
* Removes <code>race</code> and any corresponding {@link #getTrackedRace(Regatta, RaceDefinition) tracked race}
|
||||
* from this service. If it was the last {@link RaceDefinition} in its {@link Regatta} and the regatta
|
||||
* {@link Regatta#isPersistent() is not stored persistently}, the <code>regatta</code> is removed as well and will no
|
||||
* longer be returned by {@link #getAllRegattas()}. The wind tracking is stopped for <code>race</code>.
|
||||
* <p>
|
||||
*
|
||||
* Any {@link RaceTracker} for which <code>race</race> is the last race tracked that is still reachable
|
||||
* from {@link #getAllRegattas()} will be {@link RaceTracker#stop() stopped}.
|
||||
*
|
||||
* The <code>race</code> will be also removed from all leaderboards containing a column that has <code>race</code>'s
|
||||
* {@link #getTrackedRace(Regatta, RaceDefinition) corresponding} {@link TrackedRace} as its
|
||||
* {@link RaceColumn#getTrackedRace(Fleet)}.
|
||||
*
|
||||
* @param regatta
|
||||
* the regatta from which to remove the race
|
||||
* @param race
|
||||
* the race to remove
|
||||
*/
|
||||
void removeRace(Regatta regatta, RaceDefinition race) throws MalformedURLException, IOException,InterruptedException;
|
||||
|
||||
/**
|
||||
* Stops all {@link RaceTracker}s currently tracking <code>race</code>. Note that if the same tracker also may have
|
||||
* been tracking other races. Other races of the same event that are currently tracked will continue to be tracked.
|
||||
* If wind tracking for the race is currently running, it will be stopped (see also
|
||||
* {@link #stopTrackingWind(Regatta, RaceDefinition)}). The <code>race</code> (and the other races tracked by the
|
||||
* same tracker) as well as the corresponding {@link TrackedRace}s will continue to exist, e.g., when asking
|
||||
* {@link #getTrackedRace(Regatta, RaceDefinition)}.
|
||||
*/
|
||||
void stopTracking(Regatta regatta, RaceDefinition race) throws MalformedURLException, IOException, InterruptedException;
|
||||
|
||||
/**
|
||||
* @param port
|
||||
* the UDP port on which to listen for incoming messages from Expedition clients
|
||||
* @param correctByDeclination
|
||||
* An optional service to convert the wind bearings (which the receiver may
|
||||
* believe to be true bearings) from magnetic to true bearings.
|
||||
* @throws SocketException
|
||||
* thrown, e.g., in case there is already another listener on the port requested
|
||||
*/
|
||||
void startTrackingWind(Regatta regatta, RaceDefinition race, boolean correctByDeclination) throws SocketException;
|
||||
|
||||
void stopTrackingWind(Regatta regatta, RaceDefinition race) throws SocketException, IOException;
|
||||
|
||||
/**
|
||||
* The {@link Triple#getC() third component} of the triples returned is a wind tracker-specific
|
||||
* comment where a wind tracker may provide information such as its type name or, if applicable,
|
||||
* connectivity information such as the network port on which it receives wind information.
|
||||
*/
|
||||
Iterable<Triple<Regatta, RaceDefinition, String>> getWindTrackedRaces();
|
||||
|
||||
/**
|
||||
* For the JSON URL of an account / event, lists the paramURLs that can be used for {@link #addTracTracRace(URL, URI, URI, WindStore, long)}
|
||||
* calls to individually start tracking races of this event, rather than tracking <em>all</em> races in the event which
|
||||
* is hardly ever useful. The returned pair's first component is the event name.
|
||||
*/
|
||||
Pair<String, List<RaceRecord>> getTracTracRaceRecords(URL jsonURL) throws IOException, ParseException,
|
||||
org.json.simple.parser.ParseException, URISyntaxException;
|
||||
|
||||
List<com.sap.sailing.domain.swisstimingadapter.RaceRecord> getSwissTimingRaceRecords(String hostname, int port, boolean canSendRequests)
|
||||
throws InterruptedException, UnknownHostException, IOException, ParseException;
|
||||
|
||||
boolean isRaceBeingTracked(RaceDefinition r);
|
||||
|
||||
/**
|
||||
* Creates a new leaderboard with the <code>name</code> specified.
|
||||
* @param discardThresholds
|
||||
* Tells the thresholds from which on a next higher number of worst races will be discarded per
|
||||
* competitor. Example: <code>[3, 6]</code> means that starting from three races the single worst race
|
||||
* will be discarded; starting from six races, the two worst races per competitor are discarded.
|
||||
*
|
||||
* @return the leaderboard created
|
||||
*/
|
||||
FlexibleLeaderboard addFlexibleLeaderboard(String name, int[] discardThresholds, ScoringScheme scoringScheme);
|
||||
|
||||
RegattaLeaderboard addRegattaLeaderboard(RegattaIdentifier regattaIdentifier, int[] discardThresholds);
|
||||
|
||||
void removeLeaderboard(String leaderboardName);
|
||||
|
||||
/**
|
||||
* Renames a leaderboard. If a leaderboard by the name <code>oldName</code> does not exist in {@link #getLeaderboards()},
|
||||
* or if a leaderboard with the name <code>newName</code> already exists, an {@link IllegalArgumentException} is thrown.
|
||||
* If the method completes normally, the rename has been successful, and the leaderboard previously obtained by calling
|
||||
* {@link #getLeaderboardByName(String) getLeaderboardByName(oldName)} can now be obtained by calling
|
||||
* {@link #getLeaderboardByName(String) getLeaderboardByName(newName)}.
|
||||
*/
|
||||
void renameLeaderboard(String oldName, String newName);
|
||||
|
||||
RaceColumn addColumnToLeaderboard(String columnName, String leaderboardName, boolean medalRace);
|
||||
|
||||
void moveLeaderboardColumnUp(String leaderboardName, String columnName);
|
||||
|
||||
void moveLeaderboardColumnDown(String leaderboardName, String columnName);
|
||||
|
||||
void removeLeaderboardColumn(String leaderboardName, String columnName);
|
||||
|
||||
void renameLeaderboardColumn(String leaderboardName, String oldColumnName, String newColumnName);
|
||||
|
||||
/**
|
||||
* @see RaceColumn#setFactor(Double)
|
||||
*/
|
||||
void updateLeaderboardColumnFactor(String leaderboardName, String columnName, Double factor);
|
||||
|
||||
/**
|
||||
* Updates the leaderboard data in the persistent store
|
||||
*/
|
||||
void updateStoredLeaderboard(Leaderboard leaderboard);
|
||||
|
||||
void updateStoredRegatta(Regatta regatta);
|
||||
|
||||
long getDelayToLiveInMillis();
|
||||
|
||||
void setDelayToLiveInMillis(long delayToLiveInMillis);
|
||||
|
||||
/**
|
||||
* @param regattaToAddTo
|
||||
* if <code>null</code>, an existing regatta by the name of the TracTrac event with the boat class name
|
||||
* appended in parentheses will be looked up; if not found, a default regatta with that name will be
|
||||
* 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.
|
||||
*/
|
||||
RacesHandle addSwissTimingRace(RegattaIdentifier regattaToAddTo, String raceID, String hostname, int port,
|
||||
boolean canSendRequests, WindStore windStore, long timeoutInMilliseconds,
|
||||
RaceCommitteeStore raceCommitteeStore) throws InterruptedException, UnknownHostException,
|
||||
IOException, ParseException, Exception;
|
||||
|
||||
SwissTimingFactory getSwissTimingFactory();
|
||||
|
||||
void storeSwissTimingDummyRace(String racMessage, String stlMesssage, String ccgMessage) throws IllegalArgumentException;
|
||||
|
||||
void stopTrackingAndRemove(Regatta regatta) throws MalformedURLException, IOException, InterruptedException;
|
||||
|
||||
void removeRegatta(Regatta regatta) throws MalformedURLException, IOException, InterruptedException;
|
||||
|
||||
TrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier);
|
||||
|
||||
/**
|
||||
* Obtains an unmodifiable map of the leaderboard groups configured in this service keyed by their names.
|
||||
*/
|
||||
Map<String, LeaderboardGroup> getLeaderboardGroups();
|
||||
|
||||
/**
|
||||
* @param groupName The name of the requested leaderboard group
|
||||
* @return The leaderboard group with the name <code>groupName</code>, or <code>null</code> if theres no such group
|
||||
*/
|
||||
LeaderboardGroup getLeaderboardGroupByName(String groupName);
|
||||
|
||||
/**
|
||||
* Creates a new group with the name <code>groupName</code>, the description <code>desciption</code> and the
|
||||
* leaderboards with the names in <code>leaderboardNames</code> and saves it in the database.
|
||||
*
|
||||
* @param groupName
|
||||
* The name of the new group
|
||||
* @param description
|
||||
* The description of the new group
|
||||
* @param displayGroupsInReverseOrder TODO
|
||||
* @param leaderboardNames
|
||||
* The names of the leaderboards, which should be contained by the new group.<br />
|
||||
* If there isn't a leaderboard with one of these names an {@link IllegalArgumentException} is thrown.
|
||||
* @return The new leaderboard group
|
||||
*/
|
||||
LeaderboardGroup addLeaderboardGroup(String groupName, String description, boolean displayGroupsInReverseOrder,
|
||||
List<String> leaderboardNames, int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType);
|
||||
|
||||
/**
|
||||
* Removes the group with the name <code>groupName</code> from the service and the database.
|
||||
* @param groupName The name of the group which shall be removed.
|
||||
*/
|
||||
void removeLeaderboardGroup(String groupName);
|
||||
|
||||
/**
|
||||
* Renames the group with the name <code>oldName</code> to the <code>newName</code>.<br />
|
||||
* If there's no group with the name <code>oldName</code> or there's already a group with the name
|
||||
* <code>newName</code> a {@link IllegalArgumentException} is thrown.
|
||||
*
|
||||
* @param oldName The old name of the group
|
||||
* @param newName The new name of the group
|
||||
*/
|
||||
void renameLeaderboardGroup(String oldName, String newName);
|
||||
|
||||
/**
|
||||
* Updates the group data in the persistant store.
|
||||
*/
|
||||
void updateStoredLeaderboardGroup(LeaderboardGroup leaderboardGroup);
|
||||
|
||||
void addExpeditionListener(ExpeditionListener listener, boolean validMessagesOnly) throws SocketException;
|
||||
|
||||
void removeExpeditionListener(ExpeditionListener listener);
|
||||
|
||||
/**
|
||||
* @param regattaToAddTo
|
||||
* if <code>null</code> or no regatta by that identifier is found, an existing regatta by the name of the
|
||||
* TracTrac event with the boat class name appended in parentheses will be looked up; if not found, a
|
||||
* default regatta with that name will be 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, and
|
||||
* {@link #setRegattaForRace(Regatta, RaceDefinition)} is called to remember the association
|
||||
* persistently. Otherwise, a default regatta as described above will be created and used.
|
||||
* @param windStore
|
||||
* must not be <code>null</code>, but can, e.g., be an {@link EmptyWindStore}
|
||||
*/
|
||||
RacesHandle addRace(RegattaIdentifier regattaToAddTo, RaceTrackingConnectivityParameters params, WindStore windStore, long timeoutInMilliseconds,
|
||||
RaceCommitteeStore raceCommitteeStore)
|
||||
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
|
||||
|
||||
TrackedRace createTrackedRace(RegattaAndRaceIdentifier raceIdentifier, WindStore windStore,
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
RaceCommitteeStore raceCommitteeStore);
|
||||
|
||||
Regatta getOrCreateRegatta(String regattaName, String boatClassName);
|
||||
|
||||
Regatta createRegatta(String baseName, String boatClassName, Iterable<? extends Series> series, boolean persistent, ScoringScheme scoringScheme);
|
||||
|
||||
/**
|
||||
* Adds <code>raceDefinition</code> to the {@link Regatta} such that it will appear in {@link Regatta#getAllRaces()}
|
||||
* and {@link Regatta#getRaceByName(String)}.
|
||||
*
|
||||
* @param addToRegatta identifier of an regatta that must exist already
|
||||
*/
|
||||
void addRace(RegattaIdentifier addToRegatta, RaceDefinition raceDefinition);
|
||||
|
||||
void updateLeaderboardGroup(String oldName, String newName, String description, List<String> leaderboardNames,
|
||||
int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType);
|
||||
|
||||
/**
|
||||
* Executes an operation whose effects need to be replicated to any replica of this service known and
|
||||
* {@link OperationExecutionListener#executed(RacingEventServiceOperation) notifies} all registered
|
||||
* operation execution listeners about the execution of the operation.
|
||||
*/
|
||||
<T> T apply(RacingEventServiceOperation<T> operation);
|
||||
|
||||
void addOperationExecutionListener(OperationExecutionListener listener);
|
||||
|
||||
void removeOperationExecutionListener(OperationExecutionListener listener);
|
||||
|
||||
/**
|
||||
* Produces a one-shot serializable copy of those elements required for replication into <code>oos</code> so that
|
||||
* afterwards the {@link RacingEventServiceOperation}s can be {@link #apply(RacingEventServiceOperation) applied} to
|
||||
* maintain consistency with the master copy of the service. The dual operation is {@link #initiallyFillFrom}.
|
||||
*/
|
||||
void serializeForInitialReplication(ObjectOutputStream oos) throws IOException;
|
||||
|
||||
/**
|
||||
* Dual, reading operation for {@link #serializeForInitialReplication(ObjectOutputStream)}. In other words, when
|
||||
* this operation returns, this service instance is in a state "equivalent" to that of the service instance that
|
||||
* produced the stream contents in its {@link #serializeForInitialReplication(ObjectOutputStream)}. "Equivalent"
|
||||
* here means that a replica will have equal sets of regattas, tracked regattas, leaderboards and leaderboard groups but
|
||||
* will not have any active trackers for wind or positions because it relies on these elements to be sent through
|
||||
* the replication channel.
|
||||
* <p>
|
||||
*
|
||||
* Tracked regattas read from the stream are observed (see {@link RaceListener}) by this object for automatic updates
|
||||
* to the default leaderboard and for automatic linking to leaderboard columns. It is assumed that no explicit
|
||||
* replication of these operations will happen based on the changes performed on the replication master.<p>
|
||||
*
|
||||
* <b>Caution:</b> All relevant contents of this service instance will be replaced by the stream contents.
|
||||
*/
|
||||
void initiallyFillFrom(ObjectInputStream ois) throws IOException, ClassNotFoundException;
|
||||
|
||||
Event getEventByName(String name);
|
||||
|
||||
/**
|
||||
* @return a thread-safe copy of the events currently known by the service; it's safe for callers to iterate over
|
||||
* the iterable returned, and no risk of a {@link ConcurrentModificationException} exists
|
||||
*/
|
||||
Iterable<Event> getAllEvents();
|
||||
|
||||
/**
|
||||
* Creates a new event with the name <code>eventName</code>, the venue<code>venue</code> and the
|
||||
* regattas with the names in <code>regattaNames</code> and saves it in the database.
|
||||
*
|
||||
* @param eventName
|
||||
* The name of the new event
|
||||
* @param venue
|
||||
* The name of the venue of the new event
|
||||
* @param publicationUrl
|
||||
* The publication URL of the new event
|
||||
* @param isPublic
|
||||
* Indicates whether the event is public accessible via the publication URL or not
|
||||
* @param regattaNames
|
||||
* The names of the regattas contained in the new event.<br />
|
||||
* @return The new event
|
||||
*/
|
||||
Event addEvent(String eventName, String venueName, String publicationUrl, boolean isPublic, List<String> regattaNames);
|
||||
|
||||
/**
|
||||
* Updates a sailing event with the name <code>eventName</code>, the venue<code>venue</code> and the
|
||||
* regattas with the names in <code>regattaNames</code> and updates it in the database.
|
||||
*
|
||||
* @param eventName
|
||||
* The name of the event to update
|
||||
* @param venueName
|
||||
* The name of the venue of the event
|
||||
* @param publicationUrl
|
||||
* The publication URL of the event
|
||||
* @param isPublic
|
||||
* Indicates whether the event is public accessible via the publication URL or not
|
||||
* @param regattaNames
|
||||
* The names of the regattas contained in the event.<br />
|
||||
* @return The new event
|
||||
*/
|
||||
void updateEvent(String eventName, String venueName, String publicationUrl, boolean isPublic, List<String> regattaNames);
|
||||
|
||||
/**
|
||||
* Renames a sailing event. If a sailing event by the name <code>oldName</code> does not exist in {@link #getEvents()},
|
||||
* or if a event with the name <code>newName</code> already exists, an {@link IllegalArgumentException} is thrown.
|
||||
* If the method completes normally, the rename has been successful, and the event previously obtained by calling
|
||||
* {@link #getEventByName(String) getEventByName(oldName)} can now be obtained by calling
|
||||
* {@link #getEventByName(String) getEventByName(newName)}.
|
||||
*/
|
||||
void renameEvent(String oldEventName, String newEventName);
|
||||
|
||||
void removeEvent(String eventName);
|
||||
|
||||
com.sap.sailing.domain.base.DomainFactory getBaseDomainFactory();
|
||||
|
||||
com.sap.sailing.domain.swisstimingadapter.DomainFactory getSwissTimingDomainFactory();
|
||||
|
||||
}
|
||||
+23
-15
@@ -27,11 +27,11 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.ControlPoint;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceColumnInSeries;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
@@ -70,6 +70,7 @@ import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeEvent;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Race;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterConnector;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterMessage;
|
||||
@@ -107,8 +108,8 @@ import com.sap.sailing.server.operationaltransformation.AddRaceDefinition;
|
||||
import com.sap.sailing.server.operationaltransformation.AddSpecificRegatta;
|
||||
import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn;
|
||||
import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
|
||||
import com.sap.sailing.server.operationaltransformation.RecordMarkGPSFix;
|
||||
import com.sap.sailing.server.operationaltransformation.RecordCompetitorGPSFix;
|
||||
import com.sap.sailing.server.operationaltransformation.RecordMarkGPSFix;
|
||||
import com.sap.sailing.server.operationaltransformation.RecordRaceCommitteeEvent;
|
||||
import com.sap.sailing.server.operationaltransformation.RecordWindFix;
|
||||
import com.sap.sailing.server.operationaltransformation.RemoveWindFix;
|
||||
@@ -570,12 +571,13 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
}
|
||||
|
||||
@Override
|
||||
public Regatta addRegatta(URL jsonURL, URI liveURI, URI storedURI, WindStore windStore, long timeoutInMilliseconds) throws Exception {
|
||||
public Regatta addRegatta(URL jsonURL, URI liveURI, URI storedURI, WindStore windStore, long timeoutInMilliseconds,
|
||||
RaceCommitteeStore raceCommitteeStore) throws Exception {
|
||||
JSONService jsonService = getTracTracDomainFactory().parseJSONURL(jsonURL);
|
||||
Regatta regatta = null;
|
||||
for (RaceRecord rr : jsonService.getRaceRecords()) {
|
||||
URL paramURL = rr.getParamURL();
|
||||
regatta = addTracTracRace(paramURL, liveURI, storedURI, windStore, timeoutInMilliseconds).getRegatta();
|
||||
regatta = addTracTracRace(paramURL, liveURI, storedURI, windStore, timeoutInMilliseconds, raceCommitteeStore).getRegatta();
|
||||
}
|
||||
return regatta;
|
||||
}
|
||||
@@ -629,21 +631,23 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
|
||||
@Override
|
||||
public RacesHandle addSwissTimingRace(RegattaIdentifier regattaToAddTo, String raceID, String hostname,
|
||||
int port, boolean canSendRequests, WindStore windStore, long timeoutInMilliseconds) throws Exception {
|
||||
int port, boolean canSendRequests, WindStore windStore, long timeoutInMilliseconds,
|
||||
RaceCommitteeStore raceCommitteeStore) throws Exception {
|
||||
return addRace(
|
||||
regattaToAddTo,
|
||||
swissTimingDomainFactory.createTrackingConnectivityParameters(hostname, port, raceID, canSendRequests, delayToLiveInMillis,
|
||||
swissTimingFactory, swissTimingDomainFactory, windStore, swissTimingAdapterPersistence), windStore, timeoutInMilliseconds);
|
||||
swissTimingFactory, swissTimingDomainFactory, windStore, raceCommitteeStore, swissTimingAdapterPersistence), windStore, timeoutInMilliseconds,
|
||||
raceCommitteeStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RacesHandle addTracTracRace(URL paramURL, URI liveURI, URI storedURI, WindStore windStore,
|
||||
long timeoutInMilliseconds) throws Exception {
|
||||
long timeoutInMilliseconds, RaceCommitteeStore raceCommitteeStore) throws Exception {
|
||||
return addRace(
|
||||
/* regattaToAddTo */null, getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI,
|
||||
/* startOfTracking */null,
|
||||
/* endOfTracking */null, delayToLiveInMillis, /* simulateWithStartTimeNow */false, windStore), windStore,
|
||||
timeoutInMilliseconds);
|
||||
/* endOfTracking */null, delayToLiveInMillis, /* simulateWithStartTimeNow */false, windStore, raceCommitteeStore), windStore,
|
||||
timeoutInMilliseconds, raceCommitteeStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -674,7 +678,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
|
||||
@Override
|
||||
public RacesHandle addRace(RegattaIdentifier regattaToAddTo, RaceTrackingConnectivityParameters params,
|
||||
WindStore windStore, long timeoutInMilliseconds) throws Exception {
|
||||
WindStore windStore, long timeoutInMilliseconds, RaceCommitteeStore raceCommitteeStore) throws Exception {
|
||||
RaceTracker tracker = raceTrackersByID.get(params.getTrackerID());
|
||||
if (tracker == null) {
|
||||
Regatta regatta = regattaToAddTo == null ? null : getRegatta(regattaToAddTo);
|
||||
@@ -781,20 +785,23 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
|
||||
@Override
|
||||
public TrackedRace createTrackedRace(RegattaAndRaceIdentifier raceIdentifier, WindStore windStore,
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed) {
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
RaceCommitteeStore raceCommitteeStore) {
|
||||
DynamicTrackedRegatta trackedRegatta = getOrCreateTrackedRegatta(getRegatta(raceIdentifier));
|
||||
RaceDefinition race = getRace(raceIdentifier);
|
||||
return trackedRegatta.createTrackedRace(race, windStore, delayToLiveInMillis,
|
||||
millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
|
||||
/* raceDefinitionSetToUpdate */null);
|
||||
/* raceDefinitionSetToUpdate */null, raceCommitteeStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RacesHandle addTracTracRace(RegattaIdentifier regattaToAddTo, URL paramURL, URI liveURI,
|
||||
URI storedURI, TimePoint startOfTracking, TimePoint endOfTracking,
|
||||
WindStore windStore, long timeoutInMilliseconds, boolean simulateWithStartTimeNow) throws Exception {
|
||||
WindStore windStore, long timeoutInMilliseconds, boolean simulateWithStartTimeNow,
|
||||
RaceCommitteeStore raceCommitteeStore) throws Exception {
|
||||
return addRace(regattaToAddTo, getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI, startOfTracking,
|
||||
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore), windStore, timeoutInMilliseconds);
|
||||
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, windStore, raceCommitteeStore), windStore, timeoutInMilliseconds,
|
||||
raceCommitteeStore);
|
||||
}
|
||||
|
||||
private void ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking(DynamicTrackedRegatta trackedRegatta) {
|
||||
@@ -844,7 +851,8 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
// replicate the addition of the tracked race:
|
||||
CreateTrackedRace op = new CreateTrackedRace(trackedRace.getRaceIdentifier(), trackedRace.getWindStore(),
|
||||
trackedRace.getDelayToLiveInMillis(),
|
||||
trackedRace.getMillisecondsOverWhichToAverageWind(), trackedRace.getMillisecondsOverWhichToAverageSpeed());
|
||||
trackedRace.getMillisecondsOverWhichToAverageWind(), trackedRace.getMillisecondsOverWhichToAverageSpeed(),
|
||||
trackedRace.getRaceCommitteeStore());
|
||||
replicate(op);
|
||||
linkRaceToConfiguredLeaderboardColumns(trackedRace);
|
||||
final FlexibleLeaderboard defaultLeaderboard = (FlexibleLeaderboard) leaderboardsByName.get(LeaderboardNameConstants.DEFAULT_LEADERBOARD_NAME);
|
||||
|
||||
+17
-2
@@ -4,6 +4,8 @@ import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.RaceDefinition;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.racecommittee.RaceCommitteeStore;
|
||||
import com.sap.sailing.domain.racecommittee.impl.EmptyRaceCommitteeStore;
|
||||
import com.sap.sailing.domain.tracking.TrackedRegatta;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.WindStore;
|
||||
@@ -32,16 +34,28 @@ public class CreateTrackedRace extends AbstractRaceOperation<TrackedRace> {
|
||||
* {@link EmptyWindStore}.
|
||||
*/
|
||||
private transient final WindStore windStore;
|
||||
|
||||
/**
|
||||
* If a {@link RaceCommitteeStore} is provided to this command, it will be used for the construction of the tracked race.
|
||||
* However, after de-serialization, the race committee store will always be <code>null</code>, causing the use of an
|
||||
* {@link EmptyRaceCommitteeStore}.
|
||||
*/
|
||||
private transient final RaceCommitteeStore raceCommitteeStore;
|
||||
|
||||
/**
|
||||
* @param windStore
|
||||
* if <code>null</code>, an {@link EmptyWindStore} will be used. Note that the {@link #windStore} field
|
||||
* won't be serialized. A receiver of this operation will therefore always use an {@link EmptyWindStore}.
|
||||
* @param raceCommitteeStore
|
||||
* if <code>null</code>, an {@link EmptyRaceCommitteeStore} will be used. Note that the {@link #raceCommitteeStore} field
|
||||
* won't be serialized. A receiver of this operation will therefore always use an {@link EmptyRaceCommitteeStore}.
|
||||
*/
|
||||
public CreateTrackedRace(RegattaAndRaceIdentifier raceIdentifier, WindStore windStore,
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed) {
|
||||
long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
|
||||
RaceCommitteeStore raceCommitteeStore) {
|
||||
super(raceIdentifier);
|
||||
this.windStore = windStore;
|
||||
this.raceCommitteeStore = raceCommitteeStore;
|
||||
this.delayToLiveInMillis = delayToLiveInMillis;
|
||||
this.millisecondsOverWhichToAverageWind = millisecondsOverWhichToAverageWind;
|
||||
this.millisecondsOverWhichToAverageSpeed = millisecondsOverWhichToAverageSpeed;
|
||||
@@ -62,7 +76,8 @@ public class CreateTrackedRace extends AbstractRaceOperation<TrackedRace> {
|
||||
@Override
|
||||
public TrackedRace internalApplyTo(RacingEventService toState) {
|
||||
return toState.createTrackedRace(getRaceIdentifier(), windStore == null ? EmptyWindStore.INSTANCE : windStore,
|
||||
delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed);
|
||||
delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
|
||||
raceCommitteeStore == null ? EmptyRaceCommitteeStore.INSTANCE : raceCommitteeStore);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user