Merge branch 'master' into bug4425

Conflicts:
	java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java
	java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/IdleOverallLeaderBoardNode.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/leaderboard/LeaderboardSettingsDialogComponent.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/leaderboard/MultiRaceLeaderboardPanelLifecycle.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/leaderboard/MultiRaceLeaderboardSettingsDialogComponent.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/leaderboard/OverallLeaderboardSettingsDialogComponent.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/leaderboard/SingleRaceLeaderboardSettingsDialogComponent.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/MultiRaceLeaderboardPanel.java
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java
This commit is contained in:
Kai Börnert committed 2018-04-09 15:04:51 +02:00
commit 8a9137e600
840 files changed
+182611 -43851

No files matched your search

@@ -1,9 +1,13 @@
package com.sap.sailing.dashboards.gwt.client.actions;
import java.util.List;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardAction;
import com.sap.sailing.dashboards.gwt.shared.dispatch.DashboardDispatchContext;
import com.sap.sailing.dashboards.gwt.shared.dto.LeaderboardCompetitorsDTO;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
@@ -29,7 +33,9 @@ public class GetCompetitorInLeaderboardAction implements DashboardAction<Leaderb
public LeaderboardCompetitorsDTO execute(DashboardDispatchContext dashboardDispatchContext) throws DispatchException {
LeaderboardCompetitorsDTO result = new LeaderboardCompetitorsDTO();
Leaderboard lb = dashboardDispatchContext.getRacingEventService().getLeaderboardByName(this.leaderboarName);
result.setCompetitors(dashboardDispatchContext.getRacingEventService().getBaseDomainFactory().getCompetitorDTOList(lb.getCompetitorsFromBestToWorst(MillisecondsTimePoint.now())));
List<Competitor> competitorsFromBestToWorst = lb.getCompetitorsFromBestToWorst(MillisecondsTimePoint.now());
List<CompetitorDTO> competitorDTOs = dashboardDispatchContext.getRacingEventService().getBaseDomainFactory().getCompetitorDTOList(competitorsFromBestToWorst);
result.setCompetitors(competitorDTOs);
return result;
}
}
@@ -26,7 +26,7 @@ import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisDTO;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sailing.gwt.ui.client.CompetitorColorProvider;
import com.sap.sailing.gwt.ui.client.CompetitorColorProviderImpl;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.RaceCompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
@@ -74,7 +74,7 @@ public class StartAnalysisCard extends Composite implements HasWidgets, StartAna
private SailingServiceAsync sailingServiceAsync;
private StringMessages stringMessages;
private final CompetitorSelectionModel competitorSelectionModel;
private final RaceCompetitorSelectionModel competitorSelectionModel;
private final CompetitorColorProvider colorProvider;
private final double WIND_LINE_ADVANTAGE_DIV_WIDTH_IN_PT = 185;
@@ -88,7 +88,7 @@ public class StartAnalysisCard extends Composite implements HasWidgets, StartAna
this.sailingServiceAsync = sailingServiceAsync;
this.raceMapResources = raceMapResources;
colorProvider = new CompetitorColorProviderImpl();
competitorSelectionModel = new CompetitorSelectionModel(/* hasMultiSelection */true, colorProvider);
competitorSelectionModel = new RaceCompetitorSelectionModel(/* hasMultiSelection */true, colorProvider);
competitorSelectionModel.setCompetitors(startAnalysisDTO.getCompetitorDTOsFromStartAnaylsisCompetitorDTOs(),
raceMap);
initWidget(uiBinder.createAndBindUi(this));
@@ -15,6 +15,7 @@ import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisDTO;
import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisRankingTableEntryDTO;
import com.sap.sailing.dashboards.gwt.shared.dto.StartLineAdvantageDTO;
import com.sap.sailing.dashboards.gwt.shared.dto.WindAndAdvantagesInfoForStartLineDTO;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.LegType;
@@ -59,7 +60,8 @@ public final class StartAnalysisDTOFactory extends AbstractStartAnalysisCreation
competitors.add(createStartAnalysisCompetitorDTO(dashboardDispatchContext, trackedRace, rankOfCompetitorWhilePassingSecondWaypoint, competitor));
}
if (competitor != null) {
startAnalysisDTO.competitor = dashboardDispatchContext.getRacingEventService().getBaseDomainFactory().getCompetitorStore().convertToCompetitorDTO(competitor);
Boat boatOfCompetitor = trackedRace.getBoatOfCompetitor(competitor);
startAnalysisDTO.competitor = dashboardDispatchContext.getRacingEventService().getBaseDomainFactory().getCompetitorStore().convertToCompetitorWithBoatDTO(competitor, boatOfCompetitor);
logger.log(Level.INFO, "Created startanalysis for competitor"+competitor);
}
startAnalysisDTO.startAnalysisCompetitorDTOs = competitors;
@@ -191,8 +193,9 @@ public final class StartAnalysisDTOFactory extends AbstractStartAnalysisCreation
private static StartAnalysisCompetitorDTO createStartAnalysisCompetitorDTO(DashboardDispatchContext dashboardDispatchContext, TrackedRace trackedRace, int rank, Competitor competitor) {
StartAnalysisCompetitorDTO startAnalysisCompetitorDTOsForRace = new StartAnalysisCompetitorDTO();
Boat boatOfCompetitor = trackedRace.getBoatOfCompetitor(competitor);
startAnalysisCompetitorDTOsForRace.competitorDTO = dashboardDispatchContext.getRacingEventService().getBaseDomainFactory().getCompetitorStore()
.convertToCompetitorDTO(competitor);
.convertToCompetitorWithBoatDTO(competitor, boatOfCompetitor);
startAnalysisCompetitorDTOsForRace.rankingTableEntryDTO = createRankTableEntry(trackedRace, rank, competitor);
return startAnalysisCompetitorDTOsForRace;
}
@@ -1,5 +1,6 @@
package com.sap.sailing.datamining.shared;
import com.sap.sse.common.Duration;
import com.sap.sse.common.settings.SerializableSettings;
/**
@@ -11,9 +12,9 @@ public abstract class ManeuverSettings extends SerializableSettings {
private static final long serialVersionUID = -393430331972342L;
public abstract Double getMinManeuverDuration();
public abstract Duration getMinManeuverDuration();
public abstract Double getMaxManeuverDuration();
public abstract Duration getMaxManeuverDuration();
public abstract Double getMinManeuverEnteringSpeedInKnots();
@@ -30,7 +31,19 @@ public abstract class ManeuverSettings extends SerializableSettings {
public abstract Double getMinManeuverExitingAbsTWA();
public abstract Double getMaxManeuverExitingAbsTWA();
public abstract Double getMinAbsCourseChangeInDegrees();
public abstract Double getMaxAbsCourseChangeInDegrees();
public abstract Duration getMinDurationFromPrecedingManeuver();
public abstract Duration getMaxDurationFromPrecedingManeuver();
public abstract Duration getMinDurationToFollowingManeuver();
public abstract Duration getMaxDurationToFollowingManeuver();
public abstract boolean isMainCurveAnalysis();
}
@@ -1,5 +1,7 @@
package com.sap.sailing.datamining.shared;
import com.sap.sse.common.Duration;
/**
*
* @author Vladislav Chumak (D069712)
@@ -9,8 +11,8 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
private static final long serialVersionUID = 69258712144L;
private Double minManeuverDuration;
private Double maxManeuverDuration;
private Duration minManeuverDuration;
private Duration maxManeuverDuration;
private Double minManeuverEnteringSpeedInKnots;
private Double maxManeuverEnteringSpeedInKnots;
private Double minManeuverExitingSpeedInKnots;
@@ -19,20 +21,30 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
private Double maxManeuverEnteringAbsTWA;
private Double minManeuverExitingAbsTWA;
private Double maxManeuverExitingAbsTWA;
private Double minAbsCourseChangeInDegrees;
private Double maxAbsCourseChangeInDegrees;
private Duration minDurationFromPrecedingManeuver;
private Duration maxDurationFromPrecedingManeuver;
private Duration minDurationToFollowingManeuver;
private Duration maxDurationToFollowingManeuver;
private boolean mainCurveAnalysis;
public static ManeuverSettingsImpl createDefault() {
return new ManeuverSettingsImpl(1.0, null, 2.0, null, 1.0, null, null, null, null, null, false);
return new ManeuverSettingsImpl(Duration.ONE_SECOND, null, 2.0, null, 1.0, null, null, null, null, null, false,
null, null, null, null, null, null);
}
public ManeuverSettingsImpl() {
}
public ManeuverSettingsImpl(Double minManeuverDuration, Double maxManeuverDuration,
public ManeuverSettingsImpl(Duration minManeuverDuration, Duration maxManeuverDuration,
Double minManeuverEnteringSpeedInKnots, Double maxManeuverEnteringSpeedInKnots,
Double minManeuverExitingSpeedInKnots, Double maxManeuverExitingSpeedInKnots,
Double minManeuverEnteringAbsTWA, Double maxManeuverEnteringAbsTWA, Double minManeuverExitingAbsTWA,
Double maxManeuverExitingAbsTWA, boolean mainCurveAnalysis) {
Double maxManeuverExitingAbsTWA, boolean mainCurveAnalysis, Double minAbsCourseChangeInDegrees,
Double maxAbsCourseChangeInDegrees, Duration minDurationFromPrecedingManeuver,
Duration maxDurationFromPrecedingManeuver, Duration minDurationToFollowingManeuver,
Duration maxDurationToFollowingManeuver) {
super();
this.minManeuverDuration = minManeuverDuration;
this.maxManeuverDuration = maxManeuverDuration;
@@ -45,13 +57,43 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
this.minManeuverExitingAbsTWA = minManeuverExitingAbsTWA;
this.maxManeuverExitingAbsTWA = maxManeuverExitingAbsTWA;
this.mainCurveAnalysis = mainCurveAnalysis;
this.minAbsCourseChangeInDegrees = minAbsCourseChangeInDegrees;
this.maxAbsCourseChangeInDegrees = maxAbsCourseChangeInDegrees;
this.minDurationFromPrecedingManeuver = minDurationFromPrecedingManeuver;
this.maxDurationFromPrecedingManeuver = maxDurationFromPrecedingManeuver;
this.minDurationToFollowingManeuver = minDurationToFollowingManeuver;
this.maxDurationToFollowingManeuver = maxDurationToFollowingManeuver;
}
public Double getMinManeuverDuration() {
public Double getMinAbsCourseChangeInDegrees() {
return minAbsCourseChangeInDegrees;
}
public Double getMaxAbsCourseChangeInDegrees() {
return maxAbsCourseChangeInDegrees;
}
public Duration getMinDurationFromPrecedingManeuver() {
return minDurationFromPrecedingManeuver;
}
public Duration getMaxDurationFromPrecedingManeuver() {
return maxDurationFromPrecedingManeuver;
}
public Duration getMinDurationToFollowingManeuver() {
return minDurationToFollowingManeuver;
}
public Duration getMaxDurationToFollowingManeuver() {
return maxDurationToFollowingManeuver;
}
public Duration getMinManeuverDuration() {
return minManeuverDuration;
}
public Double getMaxManeuverDuration() {
public Duration getMaxManeuverDuration() {
return maxManeuverDuration;
}
@@ -86,7 +128,7 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
public Double getMaxManeuverExitingAbsTWA() {
return maxManeuverExitingAbsTWA;
}
@Override
public boolean isMainCurveAnalysis() {
return mainCurveAnalysis;
@@ -97,6 +139,11 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
final int prime = 31;
int result = 1;
result = prime * result + (mainCurveAnalysis ? 1231 : 1237);
result = prime * result + ((maxAbsCourseChangeInDegrees == null) ? 0 : maxAbsCourseChangeInDegrees.hashCode());
result = prime * result
+ ((maxDurationFromPrecedingManeuver == null) ? 0 : maxDurationFromPrecedingManeuver.hashCode());
result = prime * result
+ ((maxDurationToFollowingManeuver == null) ? 0 : maxDurationToFollowingManeuver.hashCode());
result = prime * result + ((maxManeuverDuration == null) ? 0 : maxManeuverDuration.hashCode());
result = prime * result + ((maxManeuverEnteringAbsTWA == null) ? 0 : maxManeuverEnteringAbsTWA.hashCode());
result = prime * result
@@ -104,6 +151,11 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
result = prime * result + ((maxManeuverExitingAbsTWA == null) ? 0 : maxManeuverExitingAbsTWA.hashCode());
result = prime * result
+ ((maxManeuverExitingSpeedInKnots == null) ? 0 : maxManeuverExitingSpeedInKnots.hashCode());
result = prime * result + ((minAbsCourseChangeInDegrees == null) ? 0 : minAbsCourseChangeInDegrees.hashCode());
result = prime * result
+ ((minDurationFromPrecedingManeuver == null) ? 0 : minDurationFromPrecedingManeuver.hashCode());
result = prime * result
+ ((minDurationToFollowingManeuver == null) ? 0 : minDurationToFollowingManeuver.hashCode());
result = prime * result + ((minManeuverDuration == null) ? 0 : minManeuverDuration.hashCode());
result = prime * result + ((minManeuverEnteringAbsTWA == null) ? 0 : minManeuverEnteringAbsTWA.hashCode());
result = prime * result
@@ -125,6 +177,21 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
ManeuverSettingsImpl other = (ManeuverSettingsImpl) obj;
if (mainCurveAnalysis != other.mainCurveAnalysis)
return false;
if (maxAbsCourseChangeInDegrees == null) {
if (other.maxAbsCourseChangeInDegrees != null)
return false;
} else if (!maxAbsCourseChangeInDegrees.equals(other.maxAbsCourseChangeInDegrees))
return false;
if (maxDurationFromPrecedingManeuver == null) {
if (other.maxDurationFromPrecedingManeuver != null)
return false;
} else if (!maxDurationFromPrecedingManeuver.equals(other.maxDurationFromPrecedingManeuver))
return false;
if (maxDurationToFollowingManeuver == null) {
if (other.maxDurationToFollowingManeuver != null)
return false;
} else if (!maxDurationToFollowingManeuver.equals(other.maxDurationToFollowingManeuver))
return false;
if (maxManeuverDuration == null) {
if (other.maxManeuverDuration != null)
return false;
@@ -150,6 +217,21 @@ public class ManeuverSettingsImpl extends ManeuverSettings {
return false;
} else if (!maxManeuverExitingSpeedInKnots.equals(other.maxManeuverExitingSpeedInKnots))
return false;
if (minAbsCourseChangeInDegrees == null) {
if (other.minAbsCourseChangeInDegrees != null)
return false;
} else if (!minAbsCourseChangeInDegrees.equals(other.minAbsCourseChangeInDegrees))
return false;
if (minDurationFromPrecedingManeuver == null) {
if (other.minDurationFromPrecedingManeuver != null)
return false;
} else if (!minDurationFromPrecedingManeuver.equals(other.minDurationFromPrecedingManeuver))
return false;
if (minDurationToFollowingManeuver == null) {
if (other.minDurationToFollowingManeuver != null)
return false;
} else if (!minDurationToFollowingManeuver.equals(other.minDurationToFollowingManeuver))
return false;
if (minManeuverDuration == null) {
if (other.minManeuverDuration != null)
return false;
@@ -128,7 +128,7 @@ AbsoluteTrueWindAngle=Absolute true wind angle (TWA)
TrueWindAngle=True wind angle (TWA)
Wind=Wind
VMG=Velocity Made Good
MaxAngularVelocityInDegreesPerSecond=Maximal angular velocity in deg/s
MaxTurningRateInDegreesPerSecond=Max. turning rate in deg/s
ManeuverEnteringAbsTWA=Absolute TWA before maneuver
ManeuverExitingAbsTWA=Absolute TWA after maneuver
ManeuverSpeedDetailsRetrieverChain=Maneuver speed details
@@ -149,8 +149,8 @@ AbsTWAAtManeuverClimax=Absolute TWA at maneuver climax
ManeuverEnteringSpeedInKnots=Maneuver entering speed (kts)
ManeuverExitingSpeedInKnots=Maneuver exiting speed (kts)
TackBeforeManeuver=Tack before maneuver
ManeuverBoundariesRetrieverChain=Maneuver boundaries
ManeuverBoundaries=Maneuver boundaries
CompleteManeuverCurveWithEstimationDataRetrieverChain=Complete maneuver curves with estimation data
CompleteManeuverCurveWithEstimationData=Complete maneuver curves with estimation data
ManeuverStartSpeedDeviationRatioFromAvg=Speed deviation ratio of maneuver start with avg speed before maneuver
ManeuverStartCogDeviationFromAvgInDegrees=COG deviation of maneuver start with avg COG before maneuver in degrees
ManeuverEndSpeedDeviationRatioFromAvg=Speed deviation ratio of maneuver end with avg speed after maneuver
@@ -166,4 +166,26 @@ DurationBetweenStableSpeedWithCourseAndMainCurveEndInSeconds=Duration between st
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveEnd=Speed ratio between stable speed with course and main curve end
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveEndInDegrees=Abs. course difference between stable speed with course and main curve end in degrees
AbsTwaAtLowestRatioToEnteringSpeed=Abs. TWA at lowest ratio to entering speed
AbsTwaAtHighestRatioToEnteringSpeed=Abs. TWA at highest ratio to entering speed
AbsTwaAtHighestRatioToEnteringSpeed=Abs. TWA at highest ratio to entering speed
TypeOfPreviousManeuver=Type of the previous maneuver
TypeOfNextManeuver=Type of the next maneuver
AvgTurningRateInDegreesPerSecond=Avg turning rate in deg/s
ManeuverStartsByRunningAwayFromTheWind=Maneuver starts by running away from the wind
RelativeBearingToNextMarkBeforeManeuver=Relative bearing to the next mark before maneuver
RelativeBearingToNextMarkAfterManeuver=Relative bearing to the next mark after maneuver
AbsRelativeBearingToNextMarkBeforeManeuver=Abs. relative bearing to the next mark before maneuver
AbsRelativeBearingToNextMarkAfterManeuver=Abs. relative bearing to the next mark after maneuver
RatioBetweenDistanceSailedWithAndWithoutManeuver=Ratio between distance sailed with and without maneuver
RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver=Ratio between distance sailed toward middle angle projection with and without maneuver
DurationLostByManeuver=Duration lost by maneuver
DurationLostByManeuverTowardMiddleAngleProjection=duration lost by maneuver toward middle angle projection
JibingCount=Jibing count
TackingCount=Tacking count
AbsTwaAtMaxTurningRate=Abs. TWA at max. turning rate
AbsTwaAtLowestSpeed=Abs. TWA at lowest speed
AbsTwaAtHighestSpeed=Abs. TWA at highest speed
PercentageOfMainCurveProgressUntilLowestSpeed=Percentage of main curve progress until lowest speed
PercentageOfMainCurveProgressUntilHighestSpeed=Percentage of main curve progress until highest speed
PercentageOfMainCurveProgressUntilMaxTurningRate=Percentage of main curve progress until max. turning rate speed
AbsTwaAtManeuverMiddle=Abs. TWA at maneuver middle
GpsSamplingRate=GPS sampling rate
@@ -128,7 +128,7 @@ AbsoluteTrueWindAngle=Absoluter Winkel zum wahren Wind (TWA)
TrueWindAngle=Winkel zum wahren Wind (TWA)
Wind=Wind
VMG=Luv-/Leegeschwindigkeit (VMG)
MaxAngularVelocityInDegreesPerSecond=Maximale Winkelgeschwindigkeit in Grad/Sek.
MaxTurningRateInDegreesPerSecond=Max. Drehrate in deg/s
ManeuverEnteringAbsTWA=Absolutes TWA vor Manöver
ManeuverExitingAbsTWA=Absolutes TWA nach Manöver
ManeuverSpeedDetailsRetrieverChain=Manöver-Geschwindigkeitsdetails
@@ -149,12 +149,12 @@ AbsTWAAtManeuverClimax=Absolutes TWA während Manöver-Höhepunkt
ManeuverEnteringSpeedInKnots=Manöver Anfangsgeschwindigkeit (kn)
ManeuverExitingSpeedInKnots=Manöver Endgeschwindigkeit (kn)
TackBeforeManeuver=Bug vor Manöver-Eintritt
ManeuverBoundariesRetrieverChain=Manöver Grenzen
ManeuverBoundaries=Manöver Grenzen
ManeuverStartSpeedDeviationRatioFromAvg=Verhältnis der Geschwindigkeitabweichung an Manöver-Anfang mit avg Geschwindigkeit vor Manöver
ManeuverStartCogDeviationFromAvgInDegrees=COG-Abweichung an Manöver-Anfang mit avg COG vor Manöver in Grad
ManeuverEndSpeedDeviationRatioFromAvg=Verhältnis der Geschwindigkeitabweichung an Manöver-Ende mit avg Geschwindigkeit nach Manöver
ManeuverEndCogDeviationFromAvgInDegrees=COG-Abweichung an Manöver-Ende mit avg COG nach Manöver in Grad
CompleteManeuverCurveWithEstimationDataRetrieverChain=Komplette Manöverkurven mit Schätzungsdaten
CompleteManeuverCurveWithEstimationData=Komplette Manöverkurven mit Schätzungsdaten
ManeuverStartSpeedDeviationRatioFromAvg=Verhältnis der Geschwindigkeitabweichung an Manöver-Anfang mit durchschnittlicher Geschwindigkeit vor Manöver
ManeuverStartCogDeviationFromAvgInDegrees=COG-Abweichung an Manöver-Anfang mit durchschnittlichem COG vor Manöver in Grad
ManeuverEndSpeedDeviationRatioFromAvg=Verhältnis der Geschwindigkeitabweichung an Manöver-Ende mit durchschnittlicher Geschwindigkeit nach Manöver
ManeuverEndCogDeviationFromAvgInDegrees=COG-Abweichung an Manöver-Ende mit durchschnittlichem COG nach Manöver in Grad
DurationToNextManeuverInSeconds=Dauer vom Ende des aktuellen Manövers bis zum Anfang des nächsten Manövers in Sekunden
DurationFromPreviousManeuverInSeconds=Dauer vom Ende des letzten Manövers bis zum Anfang des aktuellen Manövers in Sekunden
NextManeuverAtLeastOneSecondInFront=Anfang des nächsten Manövers ist mindestens eine Sekunde weiter als das Ende des aktuellen Manövers
@@ -166,4 +166,29 @@ DurationBetweenStableSpeedWithCourseAndMainCurveEndInSeconds=Dauer zwischen stab
SpeedRatioBetweenStableSpeedWithCourseAndMainCurveEnd=Geschwindigkeitsverhältnis zwischen stabiler Geschwindigkeit mit Kurs und Ende der Hauptkurve in Sekunden
AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveEndInDegrees=Abs. Kursunterschied zwischen stabiler Geschwindigkeit mit Kurs und Ende der Hauptkurve in Grad
AbsTwaAtLowestRatioToEnteringSpeed=Abs. TWA an Stelle mit kleinstem Verhältnis zu Anfangsgeschwindigkeit
AbsTwaAtHighestRatioToEnteringSpeed=Abs. TWA an Stelle mit höchstem Verhältnis zu Anfangsgeschwindigkeit
AbsTwaAtHighestRatioToEnteringSpeed=Abs. TWA an Stelle mit höchstem Verhältnis zu Anfangsgeschwindigkeit
TypeOfPreviousManeuver=Typ des vorigen Manövers
TypeOfNextManeuver=Typ des nächsten Manövers
AvgTurningRateInDegreesPerSecond=Durchschnitliche Drehrate in deg/s
ManeuverStartsByRunningAwayFromTheWind=Manöver beginnt in Abfall-Richtung
RelativeBearingToNextMarkBeforeManeuver=Relative Richtung zur nächsten Marke vor dem Manöver
RelativeBearingToNextMarkAfterManeuver=Relative Richtung zur nächsten Marke nach dem Manöver
AbsRelativeBearingToNextMarkBeforeManeuver=Abs. relative Richtung zur nächsten Marke vor dem Manöver
AbsRelativeBearingToNextMarkAfterManeuver=Abs. relative Richtung zur nächsten Marke nach dem Manöver
RatioBetweenDistanceSailedWithAndWithoutManeuver=Verhältnis zwischen gesegelter Distanz mit und ohne Manövrierung
RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver=Verhältnis zwischen gesegelter Distanz von Mittelwinkel-Projektion mit und ohne Manövrierung
DurationLostByManeuver=Verlorene Zeit
DurationLostByManeuverTowardMiddleAngleProjection=Verlorene Zeit anhand der Mittelwinkel-Projektion
CurveWithUnstableCourseAndSpeed=Kurve mit instabilem Kurs und Geschwindigkeit
MainCurve=Hauptkurve
JibingCount=Anzahl Halsen
TackingCount=Anzahl Wenden
AbsTwaAtMaxTurningRate=Abs. TWA bei max. Drehrate
AbsTwaAtLowestSpeed=Abs. TWA bei geringster Geschwindigkeit
AbsTwaAtHighestSpeed=Abs. TWA bei höchster Geschwindigkeit
PercentageOfMainCurveProgressUntilLowestSpeed=Prozentualer Fortschritt der Hauptkurve bis zum Erreichen von geringster Geschwindigkeit
PercentageOfMainCurveProgressUntilHighestSpeed=Prozentualer Fortschritt der Hauptkurve bis zum Erreichen von höchster Geschwindigkeit
PercentageOfMainCurveProgressUntilMaxTurningRate=Prozentualer Fortschritt der Hauptkurve bis zum Erreichen von max. Drehrate
ManeuverTypeForCompleteManeuverCurve=Manövertyp für komplette Manöverkurve
AbsTwaAtManeuverMiddle=Abs. TWA während Manövermitte
GpsSamplingRate=GPS-Samplingrate
@@ -14,7 +14,7 @@ import com.sap.sailing.datamining.data.HasFoilingSegmentContext;
import com.sap.sailing.datamining.data.HasGPSFixContext;
import com.sap.sailing.datamining.data.HasLeaderboardContext;
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
import com.sap.sailing.datamining.data.HasManeuverBoundariesContext;
import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext;
import com.sap.sailing.datamining.data.HasManeuverContext;
import com.sap.sailing.datamining.data.HasManeuverSpeedDetailsContext;
import com.sap.sailing.datamining.data.HasMarkPassingContext;
@@ -107,7 +107,7 @@ public class Activator extends AbstractDataMiningActivatorWithPredefinedQueries
internalClasses.add(HasFoilingSegmentContext.class);
internalClasses.add(HasManeuverContext.class);
internalClasses.add(HasManeuverSpeedDetailsContext.class);
internalClasses.add(HasManeuverBoundariesContext.class);
internalClasses.add(HasCompleteManeuverCurveWithEstimationDataContext.class);
internalClasses.add(HasMarkPassingContext.class);
internalClasses.add(HasRaceOfCompetitorContext.class);
internalClasses.add(HasLeaderboardGroupContext.class);
@@ -10,7 +10,7 @@ import com.sap.sailing.datamining.data.HasGPSFixContext;
import com.sap.sailing.datamining.data.HasLeaderboardContext;
import com.sap.sailing.datamining.data.HasManeuverContext;
import com.sap.sailing.datamining.data.HasManeuverSpeedDetailsContext;
import com.sap.sailing.datamining.data.HasManeuverBoundariesContext;
import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext;
import com.sap.sailing.datamining.data.HasMarkPassingContext;
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
import com.sap.sailing.datamining.data.HasRaceResultOfCompetitorContext;
@@ -28,7 +28,7 @@ import com.sap.sailing.datamining.impl.components.LeaderboardGroupRetrievalProce
import com.sap.sailing.datamining.impl.components.LeaderboardRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.ManeuverRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.ManeuverSpeedDetailsRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.ManeuverBoundariesRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.CompleteManeuverCurveWithEstimationDataRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.MarkPassingRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.RaceOfCompetitorRetrievalProcessor;
import com.sap.sailing.datamining.impl.components.TrackedLegOfCompetitorRetrievalProcessor;
@@ -128,13 +128,13 @@ public class SailingDataRetrievalChainDefinitions {
"ManeuverSpeedDetails");
dataRetrieverChainDefinitions.add(speedDetailsDataRetrieverChainDefinition);
DataRetrieverChainDefinition<RacingEventService, HasManeuverBoundariesContext> maneuverBoundariesRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
raceOfCompetitorRetrieverChainDefinition, HasManeuverBoundariesContext.class,
"ManeuverBoundariesRetrieverChain");
maneuverBoundariesRetrieverChainDefinition.endWith(RaceOfCompetitorRetrievalProcessor.class,
ManeuverBoundariesRetrievalProcessor.class, HasManeuverBoundariesContext.class,
"ManeuverBoundaries");
dataRetrieverChainDefinitions.add(maneuverBoundariesRetrieverChainDefinition);
DataRetrieverChainDefinition<RacingEventService, HasCompleteManeuverCurveWithEstimationDataContext> completeManeuverCurveWithEstimationDataRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
raceOfCompetitorRetrieverChainDefinition, HasCompleteManeuverCurveWithEstimationDataContext.class,
"CompleteManeuverCurveWithEstimationDataRetrieverChain");
completeManeuverCurveWithEstimationDataRetrieverChainDefinition.endWith(RaceOfCompetitorRetrievalProcessor.class,
CompleteManeuverCurveWithEstimationDataRetrievalProcessor.class, HasCompleteManeuverCurveWithEstimationDataContext.class, ManeuverSettings.class, ManeuverSettingsImpl.createDefault(),
"CompleteManeuverCurveWithEstimationData");
dataRetrieverChainDefinitions.add(completeManeuverCurveWithEstimationDataRetrieverChainDefinition);
final DataRetrieverChainDefinition<RacingEventService, HasMarkPassingContext> markPassingRetrieverChainDefinition = new SimpleDataRetrieverChainDefinition<>(
legOfCompetitorRetrieverChainDefinition, HasMarkPassingContext.class, "MarkPassingSailingDomainRetrieverChain");
@@ -0,0 +1,117 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.maneuverdetection.CompleteManeuverCurveWithEstimationData;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
/**
*
* @author Vladislav Chumak (D069712)
*
*/
public interface HasCompleteManeuverCurveWithEstimationDataContext {
@Connector(scanForStatistics = false)
HasRaceOfCompetitorContext getRaceOfCompetitorContext();
@Connector
CompleteManeuverCurveWithEstimationData getCompleteManeuverCurveWithEstimationData();
@Dimension(messageKey = "ToSide")
NauticalSide getToSide();
@Statistic(messageKey = "ManeuverStartSpeedDeviationRatioFromAvg", ordinal = 1, resultDecimals = 4)
Double getManeuverStartSpeedDeviationRatioFromAvgStatistic();
@Statistic(messageKey = "ManeuverStartCogDeviationFromAvgInDegrees", ordinal = 2, resultDecimals = 4)
Double getManeuverStartCogDeviationFromAvgInDegreesStatistic();
@Statistic(messageKey = "ManeuverEndSpeedDeviationRatioFromAvg", ordinal = 3, resultDecimals = 4)
Double getManeuverEndSpeedDeviationRatioFromAvgStatistic();
@Statistic(messageKey = "ManeuverEndCogDeviationFromAvgInDegrees", ordinal = 4, resultDecimals = 4)
Double getManeuverEndCogDeviationFromAvgInDegreesStatistic();
@Statistic(messageKey = "DurationToNextManeuverInSeconds", ordinal = 5, resultDecimals = 4)
Double getDurationToNextManeuverInSecondsStatistic();
@Statistic(messageKey = "DurationFromPreviousManeuverInSeconds", ordinal = 6, resultDecimals = 4)
Double getDurationFromPreviousManeuverInSecondsStatistic();
@Dimension(messageKey = "NextManeuverAtLeastOneSecondInFront", ordinal = 7)
boolean isNextManeuverAtLeastOneSecondInFront();
@Dimension(messageKey = "PreviousManeuverAtLeastOneSecondBehind", ordinal = 8)
boolean isPreviousManeuverAtLeastOneSecondBehind();
@Dimension(messageKey = "JibingCount")
ClusterDTO getJibingCount();
@Dimension(messageKey = "TackingCount")
ClusterDTO getTackingCount();
@Statistic(messageKey = "AbsTwaAtMaxTurningRate")
double getAbsTwaAtMaxTurningRate();
@Statistic(messageKey = "AbsTwaAtLowestSpeed")
double getAbsTwaAtLowestSpeed();
@Statistic(messageKey = "AbsTwaAtHighestSpeed")
double getAbsTwaAtHighestSpeed();
@Statistic(messageKey = "AbsTwaAtManeuverMiddle")
double getAbsTwaAtManeuverMiddle();
@Statistic(messageKey = "GpsSamplingRate")
double getGpsSamplingRate();
@Statistic(messageKey = "ManeuverEnteringAbsTWA")
Double getEnteringAbsTWA();
@Statistic(messageKey = "ManeuverExitingAbsTWA")
Double getExitingAbsTWA();
@Dimension(messageKey = "TypeOfPreviousManeuver")
ManeuverType getTypeOfPreviousManeuver();
@Dimension(messageKey = "TypeOfNextManeuver")
ManeuverType getTypeOfNextManeuver();
@Statistic(messageKey = "AbsoluteDirectionChange", resultDecimals = 2)
Double getAbsoluteDirectionChangeInDegrees();
@Statistic(messageKey = "RatioBetweenDistanceSailedWithAndWithoutManeuver", resultDecimals = 4)
double getRatioBetweenDistanceSailedWithAndWithoutManeuver();
@Statistic(messageKey = "DurationLostByManeuver", resultDecimals = 4)
double getDurationLostByManeuver();
@Statistic(messageKey = "DurationLostByManeuverTowardMiddleAngleProjection", resultDecimals = 4)
double getDurationLostByManeuverTowardMiddleAngleProjection();
@Statistic(messageKey = "RatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver", resultDecimals = 4)
double getRatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver();
@Statistic(messageKey = "RelativeBearingToNextMarkBeforeManeuver", resultDecimals = 1)
Double getRelativeBearingToNextMarkBeforeManeuver();
@Statistic(messageKey = "RelativeBearingToNextMarkAfterManeuver", resultDecimals = 1)
Double getRelativeBearingToNextMarkAfterManeuver();
@Statistic(messageKey = "AbsRelativeBearingToNextMarkBeforeManeuver", resultDecimals = 1)
Double getAbsRelativeBearingToNextMarkBeforeManeuver();
@Statistic(messageKey = "AbsRelativeBearingToNextMarkAfterManeuver", resultDecimals = 1)
Double getAbsRelativeBearingToNextMarkAfterManeuver();
@Statistic(messageKey = "ManeuverEnteringSpeedInKnots", resultDecimals = 2)
Double getManeuverEnteringSpeed();
@Statistic(messageKey = "ManeuverExitingSpeedInKnots", resultDecimals = 2)
Double getManeuverExitingSpeed();
}
@@ -1,51 +0,0 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sse.datamining.annotations.Connector;
import com.sap.sse.datamining.annotations.Dimension;
import com.sap.sse.datamining.annotations.Statistic;
/**
* Contains statistics for analysis of computation correctness of maneuver boundaries.
*
* @author Vladislav Chumak (D069712)
*
*/
public interface HasManeuverBoundariesContext {
@Connector(scanForStatistics = false)
HasRaceOfCompetitorContext getRaceOfCompetitorContext();
// FIXME due to UI bug there is at least one dimension per fact required
@Dimension(messageKey = "ManeuverDirection", ordinal = 3)
NauticalSide getToSide();
@Dimension(messageKey = "ManeuverType", ordinal = 4)
ManeuverType getManeuverType();
@Statistic(messageKey = "ManeuverStartSpeedDeviationRatioFromAvg", ordinal = 1, resultDecimals = 4)
Double getManeuverStartSpeedDeviationRatioFromAvgStatistic();
@Statistic(messageKey = "ManeuverStartCogDeviationFromAvgInDegrees", ordinal = 2, resultDecimals = 4)
Double getManeuverStartCogDeviationFromAvgInDegreesStatistic();
@Statistic(messageKey = "ManeuverEndSpeedDeviationRatioFromAvg", ordinal = 3, resultDecimals = 4)
Double getManeuverEndSpeedDeviationRatioFromAvgStatistic();
@Statistic(messageKey = "ManeuverEndCogDeviationFromAvgInDegrees", ordinal = 4, resultDecimals = 4)
Double getManeuverEndCogDeviationFromAvgInDegreesStatistic();
@Statistic(messageKey = "DurationToNextManeuverInSeconds", ordinal = 5, resultDecimals = 4)
Double getDurationToNextManeuverInSecondsStatistic();
@Statistic(messageKey = "DurationFromPreviousManeuverInSeconds", ordinal = 6, resultDecimals = 4)
Double getDurationFromPreviousManeuverInSecondsStatistic();
@Statistic(messageKey = "NextManeuverAtLeastOneSecondInFront", ordinal = 7)
boolean isNextManeuverAtLeastOneSecondInFront();
@Statistic(messageKey = "PreviousManeuverAtLeastOneSecondBehind", ordinal = 8)
boolean isPreviousManeuverAtLeastOneSecondBehind();
}
@@ -1,6 +1,7 @@
package com.sap.sailing.datamining.data;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.Tack;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.annotations.Connector;
@@ -13,6 +14,12 @@ public interface HasManeuverContext extends HasManeuver, HasTrackedLegOfCompetit
@Dimension(messageKey = "TackBeforeManeuver")
Tack getTackBeforeManeuver();
@Dimension(messageKey = "TypeOfPreviousManeuver")
ManeuverType getTypeOfPreviousManeuver();
@Dimension(messageKey = "TypeOfNextManeuver")
ManeuverType getTypeOfNextManeuver();
@Statistic(messageKey = "AbsoluteDirectionChange", resultDecimals = 2, ordinal = 3)
Double getAbsoluteDirectionChangeInDegrees();
@@ -61,7 +68,7 @@ public interface HasManeuverContext extends HasManeuver, HasTrackedLegOfCompetit
@Statistic(messageKey = "AbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveEndInDegrees", ordinal = 25, resultDecimals = 2)
Double getAbsCourseDifferenceBetweenStableSpeedWithCourseAndMainCurveEndInDegrees();
TimePoint getTimePointBeforeForAnalysis();
TimePoint getTimePointAfterForAnalysis();
@@ -0,0 +1,151 @@
package com.sap.sailing.datamining.impl.components;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext;
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
import com.sap.sailing.datamining.impl.data.CompleteManeuverCurveWithEstimationDataWithContext;
import com.sap.sailing.datamining.shared.ManeuverSettings;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.maneuverdetection.CompleteManeuverCurveWithEstimationData;
import com.sap.sailing.domain.maneuverdetection.ManeuverDetector;
import com.sap.sailing.domain.maneuverdetection.impl.ManeuverDetectorImpl;
import com.sap.sailing.domain.tracking.CompleteManeuverCurve;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.Duration;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
/**
*
* @author Vladislav Chumak (D069712)
*
*/
public class CompleteManeuverCurveWithEstimationDataRetrievalProcessor extends
AbstractRetrievalProcessor<HasRaceOfCompetitorContext, HasCompleteManeuverCurveWithEstimationDataContext> {
private final ManeuverSettings settings;
public CompleteManeuverCurveWithEstimationDataRetrievalProcessor(ExecutorService executor,
Collection<Processor<HasCompleteManeuverCurveWithEstimationDataContext, ?>> resultReceivers,
ManeuverSettings settings, int retrievalLevel) {
super(HasRaceOfCompetitorContext.class, HasCompleteManeuverCurveWithEstimationDataContext.class, executor,
resultReceivers, retrievalLevel);
this.settings = settings;
}
@Override
protected Iterable<HasCompleteManeuverCurveWithEstimationDataContext> retrieveData(
HasRaceOfCompetitorContext element) {
List<HasCompleteManeuverCurveWithEstimationDataContext> result = new ArrayList<>();
TrackedRace trackedRace = element.getTrackedRaceContext().getTrackedRace();
Competitor competitor = element.getCompetitor();
ManeuverDetector maneuverDetector = new ManeuverDetectorImpl(trackedRace, competitor);
Iterable<Maneuver> maneuvers = trackedRace.getManeuvers(competitor, false);
Iterable<CompleteManeuverCurve> maneuverCurves = maneuverDetector.getCompleteManeuverCurves(maneuvers);
Iterable<CompleteManeuverCurveWithEstimationData> maneuversWithEstimationData = maneuverDetector
.getCompleteManeuverCurvesWithEstimationData(maneuverCurves);
CompleteManeuverCurveWithEstimationData previousManeuver = null;
CompleteManeuverCurveWithEstimationData currentManeuver = null;
for (CompleteManeuverCurveWithEstimationData nextManeuver : maneuversWithEstimationData) {
if (currentManeuver != null) {
CompleteManeuverCurveWithEstimationDataWithContext maneuverWithContext = new CompleteManeuverCurveWithEstimationDataWithContext(
element, currentManeuver, settings, previousManeuver, nextManeuver);
if (currentManeuver.getWind() != null
&& isManeuverCompliantWithSettings(previousManeuver, maneuverWithContext, nextManeuver)) {
result.add(maneuverWithContext);
}
}
previousManeuver = currentManeuver;
currentManeuver = nextManeuver;
}
if (currentManeuver != null) {
CompleteManeuverCurveWithEstimationDataWithContext maneuverWithContext = new CompleteManeuverCurveWithEstimationDataWithContext(
element, currentManeuver, settings, previousManeuver, null);
if (currentManeuver.getWind() != null
&& isManeuverCompliantWithSettings(previousManeuver, maneuverWithContext, null)) {
result.add(maneuverWithContext);
}
}
return result;
}
private boolean isManeuverCompliantWithSettings(CompleteManeuverCurveWithEstimationData previousManeuver,
CompleteManeuverCurveWithEstimationDataWithContext currentManeuverWithContext,
CompleteManeuverCurveWithEstimationData nextManeuver) {
boolean mainCurveAnalysis = settings.isMainCurveAnalysis();
// Compute only numbers which are really required for filtering
Duration maneuverDuration = settings.getMinManeuverDuration() != null
|| settings.getMaxManeuverDuration() != null
? currentManeuverWithContext.getTimePointBeforeForAnalysis()
.until(currentManeuverWithContext.getTimePointAfterForAnalysis())
: null;
double maneuverEnteringSpeed = settings.getMinManeuverEnteringSpeedInKnots() != null
|| settings.getMaxManeuverEnteringSpeedInKnots() != null
? currentManeuverWithContext.getManeuverEnteringSpeed() : 0;
double maneuverExitingSpeed = settings.getMinManeuverExitingSpeedInKnots() != null
|| settings.getMaxManeuverExitingSpeedInKnots() != null
? currentManeuverWithContext.getManeuverExitingSpeed() : 0;
double maneuverEnteringAbsTWA = settings.getMinManeuverEnteringAbsTWA() != null
? currentManeuverWithContext.getEnteringAbsTWA() : 0;
double maneuverExitingAbsTWA = settings.getMinManeuverExitingAbsTWA() != null
? currentManeuverWithContext.getExitingAbsTWA() : 0;
Duration durationToPreviousManeuver = previousManeuver != null
? getManeuverBoundariesForAnalysis(previousManeuver, mainCurveAnalysis).getTimePointAfter()
.until(currentManeuverWithContext.getTimePointBeforeForAnalysis())
: null;
Duration durationToNextManeuver = nextManeuver != null
? currentManeuverWithContext.getTimePointAfterForAnalysis().until(
getManeuverBoundariesForAnalysis(nextManeuver, mainCurveAnalysis).getTimePointBefore())
: null;
if (!(settings.getMinManeuverDuration() != null
&& maneuverDuration.compareTo(settings.getMinManeuverDuration()) < 0
|| settings.getMaxManeuverDuration() != null
&& maneuverDuration.compareTo(settings.getMaxManeuverDuration()) > 0
|| settings.getMinManeuverEnteringSpeedInKnots() != null
&& maneuverEnteringSpeed < settings.getMinManeuverEnteringSpeedInKnots()
|| settings.getMaxManeuverEnteringSpeedInKnots() != null
&& maneuverEnteringSpeed > settings.getMaxManeuverEnteringSpeedInKnots()
|| settings.getMinManeuverExitingSpeedInKnots() != null
&& maneuverExitingSpeed < settings.getMinManeuverExitingSpeedInKnots()
|| settings.getMaxManeuverExitingSpeedInKnots() != null
&& maneuverExitingSpeed > settings.getMaxManeuverExitingSpeedInKnots()
|| settings.getMinManeuverEnteringAbsTWA() != null
&& maneuverEnteringAbsTWA < settings.getMinManeuverEnteringAbsTWA()
|| settings.getMaxManeuverEnteringAbsTWA() != null
&& maneuverEnteringAbsTWA > settings.getMaxManeuverEnteringAbsTWA()
|| settings.getMinManeuverExitingAbsTWA() != null
&& maneuverExitingAbsTWA < settings.getMinManeuverExitingAbsTWA()
|| settings.getMaxManeuverExitingAbsTWA() != null
&& maneuverExitingAbsTWA > settings.getMaxManeuverExitingAbsTWA()
|| settings.getMinAbsCourseChangeInDegrees() != null && currentManeuverWithContext
.getAbsoluteDirectionChangeInDegrees() < settings.getMinAbsCourseChangeInDegrees()
|| settings.getMaxAbsCourseChangeInDegrees() != null && currentManeuverWithContext
.getAbsoluteDirectionChangeInDegrees() > settings.getMaxAbsCourseChangeInDegrees()
|| settings.getMinDurationFromPrecedingManeuver() != null && (previousManeuver == null
|| durationToPreviousManeuver.compareTo(settings.getMinDurationFromPrecedingManeuver()) < 0)
|| settings.getMaxDurationFromPrecedingManeuver() != null && (previousManeuver == null
|| durationToPreviousManeuver.compareTo(settings.getMaxDurationFromPrecedingManeuver()) > 0)
|| settings.getMinDurationToFollowingManeuver() != null && (nextManeuver == null
|| durationToNextManeuver.compareTo(settings.getMinDurationToFollowingManeuver()) < 0)
|| settings.getMaxDurationToFollowingManeuver() != null && (nextManeuver == null
|| durationToNextManeuver.compareTo(settings.getMaxDurationToFollowingManeuver()) > 0))) {
return true;
} else {
return false;
}
}
private ManeuverCurveBoundaries getManeuverBoundariesForAnalysis(CompleteManeuverCurveWithEstimationData maneuver,
boolean mainCurveAnalysis) {
return mainCurveAnalysis ? maneuver.getMainCurve() : maneuver.getCurveWithUnstableCourseAndSpeed();
}
}
@@ -1,49 +0,0 @@
package com.sap.sailing.datamining.impl.components;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutorService;
import com.sap.sailing.datamining.data.HasManeuverBoundariesContext;
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
import com.sap.sailing.datamining.impl.data.ManeuverBoundariesWithContext;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.maneuverdetection.ManeuverWithEstimationData;
import com.sap.sailing.domain.maneuverdetection.ManeuverWithEstimationDataCalculator;
import com.sap.sailing.domain.maneuverdetection.impl.ManeuverWithEstimationDataCalculatorImpl;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
/**
*
* @author Vladislav Chumak (D069712)
*
*/
public class ManeuverBoundariesRetrievalProcessor
extends AbstractRetrievalProcessor<HasRaceOfCompetitorContext, HasManeuverBoundariesContext> {
public ManeuverBoundariesRetrievalProcessor(ExecutorService executor,
Collection<Processor<HasManeuverBoundariesContext, ?>> resultReceivers, int retrievalLevel) {
super(HasRaceOfCompetitorContext.class, HasManeuverBoundariesContext.class, executor, resultReceivers,
retrievalLevel);
}
@Override
protected Iterable<HasManeuverBoundariesContext> retrieveData(HasRaceOfCompetitorContext element) {
List<HasManeuverBoundariesContext> result = new ArrayList<>();
TrackedRace trackedRace = element.getTrackedRaceContext().getTrackedRace();
Competitor competitor = element.getCompetitor();
ManeuverWithEstimationDataCalculator calculator = new ManeuverWithEstimationDataCalculatorImpl();
Iterable<Maneuver> maneuvers = trackedRace.getManeuvers(competitor, false);
Iterable<ManeuverWithEstimationData> maneuversWithEstimationData = calculator
.computeEstimationDataForManeuvers(trackedRace, competitor, maneuvers, true);
for (ManeuverWithEstimationData maneuverWithEstimationData : maneuversWithEstimationData) {
result.add(new ManeuverBoundariesWithContext(element, maneuverWithEstimationData));
}
return result;
}
}
@@ -11,6 +11,8 @@ import com.sap.sailing.datamining.impl.data.TrackedLegOfCompetitorWithSpecificTi
import com.sap.sailing.datamining.shared.ManeuverSettings;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.tracking.Maneuver;
import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor;
@@ -33,53 +35,106 @@ public class ManeuverRetrievalProcessor
Collection<HasManeuverContext> maneuversWithContext = new ArrayList<>();
TimePoint finishTime = element.getTrackedLegOfCompetitor().getFinishTime();
if (finishTime != null) {
Iterable<Maneuver> maneuvers = null;
try {
Iterable<Maneuver> maneuvers = element.getTrackedLegOfCompetitor().getManeuvers(finishTime, false);
for (Maneuver maneuver : maneuvers) {
maneuvers = element.getTrackedLegOfCompetitor().getManeuvers(finishTime, false);
} catch (NoWindException e) {
throw new IllegalStateException("No wind retrieving the maneuvers", e);
}
Maneuver previousManeuver = null;
Maneuver currentManeuver = null;
for (Maneuver nextManeuver : maneuvers) {
if (currentManeuver != null) {
ManeuverWithContext maneuverWithContext = new ManeuverWithContext(new TrackedLegOfCompetitorWithSpecificTimePointWithContext(
element.getTrackedLegContext(), element.getTrackedLegOfCompetitor(), maneuver.getTimePoint()), maneuver, settings.isMainCurveAnalysis());
// Compute only numbers which are really required for filtering
double maneuverDuration = settings.getMinManeuverDuration() != null
|| settings.getMaxManeuverDuration() != null ? maneuverWithContext.getManeuverDurationInSeconds()
: 0;
double maneuverEnteringSpeed = settings.getMinManeuverEnteringSpeedInKnots() != null
|| settings.getMaxManeuverEnteringSpeedInKnots() != null
? maneuverWithContext.getManeuverEnteringSpeed() : 0;
double maneuverExitingSpeed = settings.getMinManeuverExitingSpeedInKnots() != null
|| settings.getMaxManeuverExitingSpeedInKnots() != null
? maneuverWithContext.getManeuverExitingSpeed() : 0;
double maneuverEnteringAbsTWA = settings.getMinManeuverEnteringAbsTWA() != null
? maneuverWithContext.getEnteringAbsTWA() : 0;
double maneuverExitingAbsTWA = settings.getMinManeuverExitingAbsTWA() != null
? maneuverWithContext.getExitingAbsTWA() : 0;
if (!(settings.getMinManeuverDuration() != null
&& maneuverDuration < settings.getMinManeuverDuration()
|| settings.getMaxManeuverDuration() != null
&& maneuverDuration > settings.getMaxManeuverDuration()
|| settings.getMinManeuverEnteringSpeedInKnots() != null
&& maneuverEnteringSpeed < settings.getMinManeuverEnteringSpeedInKnots()
|| settings.getMaxManeuverEnteringSpeedInKnots() != null
&& maneuverEnteringSpeed > settings.getMaxManeuverEnteringSpeedInKnots()
|| settings.getMinManeuverExitingSpeedInKnots() != null
&& maneuverExitingSpeed < settings.getMinManeuverExitingSpeedInKnots()
|| settings.getMaxManeuverExitingSpeedInKnots() != null
&& maneuverExitingSpeed > settings.getMaxManeuverExitingSpeedInKnots()
|| settings.getMinManeuverEnteringAbsTWA() != null
&& maneuverEnteringAbsTWA < settings.getMinManeuverEnteringAbsTWA()
|| settings.getMaxManeuverEnteringAbsTWA() != null
&& maneuverEnteringAbsTWA > settings.getMaxManeuverEnteringAbsTWA()
|| settings.getMinManeuverExitingAbsTWA() != null
&& maneuverExitingAbsTWA < settings.getMinManeuverExitingAbsTWA()
|| settings.getMaxManeuverExitingAbsTWA() != null
&& maneuverExitingAbsTWA > settings.getMaxManeuverExitingAbsTWA())) {
element.getTrackedLegContext(), element.getTrackedLegOfCompetitor(), currentManeuver.getTimePoint()), currentManeuver,
settings.isMainCurveAnalysis(), previousManeuver, nextManeuver);
if (isManeuverCompliantWithSettings(previousManeuver, maneuverWithContext, nextManeuver)) {
maneuversWithContext.add(maneuverWithContext);
}
}
} catch (NoWindException e) {
throw new IllegalStateException("No wind retrieving the maneuvers", e);
previousManeuver = currentManeuver;
currentManeuver = nextManeuver;
}
if (currentManeuver != null) {
ManeuverWithContext maneuverWithContext = new ManeuverWithContext(element, currentManeuver,
settings.isMainCurveAnalysis(), previousManeuver, null);
if (isManeuverCompliantWithSettings(previousManeuver, maneuverWithContext, null)) {
maneuversWithContext.add(maneuverWithContext);
}
}
}
return maneuversWithContext;
}
private boolean isManeuverCompliantWithSettings(Maneuver previousManeuver,
ManeuverWithContext currentManeuverWithContext, Maneuver nextManeuver) {
boolean mainCurveAnalysis = settings.isMainCurveAnalysis();
// Compute only numbers which are really required for filtering
Duration maneuverDuration = settings.getMinManeuverDuration() != null
|| settings.getMaxManeuverDuration() != null
? currentManeuverWithContext.getTimePointBeforeForAnalysis()
.until(currentManeuverWithContext.getTimePointAfterForAnalysis())
: null;
double maneuverEnteringSpeed = settings.getMinManeuverEnteringSpeedInKnots() != null
|| settings.getMaxManeuverEnteringSpeedInKnots() != null
? currentManeuverWithContext.getManeuverEnteringSpeed() : 0;
double maneuverExitingSpeed = settings.getMinManeuverExitingSpeedInKnots() != null
|| settings.getMaxManeuverExitingSpeedInKnots() != null
? currentManeuverWithContext.getManeuverExitingSpeed() : 0;
double maneuverEnteringAbsTWA = settings.getMinManeuverEnteringAbsTWA() != null
? currentManeuverWithContext.getEnteringAbsTWA() : 0;
double maneuverExitingAbsTWA = settings.getMinManeuverExitingAbsTWA() != null
? currentManeuverWithContext.getExitingAbsTWA() : 0;
Duration durationToPreviousManeuver = previousManeuver != null
? getManeuverBoundariesForAnalysis(previousManeuver, mainCurveAnalysis).getTimePointAfter()
.until(currentManeuverWithContext.getTimePointBeforeForAnalysis())
: null;
Duration durationToNextManeuver = nextManeuver != null
? currentManeuverWithContext.getTimePointAfterForAnalysis().until(
getManeuverBoundariesForAnalysis(nextManeuver, mainCurveAnalysis).getTimePointBefore())
: null;
if (!(settings.getMinManeuverDuration() != null
&& maneuverDuration.compareTo(settings.getMinManeuverDuration()) < 0
|| settings.getMaxManeuverDuration() != null
&& maneuverDuration.compareTo(settings.getMaxManeuverDuration()) > 0
|| settings.getMinManeuverEnteringSpeedInKnots() != null
&& maneuverEnteringSpeed < settings.getMinManeuverEnteringSpeedInKnots()
|| settings.getMaxManeuverEnteringSpeedInKnots() != null
&& maneuverEnteringSpeed > settings.getMaxManeuverEnteringSpeedInKnots()
|| settings.getMinManeuverExitingSpeedInKnots() != null
&& maneuverExitingSpeed < settings.getMinManeuverExitingSpeedInKnots()
|| settings.getMaxManeuverExitingSpeedInKnots() != null
&& maneuverExitingSpeed > settings.getMaxManeuverExitingSpeedInKnots()
|| settings.getMinManeuverEnteringAbsTWA() != null
&& maneuverEnteringAbsTWA < settings.getMinManeuverEnteringAbsTWA()
|| settings.getMaxManeuverEnteringAbsTWA() != null
&& maneuverEnteringAbsTWA > settings.getMaxManeuverEnteringAbsTWA()
|| settings.getMinManeuverExitingAbsTWA() != null
&& maneuverExitingAbsTWA < settings.getMinManeuverExitingAbsTWA()
|| settings.getMaxManeuverExitingAbsTWA() != null
&& maneuverExitingAbsTWA > settings.getMaxManeuverExitingAbsTWA()
|| settings.getMinAbsCourseChangeInDegrees() != null && currentManeuverWithContext
.getAbsoluteDirectionChangeInDegrees() < settings.getMinAbsCourseChangeInDegrees()
|| settings.getMaxAbsCourseChangeInDegrees() != null && currentManeuverWithContext
.getAbsoluteDirectionChangeInDegrees() > settings.getMaxAbsCourseChangeInDegrees()
|| settings.getMinDurationFromPrecedingManeuver() != null && (previousManeuver == null
|| durationToPreviousManeuver.compareTo(settings.getMinDurationFromPrecedingManeuver()) < 0)
|| settings.getMaxDurationFromPrecedingManeuver() != null && (previousManeuver == null
|| durationToPreviousManeuver.compareTo(settings.getMaxDurationFromPrecedingManeuver()) > 0)
|| settings.getMinDurationToFollowingManeuver() != null && (nextManeuver == null
|| durationToNextManeuver.compareTo(settings.getMinDurationToFollowingManeuver()) < 0)
|| settings.getMaxDurationToFollowingManeuver() != null && (nextManeuver == null
|| durationToNextManeuver.compareTo(settings.getMaxDurationToFollowingManeuver()) > 0))) {
return true;
} else {
return false;
}
}
private ManeuverCurveBoundaries getManeuverBoundariesForAnalysis(Maneuver maneuver, boolean mainCurveAnalysis) {
return mainCurveAnalysis ? maneuver.getMainCurveBoundaries()
: maneuver.getManeuverCurveWithStableSpeedAndCourseBoundaries();
}
}
@@ -0,0 +1,297 @@
package com.sap.sailing.datamining.impl.data;
import com.sap.sailing.datamining.data.HasCompleteManeuverCurveWithEstimationDataContext;
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
import com.sap.sailing.datamining.shared.ManeuverSettings;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.maneuverdetection.CompleteManeuverCurveWithEstimationData;
import com.sap.sailing.domain.maneuverdetection.HasDetailedManeuverLoss;
import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.datamining.shared.impl.dto.ClusterDTO;
/**
*
* @author Vladislav Chumak (D069712)
*
*/
public class CompleteManeuverCurveWithEstimationDataWithContext
implements HasCompleteManeuverCurveWithEstimationDataContext {
private final CompleteManeuverCurveWithEstimationData maneuverWithEstimationData;
private final HasRaceOfCompetitorContext raceOfCompetitorContext;
private final ManeuverSettings maneuverSettings;
private final CompleteManeuverCurveWithEstimationData previousManeuverCurve;
private final CompleteManeuverCurveWithEstimationData nextManeuverCurve;
public CompleteManeuverCurveWithEstimationDataWithContext(HasRaceOfCompetitorContext raceOfCompetitorContext,
CompleteManeuverCurveWithEstimationData maneuverWithEstimationData, ManeuverSettings maneuverSettings,
CompleteManeuverCurveWithEstimationData previousManeuverCurve,
CompleteManeuverCurveWithEstimationData nextManeuverCurve) {
this.raceOfCompetitorContext = raceOfCompetitorContext;
this.maneuverWithEstimationData = maneuverWithEstimationData;
this.maneuverSettings = maneuverSettings;
this.previousManeuverCurve = previousManeuverCurve;
this.nextManeuverCurve = nextManeuverCurve;
}
@Override
public HasRaceOfCompetitorContext getRaceOfCompetitorContext() {
return raceOfCompetitorContext;
}
@Override
public Double getManeuverStartSpeedDeviationRatioFromAvgStatistic() {
SpeedWithBearing speedWithBearingBeforeManeuver = getManeuverCurveBoundariesForAnalysis()
.getSpeedWithBearingBefore();
SpeedWithBearing averageSpeedWithBearingBeforeManeuver = maneuverWithEstimationData
.getCurveWithUnstableCourseAndSpeed().getAverageSpeedWithBearingBefore();
if (speedWithBearingBeforeManeuver != null && averageSpeedWithBearingBeforeManeuver != null) {
if (speedWithBearingBeforeManeuver.getKnots() < averageSpeedWithBearingBeforeManeuver.getKnots()) {
return averageSpeedWithBearingBeforeManeuver.getKnots() / speedWithBearingBeforeManeuver.getKnots();
} else {
return speedWithBearingBeforeManeuver.getKnots() / averageSpeedWithBearingBeforeManeuver.getKnots();
}
}
return null;
}
@Override
public Double getManeuverStartCogDeviationFromAvgInDegreesStatistic() {
SpeedWithBearing speedWithBearingBeforeManeuver = getManeuverCurveBoundariesForAnalysis()
.getSpeedWithBearingBefore();
SpeedWithBearing averageSpeedWithBearingBeforeManeuver = maneuverWithEstimationData
.getCurveWithUnstableCourseAndSpeed().getAverageSpeedWithBearingBefore();
if (speedWithBearingBeforeManeuver != null && averageSpeedWithBearingBeforeManeuver != null) {
return Math.abs(averageSpeedWithBearingBeforeManeuver.getBearing()
.getDifferenceTo(speedWithBearingBeforeManeuver.getBearing()).getDegrees());
}
return null;
}
@Override
public Double getManeuverEndSpeedDeviationRatioFromAvgStatistic() {
SpeedWithBearing speedWithBearingAfterManeuver = getManeuverCurveBoundariesForAnalysis()
.getSpeedWithBearingAfter();
SpeedWithBearing averageSpeedWithBearingAfterManeuver = maneuverWithEstimationData
.getCurveWithUnstableCourseAndSpeed().getAverageSpeedWithBearingAfter();
if (speedWithBearingAfterManeuver != null && averageSpeedWithBearingAfterManeuver != null) {
if (speedWithBearingAfterManeuver.getKnots() < averageSpeedWithBearingAfterManeuver.getKnots()) {
return averageSpeedWithBearingAfterManeuver.getKnots() / speedWithBearingAfterManeuver.getKnots();
} else {
return speedWithBearingAfterManeuver.getKnots() / averageSpeedWithBearingAfterManeuver.getKnots();
}
}
return null;
}
@Override
public Double getManeuverEndCogDeviationFromAvgInDegreesStatistic() {
SpeedWithBearing speedWithBearingAfterManeuver = maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed()
.getSpeedWithBearingAfter();
SpeedWithBearing averageSpeedWithBearingAfterManeuver = maneuverWithEstimationData
.getCurveWithUnstableCourseAndSpeed().getAverageSpeedWithBearingAfter();
if (speedWithBearingAfterManeuver != null && averageSpeedWithBearingAfterManeuver != null) {
return Math.abs(averageSpeedWithBearingAfterManeuver.getBearing()
.getDifferenceTo(speedWithBearingAfterManeuver.getBearing()).getDegrees());
}
return null;
}
@Override
public Double getDurationToNextManeuverInSecondsStatistic() {
Duration duration = maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed()
.getDurationFromManeuverEndToNextManeuverStart();
if (duration != null) {
return duration.asSeconds();
}
return null;
}
@Override
public Double getDurationFromPreviousManeuverInSecondsStatistic() {
Duration duration = maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed()
.getDurationFromPreviousManeuverEndToManeuverStart();
if (duration != null) {
return duration.asSeconds();
}
return null;
}
public boolean isNextManeuverAtLeastOneSecondInFront() {
return maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed()
.getDurationFromManeuverEndToNextManeuverStart() != null
&& maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed()
.getDurationFromManeuverEndToNextManeuverStart().asSeconds() >= 1;
}
@Override
public boolean isPreviousManeuverAtLeastOneSecondBehind() {
return maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed()
.getDurationFromPreviousManeuverEndToManeuverStart() != null
&& maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed()
.getDurationFromPreviousManeuverEndToManeuverStart().asSeconds() >= 1;
}
@Override
public CompleteManeuverCurveWithEstimationData getCompleteManeuverCurveWithEstimationData() {
return maneuverWithEstimationData;
}
@Override
public ClusterDTO getJibingCount() {
return new ClusterDTO(maneuverWithEstimationData.getJibingCount() + "");
}
@Override
public ClusterDTO getTackingCount() {
return new ClusterDTO(maneuverWithEstimationData.getTackingCount() + "");
}
@Override
public double getAbsTwaAtMaxTurningRate() {
return getAbsTwaFromCourse(maneuverWithEstimationData.getMainCurve().getCourseAtMaxTurningRate());
}
@Override
public double getAbsTwaAtLowestSpeed() {
return getAbsTwaFromCourse(maneuverWithEstimationData.getMainCurve().getLowestSpeed().getBearing());
}
@Override
public double getAbsTwaAtHighestSpeed() {
return getAbsTwaFromCourse(maneuverWithEstimationData.getMainCurve().getHighestSpeed().getBearing());
}
private double getAbsTwaFromCourse(Bearing course) {
double twa = maneuverWithEstimationData.getWind().getFrom().getDifferenceTo(course).getDegrees();
return Math.abs(twa);
}
@Override
public NauticalSide getToSide() {
return maneuverWithEstimationData.getMainCurve().getDirectionChangeInDegrees() < 0 ? NauticalSide.PORT
: NauticalSide.STARBOARD;
}
private ManeuverCurveBoundaries getManeuverCurveBoundariesForAnalysis() {
return maneuverSettings.isMainCurveAnalysis() ? maneuverWithEstimationData.getMainCurve()
: maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed();
}
@Override
public Double getEnteringAbsTWA() {
return getAbsTwaFromCourse(getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingBefore().getBearing());
}
@Override
public Double getExitingAbsTWA() {
return getAbsTwaFromCourse(getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingAfter().getBearing());
}
@Override
public ManeuverType getTypeOfPreviousManeuver() {
return previousManeuverCurve == null ? ManeuverType.UNKNOWN
: previousManeuverCurve.getManeuverTypeForCompleteManeuverCurve();
}
@Override
public ManeuverType getTypeOfNextManeuver() {
return nextManeuverCurve == null ? ManeuverType.UNKNOWN
: nextManeuverCurve.getManeuverTypeForCompleteManeuverCurve();
}
@Override
public Double getAbsoluteDirectionChangeInDegrees() {
return Math.abs(getManeuverCurveBoundariesForAnalysis().getDirectionChangeInDegrees());
}
@Override
public double getRatioBetweenDistanceSailedWithAndWithoutManeuver() {
return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis())
.getRatioBetweenDistanceSailedWithAndWithoutManeuver();
}
@Override
public double getDurationLostByManeuver() {
return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis()).getDurationLostByManeuver()
.asSeconds();
}
@Override
public double getDurationLostByManeuverTowardMiddleAngleProjection() {
return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis())
.getDurationLostByManeuverTowardMiddleAngleProjection().asSeconds();
}
@Override
public double getRatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver() {
return ((HasDetailedManeuverLoss) getManeuverCurveBoundariesForAnalysis())
.getRatioBetweenDistanceSailedTowardMiddleAngleProjectionWithAndWithoutManeuver();
}
@Override
public Double getRelativeBearingToNextMarkBeforeManeuver() {
return maneuverWithEstimationData.getRelativeBearingToNextMarkBeforeManeuver() == null ? null
: maneuverWithEstimationData.getRelativeBearingToNextMarkBeforeManeuver().getDegrees();
}
@Override
public Double getRelativeBearingToNextMarkAfterManeuver() {
return maneuverWithEstimationData.getRelativeBearingToNextMarkAfterManeuver() == null ? null
: maneuverWithEstimationData.getRelativeBearingToNextMarkAfterManeuver().getDegrees();
}
public TimePoint getTimePointBeforeForAnalysis() {
return getManeuverCurveBoundariesForAnalysis().getTimePointBefore();
}
public TimePoint getTimePointAfterForAnalysis() {
return getManeuverCurveBoundariesForAnalysis().getTimePointAfter();
}
@Override
public Double getManeuverEnteringSpeed() {
return getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingBefore().getKnots();
}
@Override
public Double getManeuverExitingSpeed() {
return getManeuverCurveBoundariesForAnalysis().getSpeedWithBearingAfter().getKnots();
}
@Override
public double getAbsTwaAtManeuverMiddle() {
ManeuverCurveBoundaries boundariesForAnalysis = getManeuverCurveBoundariesForAnalysis();
Bearing middleCourse = boundariesForAnalysis.getSpeedWithBearingBefore().getBearing()
.add(new DegreeBearingImpl(boundariesForAnalysis.getDirectionChangeInDegrees() / 2));
return getAbsTwaFromCourse(middleCourse);
}
@Override
public double getGpsSamplingRate() {
return maneuverSettings.isMainCurveAnalysis()
? maneuverWithEstimationData.getMainCurve().getGpsFixesCount()
/ maneuverWithEstimationData.getMainCurve().getDuration().asSeconds()
: maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed().getGpsFixesCount()
/ maneuverWithEstimationData.getCurveWithUnstableCourseAndSpeed().getDuration().asSeconds();
}
@Override
public Double getAbsRelativeBearingToNextMarkBeforeManeuver() {
Double bearing = getRelativeBearingToNextMarkBeforeManeuver();
return bearing == null ? null : Math.abs(bearing);
}
@Override
public Double getAbsRelativeBearingToNextMarkAfterManeuver() {
Double bearing = getRelativeBearingToNextMarkAfterManeuver();
return bearing == null ? null : Math.abs(bearing);
}
}
@@ -1,125 +0,0 @@
package com.sap.sailing.datamining.impl.data;
import com.sap.sailing.datamining.data.HasManeuverBoundariesContext;
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.maneuverdetection.ManeuverWithEstimationData;
import com.sap.sse.common.Duration;
/**
*
* @author Vladislav Chumak (D069712)
*
*/
public class ManeuverBoundariesWithContext implements HasManeuverBoundariesContext {
private final ManeuverWithEstimationData maneuverWithEstimationData;
private HasRaceOfCompetitorContext raceOfCompetitorContext;
public ManeuverBoundariesWithContext(HasRaceOfCompetitorContext raceOfCompetitorContext, ManeuverWithEstimationData maneuverWithEstimationData) {
this.raceOfCompetitorContext = raceOfCompetitorContext;
this.maneuverWithEstimationData = maneuverWithEstimationData;
}
@Override
public HasRaceOfCompetitorContext getRaceOfCompetitorContext() {
return raceOfCompetitorContext;
}
@Override
public NauticalSide getToSide() {
return maneuverWithEstimationData.getManeuver().getDirectionChangeInDegrees() >= 0 ? NauticalSide.STARBOARD
: NauticalSide.PORT;
}
@Override
public ManeuverType getManeuverType() {
return maneuverWithEstimationData.getManeuver().getType();
}
@Override
public Double getManeuverStartSpeedDeviationRatioFromAvgStatistic() {
SpeedWithBearing speedWithBearingBeforeManeuver = maneuverWithEstimationData.getManeuver()
.getManeuverCurveWithStableSpeedAndCourseBoundaries().getSpeedWithBearingBefore();
SpeedWithBearing averageSpeedWithBearingBeforeManeuver = maneuverWithEstimationData
.getAverageSpeedWithBearingBefore();
if (speedWithBearingBeforeManeuver != null && averageSpeedWithBearingBeforeManeuver != null) {
if(speedWithBearingBeforeManeuver.getKnots() < averageSpeedWithBearingBeforeManeuver.getKnots()) {
return averageSpeedWithBearingBeforeManeuver.getKnots() / speedWithBearingBeforeManeuver.getKnots();
} else {
return speedWithBearingBeforeManeuver.getKnots() / averageSpeedWithBearingBeforeManeuver.getKnots();
}
}
return null;
}
@Override
public Double getManeuverStartCogDeviationFromAvgInDegreesStatistic() {
SpeedWithBearing speedWithBearingBeforeManeuver = maneuverWithEstimationData.getManeuver()
.getManeuverCurveWithStableSpeedAndCourseBoundaries().getSpeedWithBearingBefore();
SpeedWithBearing averageSpeedWithBearingBeforeManeuver = maneuverWithEstimationData
.getAverageSpeedWithBearingBefore();
if (speedWithBearingBeforeManeuver != null && averageSpeedWithBearingBeforeManeuver != null) {
return Math.abs(averageSpeedWithBearingBeforeManeuver.getBearing().getDifferenceTo(speedWithBearingBeforeManeuver.getBearing()).getDegrees());
}
return null;
}
@Override
public Double getManeuverEndSpeedDeviationRatioFromAvgStatistic() {
SpeedWithBearing speedWithBearingAfterManeuver = maneuverWithEstimationData.getManeuver()
.getManeuverCurveWithStableSpeedAndCourseBoundaries().getSpeedWithBearingAfter();
SpeedWithBearing averageSpeedWithBearingAfterManeuver = maneuverWithEstimationData
.getAverageSpeedWithBearingAfter();
if (speedWithBearingAfterManeuver != null && averageSpeedWithBearingAfterManeuver != null) {
if(speedWithBearingAfterManeuver.getKnots() < averageSpeedWithBearingAfterManeuver.getKnots()) {
return averageSpeedWithBearingAfterManeuver.getKnots() / speedWithBearingAfterManeuver.getKnots();
} else {
return speedWithBearingAfterManeuver.getKnots() / averageSpeedWithBearingAfterManeuver.getKnots();
}
}
return null;
}
@Override
public Double getManeuverEndCogDeviationFromAvgInDegreesStatistic() {
SpeedWithBearing speedWithBearingAfterManeuver = maneuverWithEstimationData.getManeuver()
.getManeuverCurveWithStableSpeedAndCourseBoundaries().getSpeedWithBearingAfter();
SpeedWithBearing averageSpeedWithBearingAfterManeuver = maneuverWithEstimationData
.getAverageSpeedWithBearingAfter();
if (speedWithBearingAfterManeuver != null && averageSpeedWithBearingAfterManeuver != null) {
return Math.abs(averageSpeedWithBearingAfterManeuver.getBearing().getDifferenceTo(speedWithBearingAfterManeuver.getBearing()).getDegrees());
}
return null;
}
@Override
public Double getDurationToNextManeuverInSecondsStatistic() {
Duration duration = maneuverWithEstimationData.getDurationFromManeuverEndToNextManeuverStart();
if (duration != null) {
return duration.asSeconds();
}
return null;
}
@Override
public Double getDurationFromPreviousManeuverInSecondsStatistic() {
Duration duration = maneuverWithEstimationData.getDurationFromPreviousManeuverEndToManeuverStart();
if (duration != null) {
return duration.asSeconds();
}
return null;
}
public boolean isNextManeuverAtLeastOneSecondInFront() {
return maneuverWithEstimationData.getDurationFromManeuverEndToNextManeuverStart() != null;
}
@Override
public boolean isPreviousManeuverAtLeastOneSecondBehind() {
return maneuverWithEstimationData.getDurationFromPreviousManeuverEndToManeuverStart() != null;
}
}
@@ -4,6 +4,7 @@ import com.sap.sailing.datamining.data.HasManeuverContext;
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Tack;
import com.sap.sailing.domain.common.Wind;
@@ -23,14 +24,18 @@ public class ManeuverWithContext implements HasManeuverContext {
private static final long serialVersionUID = 7717196485074392156L;
private final HasTrackedLegOfCompetitorContext trackedLegOfCompetitor;
private final Maneuver maneuver;
private TimePoint timePointBeforeForAnalysis;
private TimePoint timePointAfterForAnalysis;
private double directionChangeInDegreesForAnalysis;
private final TimePoint timePointBeforeForAnalysis;
private final TimePoint timePointAfterForAnalysis;
private final double directionChangeInDegreesForAnalysis;
private final Maneuver previousManeuver;
private final Maneuver nextManeuver;
public ManeuverWithContext(HasTrackedLegOfCompetitorContext trackedLegOfCompetitor, Maneuver maneuver,
boolean mainCurveAnalysis) {
boolean mainCurveAnalysis, Maneuver previousManeuver, Maneuver nextManeuver) {
this.trackedLegOfCompetitor = trackedLegOfCompetitor;
this.maneuver = maneuver;
this.previousManeuver = previousManeuver;
this.nextManeuver = nextManeuver;
ManeuverCurveBoundaries enteringAndExistingDetails = mainCurveAnalysis ? maneuver.getMainCurveBoundaries()
: maneuver.getManeuverCurveWithStableSpeedAndCourseBoundaries();
this.timePointBeforeForAnalysis = enteringAndExistingDetails.getTimePointBefore();
@@ -50,6 +55,16 @@ public class ManeuverWithContext implements HasManeuverContext {
return directionChangeInDegreesForAnalysis;
}
@Override
public ManeuverType getTypeOfPreviousManeuver() {
return previousManeuver != null ? previousManeuver.getType() : ManeuverType.UNKNOWN;
}
@Override
public ManeuverType getTypeOfNextManeuver() {
return nextManeuver != null ? nextManeuver.getType() : ManeuverType.UNKNOWN;
}
@Override
public Double getManeuverEnteringSpeed() {
return getSpeedInKnotsAtTimePoint(getTimePointBeforeForAnalysis());
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.common;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import com.sap.sailing.domain.common.dto.PersonDTO;
import com.sap.sse.common.CountryCode;
@@ -14,6 +15,9 @@ import com.sap.sse.common.impl.NamedImpl;
public class CompetitorDescriptor extends NamedImpl implements Named {
private static final long serialVersionUID = -6645726854552711646L;
private final UUID competitorUUID;
private final UUID boatUUID;
private final String shortName;
private final String eventName;
private final String regattaName;
private final String boatClassName;
@@ -27,23 +31,27 @@ public class CompetitorDescriptor extends NamedImpl implements Named {
private final Double timeOnTimeFactor;
private final Duration timeOnDistanceAllowancePerNauticalMile;
public CompetitorDescriptor(String eventName, String regattaName, String boatClassName, String raceName,
String fleetName, String sailNumber, String name, String teamName, String boatName, CountryCode countryCode,
Iterable<PersonDTO> persons, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile) {
super(name);
public CompetitorDescriptor(String eventName, String regattaName, String raceName, String fleetName,
UUID competitorUUID, String fullName, String shortName, String teamName, Iterable<PersonDTO> persons,
CountryCode countryCode, Double timeOnTimeFactor,
Duration timeOnDistanceAllowancePerNauticalMile, UUID boatUUID, String boatName, String boatClassName, String sailNumber) {
super(fullName);
this.shortName = shortName;
this.eventName = eventName;
this.regattaName = regattaName;
this.boatClassName = boatClassName;
this.boatName = boatName;
this.raceName = raceName;
this.fleetName = fleetName;
this.sailNumber = sailNumber;
this.competitorUUID = competitorUUID;
this.teamName = teamName;
this.countryCode = countryCode;
this.persons = new ArrayList<>();
Util.addAll(persons, this.persons);
this.timeOnTimeFactor = timeOnTimeFactor;
this.timeOnDistanceAllowancePerNauticalMile = timeOnDistanceAllowancePerNauticalMile;
this.boatUUID = boatUUID;
this.boatName = boatName;
this.boatClassName = boatClassName;
this.sailNumber = sailNumber;
}
public String getEventName() {
@@ -90,10 +98,22 @@ public class CompetitorDescriptor extends NamedImpl implements Named {
return teamName;
}
public String getShortName() {
return shortName;
}
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
return timeOnDistanceAllowancePerNauticalMile;
}
public UUID getCompetitorUUID() {
return competitorUUID;
}
public UUID getBoatUUID() {
return boatUUID;
}
@Override
public String toString() {
return "CompetitorDescriptor [eventName=" + eventName + ", regattaName=" + regattaName + ", boatClassName="
@@ -37,6 +37,7 @@ public abstract class AbstractLeaderboardDTO implements Serializable {
public String defaultCourseAreaName;
public ScoringSchemeType scoringScheme;
public LeaderboardType type;
public boolean canBoatsOfCompetitorsChangePerRace;
private Long delayToLiveInMillisForLatestRace;
@@ -2,23 +2,28 @@ package com.sap.sailing.domain.common.dto;
import java.io.Serializable;
import com.sap.sailing.domain.common.racelog.tracking.MappableToDevice;
import com.sap.sse.common.Color;
public class BoatDTO extends NamedDTO implements Serializable {
public class BoatDTO extends NamedDTO implements Serializable, MappableToDevice {
private static final long serialVersionUID = -4076992788294272162L;
private String idAsString;
private BoatClassDTO boatClass;
private String sailId;
private Color color;
// for GWT
BoatDTO() {}
public BoatDTO() {}
public BoatDTO(String name, String sailId) {
this(name, sailId, null);
public BoatDTO(String idAsString, String name, BoatClassDTO boatClass, String sailId) {
this(idAsString, name, boatClass, sailId, null);
}
public BoatDTO(String name, String sailId, Color color) {
public BoatDTO(String idAsString, String name, BoatClassDTO boatClass, String sailId, Color color) {
super(name);
this.idAsString = idAsString;
this.boatClass = boatClass;
this.sailId = sailId;
this.color = color;
}
@@ -31,10 +36,37 @@ public class BoatDTO extends NamedDTO implements Serializable {
return sailId;
}
@Override
public String getIdAsString() {
return idAsString;
}
public BoatClassDTO getBoatClass() {
return boatClass;
}
public String getDisplayName() {
final StringBuilder sb = new StringBuilder();
final boolean hasSailId = sailId != null && !sailId.isEmpty();
if (getName() != null) {
sb.append(getName());
if (hasSailId) {
sb.append(" (").append(sailId).append(')');
}
} else if (hasSailId) {
sb.append(sailId);
} else {
sb.append(idAsString);
}
return sb.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((boatClass == null) ? 0 : boatClass.hashCode());
result = prime * result + ((idAsString == null) ? 0 : idAsString.hashCode());
result = prime * result + ((color == null) ? 0 : color.hashCode());
result = prime * result + ((sailId == null) ? 0 : sailId.hashCode());
return result;
@@ -49,6 +81,16 @@ public class BoatDTO extends NamedDTO implements Serializable {
if (getClass() != obj.getClass())
return false;
BoatDTO other = (BoatDTO) obj;
if (boatClass == null) {
if (other.boatClass != null)
return false;
} else if (!boatClass.equals(other.boatClass))
return false;
if (idAsString == null) {
if (other.idAsString != null)
return false;
} else if (!idAsString.equals(other.idAsString))
return false;
if (color == null) {
if (other.color != null)
return false;
@@ -61,4 +103,9 @@ public class BoatDTO extends NamedDTO implements Serializable {
return false;
return true;
}
@Override
public String toString() {
return getName() == null ? (getBoatClass().getName() + " / " + getSailId()) : getName();
}
}
@@ -1,55 +1,36 @@
package com.sap.sailing.domain.common.dto;
import java.io.Serializable;
import com.sap.sailing.domain.common.racelog.tracking.MappableToDevice;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
public interface CompetitorDTO extends Serializable, MappableToDevice {
String getTwoLetterIsoCountryCode();
String getThreeLetterIocCountryCode();
String getCountryName();
String getIdAsString();
/**
* Equality and hash code are based on the {@link #getIdAsString() ID}, the {@link #getSailID() sail number}, the
* {@link #getBoatClass() boat class} (whose equality and hash code, in turn, depends on its name) and the
* {@link #getThreeLetterIocCountryCode() IOC country code}. Note that the three latter properties are subject
* to change for a competitor while the ID remains unchanged.
*
* @author Axel Uhl (d043530)
*
*/
public interface CompetitorDTO extends CompetitorWithoutBoatDTO {
// TODO bug2822: Should we remove this?
String getSailID();
String getSearchTag();
/**
* If the {@code searchTag} is not {@link String#contains(CharSequence) contained} in {@link #getSearchTag()},
* appends it to the search tag, separated by a space character
* Returns a derived short information about a competitor depending on the information available
* If we have a short name set on the competitor this name will be returned.
* If no short name exist but a boat the either the sailId or the boat name will returned.
* If all these attributes have no value null is returned.
*/
void addToSearchTag(String searchTag);
String getShortInfo();
BoatDTO getBoat();
void setBoat(BoatDTO boat);
// TODO bug2822: Should we remove this?
BoatClassDTO getBoatClass();
String getName();
Color getColor();
String getEmail();
boolean hasEmail();
/**
* A regular instance will simply return this object. A compacted version may compute the result by looking it up
* from the previous version of the enclosing leaderboard.
*/
CompetitorDTO getCompetitorFromPrevious(LeaderboardDTO previousVersion);
String getFlagImageURL();
String getImageURL();
Double getTimeOnTimeFactor();
Duration getTimeOnDistanceAllowancePerNauticalMile();
}
@@ -5,67 +5,36 @@ import java.io.Serializable;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
/**
* Equality and hash code are based on the {@link #getIdAsString() ID}, the {@link #getSailID() sail number}, the
* {@link #getBoatClass() boat class} (whose equality and hash code, in turn, depends on its name) and the
* {@link #getThreeLetterIocCountryCode() IOC country code}. Note that the three latter properties are subject
* to change for a competitor while the ID remains unchanged.
*
* @author Axel Uhl (d043530)
*
*/
public class CompetitorDTOImpl extends NamedDTO implements CompetitorDTO, Serializable {
public class CompetitorDTOImpl extends CompetitorWithoutBoatDTOImpl implements CompetitorDTO, Serializable {
private static final long serialVersionUID = -4997852354821083154L;
private String countryName;
private String twoLetterIsoCountryCode;
private String threeLetterIocCountryCode;
private Color color;
private String email;
private String searchTag;
private String idAsString;
private BoatClassDTO boatClass;
private BoatDTO boat;
private String imageURL;
private String flagImageURL;
private Double timeOnTimeFactor;
private Duration timeOnDistanceAllowancePerNauticalMile;
public CompetitorDTOImpl() {}
public CompetitorDTOImpl() {
boat = new BoatDTO();
}
public CompetitorDTOImpl(String name, Color color, String email, String twoLetterIsoCountryCode, String threeLetterIocCountryCode,
public CompetitorDTOImpl(String name, String shortName, Color color, String email, String twoLetterIsoCountryCode, String threeLetterIocCountryCode,
String countryName, String idAsString, String imageURL, String flagImageURL,
BoatDTO boat, BoatClassDTO boatClass, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag) {
super(name);
this.color = color;
this.email = email;
this.twoLetterIsoCountryCode = twoLetterIsoCountryCode;
this.threeLetterIocCountryCode = threeLetterIocCountryCode;
this.countryName = countryName;
this.idAsString = idAsString;
this.imageURL = imageURL;
this.flagImageURL = flagImageURL;
Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag, BoatDTO boat) {
super(name, shortName, color, email, twoLetterIsoCountryCode, threeLetterIocCountryCode,
countryName, idAsString, imageURL, flagImageURL,
timeOnTimeFactor, timeOnDistanceAllowancePerNauticalMile, searchTag);
this.boat = boat;
}
public CompetitorDTOImpl(CompetitorWithoutBoatDTO c, BoatDTO boat) {
super(c.getName(), c.getShortName(), c.getColor(), c.getEmail(),
c.getTwoLetterIsoCountryCode(), c.getThreeLetterIocCountryCode(), c.getCountryName(), c.getIdAsString(),
c.getImageURL(), c.getFlagImageURL(), c.getTimeOnTimeFactor(),
c.getTimeOnDistanceAllowancePerNauticalMile(), c.getSearchTag());
this.boat = boat;
this.boatClass = boatClass;
this.timeOnTimeFactor = timeOnTimeFactor;
this.timeOnDistanceAllowancePerNauticalMile = timeOnDistanceAllowancePerNauticalMile;
this.searchTag = searchTag;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((boatClass == null) ? 0 : boatClass.hashCode());
result = prime * result + ((boat == null) ? 0 : boat.hashCode());
result = prime * result + ((idAsString == null) ? 0 : idAsString.hashCode());
result = prime * result + ((color == null) ? 0 : color.hashCode());
result = prime * result + ((email == null) ? 0 : email.hashCode());
result = prime * result + ((threeLetterIocCountryCode == null) ? 0 : threeLetterIocCountryCode.hashCode());
result = prime * result + ((imageURL == null) ? 0 : imageURL.hashCode());
result = prime * result + ((flagImageURL == null) ? 0 : flagImageURL.hashCode());
result = prime * result + ((timeOnTimeFactor == null) ? 0 : timeOnTimeFactor.hashCode());
result = prime * result + ((timeOnDistanceAllowancePerNauticalMile == null) ? 0 : timeOnDistanceAllowancePerNauticalMile.hashCode());
result = prime * result + ((searchTag == null) ? 0 : searchTag.hashCode());
return result;
}
@@ -78,150 +47,47 @@ public class CompetitorDTOImpl extends NamedDTO implements CompetitorDTO, Serial
if (getClass() != obj.getClass())
return false;
CompetitorDTOImpl other = (CompetitorDTOImpl) obj;
if (boatClass == null) {
if (other.boatClass != null)
return false;
} else if (!boatClass.equals(other.boatClass))
return false;
if (boat == null) {
if (other.boat != null)
return false;
} else if (!boat.equals(other.boat))
return false;
if (idAsString == null) {
if (other.idAsString != null)
return false;
} else if (!idAsString.equals(other.idAsString))
return false;
if (threeLetterIocCountryCode == null) {
if (other.threeLetterIocCountryCode != null)
return false;
} else if (!threeLetterIocCountryCode.equals(other.threeLetterIocCountryCode))
return false;
if (color == null) {
if (other.color != null)
return false;
} else if (!color.equals(other.color))
return false;
if (email == null) {
if (other.email != null)
return false;
} else if (!email.equals(other.email))
return false;
if (imageURL == null) {
if (other.imageURL != null)
return false;
} else if (!imageURL.equals(other.imageURL))
return false;
if (flagImageURL == null) {
if (other.flagImageURL != null)
return false;
} else if (!flagImageURL.equals(other.flagImageURL))
return false;
if (timeOnTimeFactor == null) {
if (other.timeOnTimeFactor != null)
return false;
} else if (!timeOnTimeFactor.equals(other.timeOnTimeFactor))
return false;
if (timeOnDistanceAllowancePerNauticalMile == null) {
if (other.timeOnDistanceAllowancePerNauticalMile != null)
return false;
} else if (!timeOnDistanceAllowancePerNauticalMile.equals(other.timeOnDistanceAllowancePerNauticalMile))
return false;
if (searchTag == null) {
if (other.searchTag != null)
return false;
} else if (!searchTag.equals(other.searchTag))
return false;
return true;
}
@Override
public String getTwoLetterIsoCountryCode() {
return twoLetterIsoCountryCode;
}
@Override
public String getThreeLetterIocCountryCode() {
return threeLetterIocCountryCode;
}
@Override
public String getCountryName() {
return countryName;
}
@Override
public String getSailID() {
return boat==null?null:boat.getSailId();
}
@Override
public String getImageURL() {
return imageURL;
}
@Override
public String getFlagImageURL() {
return flagImageURL;
}
@Override
public String getIdAsString() {
return idAsString;
}
@Override
public BoatClassDTO getBoatClass() {
return boatClass;
}
@Override
public CompetitorDTO getCompetitorFromPrevious(LeaderboardDTO previousVersion) {
return this;
}
@Override
public Color getColor() {
return color;
}
@Override
public String getSearchTag() {
return searchTag;
}
@Override
public void addToSearchTag(String searchTag) {
if (this.searchTag == null) {
this.searchTag = searchTag;
} else if (!this.searchTag.contains(searchTag)) {
this.searchTag += " "+searchTag;
public String getShortInfo() {
String result = null;
if (getShortName() != null) {
result = getShortName();
} else if (getBoat() != null) {
result = getBoat().getSailId() != null ? getBoat().getSailId() : getBoat().getName();
}
return result;
}
@Override
public String getEmail() {
return email;
public String getSailID() {
return boat == null ? null : boat.getSailId();
}
@Override
public boolean hasEmail() {
return email != null && !email.isEmpty();
public BoatClassDTO getBoatClass() {
return boat == null ? null : boat.getBoatClass();
}
@Override
public Double getTimeOnTimeFactor() {
return timeOnTimeFactor;
}
@Override
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
return timeOnDistanceAllowancePerNauticalMile;
}
public void setBoat(BoatDTO boat) {
this.boat = boat;
}
@Override
public BoatDTO getBoat() {
return boat;
}
}
}
@@ -0,0 +1,47 @@
package com.sap.sailing.domain.common.dto;
import java.io.Serializable;
import com.sap.sailing.domain.common.racelog.tracking.MappableToDevice;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
/**
* Equality and hash code are based on the {@link #getIdAsString() ID} and all contained attributes like name, shortName, email, etc.
*/
public interface CompetitorWithoutBoatDTO extends Serializable, MappableToDevice {
String getTwoLetterIsoCountryCode();
String getThreeLetterIocCountryCode();
String getCountryName();
String getIdAsString();
String getSearchTag();
/**
* If the {@code searchTag} is not contained in {@link #getSearchTag()}, appends it to the search tag, separated by a space character
*/
void addToSearchTag(String searchTag);
String getName();
String getShortName();
Color getColor();
String getEmail();
boolean hasEmail();
String getFlagImageURL();
String getImageURL();
Double getTimeOnTimeFactor();
Duration getTimeOnDistanceAllowancePerNauticalMile();
}
@@ -0,0 +1,204 @@
package com.sap.sailing.domain.common.dto;
import java.io.Serializable;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
/**
* Equality and hash code are based on the {@link #getIdAsString() ID}, the {@link #getSailID() sail number}, the
* {@link #getBoatClass() boat class} (whose equality and hash code, in turn, depends on its name) and the
* {@link #getThreeLetterIocCountryCode() IOC country code}. Note that the three latter properties are subject
* to change for a competitor while the ID remains unchanged.
*
* @author Axel Uhl (d043530)
*
*/
public class CompetitorWithoutBoatDTOImpl extends NamedDTO implements CompetitorWithoutBoatDTO, Serializable {
private static final long serialVersionUID = 3019126418065082622L;
private String countryName;
private String twoLetterIsoCountryCode;
private String threeLetterIocCountryCode;
private Color color;
private String shortName;
private String email;
private String searchTag;
private String idAsString;
private String imageURL;
private String flagImageURL;
private Double timeOnTimeFactor;
private Duration timeOnDistanceAllowancePerNauticalMile;
public CompetitorWithoutBoatDTOImpl() {}
public CompetitorWithoutBoatDTOImpl(String name, String shortName, Color color, String email, String twoLetterIsoCountryCode, String threeLetterIocCountryCode,
String countryName, String idAsString, String imageURL, String flagImageURL,
Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag) {
super(name);
this.shortName = shortName;
this.color = color;
this.email = email;
this.twoLetterIsoCountryCode = twoLetterIsoCountryCode;
this.threeLetterIocCountryCode = threeLetterIocCountryCode;
this.countryName = countryName;
this.idAsString = idAsString;
this.imageURL = imageURL;
this.flagImageURL = flagImageURL;
this.timeOnTimeFactor = timeOnTimeFactor;
this.timeOnDistanceAllowancePerNauticalMile = timeOnDistanceAllowancePerNauticalMile;
this.searchTag = searchTag;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((idAsString == null) ? 0 : idAsString.hashCode());
result = prime * result + ((color == null) ? 0 : color.hashCode());
result = prime * result + ((email == null) ? 0 : email.hashCode());
result = prime * result + ((shortName == null) ? 0 : shortName.hashCode());
result = prime * result + ((threeLetterIocCountryCode == null) ? 0 : threeLetterIocCountryCode.hashCode());
result = prime * result + ((imageURL == null) ? 0 : imageURL.hashCode());
result = prime * result + ((flagImageURL == null) ? 0 : flagImageURL.hashCode());
result = prime * result + ((timeOnTimeFactor == null) ? 0 : timeOnTimeFactor.hashCode());
result = prime * result + ((timeOnDistanceAllowancePerNauticalMile == null) ? 0 : timeOnDistanceAllowancePerNauticalMile.hashCode());
result = prime * result + ((searchTag == null) ? 0 : searchTag.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
CompetitorWithoutBoatDTOImpl other = (CompetitorWithoutBoatDTOImpl) obj;
if (idAsString == null) {
if (other.idAsString != null)
return false;
} else if (!idAsString.equals(other.idAsString))
return false;
if (threeLetterIocCountryCode == null) {
if (other.threeLetterIocCountryCode != null)
return false;
} else if (!threeLetterIocCountryCode.equals(other.threeLetterIocCountryCode))
return false;
if (color == null) {
if (other.color != null)
return false;
} else if (!color.equals(other.color))
return false;
if (email == null) {
if (other.email != null)
return false;
} else if (!email.equals(other.email))
return false;
if (shortName == null) {
if (other.shortName != null)
return false;
} else if (!shortName.equals(other.shortName))
return false;
if (imageURL == null) {
if (other.imageURL != null)
return false;
} else if (!imageURL.equals(other.imageURL))
return false;
if (flagImageURL == null) {
if (other.flagImageURL != null)
return false;
} else if (!flagImageURL.equals(other.flagImageURL))
return false;
if (timeOnTimeFactor == null) {
if (other.timeOnTimeFactor != null)
return false;
} else if (!timeOnTimeFactor.equals(other.timeOnTimeFactor))
return false;
if (timeOnDistanceAllowancePerNauticalMile == null) {
if (other.timeOnDistanceAllowancePerNauticalMile != null)
return false;
} else if (!timeOnDistanceAllowancePerNauticalMile.equals(other.timeOnDistanceAllowancePerNauticalMile))
return false;
if (searchTag == null) {
if (other.searchTag != null)
return false;
} else if (!searchTag.equals(other.searchTag))
return false;
return true;
}
@Override
public String getTwoLetterIsoCountryCode() {
return twoLetterIsoCountryCode;
}
@Override
public String getThreeLetterIocCountryCode() {
return threeLetterIocCountryCode;
}
@Override
public String getCountryName() {
return countryName;
}
@Override
public String getShortName() {
return shortName;
}
@Override
public String getImageURL() {
return imageURL;
}
@Override
public String getFlagImageURL() {
return flagImageURL;
}
@Override
public String getIdAsString() {
return idAsString;
}
@Override
public Color getColor() {
return color;
}
@Override
public String getSearchTag() {
return searchTag;
}
@Override
public void addToSearchTag(String searchTag) {
if (this.searchTag == null) {
this.searchTag = searchTag;
} else if (!this.searchTag.contains(searchTag)) {
this.searchTag += " "+searchTag;
}
}
@Override
public String getEmail() {
return email;
}
@Override
public boolean hasEmail() {
return email != null && !email.isEmpty();
}
@Override
public Double getTimeOnTimeFactor() {
return timeOnTimeFactor;
}
@Override
public Duration getTimeOnDistanceAllowancePerNauticalMile() {
return timeOnDistanceAllowancePerNauticalMile;
}
}
@@ -117,6 +117,45 @@ public class LeaderboardDTO extends AbstractLeaderboardDTO implements Serializab
return higherScoresIsBetter;
}
public BoatDTO getBoatOfCompetitor(String raceColumnName, CompetitorDTO competitor) {
BoatDTO result = null;
if (rows != null) {
LeaderboardRowDTO leaderboardRow = rows.get(competitor);
if (leaderboardRow != null) {
if (this.canBoatsOfCompetitorsChangePerRace == false) {
result = leaderboardRow.boat;
} else {
LeaderboardEntryDTO leaderboardEntry = leaderboardRow.fieldsByRaceColumnName.get(raceColumnName);
if (leaderboardEntry != null) {
result = leaderboardEntry.boat;
}
}
}
}
return result;
}
public void setBoatOfCompetitor(CompetitorDTO competitor, BoatDTO boat) {
if (rows != null && this.canBoatsOfCompetitorsChangePerRace == false) {
LeaderboardRowDTO leaderboardRowDTO = rows.get(competitor);
if (leaderboardRowDTO != null) {
leaderboardRowDTO.boat = boat;
}
}
}
public void setBoatOfCompetitorForRace(String raceColumnName, CompetitorDTO competitor, BoatDTO boat) {
if (rows != null && this.canBoatsOfCompetitorsChangePerRace == true) {
LeaderboardRowDTO leaderboardRow = rows.get(competitor);
if (leaderboardRow != null) {
LeaderboardEntryDTO leaderboardEntry = leaderboardRow.fieldsByRaceColumnName.get(raceColumnName);
if (leaderboardEntry != null) {
leaderboardEntry.boat = boat;
}
}
}
}
public void setCompetitorsFromBestToWorst(String raceColumnName, List<CompetitorDTO> orderedCompetitors) {
competitorOrderingPerRaceColumnName.put(raceColumnName, orderedCompetitors);
}
@@ -28,7 +28,10 @@ public class LeaderboardEntryDTO implements Serializable {
* fleet the competitor started in this column.
*/
public RaceIdentifier race;
/** the boat of the competitor in case of regattas where boat can change during racing, null otherwise */
public BoatDTO boat;
/**
* Either <code>null</code> in case no max points, or one of "DNS", "DNF", "OCS", "DND", "RAF", "BFD", "DNC", or "DSQ"
*/
@@ -237,206 +240,7 @@ public class LeaderboardEntryDTO implements Serializable {
}
return result;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((averageAbsoluteCrossTrackErrorInMeters == null) ? 0
: averageAbsoluteCrossTrackErrorInMeters.hashCode());
result = prime * result + ((averageRideHeightInMeters == null) ? 0 : averageRideHeightInMeters.hashCode());
result = prime * result + ((averageSamplingInterval == null) ? 0 : averageSamplingInterval.hashCode());
result = prime * result + ((averageSignedCrossTrackErrorInMeters == null) ? 0
: averageSignedCrossTrackErrorInMeters.hashCode());
result = prime * result + ((calculatedTime == null) ? 0 : calculatedTime.hashCode());
result = prime * result + ((calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) ? 0
: calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.hashCode());
result = prime * result + (discarded ? 1231 : 1237);
result = prime * result + ((distanceToStarboardSideOfStartLineInMeters == null) ? 0
: distanceToStarboardSideOfStartLineInMeters.hashCode());
result = prime * result + ((distanceToStartLineAtStartOfRaceInMeters == null) ? 0
: distanceToStartLineAtStartOfRaceInMeters.hashCode());
result = prime * result + ((distanceToStartLineFiveSecondsBeforeStartInMeters == null) ? 0
: distanceToStartLineFiveSecondsBeforeStartInMeters.hashCode());
result = prime * result + ((expeditionDataHolder == null) ? 0 : expeditionDataHolder.hashCode());
result = prime * result + ((fleet == null) ? 0 : fleet.hashCode());
result = prime * result + ((gapToLeaderInOwnTime == null) ? 0 : gapToLeaderInOwnTime.hashCode());
result = prime * result + ((heel == null) ? 0 : heel.hashCode());
result = prime * result + ((legDetails == null) ? 0 : legDetails.hashCode());
result = prime * result + ((netPoints == null) ? 0 : netPoints.hashCode());
result = prime * result + ((pitch == null) ? 0 : pitch.hashCode());
result = prime * result + ((race == null) ? 0 : race.hashCode());
result = prime * result + ((reasonForMaxPoints == null) ? 0 : reasonForMaxPoints.hashCode());
result = prime * result + ((speedOverGroundAtPassingStartWaypointInKnots == null) ? 0
: speedOverGroundAtPassingStartWaypointInKnots.hashCode());
result = prime * result
+ ((speedOverGroundAtStartOfRaceInKnots == null) ? 0 : speedOverGroundAtStartOfRaceInKnots.hashCode());
result = prime * result + ((speedOverGroundFiveSecondsBeforeStartInKnots == null) ? 0
: speedOverGroundFiveSecondsBeforeStartInKnots.hashCode());
result = prime * result + ((startTack == null) ? 0 : startTack.hashCode());
result = prime * result + ((timeBetweenRaceStartAndCompetitorStartInSeconds == null) ? 0
: timeBetweenRaceStartAndCompetitorStartInSeconds.hashCode());
result = prime * result
+ ((timeSinceLastPositionFixInSeconds == null) ? 0 : timeSinceLastPositionFixInSeconds.hashCode());
result = prime * result + ((totalPoints == null) ? 0 : totalPoints.hashCode());
result = prime * result + (totalPointsCorrected ? 1231 : 1237);
result = prime * result + ((totalPointsUncorrected == null) ? 0 : totalPointsUncorrected.hashCode());
result = prime * result + ((windwardDistanceToCompetitorFarthestAheadInMeters == null) ? 0
: windwardDistanceToCompetitorFarthestAheadInMeters.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LeaderboardEntryDTO other = (LeaderboardEntryDTO) obj;
if (averageAbsoluteCrossTrackErrorInMeters == null) {
if (other.averageAbsoluteCrossTrackErrorInMeters != null)
return false;
} else if (!averageAbsoluteCrossTrackErrorInMeters.equals(other.averageAbsoluteCrossTrackErrorInMeters))
return false;
if (averageRideHeightInMeters == null) {
if (other.averageRideHeightInMeters != null)
return false;
} else if (!averageRideHeightInMeters.equals(other.averageRideHeightInMeters))
return false;
if (averageSamplingInterval == null) {
if (other.averageSamplingInterval != null)
return false;
} else if (!averageSamplingInterval.equals(other.averageSamplingInterval))
return false;
if (averageSignedCrossTrackErrorInMeters == null) {
if (other.averageSignedCrossTrackErrorInMeters != null)
return false;
} else if (!averageSignedCrossTrackErrorInMeters.equals(other.averageSignedCrossTrackErrorInMeters))
return false;
if (calculatedTime == null) {
if (other.calculatedTime != null)
return false;
} else if (!calculatedTime.equals(other.calculatedTime))
return false;
if (calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) {
if (other.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead != null)
return false;
} else if (!calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead
.equals(other.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead))
return false;
if (discarded != other.discarded)
return false;
if (distanceToStarboardSideOfStartLineInMeters == null) {
if (other.distanceToStarboardSideOfStartLineInMeters != null)
return false;
} else if (!distanceToStarboardSideOfStartLineInMeters.equals(other.distanceToStarboardSideOfStartLineInMeters))
return false;
if (distanceToStartLineAtStartOfRaceInMeters == null) {
if (other.distanceToStartLineAtStartOfRaceInMeters != null)
return false;
} else if (!distanceToStartLineAtStartOfRaceInMeters.equals(other.distanceToStartLineAtStartOfRaceInMeters))
return false;
if (distanceToStartLineFiveSecondsBeforeStartInMeters == null) {
if (other.distanceToStartLineFiveSecondsBeforeStartInMeters != null)
return false;
} else if (!distanceToStartLineFiveSecondsBeforeStartInMeters
.equals(other.distanceToStartLineFiveSecondsBeforeStartInMeters))
return false;
if (expeditionDataHolder == null) {
if (other.expeditionDataHolder != null)
return false;
} else if (!expeditionDataHolder.equals(other.expeditionDataHolder))
return false;
if (fleet == null) {
if (other.fleet != null)
return false;
} else if (!fleet.equals(other.fleet))
return false;
if (gapToLeaderInOwnTime == null) {
if (other.gapToLeaderInOwnTime != null)
return false;
} else if (!gapToLeaderInOwnTime.equals(other.gapToLeaderInOwnTime))
return false;
if (heel == null) {
if (other.heel != null)
return false;
} else if (!heel.equals(other.heel))
return false;
if (legDetails == null) {
if (other.legDetails != null)
return false;
} else if (!legDetails.equals(other.legDetails))
return false;
if (netPoints == null) {
if (other.netPoints != null)
return false;
} else if (!netPoints.equals(other.netPoints))
return false;
if (pitch == null) {
if (other.pitch != null)
return false;
} else if (!pitch.equals(other.pitch))
return false;
if (race == null) {
if (other.race != null)
return false;
} else if (!race.equals(other.race))
return false;
if (reasonForMaxPoints != other.reasonForMaxPoints)
return false;
if (speedOverGroundAtPassingStartWaypointInKnots == null) {
if (other.speedOverGroundAtPassingStartWaypointInKnots != null)
return false;
} else if (!speedOverGroundAtPassingStartWaypointInKnots
.equals(other.speedOverGroundAtPassingStartWaypointInKnots))
return false;
if (speedOverGroundAtStartOfRaceInKnots == null) {
if (other.speedOverGroundAtStartOfRaceInKnots != null)
return false;
} else if (!speedOverGroundAtStartOfRaceInKnots.equals(other.speedOverGroundAtStartOfRaceInKnots))
return false;
if (speedOverGroundFiveSecondsBeforeStartInKnots == null) {
if (other.speedOverGroundFiveSecondsBeforeStartInKnots != null)
return false;
} else if (!speedOverGroundFiveSecondsBeforeStartInKnots
.equals(other.speedOverGroundFiveSecondsBeforeStartInKnots))
return false;
if (startTack != other.startTack)
return false;
if (timeBetweenRaceStartAndCompetitorStartInSeconds == null) {
if (other.timeBetweenRaceStartAndCompetitorStartInSeconds != null)
return false;
} else if (!timeBetweenRaceStartAndCompetitorStartInSeconds
.equals(other.timeBetweenRaceStartAndCompetitorStartInSeconds))
return false;
if (timeSinceLastPositionFixInSeconds == null) {
if (other.timeSinceLastPositionFixInSeconds != null)
return false;
} else if (!timeSinceLastPositionFixInSeconds.equals(other.timeSinceLastPositionFixInSeconds))
return false;
if (totalPoints == null) {
if (other.totalPoints != null)
return false;
} else if (!totalPoints.equals(other.totalPoints))
return false;
if (totalPointsCorrected != other.totalPointsCorrected)
return false;
if (totalPointsUncorrected == null) {
if (other.totalPointsUncorrected != null)
return false;
} else if (!totalPointsUncorrected.equals(other.totalPointsUncorrected))
return false;
if (windwardDistanceToCompetitorFarthestAheadInMeters == null) {
if (other.windwardDistanceToCompetitorFarthestAheadInMeters != null)
return false;
} else if (!windwardDistanceToCompetitorFarthestAheadInMeters
.equals(other.windwardDistanceToCompetitorFarthestAheadInMeters))
return false;
return true;
}
private void ensureExpeditionHolder() {
if (expeditionDataHolder == null) {
expeditionDataHolder = new ExpeditionDataHolder();
@@ -778,6 +582,211 @@ public class LeaderboardEntryDTO implements Serializable {
public Double getExpeditionMastButt() {
return expeditionDataHolder == null ? null : expeditionDataHolder.expeditionMastButt;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((averageAbsoluteCrossTrackErrorInMeters == null) ? 0
: averageAbsoluteCrossTrackErrorInMeters.hashCode());
result = prime * result + ((averageRideHeightInMeters == null) ? 0 : averageRideHeightInMeters.hashCode());
result = prime * result + ((averageSamplingInterval == null) ? 0 : averageSamplingInterval.hashCode());
result = prime * result + ((averageSignedCrossTrackErrorInMeters == null) ? 0
: averageSignedCrossTrackErrorInMeters.hashCode());
result = prime * result + ((boat == null) ? 0 : boat.hashCode());
result = prime * result + ((calculatedTime == null) ? 0 : calculatedTime.hashCode());
result = prime * result + ((calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) ? 0
: calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead.hashCode());
result = prime * result + (discarded ? 1231 : 1237);
result = prime * result + ((distanceToStarboardSideOfStartLineInMeters == null) ? 0
: distanceToStarboardSideOfStartLineInMeters.hashCode());
result = prime * result + ((distanceToStartLineAtStartOfRaceInMeters == null) ? 0
: distanceToStartLineAtStartOfRaceInMeters.hashCode());
result = prime * result + ((distanceToStartLineFiveSecondsBeforeStartInMeters == null) ? 0
: distanceToStartLineFiveSecondsBeforeStartInMeters.hashCode());
result = prime * result + ((expeditionDataHolder == null) ? 0 : expeditionDataHolder.hashCode());
result = prime * result + ((fleet == null) ? 0 : fleet.hashCode());
result = prime * result + ((gapToLeaderInOwnTime == null) ? 0 : gapToLeaderInOwnTime.hashCode());
result = prime * result + ((heel == null) ? 0 : heel.hashCode());
result = prime * result + ((legDetails == null) ? 0 : legDetails.hashCode());
result = prime * result + ((netPoints == null) ? 0 : netPoints.hashCode());
result = prime * result + ((pitch == null) ? 0 : pitch.hashCode());
result = prime * result + ((race == null) ? 0 : race.hashCode());
result = prime * result + ((reasonForMaxPoints == null) ? 0 : reasonForMaxPoints.hashCode());
result = prime * result + ((speedOverGroundAtPassingStartWaypointInKnots == null) ? 0
: speedOverGroundAtPassingStartWaypointInKnots.hashCode());
result = prime * result
+ ((speedOverGroundAtStartOfRaceInKnots == null) ? 0 : speedOverGroundAtStartOfRaceInKnots.hashCode());
result = prime * result + ((speedOverGroundFiveSecondsBeforeStartInKnots == null) ? 0
: speedOverGroundFiveSecondsBeforeStartInKnots.hashCode());
result = prime * result + ((startTack == null) ? 0 : startTack.hashCode());
result = prime * result + ((timeBetweenRaceStartAndCompetitorStartInSeconds == null) ? 0
: timeBetweenRaceStartAndCompetitorStartInSeconds.hashCode());
result = prime * result
+ ((timeSinceLastPositionFixInSeconds == null) ? 0 : timeSinceLastPositionFixInSeconds.hashCode());
result = prime * result + ((totalPoints == null) ? 0 : totalPoints.hashCode());
result = prime * result + (totalPointsCorrected ? 1231 : 1237);
result = prime * result + ((totalPointsUncorrected == null) ? 0 : totalPointsUncorrected.hashCode());
result = prime * result + ((windwardDistanceToCompetitorFarthestAheadInMeters == null) ? 0
: windwardDistanceToCompetitorFarthestAheadInMeters.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LeaderboardEntryDTO other = (LeaderboardEntryDTO) obj;
if (averageAbsoluteCrossTrackErrorInMeters == null) {
if (other.averageAbsoluteCrossTrackErrorInMeters != null)
return false;
} else if (!averageAbsoluteCrossTrackErrorInMeters.equals(other.averageAbsoluteCrossTrackErrorInMeters))
return false;
if (averageRideHeightInMeters == null) {
if (other.averageRideHeightInMeters != null)
return false;
} else if (!averageRideHeightInMeters.equals(other.averageRideHeightInMeters))
return false;
if (averageSamplingInterval == null) {
if (other.averageSamplingInterval != null)
return false;
} else if (!averageSamplingInterval.equals(other.averageSamplingInterval))
return false;
if (averageSignedCrossTrackErrorInMeters == null) {
if (other.averageSignedCrossTrackErrorInMeters != null)
return false;
} else if (!averageSignedCrossTrackErrorInMeters.equals(other.averageSignedCrossTrackErrorInMeters))
return false;
if (boat == null) {
if (other.boat != null)
return false;
} else if (!boat.equals(other.boat))
return false;
if (calculatedTime == null) {
if (other.calculatedTime != null)
return false;
} else if (!calculatedTime.equals(other.calculatedTime))
return false;
if (calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead == null) {
if (other.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead != null)
return false;
} else if (!calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead
.equals(other.calculatedTimeAtEstimatedArrivalAtCompetitorFarthestAhead))
return false;
if (discarded != other.discarded)
return false;
if (distanceToStarboardSideOfStartLineInMeters == null) {
if (other.distanceToStarboardSideOfStartLineInMeters != null)
return false;
} else if (!distanceToStarboardSideOfStartLineInMeters.equals(other.distanceToStarboardSideOfStartLineInMeters))
return false;
if (distanceToStartLineAtStartOfRaceInMeters == null) {
if (other.distanceToStartLineAtStartOfRaceInMeters != null)
return false;
} else if (!distanceToStartLineAtStartOfRaceInMeters.equals(other.distanceToStartLineAtStartOfRaceInMeters))
return false;
if (distanceToStartLineFiveSecondsBeforeStartInMeters == null) {
if (other.distanceToStartLineFiveSecondsBeforeStartInMeters != null)
return false;
} else if (!distanceToStartLineFiveSecondsBeforeStartInMeters
.equals(other.distanceToStartLineFiveSecondsBeforeStartInMeters))
return false;
if (expeditionDataHolder == null) {
if (other.expeditionDataHolder != null)
return false;
} else if (!expeditionDataHolder.equals(other.expeditionDataHolder))
return false;
if (fleet == null) {
if (other.fleet != null)
return false;
} else if (!fleet.equals(other.fleet))
return false;
if (gapToLeaderInOwnTime == null) {
if (other.gapToLeaderInOwnTime != null)
return false;
} else if (!gapToLeaderInOwnTime.equals(other.gapToLeaderInOwnTime))
return false;
if (heel == null) {
if (other.heel != null)
return false;
} else if (!heel.equals(other.heel))
return false;
if (legDetails == null) {
if (other.legDetails != null)
return false;
} else if (!legDetails.equals(other.legDetails))
return false;
if (netPoints == null) {
if (other.netPoints != null)
return false;
} else if (!netPoints.equals(other.netPoints))
return false;
if (pitch == null) {
if (other.pitch != null)
return false;
} else if (!pitch.equals(other.pitch))
return false;
if (race == null) {
if (other.race != null)
return false;
} else if (!race.equals(other.race))
return false;
if (reasonForMaxPoints != other.reasonForMaxPoints)
return false;
if (speedOverGroundAtPassingStartWaypointInKnots == null) {
if (other.speedOverGroundAtPassingStartWaypointInKnots != null)
return false;
} else if (!speedOverGroundAtPassingStartWaypointInKnots
.equals(other.speedOverGroundAtPassingStartWaypointInKnots))
return false;
if (speedOverGroundAtStartOfRaceInKnots == null) {
if (other.speedOverGroundAtStartOfRaceInKnots != null)
return false;
} else if (!speedOverGroundAtStartOfRaceInKnots.equals(other.speedOverGroundAtStartOfRaceInKnots))
return false;
if (speedOverGroundFiveSecondsBeforeStartInKnots == null) {
if (other.speedOverGroundFiveSecondsBeforeStartInKnots != null)
return false;
} else if (!speedOverGroundFiveSecondsBeforeStartInKnots
.equals(other.speedOverGroundFiveSecondsBeforeStartInKnots))
return false;
if (startTack != other.startTack)
return false;
if (timeBetweenRaceStartAndCompetitorStartInSeconds == null) {
if (other.timeBetweenRaceStartAndCompetitorStartInSeconds != null)
return false;
} else if (!timeBetweenRaceStartAndCompetitorStartInSeconds
.equals(other.timeBetweenRaceStartAndCompetitorStartInSeconds))
return false;
if (timeSinceLastPositionFixInSeconds == null) {
if (other.timeSinceLastPositionFixInSeconds != null)
return false;
} else if (!timeSinceLastPositionFixInSeconds.equals(other.timeSinceLastPositionFixInSeconds))
return false;
if (totalPoints == null) {
if (other.totalPoints != null)
return false;
} else if (!totalPoints.equals(other.totalPoints))
return false;
if (totalPointsCorrected != other.totalPointsCorrected)
return false;
if (totalPointsUncorrected == null) {
if (other.totalPointsUncorrected != null)
return false;
} else if (!totalPointsUncorrected.equals(other.totalPointsUncorrected))
return false;
if (windwardDistanceToCompetitorFarthestAheadInMeters == null) {
if (other.windwardDistanceToCompetitorFarthestAheadInMeters != null)
return false;
} else if (!windwardDistanceToCompetitorFarthestAheadInMeters
.equals(other.windwardDistanceToCompetitorFarthestAheadInMeters))
return false;
return true;
}
/**
* Used to ensure that only one null value needs to be transmitted, if no expedition data exists
@@ -16,6 +16,7 @@ import com.sap.sse.common.Duration;
public class LeaderboardRowDTO implements Serializable {
private static final long serialVersionUID = -5421934148931661900L;
public CompetitorDTO competitor;
public BoatDTO boat;
public Map<String, LeaderboardEntryDTO> fieldsByRaceColumnName;
public Double carriedPoints;
public Double netPoints;
@@ -36,6 +37,7 @@ public class LeaderboardRowDTO implements Serializable {
int result = 1;
result = prime * result + ((carriedPoints == null) ? 0 : carriedPoints.hashCode());
result = prime * result + ((competitor == null) ? 0 : competitor.hashCode());
result = prime * result + ((boat == null) ? 0 : boat.hashCode());
result = prime * result + ((fieldsByRaceColumnName == null) ? 0 : fieldsByRaceColumnName.hashCode());
result = prime * result
+ ((maximumSpeedOverGroundInKnots == null) ? 0 : maximumSpeedOverGroundInKnots.hashCode());
@@ -79,6 +81,11 @@ public class LeaderboardRowDTO implements Serializable {
return false;
} else if (!competitor.equals(other.competitor))
return false;
if (boat == null) {
if (other.boat != null)
return false;
} else if (!boat.equals(other.boat))
return false;
if (fieldsByRaceColumnName == null) {
if (other.fieldsByRaceColumnName != null)
return false;
@@ -6,31 +6,31 @@ import java.util.List;
import com.sap.sse.common.Util.Pair;
public class PairingListDTO implements Serializable{
public class PairingListDTO implements Serializable {
private static final long serialVersionUID = 102220422437194196L;
private List<List<List<Pair<CompetitorDTO, BoatDTO>>>> pairingList;
private List<List<List<Pair<CompetitorWithoutBoatDTO, BoatDTO>>>> pairingList;
private List<String> raceColumnNames;
public PairingListDTO() { }
public PairingListDTO(List<List<List<Pair<CompetitorDTO, BoatDTO>>>> result) {
public PairingListDTO(List<List<List<Pair<CompetitorWithoutBoatDTO, BoatDTO>>>> result) {
this(result, null);
}
public PairingListDTO(List<List<List<Pair<CompetitorDTO, BoatDTO>>>> result, List<String> raceColumnNames) {
public PairingListDTO(List<List<List<Pair<CompetitorWithoutBoatDTO, BoatDTO>>>> result, List<String> raceColumnNames) {
this.pairingList = result;
this.raceColumnNames = raceColumnNames;
}
public List<List<List<Pair<CompetitorDTO, BoatDTO>>>> getPairingList() {
public List<List<List<Pair<CompetitorWithoutBoatDTO, BoatDTO>>>> getPairingList() {
return pairingList;
}
public List<BoatDTO> getBoats() {
List<BoatDTO> boats = new ArrayList<>();
for (List<Pair<CompetitorDTO, BoatDTO>> fleet : this.pairingList.get(0)) {
for (Pair<CompetitorDTO, BoatDTO> competitorAndBoatPair : fleet) {
for (List<Pair<CompetitorWithoutBoatDTO, BoatDTO>> fleet : this.pairingList.get(0)) {
for (Pair<CompetitorWithoutBoatDTO, BoatDTO> competitorAndBoatPair : fleet) {
if (!boats.contains(competitorAndBoatPair.getB())) {
boats.add(competitorAndBoatPair.getB());
}
@@ -18,22 +18,23 @@ public class PairingListTemplateDTO implements Serializable {
public PairingListTemplateDTO() { }
public PairingListTemplateDTO(int competitorCount, int flightMultiplier) {
this(0, 0, competitorCount, flightMultiplier, null, 0.0, null);
this(0, 0, competitorCount, flightMultiplier, null, 0.0, /* selected flight names */ null);
}
public PairingListTemplateDTO(int competitorCount, int flightMultiplier, int[][] pairingListTemplate, double quality) {
this(0, 0, competitorCount, flightMultiplier, pairingListTemplate, quality, null);
this(0, 0, competitorCount, flightMultiplier, pairingListTemplate, quality, /* selected flight names */ null);
}
public PairingListTemplateDTO(int competitorCount, int[][] pairingListTemplate, double quality) {
this(0, 0, competitorCount, 0, pairingListTemplate, quality, null);
this(0, 0, competitorCount, 0, pairingListTemplate, quality, /* selected flight names */ null);
}
public PairingListTemplateDTO(int flightCount, int groupCount, int competitorCount, int flightMultiplier, int[][] pairingListTemplate, double quality) {
this(flightCount, groupCount, competitorCount, flightMultiplier, pairingListTemplate, quality, null);
this(flightCount, groupCount, competitorCount, flightMultiplier, pairingListTemplate, quality, /* selected flight names */ null);
}
public PairingListTemplateDTO(int flightCount, int groupCount, int competitorCount, int flightMultiplier, int[][] pairingListTemplate, double quality, Iterable<String> selectedFlightNames) {
public PairingListTemplateDTO(int flightCount, int groupCount, int competitorCount, int flightMultiplier,
int[][] pairingListTemplate, double quality, Iterable<String> selectedFlightNames) {
this.flightCount = flightCount;
this.groupCount = groupCount;
this.competitorCount = competitorCount;
@@ -46,6 +47,7 @@ public class PairingListTemplateDTO implements Serializable {
public void setFlightCount(int flightCount){
this.flightCount=flightCount;
}
public void setGroupCount(int groupCount) {
this.groupCount = groupCount;
}
@@ -64,6 +64,18 @@ public class PreviousCompetitorDTOImpl implements CompetitorDTO {
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getShortName() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getShortInfo() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public String getSailID() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
@@ -76,6 +88,12 @@ public class PreviousCompetitorDTOImpl implements CompetitorDTO {
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public void setBoat(BoatDTO boat) {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
" need to be replaced by an object of "+CompetitorDTOImpl.class.getName()+" after deserialization");
}
@Override
public Color getColor() {
throw new RuntimeException("Internal error. Objects of type "+PreviousCompetitorDTOImpl.class.getName()+
@@ -26,11 +26,13 @@ public class DeviceMappingConstants {
public static final String URL_EVENT_ID = "event_id";
public static final String URL_LEADERBOARD_NAME = "leaderboard_name";
public static final String URL_COMPETITOR_ID_AS_STRING = "competitor_id";
public static final String URL_BOAT_ID_AS_STRING = "boat_id";
public static final String URL_MARK_ID_AS_STRING = "mark_id";
public static final String URL_FROM_MILLIS = "from_millis";
public static final String URL_TO_MILLIS = "to_millis";
public static final String JSON_COMPETITOR_ID_AS_STRING = "competitorId";
public static final String JSON_BOAT_ID_AS_STRING = "boatId";
public static final String JSON_MARK_ID_AS_STRING = "markId";
public static final String JSON_DEVICE_UUID = "deviceUuid";
public static final String JSON_DEVICE_TYPE = "deviceType";
@@ -12,6 +12,7 @@ public enum Permission implements com.sap.sse.security.shared.Permission {
SHOW_TRACKED_RACES,
MANAGE_RACELOG_TRACKING,
MANAGE_ALL_COMPETITORS,
MANAGE_ALL_BOATS,
MANAGE_COURSE_LAYOUT,
MANAGE_WIND,
MANAGE_IGTIMI_ACCOUNTS,
@@ -23,6 +23,7 @@ public class SailingPermissionsForRoleProvider implements PermissionsForRoleProv
// AdminConsole:
Permission.MANAGE_ALL_COMPETITORS,
Permission.MANAGE_ALL_BOATS,
Permission.MANAGE_COURSE_LAYOUT,
Permission.MANAGE_DEVICE_CONFIGURATION,
Permission.MANAGE_EVENTS,
@@ -0,0 +1,14 @@
package com.sap.sailing.domain.common.tracking.impl;
/**
* Used to assemble a compatible JSON string by themselves, using the constants from here.The field identified by this
* name tells the fully-qualified class name from which the value of the field identified by {@link #FIELD_ID} has been
* created. When deserializing, the ID needs to be re-constructed as an instance of that type.
*/
public class BoatJsonConstants {
public static final String FIELD_ID = "id";
public static final String FIELD_NAME = "name";
public static final String FIELD_SAIL_ID = "sailID";
public static final String FIELD_COLOR = "color";
public static final String FIELD_BOAT_CLASS_NAME = "boatClassName";
}
@@ -8,6 +8,7 @@ package com.sap.sailing.domain.common.tracking.impl;
public class CompetitorJsonConstants {
public static final String FIELD_ID = "id";
public static final String FIELD_NAME = "name";
public static final String FIELD_SHORT_NAME = "shortName";
public static final String FIELD_SAIL_ID = "sailID";
public static final String FIELD_NATIONALITY = "nationality";
public static final String FIELD_COUNTRY_CODE = "countryCode";
@@ -20,6 +21,8 @@ public class CompetitorJsonConstants {
public static final String FIELD_NATIONALITY_ISO3 = "nationalityISO3";
public static final String FIELD_TEAM = "team";
public static final String FIELD_BOAT = "boat";
public static final String FIELD_BOAT_ID_TYPE = "boatidtype";
public static final String FIELD_BOAT_ID = "boatId";
public static final String FIELD_DISPLAY_COLOR = "displayColor";
public static final String FIELD_EMAIL = "email";
public static final String FIELD_SEARCHTAG = "searchTag";
@@ -12,8 +12,10 @@ import java.util.function.Consumer;
import com.mongodb.DBObject;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.anniversary.DetailedRaceInfo;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorWithBoat;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.RaceDefinition;
@@ -129,13 +131,25 @@ public interface DomainObjectFactory {
RaceLog loadRaceLog(RaceLogIdentifier identifier);
RegattaLog loadRegattaLog(RegattaLikeIdentifier identifier);
/**
* Loads all competitors, and resolves them via the domain factory.
* @return
* Migrates the old COMPETITORS collection and the new BOATS collection.
* The old COLLECTION is will be renamed to COMPETITORS_BAK for deveopment and test purposes
* @return a collection of the old type where all competitors contain their boats or null if migration was not required.
*/
Iterable<CompetitorWithBoat> migrateLegacyCompetitorsIfRequired();
/**
* Loads all competitors (with and without embedded boats) and resolves them via the domain factory.
* Returns a collection of {@link Competitor} or {@link CompetitorWithBoat} objects.
*/
Collection<Competitor> loadAllCompetitors();
/**
* Loads all boats and resolves them via the domain factory.
*/
Collection<Boat> loadAllBoats();
DomainFactory getBaseDomainFactory();
Iterable<Entry<DeviceConfigurationMatcher, DeviceConfiguration>> loadAllDeviceConfigurations();
@@ -8,6 +8,7 @@ import java.util.concurrent.ConcurrentHashMap;
import com.mongodb.DB;
import com.mongodb.DBObject;
import com.sap.sailing.domain.anniversary.DetailedRaceInfo;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.RaceDefinition;
@@ -122,9 +123,9 @@ public interface MongoObjectFactory {
void storeRegattaForRaceID(String id, Regatta regatta);
void removeRegattaForRaceID(String raceIDAsString, Regatta regatta);
/**
* Stores a competitor, including the team and boat. This should not be done for competitors for which
* Stores a competitor. This should not be done for competitors for which
* the master data is supplied by other systems, such as TracTrac, but rather for smartphone tracking,
* where this data is otherwise not recoverable.
* @param competitor the competitor to store/update in the database
@@ -135,11 +136,29 @@ public interface MongoObjectFactory {
* Like {@link #storeCompetitor(Competitor)}, but for a collection of competitors that are all
* expected to be new, having a unique {@link Competitor#getId() ID}.
*/
void storeCompetitors(Iterable<Competitor> competitors);
void storeCompetitors(Iterable<? extends Competitor> competitors);
void removeAllCompetitors();
void removeCompetitor(Competitor competitor);
/**
* Stores a boat. This should not be done for boats for which
* the master data is supplied by other systems, such as TracTrac, but rather for smartphone tracking,
* where this data is otherwise not recoverable.
* @param boat the boat to store/update in the database
*/
void storeBoat(Boat boat);
/**
* Like {@link #storeBoat(Boat)}, but for a collection of boats that are all
* expected to be new, having a unique {@link Boat#getId() ID}.
*/
void storeBoats(Iterable<Boat> boats);
void removeAllBoats();
void removeBoat(Boat boat);
DB getDatabase();
@@ -68,16 +68,27 @@ public enum CollectionNames {
*/
REGATTA_FOR_RACE_ID,
/**
* Stores the race log events for a tracked race.
*/
/**
* Stores competitors for smartphone tracking.
* Legacy store for competitors before implementation of bug2822
* Contains the old competitors with contained boats.
*/
COMPETITORS_BAK,
/**
* Stores competitors with or without boat references.
*/
COMPETITORS,
/**
* Stores boats.
*/
BOATS,
/**
* Stores the race log events for a tracked race.
*/
RACE_LOGS,
REGATTA_LOGS,
@@ -38,6 +38,7 @@ public enum FieldNames {
REGATTA_BUOY_ZONE_RADIUS_IN_HULL_LENGTHS,
REGATTA_USE_START_TIME_INFERENCE,
REGATTA_CONTROL_TRACKING_FROM_START_AND_FINISH_TIMES,
REGATTA_CAN_BOATS_OF_COMPETITORS_CHANGE_PER_RACE,
SERIES_NAME,
SERIES_IS_MEDAL,
SERIES_IS_FLEETS_CAN_RUN_IN_PARALLEL,
@@ -102,7 +103,7 @@ public enum FieldNames {
RACE_LOG_POSITIONED_COMPETITORS, RACE_LOG_PATHFINDER_ID, RACE_LOG_GATE_LINE_OPENING_TIME, RACE_LOG_GOLF_DOWN_TIME, RACE_LOG_START_PROCEDURE_TYPE,
RACE_LOG_PROTEST_START_TIME, RACE_LOG_PROTEST_END_TIME, RACE_LOG_COURSE_DESIGN_NAME, RACE_LOG_REVOKED_EVENT_ID, RACE_LOG_REVOKED_EVENT_TYPE,
RACE_LOG_REVOKED_EVENT_SHORT_INFO, RACE_LOG_REVOKED_REASON, RACE_LOG_DEVICE_MAPPING_EVENT_ID,
RACE_LOG_CLOSING_TIMEPOINT, TIMEPOINT_OF_FIXED_MARKPASSING, INDEX_OF_PASSED_WAYPOINT,INDEX_OF_FIRST_SUPPRESSED_WAYPOINT, MARK, RACE_LOG_COMPETITOR_ID,
RACE_LOG_CLOSING_TIMEPOINT, TIMEPOINT_OF_FIXED_MARKPASSING, INDEX_OF_PASSED_WAYPOINT,INDEX_OF_FIRST_SUPPRESSED_WAYPOINT, MARK, RACE_LOG_COMPETITOR_ID, RACE_LOG_BOAT_ID,
RACE_LOG_DEPDENDENT_ON_FLEET, RACE_LOG_DEPDENDENT_ON_RACECOLUMN, RACE_LOG_DEPDENDENT_ON_REGATTALIKE,
RACE_LOG_START_TIME_DIFFERENCE_IN_MS, RACE_LOG_FINISHING_TIME_AS_MILLIS,
/** @deprecated Replaced by {@link #REGATTA_LOG_FROM}; auto-migration from race log device mappings to regatta log is implemented */ @Deprecated RACE_LOG_FROM,
@@ -118,7 +119,7 @@ public enum FieldNames {
// did not reuse RACE_LOG* types, as this would require handling old versions of all events
REGATTA_LOG_IDENTIFIER_TYPE, REGATTA_LOG_IDENTIFIER_NAME, REGATTA_LOG_EVENT_ID, REGATTA_LOG_EVENT_CREATED_AT, REGATTA_LOG_EVENT_AUTHOR_NAME,
REGATTA_LOG_EVENT_AUTHOR_PRIORITY, REGATTA_LOG_EVENT_CLASS, REGATTA_LOG_REVOKED_EVENT_ID, REGATTA_LOG_REVOKED_EVENT_TYPE, REGATTA_LOG_REVOKED_EVENT_SHORT_INFO,
REGATTA_LOG_REVOKED_REASON, REGATTA_LOG_COMPETITOR_ID, REGATTA_LOG_DEVICE_MAPPING_EVENT_ID, REGATTA_LOG_CLOSING_TIMEPOINT,
REGATTA_LOG_REVOKED_REASON, REGATTA_LOG_COMPETITOR_ID, REGATTA_LOG_BOAT_ID, REGATTA_LOG_DEVICE_MAPPING_EVENT_ID, REGATTA_LOG_CLOSING_TIMEPOINT,
REGATTA_LOG_FROM, REGATTA_LOG_TO, REGATTA_LOG_EVENT, REGATTA_LOG_MARK,
// remote server reference fields
@@ -0,0 +1,50 @@
package com.sap.sailing.domain.persistence.impl;
import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.CourseArea;
import com.sap.sailing.domain.base.MigratableRegatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.racelog.RaceLogStore;
import com.sap.sailing.domain.ranking.RankingMetricConstructor;
import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
public class MigratableRegattaImpl extends RegattaImpl implements MigratableRegatta {
private static final long serialVersionUID = -3545488249832218320L;
private static final Logger logger = Logger.getLogger(MigratableRegattaImpl.class.getName());
/**
* To be used for storing a migrated regatta
*/
private transient final MongoObjectFactory mongoObjectFactory;
public <S extends Series> MigratableRegattaImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, String name,
BoatClass boatClass, boolean canBoatsOfCompetitorsChangePerRace, TimePoint startDate, TimePoint endDate,
Iterable<S> series, boolean persistent, ScoringScheme scoringScheme, Serializable id, CourseArea courseArea,
Double buoyZoneRadiusInHullLengths, boolean useStartTimeInference,
boolean controlTrackingFromStartAndFinishTimes, RankingMetricConstructor rankingMetricConstructor, MongoObjectFactory mongoObjectFactory) {
super(raceLogStore, regattaLogStore, name, boatClass, canBoatsOfCompetitorsChangePerRace, startDate, endDate, series,
persistent, scoringScheme, id, courseArea, buoyZoneRadiusInHullLengths, useStartTimeInference,
controlTrackingFromStartAndFinishTimes, rankingMetricConstructor);
this.mongoObjectFactory = mongoObjectFactory;
mongoObjectFactory.storeRegatta(this); // make sure the canBoatsOfCompetitorsChangePerRace flag makes it into the DB
}
public synchronized void migrateCanBoatsOfCompetitorsChangePerRace() {
// It should not be possible to call this after races have been already added to this regatta.
assert !canBoatsOfCompetitorsChangePerRace() && Util.size(getAllRaces()) == 0;
super.setCanBoatsOfCompetitorsChangePerRace(true);
if (mongoObjectFactory != null) {
logger.log(Level.INFO, "Bug2822 DB-Migration: Store migrated regatta '" + getName() + "' having now canBoatsOfCompetitorsChangePerRace=true.");
mongoObjectFactory.storeRegatta(this);
}
}
}
@@ -55,16 +55,21 @@ import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogUseCompetitorsFro
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterBoatEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnTimeFactorEvent;
import com.sap.sailing.domain.anniversary.DetailedRaceInfo;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorWithBoat;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.ControlPointWithTwoMarks;
import com.sap.sailing.domain.base.CourseArea;
@@ -116,7 +121,9 @@ import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.server.gateway.serialization.JsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.BoatJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.CompetitorWithBoatRefJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.DeviceConfigurationJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.RegattaConfigurationJsonSerializer;
import com.sap.sse.common.Duration;
@@ -135,7 +142,9 @@ import com.sap.sse.shared.media.VideoDescriptor;
public class MongoObjectFactoryImpl implements MongoObjectFactory {
private static Logger logger = Logger.getLogger(MongoObjectFactoryImpl.class.getName());
private final DB database;
private final CompetitorWithBoatRefJsonSerializer competitorWithBoatRefSerializer = CompetitorWithBoatRefJsonSerializer.create();
private final CompetitorJsonSerializer competitorSerializer = CompetitorJsonSerializer.create();
private final BoatJsonSerializer boatSerializer = BoatJsonSerializer.create();
private final TypeBasedServiceFinder<DeviceIdentifierMongoHandler> deviceIdentifierServiceFinder;
private final TypeBasedServiceFinder<RaceTrackingConnectivityParametersHandler> raceTrackingConnectivityParamsServiceFinder;
@@ -706,6 +715,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
dbRegatta.put(FieldNames.REGATTA_BUOY_ZONE_RADIUS_IN_HULL_LENGTHS.name(), regatta.getBuoyZoneRadiusInHullLengths());
dbRegatta.put(FieldNames.REGATTA_USE_START_TIME_INFERENCE.name(), regatta.useStartTimeInference());
dbRegatta.put(FieldNames.REGATTA_CONTROL_TRACKING_FROM_START_AND_FINISH_TIMES.name(), regatta.isControlTrackingFromStartAndFinishTimes());
dbRegatta.put(FieldNames.REGATTA_CAN_BOATS_OF_COMPETITORS_CHANGE_PER_RACE.name(), regatta.canBoatsOfCompetitorsChangePerRace());
dbRegatta.put(FieldNames.REGATTA_RANKING_METRIC.name(), storeRankingMetric(regatta));
boolean success = false;
final int MAX_TRIES = 3;
@@ -1067,6 +1077,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
storeRaceLogEventProperties(event, result);
result.put(FieldNames.RACE_LOG_EVENT_CLASS.name(), RaceLogRegisterCompetitorEvent.class.getSimpleName());
result.put(FieldNames.RACE_LOG_COMPETITOR_ID.name(), event.getCompetitor().getId());
result.put(FieldNames.RACE_LOG_BOAT_ID.name(), event.getBoat().getId());
return result;
}
@@ -1126,7 +1137,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
storeTimePoint(event.getCreatedAt(), result, FieldNames.RACE_LOG_EVENT_CREATED_AT);
result.put(FieldNames.RACE_LOG_EVENT_ID.name(), event.getId());
result.put(FieldNames.RACE_LOG_EVENT_PASS_ID.name(), event.getPassId());
result.put(FieldNames.RACE_LOG_EVENT_INVOLVED_BOATS.name(), storeInvolvedBoatsForRaceLogEvent(event.getInvolvedBoats()));
result.put(FieldNames.RACE_LOG_EVENT_INVOLVED_BOATS.name(), storeInvolvedBoatsForRaceLogEvent(event.getInvolvedCompetitors()));
storeRaceLogEventAuthor(result, event.getAuthor());
}
@@ -1290,8 +1301,17 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
}
return passing;
}
@Override
public void storeCompetitor(Competitor competitor) {
if (competitor.hasBoat()) {
storeCompetitorWithBoat((CompetitorWithBoat) competitor);
} else {
storeCompetitorWithoutBoat(competitor);
}
}
private void storeCompetitorWithoutBoat(Competitor competitor) {
DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
JSONObject json = competitorSerializer.serialize(competitor);
DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString());
@@ -1299,9 +1319,33 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
collection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE);
}
private void storeCompetitorWithBoat(CompetitorWithBoat competitor) {
DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
JSONObject json = competitorWithBoatRefSerializer.serialize(competitor);
DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString());
DBObject entry = (DBObject) JSON.parse(json.toString());
collection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE);
}
@Override
public void storeCompetitors(Iterable<Competitor> competitors) {
public void storeCompetitors(Iterable<? extends Competitor> competitors) {
if (competitors != null && !Util.isEmpty(competitors)) {
List<Competitor> competitorsWithoutBoat = new ArrayList<>();
List<CompetitorWithBoat> competitorsWithBoat = new ArrayList<>();
for (Competitor competitor : competitors) {
if (competitor.hasBoat()) {
competitorsWithBoat.add((CompetitorWithBoat) competitor);
} else {
competitorsWithoutBoat.add(competitor);
}
}
storeCompetitorsWithBoat(competitorsWithBoat);
storeCompetitorsWithoutBoat(competitorsWithoutBoat);
}
}
private void storeCompetitorsWithoutBoat(Iterable<Competitor> competitors) {
if (!Util.isEmpty(competitors)) {
DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
List<DBObject> competitorsDB = new ArrayList<>();
for (Competitor competitor : competitors) {
@@ -1313,9 +1357,22 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
}
}
private void storeCompetitorsWithBoat(Iterable<CompetitorWithBoat> competitors) {
if (!Util.isEmpty(competitors)) {
DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
List<DBObject> competitorsDB = new ArrayList<>();
for (CompetitorWithBoat competitor : competitors) {
JSONObject json = competitorWithBoatRefSerializer.serialize(competitor);
DBObject entry = (DBObject) JSON.parse(json.toString());
competitorsDB.add(entry);
}
collection.insert(competitorsDB);
}
}
@Override
public void removeAllCompetitors() {
logger.info("Removing all persistent competitor info");
logger.info("Removing all persistent competitors");
DBCollection collection = database.getCollection(CollectionNames.COMPETITORS.name());
collection.drop();
}
@@ -1327,7 +1384,45 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
DBObject query = (DBObject) JSON.parse(CompetitorJsonSerializer.getCompetitorIdQuery(competitor).toString());
collection.remove(query, WriteConcern.SAFE);
}
@Override
public void storeBoat(Boat boat) {
DBCollection collection = database.getCollection(CollectionNames.BOATS.name());
JSONObject json = boatSerializer.serialize(boat);
DBObject query = (DBObject) JSON.parse(BoatJsonSerializer.getBoatIdQuery(boat).toString());
DBObject entry = (DBObject) JSON.parse(json.toString());
collection.update(query, entry, /* upsrt */true, /* multi */false, WriteConcern.SAFE);
}
@Override
public void storeBoats(Iterable<Boat> boats) {
if (boats != null && !Util.isEmpty(boats)) {
DBCollection collection = database.getCollection(CollectionNames.BOATS.name());
List<DBObject> boatsDB = new ArrayList<>();
for (Boat boat : boats) {
JSONObject json = boatSerializer.serialize(boat);
DBObject entry = (DBObject) JSON.parse(json.toString());
boatsDB.add(entry);
}
collection.insert(boatsDB);
}
}
@Override
public void removeAllBoats() {
logger.info("Removing all persistent boats");
DBCollection collection = database.getCollection(CollectionNames.BOATS.name());
collection.drop();
}
@Override
public void removeBoat(Boat boat) {
logger.info("Removing persistent boat "+boat.getName()+" with ID "+boat.getId());
DBCollection collection = database.getCollection(CollectionNames.BOATS.name());
DBObject query = (DBObject) JSON.parse(BoatJsonSerializer.getBoatIdQuery(boat).toString());
collection.remove(query, WriteConcern.SAFE);
}
@Override
public void storeDeviceConfiguration(DeviceConfigurationMatcher matcher, DeviceConfiguration configuration) {
DBCollection configurationsCollections = database.getCollection(CollectionNames.CONFIGURATIONS.name());
@@ -1463,6 +1558,14 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
result.put(FieldNames.COMPETITOR_ID.name(), event.getMappedTo().getId());
storeRegattaLogEvent(regattaLikeId, result);
}
public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogDeviceBoatMappingEvent event) {
DBObject result = createBasicRegattaLogEventDBObject(event);
result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogDeviceBoatMappingEvent.class.getSimpleName());
storeDeviceMappingEvent(event, result, FieldNames.REGATTA_LOG_FROM, FieldNames.REGATTA_LOG_TO);
result.put(FieldNames.RACE_LOG_BOAT_ID.name(), event.getMappedTo().getId());
storeRegattaLogEvent(regattaLikeId, result);
}
public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId,
RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
@@ -1472,6 +1575,15 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
result.put(FieldNames.COMPETITOR_ID.name(), event.getMappedTo().getId());
storeRegattaLogEvent(regattaLikeId, result);
}
public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId,
RegattaLogDeviceBoatSensorDataMappingEvent event) {
DBObject result = createBasicRegattaLogEventDBObject(event);
result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), event.getClass().getSimpleName());
storeDeviceMappingEvent(event, result, FieldNames.REGATTA_LOG_FROM, FieldNames.REGATTA_LOG_TO);
result.put(FieldNames.RACE_LOG_BOAT_ID.name(), event.getMappedTo().getId());
storeRegattaLogEvent(regattaLikeId, result);
}
public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogDeviceMarkMappingEvent event) {
DBObject result = createBasicRegattaLogEventDBObject(event);
@@ -1491,6 +1603,13 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
storeRegattaLogEvent(regattaLikeId, result);
}
public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogRegisterBoatEvent event) {
DBObject result = createBasicRegattaLogEventDBObject(event);
result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogRegisterBoatEvent.class.getSimpleName());
result.put(FieldNames.REGATTA_LOG_BOAT_ID.name(), event.getBoat().getId());
storeRegattaLogEvent(regattaLikeId, result);
}
public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId, RegattaLogRegisterCompetitorEvent event) {
DBObject result = createBasicRegattaLogEventDBObject(event);
result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogRegisterCompetitorEvent.class.getSimpleName());
@@ -5,9 +5,12 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterBoatEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent;
@@ -43,15 +46,31 @@ public class MongoRegattaLogStoreVisitor implements RegattaLogEventVisitor {
mongoObjectFactory.storeRegattaLogEvent(regattaLikeIdentifier, event);
}
@Override
public void visit(RegattaLogDeviceBoatMappingEvent event) {
mongoObjectFactory.storeRegattaLogEvent(regattaLikeIdentifier, event);
}
@Override
public void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
mongoObjectFactory.storeRegattaLogEvent(regattaLikeIdentifier, event);
}
@Override
public void visit(RegattaLogDeviceBoatSensorDataMappingEvent event) {
mongoObjectFactory.storeRegattaLogEvent(regattaLikeIdentifier, event);
}
@Override
public void visit(RegattaLogCloseOpenEndedDeviceMappingEvent event) {
mongoObjectFactory.storeRegattaLogEvent(regattaLikeIdentifier, event);
}
@Override
public void visit(RegattaLogRegisterBoatEvent event) {
mongoObjectFactory.storeRegattaLogEvent(regattaLikeIdentifier, event);
}
@Override
public void visit(RegattaLogRegisterCompetitorEvent event) {
mongoObjectFactory.storeRegattaLogEvent(regattaLikeIdentifier, event);
@@ -14,6 +14,7 @@ Require-Bundle: org.junit;bundle-version="4.8.2",
org.mongodb.mongo-java-driver;bundle-version="2.13.0",
com.sap.sse.common
Import-Package: com.sap.sailing.domain.abstractlog.regatta.events,
com.sap.sailing.domain.base,
com.sap.sailing.domain.persistence.impl,
com.sap.sailing.domain.persistence.racelog.tracking.impl,
com.sap.sailing.domain.tractracadapter,
@@ -17,6 +17,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMa
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
@@ -59,7 +60,9 @@ public class AbstractGPSFixStoreTest extends RaceLogTrackingTestHelper {
protected final DeviceIdentifier device = new SmartphoneImeiIdentifier("a");
protected RegattaLog regattaLog;
protected SensorFixStore store;
protected final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
protected final Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null, null);
protected final Boat boat = DomainFactory.INSTANCE.getOrCreateBoat("boat", "boat", boatClass, "GER 234", null);
protected final Mark mark = DomainFactory.INSTANCE.getOrCreateMark("mark");
protected GPSFixMoving createFix(long millis, double lat, double lng, double knots, double degrees) {
@@ -121,7 +124,7 @@ public class AbstractGPSFixStoreTest extends RaceLogTrackingTestHelper {
protected DynamicTrackedRaceImpl createDynamicTrackedRace(BoatClass boatClass, RaceDefinition raceDefinition) {
DynamicTrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
/* startDate */ null, /* endDate */null, null, null, "a", null));
/* canBoatsOfCompetitorsChangePerRace */ true, /* startDate */ null, /* endDate */null, null, null, "a", null));
return new DynamicTrackedRaceImpl(regatta, raceDefinition, Collections.<Sideline> emptyList(),
EmptyWindStore.INSTANCE, 0, 0, 0, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class));
@@ -28,12 +28,18 @@ import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogUseCompetito
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorWithBoat;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SeriesImpl;
@@ -67,7 +73,7 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
private RacingEventService service;
private final static BoatClass boatClass = new BoatClassImpl("505", /* typicallyStartsUpwind */ true);
private final Fleet fleet = new FleetImpl("fleet");
private final String columnName = "column";
private RegattaLeaderboard leaderboard;
@@ -89,7 +95,8 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
Series series = new SeriesImpl("series", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, Collections.singletonList(fleet), Collections.emptySet(),
service);
regatta = service.createRegatta(RegattaImpl.getDefaultName("regatta", "Laser"), "Laser",
/* startDate */null, /* endDate */null, UUID.randomUUID(), Collections.<Series> singletonList(series), /* persistent */ true,
/* canBoatsOfCompetitorsChangePerRace */ true, /* startDate */null, /* endDate */null,
UUID.randomUUID(), Collections.<Series> singletonList(series), /* persistent */ true,
new HighPoint(), UUID.randomUUID(), /*buoyZoneRadiusInHullLengths*/2.0, /* useStartTimeInference */true, /* controlTrackingFromStartAndFinishTimes */ false, OneDesignRankingMetric::new);
series.addRaceColumn(columnName, /* trackedRegattaRegistry */null);
leaderboard = service.addRegattaLeaderboard(regatta.getRegattaIdentifier(), "RegattaLeaderboard", new int[] {});
@@ -184,13 +191,14 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
assertFalse(raceLog.isEmpty());
// add a mapping and one fix in, one out of mapping
Competitor comp1 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp1", "comp1", null, null, null, null, null,
Boat boat1 = new BoatImpl("id12345", "boat1", boatClass, /* sailID */ null);
Competitor comp1 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp1", "comp1", "c", null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
DeviceIdentifier dev1 = new SmartphoneImeiIdentifier("dev1");
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(t(), t(), author, 0, comp1, dev1, t(0), t(10)));
addFixes0(dev1);
raceLog.add(new RaceLogUseCompetitorsFromRaceLogEventImpl(t(), author, t(), UUID.randomUUID(), 0));
raceLog.add(new RaceLogRegisterCompetitorEventImpl(t(), author, 0, comp1));
raceLog.add(new RaceLogRegisterCompetitorEventImpl(t(), author, 0, comp1, boat1));
raceLog.add(new RaceLogStartOfTrackingEventImpl(t(0), author, /* passId */ 0));
// start tracking
trackRace(column);
@@ -281,8 +289,9 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
adapter.denoteRaceForRaceLogTracking(service, leaderboard, column, fleet, "race");
// add a mapping and one fix in, one out of mapping
Competitor comp1 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp1", "comp1", null, null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Boat boat1 = new BoatImpl("id12345", "boat1", boatClass, /* sailID */ null);
CompetitorWithBoat comp1 = DomainFactory.INSTANCE.getOrCreateCompetitorWithBoat("comp1", "comp1", "c1", null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null, (DynamicBoat) boat1);
DeviceIdentifier dev1 = new SmartphoneImeiIdentifier("dev1");
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(t(), t(), author, UUID.randomUUID(), comp1, dev1,
t(0), t(10)));
@@ -6,6 +6,8 @@ import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
@@ -19,6 +21,7 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
@@ -66,11 +69,12 @@ public class RaceLogFixTrackerManagerTest {
protected RaceLog raceLog2;
protected RegattaLog regattaLog;
protected SensorFixStore store;
protected final Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", null, null, null,
null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null, null);
protected final Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", "c2", null, null, null,
null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null, null);
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
protected final Boat boat = DomainFactory.INSTANCE.getOrCreateBoat("boat", "boat", boatClass, "USA 123", null);
protected final Mark mark = DomainFactory.INSTANCE.getOrCreateMark("mark");
protected final Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
private DynamicTrackedRace trackedRace;
@@ -92,10 +96,12 @@ public class RaceLogFixTrackerManagerTest {
Course course = new CourseImpl("course",
Arrays.asList(new Waypoint[] { new WaypointImpl(mark), new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(comp));
Map<Competitor, Boat> competitorsAndBoats = new HashMap<>();
competitorsAndBoats.put(comp, boat);
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, competitorsAndBoats);
DynamicTrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
/* startDate */ null, /* endDate */null, null, null, "a", null));
/* canBoatsOfCompetitorsChangePerRace */ true, /* startDate */ null, /* endDate */null, null, null, "a", null));
trackedRace = new DynamicTrackedRaceImpl(regatta, race, Collections.<Sideline> emptyList(),
EmptyWindStore.INSTANCE, 0, 0, 0, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class));
@@ -12,8 +12,10 @@ import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CyclicBarrier;
@@ -42,6 +44,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMa
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorBravoMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRevokeEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
@@ -120,15 +123,17 @@ public class SensorFixStoreAndLoadTest {
protected RaceLog raceLog;
protected RegattaLog regattaLog;
protected SensorFixStore store;
protected final Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", null, null, null,
null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null, null);
protected final Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null,
null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null, null);
private final Competitor compNotPartOfRace = DomainFactory.INSTANCE.getOrCreateCompetitor("comp3", "comp3", null, null, null,
null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
protected final Competitor comp = DomainFactory.INSTANCE.getOrCreateCompetitor("comp", "comp", null, null, null, null,
null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null, null);
protected final Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null,
null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowanceInSecondsPerNauticalMile */ null, null);
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
protected final Boat boat1 = DomainFactory.INSTANCE.getOrCreateBoat("Boat1", "Boat1", boatClass, "GER 1", null);
protected final Boat boat2 = DomainFactory.INSTANCE.getOrCreateBoat("Boat2", "Boat2", boatClass, "GER 2", null);
private final Competitor compNotPartOfRace = DomainFactory.INSTANCE.getOrCreateCompetitor("comp3", "comp3", null, null, null, null,
null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
protected final Mark mark = DomainFactory.INSTANCE.getOrCreateMark("mark");
protected final Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
protected final AbstractLogEventAuthor author = new LogEventAuthorImpl("author", 0);
private DynamicTrackedRace trackedRace;
@@ -156,10 +161,13 @@ public class SensorFixStoreAndLoadTest {
new MillisecondsTimePoint(1), 0, mark2));
Course course = new CourseImpl("course",
Arrays.asList(new Waypoint[] { new WaypointImpl(mark), new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(comp, comp2));
Map<Competitor, Boat> competitorsAndBoats = new HashMap<>();
competitorsAndBoats.put(comp, boat1);
competitorsAndBoats.put(comp2, boat2);
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, competitorsAndBoats);
DynamicTrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
/* startDate */ null, /* endDate */null, null, null, "a", null));
/* canBoatsOfCompetitorsChangePerRace */ true, /* startDate */ null, /* endDate */null, null, null, "a", null));
trackedRace = new DynamicTrackedRaceImpl(regatta, race, Collections.<Sideline> emptyList(),
EmptyWindStore.INSTANCE, 0, 0, 0, /* useMarkPassingCalculator */ false, OneDesignRankingMetric::new,
mock(RaceLogResolver.class));
@@ -412,7 +420,7 @@ public class SensorFixStoreAndLoadTest {
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP2, FIX_RIDE_HEIGHT2.getMeters()));
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP3, FIX_RIDE_HEIGHT3.getMeters()));
}
private void addMoreBravoFixes() {
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP + 1, FIX_RIDE_HEIGHT.getMeters()));
store.storeFix(device, createBravoDoubleVectorFixWithRideHeight(FIX_TIMESTAMP2 + 1, FIX_RIDE_HEIGHT2.getMeters()));
@@ -428,10 +436,10 @@ public class SensorFixStoreAndLoadTest {
@Override
public <FixT extends Timed, TrackT extends DynamicTrack<FixT>> SensorFixMapper<FixT, TrackT, Competitor> createCompetitorMapper(
Class<? extends RegattaLogDeviceMappingEvent<?>> eventType) {
if (bravoDataFixMapper.isResponsibleFor(eventType)) {
if(bravoDataFixMapper.isResponsibleFor(eventType)) {
return (SensorFixMapper) bravoDataFixMapper;
}
if (testDataFixMapper.isResponsibleFor(eventType)) {
if(testDataFixMapper.isResponsibleFor(eventType)) {
return (SensorFixMapper) testDataFixMapper;
}
throw new IllegalArgumentException("Unknown event type");
@@ -442,7 +450,7 @@ public class SensorFixStoreAndLoadTest {
protected void testNumberOfRawFixes(Track<?> track, long expected) {
if (expected == 0) {
if (track != null) {
track.lockForRead();
track.lockForRead();
try {
assertTrue(size(track.getRawFixes()) == 0);
} finally {
@@ -452,10 +460,10 @@ public class SensorFixStoreAndLoadTest {
} else {
track.lockForRead();
try {
assertEquals(expected, size(track.getRawFixes()));
assertEquals(expected, size(track.getRawFixes()));
} finally {
track.unlockAfterRead();
}
track.unlockAfterRead();
}
}
}
@@ -563,6 +571,7 @@ public class SensorFixStoreAndLoadTest {
implements RegattaLogDeviceCompetitorSensorDataMappingEvent {
private static final long serialVersionUID = -14940305448048753L;
public RegattaLogDeviceCompetitorTestMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Competitor mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
@@ -618,7 +627,7 @@ public class SensorFixStoreAndLoadTest {
assertNull(trackedRace.getSensorTrack(compNotPartOfRace, BravoFixTrack.TRACK_NAME));
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
/** Test for changes of bug 4044 - https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4044 */
public void testThatNoSensorFixesAreLoadedAsLongAsStartOfTrackingIsNull() throws InterruptedException {
@@ -637,7 +646,7 @@ public class SensorFixStoreAndLoadTest {
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 3);
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
/** Test for changes of bug 4044 - https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4044 */
public void testThatNoSensorFixesAreRecordedAsWhenStartOfTrackingIsNull() throws InterruptedException {
@@ -794,7 +803,7 @@ public class SensorFixStoreAndLoadTest {
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
statusTransitionListener.assertTransitions(TrackedRaceStatusEnum.PREPARED, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.LOADING, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.FINISHED);
}
@Test
/** Test for bug 4125 - https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4125 */
public void testThatLoadingStateIsTriggeredWhenAddingMapping() throws InterruptedException {
@@ -810,7 +819,7 @@ public class SensorFixStoreAndLoadTest {
fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
statusTransitionListener.assertTransitions(TrackedRaceStatusEnum.PREPARED, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.LOADING, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.FINISHED);
}
@Test
/** Test for bug 4125 - https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4125 */
public void testThatLoadingStateIsTriggeredWhenStartOfTrackingIsSet() throws InterruptedException {
@@ -2,19 +2,24 @@ package com.sap.sailing.domain.racelogtracking.test.impl;
import static junit.framework.Assert.assertEquals;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import com.mongodb.MongoException;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogEndOfTrackingEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartOfTrackingEventImpl;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
@@ -42,22 +47,34 @@ import com.sap.sse.common.impl.TimeRangeImpl;
public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
private static final Logger logger = Logger.getLogger(TrackedRaceLoadsFixesTest.class.getName());
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
private final BoatClass boatClass = DomainFactory.INSTANCE.getOrCreateBoatClass("49er");
private final Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
private final Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null,
null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
private final Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", "c2", null, null, null,
null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
private final Boat boat2 = DomainFactory.INSTANCE.getOrCreateBoat("boat2", "boat2", boatClass, "USA 123", null);
private final Course course = new CourseImpl("course", Arrays.asList(new WaypointImpl(mark), new WaypointImpl(mark2)));
private final RaceDefinition raceDefinition = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(comp, comp2));
private RaceDefinition raceDefinition;
@Before
public void setUp() throws UnknownHostException, MongoException {
Map<Competitor, Boat> competitorsAndBoats = new HashMap<>();
competitorsAndBoats.put(comp, boat);
competitorsAndBoats.put(comp2, boat2);
this.raceDefinition = new RaceDefinitionImpl("race", course, boatClass, competitorsAndBoats);
}
@Rule
public Timeout TrackedRaceLoadsFixesTestTimeout = new Timeout(3 * 60 * 1000);
@Test
public void doesRaceLoadOnlyBetweenStartAndEndOfTracking() throws TransformationException,
NoCorrespondingServiceRegisteredException, InterruptedException {
DeviceIdentifier markDevice = new SmartphoneImeiIdentifier("imei2");
defineMarksOnRegattaLog(mark, mark2);
map(comp, device, 0, 10000);
map(mark, markDevice, 0, 10000);
@@ -8,6 +8,8 @@ import static org.mockito.Mockito.mock;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.junit.Test;
@@ -18,6 +20,7 @@ import com.sap.sailing.domain.abstractlog.race.impl.RaceLogRaceStatusEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartOfTrackingEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMarkEventImpl;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Course;
@@ -59,18 +62,22 @@ public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
@Test
public void testStartTimeInferencePrecedenceOrder() throws TransformationException,
NoCorrespondingServiceRegisteredException, InterruptedException {
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", "c2", null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Boat boat2 = DomainFactory.INSTANCE.getOrCreateBoat("boat2", "boat2", boatClass, "USA 123", null);
Map<Competitor, Boat> competitorsAndBoats = new HashMap<>();
competitorsAndBoats.put(comp, boat);
competitorsAndBoats.put(comp2, boat2);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, competitorsAndBoats);
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null));
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
/* canBoatsOfCompetitorsChangePerRace */ true, /* startDate */ null, /* endDate */null, null, null, "a", null));
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
/* useMarkPassingCalculator */ false,
@@ -132,17 +139,21 @@ public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
@Test
public void testStartTimeChangeNotificationForFirstUpdateThroughRaceLog() throws TransformationException,
NoCorrespondingServiceRegisteredException, InterruptedException {
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", "c2", null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Boat boat2 = DomainFactory.INSTANCE.getOrCreateBoat("boat2", "boat2", boatClass, "USA 123", null);
Map<Competitor, Boat> competitorsAndBoats = new HashMap<>();
competitorsAndBoats.put(comp, boat);
competitorsAndBoats.put(comp2, boat2);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, competitorsAndBoats);
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null));
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
/* canBoatsOfCompetitorsChangePerRace */ true, /* startDate */ null, /* endDate */null, null, null, "a", null));
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
/* useMarkPassingCalculator */ false,
@@ -170,17 +181,21 @@ public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
@Test
public void testStartTimeChangeNotificationForFirstUpdateThroughStartMarkPassing() throws TransformationException,
NoCorrespondingServiceRegisteredException, InterruptedException {
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", "c2", null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Boat boat2 = DomainFactory.INSTANCE.getOrCreateBoat("boat2", "boat2", boatClass, "USA 123", null);
Map<Competitor, Boat> competitorsAndBoats = new HashMap<>();
competitorsAndBoats.put(comp, boat);
competitorsAndBoats.put(comp2, boat2);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, competitorsAndBoats);
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null));
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
/* canBoatsOfCompetitorsChangePerRace */ true, /* startDate */ null, /* endDate */null, null, null, "a", null));
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
/* useMarkPassingCalculator */ false,
@@ -211,17 +226,21 @@ public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
@Test
public void testStartAndEndTrackingTimeInferencePrecedenceOrderTriggersListener() throws TransformationException,
NoCorrespondingServiceRegisteredException, InterruptedException {
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", "c2", null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Boat boat2 = DomainFactory.INSTANCE.getOrCreateBoat("boat2", "boat2", boatClass, "USA 123", null);
Map<Competitor, Boat> competitorsAndBoats = new HashMap<>();
competitorsAndBoats.put(comp, boat);
competitorsAndBoats.put(comp2, boat2);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, competitorsAndBoats);
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null));
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
/* canBoatsOfCompetitorsChangePerRace */ true, /* startDate */ null, /* endDate */null, null, null, "a", null));
assertTrue(regatta.getRegatta().useStartTimeInference());
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
@@ -321,17 +340,21 @@ public class TrackedRaceStartTimeInferenceTest extends AbstractGPSFixStoreTest {
@Test
public void testStartAndEndOfTrackingTimeChangeNotificationForFirstUpdateThroughRaceLog() throws TransformationException,
NoCorrespondingServiceRegisteredException, InterruptedException {
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", null, null, null, null, null,
Competitor comp2 = DomainFactory.INSTANCE.getOrCreateCompetitor("comp2", "comp2", "c2", null, null, null, null,
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
Boat boat2 = DomainFactory.INSTANCE.getOrCreateBoat("boat2", "boat2", boatClass, "USA 123", null);
Map<Competitor, Boat> competitorsAndBoats = new HashMap<>();
competitorsAndBoats.put(comp, boat);
competitorsAndBoats.put(comp2, boat2);
Mark mark2 = DomainFactory.INSTANCE.getOrCreateMark("mark2");
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(1), author, new MillisecondsTimePoint(1), 0, mark));
regattaLog.add(new RegattaLogDefineMarkEventImpl(new MillisecondsTimePoint(2), author, new MillisecondsTimePoint(1), 0, mark2));
Course course = new CourseImpl("course", Arrays.asList(new Waypoint[] { new WaypointImpl(mark),
new WaypointImpl(mark2) }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, Arrays.asList(new Competitor[] { comp, comp2 }));
RaceDefinition race = new RaceDefinitionImpl("race", course, boatClass, competitorsAndBoats);
TrackedRegatta regatta = new DynamicTrackedRegattaImpl(new RegattaImpl(EmptyRaceLogStore.INSTANCE,
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass, /* startDate */
null, /* endDate */null, null, null, "a", null));
EmptyRegattaLogStore.INSTANCE, RegattaImpl.getDefaultName("regatta", boatClass.getName()), boatClass,
/* canBoatsOfCompetitorsChangePerRace */ true, /* startDate */null, /* endDate */null, null, null, "a", null));
final DynamicTrackedRaceImpl trackedRace = new DynamicTrackedRaceImpl(regatta, race,
Collections.<Sideline> emptyList(), EmptyWindStore.INSTANCE, 0, 0, 0,
/* useMarkPassingCalculator */ false,
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.racelogtracking.impl;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceBoatBravoMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorBravoMappingEventImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.tracking.BravoFix;
@@ -31,6 +32,7 @@ public class BravoDataFixMapper implements SensorFixMapper<BravoFix, DynamicSens
@Override
public boolean isResponsibleFor(Class<? extends RegattaLogDeviceMappingEvent<?>> eventType) {
return RegattaLogDeviceCompetitorBravoMappingEventImpl.class.isAssignableFrom(eventType);
return RegattaLogDeviceCompetitorBravoMappingEventImpl.class.isAssignableFrom(eventType)
|| RegattaLogDeviceBoatBravoMappingEventImpl.class.isAssignableFrom(eventType);
}
}
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.racelogtracking.impl;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceBoatBravoExtendedMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.tracking.BravoExtendedFix;
@@ -32,6 +33,7 @@ public class BravoExtendedDataFixMapper implements SensorFixMapper<BravoFix, Dyn
@Override
public boolean isResponsibleFor(Class<? extends RegattaLogDeviceMappingEvent<?>> eventType) {
return RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl.class.isAssignableFrom(eventType);
return RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl.class.isAssignableFrom(eventType)
|| RegattaLogDeviceBoatBravoExtendedMappingEventImpl.class.isAssignableFrom(eventType);
}
}
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.racelogtracking.impl;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceBoatExpeditionExtendedMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.tracking.BravoExtendedFix;
@@ -36,6 +37,7 @@ public class ExpeditionExtendedDataFixMapper implements SensorFixMapper<BravoFix
@Override
public boolean isResponsibleFor(Class<? extends RegattaLogDeviceMappingEvent<?>> eventType) {
return RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl.class.isAssignableFrom(eventType);
return RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl.class.isAssignableFrom(eventType)
|| RegattaLogDeviceBoatExpeditionExtendedMappingEventImpl.class.isAssignableFrom(eventType);
}
}
@@ -19,6 +19,7 @@ import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.common.racelog.tracking.DoesNotHaveRegattaLogException;
import com.sap.sailing.domain.common.racelog.tracking.RaceNotCreatedException;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroupResolver;
import com.sap.sailing.domain.regattalike.HasRegattaLike;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.RaceTracker;
@@ -64,13 +65,13 @@ public class RaceLogConnectivityParams extends AbstractRaceTrackingConnectivityP
@Override
public RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
RaceLogResolver raceLogResolver, long timeoutInMilliseconds) {
return createRaceTracker(regatta, trackedRegattaRegistry, windStore, raceLogResolver, timeoutInMilliseconds);
RaceLogResolver raceLogResolver, LeaderboardGroupResolver leaderboardGroupResolver, long timeoutInMilliseconds) {
return createRaceTracker(regatta, trackedRegattaRegistry, windStore, raceLogResolver, leaderboardGroupResolver, timeoutInMilliseconds);
}
@Override
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
WindStore windStore, RaceLogResolver raceLogResolver, long timeoutInMilliseconds) {
WindStore windStore, RaceLogResolver raceLogResolver, LeaderboardGroupResolver leaderboardGroupResolver, long timeoutInMilliseconds) {
if (regatta == null) {
BoatClass boatClass = new RaceInformationFinder(getRaceLog()).analyze().getBoatClass();
regatta = service.getOrCreateDefaultRegatta(
@@ -36,6 +36,7 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.impl.BaseRegattaLogEventVisitor;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
@@ -296,9 +297,9 @@ public class RaceLogRaceTracker extends AbstractRaceTrackerBaseImpl {
}
throw new RaceNotCreatedException(String.format("Race for racelog (%s) has already been created", raceLog));
}
Iterable<Competitor> competitors = raceColumn.getAllCompetitors(params.getFleet());
Map<Competitor, Boat> competitorsAndTheirBoats = raceColumn.getAllCompetitorsAndTheirBoats(params.getFleet());
Serializable raceId = denoteEvent.getRaceId();
final RaceDefinition raceDef = new RaceDefinitionImpl(raceName, course, boatClass, competitors, raceId);
final RaceDefinition raceDef = new RaceDefinitionImpl(raceName, course, boatClass, competitorsAndTheirBoats, raceId);
Iterable<Sideline> sidelines = Collections.<Sideline> emptyList();
// set race definition, so race is linked to leaderboard automatically
trackedRegatta.getRegatta().addRace(raceDef);
@@ -4,6 +4,7 @@ import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
@@ -27,6 +28,7 @@ import com.sap.sailing.domain.abstractlog.race.tracking.impl.RaceLogStartTrackin
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CourseBase;
@@ -138,13 +140,13 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
RegattaLeaderboard rLeaderboard = (RegattaLeaderboard) leaderboard;
boatClass = rLeaderboard.getRegatta().getBoatClass();
} else {
if (!Util.isEmpty(raceColumn.getAllCompetitors(fleet))) {
boatClass = findDominatingBoatClass(raceColumn.getAllCompetitors(fleet));
} else if (!Util.isEmpty(raceColumn.getAllCompetitors())) {
boatClass = findDominatingBoatClass(raceColumn.getAllCompetitors());
if (!Util.isEmpty(raceColumn.getAllCompetitorsAndTheirBoats(fleet).values())) {
boatClass = findDominatingBoatClass(raceColumn.getAllCompetitorsAndTheirBoats(fleet).values());
} else if (!Util.isEmpty(raceColumn.getAllCompetitorsAndTheirBoats().values())) {
boatClass = findDominatingBoatClass(raceColumn.getAllCompetitorsAndTheirBoats().values());
} else if (!Util.isEmpty(leaderboard.getAllCompetitors())) {
boatClass = findDominatingBoatClass(leaderboard.getAllCompetitors());
} else {
boatClass = leaderboard.getBoatClass();
} else {
throw new NotDenotableForRaceLogTrackingException("Couldn't infer boat class, no competitors on race and leaderboard");
}
}
@@ -167,8 +169,8 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
return result;
}
private BoatClass findDominatingBoatClass(Iterable<Competitor> allCompetitors) {
return Util.getDominantObject(()->StreamSupport.stream(allCompetitors.spliterator(), /* parallel */ false).map(c->c.getBoat().getBoatClass()).iterator());
private BoatClass findDominatingBoatClass(Iterable<Boat> allBoats) {
return Util.getDominantObject(()->StreamSupport.stream(allBoats.spliterator(), /* parallel */ false).map(b->b.getBoatClass()).iterator());
}
@Override
@@ -228,16 +230,16 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter {
@Override
public void copyCompetitors(final RaceColumn fromRaceColumn, final Fleet fromFleet, final Iterable<Pair<RaceColumn, Fleet>> toRaces) {
Iterable<Competitor> competitorsToCopy = fromRaceColumn.getAllCompetitors(fromFleet);
Map<Competitor, Boat> competitorsAndBoatsToCopy = fromRaceColumn.getAllCompetitorsAndTheirBoats(fromFleet);
for (Pair<RaceColumn, Fleet> toRace : toRaces) {
final RaceColumn toRaceColumn = toRace.getA();
final Fleet toFleet = toRace.getB();
try {
if (toRaceColumn.isCompetitorRegistrationInRacelogEnabled(toFleet)) {
toRaceColumn.registerCompetitors(competitorsToCopy, toFleet);
toRaceColumn.registerCompetitors(competitorsAndBoatsToCopy, toFleet);
} else {
toRaceColumn.enableCompetitorRegistrationOnRaceLog(toFleet);
toRaceColumn.registerCompetitors(competitorsToCopy, toFleet);
toRaceColumn.registerCompetitors(competitorsAndBoatsToCopy, toFleet);
}
} catch (CompetitorRegistrationOnRaceLogDisabledException e1) {
// cannot happen as we explicitly checked successfully before, or enabled it when the check failed; still produce a log documenting this strangeness:
@@ -16,10 +16,13 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.regatta.MappingEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Regatta;
@@ -170,102 +173,139 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
public void fixReceived(DeviceIdentifier device, Timed fix) {
if (!preemptiveStopRequested.get() && trackedRace.getStartOfTracking() != null) {
final TimePoint timePoint = fix.getTimePoint();
deviceMappings.forEachMappingOfDeviceIncludingTimePoint(device, fix.getTimePoint(), (mapping) -> {
mapping.getRegattaLogEvent().accept(new MappingEventVisitor() {
@Override
public void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
if (preemptiveStopRequested.get()) {
return;
deviceMappings.forEachMappingOfDeviceIncludingTimePoint(device, fix.getTimePoint(), new Consumer<DeviceMappingWithRegattaLogEvent<WithID>>() {
@Override
public void accept(DeviceMappingWithRegattaLogEvent<WithID> mapping) {
mapping.getRegattaLogEvent().accept(new MappingEventVisitor() {
@Override
public void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
recordSensorFixForCompetitor(event.getMappedTo(), event);
}
SensorFixMapper<SensorFix, DynamicSensorFixTrack<Competitor, SensorFix>, Competitor> mapper = sensorFixMapperFactory
.createCompetitorMapper(event.getClass());
DynamicSensorFixTrack<Competitor, SensorFix> track = mapper.getTrack(trackedRace,
event.getMappedTo());
if (track != null && trackedRace.isWithinStartAndEndOfTracking(fix.getTimePoint())) {
mapper.addFix(track, (DoubleVectorFix) fix);
@Override
public void visit(RegattaLogDeviceBoatSensorDataMappingEvent event) {
final Boat boat = event.getMappedTo();
final Competitor competitor = trackedRace.getCompetitorOfBoat(boat);
if (competitor != null) {
recordSensorFixForCompetitor(competitor, event);
} else {
logger.log(Level.WARNING,
"Could not record fix for boat because no competitor could be determined. Boat: "
+ boat);
}
}
}
@Override
public void visit(RegattaLogDeviceCompetitorMappingEvent event) {
if (preemptiveStopRequested.get()) {
return;
private void recordSensorFixForCompetitor(Competitor competitor, RegattaLogDeviceMappingEvent<?> event) {
if (preemptiveStopRequested.get()) {
return;
}
@SuppressWarnings("unchecked")
SensorFixMapper<SensorFix, DynamicSensorFixTrack<Competitor, SensorFix>, Competitor> mapper = sensorFixMapperFactory
.createCompetitorMapper((Class<? extends RegattaLogDeviceMappingEvent<?>>) event.getClass());
DynamicSensorFixTrack<Competitor, SensorFix> track = mapper.getTrack(trackedRace,
competitor);
if (track != null && trackedRace.isWithinStartAndEndOfTracking(fix.getTimePoint())) {
mapper.addFix(track, (DoubleVectorFix) fix);
}
}
Competitor comp = event.getMappedTo();
if (fix instanceof GPSFixMoving) {
trackedRace.recordFix(comp, (GPSFixMoving) fix);
} else {
logger.log(Level.WARNING,
String.format(
"Could not add fix for competitor (%s) in race (%s), as it"
+ " is no GPSFixMoving, meaning it is missing COG/SOG values",
comp, trackedRace.getRace().getName()));
@Override
public void visit(RegattaLogDeviceCompetitorMappingEvent event) {
recordForCompetitor(event.getMappedTo());
}
}
@Override
public void visit(RegattaLogDeviceMarkMappingEvent event) {
if (preemptiveStopRequested.get()) {
return;
@Override
public void visit(RegattaLogDeviceBoatMappingEvent event) {
final Boat boat = event.getMappedTo();
final Competitor comp = trackedRace.getCompetitorOfBoat(boat);
if (comp != null) {
recordForCompetitor(comp);
} else {
logger.log(Level.WARNING,
"Could not record fix for boat because no competitor could be determined. Boat: "
+ boat);
}
}
Mark mark = event.getMappedTo();
final DynamicGPSFixTrack<Mark, GPSFix> markTrack = trackedRace.getOrCreateTrack(mark);
final GPSFix firstFixAtOrAfter;
final boolean forceFix;
if (trackedRace.isWithinStartAndEndOfTracking(fix.getTimePoint())) {
forceFix = false;
} else {
markTrack.lockForRead();
try {
if (Util.isEmpty(markTrack.getRawFixes())
|| (firstFixAtOrAfter = markTrack.getFirstFixAtOrAfter(timePoint)) != null
&& firstFixAtOrAfter.getTimePoint().equals(timePoint)) {
// either the first fix or overwriting an existing one
forceFix = true;
} else {
// checking if the given fix is "better" than an existing one
TimePoint startOfTracking = trackedRace.getStartOfTracking();
TimePoint endOfTracking = trackedRace.getStartOfTracking();
if (startOfTracking != null) {
GPSFix fixAfterStartOfTracking = markTrack
.getFirstFixAtOrAfter(startOfTracking);
if (fixAfterStartOfTracking == null
|| !trackedRace.isWithinStartAndEndOfTracking(
fixAfterStartOfTracking.getTimePoint())) {
// There is no fix in the tracking interval, so this fix could be "better"
// than ones already available in the track
// Better means closer before/after the beginning/end of the tracking
// interval
if (timePoint.before(startOfTracking)) {
// check if it is closer to the beginning of the tracking interval
GPSFix fixBeforeStartOfTracking = markTrack
.getLastFixAtOrBefore(startOfTracking);
forceFix = (fixBeforeStartOfTracking == null
|| fixBeforeStartOfTracking.getTimePoint().before(timePoint));
} else if (endOfTracking != null && timePoint.after(endOfTracking)) {
// check if it is closer to the end of the tracking interval
GPSFix fixAfterEndOfTracking = markTrack
.getFirstFixAtOrAfter(endOfTracking);
forceFix = (fixAfterEndOfTracking == null
|| fixAfterEndOfTracking.getTimePoint().after(timePoint));
public void recordForCompetitor(Competitor comp) {
if (preemptiveStopRequested.get()) {
return;
}
if (fix instanceof GPSFixMoving) {
trackedRace.recordFix(comp, (GPSFixMoving) fix);
} else {
logger.log(Level.WARNING,
String.format(
"Could not add fix for competitor (%s) in race (%s), as it"
+ " is no GPSFixMoving, meaning it is missing COG/SOG values",
comp, trackedRace.getRace().getName()));
}
}
@Override
public void visit(RegattaLogDeviceMarkMappingEvent event) {
if (preemptiveStopRequested.get()) {
return;
}
Mark mark = event.getMappedTo();
final DynamicGPSFixTrack<Mark, GPSFix> markTrack = trackedRace.getOrCreateTrack(mark);
final GPSFix firstFixAtOrAfter;
final boolean forceFix;
if (trackedRace.isWithinStartAndEndOfTracking(fix.getTimePoint())) {
forceFix = false;
} else {
markTrack.lockForRead();
try {
if (Util.isEmpty(markTrack.getRawFixes())
|| (firstFixAtOrAfter = markTrack.getFirstFixAtOrAfter(timePoint)) != null
&& firstFixAtOrAfter.getTimePoint().equals(timePoint)) {
// either the first fix or overwriting an existing one
forceFix = true;
} else {
// checking if the given fix is "better" than an existing one
TimePoint startOfTracking = trackedRace.getStartOfTracking();
TimePoint endOfTracking = trackedRace.getStartOfTracking();
if (startOfTracking != null) {
GPSFix fixAfterStartOfTracking = markTrack
.getFirstFixAtOrAfter(startOfTracking);
if (fixAfterStartOfTracking == null
|| !trackedRace.isWithinStartAndEndOfTracking(
fixAfterStartOfTracking.getTimePoint())) {
// There is no fix in the tracking interval, so this fix could be "better"
// than ones already available in the track
// Better means closer before/after the beginning/end of the tracking
// interval
if (timePoint.before(startOfTracking)) {
// check if it is closer to the beginning of the tracking interval
GPSFix fixBeforeStartOfTracking = markTrack
.getLastFixAtOrBefore(startOfTracking);
forceFix = (fixBeforeStartOfTracking == null
|| fixBeforeStartOfTracking.getTimePoint().before(timePoint));
} else if (endOfTracking != null && timePoint.after(endOfTracking)) {
// check if it is closer to the end of the tracking interval
GPSFix fixAfterEndOfTracking = markTrack
.getFirstFixAtOrAfter(endOfTracking);
forceFix = (fixAfterEndOfTracking == null
|| fixAfterEndOfTracking.getTimePoint().after(timePoint));
} else {
forceFix = false;
}
} else {
// there is already a fix in the tracking interval
forceFix = false;
}
} else {
// there is already a fix in the tracking interval
forceFix = false;
}
} else {
forceFix = false;
}
} finally {
markTrack.unlockAfterRead();
}
} finally {
markTrack.unlockAfterRead();
}
trackedRace.recordFix(mark, (GPSFix) fix, /* only when in tracking interval */ !forceFix);
}
trackedRace.recordFix(mark, (GPSFix) fix, /* only when in tracking interval */ !forceFix);
}
});
});
}
});
}
}
@@ -378,9 +418,30 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
mappingEvent.accept(new MappingEventVisitor() {
@Override
public void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
final Competitor competitor = event.getMappedTo();
loadSensorFixesForCompetitor(timeRangeToLoad, progressConsumer, stopCallback, event, competitor);
}
@Override
public void visit(RegattaLogDeviceBoatSensorDataMappingEvent event) {
final Boat boat = event.getMappedTo();
final Competitor competitor = trackedRace.getCompetitorOfBoat(boat);
if (competitor != null) {
loadSensorFixesForCompetitor(timeRangeToLoad, progressConsumer, stopCallback, event, competitor);
} else {
logger.log(Level.WARNING,
"Could not load fixes for boat because no competitor could be determined. Boat: "
+ boat);
}
}
private void loadSensorFixesForCompetitor(TimeRange timeRangeToLoad, final Consumer<Double> progressConsumer,
final BooleanSupplier stopCallback, RegattaLogDeviceMappingEvent<?> event,
final Competitor competitor) {
@SuppressWarnings("unchecked")
SensorFixMapper<Timed, DynamicTrack<Timed>, Competitor> mapper = sensorFixMapperFactory
.createCompetitorMapper(event.getClass());
DynamicTrack<Timed> track = mapper.getTrack(trackedRace, event.getMappedTo());
.createCompetitorMapper((Class<? extends RegattaLogDeviceMappingEvent<?>>) event.getClass());
DynamicTrack<Timed> track = mapper.getTrack(trackedRace, competitor);
if (track != null) {
// for split-fleet racing, device mappings coming from the regatta log may not be relevant
// for the trackedRace because the competitors may not compete in it; in this case, the
@@ -398,7 +459,24 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
@Override
public void visit(RegattaLogDeviceCompetitorMappingEvent event) {
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(event.getMappedTo());
loadForCompetitor(event.getMappedTo(), event);
}
@Override
public void visit(RegattaLogDeviceBoatMappingEvent event) {
final Boat boat = event.getMappedTo();
final Competitor comp = trackedRace.getCompetitorOfBoat(boat);
if (comp != null) {
loadForCompetitor(comp, event);
} else {
logger.log(Level.WARNING,
"Could not load fixes for boat because no competitor could be determined. Boat: "
+ boat);
}
}
private void loadForCompetitor(Competitor competitor, RegattaLogDeviceMappingEvent<?> event) {
DynamicGPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
if (track != null) {
// for split-fleet racing, device mappings coming from the regatta log may not be relevant
// for the trackedRace because the competitors may not compete in it; in this case, the
@@ -408,7 +486,7 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
timeRangeToLoad.from(), timeRangeToLoad.to(), /* toIsInclusive */ false,
stopCallback, progressConsumer);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not load competitor track " + event.getMappedTo() + "; device "
logger.log(Level.WARNING, "Could not load competitor track " + competitor + "; device "
+ event.getDevice());
}
}
@@ -441,11 +519,21 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
throw new UnsupportedOperationException();
}
@Override
public void visit(RegattaLogDeviceBoatSensorDataMappingEvent event) {
throw new UnsupportedOperationException();
}
@Override
public void visit(RegattaLogDeviceCompetitorMappingEvent event) {
throw new UnsupportedOperationException();
}
@Override
public void visit(RegattaLogDeviceBoatMappingEvent event) {
throw new UnsupportedOperationException();
}
@Override
public void visit(RegattaLogDeviceMarkMappingEvent event) {
DynamicGPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(event.getMappedTo());
@@ -15,6 +15,8 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
@@ -70,7 +72,12 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> {
private final RegattaLogEventVisitor regattaLogEventVisitor = new BaseRegattaLogEventVisitor() {
@Override
public void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
logger.log(Level.FINE, "New mapping for: " + event.getMappedTo() + "; device: " + event.getDevice());
logger.log(Level.FINE, "New CompetitorSensorDataMapping for: " + event.getMappedTo() + "; device: " + event.getDevice());
updateMappings();
}
@Override
public void visit(RegattaLogDeviceBoatSensorDataMappingEvent event) {
logger.log(Level.FINE, "New BoatSensorDataMapping for: " + event.getMappedTo() + "; device: " + event.getDevice());
updateMappings();
}
@@ -87,6 +94,12 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> {
"New DeviceCompetitorMapping for: " + event.getMappedTo() + "; device: " + event.getDevice());
updateMappings();
}
public void visit(RegattaLogDeviceBoatMappingEvent event) {
logger.log(Level.FINE,
"New DeviceBoatMappingEvent for: " + event.getMappedTo() + "; device: " + event.getDevice());
updateMappings();
}
@Override
public void visit(RegattaLogCloseOpenEndedDeviceMappingEvent event) {
@@ -65,7 +65,7 @@ public class CurrentRaceFilterImplTest {
_505RaceRows.add(_505RaceRow);
_505Series.add(new SeriesWithRowsImpl("Default", /* isMedal */ false, /* isFleetsCanRunInParallel */ false, _505RaceRows));
final RaceGroup _505 = new RaceGroupImpl("505", /* displayName */ null,
new BoatClassImpl(BoatClassMasterdata._5O5.getDisplayName(), BoatClassMasterdata._5O5),
new BoatClassImpl(BoatClassMasterdata._5O5.getDisplayName(), BoatClassMasterdata._5O5), /* canBoatsOfCompetitorsChangePerRace */ false,
/* courseArea */ null, _505Series, /* regattaConfiguration */ null);
return _505;
}
@@ -75,7 +75,7 @@ public class CurrentRaceFilterImplTest {
final List<RaceRow> yesRaceRows = Arrays.asList(createRaceRow(1, 9, "R", "Yellow"), createRaceRow(1, 9, "R", "Blue"));
yesSeries.add(new SeriesWithRowsImpl("Default", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, yesRaceRows));
final RaceGroup yes = new RaceGroupImpl("YES", /* displayName */ null,
new BoatClassImpl(BoatClassMasterdata._470.getDisplayName(), BoatClassMasterdata._470),
new BoatClassImpl(BoatClassMasterdata._470.getDisplayName(), BoatClassMasterdata._470), /* canBoatsOfCompetitorsChangePerRace */ false,
/* courseArea */ null, yesSeries, /* regattaConfiguration */ null);
return yes;
}
@@ -89,7 +89,7 @@ public class CurrentRaceFilterImplTest {
final List<RaceRow> isafMedalRaceRows = Arrays.asList(createRaceRow(1, 1, "M", "Medal"));
isafSeries.add(new SeriesWithRowsImpl("Medal", /* isMedal */ true, /* isFleetsCanRunInParallel */ true, isafMedalRaceRows));
final RaceGroup isaf = new RaceGroupImpl("ISAF", /* displayName */ null,
new BoatClassImpl(BoatClassMasterdata._470.getDisplayName(), BoatClassMasterdata._470),
new BoatClassImpl(BoatClassMasterdata._470.getDisplayName(), BoatClassMasterdata._470), /* canBoatsOfCompetitorsChangePerRace */ false,
/* courseArea */ null, isafSeries, /* regattaConfiguration */ null);
return isaf;
}
@@ -109,7 +109,7 @@ public class CurrentRaceFilterImplTest {
final List<RaceRow> essDay4RaceRows = Arrays.asList(createRaceRow(16, 5, "R", "Default"));
essSeries.add(new SeriesWithRowsImpl("Day 4", /* isMedal */ false, /* isFleetsCanRunInParallel */ true, essDay4RaceRows));
final RaceGroup ess = new RaceGroupImpl("ESS", /* displayName */ null,
new BoatClassImpl(BoatClassMasterdata.EXTREME_40.getDisplayName(), BoatClassMasterdata.EXTREME_40),
new BoatClassImpl(BoatClassMasterdata.EXTREME_40.getDisplayName(), BoatClassMasterdata.EXTREME_40), /* canBoatsOfCompetitorsChangePerRace */ false,
/* courseArea */ null, essSeries, /* regattaConfiguration */ null);
return ess;
}
@@ -119,7 +119,7 @@ public class CurrentRaceFilterImplTest {
final List<RaceRow> leagueRaceRows = Arrays.asList(createRaceRow(1, 15, "F", "Red"), createRaceRow(1, 15, "F", "Green"), createRaceRow(1, 15, "F", "Blue"));
leagueSeries.add(new SeriesWithRowsImpl("Default", /* isMedal */ false, /* isFleetsCanRunInParallel */ false, leagueRaceRows));
final RaceGroup league = new RaceGroupImpl("League", /* displayName */ null,
new BoatClassImpl(BoatClassMasterdata.J70.getDisplayName(), BoatClassMasterdata.J70),
new BoatClassImpl(BoatClassMasterdata.J70.getDisplayName(), BoatClassMasterdata.J70), /* canBoatsOfCompetitorsChangePerRace */ false,
/* courseArea */ null, leagueSeries, /* regattaConfiguration */ null);
return league;
}
@@ -14,13 +14,21 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl;
import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorDeregistrator;
import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorsInLogAnalyzer;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
import com.sap.sailing.domain.base.CompetitorWithBoat;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.CompetitorWithBoatImpl;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class CompetitorDeregistrationTest extends AbstractRegattaLogTrackingTest {
private final Competitor competitor = new CompetitorImpl("comp", "Comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
private final Competitor competitor2 = new CompetitorImpl("comp2", "Comp2", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
private final static BoatClass boatClass = new BoatClassImpl("505", /* typicallyStartsUpwind */ true);
private final static DynamicBoat boat1 = new BoatImpl("id12345", "boat1", boatClass, /* sailID */ null);
private final static DynamicBoat boat2 = new BoatImpl("id12345", "boat1", boatClass, /* sailID */ null);
private final CompetitorWithBoat competitor = new CompetitorWithBoatImpl("comp", "Comp", "KYC", null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null, boat1);
private final CompetitorWithBoat competitor2 = new CompetitorWithBoatImpl("comp2", "Comp2", "KYC", null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null, boat2);
@Test
public void testCompetitorDeregistration() {
@@ -27,8 +27,8 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
import junit.framework.Assert;
public class DeviceMappingFinderTest extends AbstractRegattaLogTrackingTest {
private final Competitor competitor = new CompetitorImpl("comp", "Comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
private final Competitor competitor2 = new CompetitorImpl("comp2", "Comp2", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
private final Competitor competitor = new CompetitorImpl("comp", "Comp", "KYC", null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
private final Competitor competitor2 = new CompetitorImpl("comp2", "Comp2", "KYC", null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null);
private final DeviceIdentifier device = new SmartphoneImeiIdentifier("imei");
private int time = 0;
@@ -23,5 +23,5 @@ public interface RaceLogEventData extends Serializable {
* A {@link RaceLogEventData} might be associated with a list of competitors, which are somehow relevant for this
* kind of event. An example is a list of competitors who are marked for an individual recall.
*/
List<Competitor> getInvolvedBoats();
List<Competitor> getInvolvedCompetitors();
}
@@ -37,7 +37,7 @@ public interface RaceLogEventVisitor {
public void visit(RaceLogDenoteForTrackingEvent event);
public void visit(RaceLogStartTrackingEvent event);
public void visit(RaceLogRegisterCompetitorEvent event);
public void visit(RaceLogAdditionalScoringInformationEvent additionalScoringInformation);
@@ -23,11 +23,11 @@ public class MarkPassingDataFinder extends RaceLogAnalyzer<Set<Triple<Competitor
for (RaceLogEvent event : getLog().getUnrevokedEvents()) {
if (event instanceof RaceLogFixedMarkPassingEvent) {
RaceLogFixedMarkPassingEvent castedEvent = (RaceLogFixedMarkPassingEvent) event;
result.add(new Triple<Competitor, Integer, TimePoint>(castedEvent.getInvolvedBoats().get(0), castedEvent
result.add(new Triple<Competitor, Integer, TimePoint>(castedEvent.getInvolvedCompetitors().get(0), castedEvent
.getZeroBasedIndexOfPassedWaypoint(), castedEvent.getTimePointOfFixedPassing()));
} else if (event instanceof RaceLogSuppressedMarkPassingsEvent){
RaceLogSuppressedMarkPassingsEvent castedEvent = (RaceLogSuppressedMarkPassingsEvent) event;
result.add(new Triple<Competitor, Integer, TimePoint>(castedEvent.getInvolvedBoats().get(0), castedEvent.getZeroBasedIndexOfFirstSuppressedWaypoint(), null));
result.add(new Triple<Competitor, Integer, TimePoint>(castedEvent.getInvolvedCompetitors().get(0), castedEvent.getZeroBasedIndexOfFirstSuppressedWaypoint(), null));
}
}
return result;
@@ -0,0 +1,31 @@
package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
import java.util.Collections;
import java.util.Map;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl.RaceLogUsesOwnCompetitorsAnalyzer;
import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorsAndBoatsInLogAnalyzer;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
public class RaceLogRegisteredCompetitorsAndBoatsAnalyzer extends RaceLogAnalyzer<Map<Competitor, Boat>> {
public RaceLogRegisteredCompetitorsAndBoatsAnalyzer(RaceLog raceLog) {
super(raceLog);
}
@Override
protected Map<Competitor, Boat> performAnalysis() {
final Map<Competitor, Boat> result;
if (new RaceLogUsesOwnCompetitorsAnalyzer(getLog()).analyze()){
// get Events from RaceLog
result = new CompetitorsAndBoatsInLogAnalyzer<>(getLog()).analyze();
} else {
// as we're explicitly only trying to find those registrations in the RaceLog, we won't
// return anything from the regatta log.
result = Collections.emptyMap();
}
return result;
}
}
@@ -103,7 +103,7 @@ public abstract class AbstractRaceLogChangedVisitor implements RaceLogEventVisit
public void visit(RaceLogRegisterCompetitorEvent event) {
notifyListenerAboutEventAdded(event);
}
@Override
public void visit(RaceLogAdditionalScoringInformationEvent additionalScoringInformation) {
notifyListenerAboutEventAdded(additionalScoringInformation);
@@ -109,7 +109,7 @@ public abstract class BaseRaceLogEventVisitor implements RaceLogEventVisitor {
public void visit(RaceLogRegisterCompetitorEvent event) {
}
@Override
public void visit(RaceLogAdditionalScoringInformationEvent event) {
@@ -144,4 +144,5 @@ public abstract class BaseRaceLogEventVisitor implements RaceLogEventVisitor {
public void visit(RaceLogUseCompetitorsFromRaceLogEvent event) {
}
}
@@ -21,7 +21,7 @@ public class RaceLogEventDataImpl implements RaceLogEventData {
}
@Override
public List<Competitor> getInvolvedBoats() {
public List<Competitor> getInvolvedCompetitors() {
return involvedBoats;
}
@@ -32,6 +32,6 @@ public class RaceLogEventDataImpl implements RaceLogEventData {
@Override
public String toString() {
return super.toString() + ", involvedBoats: " + getInvolvedBoats() + ", passId: " + getPassId();
return super.toString() + ", involvedBoats: " + getInvolvedCompetitors() + ", passId: " + getPassId();
}
}
@@ -36,8 +36,8 @@ public abstract class RaceLogEventImpl extends AbstractLogEventImpl<RaceLogEvent
}
@Override
public List<Competitor> getInvolvedBoats() {
return raceLogEventData.getInvolvedBoats();
public List<Competitor> getInvolvedCompetitors() {
return raceLogEventData.getInvolvedCompetitors();
}
@Override
@@ -49,8 +49,8 @@ public class RaceLogFixedMarkPassingEventImpl extends RaceLogEventImpl implement
@Override
public String getShortInfo() {
return (getInvolvedBoats() == null || getInvolvedBoats().get(0) == null ? "Unknown" :
getInvolvedBoats().get(0).getName()) + " at mark " + getZeroBasedIndexOfPassedWaypoint() + " at "
return (getInvolvedCompetitors() == null || getInvolvedCompetitors().get(0) == null ? "Unknown" :
getInvolvedCompetitors().get(0).getName()) + " at mark " + getZeroBasedIndexOfPassedWaypoint() + " at "
+ getTimePointOfFixedPassing();
}
}
@@ -35,8 +35,8 @@ public class RaceLogRevokeEventImpl extends RevokeEventImpl<RaceLogEventVisitor>
}
@Override
public List<Competitor> getInvolvedBoats() {
return raceLogEventData.getInvolvedBoats();
public List<Competitor> getInvolvedCompetitors() {
return raceLogEventData.getInvolvedCompetitors();
}
@Override
@@ -42,6 +42,6 @@ public class RaceLogSuppressedMarkPassingsEventImpl extends RaceLogEventImpl imp
@Override
public String getShortInfo() {
return getInvolvedBoats().get(0).getName() + " at mark " + getZeroBasedIndexOfFirstSuppressedWaypoint();
return getInvolvedCompetitors().get(0).getName() + " at mark " + getZeroBasedIndexOfFirstSuppressedWaypoint();
}
}
@@ -3,8 +3,16 @@ package com.sap.sailing.domain.abstractlog.race.tracking;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.shared.events.RegisterCompetitorEvent;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorWithBoat;
public interface RaceLogRegisterCompetitorEvent extends RaceLogEvent,
RegisterCompetitorEvent<RaceLogEventVisitor> {
/**
* The event registers a {@link CompetitorWithBoat} or a pair of {@link Competitor} and {@link Boat} on a race.
* The competitor type is determined by the {@link Regatta} attribute 'canBoatsOfCompetitorsChangePerRace'
* If 'canBoatsOfCompetitorsChangePerRace' is true the type must be {@link Competitor}
* If 'canBoatsOfCompetitorsChangePerRace' is false the type must be {@link CompetitorWithBoat}
*/
public interface RaceLogRegisterCompetitorEvent extends RaceLogEvent, RegisterCompetitorEvent<RaceLogEventVisitor> {
Boat getBoat();
}
@@ -0,0 +1,44 @@
package com.sap.sailing.domain.abstractlog.race.tracking.analyzing.impl;
import java.util.Map;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorsAndBoatsInLogAnalyzer;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
/**
* Used to find competitors (including their boats) of a race based on {@link RaceLog} and {@link RegattaLog} contents. Checks whether the
* competitors for the given race are registered on the RaceLog via {@link RaceLogUsesOwnCompetitorsAnalyzer} or on the
* RegattaLog and fetches the competitors appropriately.
*
* Should not be used by clients directly. Instead, get the competitor set from the {@code RaceColumn}, using either one
* of {@code getAllCompetitorsAndTheirBoats()} and {@code getAllCompetitorsAndTheirBoats(Fleet)}. Those methods automatically check whether a
* tracked race is present, which takes precedence over the Race/RegattaLog.
*
* @author Jan Bross (D056848)
*
*/
public class RegisteredCompetitorsAndBoatsAnalyzer extends RaceLogAnalyzer<Map<Competitor, Boat>> {
private RegattaLog regattaLog;
public RegisteredCompetitorsAndBoatsAnalyzer(RaceLog raceLog, RegattaLog regattaLog) {
super(raceLog);
this.regattaLog = regattaLog;
}
@Override
protected Map<Competitor, Boat> performAnalysis() {
final Map<Competitor, Boat> result;
if (new RaceLogUsesOwnCompetitorsAnalyzer(getLog()).analyze()) {
// get Events from RaceLog
result = new CompetitorsAndBoatsInLogAnalyzer<>(getLog()).analyze();
} else {
// get Events from RegattaLog
result = new CompetitorsAndBoatsInLogAnalyzer<>(regattaLog).analyze();
}
return result;
}
}
@@ -10,43 +10,83 @@ import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogEventDataImpl;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.shared.events.impl.BaseRegisterCompetitorEventImpl;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorWithBoat;
import com.sap.sse.common.TimePoint;
/**
* Links a competitor to the boat it sails with in the race. The {@link #boat} field refers to the
* {@link CompetitorWithBoat#getBoat() competitor's boat} if the competitor has a fixed boat attached.
*
* @author Axel Uhl (d043530)
*
*/
public class RaceLogRegisterCompetitorEventImpl extends BaseRegisterCompetitorEventImpl<RaceLogEventVisitor> implements
RaceLogRegisterCompetitorEvent {
private static final long serialVersionUID = -5114645637316367845L;
private final RaceLogEventData raceLogEventData;
/**
* The boat the competitor sails with in the race to which the race log containing this event belongs.
* Never {@code null}.
*/
private final Boat boat;
/**
* @throws IllegalArgumentException
* if {@code competitor} is null
*/
public RaceLogRegisterCompetitorEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable id, int passId, Competitor competitor)
AbstractLogEventAuthor author, Serializable id, int passId, CompetitorWithBoat competitor)
throws IllegalArgumentException {
super(createdAt, logicalTimePoint, author, id, competitor);
this.raceLogEventData = new RaceLogEventDataImpl(null, passId);
checkBoat(competitor.getBoat());
this.boat = competitor.getBoat();
}
/**
* @throws IllegalArgumentException
* if {@code competitor} is null
* if {@code competitor} is null or if {@code boat} is null
*/
public RaceLogRegisterCompetitorEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable id, int passId, Competitor competitor, Boat boat)
throws IllegalArgumentException {
super(createdAt, logicalTimePoint, author, id, competitor);
this.raceLogEventData = new RaceLogEventDataImpl(null, passId);
checkBoat(boat);
this.boat = boat;
}
/**
* @throws IllegalArgumentException
* if {@code competitor} is null or if {@code competitor.getBoat()} is null
*/
public RaceLogRegisterCompetitorEventImpl(TimePoint logicalTimePoint,
AbstractLogEventAuthor author, int passId, Competitor competitor)
AbstractLogEventAuthor author, int passId, CompetitorWithBoat competitor)
throws IllegalArgumentException {
this(now(), logicalTimePoint, author, randId(), passId, competitor);
}
/**
* @throws IllegalArgumentException
* if {@code competitor} is null or if {@code boat} is null
*/
public RaceLogRegisterCompetitorEventImpl(TimePoint logicalTimePoint,
AbstractLogEventAuthor author, int passId, Competitor competitor, Boat boat)
throws IllegalArgumentException {
this(now(), logicalTimePoint, author, randId(), passId, competitor, boat);
}
@Override
public int getPassId() {
return raceLogEventData.getPassId();
}
@Override
public List<Competitor> getInvolvedBoats() {
return Collections.singletonList(getCompetitor());
public List<Competitor> getInvolvedCompetitors() {
return Collections.singletonList((Competitor) getCompetitor());
}
@Override
@@ -58,4 +98,20 @@ public class RaceLogRegisterCompetitorEventImpl extends BaseRegisterCompetitorEv
public void accept(RaceLogEventVisitor visitor) {
visitor.visit(this);
}
@Override
public Boat getBoat() {
return boat;
}
private static void checkBoat(Boat boat) throws IllegalArgumentException {
if (boat == null) {
throw new IllegalArgumentException("Boat must not be null");
}
}
@Override
public String getShortInfo() {
return "competitor: " + getCompetitor().toString() + " with boat " + getBoat().toString();
}
}
@@ -1,5 +1,7 @@
package com.sap.sailing.domain.abstractlog.regatta;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
@@ -13,7 +15,11 @@ public interface MappingEventVisitor {
void visit(RegattaLogDeviceMarkMappingEvent event);
void visit(RegattaLogDeviceCompetitorMappingEvent event);
void visit(RegattaLogDeviceBoatMappingEvent event);
void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event);
void visit(RegattaLogDeviceBoatSensorDataMappingEvent event);
}
@@ -2,9 +2,12 @@ package com.sap.sailing.domain.abstractlog.regatta;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterBoatEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent;
@@ -16,13 +19,19 @@ public interface RegattaLogEventVisitor {
void visit(RegattaLogDeviceMarkMappingEvent event);
void visit(RegattaLogDeviceCompetitorMappingEvent event);
void visit(RegattaLogDeviceBoatMappingEvent event);
void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event);
void visit(RegattaLogDeviceBoatSensorDataMappingEvent event);
void visit(RegattaLogCloseOpenEndedDeviceMappingEvent event);
void visit(RegattaLogRegisterBoatEvent event);
void visit(RegattaLogRegisterCompetitorEvent event);
void visit(RegattaLogSetCompetitorTimeOnTimeFactorEvent event);
void visit(RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent event);
@@ -0,0 +1,7 @@
package com.sap.sailing.domain.abstractlog.regatta.events;
import com.sap.sailing.domain.base.Boat;
public interface RegattaLogDeviceBoatMappingEvent extends RegattaLogDeviceMappingEvent<Boat> {
}
@@ -0,0 +1,7 @@
package com.sap.sailing.domain.abstractlog.regatta.events;
import com.sap.sailing.domain.base.Boat;
public interface RegattaLogDeviceBoatSensorDataMappingEvent extends RegattaLogDeviceMappingEvent<Boat> {
}
@@ -13,6 +13,12 @@ public abstract class RegattaLogDeviceMappingEventImpl<ItemType extends WithID>
RegattaLogDeviceMappingEvent<ItemType> {
private static final long serialVersionUID = -8439653251231710356L;
public interface Factory<ItemType extends WithID, T extends RegattaLogDeviceMappingEvent<ItemType>> {
T create(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, ItemType mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to);
}
private final ItemType mappedTo;
private final DeviceIdentifier device;
@@ -0,0 +1,12 @@
package com.sap.sailing.domain.abstractlog.regatta.events;
import com.sap.sailing.domain.abstractlog.Revokable;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.base.Boat;
/**
* The event registers a standalone {@link Boat} on a regatta.
*/
public interface RegattaLogRegisterBoatEvent extends RegattaLogEvent, Revokable {
Boat getBoat();
}
@@ -3,8 +3,16 @@ package com.sap.sailing.domain.abstractlog.regatta.events;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.shared.events.RegisterCompetitorEvent;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorWithBoat;
public interface RegattaLogRegisterCompetitorEvent extends RegattaLogEvent,
RegisterCompetitorEvent<RegattaLogEventVisitor> {
/**
* The event registers a {@link Competitor} or {@link CompetitorWithBoat} on a regatta.
* The competitor type is determined by the {@link Regatta} attribute 'canBoatsOfCompetitorsChangePerRace'
* If 'canBoatsOfCompetitorsChangePerRace' is true the type must be {@link Competitor}
* If 'canBoatsOfCompetitorsChangePerRace' is false the type must be {@link CompetitorWithBoat}
*/
public interface RegattaLogRegisterCompetitorEvent
extends RegattaLogEvent, RegisterCompetitorEvent<RegattaLogEventVisitor> {
}
@@ -0,0 +1,41 @@
package com.sap.sailing.domain.abstractlog.regatta.events.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.regatta.MappingEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
/**
* Base type for mapping event for devices mapped for specific Bravo type fixes.
*/
public abstract class AbstractRegattaLogDeviceBoatSensorDataMappingEventImpl extends RegattaLogDeviceMappingEventImpl<Boat>
implements RegattaLogDeviceBoatSensorDataMappingEvent {
private static final long serialVersionUID = -1494030544804758753L;
public AbstractRegattaLogDeviceBoatSensorDataMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Boat mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
super(createdAt, logicalTimePoint, author, pId, mappedTo, device, from, to);
}
public AbstractRegattaLogDeviceBoatSensorDataMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
Boat mappedTo, DeviceIdentifier device, TimePoint from, TimePoint to) {
super(logicalTimePoint, author, mappedTo, device, from, to);
}
@Override
public void accept(RegattaLogEventVisitor visitor) {
visitor.visit(this);
}
@Override
public void accept(MappingEventVisitor visitor) {
visitor.visit(this);
}
}
@@ -18,12 +18,6 @@ public abstract class AbstractRegattaLogDeviceCompetitorSensorDataMappingEventIm
implements RegattaLogDeviceCompetitorSensorDataMappingEvent {
private static final long serialVersionUID = -1494030544804758753L;
public interface Factory<T extends RegattaLogDeviceCompetitorSensorDataMappingEvent> {
T create(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Competitor mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to);
}
public AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Competitor mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
@@ -0,0 +1,27 @@
package com.sap.sailing.domain.abstractlog.regatta.events.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
/**
* Mapping event for devices mapped for Bravo extended type fixes.
*/
public class RegattaLogDeviceBoatBravoExtendedMappingEventImpl extends AbstractRegattaLogDeviceBoatSensorDataMappingEventImpl {
private static final long serialVersionUID = -1494030544804758753L;
public RegattaLogDeviceBoatBravoExtendedMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Boat mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
super(createdAt, logicalTimePoint, author, pId, mappedTo, device, from, to);
}
public RegattaLogDeviceBoatBravoExtendedMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
Boat mappedTo, DeviceIdentifier device, TimePoint from, TimePoint to) {
super(logicalTimePoint, author, mappedTo, device, from, to);
}
}
@@ -0,0 +1,26 @@
package com.sap.sailing.domain.abstractlog.regatta.events.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
/**
* Mapping event for devices mapped for Bravo type fixes.
*/
public class RegattaLogDeviceBoatBravoMappingEventImpl extends AbstractRegattaLogDeviceBoatSensorDataMappingEventImpl {
private static final long serialVersionUID = -1494030544804758753L;
public RegattaLogDeviceBoatBravoMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Boat mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
super(createdAt, logicalTimePoint, author, pId, mappedTo, device, from, to);
}
public RegattaLogDeviceBoatBravoMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
Boat mappedTo, DeviceIdentifier device, TimePoint from, TimePoint to) {
super(logicalTimePoint, author, mappedTo, device, from, to);
}
}
@@ -0,0 +1,28 @@
package com.sap.sailing.domain.abstractlog.regatta.events.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
/**
* Mapping event for devices mapped for "Expedition" extended type fixes, coming from the
* "Expedition" software that was originally used in the context of this solution only for
* handling wind data but now is also used to forward sensor data into competitor tracks.
*/
public class RegattaLogDeviceBoatExpeditionExtendedMappingEventImpl extends AbstractRegattaLogDeviceBoatSensorDataMappingEventImpl {
private static final long serialVersionUID = -7865925670153838864L;
public RegattaLogDeviceBoatExpeditionExtendedMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Boat mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
super(createdAt, logicalTimePoint, author, pId, mappedTo, device, from, to);
}
public RegattaLogDeviceBoatExpeditionExtendedMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
Boat mappedTo, DeviceIdentifier device, TimePoint from, TimePoint to) {
super(logicalTimePoint, author, mappedTo, device, from, to);
}
}
@@ -0,0 +1,38 @@
package com.sap.sailing.domain.abstractlog.regatta.events.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.regatta.MappingEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
public class RegattaLogDeviceBoatMappingEventImpl extends RegattaLogDeviceMappingEventImpl<Boat>
implements RegattaLogDeviceBoatMappingEvent {
public RegattaLogDeviceBoatMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Boat mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint toInclusive) {
super(createdAt, logicalTimePoint, author, pId, mappedTo, device, from, toInclusive);
}
public RegattaLogDeviceBoatMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
Boat mappedTo, DeviceIdentifier device, TimePoint from, TimePoint toInclusive) {
super(logicalTimePoint, author, mappedTo, device, from, toInclusive);
}
private static final long serialVersionUID = -1494030544804758753L;
@Override
public void accept(RegattaLogEventVisitor visitor) {
visitor.visit(this);
}
@Override
public void accept(MappingEventVisitor visitor) {
visitor.visit(this);
}
}
@@ -13,7 +13,6 @@ import com.sap.sse.common.TimePoint;
public class RegattaLogDeviceCompetitorBravoMappingEventImpl extends AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl {
private static final long serialVersionUID = -1494030544804758753L;
public RegattaLogDeviceCompetitorBravoMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable pId, Competitor mappedTo, DeviceIdentifier device,
TimePoint from, TimePoint to) {
@@ -0,0 +1,57 @@
package com.sap.sailing.domain.abstractlog.regatta.events.impl;
import java.io.Serializable;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.AbstractLogEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterBoatEvent;
import com.sap.sailing.domain.base.Boat;
import com.sap.sse.common.TimePoint;
public class RegattaLogRegisterBoatEventImpl extends AbstractLogEventImpl<RegattaLogEventVisitor>
implements RegattaLogRegisterBoatEvent {
private static final long serialVersionUID = -4531928509653259811L;
private final Boat boat;
/**
* @throws IllegalArgumentException
* if {@code boat} is null
*/
public RegattaLogRegisterBoatEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Serializable id, Boat boat) throws IllegalArgumentException {
super(createdAt, logicalTimePoint, author, id);
checkBoat(boat);
this.boat = boat;
}
/**
* @throws IllegalArgumentException
* if {@code boat} is null
*/
public RegattaLogRegisterBoatEventImpl(TimePoint logicalTimePoint,
AbstractLogEventAuthor author, Boat boat) throws IllegalArgumentException {
this(now(), logicalTimePoint, author, randId(), boat);
}
@Override
public void accept(RegattaLogEventVisitor visitor) {
visitor.visit(this);
}
private static void checkBoat(Boat boat) throws IllegalArgumentException {
if (boat == null) {
throw new IllegalArgumentException("Boat may not be null");
}
}
@Override
public Boat getBoat() {
return boat;
}
@Override
public String getShortInfo() {
return "boat: " + getBoat().toString();
}
}
@@ -7,8 +7,16 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.shared.events.impl.BaseRegisterCompetitorEventImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorWithBoat;
import com.sap.sse.common.TimePoint;
/**
* This event can be used for 2 kinds of competitor registrations.
* If 'canBoatsOfCompetitorsChangePerRace' is true for a regatta the event registers a standalone {@link Competitor} without a boat.
* If 'canBoatsOfCompetitorsChangePerRace' is false the event registers a {@link CompetitorWithBoat}.
* @author Frank Mittag
*
*/
public class RegattaLogRegisterCompetitorEventImpl extends BaseRegisterCompetitorEventImpl<RegattaLogEventVisitor>
implements RegattaLogRegisterCompetitorEvent {
private static final long serialVersionUID = -5114645637316367845L;
@@ -3,9 +3,12 @@ package com.sap.sailing.domain.abstractlog.regatta.impl;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterBoatEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent;
@@ -24,15 +27,27 @@ public class BaseRegattaLogEventVisitor implements RegattaLogEventVisitor {
@Override
public void visit(RegattaLogDeviceCompetitorMappingEvent event) {
}
@Override
public void visit(RegattaLogDeviceBoatMappingEvent event) {
}
@Override
public void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
}
@Override
public void visit(RegattaLogDeviceBoatSensorDataMappingEvent event) {
}
@Override
public void visit(RegattaLogCloseOpenEndedDeviceMappingEvent event) {
}
@Override
public void visit(RegattaLogRegisterBoatEvent event) {
}
@Override
public void visit(RegattaLogRegisterCompetitorEvent event) {
}
@@ -4,9 +4,12 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDefineMarkEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceBoatSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorSensorDataMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterBoatEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEvent;
@@ -29,12 +32,22 @@ public abstract class RegattaLogEventListener implements RegattaLogEventVisitor
public void visit(RegattaLogDeviceCompetitorMappingEvent event) {
eventAdded(event);
}
@Override
public void visit(RegattaLogDeviceBoatMappingEvent event) {
eventAdded(event);
}
@Override
public void visit(RegattaLogCloseOpenEndedDeviceMappingEvent event) {
eventAdded(event);
}
@Override
public void visit(RegattaLogRegisterBoatEvent event) {
eventAdded(event);
}
@Override
public void visit(RegattaLogRegisterCompetitorEvent event) {
eventAdded(event);
@@ -59,4 +72,9 @@ public abstract class RegattaLogEventListener implements RegattaLogEventVisitor
public void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
eventAdded(event);
}
@Override
public void visit(RegattaLogDeviceBoatSensorDataMappingEvent event) {
eventAdded(event);
}
}
@@ -0,0 +1,70 @@
package com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterBoatEvent;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
import com.sap.sse.common.Util;
/**
* Finds the boat registration events for a given set of {@link Boat boats} that must be
* {@link AbstractLog#revokeEvent(AbstractLogEventAuthor, AbstractLogEvent) revoked} in order to deregister the
* boats. Note that the de-registration cannot be performed during analysis because
* {@link BaseLogAnalyzer#analyze()} obtains a read lock on the log whereas
* {@link AbstractLog#revokeEvent(AbstractLogEventAuthor, AbstractLogEvent)} requires a write lock, and upgrading from a
* read to a write lock is not possible.<p>
*
* Clients must call {@link #deregister} with the result of {@link #analyze()} in order to actually perform the
* deregistration.
*
* @author Frank Mittag
*
*/
public class RegattaLogBoatDeregistrator<LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT>
extends BaseLogAnalyzer<LogT, EventT, VisitorT, Set<EventT>> {
private static final Logger logger = Logger.getLogger(RegattaLogBoatDeregistrator.class.getName());
protected final Iterable<Boat> boatsToDeregister;
private AbstractLogEventAuthor eventAuthor;
public RegattaLogBoatDeregistrator(LogT log, Iterable<Boat> boatsToDeregister, AbstractLogEventAuthor eventAuthor) {
super(log);
this.boatsToDeregister = boatsToDeregister;
this.eventAuthor = eventAuthor;
}
@Override
protected Set<EventT> performAnalysis() {
final Set<EventT> result = new HashSet<>();
final HashSet<Boat> boatSet = new HashSet<Boat>();
Util.addAll(boatsToDeregister, boatSet);
for (EventT event : log.getUnrevokedEventsDescending()) {
if (event instanceof RegattaLogRegisterBoatEvent) {
RegattaLogRegisterBoatEvent registerEvent = (RegattaLogRegisterBoatEvent) event;
if (boatSet.contains(registerEvent.getBoat())) {
result.add(event);
}
}
}
return result;
}
public void deregister(final Set<EventT> boatRegistrationEvents) {
for (final EventT event : boatRegistrationEvents) {
try {
log.revokeEvent(eventAuthor, event,
"unregistering boat because no longer selected for registration");
} catch (NotRevokableException e) {
logger.log(Level.WARNING, "could not unregister boat by adding RevokeEvent", e);
}
}
}
}
@@ -0,0 +1,36 @@
package com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl;
import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterBoatEvent;
import com.sap.sailing.domain.base.Boat;
/**
* This class searches for RegisterBoat events in the given log.
*
* Boats alone in a regatta log are not enough to be used in a real race.
* Instead a competitor and a boat together must be registered through a {@link RegisterCompetitorEvent} event.
*
*/
public class RegattaLogBoatsInLogAnalyzer<LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT>
extends BaseLogAnalyzer<LogT, EventT, VisitorT, Set<Boat>> {
public RegattaLogBoatsInLogAnalyzer(LogT log) {
super(log);
}
@Override
protected Set<Boat> performAnalysis() {
Set<Boat> result = new HashSet<Boat>();
for (EventT event : getLog().getUnrevokedEvents()) {
if (event instanceof RegattaLogRegisterBoatEvent) {
result.add(((RegattaLogRegisterBoatEvent) event).getBoat());
}
}
return result;
}
}
@@ -0,0 +1,55 @@
package com.sap.sailing.domain.abstractlog.shared.analyzing;
import java.util.HashMap;
import java.util.Map;
import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.BaseLogAnalyzer;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.tracking.RaceLogRegisterCompetitorEvent;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompetitorEvent;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorWithBoat;
/**
* This class searches for {@link RaceLogRegisterCompetitorEvent}s or {@link RegattaLogRegisterCompetitorEvent}s in the given log
* in order to determine the competitor/boat mappings for both kind of events
*
*/
public class CompetitorsAndBoatsInLogAnalyzer<LogT extends AbstractLog<EventT, VisitorT>, EventT extends AbstractLogEvent<VisitorT>, VisitorT>
extends BaseLogAnalyzer<LogT, EventT, VisitorT, Map<Competitor, Boat>> {
public CompetitorsAndBoatsInLogAnalyzer(LogT log) {
super(log);
}
@Override
protected Map<Competitor, Boat> performAnalysis() {
Map<Competitor, Boat> result = new HashMap<>();
LogT log = getLog();
if (log instanceof RegattaLog) {
for (EventT event : getLog().getUnrevokedEvents()) {
if (event instanceof RegattaLogRegisterCompetitorEvent) {
RegattaLogRegisterCompetitorEvent regattaLogCompetitorEvent = (RegattaLogRegisterCompetitorEvent) event;
if (regattaLogCompetitorEvent.getCompetitor().hasBoat()) {
CompetitorWithBoat competitorWithBoat = (CompetitorWithBoat) regattaLogCompetitorEvent.getCompetitor();
result.put(competitorWithBoat, competitorWithBoat.getBoat());
}
}
}
} else if (log instanceof RaceLog) {
for (EventT event : getLog().getUnrevokedEvents()) {
if (event instanceof RaceLogRegisterCompetitorEvent) {
RaceLogRegisterCompetitorEvent raceLogCompetitorEvent = (RaceLogRegisterCompetitorEvent) event;
result.put(raceLogCompetitorEvent.getCompetitor(), raceLogCompetitorEvent.getBoat());
}
}
}
return result;
}
}
@@ -35,7 +35,7 @@ public class CompetitorsInLogAnalyzer<LogT extends AbstractLog<EventT, VisitorT>
@Override
protected Set<Competitor> performAnalysis() {
Set<Competitor> result = new HashSet<Competitor>();
Set<Competitor> result = new HashSet<>();
for (EventT event : getLog().getUnrevokedEvents()) {
if (event instanceof RegisterCompetitorEvent) {
@@ -3,11 +3,12 @@ package com.sap.sailing.domain.abstractlog.shared.events;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.Revokable;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sse.common.IsManagedByCache;
/**
* Register a competitor for that race using the {@link RaceLog} in racelog-tracked races.
* Register a competitor for {@link RaceLog} and {@link RegattaLog} tracked races and regattas.
*
* A dummy {@link Competitor} implementation with only an {@link Competitor#getId() id} may be used,
* if the competitor is known to already exist on the server, as it is
@@ -1,14 +1,33 @@
package com.sap.sailing.domain.base;
import com.sap.sse.common.Color;
import com.sap.sse.common.Named;
import com.sap.sse.common.IsManagedByCache;
import com.sap.sse.common.NamedWithID;
import com.sap.sse.datamining.annotations.Dimension;
public interface Boat extends Named {
BoatClass getBoatClass();
/**
* The boat being sailed by a competitor.
*
*/
public interface Boat extends NamedWithID, IsManagedByCache<SharedDomainFactory> {
BoatClass getBoatClass();
@Dimension(messageKey="SailID")
String getSailID();
Color getColor();
/**
* Adds a listener to this boat.
* Adding a listener that is already part of this boat's listeners set remains without effect.
*/
void addBoatChangeListener(BoatChangeListener listener);
/**
* Removes a listener from this boat.
* Trying to remove a listener that is not currently in the set of this boats's listener remains
* without effect.
*/
void removeBoatChangeListener(BoatChangeListener listener);
}
Loaded 100 of 840 files, more files were not shown because too many files have changed in this diff. Show more