Merge branch 'master' into bug5060

This commit is contained in:
Axel Uhl
2020-05-15 00:31:58 +02:00
1098 changed files with 91856 additions and 14291 deletions
@@ -5,6 +5,7 @@ import com.sap.sailing.domain.common.impl.NauticalMileDistance;
import com.sap.sse.common.Distance;
import com.sap.sse.common.Duration;
import com.sap.sse.common.Speed;
import com.sap.sse.common.impl.SecondsDurationImpl;
public abstract class AbstractDistance implements Distance {
@@ -41,6 +42,11 @@ public abstract class AbstractDistance implements Distance {
return inSeconds(duration.asSeconds());
}
@Override
public Duration atSpeed(Speed speed) {
return new SecondsDurationImpl(getMeters() / speed.getMetersPerSecond());
}
@Override
public double getNauticalMiles() {
return getMeters() / Mile.METERS_PER_NAUTICAL_MILE;
@@ -64,6 +64,12 @@ public enum DataImportSubProgress {
return messages.importSensorFixes();
}
},
IMPORT_TRACKED_RACES {
@Override
public String getMessage(CommonStringMessages messages) {
return messages.importTrackedRaces();
}
},
UPDATE_EVENT_LEADERBOARD_GROUP_LINKS {
@Override
public String getMessage(CommonStringMessages messages) {
@@ -263,7 +263,6 @@ public enum DetailType implements Serializable {
availableDetailsTypes.add(DetailType.LEG_GAP_TO_LEADER_IN_SECONDS);
availableDetailsTypes.add(DetailType.RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
availableDetailsTypes.add(DetailType.RACE_RANK);
availableDetailsTypes.add(DetailType.RACE_IMPLIED_WIND);
availableDetailsTypes.add(DetailType.REGATTA_RANK);
availableDetailsTypes.add(DetailType.CHART_DISTANCE_TO_START_LINE);
availableDetailsTypes.add(DetailType.CHART_BEAT_ANGLE);
@@ -390,9 +389,8 @@ public enum DetailType implements Serializable {
}
/**
* Returns all types in the enum, minus those for expedition, bravo and bravo extended
*
* @return
* Returns all types in the enum, minus those for expedition, bravo, bravo extended
* and the ToT/ToD/ORC PCS ones
*/
public static Collection<DetailType> getAllNonRestrictedDetailTypes() {
final Collection<DetailType> all = new LinkedHashSet<>(Arrays.asList(values()));
@@ -402,6 +400,8 @@ public enum DetailType implements Serializable {
all.removeAll(getRaceExpeditionDetailTypes());
all.removeAll(getLegExpeditionDetailColumnTypes());
all.removeAll(getOverallBravoDetailTypes());
all.removeAll(getAllToTToDHandicapDetailTypes());
all.removeAll(getAllOrcPerformanceCurveDetailTypes());
return all;
}
@@ -12,9 +12,11 @@ public interface MasterDataImportObjectCreationCount extends Serializable {
int getRegattaCount();
int getMediaTrackCount();
int getMediaTrackCount();
Set<String> getOverwrittenRegattaNames();
void addOneMediaTrack();
void addOneMediaTrack();
int getTrackedRacesCount();
}
@@ -6,7 +6,6 @@ import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import com.sap.sailing.domain.common.LeaderboardType;
import com.sap.sailing.domain.common.RaceIdentifier;
@@ -29,8 +28,7 @@ public abstract class AbstractLeaderboardDTO extends NamedDTO implements Seriali
*/
public String regattaName;
public String displayName;
public UUID defaultCourseAreaId;
public String defaultCourseAreaName;
public List<CourseAreaDTO> courseAreas;
public ScoringSchemeType scoringScheme;
public LeaderboardType type;
public boolean canBoatsOfCompetitorsChangePerRace;
@@ -0,0 +1,46 @@
package com.sap.sailing.domain.common.dto;
import java.util.UUID;
import com.sap.sse.security.shared.dto.NamedDTO;
/**
* Equality and hash code are based on the course area's {@link #id}.
*/
public class CourseAreaDTO extends NamedDTO {
private static final long serialVersionUID = -5279690838452265454L;
public UUID id;
public CourseAreaDTO() {
}
public CourseAreaDTO(String name) {
super(name);
}
public UUID getId() {
return id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = prime * ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
CourseAreaDTO other = (CourseAreaDTO) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
@@ -56,8 +56,7 @@ public class IncrementalLeaderboardDTO extends LeaderboardDTO implements Increme
private boolean competitorDisplayNamesUnchanged;
private boolean regattaNameUnchanged;
private boolean displayNameUnchanged;
private boolean defaultCourseAreaIdAsStringUnchanged;
private boolean defaultCourseAreaNameUnchanged;
private boolean courseAreasUnchanged;
private boolean boatClassUnchanged;
/**
@@ -352,11 +351,8 @@ public class IncrementalLeaderboardDTO extends LeaderboardDTO implements Increme
if (this.commentUnchanged) {
this.setComment(previousVersion.getComment());
}
if (this.defaultCourseAreaIdAsStringUnchanged) {
this.defaultCourseAreaId = previousVersion.defaultCourseAreaId;
}
if (this.defaultCourseAreaNameUnchanged) {
this.defaultCourseAreaName = previousVersion.defaultCourseAreaName;
if (this.courseAreasUnchanged) {
this.courseAreas = previousVersion.courseAreas;
}
if (this.displayNameUnchanged) {
this.displayName = previousVersion.displayName;
@@ -519,13 +515,9 @@ public class IncrementalLeaderboardDTO extends LeaderboardDTO implements Increme
this.displayName = null;
this.displayNameUnchanged = true;
}
if (Util.equalsWithNull(this.defaultCourseAreaId, previousVersion.defaultCourseAreaId)) {
this.defaultCourseAreaId = null;
this.defaultCourseAreaIdAsStringUnchanged = true;
}
if (Util.equalsWithNull(this.defaultCourseAreaName, previousVersion.defaultCourseAreaName)) {
this.defaultCourseAreaName = null;
this.defaultCourseAreaNameUnchanged = true;
if (Util.equalsWithNull(this.courseAreas, previousVersion.courseAreas)) {
this.courseAreas = null;
this.courseAreasUnchanged = true;
}
if (Util.equalsWithNull(this.getBoatClass(), previousVersion.getBoatClass())) {
this.setBoatClass(null);
@@ -60,8 +60,18 @@ public class LegEntryDTO implements Serializable {
public boolean finished;
public Map<ManeuverType, Integer> numberOfManeuvers;
public Map<ManeuverType, Double> averageManeuverLossInMeters;
public Double averageAbsoluteCrossTrackErrorInMeters;
public Double averageSignedCrossTrackErrorInMeters;
/**
* The absolute cross track error; averaged when asked for a time point after the competitor has finished the leg,
* or the current value when in the leg; {@code null} when not yet in the leg.
*/
public Double currentOrAverageAbsoluteCrossTrackErrorInMeters;
/**
* The signed cross track error; averaged when asked for a time point after the competitor has finished the leg,
* or the current value when in the leg; {@code null} when not yet in the leg.
*/
public Double currentOrAverageSignedCrossTrackErrorInMeters;
/**
* The corrected time spent since the start of the race up to the current time point or the finishing of
@@ -75,11 +85,11 @@ public class LegEntryDTO implements Serializable {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((averageAbsoluteCrossTrackErrorInMeters == null) ? 0
: averageAbsoluteCrossTrackErrorInMeters.hashCode());
result = prime * result + ((currentOrAverageAbsoluteCrossTrackErrorInMeters == null) ? 0
: currentOrAverageAbsoluteCrossTrackErrorInMeters.hashCode());
result = prime * result + ((averageManeuverLossInMeters == null) ? 0 : averageManeuverLossInMeters.hashCode());
result = prime * result + ((averageSignedCrossTrackErrorInMeters == null) ? 0
: averageSignedCrossTrackErrorInMeters.hashCode());
result = prime * result + ((currentOrAverageSignedCrossTrackErrorInMeters == null) ? 0
: currentOrAverageSignedCrossTrackErrorInMeters.hashCode());
result = prime * result
+ ((averageSpeedOverGroundInKnots == null) ? 0 : averageSpeedOverGroundInKnots.hashCode());
result = prime * result + ((correctedTotalTime == null) ? 0 : correctedTotalTime.hashCode());
@@ -124,20 +134,20 @@ public class LegEntryDTO implements Serializable {
if (getClass() != obj.getClass())
return false;
LegEntryDTO other = (LegEntryDTO) obj;
if (averageAbsoluteCrossTrackErrorInMeters == null) {
if (other.averageAbsoluteCrossTrackErrorInMeters != null)
if (currentOrAverageAbsoluteCrossTrackErrorInMeters == null) {
if (other.currentOrAverageAbsoluteCrossTrackErrorInMeters != null)
return false;
} else if (!averageAbsoluteCrossTrackErrorInMeters.equals(other.averageAbsoluteCrossTrackErrorInMeters))
} else if (!currentOrAverageAbsoluteCrossTrackErrorInMeters.equals(other.currentOrAverageAbsoluteCrossTrackErrorInMeters))
return false;
if (averageManeuverLossInMeters == null) {
if (other.averageManeuverLossInMeters != null)
return false;
} else if (!averageManeuverLossInMeters.equals(other.averageManeuverLossInMeters))
return false;
if (averageSignedCrossTrackErrorInMeters == null) {
if (other.averageSignedCrossTrackErrorInMeters != null)
if (currentOrAverageSignedCrossTrackErrorInMeters == null) {
if (other.currentOrAverageSignedCrossTrackErrorInMeters != null)
return false;
} else if (!averageSignedCrossTrackErrorInMeters.equals(other.averageSignedCrossTrackErrorInMeters))
} else if (!currentOrAverageSignedCrossTrackErrorInMeters.equals(other.currentOrAverageSignedCrossTrackErrorInMeters))
return false;
if (averageSpeedOverGroundInKnots == null) {
if (other.averageSpeedOverGroundInKnots != null)
@@ -17,5 +17,6 @@ public interface CommonStringMessages {
String competitorRegistrationTypeClosed();
String competitorRegistrationTypeOpenModerated();
String competitorRegistrationTypeOpenUnmoderated();
String importTrackedRaces();
}
@@ -23,11 +23,13 @@ public class MasterDataImportObjectCreationCountImpl implements MasterDataImport
private int eventCount = 0;
private int regattaCount = 0;
private int mediaTrackCount = 0;
private int trackedRacesCount = 0;
private Set<String> createdLeaderboards = new HashSet<String>();
private Set<String> createdLeaderboardGroups = new HashSet<String>();
private Set<String> createdEvents = new HashSet<String>();
private Set<String> createdRegattas = new HashSet<String>();
private Set<String> createdTrackedRaces = new HashSet<String>();
private Set<String> overwrittenRegattas = new HashSet<String>();
@@ -54,6 +56,11 @@ public class MasterDataImportObjectCreationCountImpl implements MasterDataImport
regattaCount++;
}
public void addOneTrackedRace(String id) {
createdTrackedRaces.add(id);
trackedRacesCount++;
}
@Override
public void addOneMediaTrack() {
mediaTrackCount++;
@@ -64,10 +71,12 @@ public class MasterDataImportObjectCreationCountImpl implements MasterDataImport
leaderboardGroupCount = leaderboardGroupCount + toAdd.leaderboardGroupCount;
eventCount = eventCount + toAdd.eventCount;
regattaCount = regattaCount + toAdd.regattaCount;
trackedRacesCount = trackedRacesCount + toAdd.trackedRacesCount;
createdEvents.addAll(toAdd.createdEvents);
createdLeaderboardGroups.addAll(toAdd.createdLeaderboardGroups);
createdLeaderboards.addAll(toAdd.createdLeaderboards);
createdRegattas.addAll(toAdd.createdRegattas);
createdTrackedRaces.addAll(toAdd.createdTrackedRaces);
}
public boolean alreadyAddedLeaderboardWithName(String name) {
@@ -85,6 +94,10 @@ public class MasterDataImportObjectCreationCountImpl implements MasterDataImport
public boolean alreadyAddedRegattaWithId(String id) {
return createdRegattas.contains(id);
}
public boolean alreadyAddedTrackedRaceWithId(String id) {
return createdTrackedRaces.contains(id);
}
@Override
public int getLeaderboardCount() {
@@ -110,6 +123,11 @@ public class MasterDataImportObjectCreationCountImpl implements MasterDataImport
public int getMediaTrackCount() {
return mediaTrackCount;
}
@Override
public int getTrackedRacesCount() {
return trackedRacesCount;
}
@Override
public Set<String> getOverwrittenRegattaNames() {
@@ -0,0 +1,15 @@
package com.sap.sailing.domain.common.orc;
import java.util.function.Function;
import com.sap.sailing.domain.common.Wind;
public interface AverageWindOnLegCache {
/**
* Caches the legs by their {@link Object#equals(Object) equality and allows for one wind reading per such leg.
* If you want to map differently-scaled "variants" of the same original leg (e.g., because of different distances
* traveled on that leg) as the same key then you'll have to come up with a wrapper around your leg that
* has a definition of equality using only the underlying original leg for comparison.
*/
<L extends ORCPerformanceCurveLeg> Wind getAverageWind(L leg, Function<L, Wind> averageWindForLegSupplier);
}
@@ -4,7 +4,9 @@ import java.io.Serializable;
import java.util.Map;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
import com.sap.sailing.domain.common.impl.NauticalMileDistance;
import com.sap.sse.common.Bearing;
import com.sap.sse.common.CountryCode;
import com.sap.sse.common.Distance;
import com.sap.sse.common.Duration;
import com.sap.sse.common.Speed;
@@ -24,10 +26,9 @@ import com.sap.sse.common.impl.DegreeBearingImpl;
* {@link RankingMetric}.
* <p>
*
* The {@link WithID} interface is to be implemented such that a {@link String} is produced as the ID that contains the
* concatenation (without intermediate white space) of the {@code NatAuth}, the {@code CertNo} and the {@code BIN}
* fields, as provided as single fields in the JSON representation, and as provided in the concatenated form in the
* {@code NATCERTN.FILE_ID} column in the RMS format.
* The {@link WithID} interface is to be implemented based on the {@link #getReferenceNumber()} which is unique across the
* ORC world-wide certificate database. Note that the {@link #getBoatKey()} consisting of the {@link #getFileId()} and the
* {@link #getIssuingCountry()} field values is a unique key for the boat to which the certificate belongs.
* <p>
*
* The certificate contains time allowances (or, conversely, speed predictions) for a combination of true wind speeds
@@ -64,13 +65,30 @@ public interface ORCCertificate extends WithID, Serializable {
Bearing[] ALLOWANCES_TRUE_WIND_ANGLES = { new DegreeBearingImpl(52), new DegreeBearingImpl(60),
new DegreeBearingImpl(75), new DegreeBearingImpl(90), new DegreeBearingImpl(110),
new DegreeBearingImpl(120), new DegreeBearingImpl(135), new DegreeBearingImpl(150) };
Distance NAUTICAL_MILE = new NauticalMileDistance(1);
/**
* As the ID of an ORC certificate we use the concatenation (without intermediate white space) of the
* {@code NatAuth}, the {@code CertNo} and the {@code BIN} fields, as provided as single fields in the JSON
* representation
* We use the {@link #getReferenceNumber() reference number ("RefNo")} as the ID of a certificate document.
* It is unique for all of ORC's certificates issued world-wide.
*/
@Override
String getId();
String getReferenceNumber();
/**
* Technically, at ORC a certificate's boat is identified by a "file ID" as returned by this method, together
* with the {@link #getIssuingCountry() issuing country} which together makes this a unique boat key. For each
* such boat key there is at most one valid certificate at a time.
*/
String getFileId();
/**
* The country whose authority issued this certificate. Together with the {@link #getFileId() file ID} this makes for a
* unique key of the boat to which this certifiate belongs.
*/
CountryCode getIssuingCountry();
/**
* Returns the sailnumber of the {@link Competitor} which this certificate belongs to.
@@ -15,6 +15,12 @@ public interface ORCPerformanceCurveLeg extends Serializable {
*/
Bearing getTwa();
/**
* Same as {@link #getTwa()}, but with the possibility to pass a cache that can remember the results
* of computing the wind for a specific leg across a certain computing scope.
*/
Bearing getTwa(AverageWindOnLegCache cache);
String toString();
ORCPerformanceCurveLegTypes getType();
@@ -3,9 +3,9 @@ package com.sap.sailing.domain.common.orc.impl;
import java.util.Collections;
import java.util.Map;
import com.sap.sailing.domain.common.impl.NauticalMileDistance;
import com.sap.sailing.domain.common.orc.ORCCertificate;
import com.sap.sse.common.Bearing;
import com.sap.sse.common.CountryCode;
import com.sap.sse.common.Distance;
import com.sap.sse.common.Duration;
import com.sap.sse.common.Speed;
@@ -24,10 +24,8 @@ import com.sap.sse.common.Util;
public class ORCCertificateImpl implements ORCCertificate {
private static final long serialVersionUID = 8725162998514202782L;
private final String idConsistingOfNatAuthCertNoAndBIN;
private final String referenceNumber;
public final static Distance NAUTICAL_MILE = new NauticalMileDistance(1);
private final String sailNumber;
private final String boatName;
private final String boatClassName;
@@ -35,7 +33,9 @@ public class ORCCertificateImpl implements ORCCertificate {
private final Duration gph;
private final Double cdl;
private final TimePoint issueDate;
private final String fileId;
private final CountryCode issuingCountry;
/**
* The "core" of the certificate for performance curve scoring; the values in the map tell how fast the boat
* described by this certificate is expected to sail for the true wind speed (TWS) provided by the key, and the true
@@ -111,11 +111,13 @@ public class ORCCertificateImpl implements ORCCertificate {
* {@link ORCCertificate#ALLOWANCES_TRUE_WIND_ANGLES}.
*/
public ORCCertificateImpl(Speed[] allowancesTrueWindSpeeds, Bearing[] allowancesTrueWindAngles,
String idConsistingOfNatAuthCertNoAndBIN, String sailnumber, String boatName, String boatClassName,
Distance length, Duration gph, Double cdl, TimePoint issueDate,
String referenceNumber, String fileId, String sailnumber, String boatName,
String boatClassName, Distance length, Duration gph, Double cdl,
TimePoint issueDate, CountryCode issuingCountry,
Map<Speed, Map<Bearing, Speed>> velocityPredictionsPerTrueWindSpeedAndAngle, Map<Speed, Bearing> beatAngles,
Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed, Map<Speed, Duration> beatAllowancePerTrueWindSpeed,
Map<Speed, Bearing> runAngles, Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed,
Map<Speed, Bearing> runAngles,
Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed,
Map<Speed, Duration> runAllowancePerTrueWindSpeed,
Map<Speed, Speed> windwardLeewardSpeedPredictionsPerTrueWindSpeed,
Map<Speed, Speed> longDistanceSpeedPredictionsPerTrueWindSpeed,
@@ -123,7 +125,9 @@ public class ORCCertificateImpl implements ORCCertificate {
Map<Speed, Speed> nonSpinnakerSpeedPredictionsPerTrueWindSpeed) {
this.allowancesTrueWindAngles = allowancesTrueWindAngles;
this.allowancesTrueWindSpeeds = allowancesTrueWindSpeeds;
this.idConsistingOfNatAuthCertNoAndBIN = idConsistingOfNatAuthCertNoAndBIN;
this.referenceNumber = referenceNumber;
this.fileId = fileId;
this.issuingCountry = issuingCountry;
this.sailNumber = sailnumber;
this.boatName = boatName;
this.boatClassName = boatClassName;
@@ -150,21 +154,23 @@ public class ORCCertificateImpl implements ORCCertificate {
* {@link ORCCertificate#ALLOWANCES_TRUE_WIND_ANGLES}, respectively, for the matrix of time allowances
* or, conversely, the speed predictions.
*/
public ORCCertificateImpl(String idConsistingOfNatAuthCertNoAndBIN,
String sailnumber, String boatName, String boatClassName,
Distance length, Duration gph,
Double cdl, TimePoint issueDate,
Map<Speed, Map<Bearing, Speed>> velocityPredictionsPerTrueWindSpeedAndAngle,
public ORCCertificateImpl(String referenceNumber,
String fileId, String sailnumber, String boatName,
String boatClassName, Distance length,
Duration gph, Double cdl,
TimePoint issueDate,
CountryCode issuingCountry, Map<Speed, Map<Bearing, Speed>> velocityPredictionsPerTrueWindSpeedAndAngle,
Map<Speed, Bearing> beatAngles, Map<Speed, Speed> beatVMGPredictionPerTrueWindSpeed,
Map<Speed, Duration> beatAllowancePerTrueWindSpeed, Map<Speed, Bearing> runAngles,
Map<Speed, Duration> beatAllowancePerTrueWindSpeed,
Map<Speed, Bearing> runAngles,
Map<Speed, Speed> runVMGPredictionPerTrueWindSpeed,
Map<Speed, Duration> runAllowancePerTrueWindSpeed,
Map<Speed, Speed> windwardLeewardSpeedPredictionsPerTrueWindSpeed,
Map<Speed, Speed> longDistanceSpeedPredictionsPerTrueWindSpeed,
Map<Speed, Speed> circularRandomSpeedPredictionsPerTrueWindSpeed,
Map<Speed, Speed> nonSpinnakerSpeedPredictionsPerTrueWindSpeed) {
this(ALLOWANCES_TRUE_WIND_SPEEDS, ALLOWANCES_TRUE_WIND_ANGLES, idConsistingOfNatAuthCertNoAndBIN, sailnumber,
boatName, boatClassName, length, gph, cdl, issueDate, velocityPredictionsPerTrueWindSpeedAndAngle,
this(ALLOWANCES_TRUE_WIND_SPEEDS, ALLOWANCES_TRUE_WIND_ANGLES, referenceNumber, fileId, sailnumber, boatName,
boatClassName, length, gph, cdl, issueDate, issuingCountry, velocityPredictionsPerTrueWindSpeedAndAngle,
beatAngles, beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, runAngles,
runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed,
windwardLeewardSpeedPredictionsPerTrueWindSpeed, longDistanceSpeedPredictionsPerTrueWindSpeed,
@@ -173,7 +179,22 @@ public class ORCCertificateImpl implements ORCCertificate {
@Override
public String getId() {
return idConsistingOfNatAuthCertNoAndBIN;
return getReferenceNumber();
}
@Override
public String getReferenceNumber() {
return referenceNumber;
}
@Override
public String getFileId() {
return fileId;
}
@Override
public CountryCode getIssuingCountry() {
return issuingCountry;
}
@Override
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.common.orc.impl;
import com.sap.sailing.domain.common.orc.AverageWindOnLegCache;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLeg;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLegTypes;
import com.sap.sse.common.Bearing;
@@ -33,6 +34,11 @@ public class ORCPerformanceCurveLegImpl implements ORCPerformanceCurveLeg {
return twa;
}
@Override
public Bearing getTwa(AverageWindOnLegCache cache) {
return twa;
}
@Override
public ORCPerformanceCurveLeg scale(double share) {
final Distance scaledLength = getLength().scale(share);
@@ -22,6 +22,7 @@ public enum AvailableWindFinderSpotCollections {
KORNATEN("kornaten"),
MUEGGELSEE("mueggelsee"),
TEGERNSEE("tegernsee"),
TORTOLA("tortola"),
AUCKLAND("auckland");
private final String name;