Added LeaderboardType calculation to set it in LeaderboardDTOs

This commit is contained in:
Benjamin Barth committed 2015-12-02 17:56:12 +01:00
1 parent 20c226930d
commit f4686bbe85
5 files changed
+638 -609

No files matched your search

@@ -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();
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}