mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-29 23:37:10 +00:00
Added LeaderboardType calculation to set it in LeaderboardDTOs
This commit is contained in:
1 parent
20c226930d
commit
f4686bbe85
5 files changed
+638
-609
No files matched your search
+5
@@ -42,6 +42,7 @@ import com.sap.sailing.domain.base.RaceColumnInSeries;
|
||||
import com.sap.sailing.domain.base.RaceColumnListener;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
@@ -1218,6 +1219,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
this.getScoreCorrection() == null ? null : this.getScoreCorrection().getComment(),
|
||||
this.getScoringScheme() == null ? null : this.getScoringScheme().getType(), this
|
||||
.getScoringScheme().isHigherBetter(), new UUIDGenerator(), addOverallDetails);
|
||||
result.type = getLeaderboardType();
|
||||
result.competitors = new ArrayList<CompetitorDTO>();
|
||||
result.name = this.getName();
|
||||
result.competitorDisplayNames = new HashMap<CompetitorDTO, String>();
|
||||
@@ -1929,4 +1931,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
public NumberOfCompetitorsInLeaderboardFetcher getNumberOfCompetitorsInLeaderboardFetcher() {
|
||||
return new NumberOfCompetitorsFetcherImpl();
|
||||
}
|
||||
|
||||
protected abstract LeaderboardType getLeaderboardType();
|
||||
|
||||
}
|
||||
+342
-336
@@ -1,336 +1,342 @@
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
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.AbstractRaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.regattalike.BaseRegattaLikeImpl;
|
||||
import com.sap.sailing.domain.regattalike.FlexibleLeaderboardAsRegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.IsRegattaLike;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeListener;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
/**
|
||||
* 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.<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)
|
||||
*
|
||||
*/
|
||||
public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements FlexibleLeaderboard {
|
||||
private static Logger logger = Logger.getLogger(FlexibleLeaderboardImpl.class.getName());
|
||||
|
||||
protected static final DefaultFleetImpl defaultFleet = new DefaultFleetImpl();
|
||||
private static final long serialVersionUID = -5708971849158747846L;
|
||||
private final List<FlexibleRaceColumn> races;
|
||||
private final ScoringScheme scoringScheme;
|
||||
private String name;
|
||||
private transient RaceLogStore raceLogStore;
|
||||
private CourseArea courseArea;
|
||||
private RaceExecutionOrderProvider raceExecutionOrderProvider;
|
||||
|
||||
/**
|
||||
* @see RegattaLog for the reason why the leaderboard manages a {@code RegattaLog}
|
||||
*/
|
||||
private final IsRegattaLike regattaLikeHelper;
|
||||
|
||||
public FlexibleLeaderboardImpl(String name, ThresholdBasedResultDiscardingRule resultDiscardingRule,
|
||||
ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
this(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
|
||||
name, resultDiscardingRule, scoringScheme, courseArea);
|
||||
}
|
||||
|
||||
public FlexibleLeaderboardImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
String name, ThresholdBasedResultDiscardingRule resultDiscardingRule,
|
||||
ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
super(resultDiscardingRule);
|
||||
this.scoringScheme = scoringScheme;
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("A leaderboard's name must not be null");
|
||||
}
|
||||
this.name = name;
|
||||
this.races = new ArrayList<>();
|
||||
this.raceLogStore = raceLogStore;
|
||||
this.courseArea = courseArea;
|
||||
this.regattaLikeHelper = new BaseRegattaLikeImpl(new FlexibleLeaderboardAsRegattaLikeIdentifier(this), regattaLogStore) {
|
||||
private static final long serialVersionUID = 4082392360832548953L;
|
||||
|
||||
@Override
|
||||
public RaceColumn getRaceColumnByName(String raceColumnName) {
|
||||
return getRaceColumnByName(raceColumnName);
|
||||
}
|
||||
};
|
||||
this.raceExecutionOrderProvider = new RaceExecutionOrderCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialization has to be maintained in lock-step with {@link #writeObject(ObjectOutputStream) serialization}.
|
||||
* When de-serializing, a possibly remote {@link #raceLogStore} is ignored because it is transient. Instead, an
|
||||
* {@link EmptyRaceLogStore} is used for the de-serialized instance. A new {@link RaceLogInformation} is
|
||||
* assembled for this empty race log and applied to all columns.
|
||||
*/
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
ois.defaultReadObject();
|
||||
raceLogStore = EmptyRaceLogStore.INSTANCE;
|
||||
for (RaceColumn column : getRaceColumns()) {
|
||||
column.setRaceLogInformation(raceLogStore, new FlexibleLeaderboardAsRegattaLikeIdentifier(this));
|
||||
}
|
||||
}
|
||||
|
||||
protected Object readResolve() throws ObjectStreamException {
|
||||
raceExecutionOrderProvider.triggerUpdate();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param newName must not be <code>null</code>
|
||||
*/
|
||||
public void setName(String newName) {
|
||||
if (newName == null) {
|
||||
throw new IllegalArgumentException("A leaderboard's name must not be null");
|
||||
}
|
||||
this.name = newName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceColumn addRace(TrackedRace race, String columnName, boolean medalRace) {
|
||||
FlexibleRaceColumn column = addRaceColumn(columnName, medalRace, /* logAlreadyExistingColumn */false);
|
||||
column.setTrackedRace(defaultFleet, race); // triggers listeners because this object was registered above as
|
||||
// race column listener on the column
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexibleRaceColumn addRaceColumn(String name, boolean medalRace) {
|
||||
return addRaceColumn(name, medalRace, /* logAlreadyExistingColumn */true);
|
||||
}
|
||||
|
||||
private FlexibleRaceColumn addRaceColumn(String name, boolean medalRace, boolean logAlreadyExistingColumn) {
|
||||
FlexibleRaceColumn column = getRaceColumnByName(name);
|
||||
if (column != null) {
|
||||
if (logAlreadyExistingColumn) {
|
||||
final String msg = "Trying to create race column with duplicate name " + name + " in leaderboard " + getName();
|
||||
logger.severe(msg);
|
||||
}
|
||||
} else {
|
||||
column = createRaceColumn(name, medalRace);
|
||||
column.addRaceColumnListener(this);
|
||||
races.add(column);
|
||||
column.setRaceLogInformation(raceLogStore, new FlexibleLeaderboardAsRegattaLikeIdentifier(this));
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(column);
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexibleRaceColumn getRaceColumnByName(String columnName) {
|
||||
return (FlexibleRaceColumn) super.getRaceColumnByName(columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fleet getFleet(String fleetName) {
|
||||
Fleet result;
|
||||
if (fleetName == null) {
|
||||
result = defaultFleet;
|
||||
} else {
|
||||
result = super.getFleet(fleetName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRaceColumn(String columnName) {
|
||||
final FlexibleRaceColumn raceColumn = getRaceColumnByName(columnName);
|
||||
if (raceColumn != null) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
raceLogStore.removeRaceLog(raceColumn.getRaceLogIdentifier(fleet));
|
||||
if (raceColumn.getTrackedRace(fleet) != null) {
|
||||
raceColumn.getTrackedRace(fleet).detachRaceExecutionOrderProvider(raceExecutionOrderProvider);
|
||||
}
|
||||
}
|
||||
races.remove(raceColumn);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(raceColumn);
|
||||
raceColumn.removeRaceColumnListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RaceColumn> getRaceColumns() {
|
||||
final Iterable<RaceColumn> result;
|
||||
if (races != null) {
|
||||
result = Collections.unmodifiableCollection(new ArrayList<RaceColumn>(races));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected RaceColumnImpl createRaceColumn(String column, boolean medalRace) {
|
||||
return new RaceColumnImpl(column, medalRace, raceExecutionOrderProvider);
|
||||
}
|
||||
|
||||
protected Iterable<Fleet> turnNullOrEmptyFleetsIntoDefaultFleet(Fleet... fleets) {
|
||||
Iterable<Fleet> theFleets;
|
||||
if (fleets == null || fleets.length == 0) {
|
||||
Fleet defaultfleetCasted = defaultFleet;
|
||||
theFleets = Collections.singleton(defaultfleetCasted);
|
||||
} else {
|
||||
theFleets = Arrays.asList(fleets);
|
||||
}
|
||||
return theFleets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRaceColumnUp(String name) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(name)) {
|
||||
race = r;
|
||||
}
|
||||
}
|
||||
if (race != null) {
|
||||
int index = 0;
|
||||
index = races.lastIndexOf(race);
|
||||
index--;
|
||||
if (index >= 0) {
|
||||
races.remove(race);
|
||||
races.add(index, race);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(race, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRaceColumnDown(String name) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(name)) {
|
||||
race = r;
|
||||
}
|
||||
}
|
||||
if (race != null) {
|
||||
int index = 0;
|
||||
index = races.lastIndexOf(race);
|
||||
if (index != -1) {
|
||||
index++;
|
||||
if (index < races.size()) {
|
||||
races.remove(race);
|
||||
races.add(index, race);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(race, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIsMedalRace(String raceName, boolean isMedalRace) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(raceName))
|
||||
race = r;
|
||||
}
|
||||
if (race != null) {
|
||||
race.setIsMedalRace(isMedalRace);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoringScheme getScoringScheme() {
|
||||
return scoringScheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return courseArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultCourseArea(CourseArea newCourseArea) {
|
||||
this.courseArea = newCourseArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsRegattaLike getRegattaLike() {
|
||||
return regattaLikeHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaLog getRegattaLog() {
|
||||
return regattaLikeHelper.getRegattaLog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaLikeIdentifier getRegattaLikeIdentifier() {
|
||||
return regattaLikeHelper.getRegattaLikeIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(RegattaLikeListener listener) {
|
||||
regattaLikeHelper.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(RegattaLikeListener listener) {
|
||||
regattaLikeHelper.removeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getTimeOnTimeFactor(Competitor competitor) {
|
||||
return regattaLikeHelper.getTimeOnTimeFactor(competitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getTimeOnDistanceAllowancePerNauticalMile(Competitor competitor) {
|
||||
return regattaLikeHelper.getTimeOnDistanceAllowancePerNauticalMile(competitor);
|
||||
}
|
||||
|
||||
private class RaceExecutionOrderCache extends AbstractRaceExecutionOrderProvider {
|
||||
private static final long serialVersionUID = 652833386555762661L;
|
||||
|
||||
public RaceExecutionOrderCache() {
|
||||
super();
|
||||
addRaceColumnListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Fleet, Iterable<? extends RaceColumn>> getRaceColumnsOfSeries() {
|
||||
final Map<Fleet, Iterable<? extends RaceColumn>> result = new HashMap<>();
|
||||
result.put(FlexibleLeaderboardImpl.defaultFleet, getRaceColumns());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
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.AbstractRaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.regattalike.BaseRegattaLikeImpl;
|
||||
import com.sap.sailing.domain.regattalike.FlexibleLeaderboardAsRegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.IsRegattaLike;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeListener;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
/**
|
||||
* 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.<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)
|
||||
*
|
||||
*/
|
||||
public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements FlexibleLeaderboard {
|
||||
private static Logger logger = Logger.getLogger(FlexibleLeaderboardImpl.class.getName());
|
||||
|
||||
protected static final DefaultFleetImpl defaultFleet = new DefaultFleetImpl();
|
||||
private static final long serialVersionUID = -5708971849158747846L;
|
||||
private final List<FlexibleRaceColumn> races;
|
||||
private final ScoringScheme scoringScheme;
|
||||
private String name;
|
||||
private transient RaceLogStore raceLogStore;
|
||||
private CourseArea courseArea;
|
||||
private RaceExecutionOrderProvider raceExecutionOrderProvider;
|
||||
|
||||
/**
|
||||
* @see RegattaLog for the reason why the leaderboard manages a {@code RegattaLog}
|
||||
*/
|
||||
private final IsRegattaLike regattaLikeHelper;
|
||||
|
||||
public FlexibleLeaderboardImpl(String name, ThresholdBasedResultDiscardingRule resultDiscardingRule,
|
||||
ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
this(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
|
||||
name, resultDiscardingRule, scoringScheme, courseArea);
|
||||
}
|
||||
|
||||
public FlexibleLeaderboardImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
String name, ThresholdBasedResultDiscardingRule resultDiscardingRule,
|
||||
ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
super(resultDiscardingRule);
|
||||
this.scoringScheme = scoringScheme;
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("A leaderboard's name must not be null");
|
||||
}
|
||||
this.name = name;
|
||||
this.races = new ArrayList<>();
|
||||
this.raceLogStore = raceLogStore;
|
||||
this.courseArea = courseArea;
|
||||
this.regattaLikeHelper = new BaseRegattaLikeImpl(new FlexibleLeaderboardAsRegattaLikeIdentifier(this), regattaLogStore) {
|
||||
private static final long serialVersionUID = 4082392360832548953L;
|
||||
|
||||
@Override
|
||||
public RaceColumn getRaceColumnByName(String raceColumnName) {
|
||||
return getRaceColumnByName(raceColumnName);
|
||||
}
|
||||
};
|
||||
this.raceExecutionOrderProvider = new RaceExecutionOrderCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialization has to be maintained in lock-step with {@link #writeObject(ObjectOutputStream) serialization}.
|
||||
* When de-serializing, a possibly remote {@link #raceLogStore} is ignored because it is transient. Instead, an
|
||||
* {@link EmptyRaceLogStore} is used for the de-serialized instance. A new {@link RaceLogInformation} is
|
||||
* assembled for this empty race log and applied to all columns.
|
||||
*/
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
ois.defaultReadObject();
|
||||
raceLogStore = EmptyRaceLogStore.INSTANCE;
|
||||
for (RaceColumn column : getRaceColumns()) {
|
||||
column.setRaceLogInformation(raceLogStore, new FlexibleLeaderboardAsRegattaLikeIdentifier(this));
|
||||
}
|
||||
}
|
||||
|
||||
protected Object readResolve() throws ObjectStreamException {
|
||||
raceExecutionOrderProvider.triggerUpdate();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param newName must not be <code>null</code>
|
||||
*/
|
||||
public void setName(String newName) {
|
||||
if (newName == null) {
|
||||
throw new IllegalArgumentException("A leaderboard's name must not be null");
|
||||
}
|
||||
this.name = newName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceColumn addRace(TrackedRace race, String columnName, boolean medalRace) {
|
||||
FlexibleRaceColumn column = addRaceColumn(columnName, medalRace, /* logAlreadyExistingColumn */false);
|
||||
column.setTrackedRace(defaultFleet, race); // triggers listeners because this object was registered above as
|
||||
// race column listener on the column
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexibleRaceColumn addRaceColumn(String name, boolean medalRace) {
|
||||
return addRaceColumn(name, medalRace, /* logAlreadyExistingColumn */true);
|
||||
}
|
||||
|
||||
private FlexibleRaceColumn addRaceColumn(String name, boolean medalRace, boolean logAlreadyExistingColumn) {
|
||||
FlexibleRaceColumn column = getRaceColumnByName(name);
|
||||
if (column != null) {
|
||||
if (logAlreadyExistingColumn) {
|
||||
final String msg = "Trying to create race column with duplicate name " + name + " in leaderboard " + getName();
|
||||
logger.severe(msg);
|
||||
}
|
||||
} else {
|
||||
column = createRaceColumn(name, medalRace);
|
||||
column.addRaceColumnListener(this);
|
||||
races.add(column);
|
||||
column.setRaceLogInformation(raceLogStore, new FlexibleLeaderboardAsRegattaLikeIdentifier(this));
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(column);
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexibleRaceColumn getRaceColumnByName(String columnName) {
|
||||
return (FlexibleRaceColumn) super.getRaceColumnByName(columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fleet getFleet(String fleetName) {
|
||||
Fleet result;
|
||||
if (fleetName == null) {
|
||||
result = defaultFleet;
|
||||
} else {
|
||||
result = super.getFleet(fleetName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRaceColumn(String columnName) {
|
||||
final FlexibleRaceColumn raceColumn = getRaceColumnByName(columnName);
|
||||
if (raceColumn != null) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
raceLogStore.removeRaceLog(raceColumn.getRaceLogIdentifier(fleet));
|
||||
if (raceColumn.getTrackedRace(fleet) != null) {
|
||||
raceColumn.getTrackedRace(fleet).detachRaceExecutionOrderProvider(raceExecutionOrderProvider);
|
||||
}
|
||||
}
|
||||
races.remove(raceColumn);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(raceColumn);
|
||||
raceColumn.removeRaceColumnListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RaceColumn> getRaceColumns() {
|
||||
final Iterable<RaceColumn> result;
|
||||
if (races != null) {
|
||||
result = Collections.unmodifiableCollection(new ArrayList<RaceColumn>(races));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected RaceColumnImpl createRaceColumn(String column, boolean medalRace) {
|
||||
return new RaceColumnImpl(column, medalRace, raceExecutionOrderProvider);
|
||||
}
|
||||
|
||||
protected Iterable<Fleet> turnNullOrEmptyFleetsIntoDefaultFleet(Fleet... fleets) {
|
||||
Iterable<Fleet> theFleets;
|
||||
if (fleets == null || fleets.length == 0) {
|
||||
Fleet defaultfleetCasted = defaultFleet;
|
||||
theFleets = Collections.singleton(defaultfleetCasted);
|
||||
} else {
|
||||
theFleets = Arrays.asList(fleets);
|
||||
}
|
||||
return theFleets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRaceColumnUp(String name) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(name)) {
|
||||
race = r;
|
||||
}
|
||||
}
|
||||
if (race != null) {
|
||||
int index = 0;
|
||||
index = races.lastIndexOf(race);
|
||||
index--;
|
||||
if (index >= 0) {
|
||||
races.remove(race);
|
||||
races.add(index, race);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(race, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRaceColumnDown(String name) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(name)) {
|
||||
race = r;
|
||||
}
|
||||
}
|
||||
if (race != null) {
|
||||
int index = 0;
|
||||
index = races.lastIndexOf(race);
|
||||
if (index != -1) {
|
||||
index++;
|
||||
if (index < races.size()) {
|
||||
races.remove(race);
|
||||
races.add(index, race);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(race, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIsMedalRace(String raceName, boolean isMedalRace) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(raceName))
|
||||
race = r;
|
||||
}
|
||||
if (race != null) {
|
||||
race.setIsMedalRace(isMedalRace);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoringScheme getScoringScheme() {
|
||||
return scoringScheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return courseArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultCourseArea(CourseArea newCourseArea) {
|
||||
this.courseArea = newCourseArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsRegattaLike getRegattaLike() {
|
||||
return regattaLikeHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaLog getRegattaLog() {
|
||||
return regattaLikeHelper.getRegattaLog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaLikeIdentifier getRegattaLikeIdentifier() {
|
||||
return regattaLikeHelper.getRegattaLikeIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(RegattaLikeListener listener) {
|
||||
regattaLikeHelper.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(RegattaLikeListener listener) {
|
||||
regattaLikeHelper.removeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getTimeOnTimeFactor(Competitor competitor) {
|
||||
return regattaLikeHelper.getTimeOnTimeFactor(competitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getTimeOnDistanceAllowancePerNauticalMile(Competitor competitor) {
|
||||
return regattaLikeHelper.getTimeOnDistanceAllowancePerNauticalMile(competitor);
|
||||
}
|
||||
|
||||
private class RaceExecutionOrderCache extends AbstractRaceExecutionOrderProvider {
|
||||
private static final long serialVersionUID = 652833386555762661L;
|
||||
|
||||
public RaceExecutionOrderCache() {
|
||||
super();
|
||||
addRaceColumnListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Fleet, Iterable<? extends RaceColumn>> getRaceColumnsOfSeries() {
|
||||
final Map<Fleet, Iterable<? extends RaceColumn>> result = new HashMap<>();
|
||||
result.put(FlexibleLeaderboardImpl.defaultFleet, getRaceColumns());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LeaderboardType getLeaderboardType() {
|
||||
return LeaderboardType.FlexibleLeaderboard;
|
||||
}
|
||||
}
|
||||
+123
-117
@@ -1,117 +1,123 @@
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
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.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.base.impl.RaceColumnInSeriesImpl;
|
||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ResultDiscardingRule;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.regattalike.IsRegattaLike;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*
|
||||
*/
|
||||
public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements RegattaLeaderboard {
|
||||
private static final long serialVersionUID = 2370461218294770084L;
|
||||
private final Regatta regatta;
|
||||
|
||||
public RegattaLeaderboardImpl(Regatta regatta, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(resultDiscardingRule);
|
||||
this.regatta = regatta;
|
||||
regatta.addRaceColumnListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the display name of this regatta leaderboard so that the regatta's name is no longer used as the default name.
|
||||
*/
|
||||
@Override
|
||||
public void setName(String newName) {
|
||||
setDisplayName(newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Regatta getRegatta() {
|
||||
return regatta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getRegatta().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RaceColumn> getRaceColumns() {
|
||||
List<RaceColumn> result = new ArrayList<RaceColumn>();
|
||||
for (Series series : getRegatta().getSeries()) {
|
||||
for (RaceColumn raceColumn : series.getRaceColumns()) {
|
||||
result.add(raceColumn);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceColumnInSeries getRaceColumnByName(String columnName) {
|
||||
return (RaceColumnInSeriesImpl) super.getRaceColumnByName(columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoringScheme getScoringScheme() {
|
||||
return regatta.getScoringScheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return regatta.getDefaultCourseArea();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the regatta' series {@link Regatta#definesSeriesDiscardThresholds() define} their own result discarding rules, this leaderboard uses
|
||||
* a composite result discarding rule of type {@link PerSeriesResultDiscardingRuleImpl} that contains discards within each series according
|
||||
* to the series' discarding rules. Otherwise, the default cross-leaderboard result discarding rule is obtained from the super class
|
||||
* implementation.
|
||||
*/
|
||||
@Override
|
||||
public ResultDiscardingRule getResultDiscardingRule() {
|
||||
if (regatta.definesSeriesDiscardThresholds()) {
|
||||
return new PerSeriesResultDiscardingRuleImpl(regatta);
|
||||
} else {
|
||||
return super.getResultDiscardingRule();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Regatta#getAllCompetitors()} which is expected to deliver all competitors from this
|
||||
* leaderboard's regatta which includes those belonging to {@link RaceDefinition races}
|
||||
* {@link Regatta#getAllRaces() belonging to the regatta} as well as competitors listed on the regatta's
|
||||
* {@link RegattaLog}.
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Competitor> getAllCompetitors() {
|
||||
return regatta.getAllCompetitors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsRegattaLike getRegattaLike() {
|
||||
return regatta;
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
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.RaceDefinition;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.base.impl.RaceColumnInSeriesImpl;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ResultDiscardingRule;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.regattalike.IsRegattaLike;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*
|
||||
*/
|
||||
public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements RegattaLeaderboard {
|
||||
private static final long serialVersionUID = 2370461218294770084L;
|
||||
private final Regatta regatta;
|
||||
|
||||
public RegattaLeaderboardImpl(Regatta regatta, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(resultDiscardingRule);
|
||||
this.regatta = regatta;
|
||||
regatta.addRaceColumnListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the display name of this regatta leaderboard so that the regatta's name is no longer used as the default name.
|
||||
*/
|
||||
@Override
|
||||
public void setName(String newName) {
|
||||
setDisplayName(newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Regatta getRegatta() {
|
||||
return regatta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getRegatta().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RaceColumn> getRaceColumns() {
|
||||
List<RaceColumn> result = new ArrayList<RaceColumn>();
|
||||
for (Series series : getRegatta().getSeries()) {
|
||||
for (RaceColumn raceColumn : series.getRaceColumns()) {
|
||||
result.add(raceColumn);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceColumnInSeries getRaceColumnByName(String columnName) {
|
||||
return (RaceColumnInSeriesImpl) super.getRaceColumnByName(columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoringScheme getScoringScheme() {
|
||||
return regatta.getScoringScheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return regatta.getDefaultCourseArea();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the regatta' series {@link Regatta#definesSeriesDiscardThresholds() define} their own result discarding rules, this leaderboard uses
|
||||
* a composite result discarding rule of type {@link PerSeriesResultDiscardingRuleImpl} that contains discards within each series according
|
||||
* to the series' discarding rules. Otherwise, the default cross-leaderboard result discarding rule is obtained from the super class
|
||||
* implementation.
|
||||
*/
|
||||
@Override
|
||||
public ResultDiscardingRule getResultDiscardingRule() {
|
||||
if (regatta.definesSeriesDiscardThresholds()) {
|
||||
return new PerSeriesResultDiscardingRuleImpl(regatta);
|
||||
} else {
|
||||
return super.getResultDiscardingRule();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Regatta#getAllCompetitors()} which is expected to deliver all competitors from this
|
||||
* leaderboard's regatta which includes those belonging to {@link RaceDefinition races}
|
||||
* {@link Regatta#getAllRaces() belonging to the regatta} as well as competitors listed on the regatta's
|
||||
* {@link RegattaLog}.
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Competitor> getAllCompetitors() {
|
||||
return regatta.getAllCompetitors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsRegattaLike getRegattaLike() {
|
||||
return regatta;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LeaderboardType getLeaderboardType() {
|
||||
return LeaderboardType.RegattaLeaderboard;
|
||||
}
|
||||
}
|
||||
+70
-64
@@ -1,64 +1,70 @@
|
||||
package com.sap.sailing.domain.leaderboard.meta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sse.concurrent.LockUtil;
|
||||
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
|
||||
public class FlexibleMetaLeaderboard extends AbstractMetaLeaderboard {
|
||||
private static final long serialVersionUID = 789076326144062944L;
|
||||
|
||||
private final List<Leaderboard> leaderboards;
|
||||
|
||||
private final NamedReentrantReadWriteLock leaderboardsLock;
|
||||
|
||||
public FlexibleMetaLeaderboard(String name, ScoringScheme scoringScheme,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(name, scoringScheme, resultDiscardingRule);
|
||||
leaderboards = new ArrayList<Leaderboard>();
|
||||
leaderboardsLock = new NamedReentrantReadWriteLock("leaderboards collection of "+FlexibleMetaLeaderboard.class.getSimpleName()+" "+getName(),
|
||||
/* fair */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Leaderboard> getLeaderboards() {
|
||||
LockUtil.lockForRead(leaderboardsLock);
|
||||
try {
|
||||
return new ArrayList<Leaderboard>(leaderboards);
|
||||
} finally {
|
||||
LockUtil.unlockAfterRead(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
public void addLeaderboard(Leaderboard leaderboard) {
|
||||
LockUtil.lockForWrite(leaderboardsLock);
|
||||
try {
|
||||
leaderboards.add(leaderboard);
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(getColumnForLeaderboard(leaderboard));
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeLeaderboard(Leaderboard leaderboard) {
|
||||
LockUtil.lockForWrite(leaderboardsLock);
|
||||
try {
|
||||
leaderboards.remove(leaderboard);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(getColumnForLeaderboard(leaderboard));
|
||||
unregisterScoreCorrectionChangeForwarder(leaderboard);
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.leaderboard.meta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sse.concurrent.LockUtil;
|
||||
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
|
||||
public class FlexibleMetaLeaderboard extends AbstractMetaLeaderboard {
|
||||
private static final long serialVersionUID = 789076326144062944L;
|
||||
|
||||
private final List<Leaderboard> leaderboards;
|
||||
|
||||
private final NamedReentrantReadWriteLock leaderboardsLock;
|
||||
|
||||
public FlexibleMetaLeaderboard(String name, ScoringScheme scoringScheme,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(name, scoringScheme, resultDiscardingRule);
|
||||
leaderboards = new ArrayList<Leaderboard>();
|
||||
leaderboardsLock = new NamedReentrantReadWriteLock("leaderboards collection of "+FlexibleMetaLeaderboard.class.getSimpleName()+" "+getName(),
|
||||
/* fair */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Leaderboard> getLeaderboards() {
|
||||
LockUtil.lockForRead(leaderboardsLock);
|
||||
try {
|
||||
return new ArrayList<Leaderboard>(leaderboards);
|
||||
} finally {
|
||||
LockUtil.unlockAfterRead(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
public void addLeaderboard(Leaderboard leaderboard) {
|
||||
LockUtil.lockForWrite(leaderboardsLock);
|
||||
try {
|
||||
leaderboards.add(leaderboard);
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(getColumnForLeaderboard(leaderboard));
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeLeaderboard(Leaderboard leaderboard) {
|
||||
LockUtil.lockForWrite(leaderboardsLock);
|
||||
try {
|
||||
leaderboards.remove(leaderboard);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(getColumnForLeaderboard(leaderboard));
|
||||
unregisterScoreCorrectionChangeForwarder(leaderboard);
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LeaderboardType getLeaderboardType() {
|
||||
return LeaderboardType.FlexibleMetaLeaderboard;
|
||||
}
|
||||
}
|
||||
+98
-92
@@ -1,92 +1,98 @@
|
||||
package com.sap.sailing.domain.leaderboard.meta;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
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.TrackedRaces;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroupListener;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* A meta leaderboard which considers all regular leaderboards of a {@link LeaderboardGroup}. To stay up to date, this
|
||||
* meta leaderboard registers itself as a {@link LeaderboardGroupListener} on the leaderboard group it represents. This
|
||||
* way, whenever a leaderboard is added to or removed from the group, this meta leaderboard can in turn inform its
|
||||
* {@link RaceColumnListener}s about the impact this change has on the set of {@link TrackedRaces} and therefore the
|
||||
* competitors attached to this meta leaderboard.
|
||||
* <p>
|
||||
*
|
||||
* After an object of this type has been de-serialized, and after all objects referenced by it (leaderboard, leaderboard
|
||||
* group) have been initialized, {@link #registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards()} must be called to
|
||||
* ensure that score corrections are propagated as desired. This is because score correction listeners are "transient"
|
||||
* and are as such not serialized. Note: calling {@link #registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards()}
|
||||
* during <code>readObject</code> or <code>readResolve</code> is not possible because the object graph hasn't been fully
|
||||
* initialized yet when those methods are called. Hence, the structures for registering the score correction listeners
|
||||
* are not yet in place at that time.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class LeaderboardGroupMetaLeaderboard extends AbstractMetaLeaderboard implements LeaderboardGroupListener, RaceColumnListener {
|
||||
private static final long serialVersionUID = 8087872002175528002L;
|
||||
|
||||
private final LeaderboardGroup leaderboardGroup;
|
||||
|
||||
public LeaderboardGroupMetaLeaderboard(LeaderboardGroup leaderboardGroup, ScoringScheme scoringScheme,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(leaderboardGroup.getName() + " " + LeaderboardNameConstants.OVERALL, scoringScheme, resultDiscardingRule);
|
||||
this.leaderboardGroup = leaderboardGroup;
|
||||
leaderboardGroup.addLeaderboardGroupListener(this);
|
||||
registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards();
|
||||
}
|
||||
|
||||
public void registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards() {
|
||||
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Leaderboard> getLeaderboards() {
|
||||
return leaderboardGroup.getLeaderboards();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaderboardAdded(LeaderboardGroup group, Leaderboard leaderboard) {
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
getRaceColumnListeners().notifyListenersAboutTrackedRaceLinked(raceColumn, fleet, trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(getColumnForLeaderboard(leaderboard));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaderboardRemoved(LeaderboardGroup group, Leaderboard leaderboard) {
|
||||
leaderboard.removeRaceColumnListener(this);
|
||||
unregisterScoreCorrectionChangeForwarder(leaderboard);
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(getColumnForLeaderboard(leaderboard));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.leaderboard.meta;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
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.TrackedRaces;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroupListener;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* A meta leaderboard which considers all regular leaderboards of a {@link LeaderboardGroup}. To stay up to date, this
|
||||
* meta leaderboard registers itself as a {@link LeaderboardGroupListener} on the leaderboard group it represents. This
|
||||
* way, whenever a leaderboard is added to or removed from the group, this meta leaderboard can in turn inform its
|
||||
* {@link RaceColumnListener}s about the impact this change has on the set of {@link TrackedRaces} and therefore the
|
||||
* competitors attached to this meta leaderboard.
|
||||
* <p>
|
||||
*
|
||||
* After an object of this type has been de-serialized, and after all objects referenced by it (leaderboard, leaderboard
|
||||
* group) have been initialized, {@link #registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards()} must be called to
|
||||
* ensure that score corrections are propagated as desired. This is because score correction listeners are "transient"
|
||||
* and are as such not serialized. Note: calling {@link #registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards()}
|
||||
* during <code>readObject</code> or <code>readResolve</code> is not possible because the object graph hasn't been fully
|
||||
* initialized yet when those methods are called. Hence, the structures for registering the score correction listeners
|
||||
* are not yet in place at that time.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class LeaderboardGroupMetaLeaderboard extends AbstractMetaLeaderboard implements LeaderboardGroupListener, RaceColumnListener {
|
||||
private static final long serialVersionUID = 8087872002175528002L;
|
||||
|
||||
private final LeaderboardGroup leaderboardGroup;
|
||||
|
||||
public LeaderboardGroupMetaLeaderboard(LeaderboardGroup leaderboardGroup, ScoringScheme scoringScheme,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(leaderboardGroup.getName() + " " + LeaderboardNameConstants.OVERALL, scoringScheme, resultDiscardingRule);
|
||||
this.leaderboardGroup = leaderboardGroup;
|
||||
leaderboardGroup.addLeaderboardGroupListener(this);
|
||||
registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards();
|
||||
}
|
||||
|
||||
public void registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards() {
|
||||
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Leaderboard> getLeaderboards() {
|
||||
return leaderboardGroup.getLeaderboards();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaderboardAdded(LeaderboardGroup group, Leaderboard leaderboard) {
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
getRaceColumnListeners().notifyListenersAboutTrackedRaceLinked(raceColumn, fleet, trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(getColumnForLeaderboard(leaderboard));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaderboardRemoved(LeaderboardGroup group, Leaderboard leaderboard) {
|
||||
leaderboard.removeRaceColumnListener(this);
|
||||
unregisterScoreCorrectionChangeForwarder(leaderboard);
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(getColumnForLeaderboard(leaderboard));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LeaderboardType getLeaderboardType() {
|
||||
return LeaderboardType.RegattaMetaLeaderboard;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user