mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-21 03:30:12 +00:00
Merge branch 'master' into racecommittee_app
This commit is contained in:
commit
cef3f3fa83
6 files changed
+65
-25
No files matched your search
+11
-10
@@ -13,6 +13,7 @@ import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.WriteConcern;
|
||||
import com.mongodb.util.JSON;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.ControlPoint;
|
||||
@@ -216,7 +217,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
}
|
||||
storeColumnFactors(leaderboard, dbLeaderboard);
|
||||
storeLeaderboardCorrectionsAndDiscards(leaderboard, dbLeaderboard);
|
||||
leaderboardCollection.update(query, dbLeaderboard, /* upsrt */ true, /* multi */ false);
|
||||
leaderboardCollection.update(query, dbLeaderboard, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
||||
}
|
||||
|
||||
private void storeColumnFactors(Leaderboard leaderboard, BasicDBObject dbLeaderboard) {
|
||||
@@ -350,7 +351,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name());
|
||||
BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), oldName);
|
||||
BasicDBObject renameUpdate = new BasicDBObject("$set", new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), newName));
|
||||
leaderboardCollection.update(query, renameUpdate);
|
||||
leaderboardCollection.update(query, renameUpdate, /* upsert */ true, /* multi */ false, WriteConcern.SAFE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -392,7 +393,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
dbLeaderboardIds.add(dbLeaderboardId);
|
||||
}
|
||||
dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_LEADERBOARDS.name(), dbLeaderboardIds);
|
||||
leaderboardGroupCollection.update(query, dbLeaderboardGroup, true, false);
|
||||
leaderboardGroupCollection.update(query, dbLeaderboardGroup, true, false, WriteConcern.SAFE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -407,7 +408,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name());
|
||||
BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), oldName);
|
||||
BasicDBObject update = new BasicDBObject("$set", new BasicDBObject(FieldNames.LEADERBOARD_GROUP_NAME.name(), newName));
|
||||
leaderboardGroupCollection.update(query, update);
|
||||
leaderboardGroupCollection.update(query, update, /* upsert */ true, /* multi */ false, WriteConcern.SAFE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -423,7 +424,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
eventDBObject.put(FieldNames.EVENT_IS_PUBLIC.name(), event.isPublic());
|
||||
DBObject venueDBObject = getVenueAsDBObject(event.getVenue());
|
||||
eventDBObject.put(FieldNames.VENUE.name(), venueDBObject);
|
||||
eventCollection.update(query, eventDBObject, /* upsrt */ true, /* multi */ false);
|
||||
eventCollection.update(query, eventDBObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -431,7 +432,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
DBCollection eventCollection = database.getCollection(CollectionNames.EVENTS.name());
|
||||
BasicDBObject query = new BasicDBObject(FieldNames.EVENT_ID.name(), id);
|
||||
BasicDBObject renameUpdate = new BasicDBObject("$set", new BasicDBObject(FieldNames.EVENT_NAME.name(), newName));
|
||||
eventCollection.update(query, renameUpdate);
|
||||
eventCollection.update(query, renameUpdate, /* upsert */ true, /* multi */ false, WriteConcern.SAFE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -484,7 +485,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
dbRegatta.put(FieldNames.REGATTA_REGATTA_CONFIGURATION.name(), configurationObject);
|
||||
}
|
||||
|
||||
regattasCollection.update(query, dbRegatta, /* upsrt */ true, /* multi */ false);
|
||||
regattasCollection.update(query, dbRegatta, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -546,7 +547,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
DBObject query = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString);
|
||||
DBObject entry = new BasicDBObject(FieldNames.RACE_ID_AS_STRING.name(), raceIDAsString);
|
||||
entry.put(FieldNames.REGATTA_NAME.name(), regatta.getName());
|
||||
regattaForRaceIDCollection.update(query, entry, /* upsrt */ true, /* multi */ false);
|
||||
regattaForRaceIDCollection.update(query, entry, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -900,7 +901,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
JSONObject json = competitorSerializer.serialize(competitor);
|
||||
DBObject query = (DBObject) JSON.parse(competitorSerializer.getCompetitorIdQuery(competitor).toString());
|
||||
DBObject entry = (DBObject) JSON.parse(json.toString());
|
||||
collection.update(query, entry, /* upsrt */true, /* multi */false);
|
||||
collection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -930,7 +931,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
entryObject.put(FieldNames.CONFIGURATION_MATCHER.name(), createDeviceConfigurationMatcherObject(matcher));
|
||||
entryObject.put(FieldNames.CONFIGURATION_CONFIG.name(), createDeviceConfigurationObject(configuration));
|
||||
|
||||
configurationsCollections.update(query, entryObject, /* upsrt */ true, /* multi */ false);
|
||||
configurationsCollections.update(query, entryObject, /* upsrt */ true, /* multi */ false, WriteConcern.SAFE);
|
||||
}
|
||||
|
||||
private DBObject createDeviceConfigurationMatcherObject(DeviceConfigurationMatcher matcher) {
|
||||
|
||||
+2
@@ -135,6 +135,8 @@ public class TransientCompetitorStoreImpl implements CompetitorStore, Serializab
|
||||
LockUtil.lockForWrite(lock);
|
||||
try {
|
||||
competitorCache.clear();
|
||||
competitorsByIdAsString.clear();
|
||||
competitorsToUpdateDuringGetOrCreate.clear();
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(lock);
|
||||
}
|
||||
|
||||
+11
@@ -3,6 +3,8 @@ package com.sap.sailing.domain.test;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CompetitorFactory;
|
||||
import com.sap.sailing.domain.base.impl.BoatClassImpl;
|
||||
import com.sap.sailing.domain.base.impl.BoatImpl;
|
||||
import com.sap.sailing.domain.base.impl.CompetitorImpl;
|
||||
@@ -21,6 +23,15 @@ public abstract class AbstractLeaderboardTest {
|
||||
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), /* sailID */ null));
|
||||
}
|
||||
|
||||
public static Competitor createCompetitor(String competitorName, CompetitorFactory competitorFactory) {
|
||||
return competitorFactory.getOrCreateCompetitor(123, competitorName, Color.RED, new TeamImpl("STG", Collections.singleton(
|
||||
new PersonImpl(competitorName, new NationalityImpl("GER"),
|
||||
/* dateOfBirth */ null, "This is famous "+competitorName)),
|
||||
new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
|
||||
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl(competitorName + "'s boat",
|
||||
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), /* sailID */ null));
|
||||
}
|
||||
|
||||
public static CompetitorImpl createCompetitor(String competitorName, Serializable id) {
|
||||
return new CompetitorImpl(id, competitorName, Color.RED, new TeamImpl("STG", Collections.singleton(
|
||||
new PersonImpl(competitorName, new NationalityImpl("GER"),
|
||||
|
||||
+4
-4
@@ -10,13 +10,13 @@ import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.NationalityJsonSerializer;
|
||||
|
||||
public class NationalityJsonDeserializer implements JsonDeserializer<Nationality> {
|
||||
private final SharedDomainFactory domainFactory;
|
||||
private final SharedDomainFactory domainFactory;
|
||||
|
||||
public NationalityJsonDeserializer(SharedDomainFactory domainFactory) {
|
||||
this.domainFactory = domainFactory;
|
||||
}
|
||||
this.domainFactory = domainFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public Nationality deserialize(JSONObject object) throws JsonDeserializationException {
|
||||
final Nationality result;
|
||||
if (object == null) {
|
||||
|
||||
+33
-9
@@ -3,9 +3,11 @@ package com.sap.sailing.server.replication.test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -15,13 +17,17 @@ import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceColumnListener;
|
||||
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
|
||||
import com.sap.sailing.domain.base.impl.DynamicCompetitor;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.leaderboard.DelayedLeaderboardCorrections;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
|
||||
import com.sap.sailing.domain.persistence.PersistenceFactory;
|
||||
import com.sap.sailing.domain.persistence.media.MediaDBFactory;
|
||||
@@ -40,6 +46,8 @@ import com.sap.sailing.server.replication.ReplicationMasterDescriptor;
|
||||
import com.sap.sailing.server.replication.ReplicationService;
|
||||
|
||||
public class DelayedLeaderboardCorrectionsReplicationTest extends AbstractServerReplicationTest {
|
||||
private static final Logger logger = Logger.getLogger(DelayedLeaderboardCorrectionsReplicationTest.class.getName());
|
||||
|
||||
private static final String Q2 = "Q2";
|
||||
private ReplicationService replicaReplicator;
|
||||
private ReplicationMasterDescriptor masterDescriptor;
|
||||
@@ -66,8 +74,9 @@ public class DelayedLeaderboardCorrectionsReplicationTest extends AbstractServer
|
||||
// then start initial load, wait until finished; then link a tracked race to leaderboard's RaceColumn on master and
|
||||
// verify that on the replica it is associated to the RaceColumn as well, and the DelayedLeaderboardCorrections are
|
||||
// resolved properly on the replica.
|
||||
BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
|
||||
Competitor hasso = AbstractLeaderboardTest.createCompetitor("Dr. Hasso Plattner");
|
||||
final DomainFactory domainFactory = DomainFactory.INSTANCE;
|
||||
BoatClass boatClass = domainFactory.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
|
||||
DynamicCompetitor hasso = AbstractLeaderboardTest.createCompetitor("Dr. Hasso Plattner"); // don't create competitor using CompetitorStore
|
||||
final DynamicTrackedRace q2YellowTrackedRace = new MockedTrackedRaceWithFixedRank(hasso, /* rank */ 1, /* started */ false, boatClass) {
|
||||
private static final long serialVersionUID = 1234L;
|
||||
@Override
|
||||
@@ -75,7 +84,7 @@ public class DelayedLeaderboardCorrectionsReplicationTest extends AbstractServer
|
||||
return new RegattaNameAndRaceName("Kieler Woche (5o5)", "Yellow Race 2");
|
||||
}
|
||||
};
|
||||
master = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace);
|
||||
master = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace, domainFactory);
|
||||
final String leaderboardName = "My new leaderboard";
|
||||
final int[] discardThresholds = new int[] { 19, 44 };
|
||||
CreateFlexibleLeaderboard createTestLeaderboard = new CreateFlexibleLeaderboard(leaderboardName, null, discardThresholds, new LowPoint(), null);
|
||||
@@ -92,11 +101,14 @@ public class DelayedLeaderboardCorrectionsReplicationTest extends AbstractServer
|
||||
masterLeaderboard.getRaceColumnByName(Q2), MillisecondsTimePoint.now()));
|
||||
|
||||
// re-load new master from persistence
|
||||
master = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace);
|
||||
replica = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace);
|
||||
master = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace, domainFactory);
|
||||
DomainFactoryImpl replicaDomainFactory = new DomainFactoryImpl();
|
||||
replica = createRacingEventServiceWithOneMockedTrackedRace(q2YellowTrackedRace, replicaDomainFactory);
|
||||
final Leaderboard masterLeaderboardReloaded = master.getLeaderboardByName(leaderboardName);
|
||||
assertNotNull(masterLeaderboardReloaded);
|
||||
// expecting the correction to only be in the DelayedLeaderboardCorrection object but not the leaderboard itself
|
||||
// expecting the correction to not be in the leaderboard because the competitor was not found in the
|
||||
// domain factory's competitor store while loading and therefore the score correction could not immediately
|
||||
// be applied to the leaderboard's real score correction
|
||||
assertEquals(MaxPointsReason.NONE, masterLeaderboardReloaded.getMaxPointsReason(hasso,
|
||||
masterLeaderboardReloaded.getRaceColumnByName(Q2), MillisecondsTimePoint.now()));
|
||||
|
||||
@@ -104,19 +116,30 @@ public class DelayedLeaderboardCorrectionsReplicationTest extends AbstractServer
|
||||
Pair<ReplicationServiceTestImpl, ReplicationMasterDescriptor> descriptors = basicSetUp(/* dropDB */ false, master, replica);
|
||||
replicaReplicator = descriptors.getA();
|
||||
masterDescriptor = descriptors.getB();
|
||||
// starting to replicate will clear the competitor store used by the replica in this test;
|
||||
// the competitor will have to be looked up again after it was received by the replica.
|
||||
replicaReplicator.startToReplicateFrom(masterDescriptor);
|
||||
Thread.sleep(1000);
|
||||
|
||||
Leaderboard replicaLeaderboard = replica.getLeaderboardByName(leaderboardName);
|
||||
assertNotNull(replicaLeaderboard);
|
||||
assertNotNull(replicaLeaderboard.getRaceColumnByName(Q2));
|
||||
// so far, the replica should also only have the delayed corrections:
|
||||
// so far, the replica should also only have the delayed corrections since during deserializing them the
|
||||
// replicatedHasso competitor was not yet known to the replica's competitor store:
|
||||
assertEquals(MaxPointsReason.NONE, replicaLeaderboard.getMaxPointsReason(hasso,
|
||||
replicaLeaderboard.getRaceColumnByName(Q2), MillisecondsTimePoint.now()));
|
||||
|
||||
Leaderboard newMasterLeaderboard = master.getLeaderboardByName(masterLeaderboard.getName());
|
||||
SettableScoreCorrection newMasterScoreCorrections = newMasterLeaderboard.getScoreCorrection();
|
||||
RaceColumn newMasterQ2 = newMasterLeaderboard.getRaceColumnByName(Q2);
|
||||
newMasterScoreCorrections.getCompetitorsThatHaveCorrectionsIn(newMasterQ2);
|
||||
assertTrue(Util.isEmpty(newMasterScoreCorrections.getCompetitorsThatHaveCorrectionsIn(newMasterQ2))); // no score corrections applied yet
|
||||
// now connect the tracked race again to the leaderboard column in the re-loaded environment
|
||||
master.apply(new ConnectTrackedRaceToLeaderboardColumn(masterLeaderboard.getName(), Q2, /* default fleet */
|
||||
masterLeaderboard.getFleet(null).getName(), q2YellowTrackedRace.getRaceIdentifier()));
|
||||
logger.info("hasso object ID hash: "+System.identityHashCode(hasso));
|
||||
logger.info("got score correction for competitor "+System.identityHashCode(newMasterScoreCorrections.getCompetitorsThatHaveCorrectionsIn(newMasterQ2).iterator().next()));
|
||||
assertTrue(Util.contains(newMasterScoreCorrections.getCompetitorsThatHaveCorrectionsIn(newMasterQ2), hasso)); // now score corrections must have been applied from Delayed...
|
||||
// now the delayed corrections are expected to have been resolved:
|
||||
assertEquals(MaxPointsReason.DNF, master.getLeaderboardByName(leaderboardName).getMaxPointsReason(hasso,
|
||||
master.getLeaderboardByName(leaderboardName).getRaceColumnByName(Q2), MillisecondsTimePoint.now()));
|
||||
@@ -126,8 +149,9 @@ public class DelayedLeaderboardCorrectionsReplicationTest extends AbstractServer
|
||||
replicaLeaderboard.getRaceColumnByName(Q2), MillisecondsTimePoint.now()));
|
||||
}
|
||||
|
||||
private RacingEventServiceImpl createRacingEventServiceWithOneMockedTrackedRace(final DynamicTrackedRace q2YellowTrackedRace) {
|
||||
return new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, DomainFactory.INSTANCE), PersistenceFactory.INSTANCE
|
||||
private RacingEventServiceImpl createRacingEventServiceWithOneMockedTrackedRace(final DynamicTrackedRace q2YellowTrackedRace,
|
||||
DomainFactory domainFactory) {
|
||||
return new RacingEventServiceImpl(PersistenceFactory.INSTANCE.getDomainObjectFactory(MongoDBService.INSTANCE, domainFactory), PersistenceFactory.INSTANCE
|
||||
.getMongoObjectFactory(MongoDBService.INSTANCE), MediaDBFactory.INSTANCE.getMediaDB(MongoDBService.INSTANCE), EmptyWindStore.INSTANCE) {
|
||||
@Override
|
||||
public DynamicTrackedRace getExistingTrackedRace(RegattaAndRaceIdentifier raceIdentifier) {
|
||||
|
||||
@@ -169,6 +169,7 @@ public class LeaderboardData extends ExportAction {
|
||||
addNamedElementWithValue(raceElement, "same_day_index", sameDayGroupIndex);
|
||||
raceElement.addContent(createDataConfidenceXML(raceConfidenceAndErrorMessages));
|
||||
|
||||
addNamedElementWithValue(raceElement, "start_type", race.getTrackedLeg(race.getRace().getCourse().getFirstLeg()).getLegType(race.getStartOfRace()).name());
|
||||
addNamedElementWithValue(raceElement, "delay_to_live_in_millis", race.getDelayToLiveInMillis());
|
||||
|
||||
addNamedElementWithValue(raceElement, "timepoint_of_last_event_as_millis", handleValue(race.getTimePointOfLastEvent()));
|
||||
@@ -180,8 +181,10 @@ public class LeaderboardData extends ExportAction {
|
||||
addNamedElementWithValue(raceElement, "start_of_tracking_time_as_millis", handleValue(race.getStartOfTracking()));
|
||||
addNamedElementWithValue(raceElement, "end_of_tracking_time_as_millis", handleValue(race.getEndOfTracking()));
|
||||
|
||||
LineLengthAndAdvantage start = race.getStartLine(race.getStartOfTracking());
|
||||
addNamedElementWithValue(raceElement, "start_line_length_in_meters", start.getLength().getMeters());
|
||||
|
||||
addNamedElementWithValue(raceElement, "course_length_in_meters", race.getCourseLength().getMeters());
|
||||
|
||||
raceElement.addContent(createWindXML("wind_", race.getAverageWindSpeedWithConfidence(/*resolutionInMillis*/ 5*60*1000)));
|
||||
|
||||
final List<Competitor> allCompetitors = race.getCompetitorsFromBestToWorst(/*timePoint*/ race.getEndOfRace());
|
||||
@@ -191,7 +194,6 @@ public class LeaderboardData extends ExportAction {
|
||||
for (Competitor competitor : allCompetitors) {
|
||||
Element competitorElement = createCompetitorXML(competitor, leaderboard, /*shortVersion*/ true, null);
|
||||
Element competitorRaceDataElement = new Element("competitor_race_data");
|
||||
LineLengthAndAdvantage start = race.getStartLine(race.getStartOfTracking());
|
||||
addNamedElementWithValue(competitorRaceDataElement, "distance_to_start_line_on_race_start_in_meters", race.getDistanceToStartLine(competitor, race.getStartOfRace()).getMeters());
|
||||
addNamedElementWithValue(competitorRaceDataElement, "distance_from_starboard_side_of_start_line_when_passing_start_in_meters", race.getDistanceFromStarboardSideOfStartLineWhenPassingStart(competitor).getMeters());
|
||||
addNamedElementWithValue(competitorRaceDataElement, "speed_when_crossing_start_line_in_knots", race.getSpeedWhenCrossingStartLine(competitor).getKnots());
|
||||
|
||||
Reference in new issue
Block a user