Merge remote-tracking branch 'origin/master'

This commit is contained in:
fmittag committed 2012-06-06 18:59:09 +02:00
commit 2e0bcaa63d
32 files changed
+633 -216

No files matched your search

@@ -6,6 +6,7 @@ import com.mongodb.DBObject;
import com.sap.sailing.domain.base.Event;
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.common.RaceIdentifier;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.leaderboard.Leaderboard;
@@ -22,26 +23,26 @@ import com.sap.sailing.domain.tracking.WindTrack;
public interface DomainObjectFactory {
WindTrack loadWindTrack(Regatta regatta, RaceDefinition race, WindSource windSource, long millisecondsOverWhichToAverage);
Leaderboard loadLeaderboard(String name);
Leaderboard loadLeaderboard(String name, RegattaRegistry regattaRegistry);
Iterable<Leaderboard> getAllLeaderboards();
Iterable<Leaderboard> getAllLeaderboards(RegattaRegistry regattaRegistry);
RaceIdentifier loadRaceIdentifier(DBObject dbObject);
/**
* @return The group with the name <code>name</code>, or <code>null</code> if no such group exists.
*/
LeaderboardGroup loadLeaderboardGroup(String name);
LeaderboardGroup loadLeaderboardGroup(String name, RegattaRegistry regattaRegistry);
/**
* @return All groups in the database.
*/
Iterable<LeaderboardGroup> getAllLeaderboardGroups();
Iterable<LeaderboardGroup> getAllLeaderboardGroups(RegattaRegistry regattaRegistry);
/**
* @return All leaderboards in the database, which aren't contained by a leaderboard group
*/
Iterable<Leaderboard> getLeaderboardsNotInGroup();
Iterable<Leaderboard> getLeaderboardsNotInGroup(RegattaRegistry regattaRegistry);
Map<? extends WindSource, ? extends WindTrack> loadWindTracks(Regatta regatta, RaceDefinition race,
long millisecondsOverWhichToAverageWind);
@@ -6,9 +6,8 @@ import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.common.WindSource;
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.RegattaLeaderboard;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
@@ -30,7 +29,7 @@ public interface MongoObjectFactory {
* Stores the configuration data of <code>leaderboard</code> in the Mongo DB associated with this
* factory.
*/
void storeFlexibleLeaderboard(FlexibleLeaderboard leaderboard);
void storeLeaderboard(Leaderboard leaderboard);
/**
* Removes the leaderboard named <code>name</code> from the database.
@@ -70,5 +69,4 @@ public interface MongoObjectFactory {
void removeRegatta(Regatta regatta);
void storeRegattaLeaderboard(RegattaLeaderboard result);
}
@@ -1,6 +1,6 @@
package com.sap.sailing.domain.persistence.impl;
import java.util.Comparator;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -8,12 +8,10 @@ import java.util.Map;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.common.MaxPointsReason;
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.ThresholdBasedResultDiscardingRule;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.RaceColumnImpl;
import com.sap.sailing.domain.tracking.TrackedRace;
/**
@@ -23,54 +21,38 @@ import com.sap.sailing.domain.tracking.TrackedRace;
* score corrections are then assigned to the {@link Competitor}s once they show up by
* {@link #addRace(TrackedRace, String, boolean) adding races} to this leaderboard.<p>
*
* TODO This class should be in the impl package. However, in order to temporarily solve bug 595, moving this class
* to the exported package may help. A better solution would involve obtaining this bundle's class loader in
* <code>ObjectInputStreamResolvingAgainstDomainFactory</code> which is able to obtain the class from a non-exported
* package.
* This object registers itself as a {@link RaceColumnListener} on the {@link Leaderboard} at construction time. It
* therefore receives all updates to the linking structure between the leaderboard's {@link RaceColumn}s and the
* {@link TrackedRace}s associated with them and can react accordingly to assign left-over corrections to the
* correct, resolved competitor objects (see {@link #trackedRaceLinked(RaceColumn, Fleet, TrackedRace)}).
*
* @author Axel Uhl (d043530)
*
*/
public class FlexibleLeaderboardImplWithDelayedCarriedPoints extends FlexibleLeaderboardImpl {
private static final long serialVersionUID = -8933075542228571746L;
public class DelayedLeaderboardCorrectionsImpl implements DelayedLeaderboardCorrections, Serializable {
private static final long serialVersionUID = 8824782847677232275L;
private final Map<String, Integer> carriedPointsByCompetitorName;
private final Map<String, Map<RaceColumn, MaxPointsReason>> maxPointsReasonsByCompetitorName;
private final Map<String, Map<RaceColumn, Integer>> correctedScoresByCompetitorName;
private final Map<String, String> displayNamesByCompetitorName;
private final Leaderboard leaderboard;
/**
* A wrapper for {@link RaceColumn} that, when its {@link #setTrackedRace(Fleet, TrackedRace)} method is called,
* additionally calls {@link FlexibleLeaderboardImplWithDelayedCarriedPoints#assignLeftOvers(TrackedRace)}.
*
* @author Axel Uhl (D043530)
*/
private class RaceColumnForDelayedCarriedPoints extends RaceColumnImpl {
private static final long serialVersionUID = -1243132535406059096L;
public RaceColumnForDelayedCarriedPoints(Leaderboard leaderboard, String name, boolean medalRace, Iterable<Fleet> fleets) {
super(name, medalRace, fleets);
}
@Override
public void setTrackedRace(Fleet fleet, TrackedRace trackedRace) {
super.setTrackedRace(fleet, trackedRace);
if (trackedRace != null) {
assignLeftOvers(trackedRace);
}
}
}
public FlexibleLeaderboardImplWithDelayedCarriedPoints(String name, SettableScoreCorrection scoreCorrection,
ThresholdBasedResultDiscardingRule resultDiscardingRule, Comparator<Integer> scoreComparator) {
super(name, scoreCorrection, resultDiscardingRule, scoreComparator);
public DelayedLeaderboardCorrectionsImpl(Leaderboard leaderboard) {
carriedPointsByCompetitorName = new HashMap<String, Integer>();
maxPointsReasonsByCompetitorName = new HashMap<String, Map<RaceColumn,MaxPointsReason>>();
correctedScoresByCompetitorName = new HashMap<String, Map<RaceColumn,Integer>>();
displayNamesByCompetitorName = new HashMap<String, String>();
this.leaderboard = leaderboard;
leaderboard.addRaceColumnListener(this);
}
@Override
public Leaderboard getLeaderboard() {
return leaderboard;
}
private void assertNoTrackedRaceAssociatedYet() {
for (RaceColumn raceColumn : getRaceColumns()) {
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
if (raceColumn.hasTrackedRaces()) {
throw new IllegalStateException("Can't enqueue competitor name-based state while tracked races are already associated with leaderboard");
}
@@ -78,15 +60,12 @@ public class FlexibleLeaderboardImplWithDelayedCarriedPoints extends FlexibleLea
}
@Override
protected RaceColumnImpl createRaceColumn(String columnName, boolean medalRace, Fleet... fleets) {
return new RaceColumnForDelayedCarriedPoints(this, columnName, medalRace, turnNullOrEmptyFleetsIntoDefaultFleet(fleets));
}
public void setCarriedPoints(String competitorName, int carriedPoints) {
assertNoTrackedRaceAssociatedYet();
carriedPointsByCompetitorName.put(competitorName, carriedPoints);
}
@Override
public void setMaxPointsReason(String competitorName, RaceColumn raceColumn, MaxPointsReason maxPointsReason) {
assertNoTrackedRaceAssociatedYet();
Map<RaceColumn, MaxPointsReason> map = maxPointsReasonsByCompetitorName.get(competitorName);
@@ -97,6 +76,7 @@ public class FlexibleLeaderboardImplWithDelayedCarriedPoints extends FlexibleLea
map.put(raceColumn, maxPointsReason);
}
@Override
public void correctScore(String competitorName, RaceColumn raceColumn, int correctedScore) {
assertNoTrackedRaceAssociatedYet();
Map<RaceColumn, Integer> map = correctedScoresByCompetitorName.get(competitorName);
@@ -107,18 +87,6 @@ public class FlexibleLeaderboardImplWithDelayedCarriedPoints extends FlexibleLea
map.put(raceColumn, correctedScore);
}
/**
* Performs the regular {@link FlexibleLeaderboardImpl#addRace(TrackedRace, String, boolean)} and then checks if
* there are any carried points etc. left over to assign to the competitor objects (see
* {@link #assignLeftOvers(TrackedRace)}).
*/
@Override
public RaceColumn addRace(TrackedRace race, String columnName, boolean medalRace, Fleet fleet) {
RaceColumn result = super.addRace(race, columnName, medalRace, fleet);
assignLeftOvers(race);
return result;
}
/**
* Checks if there are any carried points, max points reasons or corrected scores left over that may now receive
* their competitor record. If so, {@link #setCarriedPoints(com.sap.sailing.domain.base.Competitor, int)},
@@ -135,7 +103,7 @@ public class FlexibleLeaderboardImplWithDelayedCarriedPoints extends FlexibleLea
for (Iterator<Map.Entry<String, Integer>> carryEntryIter = carriedPointsByCompetitorName.entrySet().iterator(); carryEntryIter.hasNext(); ) {
Map.Entry<String, Integer> carryEntry = carryEntryIter.next();
if (competitorsByName.containsKey(carryEntry.getKey())) {
setCarriedPoints(competitorsByName.get(carryEntry.getKey()), carryEntry.getValue());
leaderboard.setCarriedPoints(competitorsByName.get(carryEntry.getKey()), carryEntry.getValue());
carryEntryIter.remove();
}
}
@@ -144,7 +112,7 @@ public class FlexibleLeaderboardImplWithDelayedCarriedPoints extends FlexibleLea
java.util.Map.Entry<String, Map<RaceColumn, MaxPointsReason>> maxPointsReasonEntries = maxPointsReasonsEntryIter.next();
if (competitorsByName.containsKey(maxPointsReasonEntries.getKey())) {
for (Map.Entry<RaceColumn, MaxPointsReason> maxPointsReasonEntry : maxPointsReasonEntries.getValue().entrySet()) {
getScoreCorrection().setMaxPointsReason(competitorsByName.get(maxPointsReasonEntries.getKey()),
leaderboard.getScoreCorrection().setMaxPointsReason(competitorsByName.get(maxPointsReasonEntries.getKey()),
maxPointsReasonEntry.getKey(), maxPointsReasonEntry.getValue());
}
maxPointsReasonsEntryIter.remove();
@@ -155,7 +123,7 @@ public class FlexibleLeaderboardImplWithDelayedCarriedPoints extends FlexibleLea
java.util.Map.Entry<String, Map<RaceColumn, Integer>> correctedScoresEntries = correctedScoresEntryIter.next();
if (competitorsByName.containsKey(correctedScoresEntries.getKey())) {
for (java.util.Map.Entry<RaceColumn, Integer> correctedScoreEntry : correctedScoresEntries.getValue().entrySet()) {
getScoreCorrection().correctScore(competitorsByName.get(correctedScoresEntries.getKey()),
leaderboard.getScoreCorrection().correctScore(competitorsByName.get(correctedScoresEntries.getKey()),
correctedScoreEntry.getKey(), correctedScoreEntry.getValue());
}
correctedScoresEntryIter.remove();
@@ -165,14 +133,24 @@ public class FlexibleLeaderboardImplWithDelayedCarriedPoints extends FlexibleLea
displayNamesByCompetitorName.entrySet().iterator(); displayNamesEntryIter.hasNext();) {
java.util.Map.Entry<String, String> displayNamesEntry = displayNamesEntryIter.next();
if (competitorsByName.containsKey(displayNamesEntry.getKey())) {
setDisplayName(competitorsByName.get(displayNamesEntry.getKey()), displayNamesEntry.getValue());
leaderboard.setDisplayName(competitorsByName.get(displayNamesEntry.getKey()), displayNamesEntry.getValue());
displayNamesEntryIter.remove();
}
}
}
@Override
public void setDisplayName(String competitorName, String displayName) {
assertNoTrackedRaceAssociatedYet();
displayNamesByCompetitorName.put(competitorName, displayName);
}
@Override
public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
assignLeftOvers(trackedRace);
}
@Override
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
}
}
@@ -24,6 +24,7 @@ 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.base.SpeedWithBearing;
import com.sap.sailing.domain.base.Venue;
@@ -39,6 +40,7 @@ import com.sap.sailing.domain.common.Color;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.WindSource;
@@ -48,12 +50,17 @@ import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.RGBColor;
import com.sap.sailing.domain.common.impl.WindSourceImpl;
import com.sap.sailing.domain.common.impl.WindSourceWithAdditionalID;
import com.sap.sailing.domain.leaderboard.DelayedLeaderboardCorrections;
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.RegattaLeaderboard;
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
@@ -131,14 +138,14 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
@Override
public Leaderboard loadLeaderboard(String name) {
public Leaderboard loadLeaderboard(String name, RegattaRegistry regattaRegistry) {
DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name());
Leaderboard result = null;
try {
BasicDBObject query = new BasicDBObject();
query.put(FieldNames.LEADERBOARD_NAME.name(), name);
for (DBObject o : leaderboardCollection.find(query)) {
result = loadLeaderboard(o);
result = loadLeaderboard(o, regattaRegistry);
}
} catch (Throwable t) {
// something went wrong during DB access; report, then use empty new wind track
@@ -149,12 +156,12 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
@Override
public Iterable<Leaderboard> getAllLeaderboards() {
public Iterable<Leaderboard> getAllLeaderboards(RegattaRegistry regattaRegistry) {
DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name());
Set<Leaderboard> result = new HashSet<Leaderboard>();
try {
for (DBObject o : leaderboardCollection.find()) {
result.add(loadLeaderboard(o));
result.add(loadLeaderboard(o, regattaRegistry));
}
} catch (Throwable t) {
// something went wrong during DB access; report, then use empty new wind track
@@ -164,18 +171,43 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return result;
}
private Leaderboard loadLeaderboard(DBObject o) {
/**
* If the DBObject has a field {@link FieldNames#REGATTA_NAME} then the object represents a {@link RegattaLeaderboard}. Otherwise,
* a {@link FlexibleLeaderboard} will be loaded.
*/
private Leaderboard loadLeaderboard(DBObject dbLeaderboard, RegattaRegistry regattaRegistry) {
SettableScoreCorrection scoreCorrection = new ScoreCorrectionImpl();
BasicDBList dbDiscardIndexResultsStartingWithHowManyRaces = (BasicDBList) o.get(FieldNames.LEADERBOARD_DISCARDING_THRESHOLDS.name());
BasicDBList dbDiscardIndexResultsStartingWithHowManyRaces = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_DISCARDING_THRESHOLDS.name());
int[] discardIndexResultsStartingWithHowManyRaces = new int[dbDiscardIndexResultsStartingWithHowManyRaces.size()];
int i=0;
for (Object discardingThresholdAsObject : dbDiscardIndexResultsStartingWithHowManyRaces) {
discardIndexResultsStartingWithHowManyRaces[i++] = (Integer) discardingThresholdAsObject;
}
ThresholdBasedResultDiscardingRule resultDiscardingRule = new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces);
FlexibleLeaderboardImplWithDelayedCarriedPoints result = new FlexibleLeaderboardImplWithDelayedCarriedPoints(
(String) o.get(FieldNames.LEADERBOARD_NAME.name()), scoreCorrection, resultDiscardingRule, new LowerScoreIsBetter());
BasicDBList dbRaceColumns = (BasicDBList) o.get(FieldNames.LEADERBOARD_COLUMNS.name());
String regattaName = (String) dbLeaderboard.get(FieldNames.REGATTA_NAME.name());
Leaderboard result;
if (regattaName == null) {
result = loadFlexibleLeaderboard(dbLeaderboard, scoreCorrection, resultDiscardingRule);
} else {
result = loadRegattaLeaderboard(regattaName, dbLeaderboard, scoreCorrection, resultDiscardingRule, regattaRegistry);
}
DelayedLeaderboardCorrections loadedLeaderboardCorrections = new DelayedLeaderboardCorrectionsImpl(result);
loadLeaderboardCorrections(dbLeaderboard, loadedLeaderboardCorrections);
return result;
}
private RegattaLeaderboard loadRegattaLeaderboard(String regattaName, DBObject dbLeaderboard, SettableScoreCorrection scoreCorrection,
ThresholdBasedResultDiscardingRule resultDiscardingRule, RegattaRegistry regattaRegistry) {
Regatta regatta = regattaRegistry.getRegatta(new RegattaName(regattaName));
RegattaLeaderboard result = new RegattaLeaderboardImpl(regatta, scoreCorrection, resultDiscardingRule, new LowerScoreIsBetter());
return result;
}
private FlexibleLeaderboard loadFlexibleLeaderboard(DBObject dbLeaderboard,
SettableScoreCorrection scoreCorrection, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
FlexibleLeaderboardImpl result = new FlexibleLeaderboardImpl(
(String) dbLeaderboard.get(FieldNames.LEADERBOARD_NAME.name()), scoreCorrection, resultDiscardingRule, new LowerScoreIsBetter());
BasicDBList dbRaceColumns = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_COLUMNS.name());
// For a FlexibleLeaderboard, fleets are owned by the leaderboard's RaceColumn objects. We need to manage them here:
Map<String, Fleet> fleetsByName = new HashMap<String, Fleet>();
for (Object dbRaceColumnAsObject : dbRaceColumns) {
@@ -211,39 +243,42 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
raceColumn.setRaceIdentifier(fleetsByName.get(e.getKey()), e.getValue());
}
}
DBObject carriedPoints = (DBObject) o.get(FieldNames.LEADERBOARD_CARRIED_POINTS.name());
return result;
}
private void loadLeaderboardCorrections(DBObject dbLeaderboard, DelayedLeaderboardCorrections correctionsToUpdate) {
DBObject carriedPoints = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_CARRIED_POINTS.name());
if (carriedPoints != null) {
for (String competitorName : carriedPoints.keySet()) {
Integer carriedPointsForCompetitor = (Integer) carriedPoints.get(competitorName);
if (carriedPointsForCompetitor != null) {
result.setCarriedPoints(MongoUtils.unescapeDollarAndDot(competitorName), carriedPointsForCompetitor);
correctionsToUpdate.setCarriedPoints(MongoUtils.unescapeDollarAndDot(competitorName), carriedPointsForCompetitor);
}
}
}
DBObject dbScoreCorrection = (DBObject) o.get(FieldNames.LEADERBOARD_SCORE_CORRECTIONS.name());
DBObject dbScoreCorrection = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_SCORE_CORRECTIONS.name());
for (String raceName : dbScoreCorrection.keySet()) {
DBObject dbScoreCorrectionForRace = (DBObject) dbScoreCorrection.get(raceName);
for (String competitorName : dbScoreCorrectionForRace.keySet()) {
RaceColumn raceColumn = result.getRaceColumnByName(raceName);
RaceColumn raceColumn = correctionsToUpdate.getLeaderboard().getRaceColumnByName(raceName);
DBObject dbScoreCorrectionForCompetitorInRace = (DBObject) dbScoreCorrectionForRace.get(competitorName);
if (dbScoreCorrectionForCompetitorInRace.containsField(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name())) {
result.setMaxPointsReason(MongoUtils.unescapeDollarAndDot(competitorName), raceColumn, MaxPointsReason
correctionsToUpdate.setMaxPointsReason(MongoUtils.unescapeDollarAndDot(competitorName), raceColumn, MaxPointsReason
.valueOf((String) dbScoreCorrectionForCompetitorInRace
.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON.name())));
}
if (dbScoreCorrectionForCompetitorInRace.containsField(FieldNames.LEADERBOARD_CORRECTED_SCORE.name())) {
result.correctScore(MongoUtils.unescapeDollarAndDot(competitorName), raceColumn, (Integer) dbScoreCorrectionForCompetitorInRace
correctionsToUpdate.correctScore(MongoUtils.unescapeDollarAndDot(competitorName), raceColumn, (Integer) dbScoreCorrectionForCompetitorInRace
.get(FieldNames.LEADERBOARD_CORRECTED_SCORE.name()));
}
}
}
DBObject competitorDisplayNames = (DBObject) o.get(FieldNames.LEADERBOARD_COMPETITOR_DISPLAY_NAMES.name());
DBObject competitorDisplayNames = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_COMPETITOR_DISPLAY_NAMES.name());
if (competitorDisplayNames != null) {
for (String escapedCompetitorName : competitorDisplayNames.keySet()) {
result.setDisplayName(MongoUtils.unescapeDollarAndDot(escapedCompetitorName), (String) competitorDisplayNames.get(escapedCompetitorName));
correctionsToUpdate.setDisplayName(MongoUtils.unescapeDollarAndDot(escapedCompetitorName), (String) competitorDisplayNames.get(escapedCompetitorName));
}
}
return result;
}
/**
@@ -274,14 +309,14 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
@Override
public LeaderboardGroup loadLeaderboardGroup(String name) {
public LeaderboardGroup loadLeaderboardGroup(String name, RegattaRegistry regattaRegistry) {
DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name());
LeaderboardGroup leaderboardGroup = null;
try {
BasicDBObject query = new BasicDBObject();
query.put(FieldNames.LEADERBOARD_GROUP_NAME.name(), name);
leaderboardGroup = loadLeaderboardGroup(leaderboardGroupCollection.findOne(query));
leaderboardGroup = loadLeaderboardGroup(leaderboardGroupCollection.findOne(query), regattaRegistry);
} catch (Throwable t) {
logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboard group "+name+".");
logger.throwing(DomainObjectFactoryImpl.class.getName(), "loadLeaderboardGroup", t);
@@ -291,13 +326,13 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
@Override
public Iterable<LeaderboardGroup> getAllLeaderboardGroups() {
public Iterable<LeaderboardGroup> getAllLeaderboardGroups(RegattaRegistry regattaRegistry) {
DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name());
Set<LeaderboardGroup> leaderboardGroups = new HashSet<LeaderboardGroup>();
try {
for (DBObject o : leaderboardGroupCollection.find()) {
leaderboardGroups.add(loadLeaderboardGroup(o));
leaderboardGroups.add(loadLeaderboardGroup(o, regattaRegistry));
}
} catch (Throwable t) {
logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboard groups.");
@@ -307,7 +342,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
return leaderboardGroups;
}
private LeaderboardGroup loadLeaderboardGroup(DBObject o) {
private LeaderboardGroup loadLeaderboardGroup(DBObject o, RegattaRegistry regattaRegistry) {
DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name());
String name = (String) o.get(FieldNames.LEADERBOARD_GROUP_NAME.name());
@@ -318,14 +353,14 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
for (Object object : dbLeaderboardIds) {
ObjectId dbLeaderboardId = (ObjectId) object;
DBObject dbLeaderboard = leaderboardCollection.findOne(dbLeaderboardId);
leaderboards.add(loadLeaderboard(dbLeaderboard));
leaderboards.add(loadLeaderboard(dbLeaderboard, regattaRegistry));
}
return new LeaderboardGroupImpl(name, description, leaderboards);
}
@Override
public Iterable<Leaderboard> getLeaderboardsNotInGroup() {
public Iterable<Leaderboard> getLeaderboardsNotInGroup(RegattaRegistry regattaRegistry) {
DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name());
Set<Leaderboard> result = new HashSet<Leaderboard>();
try {
@@ -333,7 +368,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
BasicDBObject query = new BasicDBObject("$where", "function() { return db." + CollectionNames.LEADERBOARD_GROUPS.name() + ".find({ "
+ FieldNames.LEADERBOARD_GROUP_LEADERBOARDS.name() + ": this._id }).count() == 0; }");
for (DBObject o : leaderboardCollection.find(query)) {
result.add(loadLeaderboard(o));
result.add(loadLeaderboard(o, regattaRegistry));
}
} catch (Throwable t) {
logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load leaderboards.");
@@ -452,7 +487,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
DBCollection regattaCollection = database.getCollection(CollectionNames.REGATTAS.name());
DBObject dbRegatta = regattaCollection.findOne(query);
Regatta result = loadRegatta(dbRegatta, trackedRegattaRegistry);
assert result.getName().equals(name);
assert result == null || result.getName().equals(name);
return result;
}
@@ -126,7 +126,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
}
@Override
public void storeFlexibleLeaderboard(FlexibleLeaderboard leaderboard) {
public void storeLeaderboard(Leaderboard leaderboard) {
DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name());
try {
leaderboardCollection.ensureIndex(FieldNames.LEADERBOARD_NAME.name());
@@ -135,29 +135,46 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
logger.throwing(MongoObjectFactoryImpl.class.getName(), "storeLeaderboard", npe);
}
BasicDBObject query = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName());
BasicDBObject result = new BasicDBObject();
result.put(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName());
BasicDBObject dbLeaderboard = new BasicDBObject();
dbLeaderboard.put(FieldNames.LEADERBOARD_NAME.name(), leaderboard.getName());
if (leaderboard instanceof FlexibleLeaderboard) {
storeFlexibleLeaderboard((FlexibleLeaderboard) leaderboard, dbLeaderboard);
} else if (leaderboard instanceof RegattaLeaderboard) {
storeRegattaLeaderboard((RegattaLeaderboard) leaderboard, dbLeaderboard);
}
storeLeaderboardCorrections(leaderboard, dbLeaderboard);
leaderboardCollection.update(query, dbLeaderboard, /* upsrt */ true, /* multi */ false);
}
private void storeRegattaLeaderboard(RegattaLeaderboard leaderboard, DBObject dbLeaderboard) {
dbLeaderboard.put(FieldNames.REGATTA_NAME.name(), leaderboard.getRegatta().getName());
}
private void storeFlexibleLeaderboard(FlexibleLeaderboard leaderboard, BasicDBObject dbLeaderboard) {
BasicDBList dbRaceColumns = new BasicDBList();
result.put(FieldNames.LEADERBOARD_COLUMNS.name(), dbRaceColumns);
dbLeaderboard.put(FieldNames.LEADERBOARD_COLUMNS.name(), dbRaceColumns);
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
BasicDBObject dbRaceColumn = storeRaceColumn(raceColumn);
dbRaceColumns.add(dbRaceColumn);
}
}
private void storeLeaderboardCorrections(Leaderboard leaderboard, BasicDBObject dbLeaderboard) {
if (leaderboard.hasCarriedPoints()) {
BasicDBObject dbCarriedPoints = new BasicDBObject();
result.put(FieldNames.LEADERBOARD_CARRIED_POINTS.name(), dbCarriedPoints);
dbLeaderboard.put(FieldNames.LEADERBOARD_CARRIED_POINTS.name(), dbCarriedPoints);
for (Competitor competitor : leaderboard.getCompetitors()) {
dbCarriedPoints.put(MongoUtils.escapeDollarAndDot(competitor.getName()), leaderboard.getCarriedPoints(competitor));
}
}
BasicDBObject dbScoreCorrections = new BasicDBObject();
storeScoreCorrections(leaderboard, dbScoreCorrections);
result.put(FieldNames.LEADERBOARD_SCORE_CORRECTIONS.name(), dbScoreCorrections);
dbLeaderboard.put(FieldNames.LEADERBOARD_SCORE_CORRECTIONS.name(), dbScoreCorrections);
BasicDBList dbResultDiscardingThresholds = new BasicDBList();
for (int threshold : leaderboard.getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces()) {
dbResultDiscardingThresholds.add(threshold);
}
result.put(FieldNames.LEADERBOARD_DISCARDING_THRESHOLDS.name(), dbResultDiscardingThresholds);
dbLeaderboard.put(FieldNames.LEADERBOARD_DISCARDING_THRESHOLDS.name(), dbResultDiscardingThresholds);
BasicDBObject competitorDisplayNames = new BasicDBObject();
for (Competitor competitor : leaderboard.getCompetitors()) {
String displayNameForCompetitor = leaderboard.getDisplayName(competitor);
@@ -165,14 +182,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
competitorDisplayNames.put(MongoUtils.escapeDollarAndDot(competitor.getName()), displayNameForCompetitor);
}
}
result.put(FieldNames.LEADERBOARD_COMPETITOR_DISPLAY_NAMES.name(), competitorDisplayNames);
leaderboardCollection.update(query, result, /* upsrt */ true, /* multi */ false);
}
@Override
public void storeRegattaLeaderboard(RegattaLeaderboard result) {
// TODO Auto-generated method stub
dbLeaderboard.put(FieldNames.LEADERBOARD_COMPETITOR_DISPLAY_NAMES.name(), competitorDisplayNames);
}
private BasicDBObject storeRaceColumn(RaceColumn raceColumn) {
@@ -258,15 +268,6 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
leaderboardGroupCollection.update(query, result, true, false);
}
private void storeLeaderboard(Leaderboard leaderboard) {
if (leaderboard instanceof FlexibleLeaderboard) {
storeFlexibleLeaderboard((FlexibleLeaderboard) leaderboard);
} else if (leaderboard instanceof RegattaLeaderboard) {
storeRegattaLeaderboard((RegattaLeaderboard) leaderboard);
}
}
@Override
public void removeLeaderboardGroup(String groupName) {
DBCollection leaderboardGroupCollection = database.getCollection(CollectionNames.LEADERBOARD_GROUPS.name());
@@ -10,7 +10,7 @@ import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
public abstract class AbstractLeaderboardTest {
protected CompetitorImpl createCompetitor(String competitorName) {
public static CompetitorImpl createCompetitor(String competitorName) {
return new CompetitorImpl(123, competitorName, new TeamImpl("STG", Collections.singleton(
new PersonImpl(competitorName, new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous "+competitorName)),
@@ -6,6 +6,7 @@ import java.util.NavigableSet;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.RegattaListener;
import com.sap.sailing.domain.base.Leg;
@@ -362,6 +363,18 @@ public class MockedTrackedRace implements DynamicTrackedRace {
// TODO Auto-generated method stub
return false;
}
@Override
public void addRaceColumnListener(RaceColumnListener listener) {
// TODO Auto-generated method stub
}
@Override
public void removeRaceColumnListener(RaceColumnListener listener) {
// TODO Auto-generated method stub
}
};
}
@@ -16,12 +16,19 @@ import com.sap.sailing.domain.tracking.TrackedRace;
* {@link RaceColumn} therefore provides access to the {@link TrackedRace}s by {@link Fleet} and by {@link Competitor}.
* The {@link TrackedRace}s represent the data of a race. Over the life time of this object it can be assigned one or more
* {@link TrackedRace}s which then act(s) as data provider to this column. If no tracked race has been assigned, the
* scores reported by this column will all default to zero.
* scores reported by this column will all default to zero.<p>
*
* A {@link RaceColumnListener} can be {@link #addRaceColumnListener added} to receive notifications about tracked races
* being {@link #setTrackedRace(Fleet, TrackedRace) linked} to this column or unlinked from this column.
*
* @author Axel Uhl (D043530)
*
*/
public interface RaceColumn extends Named {
void addRaceColumnListener(RaceColumnListener listener);
void removeRaceColumnListener(RaceColumnListener listener);
/**
* @return the fleets for each of which this column has a single race and therefore optionally a {@link TrackedRace}, in
* ascending order; best fleets first
@@ -0,0 +1,9 @@
package com.sap.sailing.domain.base;
import com.sap.sailing.domain.tracking.TrackedRace;
public interface RaceColumnListener {
void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace);
void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace);
}
@@ -72,4 +72,8 @@ public interface Regatta extends Named {
* the data of this regatta needs to be maintained persistently.
*/
boolean isPersistent();
void addRaceColumnListener(RaceColumnListener listener);
void removeRaceColumnListener(RaceColumnListener listener);
}
@@ -0,0 +1,17 @@
package com.sap.sailing.domain.base;
import java.util.ConcurrentModificationException;
import com.sap.sailing.domain.common.RegattaIdentifier;
public interface RegattaRegistry {
/**
* @return a thread-safe copy of the regattas 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<Regatta> getAllRegattas();
Regatta getRegattaByName(String name);
Regatta getRegatta(RegattaIdentifier regattaIdentifier);
}
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.base;
import com.sap.sailing.domain.common.Named;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
/**
@@ -10,7 +11,10 @@ import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
* race column have to be run in this round. For example, if the 49er regatta has so many competitors that they cannot
* all start in one race, the qualification round can be split into two {@link Fleet}s, "Yellow" and "Blue," each
* getting their separate races. Fleet assignment may or may not vary. This usually depends on the round's
* characteristics of having ordered or unordered fleets.
* characteristics of having ordered or unordered fleets.<p>
*
* To receive notifications when {@link TrackedRace tracked races} are linked to or unlinked from any of this series'
* columns, {@link RaceColumnListener}s can be added / removed.
*
* @author Axel Uhl (D043530)
*
@@ -55,4 +59,8 @@ public interface Series extends Named {
* Sets this series' regatta.
*/
void setRegatta(Regatta regatta);
void addRaceColumnListener(RaceColumnListener listener);
void removeRaceColumnListener(RaceColumnListener listener);
}
@@ -1,11 +1,16 @@
package com.sap.sailing.domain.base.impl;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.common.impl.Util.Pair;
@@ -17,11 +22,40 @@ public abstract class AbstractRaceColumn implements RaceColumn {
private final Map<Fleet, TrackedRace> trackedRaces;
private String name;
private final Map<Fleet, RaceIdentifier> raceIdentifiers;
private transient Set<RaceColumnListener> listeners;
public AbstractRaceColumn(String name) {
this.name = name;
this.trackedRaces = new HashMap<Fleet, TrackedRace>();
this.raceIdentifiers = new HashMap<Fleet, RaceIdentifier>();
this.listeners = new HashSet<RaceColumnListener>();
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
listeners = new HashSet<RaceColumnListener>();
}
@Override
public void addRaceColumnListener(RaceColumnListener listener) {
listeners.add(listener);
}
@Override
public void removeRaceColumnListener(RaceColumnListener listener) {
listeners.remove(listener);
}
private void notifyListenersAboutTrackedRaceLinked(Fleet fleet, TrackedRace trackedRace) {
for (RaceColumnListener listener : listeners) {
listener.trackedRaceLinked(this, fleet, trackedRace);
}
}
private void notifyListenersAboutTrackedRaceUnlinked(Fleet fleet, TrackedRace trackedRace) {
for (RaceColumnListener listener : listeners) {
listener.trackedRaceUnlinked(this, fleet, trackedRace);
}
}
@Override
@@ -31,8 +65,14 @@ public abstract class AbstractRaceColumn implements RaceColumn {
@Override
public void setTrackedRace(Fleet fleet, TrackedRace trackedRace) {
this.trackedRaces.put(fleet, trackedRace);
TrackedRace previouslyLinkedRace = this.trackedRaces.put(fleet, trackedRace);
this.setRaceIdentifier(fleet, trackedRace == null ? null : trackedRace.getRaceIdentifier());
if (previouslyLinkedRace != null) {
notifyListenersAboutTrackedRaceUnlinked(fleet, previouslyLinkedRace);
}
if (trackedRace != null) {
notifyListenersAboutTrackedRaceLinked(fleet, trackedRace);
}
}
@Override
@@ -99,4 +139,9 @@ public abstract class AbstractRaceColumn implements RaceColumn {
}
return null;
}
@Override
public String toString() {
return getName();
}
}
@@ -10,6 +10,9 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.RegattaListener;
@@ -17,15 +20,17 @@ import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.common.RegattaIdentifier;
import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.impl.NamedImpl;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
public class RegattaImpl extends NamedImpl implements Regatta {
public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListener {
private static final Logger logger = Logger.getLogger(RegattaImpl.class.getName());
private static final long serialVersionUID = 6509564189552478869L;
private final Set<RaceDefinition> races;
private final BoatClass boatClass;
private transient Set<RegattaListener> regattaListeners;
private final Iterable<? extends Series> series;
private transient Set<RaceColumnListener> raceColumnListeners;
/**
* Regattas may be constructed as implicit default regattas in which case they won't need to be stored
@@ -40,7 +45,6 @@ public class RegattaImpl extends NamedImpl implements Regatta {
/**
* Constructs a regatta with a single default series with empty race column list, and a single default fleet which
* is not {@link #isPersistent() marked for persistence}.
* @param trackedRegattaRegistry TODO
*/
public RegattaImpl(String baseName, BoatClass boatClass, TrackedRegattaRegistry trackedRegattaRegistry) {
this(baseName, boatClass, Collections.singletonList(new SeriesImpl("Default", /* isMedal */false, Collections
@@ -57,10 +61,12 @@ public class RegattaImpl extends NamedImpl implements Regatta {
super(baseName+(boatClass==null?"":" ("+boatClass.getName()+")"));
races = new HashSet<RaceDefinition>();
regattaListeners = new HashSet<RegattaListener>();
raceColumnListeners = new HashSet<RaceColumnListener>();
this.boatClass = boatClass;
this.series = series;
for (Series s : series) {
s.setRegatta(this);
s.addRaceColumnListener(this);
}
this.persistent = persistent;
}
@@ -84,6 +90,7 @@ public class RegattaImpl extends NamedImpl implements Regatta {
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
regattaListeners = new HashSet<>();
raceColumnListeners = new HashSet<RaceColumnListener>();
}
@Override
@@ -182,4 +189,36 @@ public class RegattaImpl extends NamedImpl implements Regatta {
}
}
@Override
public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
notifyListenersAboutTrackedRaceLinked(raceColumn, fleet, trackedRace);
}
@Override
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
}
@Override
public void addRaceColumnListener(RaceColumnListener listener) {
raceColumnListeners.add(listener);
}
@Override
public void removeRaceColumnListener(RaceColumnListener listener) {
raceColumnListeners.remove(listener);
}
private void notifyListenersAboutTrackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
for (RaceColumnListener listener : raceColumnListeners) {
listener.trackedRaceLinked(raceColumn, fleet, trackedRace);
}
}
private void notifyListenersAboutTrackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
for (RaceColumnListener listener : raceColumnListeners) {
listener.trackedRaceUnlinked(raceColumn, fleet, trackedRace);
}
}
}
@@ -1,29 +1,44 @@
package com.sap.sailing.domain.base.impl;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnInSeries;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.common.impl.NamedImpl;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
public class SeriesImpl extends NamedImpl implements Series {
public class SeriesImpl extends NamedImpl implements Series, RaceColumnListener {
private static final long serialVersionUID = -1640404303144907381L;
private final Map<String, Fleet> fleetsByName;
private final List<Fleet> fleetsInAscendingOrder;
private final List<RaceColumnInSeries> raceColumns;
private boolean isMedal;
private Regatta regatta;
private transient Set<RaceColumnListener> listeners;
/**
* @param fleets must be non-empty
*/
public SeriesImpl(String name, boolean isMedal, Iterable<? extends Fleet> fleets, Iterable<String> raceColumnNames,
TrackedRegattaRegistry trackedRegattaRegistry) {
super(name);
if (fleets == null || Util.isEmpty(fleets)) {
throw new IllegalArgumentException("Series must have at least one fleet");
}
this.fleetsByName = new HashMap<String, Fleet>();
for (Fleet fleet : fleets) {
this.fleetsByName.put(fleet.getName(), fleet);
@@ -31,12 +46,39 @@ public class SeriesImpl extends NamedImpl implements Series {
fleetsInAscendingOrder = new ArrayList<Fleet>(fleetsByName.values());
Collections.sort(fleetsInAscendingOrder);
List<RaceColumnInSeries> myRaceColumns = new ArrayList<RaceColumnInSeries>();
for (String raceColumnName : raceColumnNames) {
RaceColumnInSeriesImpl raceColumn = new RaceColumnInSeriesImpl(raceColumnName, this, trackedRegattaRegistry);
myRaceColumns.add(raceColumn);
}
this.raceColumns = myRaceColumns;
this.isMedal = isMedal;
this.listeners = new HashSet<RaceColumnListener>();
for (String raceColumnName : raceColumnNames) {
addRaceColumn(raceColumnName, trackedRegattaRegistry);
}
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
listeners = new HashSet<RaceColumnListener>();
}
@Override
public void addRaceColumnListener(RaceColumnListener listener) {
listeners.add(listener);
}
@Override
public void removeRaceColumnListener(RaceColumnListener listener) {
listeners.remove(listener);
}
private void notifyListenersAboutTrackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
for (RaceColumnListener listener : listeners) {
listener.trackedRaceLinked(raceColumn, fleet, trackedRace);
}
}
private void notifyListenersAboutTrackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
for (RaceColumnListener listener : listeners) {
listener.trackedRaceUnlinked(raceColumn, fleet, trackedRace);
}
}
@Override
@@ -65,11 +107,17 @@ public class SeriesImpl extends NamedImpl implements Series {
@Override
public RaceColumnInSeries addRaceColumn(String raceColumnName, TrackedRegattaRegistry trackedRegattaRegistry) {
final RaceColumnInSeriesImpl result = new RaceColumnInSeriesImpl(raceColumnName, this, trackedRegattaRegistry);
final RaceColumnInSeriesImpl result = createRaceColumn(raceColumnName, trackedRegattaRegistry);
result.addRaceColumnListener(this);
raceColumns.add(result);
return result;
}
private RaceColumnInSeriesImpl createRaceColumn(String raceColumnName, TrackedRegattaRegistry trackedRegattaRegistry) {
RaceColumnInSeriesImpl result = new RaceColumnInSeriesImpl(raceColumnName, this, trackedRegattaRegistry);
return result;
}
@Override
public void moveRaceColumnUp(String raceColumnName) {
// start at second element because first can't be moved up
@@ -101,6 +149,7 @@ public class SeriesImpl extends NamedImpl implements Series {
RaceColumnInSeries rc = getRaceColumnByName(raceColumnName);
if (rc != null) {
raceColumns.remove(rc);
rc.removeRaceColumnListener(this);
}
}
@@ -123,4 +172,16 @@ public class SeriesImpl extends NamedImpl implements Series {
public void setIsMedal(boolean isMedal) {
this.isMedal = isMedal;
}
@Override
public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
notifyListenersAboutTrackedRaceLinked(raceColumn, fleet, trackedRace);
}
@Override
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
}
}
@@ -0,0 +1,28 @@
package com.sap.sailing.domain.leaderboard;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.common.MaxPointsReason;
/**
* For a {@link Leaderboard}, captures corrections such as {@link ScoreCorrection}s or display names for competitors. It
* does so by keying the corrections by competitor names which can work as a competitor "ID," e.g., in a persistence layer.
* When for any of the leaderboards columns a new {@link TrackedRace} is linked, the not yet resolved corrections are matched
* against the tracked race's competitor names and resolved. For this to work, this object needs to be registered as
* {@link RaceColumnListener} with the object owning all {@link RaceColumn}s for the leaderboard. The type of object
* may vary depending on the concrete leaderboard type.
*
* @author Axel Uhl (D043530)
*
*/
public interface DelayedLeaderboardCorrections extends RaceColumnListener {
void correctScore(String competitorName, RaceColumn raceColumn, int correctedScore);
void setCarriedPoints(String competitorName, int carriedPoints);
void setMaxPointsReason(String competitorName, RaceColumn raceColumn, MaxPointsReason maxPointsReason);
void setDisplayName(String competitorName, String displayName);
Leaderboard getLeaderboard();
}
@@ -2,7 +2,7 @@ package com.sap.sailing.domain.leaderboard;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.tracking.TrackedRace;
@@ -6,6 +6,7 @@ import java.util.Map;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.Named;
@@ -224,4 +225,8 @@ public interface Leaderboard extends Named {
public void setResultDiscardingRule(ThresholdBasedResultDiscardingRule discardingRule);
Competitor getCompetitorByIdAsString(String idAsString);
void addRaceColumnListener(RaceColumnListener listener);
void removeRaceColumnListener(RaceColumnListener listener);
}
@@ -1,5 +1,7 @@
package com.sap.sailing.domain.leaderboard.impl;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -13,6 +15,7 @@ import java.util.Set;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.TimePoint;
@@ -25,7 +28,17 @@ import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
import com.sap.sailing.domain.tracking.TrackedRace;
public abstract class AbstractLeaderboardImpl implements Leaderboard {
/**
* Abstract leaderboard implementation that already knows about carried points, competitor display name re-keying,
* score corrections and result discarding rules. It manages a set of registered {@link RaceColumnListener}s and
* is itself one. All events received this way are forwarded to all {@link RaceColumnListener}s subscribed. This can
* be used to subscribe a concrete leaderboard implementation to the data structure providing the actual race columns
* in order to be notified whenever the set of {@link TrackedRace}s attached to the leaderboard changes.
*
* @author Axel Uhl (D043530)
*
*/
public abstract class AbstractLeaderboardImpl implements Leaderboard, RaceColumnListener {
private static final long serialVersionUID = -328091952760083438L;
/**
@@ -51,6 +64,8 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
private final Comparator<Integer> scoreComparator;
private transient Set<RaceColumnListener> raceColumnListeners;
/**
* A leaderboard entry representing a snapshot of a cell at a given time point for a single race/competitor.
*
@@ -110,6 +125,12 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
this.displayNames = new HashMap<Competitor, String>();
this.resultDiscardingRule = resultDiscardingRule;
this.scoreComparator = scoreComparator;
this.raceColumnListeners = new HashSet<RaceColumnListener>();
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
raceColumnListeners = new HashSet<RaceColumnListener>();
}
@Override
@@ -406,4 +427,37 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
protected Comparator<? super Competitor> getTotalRankComparator(TimePoint timePoint) {
return new LeaderboardTotalRankComparator(this, timePoint, scoreComparator);
}
@Override
public void addRaceColumnListener(RaceColumnListener listener) {
raceColumnListeners.add(listener);
}
@Override
public void removeRaceColumnListener(RaceColumnListener listener) {
raceColumnListeners.remove(listener);
}
@Override
public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
notifyListenersAboutTrackedRaceLinked(raceColumn, fleet, trackedRace);
}
@Override
public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
}
private void notifyListenersAboutTrackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
for (RaceColumnListener listener : raceColumnListeners) {
listener.trackedRaceLinked(raceColumn, fleet, trackedRace);
}
}
private void notifyListenersAboutTrackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {
for (RaceColumnListener listener : raceColumnListeners) {
listener.trackedRaceUnlinked(raceColumn, fleet, trackedRace);
}
}
}
@@ -9,6 +9,7 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
@@ -18,7 +19,10 @@ import com.sap.sailing.domain.tracking.TrackedRace;
/**
* A leaderboard implementation that allows users to flexibly configure which columns exist. No constraints need to be observed regarding
* the columns belonging to the same regatta or even boat class.
* the columns belonging to the same regatta or even boat class.<p>
*
* The flexible leaderboard listens as {@link RaceColumnListener} on all its {@link RaceColumn}s and forwards all events to
* all {@link RaceColumnListener}s subscribed with this leaderboard.
*
* @author Axel Uhl (D043530)
*
@@ -64,6 +68,7 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
logger.severe(msg);
} else {
column = createRaceColumn(name, medalRace, fleets);
column.addRaceColumnListener(this);
races.add(column);
}
return column;
@@ -87,7 +92,9 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
@Override
public void removeRaceColumn(String columnName) {
races.remove(getRaceColumnByName(columnName));
final FlexibleRaceColumn raceColumn = getRaceColumnByName(columnName);
races.remove(raceColumn);
raceColumn.removeRaceColumnListener(this);
}
@Override
@@ -100,9 +107,10 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
FlexibleRaceColumn column = getRaceColumnByName(columnName);
if (column == null) {
column = createRaceColumn(columnName, medalRace);
column.addRaceColumnListener(this);
races.add(column);
}
column.setTrackedRace(fleet, race);
column.setTrackedRace(fleet, race); // triggers listeners because this object was registered above as race column listener on the column
return column;
}
@@ -174,4 +182,5 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
race.setIsMedalRace(isMedalRace);
}
}
}
@@ -7,6 +7,7 @@ import java.util.List;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnInSeries;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.impl.RaceColumnInSeriesImpl;
@@ -15,7 +16,10 @@ import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
/**
* A leaderboard that is based on the definition of a {@link Regatta} with its {@link Series} and {@link Fleet}.
* A leaderboard that is based on the definition of a {@link Regatta} with its {@link Series} and {@link Fleet}. The regatta
* leaderboard listens to its {@link Regatta} as a {@link RaceColumnListener} and forwards all link/unlink events for
* {@link TrackedRace}s being linked to / unlinked from race columns to all {@link RaceColumnListener}s subscribed with
* this leaderboard.
*
* @author Axel Uhl (D043530)
*
@@ -28,6 +32,7 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R
ThresholdBasedResultDiscardingRule resultDiscardingRule, Comparator<Integer> scoreComparator) {
super(scoreCorrection, resultDiscardingRule, scoreComparator);
this.regatta = regatta;
regatta.addRaceColumnListener(this);
}
@Override
@@ -62,24 +62,20 @@ public class LeaderboardEntryPoint extends AbstractEntryPoint {
if (tvModeParam != null) {
Timer timer = new Timer(PlayModes.Replay, 1000l);
timer.setLivePlayDelayInMillis(5000l);
TVViewPanel tvViewPanel = new TVViewPanel(sailingService, stringMessages, this, leaderboardName,
userAgentType, null, timer, logoAndTitlePanel, mainPanel);
contentScrollPanel.setWidget(tvViewPanel);
} else {
Timer timer = new Timer(PlayModes.Replay, /* delayBetweenAutoAdvancesInMilliseconds */3000l);
timer.setLivePlayDelayInMillis(5000l);
LeaderboardPanel leaderboardPanel = new LeaderboardPanel(sailingService, new AsyncActionsExecutor(),
LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(null, null, null, /* autoExpandFirstRace */ false),
/* preSelectedRace */ null, new CompetitorSelectionModel(/* hasMultiSelection */ true), timer,
leaderboardName, leaderboardGroupName,
LeaderboardEntryPoint.this, stringMessages, userAgentType);
contentScrollPanel.setWidget(leaderboardPanel);
breadcrumbPanel = createBreadcrumbPanel();
}
if (breadcrumbPanel != null) {
mainPanel.addNorth(breadcrumbPanel, 30);
}
@@ -1460,13 +1460,17 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
@Override
public Pair<Integer, Integer> updateLeaderboardMaxPointsReason(String leaderboardName, String competitorIdAsString, String raceColumnName,
MaxPointsReason maxPointsReason, Date date) throws NoWindException {
return getService().apply(new UpdateLeaderboardMaxPointsReason(leaderboardName, raceColumnName, competitorIdAsString, maxPointsReason, date));
return getService().apply(
new UpdateLeaderboardMaxPointsReason(leaderboardName, raceColumnName, competitorIdAsString,
maxPointsReason, new MillisecondsTimePoint(date)));
}
@Override
public Triple<Integer, Integer, Boolean> updateLeaderboardScoreCorrection(String leaderboardName,
String competitorIdAsString, String columnName, Integer correctedScore, Date date) throws NoWindException {
return getService().apply(new UpdateLeaderboardScoreCorrection(leaderboardName, columnName, competitorIdAsString, correctedScore, date));
return getService().apply(
new UpdateLeaderboardScoreCorrection(leaderboardName, columnName, competitorIdAsString, correctedScore,
new MillisecondsTimePoint(date)));
}
@Override
@@ -14,7 +14,10 @@ Require-Bundle: com.mongodb.driver;bundle-version="2.6.2",
org.eclipse.osgi,
com.sap.sailing.domain.persistence,
com.sap.sailing.server,
com.sap.sailing.domain.common
com.sap.sailing.domain.common,
com.sap.sailing.expeditionconnector,
org.json.simple;bundle-version="1.1.0",
com.sap.sailing.domain.swisstimingadapter
Import-Package: junit.framework;version="4.8.1",
org.junit;version="4.8.1"
@@ -4,36 +4,53 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.junit.Test;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CourseArea;
import com.sap.sailing.domain.base.DomainFactory;
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.RaceColumnInSeries;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.Venue;
import com.sap.sailing.domain.base.impl.CourseAreaImpl;
import com.sap.sailing.domain.base.impl.EventImpl;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.base.impl.RaceColumnInSeriesImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SeriesImpl;
import com.sap.sailing.domain.base.impl.VenueImpl;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.leaderboard.Leaderboard;
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.test.AbstractLeaderboardTest;
import com.sap.sailing.domain.test.MockedTrackedRaceWithFixedRank;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn;
import com.sap.sailing.server.operationaltransformation.UpdateLeaderboardMaxPointsReason;
public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest {
@Test
@@ -64,13 +81,86 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
}
}
@Test
public void testLoadStoreSimpleRegattaLeaderboard() {
RacingEventService res = new RacingEventServiceImpl(getMongoService());
final int numberOfQualifyingRaces = 5;
final int numberOfFinalRaces = 7;
final String regattaBaseName = "Kieler Woche";
BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
Regatta regattaProxy = createRegatta(regattaBaseName, boatClass, /* persistent */ true);
Regatta regatta = res.createRegatta(regattaProxy.getBaseName(), regattaProxy.getBoatClass().getName(),
regattaProxy.getSeries(), regattaProxy.isPersistent());
addRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regatta);
res.addRegattaLeaderboard(regatta.getRegattaIdentifier(), new int[] { 3, 5 });
DomainObjectFactory dof = MongoFactory.INSTANCE.getDomainObjectFactory(getMongoService());
Regatta loadedRegatta = dof.loadRegatta(regatta.getName(), /* trackedRegattaRegistry */ null);
assertNotNull(loadedRegatta);
assertEquals(regatta.getName(), loadedRegatta.getName());
assertEquals(Util.size(regatta.getSeries()), Util.size(loadedRegatta.getSeries()));
Leaderboard loadedLeaderboard = dof.loadLeaderboard(regatta.getName(), res);
assertNotNull(loadedLeaderboard);
assertTrue(loadedLeaderboard instanceof RegattaLeaderboard);
RegattaLeaderboard loadedRegattaLeaderboard = (RegattaLeaderboard) loadedLeaderboard;
assertSame(regatta, loadedRegattaLeaderboard.getRegatta());
}
@Test
public void testLoadStoreRegattaLeaderboardWithScoreCorrections() {
Competitor hasso = AbstractLeaderboardTest.createCompetitor("Dr. Hasso Plattner");
final TrackedRace q2YellowTrackedRace = new MockedTrackedRaceWithFixedRank(hasso, /* rank */ 1, /* started */ false) {
private static final long serialVersionUID = 1234L;
@Override
public RegattaAndRaceIdentifier getRaceIdentifier() {
return new RegattaNameAndRaceName("Kieler Woche (29erXX)", "Yellow Race 2");
}
};
RacingEventService res = new RacingEventServiceImpl(getMongoService()) {
@Override
public TrackedRace getExistingTrackedRace(RaceIdentifier raceIdentifier) {
return q2YellowTrackedRace;
}
};
final int numberOfQualifyingRaces = 5;
final int numberOfFinalRaces = 7;
final String regattaBaseName = "Kieler Woche";
BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
Regatta regattaProxy = createRegatta(regattaBaseName, boatClass, /* persistent */ true);
Regatta regatta = res.createRegatta(regattaProxy.getBaseName(), regattaProxy.getBoatClass().getName(),
regattaProxy.getSeries(), regattaProxy.isPersistent());
addRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regatta);
RegattaLeaderboard regattaLeaderboard = res.addRegattaLeaderboard(regatta.getRegattaIdentifier(), new int[] { 3, 5 });
final RaceColumnInSeries q2 = regatta.getSeriesByName("Qualifying").getRaceColumnByName("Q2");
final Fleet yellow = q2.getFleetByName("Yellow");
res.apply(new ConnectTrackedRaceToLeaderboardColumn(regattaLeaderboard.getName(), q2.getName(), yellow
.getName(), q2YellowTrackedRace.getRaceIdentifier()));
res.apply(new UpdateLeaderboardMaxPointsReason(regattaLeaderboard.getName(), q2.getName(), hasso.getId().toString(),
MaxPointsReason.DNF, MillisecondsTimePoint.now()));
RacingEventService resForLoading = new RacingEventServiceImpl(getMongoService());
Regatta loadedRegatta = resForLoading.getRegattaByName("Kieler Woche (29erXX)");
assertNotNull(loadedRegatta);
assertEquals(regatta.getName(), loadedRegatta.getName());
assertEquals(Util.size(regatta.getSeries()), Util.size(loadedRegatta.getSeries()));
Leaderboard loadedLeaderboard = resForLoading.getLeaderboardByName(loadedRegatta.getName());
assertNotNull(loadedLeaderboard);
assertEquals(regattaLeaderboard.getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces().length,
loadedLeaderboard.getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces().length);
assertTrue(Arrays.equals(regattaLeaderboard.getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces(),
loadedLeaderboard.getResultDiscardingRule().getDiscardIndexResultsStartingWithHowManyRaces()));
assertTrue(loadedLeaderboard instanceof RegattaLeaderboard);
RegattaLeaderboard loadedRegattaLeaderboard = (RegattaLeaderboard) loadedLeaderboard;
assertSame(loadedRegatta, loadedRegattaLeaderboard.getRegatta());
}
@Test
public void testLoadStoreSimpleRegatta() {
final int numberOfQualifyingRaces = 5;
final int numberOfFinalRaces = 7;
final String regattaBaseName = "Kieler Woche";
BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
Regatta regatta = createRegatta(numberOfQualifyingRaces, numberOfFinalRaces, regattaBaseName, boatClass);
Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regattaBaseName,
boatClass, /* persistent */false);
MongoObjectFactory mof = MongoFactory.INSTANCE.getMongoObjectFactory(getMongoService());
mof.storeRegatta(regatta);
@@ -94,7 +184,8 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
final int numberOfFinalRaces = 7;
final String regattaBaseName = "Kieler Woche";
BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
Regatta regatta = createRegatta(numberOfQualifyingRaces, numberOfFinalRaces, regattaBaseName, boatClass);
Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regattaBaseName, boatClass,
/* persistent */ false);
MongoObjectFactory mof = MongoFactory.INSTANCE.getMongoObjectFactory(getMongoService());
mof.storeRegatta(regatta);
@@ -132,7 +223,8 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
final int numberOfFinalRaces = 7;
final String regattaBaseName = "Kieler Woche";
BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("29erXX", /* typicallyStartsUpwind */ true);
Regatta regatta = createRegatta(numberOfQualifyingRaces, numberOfFinalRaces, regattaBaseName, boatClass);
Regatta regatta = createRegattaAndAddRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regattaBaseName, boatClass,
/* persistent */ false);
Series qualifyingSeries = regatta.getSeries().iterator().next();
RaceColumn q2 = qualifyingSeries.getRaceColumnByName("Q2");
final RegattaNameAndRaceName q2TrackedRaceIdentifier = new RegattaNameAndRaceName(regatta.getName(), "Q2 TracTrac");
@@ -151,43 +243,61 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest
assertNull(loadedQualifyingSeries.getRaceColumnByName("Q2").getRaceIdentifier(loadedQualifyingSeries.getFleetByName("Blue")));
}
private Regatta createRegatta(final int numberOfQualifyingRaces, final int numberOfFinalRaces,
final String regattaBaseName, BoatClass boatClass) {
private Regatta createRegattaAndAddRaceColumns(final int numberOfQualifyingRaces, final int numberOfFinalRaces,
final String regattaBaseName, BoatClass boatClass, boolean persistent) {
Regatta regatta = createRegatta(regattaBaseName, boatClass, persistent);
addRaceColumns(numberOfQualifyingRaces, numberOfFinalRaces, regatta);
return regatta;
}
private void addRaceColumns(final int numberOfQualifyingRaces, final int numberOfFinalRaces, Regatta regatta) {
List<String> finalRaceColumnNames = new ArrayList<String>();
for (int i=1; i<=numberOfFinalRaces; i++) {
finalRaceColumnNames.add("F"+i);
}
List<String> qualifyingRaceColumnNames = new ArrayList<String>();
for (int i=1; i<=numberOfQualifyingRaces; i++) {
qualifyingRaceColumnNames.add("Q"+i);
}
List<String> medalRaceColumnNames = new ArrayList<String>();
medalRaceColumnNames.add("M");
addRaceColumnsToSeries(qualifyingRaceColumnNames, regatta.getSeriesByName("Qualifying"));
addRaceColumnsToSeries(finalRaceColumnNames, regatta.getSeriesByName("Final"));
addRaceColumnsToSeries(medalRaceColumnNames, regatta.getSeriesByName("Medal"));
}
private Regatta createRegatta(final String regattaBaseName, BoatClass boatClass, boolean persistent) {
List<String> emptyRaceColumnNames = Collections.emptyList();
List<Series> series = new ArrayList<Series>();
// -------- qualifying series ------------
List<Fleet> qualifyingFleets = new ArrayList<Fleet>();
qualifyingFleets.add(new FleetImpl("Yellow"));
qualifyingFleets.add(new FleetImpl("Blue"));
List<String> qualifyingRaceColumnNames = new ArrayList<String>();
for (int i=1; i<=numberOfQualifyingRaces; i++) {
qualifyingRaceColumnNames.add("Q"+i);
}
Series qualifyingSeries = new SeriesImpl("Qualifying", /* isMedal */false, qualifyingFleets,
qualifyingRaceColumnNames, /* trackedRegattaRegistry */ null);
emptyRaceColumnNames, /* trackedRegattaRegistry */ null);
series.add(qualifyingSeries);
// -------- final series ------------
List<Fleet> finalFleets = new ArrayList<Fleet>();
finalFleets.add(new FleetImpl("Gold", 1));
finalFleets.add(new FleetImpl("Silver", 2));
List<String> finalRaceColumnNames = new ArrayList<String>();
for (int i=1; i<=numberOfFinalRaces; i++) {
finalRaceColumnNames.add("F"+i);
}
Series finalSeries = new SeriesImpl("Final", /* isMedal */ false, finalFleets, finalRaceColumnNames, /* trackedRegattaRegistry */ null);
Series finalSeries = new SeriesImpl("Final", /* isMedal */ false, finalFleets, emptyRaceColumnNames, /* trackedRegattaRegistry */ null);
series.add(finalSeries);
// ------------ medal --------------
List<Fleet> medalFleets = new ArrayList<Fleet>();
medalFleets.add(new FleetImpl("Medal"));
List<String> medalRaceColumnNames = new ArrayList<String>();
medalRaceColumnNames.add("M");
Series medalSeries = new SeriesImpl("Medal", /* isMedal */ true, medalFleets, medalRaceColumnNames, /* trackedRegattaRegistry */ null);
Series medalSeries = new SeriesImpl("Medal", /* isMedal */ true, medalFleets, emptyRaceColumnNames, /* trackedRegattaRegistry */ null);
series.add(medalSeries);
Regatta regatta = new RegattaImpl(regattaBaseName, boatClass, series, /* persistent */ false);
Regatta regatta = new RegattaImpl(regattaBaseName, boatClass, series, persistent);
return regatta;
}
private void addRaceColumnsToSeries(List<String> finalRaceColumnNames, Series finalSeries) {
for (String raceColumnName : finalRaceColumnNames) {
finalSeries.addRaceColumn(raceColumnName, /* trackedRegattaRegistry */ null);
}
}
}
@@ -59,7 +59,7 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl(groupName, groupDescription, leaderboards);
mongoObjectFactory.storeLeaderboardGroup(leaderboardGroup);
final LeaderboardGroup loadedLeaderboardGroup = domainObjectFactory.loadLeaderboardGroup(groupName);
final LeaderboardGroup loadedLeaderboardGroup = domainObjectFactory.loadLeaderboardGroup(groupName, /* regattaRegistry */ null);
Assert.assertEquals(groupName, loadedLeaderboardGroup.getName());
Assert.assertEquals(groupDescription, loadedLeaderboardGroup.getDescription());
@@ -99,11 +99,11 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter()),
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[2], new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter()) };
mongoObjectFactory.storeFlexibleLeaderboard(ungroupedLeaderboards[0]);
mongoObjectFactory.storeFlexibleLeaderboard(ungroupedLeaderboards[1]);
mongoObjectFactory.storeFlexibleLeaderboard(ungroupedLeaderboards[2]);
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[0]);
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[1]);
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[2]);
Iterable<Leaderboard> loadedUngroupedLeaderboards = domainObjectFactory.getLeaderboardsNotInGroup();
Iterable<Leaderboard> loadedUngroupedLeaderboards = domainObjectFactory.getLeaderboardsNotInGroup(/* regattaRegistry */ null);
Assert.assertTrue(loadedUngroupedLeaderboards.iterator().hasNext());
@@ -147,7 +147,7 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
mongoObjectFactory.renameLeaderboard(leaderboardName, newLeaderboardName);
leaderboard.setName(newLeaderboardName);
LeaderboardGroup loadedGroup = domainObjectFactory.loadLeaderboardGroup(groupName);
LeaderboardGroup loadedGroup = domainObjectFactory.loadLeaderboardGroup(groupName, /* regattaRegistry */ null);
String loadedLeaderboardName = loadedGroup.getLeaderboards().iterator().next().getName();
Assert.assertEquals(newLeaderboardName, loadedLeaderboardName);
@@ -155,16 +155,16 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
final String regattaName = "Event";
final String raceName = "Race";
leaderboard.getRaceColumnByName(columnName).setRaceIdentifier(fleet, new RegattaNameAndRaceName(regattaName, raceName));
mongoObjectFactory.storeFlexibleLeaderboard(leaderboard);
mongoObjectFactory.storeLeaderboard(leaderboard);
//Check if the leaderboard updated correctly
final Leaderboard loadedLeaderboard = domainObjectFactory.loadLeaderboard(leaderboard.getName());
final Leaderboard loadedLeaderboard = domainObjectFactory.loadLeaderboard(leaderboard.getName(), /* regattaRegistry */ null);
final RaceColumn loadedRaceColumnByName = loadedLeaderboard.getRaceColumnByName(columnName);
Fleet loadedFleet = loadedRaceColumnByName.getFleetByName(fleet.getName());
Assert.assertEquals(race.getRaceIdentifier(fleet), loadedRaceColumnByName.getRaceIdentifier(loadedFleet));
// Check if the group received the changes
loadedGroup = domainObjectFactory.loadLeaderboardGroup(groupName);
loadedGroup = domainObjectFactory.loadLeaderboardGroup(groupName, /* regattaRegistry */ null);
final RaceColumn loadedRaceColumnFromGroupByName = loadedGroup.getLeaderboards().iterator().next().getRaceColumnByName(columnName);
Fleet loadedGroupFleet = loadedRaceColumnFromGroupByName.getFleetByName(fleet.getName());
RaceIdentifier loadedIdentifier = loadedRaceColumnFromGroupByName.getRaceIdentifier(loadedGroupFleet);
@@ -37,8 +37,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
new MongoObjectFactoryImpl(db).storeFlexibleLeaderboard(leaderboard);
Leaderboard loadedLeaderboard = new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName);
new MongoObjectFactoryImpl(db).storeLeaderboard(leaderboard);
Leaderboard loadedLeaderboard = new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName, /* regattaRegistry */ null);
assertEquals(leaderboardName, loadedLeaderboard.getName());
assertTrue(Arrays.equals(discardIndexResultsStartingWithHowManyRaces, loadedLeaderboard.getResultDiscardingRule()
.getDiscardIndexResultsStartingWithHowManyRaces()));
@@ -56,8 +56,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
TrackedRace raceWithOneCompetitor = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
leaderboard.addRace(raceWithOneCompetitor, raceColumnName, /* medalRace */ false, leaderboard.getFleet(null));
leaderboard.setCarriedPoints(competitor, carriedPointsForWolfgangHunger);
new MongoObjectFactoryImpl(db).storeFlexibleLeaderboard(leaderboard);
FlexibleLeaderboard loadedLeaderboard = (FlexibleLeaderboard) new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName);
new MongoObjectFactoryImpl(db).storeLeaderboard(leaderboard);
FlexibleLeaderboard loadedLeaderboard = (FlexibleLeaderboard) new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName, /* regattaRegistry */ null);
// attach tracked race to leaderboard to ensure that competitor object is assigned properly
loadedLeaderboard.addRace(raceWithOneCompetitor, raceColumnName, /* medalRace, ignored */ false, leaderboard.getFleet(null));
assertEquals(leaderboardName, loadedLeaderboard.getName());
@@ -83,8 +83,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
leaderboard.addRace(raceWithOneCompetitor1, raceColumnName1, /* medalRace */ false, leaderboard.getFleet(null));
leaderboard.addRace(raceWithOneCompetitor2, raceColumnName2, /* medalRace */ true, leaderboard.getFleet(null));
leaderboard.getScoreCorrection().correctScore(competitor, leaderboard.getRaceColumnByName(raceColumnName1), correctedPoints);
new MongoObjectFactoryImpl(db).storeFlexibleLeaderboard(leaderboard);
FlexibleLeaderboard loadedLeaderboard = (FlexibleLeaderboard) new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName);
new MongoObjectFactoryImpl(db).storeLeaderboard(leaderboard);
FlexibleLeaderboard loadedLeaderboard = (FlexibleLeaderboard) new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName, /* regattaRegistry */ null);
// attach tracked race to leaderboard to ensure that competitor object is assigned properly
RaceColumn loadedColumn1 = loadedLeaderboard.addRace(raceWithOneCompetitor1, raceColumnName1, /* medalRace, ignored */ false, leaderboard.getFleet(null));
RaceColumn loadedColumn2 = loadedLeaderboard.addRace(raceWithOneCompetitor2, raceColumnName2, /* medalRace, ignored */ false, leaderboard.getFleet(null));
@@ -109,8 +109,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
leaderboard.addRace(raceWithOneCompetitor1, raceColumnName1, /* medalRace */ false, leaderboard.getFleet(null));
leaderboard.addRace(raceWithOneCompetitor2, raceColumnName2, /* medalRace */ true, leaderboard.getFleet(null));
leaderboard.getScoreCorrection().setMaxPointsReason(competitor, leaderboard.getRaceColumnByName(raceColumnName2), maxPointsReason);
new MongoObjectFactoryImpl(db).storeFlexibleLeaderboard(leaderboard);
FlexibleLeaderboard loadedLeaderboard = (FlexibleLeaderboard) new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName);
new MongoObjectFactoryImpl(db).storeLeaderboard(leaderboard);
FlexibleLeaderboard loadedLeaderboard = (FlexibleLeaderboard) new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName, /* regattaRegistry */ null);
// attach tracked race to leaderboard to ensure that competitor object is assigned properly
RaceColumn loadedColumn1 = loadedLeaderboard.addRace(raceWithOneCompetitor1, raceColumnName1, /* medalRace, ignored */ false, leaderboard.getFleet(null));
RaceColumn loadedColumn2 = loadedLeaderboard.addRace(raceWithOneCompetitor2, raceColumnName2, /* medalRace, ignored */ false, leaderboard.getFleet(null));
@@ -137,8 +137,8 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
leaderboard.addRace(raceWithOneCompetitor2, raceColumnName2, /* medalRace */ true, leaderboard.getFleet(null));
leaderboard.getScoreCorrection().correctScore(competitor, leaderboard.getRaceColumnByName(raceColumnName1), correctedPoints);
leaderboard.getScoreCorrection().setMaxPointsReason(competitor, leaderboard.getRaceColumnByName(raceColumnName2), maxPointsReason);
new MongoObjectFactoryImpl(db).storeFlexibleLeaderboard(leaderboard);
FlexibleLeaderboard loadedLeaderboard = (FlexibleLeaderboard) new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName);
new MongoObjectFactoryImpl(db).storeLeaderboard(leaderboard);
FlexibleLeaderboard loadedLeaderboard = (FlexibleLeaderboard) new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName, /* regattaRegistry */ null);
// attach tracked race to leaderboard to ensure that competitor object is assigned properly
RaceColumn loadedColumn1 = loadedLeaderboard.addRace(raceWithOneCompetitor1, raceColumnName1, /* medalRace, ignored */ false, leaderboard.getFleet(null));
RaceColumn loadedColumn2 = loadedLeaderboard.addRace(raceWithOneCompetitor2, raceColumnName2, /* medalRace, ignored */ false, leaderboard.getFleet(null));
@@ -20,6 +20,7 @@ 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.RaceIdentifier;
@@ -67,20 +68,10 @@ import com.sap.sailing.expeditionconnector.ExpeditionListener;
* @author Axel Uhl (d043530)
*
*/
public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetcher, RaceFetcher {
/**
* @return a thread-safe copy of the regattas 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<Regatta> getAllRegattas();
Regatta getRegattaByName(String name);
public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetcher, RegattaRegistry, RaceFetcher {
@Override
Regatta getRegatta(RegattaName regattaName);
Regatta getRegatta(RegattaIdentifier regattaIdentifier);
@Override
RaceDefinition getRace(RegattaAndRaceIdentifier raceIdentifier);
@@ -20,8 +20,8 @@ import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import com.mongodb.MongoException;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
@@ -35,6 +35,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.Util.Triple;
import com.sap.sailing.domain.common.impl.WindSourceImpl;
import com.sap.sailing.domain.persistence.MongoFactory;
import com.sap.sailing.domain.persistence.MongoWindStoreFactory;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
@@ -337,8 +338,10 @@ public class AdminApp extends Servlet {
try {
TimePoint timePoint = getTimePoint(req, PARAM_NAME_TIME, PARAM_NAME_TIME_MILLIS, MillisecondsTimePoint.now());
Wind wind = new WindImpl(p, timePoint, speed);
final DynamicTrackedRace trackedRace = getService().getOrCreateTrackedRegatta(regatta).getTrackedRace(race);
trackedRace.recordWind(wind, trackedRace.getWindSources(WindSourceType.WEB).iterator().next());
final DynamicTrackedRace trackedRace = getService().getOrCreateTrackedRegatta(regatta).getExistingTrackedRace(race);
if (trackedRace != null) {
trackedRace.recordWind(wind, new WindSourceImpl(WindSourceType.WEB));
}
} catch (InvalidDateException ex) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Couldn't parse time specification " + ex.getMessage());
}
@@ -199,8 +199,8 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
// Add one default leaderboard that aggregates all races currently tracked by this service.
// This is more for debugging purposes than for anything else.
addFlexibleLeaderboard(DefaultLeaderboardName.DEFAULT_LEADERBOARD_NAME, new int[] { 5, 8 });
loadStoredLeaderboardsAndGroups();
loadStoredRegattas();
loadStoredLeaderboardsAndGroups();
loadStoredEvents();
}
@@ -222,14 +222,14 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
private void loadStoredLeaderboardsAndGroups() {
// Loading all leaderboard groups and the contained leaderboards
for (LeaderboardGroup leaderboardGroup : domainObjectFactory.getAllLeaderboardGroups()) {
for (LeaderboardGroup leaderboardGroup : domainObjectFactory.getAllLeaderboardGroups(this)) {
leaderboardGroupsByName.put(leaderboardGroup.getName(), leaderboardGroup);
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
leaderboardsByName.put(leaderboard.getName(), leaderboard);
}
}
// Loading the remaining leaderboards
for (Leaderboard leaderboard : domainObjectFactory.getLeaderboardsNotInGroup()) {
for (Leaderboard leaderboard : domainObjectFactory.getLeaderboardsNotInGroup(this)) {
leaderboardsByName.put(leaderboard.getName(), leaderboard);
}
}
@@ -244,7 +244,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
}
leaderboardsByName.put(name, result);
}
mongoObjectFactory.storeFlexibleLeaderboard(result);
mongoObjectFactory.storeLeaderboard(result);
return result;
}
@@ -261,7 +261,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
}
leaderboardsByName.put(result.getName(), result);
}
mongoObjectFactory.storeRegattaLeaderboard(result);
mongoObjectFactory.storeLeaderboard(result);
} else {
logger.warning("Cannot find regatta "+regattaIdentifier+". Hence, cannot create regatta leaderboard for it.");
}
@@ -347,13 +347,13 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
@Override
public void updateStoredFlexibleLeaderboard(FlexibleLeaderboard leaderboard) {
mongoObjectFactory.storeFlexibleLeaderboard(leaderboard);
mongoObjectFactory.storeLeaderboard(leaderboard);
syncGroupsAfterLeaderboardChange(leaderboard, true);
}
@Override
public void updateStoredRegattaLeaderboard(RegattaLeaderboard leaderboard) {
mongoObjectFactory.storeRegattaLeaderboard(leaderboard);
mongoObjectFactory.storeLeaderboard(leaderboard);
syncGroupsAfterLeaderboardChange(leaderboard, true);
}
@@ -1,10 +1,7 @@
package com.sap.sailing.server.operationaltransformation;
import java.util.Date;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.TimePoint;
@@ -18,14 +15,14 @@ public class UpdateLeaderboardMaxPointsReason extends AbstractLeaderboardColumnO
private static final long serialVersionUID = -492130952256848047L;
private final String competitorIdAsString;
private final MaxPointsReason newMaxPointsReason;
private final Date date;
private final TimePoint timePoint;
public UpdateLeaderboardMaxPointsReason(String leaderboardName, String columnName, String competitorIdAsString,
MaxPointsReason newMaxPointsReason, Date date) {
MaxPointsReason newMaxPointsReason, TimePoint timePoint) {
super(leaderboardName, columnName);
this.competitorIdAsString = competitorIdAsString;
this.newMaxPointsReason = newMaxPointsReason;
this.date = date;
this.timePoint = timePoint;
}
@Override
@@ -42,7 +39,6 @@ public class UpdateLeaderboardMaxPointsReason extends AbstractLeaderboardColumnO
@Override
public Pair<Integer, Integer> internalApplyTo(RacingEventService toState) throws NoWindException {
TimePoint timePoint = new MillisecondsTimePoint(date);
Leaderboard leaderboard = toState.getLeaderboardByName(getLeaderboardName());
if (leaderboard != null) {
Competitor competitor = leaderboard.getCompetitorByIdAsString(competitorIdAsString);
@@ -1,11 +1,9 @@
package com.sap.sailing.server.operationaltransformation;
import java.util.Date;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.server.RacingEventService;
@@ -15,14 +13,14 @@ public class UpdateLeaderboardScoreCorrection extends AbstractLeaderboardColumnO
private static final long serialVersionUID = -977025759476022993L;
private final String competitorIdAsString;
private final Integer correctedScore;
private final Date date;
private final TimePoint timePoint;
public UpdateLeaderboardScoreCorrection(String leaderboardName, String columnName, String competitorIdAsString,
Integer correctedScore, Date date) {
Integer correctedScore, TimePoint timePoint) {
super(leaderboardName, columnName);
this.competitorIdAsString = competitorIdAsString;
this.correctedScore = correctedScore;
this.date = date;
this.timePoint = timePoint;
}
@Override
@@ -44,7 +42,6 @@ public class UpdateLeaderboardScoreCorrection extends AbstractLeaderboardColumnO
int newTotalPoints;
boolean isScoreCorrected;
if (leaderboard != null) {
MillisecondsTimePoint timePoint = new MillisecondsTimePoint(date);
Competitor competitor = leaderboard.getCompetitorByIdAsString(competitorIdAsString);
if (competitor != null) {
RaceColumn raceColumn = leaderboard.getRaceColumnByName(getColumnName());