added time-on-time and time-on-distance fields and listener pattern on Competitor/DynamicCompetitor

This commit is contained in:
Axel Uhl committed 2015-05-07 09:56:16 +02:00
1 parent 33c479260b
commit 26d178b3d9
8 files changed
+149 -2

No files matched your search

@@ -2,7 +2,9 @@ package com.sap.sailing.domain.base;
import java.net.URI;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
import com.sap.sse.common.IsManagedByCache;
import com.sap.sse.common.Named;
import com.sap.sse.common.WithID;
@@ -39,4 +41,35 @@ public interface Competitor extends Named, WithID, IsManagedByCache<SharedDomain
* without effect.
*/
void removeCompetitorChangeListener(CompetitorChangeListener listener);
/**
* The default time-on-time handicap factor for this competitor. If <code>null</code>, no time-on-time handicap
* factor is defined for this competitor. For a simple time-on-time scheme, the factor is multiplied with the actual
* time sailed to obtain the corrected time. For a "performance line" system, afterwards an additional
* distance-based allowance may be subtracted from the resulting time.
* <p>
*
* A particular regatta can make specific arrangements and override this default value for this competitor in its
* {@link RegattaLog}, accommodating for the fact that in between regattas competitors may get a new, different
* rating, resulting in different handicaps for different regattas.
*
* @see #getTimeOnDistanceAllowancePerNauticalMile
*/
Double getTimeOnTimeFactor();
/**
* The default time-on-distance time allowance for this competitor, used in handicap regattas. If <code>null</code>,
* no time-on-distance allowance is defined for this competitor. For a simple time-on-distance scheme, the factor is
* multiplied with the (windward) course length and the result is subtracted from the actual time sailed to obtain
* the corrected time. For a "performance line" system, the actual time sailed will be multiplied with the
* {@link #getTimeOnTimeFactor() time-on-time factor} before subtracting the time-on-distance allowance.
* <p>
*
* A particular regatta can make specific arrangements and override this default value for this competitor in its
* {@link RegattaLog}, accommodating for the fact that in between regattas competitors may get a new, different
* rating, resulting in different handicaps for different regattas.
*
* @see #getTimeOnTimeFactor
*/
Duration getTimeOnDistanceAllowancePerNauticalMile();
}
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.base;
import java.net.URI;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
public interface CompetitorChangeListener extends BoatChangeListener, NationalityChangeListener {
void colorChanged(Color oldColor, Color newColor);
@@ -12,4 +13,8 @@ public interface CompetitorChangeListener extends BoatChangeListener, Nationalit
void emailChanged(String oldEmail, String newEmail);
void flagImageChanged(URI oldFlagImageURI, URI newFlagImageURI);
void timeOnTimeFactorChanged(Double oldTimeOnTimeFactor, Double newTimeOnTimeFactor);
void timeOnDistanceAllowancePerNauticalMileChanged(Duration oldTimeOnDistanceAllowancePerNauticalMile, Duration newTimeOnDistanceAllowancePerNauticalMile);
}
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorChangeListener;
import com.sap.sailing.domain.base.SharedDomainFactory;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
import com.sap.sse.common.Util;
public class CompetitorImpl implements DynamicCompetitor {
@@ -23,6 +24,8 @@ public class CompetitorImpl implements DynamicCompetitor {
private transient Set<CompetitorChangeListener> listeners;
private String email;
private URI flagImage;
private Double timeOnTimeFactor;
private Duration timeOnDistanceAllowancePerNauticalMile;
public CompetitorImpl(Serializable id, String name, Color color, String email, URI flagImage, DynamicTeam team, DynamicBoat boat) {
this.id = id;
@@ -153,4 +156,37 @@ public class CompetitorImpl implements DynamicCompetitor {
}
}
}
@Override
public Double getTimeOnTimeFactor() {
return timeOnTimeFactor;
}
@Override
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
return timeOnDistanceAllowancePerNauticalMile;
}
@Override
public void setTimeOnTimeFactor(Double timeOnTimeFactor) {
Double oldTimeOnTimeFactor = this.timeOnTimeFactor;
this.timeOnTimeFactor = timeOnTimeFactor;
if (!Util.equalsWithNull(oldTimeOnTimeFactor, timeOnTimeFactor)) {
for (CompetitorChangeListener listener : getListeners()) {
listener.timeOnTimeFactorChanged(oldTimeOnTimeFactor, timeOnTimeFactor);
}
}
}
@Override
public void setTimeOnDistanceAllowancePerNauticalMile(Duration timeOnDistanceAllowancePerNauticalMile) {
Duration oldTimeOnDistanceAllowancePerNauticalMile = this.timeOnDistanceAllowancePerNauticalMile;
this.timeOnDistanceAllowancePerNauticalMile = timeOnDistanceAllowancePerNauticalMile;
if (!Util.equalsWithNull(oldTimeOnDistanceAllowancePerNauticalMile, timeOnDistanceAllowancePerNauticalMile)) {
for (CompetitorChangeListener listener : getListeners()) {
listener.timeOnDistanceAllowancePerNauticalMileChanged(oldTimeOnDistanceAllowancePerNauticalMile, timeOnDistanceAllowancePerNauticalMile);
}
}
}
}
@@ -5,6 +5,7 @@ import java.net.URI;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.Renamable;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
public interface DynamicCompetitor extends Competitor, Renamable {
DynamicBoat getBoat();
@@ -16,4 +17,8 @@ public interface DynamicCompetitor extends Competitor, Renamable {
void setEmail(String email);
void setFlagImage(URI flagImage);
void setTimeOnTimeFactor(Double timeOnTimeFactor);
void setTimeOnDistanceAllowancePerNauticalMile(Duration timeOnDistanceAllowancePerNauticalMile);
}
@@ -21,6 +21,7 @@ import com.sap.sailing.domain.base.WithNationality;
import com.sap.sailing.domain.base.impl.DomainFactoryImpl;
import com.sap.sailing.domain.base.impl.DynamicCompetitor;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
import com.sap.sse.common.impl.RGBColor;
/**
@@ -53,6 +54,12 @@ public class CompetitorListenerTest extends AbstractSerializationTest {
private boolean flagImageChanged;
private URI oldFlagImageURL;
private URI newFlagImageURL;
private boolean timeOnTimeFactorChanged;
private Double oldTimeOnTimeFactor;
private Double newTimeOnTimeFactor;
private boolean timeOnDistanceAllowancePerNauticalMileChanged;
private Duration oldTimeOnDistanceAllowancePerNauticalMile;
private Duration newTimeOnDistanceAllowancePerNauticalMile;
@Before
public void setUp() {
@@ -77,6 +84,12 @@ public class CompetitorListenerTest extends AbstractSerializationTest {
flagImageChanged = false;
oldFlagImageURL = null;
newFlagImageURL = null;
timeOnTimeFactorChanged = false;
oldTimeOnTimeFactor = null;
newTimeOnTimeFactor = null;
timeOnDistanceAllowancePerNauticalMileChanged = false;
oldTimeOnDistanceAllowancePerNauticalMile = null;
newTimeOnDistanceAllowancePerNauticalMile = null;
listener = new CompetitorChangeListener() {
private static final long serialVersionUID = 4581029778988240209L;
@@ -122,6 +135,22 @@ public class CompetitorListenerTest extends AbstractSerializationTest {
CompetitorListenerTest.this.oldFlagImageURL = oldFlagImageURL;
CompetitorListenerTest.this.newFlagImageURL = newFlagImageURL;
}
@Override
public void timeOnTimeFactorChanged(Double oldTimeOnTimeFactor, Double newTimeOnTimeFactor) {
timeOnTimeFactorChanged = true;
CompetitorListenerTest.this.oldTimeOnTimeFactor = oldTimeOnTimeFactor;
CompetitorListenerTest.this.newTimeOnTimeFactor = newTimeOnTimeFactor;
}
@Override
public void timeOnDistanceAllowancePerNauticalMileChanged(
Duration oldTimeOnDistanceAllowancePerNauticalMile,
Duration newTimeOnDistanceAllowancePerNauticalMile) {
timeOnDistanceAllowancePerNauticalMileChanged = true;
CompetitorListenerTest.this.oldTimeOnDistanceAllowancePerNauticalMile = oldTimeOnDistanceAllowancePerNauticalMile;
CompetitorListenerTest.this.newTimeOnDistanceAllowancePerNauticalMile = newTimeOnDistanceAllowancePerNauticalMile;
}
};
competitor.addCompetitorChangeListener(listener);
}
@@ -138,6 +167,22 @@ public class CompetitorListenerTest extends AbstractSerializationTest {
assertNull(competitor.getTeam().getNationality());
}
@Test
public void testChangeTimeOnTimeFactor() {
competitor.setTimeOnTimeFactor(1.209);
assertTrue(timeOnTimeFactorChanged);
assertNull(oldTimeOnTimeFactor);
assertEquals(1.209, newTimeOnTimeFactor, 0.00000001);
}
@Test
public void testChangeTimeOnDistanceAllowancePerNauticalMile() {
competitor.setTimeOnDistanceAllowancePerNauticalMile(Duration.ONE_HOUR);
assertTrue(timeOnDistanceAllowancePerNauticalMileChanged);
assertNull(oldTimeOnDistanceAllowancePerNauticalMile);
assertEquals(Duration.ONE_HOUR.asMillis(), newTimeOnDistanceAllowancePerNauticalMile.asMillis());
}
@Test
public void testSimpleCompetitorListenerPatternForName() {
competitor.setName("Dr. Hasso Plattner");
@@ -23,6 +23,7 @@ import com.sap.sailing.domain.tracking.RaceChangeListener;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
import com.sap.sse.concurrent.ConcurrentWeakHashMap;
import com.sap.sse.concurrent.LockUtil;
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
@@ -127,6 +128,17 @@ public class LeaderboardCacheManager {
public void flagImageChanged(URI oldFlagImageURL, URI newFlagImageURL) {
removeFromCache(leaderboard);
}
@Override
public void timeOnTimeFactorChanged(Double oldTimeOnTimeFactor, Double newTimeOnTimeFactor) {
removeFromCache(leaderboard);
}
@Override
public void timeOnDistanceAllowancePerNauticalMileChanged(Duration oldTimeOnDistanceAllowancePerNauticalMile,
Duration newTimeOnDistanceAllowancePerNauticalMile) {
removeFromCache(leaderboard);
}
}
private class CacheInvalidationUponScoreCorrectionListener implements ScoreCorrectionListener {
@@ -127,7 +127,7 @@ public class ORCPerformanceCurveCertificate implements Serializable {
* {@link #durationPerNauticalMileAtTrueWindAngleAndSpeed} which duration is expected for the competitor
* described by this certificate to sail the complete <code>leg</code>.
*/
private Map<Speed, Duration> getAllowancesForLegPerTrueWindSpeed(TrackedLeg leg, Bearing trueWindToDirection) throws FunctionEvaluationException {
protected Map<Speed, Duration> getAllowancesForLegPerTrueWindSpeed(TrackedLeg leg, Bearing trueWindToDirection) throws FunctionEvaluationException {
Bearing legBearing = leg.getLegBearing(leg.getReferenceTimePoint());
Distance greatCircleLegDistance = leg.getGreatCircleDistance(leg.getReferenceTimePoint());
if (trueWindToDirection == null) {
@@ -145,7 +145,7 @@ public class ORCPerformanceCurveCertificate implements Serializable {
*
* If the <code>competitor</code> hasn't started the race yet, <code>null</code> is returned.
*/
private Map<Speed, Duration> getAllowances(TrackedRace trackedRace, Competitor competitor, TimePoint timePoint) {
protected Map<Speed, Duration> getAllowances(TrackedRace trackedRace, Competitor competitor, TimePoint timePoint) {
final Map<Speed, Duration> result;
if (trackedRace.getMarkPassings(competitor).isEmpty()) {
result = null;
@@ -10,6 +10,7 @@ import com.sap.sailing.domain.base.Team;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
import com.sap.sse.common.IsManagedByCache;
import com.sap.sse.common.TimePoint;
@@ -89,6 +90,16 @@ public class DummyMarkPassingWithTimePointOnly implements MarkPassing {
public URI getFlagImage() {
return null;
}
@Override
public Double getTimeOnTimeFactor() {
return null;
}
@Override
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
return null;
}
};
}
}