availableDetailsTypes = getDefaultDetailTypesForChart();
+ availableDetailsTypes.add(DetailType.RACE_CURRENT_RIDE_HEIGHT_IN_METERS);
+ availableDetailsTypes.add(DetailType.CURRENT_HEEL_IN_DEGREES);
+ availableDetailsTypes.add(DetailType.CURRENT_PITCH_IN_DEGREES);
+ return availableDetailsTypes;
+ }
}
\ No newline at end of file
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceIdentifier.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DeviceIdentifier.java
similarity index 96%
rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceIdentifier.java
rename to java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DeviceIdentifier.java
index 5471253c027..b29ebc77bbf 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceIdentifier.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/DeviceIdentifier.java
@@ -1,9 +1,7 @@
-package com.sap.sailing.domain.racelogtracking;
+package com.sap.sailing.domain.common;
import java.io.Serializable;
-import com.sap.sailing.domain.abstractlog.race.RaceLog;
-
/**
* Identifies any kind of tracking device. Should be implemented accordingly for different tracking
* adapters, e.g. for smartphones, Igtimi trackers etc.
@@ -37,6 +35,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
* {@link Object#equals(Object)} and {@link Object#hashCode()} should be implemented so that multiple
* deserializations of same device identifier (conceptually) result in objects that are be identified
* as being equal through these two methods.
+ *
* @author Fredrik Teschke
*
*/
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/LegIdentifier.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/LegIdentifier.java
index 73ca7a2e740..4398e6c2f2e 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/LegIdentifier.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/LegIdentifier.java
@@ -1,7 +1,7 @@
package com.sap.sailing.domain.common;
public interface LegIdentifier extends RegattaAndRaceIdentifier {
- RaceIdentifier getRaceIdentifier();
+ RegattaAndRaceIdentifier getRaceIdentifier();
String getLegName();
int getLegNumber();
}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/LegIdentifierImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/LegIdentifierImpl.java
index 9800153f114..dbef906d0eb 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/LegIdentifierImpl.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/LegIdentifierImpl.java
@@ -2,7 +2,7 @@ package com.sap.sailing.domain.common;
public class LegIdentifierImpl extends RegattaNameAndRaceName implements LegIdentifier {
private static final long serialVersionUID = 3599904513673776450L;
- private RaceIdentifier raceIdentifier = null;
+ private RegattaAndRaceIdentifier raceIdentifier = null;
private String legName;
LegIdentifierImpl() {}
@@ -14,11 +14,10 @@ public class LegIdentifierImpl extends RegattaNameAndRaceName implements LegIden
}
@Override
- public RaceIdentifier getRaceIdentifier() {
+ public RegattaAndRaceIdentifier getRaceIdentifier() {
return this.raceIdentifier;
}
-
@Override
public String getLegName() {
return legName;
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ScoringSchemeType.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ScoringSchemeType.java
index 875734f00c2..c419b8d1bd1 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ScoringSchemeType.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ScoringSchemeType.java
@@ -2,7 +2,7 @@ package com.sap.sailing.domain.common;
public enum ScoringSchemeType {
// make sure to also add new ones to ScoringSchemeTypeFormatter
- LOW_POINT, HIGH_POINT, HIGH_POINT_ESS_OVERALL,HIGH_POINT_ESS_OVERALL_12, HIGH_POINT_LAST_BREAKS_TIE, HIGH_POINT_FIRST_GETS_TEN,
+ LOW_POINT, LOW_POINT_WITH_AUTOMATIC_RDG, HIGH_POINT, HIGH_POINT_ESS_OVERALL,HIGH_POINT_ESS_OVERALL_12, HIGH_POINT_LAST_BREAKS_TIE, HIGH_POINT_FIRST_GETS_TEN,
HIGH_POINT_FIRST_GETS_ONE, LOW_POINT_WINNER_GETS_ZERO, HIGH_POINT_WINNER_GETS_SIX, HIGH_POINT_WINNER_GETS_FIVE, HIGH_POINT_WINNER_GETS_EIGHT,
HIGH_POINT_WINNER_GETS_EIGHT_AND_INTERPOLATION, HIGH_POINT_FIRST_GETS_TEN_OR_EIGHT, HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT, HIGH_POINT_FIRST_GETS_TWELVE_OR_EIGHT_2017, LOW_POINT_WITH_ELIMINATIONS_AND_ROUNDS_WINNER_GETS_07,
LOW_POINT_LEAGUE_OVERALL, HIGH_POINT_MATCH_RACING, LOW_POINT_TIE_BREAK_BASED_ON_LAST_SERIES_ONLY
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TrackedRaceStatusEnum.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TrackedRaceStatusEnum.java
index 572e618db8d..c5b8201eaf7 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TrackedRaceStatusEnum.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/TrackedRaceStatusEnum.java
@@ -1,6 +1,6 @@
package com.sap.sailing.domain.common;
-public enum TrackedRaceStatusEnum { PREPARED(0), LOADING(1), TRACKING(2), FINISHED(3), ERROR(4);
+public enum TrackedRaceStatusEnum { PREPARED(0), LOADING(1), TRACKING(2), FINISHED(3), ERROR(4), REMOVED(5);
private final int order;
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/AnniversaryType.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/AnniversaryType.java
new file mode 100644
index 00000000000..d3fa095916a
--- /dev/null
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/AnniversaryType.java
@@ -0,0 +1,5 @@
+package com.sap.sailing.domain.common.dto;
+
+public enum AnniversaryType {
+ REPEATED_DIGIT, QUARTER
+}
\ No newline at end of file
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/CompetitorDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/CompetitorDTO.java
index 16bceb8a47a..cc14be28357 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/CompetitorDTO.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/CompetitorDTO.java
@@ -21,7 +21,8 @@ public interface CompetitorDTO extends Serializable, MappableToDevice {
String getSearchTag();
/**
- * If the {@code searchTag} is not contained in {@link #getSearchTag()}, appends it to the search tag, separated by a space character
+ * 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
*/
void addToSearchTag(String searchTag);
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/EventType.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/EventType.java
new file mode 100644
index 00000000000..f6a7104ff4e
--- /dev/null
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/EventType.java
@@ -0,0 +1,5 @@
+package com.sap.sailing.domain.common.dto;
+
+public enum EventType {
+ SINGLE_REGATTA, MULTI_REGATTA, SERIES
+}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java
index 150ec7d4087..4435b336e9f 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardEntryDTO.java
@@ -138,7 +138,7 @@ public class LeaderboardEntryDTO implements Serializable {
return totalPointsCorrected || (reasonForMaxPoints != null && reasonForMaxPoints != MaxPointsReason.NONE);
}
- public Duration getTimeSailedInMillis() {
+ public Duration getTimeSailed() {
final Duration result;
if (legDetails != null) {
long timeInMilliseconds = 0;
@@ -159,7 +159,7 @@ public class LeaderboardEntryDTO implements Serializable {
return result;
}
- public Distance getDistanceTraveledInMeters() {
+ public Distance getDistanceTraveled() {
Distance result = null;
if (legDetails != null) {
for (LegEntryDTO legDetail : legDetails) {
@@ -176,6 +176,47 @@ public class LeaderboardEntryDTO implements Serializable {
return result;
}
+ public Duration getDurationFoiled() {
+ final Duration result;
+ if (legDetails != null) {
+ Double acc = null;
+ for (LegEntryDTO legDetail : legDetails) {
+ if (legDetail != null) {
+ if (legDetail.currentDurationFoiledInSeconds != null) {
+ if (acc == null) {
+ acc = 0.0;
+ }
+ acc += legDetail.currentDurationFoiledInSeconds;
+ } else {
+ acc = null;
+ break;
+ }
+ }
+ }
+ result = acc == null ? null : new MillisecondsDurationImpl((long) (acc*1000.));
+ } else {
+ result = null;
+ }
+ return result;
+ }
+
+ public Distance getDistanceFoiled() {
+ Distance result = null;
+ if (legDetails != null) {
+ for (LegEntryDTO legDetail : legDetails) {
+ if (legDetail != null) {
+ if (legDetail.currentDistanceFoiledInMeters != null) {
+ if (result == null) {
+ result = Distance.NULL;
+ }
+ result = result.add(new MeterDistance(legDetail.currentDistanceFoiledInMeters));
+ }
+ }
+ }
+ }
+ return result;
+ }
+
public int getOneBasedCurrentLegNumber() {
int result = 0;
if (legDetails != null && !legDetails.isEmpty()) {
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardRowDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardRowDTO.java
index 4e60ad845c6..5ca9daaf00e 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardRowDTO.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LeaderboardRowDTO.java
@@ -26,6 +26,8 @@ public class LeaderboardRowDTO implements Serializable {
public Double totalTimeSailedUpwindInSeconds;
public Double totalTimeSailedReachingInSeconds;
public Double totalDistanceTraveledInMeters;
+ public Double totalDurationFoiledInSeconds;
+ public Double totalDistanceFoiledInMeters;
@Override
public int hashCode() {
@@ -38,6 +40,10 @@ public class LeaderboardRowDTO implements Serializable {
+ ((maximumSpeedOverGroundInKnots == null) ? 0 : maximumSpeedOverGroundInKnots.hashCode());
result = prime * result
+ ((totalDistanceTraveledInMeters == null) ? 0 : totalDistanceTraveledInMeters.hashCode());
+ result = prime * result
+ + ((totalDurationFoiledInSeconds == null) ? 0 : totalDurationFoiledInSeconds.hashCode());
+ result = prime * result
+ + ((totalDistanceFoiledInMeters == null) ? 0 : totalDistanceFoiledInMeters.hashCode());
result = prime * result + ((netPoints == null) ? 0 : netPoints.hashCode());
result = prime * result
+ ((totalTimeSailedDownwindInSeconds == null) ? 0 : totalTimeSailedDownwindInSeconds.hashCode());
@@ -87,6 +93,16 @@ public class LeaderboardRowDTO implements Serializable {
return false;
} else if (!totalDistanceTraveledInMeters.equals(other.totalDistanceTraveledInMeters))
return false;
+ if (totalDurationFoiledInSeconds == null) {
+ if (other.totalDurationFoiledInSeconds != null)
+ return false;
+ } else if (!totalDurationFoiledInSeconds.equals(other.totalDurationFoiledInSeconds))
+ return false;
+ if (totalDistanceFoiledInMeters == null) {
+ if (other.totalDistanceFoiledInMeters != null)
+ return false;
+ } else if (!totalDistanceFoiledInMeters.equals(other.totalDistanceFoiledInMeters))
+ return false;
if (netPoints == null) {
if (other.netPoints != null)
return false;
@@ -120,11 +136,11 @@ public class LeaderboardRowDTO implements Serializable {
return true;
}
- public Distance getDistanceTraveledInMeters(String raceColumnName) {
+ public Distance getDistanceTraveled(String raceColumnName) {
final Distance result;
LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
if (fieldsForRace != null) {
- result = fieldsForRace.getDistanceTraveledInMeters();
+ result = fieldsForRace.getDistanceTraveled();
} else {
result = null;
}
@@ -135,7 +151,29 @@ public class LeaderboardRowDTO implements Serializable {
final Duration result;
LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
if (fieldsForRace != null) {
- result = fieldsForRace.getTimeSailedInMillis();
+ result = fieldsForRace.getTimeSailed();
+ } else {
+ result = null;
+ }
+ return result;
+ }
+
+ public Distance getDistanceFoiled(String raceColumnName) {
+ final Distance result;
+ LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
+ if (fieldsForRace != null) {
+ result = fieldsForRace.getDistanceFoiled();
+ } else {
+ result = null;
+ }
+ return result;
+ }
+
+ public Duration getDurationFoiled(String raceColumnName) {
+ final Duration result;
+ LeaderboardEntryDTO fieldsForRace = fieldsByRaceColumnName.get(raceColumnName);
+ if (fieldsForRace != null) {
+ result = fieldsForRace.getDurationFoiled();
} else {
result = null;
}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LegEntryDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LegEntryDTO.java
index 255fbbb3a00..e545f1fe01a 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LegEntryDTO.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/LegEntryDTO.java
@@ -44,6 +44,8 @@ public class LegEntryDTO implements Serializable {
public Double currentHeelInDegrees;
public Double currentPitchInDegrees;
+ public Double currentDistanceFoiledInMeters;
+ public Double currentDurationFoiledInSeconds;
/**
* If the competitor has already finished the leg at the time point for which this entry was created, contains the
@@ -81,6 +83,8 @@ public class LegEntryDTO implements Serializable {
result = prime * result + ((currentHeelInDegrees == null) ? 0 : currentHeelInDegrees.hashCode());
result = prime * result + ((currentPitchInDegrees == null) ? 0 : currentPitchInDegrees.hashCode());
result = prime * result + ((currentRideHeightInMeters == null) ? 0 : currentRideHeightInMeters.hashCode());
+ result = prime * result + ((currentDurationFoiledInSeconds == null) ? 0 : currentDurationFoiledInSeconds.hashCode());
+ result = prime * result + ((currentDistanceFoiledInMeters == null) ? 0 : currentDistanceFoiledInMeters.hashCode());
result = prime * result
+ ((currentSpeedOverGroundInKnots == null) ? 0 : currentSpeedOverGroundInKnots.hashCode());
result = prime * result + ((distanceTraveledInMeters == null) ? 0 : distanceTraveledInMeters.hashCode());
@@ -150,6 +154,16 @@ public class LegEntryDTO implements Serializable {
return false;
} else if (!currentRideHeightInMeters.equals(other.currentRideHeightInMeters))
return false;
+ if (currentDurationFoiledInSeconds == null) {
+ if (other.currentDurationFoiledInSeconds != null)
+ return false;
+ } else if (!currentDurationFoiledInSeconds.equals(other.currentDurationFoiledInSeconds))
+ return false;
+ if (currentDistanceFoiledInMeters == null) {
+ if (other.currentDistanceFoiledInMeters != null)
+ return false;
+ } else if (!currentDistanceFoiledInMeters.equals(other.currentDistanceFoiledInMeters))
+ return false;
if (currentSpeedOverGroundInKnots == null) {
if (other.currentSpeedOverGroundInKnots != null)
return false;
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/DegreeBearingImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/DegreeBearingImpl.java
index 70e37a8717f..5ea889222d9 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/DegreeBearingImpl.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/impl/DegreeBearingImpl.java
@@ -9,7 +9,7 @@ public class DegreeBearingImpl extends AbstractBearing implements Bearing {
private final double bearingDeg;
/**
*
- * @param bearingDeg if a mount degrees over 360, then it will be mod 360 degrees
+ * @param bearingDeg if amount degrees over 360, then it will be mod 360 degrees
*/
public DegreeBearingImpl(double bearingDeg) {
super();
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/RaceLogServletConstants.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/RaceLogServletConstants.java
index dd7a29543fd..7c0541fd099 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/RaceLogServletConstants.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/RaceLogServletConstants.java
@@ -11,5 +11,7 @@ public interface RaceLogServletConstants {
static final String PARAMS_RACE_COLUMN_NAME = "race_column";
static final String PARAMS_RACE_FLEET_NAME = "fleet";
static final String PARAMS_CLIENT_UUID = "clientuuid";
- static final String PARAM_COURSE_AREA_FILTER = "courseArea";
+ static final String PARAMS_COURSE_AREA_FILTER = "courseArea";
+ static final String PARAMS_TRACK_WIND = "trackWind";
+ static final String PARAMS_CORRECT_WIND_DIRECTION_BY_MAGNETIC_DECLINATION = "correctWindDirectionByMagneticDeclination";
}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/impl/ScalableDistance.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/impl/ScalableDistance.java
new file mode 100755
index 00000000000..065b6f4899f
--- /dev/null
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/scalablevalue/impl/ScalableDistance.java
@@ -0,0 +1,44 @@
+package com.sap.sailing.domain.common.scalablevalue.impl;
+
+import com.sap.sailing.domain.common.Distance;
+import com.sap.sailing.domain.common.impl.MeterDistance;
+import com.sap.sse.common.scalablevalue.ScalableValue;
+import com.sap.sse.common.scalablevalue.ScalableValueWithDistance;
+
+public class ScalableDistance implements ScalableValueWithDistance {
+ private final double meters;
+
+ public ScalableDistance(Distance distance) {
+ this.meters = distance.getMeters();
+ }
+
+ private ScalableDistance(double meters) {
+ this.meters = meters;
+ }
+
+ @Override
+ public ScalableDistance multiply(double factor) {
+ return new ScalableDistance(factor*meters);
+ }
+
+ @Override
+ public ScalableDistance add(ScalableValue t) {
+ return new ScalableDistance(meters+t.getValue());
+ }
+
+ @Override
+ public Distance divide(double divisor) {
+ return new MeterDistance(meters / divisor);
+ }
+
+ @Override
+ public Double getValue() {
+ return meters;
+ }
+
+ @Override
+ public double getDistance(Distance other) {
+ return Math.abs(meters-other.getMeters());
+ }
+
+}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/security/Permission.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/security/Permission.java
index b0e3272131a..40a5d7e7893 100755
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/security/Permission.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/security/Permission.java
@@ -14,6 +14,7 @@ public enum Permission implements com.sap.sse.security.shared.Permission {
MANAGE_COURSE_LAYOUT,
MANAGE_WIND,
MANAGE_IGTIMI_ACCOUNTS,
+ MANAGE_EXPEDITION_DEVICE_CONFIGURATIONS,
MANAGE_LEADERBOARDS,
MANAGE_LEADERBOARD_RESULTS,
MANAGE_LEADERBOARD_GROUPS,
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/BravoExtendedSensorDataMetadata.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/BravoExtendedSensorDataMetadata.java
new file mode 100644
index 00000000000..efd9c9a863d
--- /dev/null
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/BravoExtendedSensorDataMetadata.java
@@ -0,0 +1,115 @@
+package com.sap.sailing.domain.common.sensordata;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
+
+/**
+ * Metadata that defines the column structure of BravoExtended fixes when imported as
+ * {@link com.sap.sailing.domain.common.tracking.DoubleVectorFix}.
+ *
+ *
+ * The current implementation only stores a subset of the information available during the import.
+ *
+ *
+ * The first columns need to be consistent with {@link BravoSensorDataMetadata}. Furthermore,
+ * once data has been stored in a sensor store, the order of literals must remain constant,
+ * and no literals must be deleted anymore because the ordinal is used to determine the index
+ * into the {@link DoubleVectorFix}.
+ */
+public enum BravoExtendedSensorDataMetadata implements ColumnMetadata {
+ RIDE_HEIGHT_PORT_HULL("RideHeightPort", /* expectedInLogfile */ true), //
+ RIDE_HEIGHT_STBD_HULL("RideHeightStbd", /* expectedInLogfile */ true), //
+ HEEL("Heel", /* expectedInLogfile */ true), //
+ PITCH("PitchRate", /* expectedInLogfile */ true), //
+ DB_RAKE_PORT("DaggerBoardRakeAnglePort", /* expectedInLogfile */ true), //
+ DB_RAKE_STBD("DaggerBoardRakeAngleStbd", /* expectedInLogfile */ true), //
+ RUDDER_RAKE_PORT("RudderRakeAnglePort", /* expectedInLogfile */ true), //
+ RUDDER_RAKE_STBD("RudderRakeAngleStbd", /* expectedInLogfile */ true), //
+ MAST_ROTATION("MastRotation", /* expectedInLogfile */ true), //
+ LEEWAY(null, /* expectedInLogfile */ false), //
+ SET(null, /* expectedInLogfile */ false), //
+ DRIFT(null, /* expectedInLogfile */ false), //
+ DEPTH(null, /* expectedInLogfile */ false), //
+ RUDDER(null, /* expectedInLogfile */ false), //
+ FORESTAY_LOAD(null, /* expectedInLogfile */ false), //
+ FORESTAY_PRESSURE(null, /* expectedInLogfile */ false), //
+ TACK_ANGLE(null, /* expectedInLogfile */ false), //
+ RAKE_DEG(null, /* expectedInLogfile */ false), //
+ DEFLECTOR_PERCENTAGE(null, /* expectedInLogfile */ false), //
+ TARGET_HEEL(null, /* expectedInLogfile */ false), //
+ DEFLECTOR_MILLIMETERS(null, /* expectedInLogfile */ false), //
+ TARGET_BOATSPEED_P(null, /* expectedInLogfile */ false), //
+ LAT("Lat", /* expectedInLogfile */ true), //
+ LON("Lon", /* expectedInLogfile */ true), //
+ COG("COG", /* expectedInLogfile */ true), //
+ SOG("SOG", /* expectedInLogfile */ true), //
+ ;
+
+ private final String columnName;
+
+ /**
+ * Some values seem to only appear in the UDP stream but so far not in the log file. Therefore,
+ * those columns shall not be part of the response to {@link #getColumnNamesToIndexInDoubleFix()},
+ * indicated by this field being {@code false} for those attributes.
+ */
+ private final boolean expectedInLogFile;
+
+ private BravoExtendedSensorDataMetadata(String columnName, boolean expectedInLogfile) {
+ this.columnName = columnName;
+ this.expectedInLogFile = expectedInLogfile;
+ }
+
+ public String getColumnName() {
+ return columnName;
+ }
+
+ public boolean isExpectedInLogFile() {
+ return expectedInLogFile;
+ }
+
+ /**
+ * The index in the {@link DoubleVectorFix} where this data item will be stored
+ */
+ public int getColumnIndex() {
+ return this.ordinal();
+ }
+
+ public static final int HEADER_COLUMN_OFFSET = 3;
+
+ public static BravoExtendedSensorDataMetadata byColumnName(String valueName) {
+ BravoExtendedSensorDataMetadata[] values = BravoExtendedSensorDataMetadata.values();
+ for (BravoExtendedSensorDataMetadata item : values) {
+ if (Objects.equals(item.getColumnName(), valueName)) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ public static int getTrackColumnCount() {
+ int result = 0;
+ for (final BravoExtendedSensorDataMetadata m : BravoExtendedSensorDataMetadata.values()) {
+ if (m.isExpectedInLogFile()) {
+ result++;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @return namens of those columns with {@link #isExpectedInLogFile()} being {@code true}, mapped to their
+ * {@link #getColumnIndex() column index}
+ */
+ public static Map getColumnNamesToIndexInDoubleFix() {
+ final Map columnNamesToIndexInDoubleFix = new HashMap<>();
+ for (final BravoExtendedSensorDataMetadata column : BravoExtendedSensorDataMetadata.values()) {
+ if (column.isExpectedInLogFile()) {
+ columnNamesToIndexInDoubleFix.put(column.getColumnName(), column.getColumnIndex());
+ }
+ }
+ return columnNamesToIndexInDoubleFix;
+ }
+}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/BravoSensorDataMetadata.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/BravoSensorDataMetadata.java
index 091e6329eff..f7c7a853a37 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/BravoSensorDataMetadata.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/BravoSensorDataMetadata.java
@@ -1,23 +1,24 @@
package com.sap.sailing.domain.common.sensordata;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
/**
- * Metadata that defines the column structure of {@link com.sap.sailing.domain.common.tracking.DoubleVectorFix}es when
- * imported.
+ * Metadata that defines the column structure of Bravo fixes when imported as
+ * {@link com.sap.sailing.domain.common.tracking.DoubleVectorFix}.
+ *
*
* The current implementation only stores a subset of the information available during the import.
*/
-public enum BravoSensorDataMetadata {
-
+public enum BravoSensorDataMetadata implements ColumnMetadata {
RIDE_HEIGHT_PORT_HULL("RideHeightPortHull"), //
RIDE_HEIGHT_STBD_HULL("RideHeightStbdHull"), //
HEEL("Heel"), //
PITCH("ImuSensor_Pitch");
-
private String columnName;
private BravoSensorDataMetadata(String columnName) {
@@ -51,8 +52,16 @@ public enum BravoSensorDataMetadata {
public static List getTrackColumnNames() {
ArrayList colNames = new ArrayList<>(getTrackColumnCount());
for (BravoSensorDataMetadata item : BravoSensorDataMetadata.values()) {
- colNames.add(item.columnName);
+ colNames.add(item.getColumnName());
}
return colNames;
}
+
+ public static Map getColumnNamesToIndexInDoubleFix() {
+ final Map columnNamesToIndexInDoubleFix = new HashMap<>();
+ for (final BravoSensorDataMetadata column : BravoSensorDataMetadata.values()) {
+ columnNamesToIndexInDoubleFix.put(column.getColumnName(), column.getColumnIndex());
+ }
+ return columnNamesToIndexInDoubleFix;
+ }
}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/ColumnMetadata.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/ColumnMetadata.java
new file mode 100644
index 00000000000..5380fa447be
--- /dev/null
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/ColumnMetadata.java
@@ -0,0 +1,14 @@
+package com.sap.sailing.domain.common.sensordata;
+
+import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
+import com.sap.sailing.domain.common.tracking.SensorFix;
+
+/**
+ * Definition of column metadata used by {@link SensorFix} implementations to resolve columns in underlying
+ * {@link DoubleVectorFix DoubleVectorFixes}. Once data has been stored in a sensor store according to such a
+ * specification, the order of literals in implementing {@code enum} types must remain constant, and no literals must be
+ * deleted anymore because the ordinal is used to determine the index into the {@link DoubleVectorFix}.
+ */
+public interface ColumnMetadata {
+ int getColumnIndex();
+}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/ExpeditionExtendedSensorDataMetadata.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/ExpeditionExtendedSensorDataMetadata.java
new file mode 100755
index 00000000000..3858832e652
--- /dev/null
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/sensordata/ExpeditionExtendedSensorDataMetadata.java
@@ -0,0 +1,109 @@
+package com.sap.sailing.domain.common.sensordata;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
+
+/**
+ * Metadata that defines the column structure of BravoExtended fixes when imported as
+ * {@link com.sap.sailing.domain.common.tracking.DoubleVectorFix}.
+ *
+ *
+ * The current implementation only stores a subset of the information available during the import.
+ *
+ *
+ * The first columns need to be consistent with {@link BravoSensorDataMetadata}.
+ */
+public enum ExpeditionExtendedSensorDataMetadata {
+ HEEL("Heel", BravoExtendedSensorDataMetadata.HEEL), //
+ TRIM("Trim", BravoExtendedSensorDataMetadata.PITCH), //
+ LEEWAY("Leeway", BravoExtendedSensorDataMetadata.LEEWAY, /* expected in logfile */ true), //
+ SET("Set", BravoExtendedSensorDataMetadata.SET, /* expected in logfile */ true), //
+ DRIFT("Drift", BravoExtendedSensorDataMetadata.DRIFT, /* expected in logfile */ true), //
+ DEPTH("Depth", BravoExtendedSensorDataMetadata.DEPTH, /* expected in logfile */ true), //
+ RUDDER("Rudder", BravoExtendedSensorDataMetadata.RUDDER, /* expected in logfile */ true), //
+ FORESTAY_LOAD("Forestay", BravoExtendedSensorDataMetadata.FORESTAY_LOAD, /* expected in logfile */ true), //
+ FORESTAY_PRESSURE("ForestayPres", BravoExtendedSensorDataMetadata.FORESTAY_PRESSURE, /* expected in logfile */ true), //
+ TACK_ANGLE(null, BravoExtendedSensorDataMetadata.TACK_ANGLE), //
+ RAKE_DEG("RakeDeg", BravoExtendedSensorDataMetadata.RAKE_DEG, /* expected in logfile */ true), //
+ DEFLECTOR_PERCENTAGE("DflectrPP", BravoExtendedSensorDataMetadata.DEFLECTOR_PERCENTAGE, /* expected in logfile */ true), //
+ TARGET_HEEL("TG Heell", BravoExtendedSensorDataMetadata.TARGET_HEEL, /* expected in logfile */ true), //
+ DEFLECTOR_MILLIMETERS("DflectrMM", BravoExtendedSensorDataMetadata.DEFLECTOR_MILLIMETERS, /* expected in logfile */ true), //
+ TARGET_BOATSPEED_P("BspTr", BravoExtendedSensorDataMetadata.TARGET_BOATSPEED_P, /* expected in logfile */ true), //
+ ;
+
+ private String columnName;
+
+ /**
+ * Expedition extended fixes are mapped to Bravo extended fixes whose metadata is described
+ * in {@link BravoExtendedSensorDataMetadata}. When parsing an Expedition file, the columns
+ * in the resulting {@link DoubleVectorFix} must be chosen such that they match up with the
+ * corresponding fields as described by {@link BravoExtendedSensorDataMetadata}. This turns
+ * the ordinals of this enum's literals insignificant; the position is taken solely from
+ * the Bravo metadata.
+ */
+ private final BravoExtendedSensorDataMetadata mappedToBravoField;
+
+ private final boolean expectedInLogfile;
+
+ private ExpeditionExtendedSensorDataMetadata(String columnName, BravoExtendedSensorDataMetadata mappedToBravoField) {
+ this(columnName, mappedToBravoField, mappedToBravoField.isExpectedInLogFile());
+ }
+
+ private ExpeditionExtendedSensorDataMetadata(String columnName, BravoExtendedSensorDataMetadata mappedToBravoField, boolean expectedInLogfile) {
+ this.columnName = columnName;
+ this.mappedToBravoField = mappedToBravoField;
+ this.expectedInLogfile = expectedInLogfile;
+ }
+
+ public String getColumnName() {
+ return columnName;
+ }
+
+ /**
+ * The index in the {@link DoubleVectorFix} where this data item will be stored
+ */
+ public int getColumnIndex() {
+ return mappedToBravoField.getColumnIndex();
+ }
+
+ public boolean isExpectedInLogFile() {
+ return expectedInLogfile;
+ }
+
+ public static ExpeditionExtendedSensorDataMetadata byColumnName(String valueName) {
+ ExpeditionExtendedSensorDataMetadata[] values = ExpeditionExtendedSensorDataMetadata.values();
+ for (ExpeditionExtendedSensorDataMetadata item : values) {
+ if (Objects.equals(item.getColumnName(), valueName)) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ public static int getTrackColumnCount() {
+ return ExpeditionExtendedSensorDataMetadata.values().length;
+ }
+
+ public static List getTrackColumnNames() {
+ ArrayList colNames = new ArrayList<>(getTrackColumnCount());
+ for (ExpeditionExtendedSensorDataMetadata item : ExpeditionExtendedSensorDataMetadata.values()) {
+ colNames.add(item.getColumnName());
+ }
+ return colNames;
+ }
+
+ public static Map getColumnNamesToIndexInDoubleFix() {
+ final Map columnNamesToIndexInDoubleFix = new HashMap<>();
+ for (final ExpeditionExtendedSensorDataMetadata column : ExpeditionExtendedSensorDataMetadata.values()) {
+ if (column.isExpectedInLogFile()) {
+ columnNamesToIndexInDoubleFix.put(column.getColumnName(), column.getColumnIndex());
+ }
+ }
+ return columnNamesToIndexInDoubleFix;
+ }
+}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/BravoExtendedFix.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/BravoExtendedFix.java
new file mode 100644
index 00000000000..d38e8be6b5d
--- /dev/null
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/BravoExtendedFix.java
@@ -0,0 +1,28 @@
+package com.sap.sailing.domain.common.tracking;
+
+import com.sap.sailing.domain.common.Bearing;
+import com.sap.sailing.domain.common.Distance;
+
+/**
+ * Extended version of {@link BravoFix} that provides access to more measures found in the extended data format.
+ */
+public interface BravoExtendedFix extends BravoFix {
+ Double getPortDaggerboardRake();
+ Double getStbdDaggerboardRake();
+ Double getPortRudderRake();
+ Double getStbdRudderRake();
+ Bearing getMastRotation();
+ Bearing getLeeway();
+ Double getSet();
+ Bearing getDrift();
+ Distance getDepth();
+ Bearing getRudder();
+ Double getForestayLoad();
+ Double getForestayPressure();
+ Bearing getTackAngle();
+ Bearing getRake();
+ Double getDeflectorPercentage();
+ Bearing getTargetHeel();
+ Distance getDeflector();
+ Double getTargetBoatspeedP();
+}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/BravoFix.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/BravoFix.java
index aea9ffd3615..3cb3a5e7302 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/BravoFix.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/BravoFix.java
@@ -33,13 +33,17 @@ public interface BravoFix extends SensorFix {
@Dimension(messageKey="IsFoiling")
boolean isFoiling();
+
+ /**
+ * Same as {@link #isFoiling()}, only that instead of using the {@link #MIN_FOILING_HEIGHT_THRESHOLD} constant as
+ * the threshold value for the ride height, here the caller can provide a specific ride height that must be reached
+ * for a fix to be considered foiling.
+ */
+ boolean isFoiling(Distance minimumRideHeight);
@Statistic(messageKey="pitch", resultDecimals=1)
Bearing getPitch();
@Statistic(messageKey = "heel", resultDecimals = 1)
Bearing getHeel();
-
-
-
}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/DoubleVectorFix.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/DoubleVectorFix.java
index 4e955af6679..9367955be94 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/DoubleVectorFix.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/DoubleVectorFix.java
@@ -3,10 +3,15 @@ package com.sap.sailing.domain.common.tracking;
import com.sap.sse.common.Timed;
/**
- * A fix that simply holds an array of double values. The interpretation of the data depends on the concrete mapping in
- * the RegattaLog.
+ * A fix that simply holds an array of {@link Double} values. The interpretation of the data depends on the concrete
+ * mapping in the RegattaLog. Asking beyond the end of the vector using {@link #get(int)} will return {@code null} but
+ * not throw an exception.
*/
public interface DoubleVectorFix extends Timed {
- double[] get();
- double get(int index);
+ Double[] get();
+ Double get(int index);
+ /**
+ * Tells whether at least one component is not {@code null}
+ */
+ boolean hasValidData();
}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/BravoExtendedFixImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/BravoExtendedFixImpl.java
new file mode 100644
index 00000000000..4fc24390061
--- /dev/null
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/BravoExtendedFixImpl.java
@@ -0,0 +1,126 @@
+package com.sap.sailing.domain.common.tracking.impl;
+
+import com.sap.sailing.domain.common.Bearing;
+import com.sap.sailing.domain.common.Distance;
+import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
+import com.sap.sailing.domain.common.impl.MeterDistance;
+import com.sap.sailing.domain.common.sensordata.BravoExtendedSensorDataMetadata;
+import com.sap.sailing.domain.common.sensordata.ColumnMetadata;
+import com.sap.sailing.domain.common.tracking.BravoExtendedFix;
+import com.sap.sailing.domain.common.tracking.BravoFix;
+import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
+
+/**
+ * Implementation of {@link BravoExtendedFix}. {@link BravoExtendedFix} adds more measures compared to {@link BravoFix}.
+ */
+public class BravoExtendedFixImpl extends BravoFixImpl implements BravoExtendedFix {
+ private static final long serialVersionUID = 5622321493028301922L;
+
+ public BravoExtendedFixImpl(DoubleVectorFix fix) {
+ super(fix);
+ }
+
+ @Override
+ protected ColumnMetadata resolveMetadataFromValueName(String valueName) {
+ return BravoExtendedSensorDataMetadata.byColumnName(valueName);
+ }
+
+ @Override
+ public Double getPortDaggerboardRake() {
+ return fix.get(BravoExtendedSensorDataMetadata.DB_RAKE_PORT.getColumnIndex());
+ }
+
+ @Override
+ public Double getStbdDaggerboardRake() {
+ return fix.get(BravoExtendedSensorDataMetadata.DB_RAKE_STBD.getColumnIndex());
+ }
+
+ @Override
+ public Double getPortRudderRake() {
+ return fix.get(BravoExtendedSensorDataMetadata.RUDDER_RAKE_PORT.getColumnIndex());
+ }
+
+ @Override
+ public Double getStbdRudderRake() {
+ return fix.get(BravoExtendedSensorDataMetadata.RUDDER_RAKE_STBD.getColumnIndex());
+ }
+
+ @Override
+ public Bearing getMastRotation() {
+ final Double bearingDeg = fix.get(BravoExtendedSensorDataMetadata.MAST_ROTATION.getColumnIndex());
+ return bearingDeg == null ? null : new DegreeBearingImpl(bearingDeg);
+ }
+
+ @Override
+ public Bearing getLeeway() {
+ final Double leeway = fix.get(BravoExtendedSensorDataMetadata.LEEWAY.getColumnIndex());
+ return leeway == null ? null : new DegreeBearingImpl(leeway);
+ }
+
+ @Override
+ public Double getSet() {
+ return fix.get(BravoExtendedSensorDataMetadata.SET.getColumnIndex());
+ }
+
+ @Override
+ public Bearing getDrift() {
+ final Double drift = fix.get(BravoExtendedSensorDataMetadata.DRIFT.getColumnIndex());
+ return drift == null ? null : new DegreeBearingImpl(drift);
+ }
+
+ @Override
+ public Distance getDepth() {
+ final Double depthInMeters = fix.get(BravoExtendedSensorDataMetadata.DEPTH.getColumnIndex());
+ return depthInMeters == null ? null : new MeterDistance(depthInMeters);
+ }
+
+ @Override
+ public Bearing getRudder() {
+ final Double rudderAngleDeg = fix.get(BravoExtendedSensorDataMetadata.RUDDER.getColumnIndex());
+ return rudderAngleDeg == null ? null : new DegreeBearingImpl(rudderAngleDeg);
+ }
+
+ @Override
+ public Double getForestayLoad() {
+ return fix.get(BravoExtendedSensorDataMetadata.FORESTAY_LOAD.getColumnIndex());
+ }
+
+ @Override
+ public Double getForestayPressure() {
+ return fix.get(BravoExtendedSensorDataMetadata.FORESTAY_PRESSURE.getColumnIndex());
+ }
+
+ @Override
+ public Bearing getTackAngle() {
+ final Double tackAngleDeg = fix.get(BravoExtendedSensorDataMetadata.TACK_ANGLE.getColumnIndex());
+ return tackAngleDeg == null ? null : new DegreeBearingImpl(tackAngleDeg);
+ }
+
+ @Override
+ public Bearing getRake() {
+ final Double rakeDeg = fix.get(BravoExtendedSensorDataMetadata.RAKE_DEG.getColumnIndex());
+ return rakeDeg == null ? null : new DegreeBearingImpl(rakeDeg);
+ }
+
+ @Override
+ public Double getDeflectorPercentage() {
+ return fix.get(BravoExtendedSensorDataMetadata.DEFLECTOR_PERCENTAGE.getColumnIndex());
+ }
+
+ @Override
+ public Bearing getTargetHeel() {
+ final Double targetHeelDeg = fix.get(BravoExtendedSensorDataMetadata.TARGET_HEEL.getColumnIndex());
+ return targetHeelDeg == null ? null : new DegreeBearingImpl(targetHeelDeg);
+ }
+
+ @Override
+ public Distance getDeflector() {
+ final Double deflectorMillimeters = fix.get(BravoExtendedSensorDataMetadata.DEFLECTOR_MILLIMETERS.getColumnIndex());
+ return deflectorMillimeters == null ? null : new MeterDistance(deflectorMillimeters / 1000.);
+ }
+
+ @Override
+ public Double getTargetBoatspeedP() {
+ return fix.get(BravoExtendedSensorDataMetadata.TARGET_BOATSPEED_P.getColumnIndex());
+ }
+}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/BravoFixImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/BravoFixImpl.java
index 296b472a1f2..7db57751513 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/BravoFixImpl.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/BravoFixImpl.java
@@ -5,43 +5,37 @@ import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.MeterDistance;
import com.sap.sailing.domain.common.sensordata.BravoSensorDataMetadata;
+import com.sap.sailing.domain.common.sensordata.ColumnMetadata;
import com.sap.sailing.domain.common.tracking.BravoFix;
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
-import com.sap.sse.common.TimePoint;
/**
* Implementation of {@link BravoFix} that wraps a {@link DoubleVectorFix} which holds the actual sensor data. The
* mapping metadata is stored in the {@link BravoSensorDataMetadata} enum.
*/
-public class BravoFixImpl implements BravoFix {
+public class BravoFixImpl extends SensorFixImpl implements BravoFix {
private static final long serialVersionUID = 2033254212013221160L;
- private final DoubleVectorFix fix;
public BravoFixImpl(DoubleVectorFix fix) {
- this.fix = fix;
+ super(fix);
}
-
+
@Override
- public double get(String valueName) {
- BravoSensorDataMetadata colDefEnum = BravoSensorDataMetadata.byColumnName(valueName);
- if (colDefEnum == null) {
- throw new IllegalArgumentException("Unknown value \"" + valueName + "\" for " + getClass().getSimpleName());
- }
- int index = colDefEnum.getColumnIndex();
- return fix.get(index);
- }
-
- @Override
- public TimePoint getTimePoint() {
- return fix.getTimePoint();
+ protected ColumnMetadata resolveMetadataFromValueName(String valueName) {
+ return BravoSensorDataMetadata.byColumnName(valueName);
}
@Override
public Distance getRideHeight() {
- double rideHeightPortHullasDouble = fix.get(BravoSensorDataMetadata.RIDE_HEIGHT_PORT_HULL.getColumnIndex());
- double rideHeightStarboardHullasDouble = fix
+ Double rideHeightPortHullasDouble = fix.get(BravoSensorDataMetadata.RIDE_HEIGHT_PORT_HULL.getColumnIndex());
+ Double rideHeightStarboardHullAsDouble = fix
.get(BravoSensorDataMetadata.RIDE_HEIGHT_STBD_HULL.getColumnIndex());
- return new MeterDistance(Math.min(rideHeightPortHullasDouble, rideHeightStarboardHullasDouble));
+ return rideHeightPortHullasDouble == null ?
+ rideHeightStarboardHullAsDouble == null ? null :
+ new MeterDistance(rideHeightStarboardHullAsDouble) :
+ rideHeightStarboardHullAsDouble == null ?
+ new MeterDistance(rideHeightPortHullasDouble) :
+ new MeterDistance(Math.min(rideHeightPortHullasDouble, rideHeightStarboardHullAsDouble));
}
@Override
@@ -59,16 +53,23 @@ public class BravoFixImpl implements BravoFix {
@Override
public boolean isFoiling() {
- return getRideHeight().compareTo(MIN_FOILING_HEIGHT_THRESHOLD) >= 0;
+ return isFoiling(MIN_FOILING_HEIGHT_THRESHOLD);
+ }
+
+ @Override
+ public boolean isFoiling(Distance minimumRideHeight) {
+ return getRideHeight().compareTo(minimumRideHeight) >= 0;
}
@Override
public Bearing getPitch() {
- return new DegreeBearingImpl(fix.get(BravoSensorDataMetadata.PITCH.getColumnIndex()));
+ final Double bearingDeg = fix.get(BravoSensorDataMetadata.PITCH.getColumnIndex());
+ return bearingDeg == null ? null : new DegreeBearingImpl(bearingDeg);
}
@Override
public Bearing getHeel() {
- return new DegreeBearingImpl(fix.get(BravoSensorDataMetadata.HEEL.getColumnIndex()));
+ final Double bearingDeg = fix.get(BravoSensorDataMetadata.HEEL.getColumnIndex());
+ return bearingDeg == null ? null : new DegreeBearingImpl(bearingDeg);
}
}
diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/DoubleVectorFixImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/DoubleVectorFixImpl.java
index 9c6b1ca99f3..031a5b197d9 100644
--- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/DoubleVectorFixImpl.java
+++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/tracking/impl/DoubleVectorFixImpl.java
@@ -1,12 +1,16 @@
package com.sap.sailing.domain.common.tracking.impl;
import java.util.Arrays;
+import java.util.BitSet;
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
import com.sap.sse.common.TimePoint;
/**
- * Implementation of {@link DoubleVectorFix}.
+ * Implementation of {@link DoubleVectorFix}. In order to save some space and reduce the number of object headers,
+ * instead of storing {@link Double} objects the structure internally uses an array of {@code double} values and
+ * additionally remembers in a {@link BitSet} which components are {@code null}. The {@link #get()} and {@link #get(int)}
+ * methods then translate back to a {@link Double} representation accordingly.
*/
public class DoubleVectorFixImpl implements DoubleVectorFix {
@@ -14,10 +18,25 @@ public class DoubleVectorFixImpl implements DoubleVectorFix {
private final double[] fixData;
private final TimePoint timePoint;
+
+ /**
+ * The constructor accepts a {@code Double[]} for the data components, allowing for {@code null}
+ * values to be used. To save space, internally a {@code double[]} is used to represent the data.
+ * In order to encode the {@code null} values, this bit set stores which array components had
+ * valid, non-{@code null} data.
+ */
+ private final BitSet validComponents;
- public DoubleVectorFixImpl(TimePoint timePoint, double[] fixData) {
+ public DoubleVectorFixImpl(TimePoint timePoint, Double[] fixData) {
this.timePoint = timePoint;
- this.fixData = fixData;
+ this.fixData = new double[fixData.length];
+ this.validComponents = new BitSet(fixData.length);
+ for (int i=0; i
+
+
+
+
+
+
diff --git a/java/com.sap.sailing.domain.expeditionadapter/.project b/java/com.sap.sailing.domain.expeditionadapter/.project
new file mode 100755
index 00000000000..a413084a0cd
--- /dev/null
+++ b/java/com.sap.sailing.domain.expeditionadapter/.project
@@ -0,0 +1,28 @@
+
+
+ com.sap.sailing.domain.expeditionadapter
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/java/com.sap.sailing.domain.expeditionadapter/.settings/org.eclipse.jdt.core.prefs b/java/com.sap.sailing.domain.expeditionadapter/.settings/org.eclipse.jdt.core.prefs
new file mode 100755
index 00000000000..0c68a61dca8
--- /dev/null
+++ b/java/com.sap.sailing.domain.expeditionadapter/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/java/com.sap.sailing.domain.expeditionadapter/.settings/org.eclipse.pde.core.prefs b/java/com.sap.sailing.domain.expeditionadapter/.settings/org.eclipse.pde.core.prefs
new file mode 100755
index 00000000000..f29e940a005
--- /dev/null
+++ b/java/com.sap.sailing.domain.expeditionadapter/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+pluginProject.extensions=false
+resolve.requirebundle=false
diff --git a/java/com.sap.sailing.domain.expeditionadapter/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.expeditionadapter/META-INF/MANIFEST.MF
new file mode 100755
index 00000000000..43e36b46448
--- /dev/null
+++ b/java/com.sap.sailing.domain.expeditionadapter/META-INF/MANIFEST.MF
@@ -0,0 +1,13 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Expeditionadapter
+Bundle-SymbolicName: com.sap.sailing.domain.expeditionadapter
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: SAP
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: org.osgi.framework
+Require-Bundle: com.sap.sailing.server.trackfiles,
+ com.sap.sailing.domain,
+ com.sap.sse.common,
+ com.sap.sailing.domain.common
+Bundle-Activator: com.sap.sailing.domain.expeditionadapter.impl.Activator
diff --git a/java/com.sap.sailing.domain.expeditionadapter/build.properties b/java/com.sap.sailing.domain.expeditionadapter/build.properties
new file mode 100755
index 00000000000..34d2e4d2dad
--- /dev/null
+++ b/java/com.sap.sailing.domain.expeditionadapter/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/java/com.sap.sailing.domain.expeditionadapter/pom.xml b/java/com.sap.sailing.domain.expeditionadapter/pom.xml
new file mode 100755
index 00000000000..420cb8c34f6
--- /dev/null
+++ b/java/com.sap.sailing.domain.expeditionadapter/pom.xml
@@ -0,0 +1,12 @@
+
+
+ 4.0.0
+
+ root
+ com.sap.sailing
+ 1.0.0-SNAPSHOT
+
+ com.sap.sailing.domain.expeditionadapter
+ eclipse-plugin
+
diff --git a/java/com.sap.sailing.domain.expeditionadapter/src/com/sap/sailing/domain/expeditionadapter/impl/Activator.java b/java/com.sap.sailing.domain.expeditionadapter/src/com/sap/sailing/domain/expeditionadapter/impl/Activator.java
new file mode 100755
index 00000000000..a73939a8ac8
--- /dev/null
+++ b/java/com.sap.sailing.domain.expeditionadapter/src/com/sap/sailing/domain/expeditionadapter/impl/Activator.java
@@ -0,0 +1,17 @@
+package com.sap.sailing.domain.expeditionadapter.impl;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.sap.sailing.server.trackfiles.common.GPSFixImporterRegistration;
+
+public class Activator implements BundleActivator {
+ @Override
+ public void start(BundleContext context) throws Exception {
+ GPSFixImporterRegistration.register(new ExpeditionGPSFixImporter(), context);
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ }
+}
diff --git a/java/com.sap.sailing.domain.expeditionadapter/src/com/sap/sailing/domain/expeditionadapter/impl/ExpeditionGPSFixImporter.java b/java/com.sap.sailing.domain.expeditionadapter/src/com/sap/sailing/domain/expeditionadapter/impl/ExpeditionGPSFixImporter.java
new file mode 100755
index 00000000000..be38baee40d
--- /dev/null
+++ b/java/com.sap.sailing.domain.expeditionadapter/src/com/sap/sailing/domain/expeditionadapter/impl/ExpeditionGPSFixImporter.java
@@ -0,0 +1,61 @@
+package com.sap.sailing.domain.expeditionadapter.impl;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
+import com.sap.sailing.domain.common.impl.DegreePosition;
+import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
+import com.sap.sailing.domain.common.tracking.GPSFixMoving;
+import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
+import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
+import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
+import com.sap.sailing.domain.trackimport.FormatNotSupportedException;
+import com.sap.sailing.domain.trackimport.GPSFixImporter;
+import com.sap.sailing.server.trackfiles.impl.ExpeditionExtendedDataImporterImpl;
+
+public class ExpeditionGPSFixImporter implements GPSFixImporter {
+ private static final String LAT_COLUMN_HEADING = ExpeditionExtendedDataImporterImpl.COL_NAME_LAT;
+ private static final String LON_COLUMN_HEADING = ExpeditionExtendedDataImporterImpl.COL_NAME_LON;
+ private static final String COG_COLUMN_HEADING = "Cog";
+ private static final String SOG_COLUMN_HEADING = "Sog";
+ @Override
+ public void importFixes(InputStream inputStream, Callback callback, boolean inferSpeedAndBearing, final String sourceName)
+ throws FormatNotSupportedException, IOException {
+ TrackFileImportDeviceIdentifier device = new TrackFileImportDeviceIdentifierImpl(sourceName, getType() + "@" + new Date());
+ final BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
+ final String headerLine = br.readLine();
+ final Map columnDefinitions = ExpeditionExtendedDataImporterImpl.parseHeader(headerLine);
+ final AtomicInteger lineNr = new AtomicInteger(0);
+ br.lines().forEach(line->{
+ if (!line.trim().isEmpty()) {
+ ExpeditionExtendedDataImporterImpl.parseLine(lineNr.incrementAndGet(), sourceName, line, columnDefinitions,
+ (timePoint, columnValues, columns)->{
+ final double latDeg = Double.parseDouble(columnValues[columns.get(LAT_COLUMN_HEADING)]);
+ final double lonDeg = Double.parseDouble(columnValues[columns.get(LON_COLUMN_HEADING)]);
+ final double cogDeg = Double.parseDouble(columnValues[columns.get(COG_COLUMN_HEADING)]);
+ final double sogKnots = Double.parseDouble(columnValues[columns.get(SOG_COLUMN_HEADING)]);
+ final GPSFixMoving fix = new GPSFixMovingImpl(new DegreePosition(latDeg, lonDeg), timePoint,
+ new KnotSpeedWithBearingImpl(sogKnots, new DegreeBearingImpl(cogDeg)));
+ callback.addFix(fix, device);
+ });
+ }
+ });
+ }
+
+ @Override
+ public Iterable getSupportedFileExtensions() {
+ return Arrays.asList(new String[] { "csv", "log", "txt" });
+ }
+
+ @Override
+ public String getType() {
+ return "Expedition";
+ }
+}
diff --git a/java/com.sap.sailing.domain.igtimiadapter.test/src/com/sap/sailing/domain/igtimiadapter/test/FixFactoryTest.java b/java/com.sap.sailing.domain.igtimiadapter.test/src/com/sap/sailing/domain/igtimiadapter/test/FixFactoryTest.java
new file mode 100755
index 00000000000..808ba392812
--- /dev/null
+++ b/java/com.sap.sailing.domain.igtimiadapter.test/src/com/sap/sailing/domain/igtimiadapter/test/FixFactoryTest.java
@@ -0,0 +1,46 @@
+package com.sap.sailing.domain.igtimiadapter.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.sap.sailing.domain.igtimiadapter.datatypes.Fix;
+import com.sap.sailing.domain.igtimiadapter.impl.FixFactory;
+import com.sap.sse.common.Util;
+
+public class FixFactoryTest {
+ private FixFactory fixFactory;
+
+ @Before
+ public void setUp() {
+ fixFactory = new FixFactory();
+ }
+
+ @Test
+ public void testUnknownFixTypes() throws ParseException {
+ final String[] messages = new String[] {
+ "{\"DC-FE-AAKG\":{\"1\":{\"t\":[1510174025500],\"1\":[170.5044476],\"2\":[-45.87697]}}}",
+ "{\"DC-FE-AAKG\":{\"2\":{\"t\":[1510174025500],\"1\":[1]}}}",
+ "{\"DC-FE-AAKG\":{\"3\":{\"t\":[1510174025500],\"1\":[10]}}}",
+ "{\"DC-FE-AAKG\":{\"7\":{\"t\":[1510174025500],\"1\":[187.7]}}}",
+ "{\"DC-FE-AAKG\":{\"11\":{\"t\":[1510174025500],\"1\":[54]}}}",
+ "{\"DC-FE-AAKG\":{\"12\":{\"t\":[1510174025500],\"1\":[1.852]}}}",
+ "{\"DC-FE-AAKG\":{\"22\":{\"t\":[1510174025500],\"1\":[263.4]}}}",
+ "{\"DC-FE-AAKG\":{\"23\":{\"t\":[1510174025500],\"1\":[1.852]}}}",
+ "{\"DC-FE-AAKG\":{\"6\":{\"t\":[1510174025500],\"1\":[0]}}}",
+ "{\"DC-FE-AAKG\":{\"9\":{\"t\":[1510174025500],\"1\":[0]}}}" };
+ List fixes = new ArrayList<>();
+ for (final String message : messages) {
+ JSONObject jsonObject = (JSONObject) new JSONParser().parse(message);
+ Util.addAll(fixFactory.createFixes(jsonObject), fixes);
+ }
+ assertTrue(!Util.isEmpty(fixes)); // this largely asserts that no exception was thrown although there were unknown fix types (22/23)
+ }
+}
diff --git a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/IgtimiConnectionFactory.java b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/IgtimiConnectionFactory.java
index 04bc60e64b3..5d14e3206f4 100755
--- a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/IgtimiConnectionFactory.java
+++ b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/IgtimiConnectionFactory.java
@@ -1,6 +1,8 @@
package com.sap.sailing.domain.igtimiadapter;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
import javax.xml.parsers.ParserConfigurationException;
@@ -32,11 +34,8 @@ public interface IgtimiConnectionFactory {
* Obtains a URL that a user agent (e.g., a web browser) can be sent to in order to allow that user to authenticate
* and then authorize this factory's {@link Client} for accessing the user's Igtimi data. The URL is chosen such that
* it redirects to the {@link AuthorizationCallback} with the code response type.
- * @param redirectProtocol TODO
- * @param redirectHost TODO
- * @param redirectPort TODO
*/
- String getAuthorizationUrl(String redirectProtocol, String redirectHost, String redirectPort);
+ String getAuthorizationUrl(String redirectProtocol, String redirectHost, String redirectPort) throws MalformedURLException, UnsupportedEncodingException;
/**
* Using the "account" service, retrieves the {@link Account} information for this access token and stores the token
diff --git a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/Activator.java b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/Activator.java
index f9c2941f1e6..14c6ed4004c 100755
--- a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/Activator.java
+++ b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/Activator.java
@@ -38,9 +38,15 @@ public class Activator implements BundleActivator {
private static final String DEFAULT_CLIENT_ID = "d29eae61621af3057db0e638232a027e96b1d2291b1b89a1481dfcac075b0bf4";
private static final String DEFAULT_CLIENT_SECRET = "537dbd14a84fcb470c91d85e8c4f8f7a356ac5ffc8727594d1bfe900ee5942ef";
+ private static final String DEFAULT_REDIRECT_PROTOCOL = "https";
+ private static final String DEFAULT_REDIRECT_HOST = "www.sapsailing.com";
+ private static final String DEFAULT_REDIRECT_PORT = null; // port==null means default
private static final String CLIENT_REDIRECT_PATH = "/igtimi/oauth/v1/authorizationcallback";
private static final String CLIENT_ID_PROPERTY_NAME = "igtimi.client.id";
private static final String CLIENT_SECRET_PROPERTY_NAME = "igtimi.client.secret";
+ private static final String CLIENT_REDIRECT_PROTOCOL_PROPERTY_NAME = "igtimi.client.redirect.protocol";
+ private static final String CLIENT_REDIRECT_HOST_PROPERTY_NAME = "igtimi.client.redirect.host";
+ private static final String CLIENT_REDIRECT_PORT_PROPERTY_NAME = "igtimi.client.redirect.port";
private final Future connectionFactory;
private final Future windTrackerFactory;
private final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactoryWithPriority(Thread.NORM_PRIORITY, /* daemon */ true));
@@ -49,7 +55,10 @@ public class Activator implements BundleActivator {
logger.info(getClass().getName()+" constructor");
final String clientId = System.getProperty(CLIENT_ID_PROPERTY_NAME, DEFAULT_CLIENT_ID);
final String clientSecret = System.getProperty(CLIENT_SECRET_PROPERTY_NAME, DEFAULT_CLIENT_SECRET);
- final Client client = new ClientImpl(clientId, clientSecret, "https", "www.sapsailing.com", /* port==null means default */ null, CLIENT_REDIRECT_PATH);
+ final String clientRedirectProtocol = System.getProperty(CLIENT_REDIRECT_PROTOCOL_PROPERTY_NAME, DEFAULT_REDIRECT_PROTOCOL);
+ final String clientRedirectHost = System.getProperty(CLIENT_REDIRECT_HOST_PROPERTY_NAME, DEFAULT_REDIRECT_HOST);
+ final String clientRedirectPort = System.getProperty(CLIENT_REDIRECT_PORT_PROPERTY_NAME, DEFAULT_REDIRECT_PORT);
+ final Client client = new ClientImpl(clientId, clientSecret, clientRedirectProtocol, clientRedirectHost, clientRedirectPort, CLIENT_REDIRECT_PATH);
final DomainObjectFactory domainObjectFactory = PersistenceFactory.INSTANCE.getDefaultDomainObjectFactory();
final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory();
connectionFactory = executor.submit(new Callable() {
diff --git a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/FixFactory.java b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/FixFactory.java
index 71700a8136e..83d1e869d5b 100755
--- a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/FixFactory.java
+++ b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/FixFactory.java
@@ -54,9 +54,12 @@ public class FixFactory {
Sensor sensor = new SensorImpl(deviceSerialNumber,
fixTypeAndOptionalColonSeparatedSensorsSubId.length < 2 ? 0
: Long.valueOf(fixTypeAndOptionalColonSeparatedSensorsSubId[1]));
- Fix fix = createFix(sensor, Type.valueOf(fixType), timePoint, valuesPerSubindex);
- result.add(fix);
- fixIndex++;
+ final Type ft = Type.valueOf(fixType);
+ if (ft != null) {
+ Fix fix = createFix(sensor, ft, timePoint, valuesPerSubindex);
+ result.add(fix);
+ fixIndex++;
+ }
}
}
return result;
diff --git a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/IgtimiConnectionFactoryImpl.java b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/IgtimiConnectionFactoryImpl.java
index f3ea520e9cb..b75b3f4c482 100755
--- a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/IgtimiConnectionFactoryImpl.java
+++ b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/impl/IgtimiConnectionFactoryImpl.java
@@ -3,8 +3,10 @@ package com.sap.sailing.domain.igtimiadapter.impl;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
@@ -31,7 +33,6 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.client.SystemDefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.simple.JSONArray;
@@ -51,6 +52,7 @@ import com.sap.sailing.domain.igtimiadapter.datatypes.Type;
import com.sap.sailing.domain.igtimiadapter.persistence.DomainObjectFactory;
import com.sap.sailing.domain.igtimiadapter.persistence.MongoObjectFactory;
import com.sap.sse.common.TimePoint;
+import com.sap.sse.util.LaxRedirectStrategyForAllRedirectResponseCodes;
public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory {
private static final Logger logger = Logger.getLogger(IgtimiConnectionFactoryImpl.class.getName());
@@ -321,9 +323,17 @@ public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory {
}
@Override
- public String getAuthorizationUrl(String redirectProtocol, String redirectHost, String redirectPort) {
+ public String getAuthorizationUrl(String redirectProtocol, String redirectHost, String redirectPortAsString) throws MalformedURLException, UnsupportedEncodingException {
+ final URL redirectTarget;
+ int redirectPort;
+ if (redirectPortAsString == null || redirectPortAsString.trim().isEmpty() || (redirectPort=Integer.valueOf(redirectPortAsString)) == 0) {
+ redirectTarget = new URL(redirectProtocol, redirectHost, /* file */ "");
+ } else {
+ redirectTarget = new URL(redirectProtocol, redirectHost, redirectPort, /* file */ "");
+ }
return getBaseUrl()+"/oauth/authorize?response_type=code&client_id="+getClient().getId()+
- "&redirect_uri="+client.getRedirectUri(redirectProtocol, redirectHost, redirectPort);
+ "&redirect_uri="+URLEncoder.encode(client.getDefaultRedirectUri(), "UTF-8")
+ + "&state="+URLEncoder.encode(redirectTarget.toString(), "UTF-8");
}
private Client getClient() {
@@ -373,7 +383,7 @@ public class IgtimiConnectionFactoryImpl implements IgtimiConnectionFactory {
DefaultHttpClient client = new SystemDefaultHttpClient();
CookieStore cookieStore = new BasicCookieStore();
client.setCookieStore(cookieStore);
- client.setRedirectStrategy(new LaxRedirectStrategy());
+ client.setRedirectStrategy(new LaxRedirectStrategyForAllRedirectResponseCodes());
HttpGet get = new HttpGet(getOauthAuthorizeUrl());
HttpResponse responseForAuthorize = client.execute(get);
return signInAndReturnAuthorizationForm(client, responseForAuthorize, userEmail, userPassword);
diff --git a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/oauth/AuthorizationCallback.java b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/oauth/AuthorizationCallback.java
index f2aabc8176e..ce75312a129 100755
--- a/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/oauth/AuthorizationCallback.java
+++ b/java/com.sap.sailing.domain.igtimiadapter/src/com/sap/sailing/domain/igtimiadapter/oauth/AuthorizationCallback.java
@@ -1,7 +1,9 @@
package com.sap.sailing.domain.igtimiadapter.oauth;
import java.io.IOException;
+import java.net.URI;
import java.net.URISyntaxException;
+import java.net.URLEncoder;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -33,22 +35,38 @@ public class AuthorizationCallback {
connectionFactory = Activator.getInstance().getConnectionFactory();
}
+ /**
+ * When a non-empty {@code state} parameter is passed, it is assumed to hold the base URL of the server
+ * to which to re-direct this request. In this case we're probably running on www.sapsailing.com, and
+ * an authorization request redirect callback from the Igtimi Oauth provider has reached us. The original
+ * server that requested authentication is expected to have set its base URL in the {@code state} parameter
+ * and will then receive the same call, only without the {@code state} parameter.
+ *
+ * If the {@code state} parameter is empty, the call is meant for "us" (this server instance), and the
+ * access token will be obtained from the {@code code} passed with the request.
+ */
@GET
@Produces("text/plain;charset=UTF-8")
@Path(AUTHORIZATIONCALLBACK)
- public Response obtainAccessToken(@QueryParam("code") String code) throws ClientProtocolException, IOException, IllegalStateException, ParseException, URISyntaxException {
+ public Response obtainAccessToken(@QueryParam("code") String code, @QueryParam("state") String state)
+ throws ClientProtocolException, IOException, IllegalStateException, ParseException, URISyntaxException {
Response result;
- if (code != null) {
- try {
- connectionFactory.obtainAccessTokenFromAuthorizationCode(code);
- result = Response.ok().entity("SAP Sailing Analytics authorized successfully to access user's tracks").build();
- } catch (Exception e) {
- result = Response.status(Status.UNAUTHORIZED).entity(e.getMessage()).build();
- logger.log(Level.SEVERE, "Error trying to obtain access token from authentication code " + code, e);
- }
+ if (state != null) {
+ // redirect to the server whose base URL is contained in the state parameter
+ result = Response.temporaryRedirect(new URI(state+"/igtimi/oauth/v1"+AUTHORIZATIONCALLBACK+"?code="+URLEncoder.encode(code, "UTF-8"))).build();
} else {
- result = Response.status(Status.UNAUTHORIZED).entity("code parameter not found in request").build();
- logger.log(Level.SEVERE, "Authentication code not found in request");
+ if (code != null) {
+ try {
+ connectionFactory.obtainAccessTokenFromAuthorizationCode(code);
+ result = Response.ok().entity("SAP Sailing Analytics authorized successfully to access user's tracks").build();
+ } catch (Exception e) {
+ result = Response.status(Status.UNAUTHORIZED).entity(e.getMessage()).build();
+ logger.log(Level.SEVERE, "Error trying to obtain access token from authentication code " + code, e);
+ }
+ } else {
+ result = Response.status(Status.UNAUTHORIZED).entity("code parameter not found in request").build();
+ logger.log(Level.SEVERE, "Authentication code not found in request");
+ }
}
return result;
}
diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/DomainObjectFactory.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/DomainObjectFactory.java
index 41925366e0e..f92b84e6a8a 100755
--- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/DomainObjectFactory.java
+++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/DomainObjectFactory.java
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.persistence;
+import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Map;
@@ -11,6 +12,7 @@ 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.anniversary.DetailedRaceInfo;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Event;
@@ -23,6 +25,7 @@ import com.sap.sailing.domain.base.configuration.DeviceConfiguration;
import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.WindSource;
+import com.sap.sailing.domain.common.dto.AnniversaryType;
import com.sap.sailing.domain.leaderboard.EventResolver;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
@@ -194,4 +197,9 @@ public interface DomainObjectFactory {
RegattaLeaderboardWithEliminations loadRegattaLeaderboardWithEliminations(DBObject dbLeaderboard,
String leaderboardName, String wrappedRegattaLeaderboardName, LeaderboardRegistry leaderboardRegistry);
+
+ /**
+ * Loads all stored anniversary races.
+ */
+ Map extends Integer, ? extends Pair> getAnniversaryData() throws MalformedURLException;
}
diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/MongoObjectFactory.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/MongoObjectFactory.java
index e196204e2e3..84ea757462e 100755
--- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/MongoObjectFactory.java
+++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/MongoObjectFactory.java
@@ -2,9 +2,11 @@ package com.sap.sailing.domain.persistence;
import java.io.Serializable;
import java.net.URL;
+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.Competitor;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.domain.base.RaceDefinition;
@@ -15,6 +17,7 @@ import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.configuration.DeviceConfiguration;
import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher;
import com.sap.sailing.domain.common.WindSource;
+import com.sap.sailing.domain.common.dto.AnniversaryType;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
@@ -22,6 +25,7 @@ import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegatta;
+import com.sap.sse.common.Util.Pair;
/**
* Offers methods to construct {@link DBObject MongoDB objects} from domain objects.
@@ -181,4 +185,9 @@ public interface MongoObjectFactory {
* objects obtained through {@link DomainObjectFactory#loadConnectivityParametersForRacesToRestore(Consumer)}.
*/
void removeAllConnectivityParametersForRacesToRestore();
+
+ /**
+ * Stores determined Anniversary races.
+ */
+ void storeAnniversaryData(ConcurrentHashMap> knownAnniversaries);
}
diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/CollectionNames.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/CollectionNames.java
index 2651cd72545..29f55619367 100755
--- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/CollectionNames.java
+++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/CollectionNames.java
@@ -107,4 +107,9 @@ public enum CollectionNames {
* way by corresponding implementations of the RaceTrackingConnectivityParametersMongoHandler} interface.
*/
CONNECTIVITY_PARAMS_FOR_RACES_TO_BE_RESTORED,
+
+ /**
+ * Contains the known anniversaries
+ */
+ ANNIVERSARIES
}
diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java
index db509e2f7a1..a8bdcb83c67 100644
--- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java
+++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java
@@ -39,6 +39,7 @@ import com.mongodb.WriteResult;
import com.mongodb.util.JSON;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
+import com.sap.sailing.domain.abstractlog.race.CompetitorResult.MergeState;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogCourseAreaChangedEvent;
@@ -101,14 +102,18 @@ 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.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.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.abstractlog.regatta.events.impl.AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogCloseOpenEndedDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDefineMarkEventImpl;
+import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorBravoMappingEventImpl;
+import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl;
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.events.impl.RegattaLogRegisterCompetitorEventImpl;
@@ -116,6 +121,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRevokeEv
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogSetCompetitorTimeOnDistanceAllowancePerNauticalMileEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogSetCompetitorTimeOnTimeFactorEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
+import com.sap.sailing.domain.anniversary.DetailedRaceInfo;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
@@ -150,6 +156,7 @@ import com.sap.sailing.domain.base.impl.SeriesImpl;
import com.sap.sailing.domain.base.impl.VenueImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.CourseDesignerMode;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.MarkType;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.PassingInstruction;
@@ -163,6 +170,8 @@ import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
+import com.sap.sailing.domain.common.dto.AnniversaryType;
+import com.sap.sailing.domain.common.dto.EventType;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
@@ -199,7 +208,6 @@ import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongo
import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.racelog.RaceLogStore;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.impl.PlaceHolderDeviceIdentifierSerializationHandler;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.ranking.RankingMetricConstructor;
@@ -1594,8 +1602,15 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
final Long finishingTimePointAsMillis = (Long) dbObject.get(FieldNames.RACE_LOG_FINISHING_TIME_AS_MILLIS.name());
final TimePoint finishingTime = finishingTimePointAsMillis == null ? null : new MillisecondsTimePoint(finishingTimePointAsMillis);
final String comment = (String) dbObject.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name());
+ final String mergeStateAsString = (String) dbObject.get(FieldNames.LEADERBOARD_SCORE_CORRECTION_MERGE_STATE.name());
+ final MergeState mergeState;
+ if (mergeStateAsString == null) {
+ mergeState = MergeState.OK;
+ } else {
+ mergeState = MergeState.valueOf(mergeStateAsString);
+ }
CompetitorResultImpl positionedCompetitor = new CompetitorResultImpl(
- competitorId, competitorDisplayName, rank == null ? rankCounter : rank, maxPointsReason, score, finishingTime, comment);
+ competitorId, competitorDisplayName, rank == null ? rankCounter : rank, maxPointsReason, score, finishingTime, comment, mergeState);
positionedCompetitors.add(positionedCompetitor);
rankCounter++;
}
@@ -1704,6 +1719,12 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
} else if (eventClass.equals(RegattaLogDeviceCompetitorBravoMappingEventImpl.class.getSimpleName())) {
return loadRegattaLogDeviceCompetitorBravoMappingEvent(createdAt, author, logicalTimePoint, id, dbObject,
regattaLogIdentifier, o);
+ } else if (eventClass.equals(RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl.class.getSimpleName())) {
+ return loadRegattaLogDeviceCompetitorBravoExtendedMappingEvent(createdAt, author, logicalTimePoint, id, dbObject,
+ regattaLogIdentifier, o);
+ } else if (eventClass.equals(RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl.class.getSimpleName())) {
+ return loadRegattaLogDeviceCompetitorExpeditionExtendedMappingEvent(createdAt, author, logicalTimePoint, id, dbObject,
+ regattaLogIdentifier, o);
} else if (eventClass.equals(RegattaLogDeviceMarkMappingEvent.class.getSimpleName())) {
return loadRegattaLogDeviceMarkMappingEvent(createdAt, author, logicalTimePoint, id, dbObject, regattaLogIdentifier, o);
} else if (eventClass.equals(RegattaLogCloseOpenEndedDeviceMappingEvent.class.getSimpleName())) {
@@ -1891,6 +1912,28 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
private RegattaLogDeviceCompetitorBravoMappingEventImpl loadRegattaLogDeviceCompetitorBravoMappingEvent(
TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id,
final DBObject dbObject, RegattaLikeIdentifier regattaLogIdentifier, DBObject outerDBObject) {
+ return loadRegattaLogDeviceCompetitorSensorDataMappingEvent(createdAt, author, logicalTimePoint, id, dbObject,
+ regattaLogIdentifier, outerDBObject, RegattaLogDeviceCompetitorBravoMappingEventImpl::new);
+ }
+
+ private RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl loadRegattaLogDeviceCompetitorBravoExtendedMappingEvent(
+ TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id,
+ final DBObject dbObject, RegattaLikeIdentifier regattaLogIdentifier, DBObject outerDBObject) {
+ return loadRegattaLogDeviceCompetitorSensorDataMappingEvent(createdAt, author, logicalTimePoint, id, dbObject,
+ regattaLogIdentifier, outerDBObject, RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl::new);
+ }
+
+ private RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl loadRegattaLogDeviceCompetitorExpeditionExtendedMappingEvent(
+ TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id,
+ final DBObject dbObject, RegattaLikeIdentifier regattaLogIdentifier, DBObject outerDBObject) {
+ return loadRegattaLogDeviceCompetitorSensorDataMappingEvent(createdAt, author, logicalTimePoint, id, dbObject,
+ regattaLogIdentifier, outerDBObject, RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl::new);
+ }
+
+ private MappingT loadRegattaLogDeviceCompetitorSensorDataMappingEvent(
+ TimePoint createdAt, AbstractLogEventAuthor author, TimePoint logicalTimePoint, Serializable id,
+ final DBObject dbObject, RegattaLikeIdentifier regattaLogIdentifier, DBObject outerDBObject,
+ AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl.Factory factory) {
DeviceIdentifier device = null;
try {
device = loadDeviceId(deviceIdentifierServiceFinder, (DBObject) dbObject.get(FieldNames.DEVICE_ID.name()));
@@ -1911,7 +1954,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
final TimePoint from = times.getA();
final TimePoint to = times.getB();
final boolean needsMigration = times.getC();
- final RegattaLogDeviceCompetitorBravoMappingEventImpl result = new RegattaLogDeviceCompetitorBravoMappingEventImpl(
+ final MappingT result = factory.create(
createdAt, logicalTimePoint, author, id, mappedTo, device, from, to);
if (needsMigration) {
// remove old version of mapping event
@@ -2366,4 +2409,57 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
};
}
+
+ @Override
+ public Map> getAnniversaryData() throws MalformedURLException {
+ HashMap> fromDb = new HashMap<>();
+ DBCollection anniversarysStored = database.getCollection(CollectionNames.ANNIVERSARIES.name());
+ DBCursor cursor = anniversarysStored.find();
+ while (cursor.hasNext()) {
+ DBObject toLoad = cursor.next();
+ String leaderboardName = toLoad.get(FieldNames.LEADERBOARD_NAME.name()).toString();
+ String eventID = toLoad.get(FieldNames.EVENT_ID.name()).toString();
+
+ final Object mongoDisplayName = toLoad.get(FieldNames.LEADERBOARD_DISPLAY_NAME.name());
+ final String leaderboardDisplayName;
+ if (mongoDisplayName == null) {
+ leaderboardDisplayName = null;
+ } else {
+ leaderboardDisplayName = mongoDisplayName.toString();
+ }
+ final Object mongoEventName = toLoad.get(FieldNames.EVENT_NAME.name());
+ final String eventName;
+ if (mongoEventName == null) {
+ eventName = null;
+ } else {
+ eventName = mongoEventName.toString();
+ }
+
+ TimePoint startOfRace = new MillisecondsTimePoint(
+ ((Number) toLoad.get(FieldNames.START_OF_RACE.name())).longValue());
+ String race = toLoad.get(FieldNames.RACE_NAME.name()).toString();
+ String regatta = toLoad.get(FieldNames.REGATTA_NAME.name()).toString();
+ Object rurl = toLoad.get(FieldNames.REMOTE_URL.name());
+ final URL remoteUrlOrNull;
+ if (rurl != null) {
+ remoteUrlOrNull = new URL(rurl.toString());
+ } else {
+ remoteUrlOrNull = null;
+ }
+ final Object typeJson = toLoad.get(FieldNames.EVENT_TYPE.name());
+ final EventType eventType;
+ if (typeJson == null) {
+ eventType = null;
+ } else {
+ eventType = EventType.valueOf(typeJson.toString());
+ }
+ DetailedRaceInfo loadedAnniversary = new DetailedRaceInfo(new RegattaNameAndRaceName(regatta, race),
+ leaderboardName, leaderboardDisplayName, startOfRace, UUID.fromString(eventID), eventName, eventType,
+ remoteUrlOrNull);
+ int anniversary = ((Number) toLoad.get(FieldNames.ANNIVERSARY_NUMBER.name())).intValue();
+ String type = toLoad.get(FieldNames.ANNIVERSARY_TYPE.name()).toString();
+ fromDb.put(anniversary, new Pair<>(loadedAnniversary, AnniversaryType.valueOf(type)));
+ }
+ return fromDb;
+ }
}
diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java
index 0f0509aa82b..a3dfe0b6343 100644
--- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java
+++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java
@@ -80,7 +80,8 @@ public enum FieldNames {
LEADERBOARD_IS_MEDAL_RACE_COLUMN, LEADERBOARD_CARRIED_POINTS, LEADERBOARD_CARRIED_POINTS_BY_ID,
LEADERBOARD_SCORE_CORRECTIONS, LEADERBOARD_DISCARDING_THRESHOLDS,
LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON, LEADERBOARD_CORRECTED_SCORE, LEADERBOARD_SCORE_CORRECTION_TIMESTAMP,
- LEADERBOARD_RANK, LEADERBOARD_SCORE_CORRECTION_COMMENT, LEADERBOARD_COLUMN_FACTORS, WRAPPED_REGATTA_LEADERBOARD_NAME,
+ LEADERBOARD_RANK, LEADERBOARD_SCORE_CORRECTION_COMMENT, LEADERBOARD_SCORE_CORRECTION_MERGE_STATE,
+ LEADERBOARD_COLUMN_FACTORS, WRAPPED_REGATTA_LEADERBOARD_NAME,
ELMINATED_COMPETITORS,
// leaderboard group
@@ -161,5 +162,8 @@ public enum FieldNames {
SAILORS_INFO_URL, SAILORS_INFO_LOCALE,
// double vector fixes
- FIX;
+ FIX,
+
+ //anniversary fields
+ START_OF_RACE, ANNIVERSARY_NUMBER, REMOTE_URL, ANNIVERSARY_TYPE, EVENT_TYPE;
}
diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java
index 6bf58f9873f..feed1f28979 100644
--- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java
+++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java
@@ -7,6 +7,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -62,7 +63,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRegisterCompe
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.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorBravoMappingEventImpl;
+import com.sap.sailing.domain.anniversary.DetailedRaceInfo;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.ControlPoint;
import com.sap.sailing.domain.base.ControlPointWithTwoMarks;
@@ -85,6 +86,7 @@ import com.sap.sailing.domain.base.configuration.RegattaConfiguration;
import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherSingle;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.common.Bearing;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.PassingInstruction;
import com.sap.sailing.domain.common.Positioned;
@@ -93,6 +95,7 @@ import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.WindSource;
+import com.sap.sailing.domain.common.dto.AnniversaryType;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.Leaderboard;
@@ -106,7 +109,6 @@ import com.sap.sailing.domain.persistence.MongoObjectFactory;
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.PlaceHolderDeviceIdentifierMongoHandler;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler;
@@ -125,6 +127,7 @@ import com.sap.sse.common.Timed;
import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
import com.sap.sse.common.Util;
+import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.shared.media.ImageDescriptor;
import com.sap.sse.shared.media.VideoDescriptor;
@@ -1236,6 +1239,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
result.put(FieldNames.RACE_LOG_FINISHING_TIME_AS_MILLIS.name(), competitorResult.getFinishingTime() == null ? null : competitorResult.getFinishingTime().asMillis());
result.put(FieldNames.LEADERBOARD_RANK.name(), competitorResult.getOneBasedRank());
result.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_COMMENT.name(), competitorResult.getComment());
+ result.put(FieldNames.LEADERBOARD_SCORE_CORRECTION_MERGE_STATE.name(), competitorResult.getMergeState().name());
return result;
}
@@ -1473,7 +1477,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
public void storeRegattaLogEvent(RegattaLikeIdentifier regattaLikeId,
RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
DBObject result = createBasicRegattaLogEventDBObject(event);
- result.put(FieldNames.REGATTA_LOG_EVENT_CLASS.name(), RegattaLogDeviceCompetitorBravoMappingEventImpl.class.getSimpleName());
+ 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.COMPETITOR_ID.name(), event.getMappedTo().getId());
storeRegattaLogEvent(regattaLikeId, result);
@@ -1630,4 +1634,35 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
database.getCollection(CollectionNames.CONNECTIVITY_PARAMS_FOR_RACES_TO_BE_RESTORED.name()).drop();
}
+ @Override
+ public void storeAnniversaryData(
+ ConcurrentHashMap> knownAnniversaries) {
+ try {
+ DBCollection anniversarysStored = database.getCollection(CollectionNames.ANNIVERSARIES.name());
+ for (Entry> anniversary : knownAnniversaries.entrySet()) {
+ BasicDBObject currentProxy = new BasicDBObject(FieldNames.ANNIVERSARY_NUMBER.name(),
+ anniversary.getKey().intValue());
+ BasicDBObject newValue = new BasicDBObject(FieldNames.ANNIVERSARY_NUMBER.name(),
+ anniversary.getKey().intValue());
+ DetailedRaceInfo raceInfo = anniversary.getValue().getA();
+ newValue.append(FieldNames.RACE_NAME.name(), raceInfo.getIdentifier().getRaceName());
+ newValue.append(FieldNames.REGATTA_NAME.name(), raceInfo.getIdentifier().getRegattaName());
+ newValue.append(FieldNames.LEADERBOARD_NAME.name(), raceInfo.getLeaderboardName());
+ newValue.append(FieldNames.LEADERBOARD_DISPLAY_NAME.name(), raceInfo.getLeaderboardDisplayName());
+ storeTimePoint(raceInfo.getStartOfRace(), newValue, (FieldNames.START_OF_RACE.name()));
+ newValue.append(FieldNames.EVENT_ID.name(), raceInfo.getEventID().toString());
+ newValue.append(FieldNames.EVENT_NAME.name(), raceInfo.getEventName());
+ newValue.append(FieldNames.EVENT_TYPE.name(),
+ raceInfo.getEventType() == null ? null : raceInfo.getEventType().name());
+
+ final URL remoteUrl = raceInfo.getRemoteUrl();
+ newValue.append(FieldNames.REMOTE_URL.name(), remoteUrl == null ? null : remoteUrl.toExternalForm());
+ newValue.append(FieldNames.ANNIVERSARY_TYPE.name(), anniversary.getValue().getB().toString());
+ anniversarysStored.update(currentProxy, newValue, true, false);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
}
diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/DoubleVectorFixMongoHandlerImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/DoubleVectorFixMongoHandlerImpl.java
index c39f4e58069..7d4043b0e56 100644
--- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/DoubleVectorFixMongoHandlerImpl.java
+++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/DoubleVectorFixMongoHandlerImpl.java
@@ -38,20 +38,20 @@ public class DoubleVectorFixMongoHandlerImpl implements FixMongoHandler dbValues = (List) dbObject;
- double[] result = new double[dbValues.size()];
- for(int i = 0 ; i < dbValues.size() ; i++) {
- result[i] = dbValues.get(i).doubleValue();
+ Double[] result = new Double[dbValues.size()];
+ for (int i = 0 ; i < dbValues.size() ; i++) {
+ result[i] = dbValues.get(i) == null ? null : dbValues.get(i).doubleValue();
}
return result;
}
diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoSensorFixStoreImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoSensorFixStoreImpl.java
index d9cf59b0009..9459a46b8ed 100644
--- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoSensorFixStoreImpl.java
+++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/MongoSensorFixStoreImpl.java
@@ -20,6 +20,7 @@ import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.persistence.DomainObjectFactory;
import com.sap.sailing.domain.persistence.MongoObjectFactory;
@@ -30,7 +31,6 @@ import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongo
import com.sap.sailing.domain.persistence.racelog.tracking.FixMongoHandler;
import com.sap.sailing.domain.persistence.racelog.tracking.MongoSensorFixStore;
import com.sap.sailing.domain.racelog.tracking.FixReceivedListener;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sse.common.Duration;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
@@ -325,9 +325,7 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
throws TransformationException, NoCorrespondingServiceRegisteredException {
Map result = new HashMap<>();
for (final DeviceIdentifier deviceIdentifier : forDevices) {
- final DBObject deviceQuery = new BasicDBObject(
- FieldNames.DEVICE_ID.name() + "." + FieldNames.DEVICE_TYPE_SPECIFIC_ID.name(),
- deviceIdentifier.getStringRepresentation());
+ final DBObject deviceQuery = getDeviceQuery(deviceIdentifier);
final DBObject orderBy = new BasicDBObject(
FieldNames.GPSFIX.name() + "." + FieldNames.TIME_AS_MILLIS.name(), -1);
DBCursor lastFixForDeviceCursor = fixesCollection.find(deviceQuery).sort(orderBy).limit(1);
diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/PlaceHolderDeviceIdentifierMongoHandler.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/PlaceHolderDeviceIdentifierMongoHandler.java
index ee3ee4fe186..ccf0364559e 100644
--- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/PlaceHolderDeviceIdentifierMongoHandler.java
+++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/racelog/tracking/impl/PlaceHolderDeviceIdentifierMongoHandler.java
@@ -1,8 +1,8 @@
package com.sap.sailing.domain.persistence.racelog.tracking.impl;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.impl.PlaceHolderDeviceIdentifierSerializationHandler;
public class PlaceHolderDeviceIdentifierMongoHandler extends PlaceHolderDeviceIdentifierSerializationHandler
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java
index 2a74622a15d..dcb29f6b6e5 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/AbstractGPSFixStoreTest.java
@@ -24,6 +24,7 @@ import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Sideline;
import com.sap.sailing.domain.base.impl.RegattaImpl;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
@@ -38,7 +39,6 @@ import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.racelog.tracking.test.mock.MockDeviceAndSessionIdentifierWithGPSFixesDeserializer;
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java
index 33176ca2846..4c9f475b7f3 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java
@@ -36,6 +36,7 @@ import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SeriesImpl;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
@@ -47,7 +48,6 @@ import com.sap.sailing.domain.leaderboard.impl.HighPoint;
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter;
import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory;
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.RaceLogFixTrackerManager;
@@ -209,7 +209,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
// stop tracking, then no more fixes arrive at race
service.getRaceTrackerById(raceLog.getId()).stop(false);
- raceLogFixTrackerManager.stop(false);
+ raceLogFixTrackerManager.stop(/* preemptive */ false, /* willBeRemoved */ false);
addFixes3(race, comp1, dev1);
}
@@ -289,7 +289,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
// stop tracking, then no more fixes arrive at race
service.getRaceTrackerById(raceLog.getId()).stop(/* preemptive */ false);
- raceLogFixTrackerManager.stop(false);
+ raceLogFixTrackerManager.stop(false, /* willBeRemoved */ false);
addFixes3(race, comp1, dev1);
}
}
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/DeviceMappingsAndSensorFixStoreLockingTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/DeviceMappingsAndSensorFixStoreLockingTest.java
index 2a23fcdeda4..383942f7784 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/DeviceMappingsAndSensorFixStoreLockingTest.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/DeviceMappingsAndSensorFixStoreLockingTest.java
@@ -16,9 +16,9 @@ import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCo
import com.sap.sailing.domain.abstractlog.regatta.impl.RegattaLogImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.tracking.impl.DoubleVectorFixImpl;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.RegattaLogDeviceMappings;
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
import com.sap.sse.common.MultiTimeRange;
@@ -76,7 +76,7 @@ public class DeviceMappingsAndSensorFixStoreLockingTest extends AbstractGPSFixSt
};
}.start();
- store.storeFix(device, new DoubleVectorFixImpl(new MillisecondsTimePoint(1), new double[]{0.0}));
+ store.storeFix(device, new DoubleVectorFixImpl(new MillisecondsTimePoint(1), new Double[]{0.0}));
}
}
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/GPSFixStoreListenerTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/GPSFixStoreListenerTest.java
index bab51469897..2174d0718e8 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/GPSFixStoreListenerTest.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/GPSFixStoreListenerTest.java
@@ -9,10 +9,10 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.persistence.racelog.tracking.impl.MongoSensorFixStoreImpl;
import com.sap.sailing.domain.racelog.tracking.FixReceivedListener;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
public class GPSFixStoreListenerTest extends AbstractGPSFixStoreTest {
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/RaceLogFixTrackerManagerTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/RaceLogFixTrackerManagerTest.java
index bddfc87bf0b..5558db801d9 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/RaceLogFixTrackerManagerTest.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/RaceLogFixTrackerManagerTest.java
@@ -31,6 +31,7 @@ import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
@@ -45,7 +46,6 @@ import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
import com.sap.sailing.domain.racelogsensortracking.SensorFixMapperFactory;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.RaceLogFixTrackerManager;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
@@ -119,7 +119,7 @@ public class RaceLogFixTrackerManagerTest {
throw new IllegalArgumentException("Unknown event type");
}
});
- raceLogFixTrackerManager.stop(false);
+ raceLogFixTrackerManager.stop(/* preemptive */ false, /* willBeRemoved */ false);
}
/**
@@ -140,6 +140,6 @@ public class RaceLogFixTrackerManagerTest {
}
});
trackedRace.attachRaceLog(raceLog2);
- raceLogFixTrackerManager.stop(false);
+ raceLogFixTrackerManager.stop(/* preemptive */ false, /* willBeRemoved */ false);
}
}
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java
index 3886aa96e8e..383919426b2 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreAndLoadTest.java
@@ -54,7 +54,10 @@ import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.Distance;
+import com.sap.sailing.domain.common.Position;
+import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
@@ -75,12 +78,12 @@ import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
import com.sap.sailing.domain.racelogsensortracking.SensorFixMapperFactory;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.impl.BravoDataFixMapper;
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.FixLoaderAndTracker;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.tracking.BravoFixTrack;
+import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.DynamicSensorFixTrack;
import com.sap.sailing.domain.tracking.DynamicTrack;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
@@ -92,6 +95,7 @@ import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.domain.tracking.impl.SensorFixTrackImpl;
+import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Timed;
import com.sap.sse.common.Util.Pair;
@@ -178,95 +182,65 @@ public class SensorFixStoreAndLoadTest {
public void testLoadAlreadyAddedFixes() throws InterruptedException {
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
-
addBravoFixes();
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
trackedRace.waitForLoadingToFinish();
-
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
public void testAddFixesWhileTracking() throws InterruptedException {
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
addBravoFixes();
-
trackedRace.waitForLoadingToFinish();
-
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
public void testNoFixesAreLoadedIfNoStoredFixIsInTimeRange() throws InterruptedException {
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
device, new MillisecondsTimePoint(AFTER_LAST_FIX), new MillisecondsTimePoint(END_OF_TRACKING)));
-
addBravoFixes();
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
trackedRace.waitForLoadingToFinish();
-
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 0);
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
public void testFixesNotInMappedTimeRangeAreIgnoredWhileTracking() throws InterruptedException {
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
device, new MillisecondsTimePoint(AFTER_LAST_FIX), new MillisecondsTimePoint(END_OF_TRACKING)));
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
addBravoFixes();
-
trackedRace.waitForLoadingToFinish();
-
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 0);
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
public void testCompetitorWithoutMappingHasNoTrack() throws InterruptedException {
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
-
addBravoFixes();
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
trackedRace.waitForLoadingToFinish();
-
assertNull(trackedRace.getSensorTrack(comp2, BravoFixTrack.TRACK_NAME));
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -275,20 +249,14 @@ public class SensorFixStoreAndLoadTest {
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp2,
device, new MillisecondsTimePoint(MID_OF_TRACKING + 1), new MillisecondsTimePoint(END_OF_TRACKING)));
-
addBravoFixes();
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
trackedRace.waitForLoadingToFinish();
-
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
testNumberOfRawFixes(trackedRace.getSensorTrack(comp2, BravoFixTrack.TRACK_NAME), 1);
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -297,19 +265,13 @@ public class SensorFixStoreAndLoadTest {
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
device, new MillisecondsTimePoint(MID_OF_TRACKING + 1), new MillisecondsTimePoint(END_OF_TRACKING)));
-
addBravoFixes();
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
trackedRace.waitForLoadingToFinish();
-
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 3);
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -319,19 +281,13 @@ public class SensorFixStoreAndLoadTest {
new MillisecondsTimePoint(MID_OF_TRACKING));
regattaLog.add(mappingEvent);
regattaLog.add(new RegattaLogRevokeEventImpl(author, mappingEvent, "Test purposes"));
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
addBravoFixes();
-
trackedRace.waitForLoadingToFinish();
-
assertNull(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME));
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -342,24 +298,17 @@ public class SensorFixStoreAndLoadTest {
new MillisecondsTimePoint(END_OF_TRACKING));
regattaLog.add(mappingEvent);
regattaLog.add(new RegattaLogRevokeEventImpl(author, mappingEvent, "Test purposes"));
-
// non-revoked mapping timestamp 100-200
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
addBravoFixes();
-
trackedRace.waitForLoadingToFinish();
-
// Only Fixes from 100 to 200 may be included
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -371,26 +320,17 @@ public class SensorFixStoreAndLoadTest {
RegattaLogCloseOpenEndedDeviceMappingEventImpl closeEvent = new RegattaLogCloseOpenEndedDeviceMappingEventImpl(
new MillisecondsTimePoint(4), author, mappingEventId, new MillisecondsTimePoint(MID_OF_TRACKING));
regattaLog.add(closeEvent);
-
addBravoFixes();
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
trackedRace.waitForLoadingToFinish();
-
BravoFixTrack bravoFixTrack = trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME);
-
testNumberOfRawFixes(bravoFixTrack, 2);
-
regattaLog.add(new RegattaLogRevokeEventImpl(author, closeEvent, "Test purposes"));
-
trackedRace.waitForLoadingToFinish();
testNumberOfRawFixes(bravoFixTrack, 3);
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -405,7 +345,7 @@ public class SensorFixStoreAndLoadTest {
BravoFixTrack bravoFixTrack = trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME);
assertEquals(FIX_RIDE_HEIGHT,
bravoFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP)).getRideHeight());
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -414,21 +354,15 @@ public class SensorFixStoreAndLoadTest {
deviceTest, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
-
addTestFixes();
addBravoFixes();
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
trackedRace.waitForLoadingToFinish();
-
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, TestFixTrackImpl.TRACK_NAME), 1);
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -437,22 +371,15 @@ public class SensorFixStoreAndLoadTest {
deviceTest, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(MID_OF_TRACKING)));
-
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
addTestFixes();
addBravoFixes();
-
trackedRace.waitForLoadingToFinish();
-
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, TestFixTrackImpl.TRACK_NAME), 1);
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 2);
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -461,18 +388,12 @@ public class SensorFixStoreAndLoadTest {
deviceTest, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(END_OF_TRACKING)));
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(END_OF_TRACKING)));
-
-
FixLoaderAndTracker fixLoaderAndTracker = createFixLoaderAndTracker();
-
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
-
addTestFixes();
addBravoFixes();
-
trackedRace.waitForLoadingToFinish();
-
BravoFixTrack bravoFixTrack = trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME);
assertEquals(FIX_RIDE_HEIGHT,
bravoFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP)).getRideHeight());
@@ -480,12 +401,10 @@ public class SensorFixStoreAndLoadTest {
bravoFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP2)).getRideHeight());
assertEquals(FIX_RIDE_HEIGHT3,
bravoFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP3)).getRideHeight());
-
TestFixTrackImpl testFixTrack = trackedRace.getSensorTrack(comp, TestFixTrackImpl.TRACK_NAME);
assertEquals(FIX_TEST_VALUE,
testFixTrack.getFirstFixAtOrAfter(new MillisecondsTimePoint(FIX_TIMESTAMP)).getTestValue());
-
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
private void addBravoFixes() {
@@ -501,7 +420,6 @@ public class SensorFixStoreAndLoadTest {
}
private FixLoaderAndTracker createFixLoaderAndTracker() {
-
return new FixLoaderAndTracker(trackedRace, store, new SensorFixMapperFactory() {
private TestDataFixMapper testDataFixMapper = new TestDataFixMapper();
private BravoDataFixMapper bravoDataFixMapper = new BravoDataFixMapper();
@@ -542,7 +460,7 @@ public class SensorFixStoreAndLoadTest {
}
private DoubleVectorFix createBravoDoubleVectorFixWithRideHeight(long timestamp, double rideHeight) {
- double[] fixData = new double[BravoSensorDataMetadata.getTrackColumnCount()];
+ Double[] fixData = new Double[BravoSensorDataMetadata.getTrackColumnCount()];
// fill the port/starboard columns as well because their minimum defines the true ride height
fixData[BravoSensorDataMetadata.RIDE_HEIGHT_PORT_HULL.getColumnIndex()] = rideHeight;
fixData[BravoSensorDataMetadata.RIDE_HEIGHT_STBD_HULL.getColumnIndex()] = rideHeight;
@@ -554,7 +472,7 @@ public class SensorFixStoreAndLoadTest {
}
private DoubleVectorFix createTestDoubleVectorFixWithTestValue(long timestamp, double testValue) {
- double[] fixData = new double[TestFixImpl.COLUMNS.size()];
+ Double[] fixData = new Double[TestFixImpl.COLUMNS.size()];
fixData[TestFixImpl.TEST_COLUMN_INDEX] = testValue;
return new DoubleVectorFixImpl(new MillisecondsTimePoint(timestamp), fixData);
}
@@ -679,7 +597,7 @@ public class SensorFixStoreAndLoadTest {
trackedRace.waitForLoadingToFinish();
assertNotNull(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME));
assertNotNull(trackedRace.getSensorTrack(comp2, BravoFixTrack.TRACK_NAME));
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
/** Regression test for bug 4052 - https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=4052 */
@@ -693,7 +611,7 @@ public class SensorFixStoreAndLoadTest {
trackedRace.attachRegattaLog(regattaLog);
trackedRace.waitForLoadingToFinish();
assertNull(trackedRace.getSensorTrack(compNotPartOfRace, BravoFixTrack.TRACK_NAME));
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -712,7 +630,7 @@ public class SensorFixStoreAndLoadTest {
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(START_OF_TRACKING));
trackedRace.waitForLoadingToFinish();
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 3);
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -725,7 +643,7 @@ public class SensorFixStoreAndLoadTest {
trackedRace.attachRegattaLog(regattaLog);
addBravoFixes();
assertNull(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME));
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -746,7 +664,51 @@ public class SensorFixStoreAndLoadTest {
trackedRace.waitForLoadingToFinish();
// only the initial 3 fixes are available
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 3);
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
+ final DynamicGPSFixTrack gpsFixTrack = trackedRace.getTrack(comp);
+ final DegreePosition pos1 = new DegreePosition(0, 0);
+ final DegreeBearingImpl course = new DegreeBearingImpl(0);
+ final KnotSpeedWithBearingImpl speed = new KnotSpeedWithBearingImpl(10, course);
+ final MillisecondsTimePoint timePoint = new MillisecondsTimePoint(FIX_TIMESTAMP);
+ final MillisecondsTimePoint timePoint2 = new MillisecondsTimePoint(FIX_TIMESTAMP2);
+ final MillisecondsTimePoint timePoint3 = new MillisecondsTimePoint(FIX_TIMESTAMP3);
+ final TimePoint timePointBetween2And3 = new MillisecondsTimePoint((FIX_TIMESTAMP2+FIX_TIMESTAMP3)/2);
+ final GPSFixMoving fix1 = new GPSFixMovingImpl(pos1, timePoint, speed);
+ final Position pos2 = pos1.translateGreatCircle(course, speed.travel(timePoint.until(timePoint2)));
+ final GPSFixMoving fix2 = new GPSFixMovingImpl(pos2, timePoint2, speed);
+ final Position pos3 = pos2.translateGreatCircle(course, speed.travel(timePoint2.until(timePoint3)));
+ final GPSFixMoving fix3 = new GPSFixMovingImpl(pos3, timePoint3, speed);
+ gpsFixTrack.add(fix1);
+ gpsFixTrack.add(fix2);
+ gpsFixTrack.add(fix3);
+ final BravoFixTrack bravoFixTrack = trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME);
+ final Distance foilingDistance = bravoFixTrack.getDistanceSpentFoiling(timePoint, timePoint3);
+ final Distance distanceTraveled = gpsFixTrack.getDistanceTraveled(timePoint, timePoint3);
+ assertEquals(distanceTraveled.getMeters(), foilingDistance.getMeters(), 0.001);
+ final Duration foilingDuration = bravoFixTrack.getTimeSpentFoiling(timePoint, timePoint3);
+ assertEquals(timePoint.until(timePoint3).asMillis(), foilingDuration.asMillis());
+
+ // now insert a GPS fix which leads to an extended distance traveled as it is not exactly on the previous track
+ final DegreeBearingImpl temporaryCourse = new DegreeBearingImpl(90);
+ final GPSFixMoving fixBetween2And3 = new GPSFixMovingImpl(
+ pos2.translateGreatCircle(temporaryCourse, speed.add(new KnotSpeedWithBearingImpl(5, temporaryCourse)).travel(timePoint2.until(timePointBetween2And3))),
+ timePointBetween2And3, speed);
+ gpsFixTrack.add(fixBetween2And3);
+ final Distance distanceTraveledDifferently = gpsFixTrack.getDistanceTraveled(timePoint, timePoint3);
+ assertTrue(distanceTraveledDifferently.compareTo(distanceTraveled) > 0);
+ final Distance foilingDistanceDifferent = bravoFixTrack.getDistanceSpentFoiling(timePoint, timePoint3);
+ assertEquals(distanceTraveledDifferently.getMeters(), foilingDistanceDifferent.getMeters(), 0.001);
+
+ // now overwrite fix3 by a new one with increased speed, therefore extended distance:
+ final SpeedWithBearing doubledSpeed = speed.add(speed);
+ final GPSFixMoving fix3Faster = new GPSFixMovingImpl(
+ pos2.translateGreatCircle(course, doubledSpeed.travel(timePoint2.until(timePoint3))),
+ timePoint3, doubledSpeed);
+ gpsFixTrack.add(fix3Faster, /* replace */ true);
+ final Distance distanceTraveledFaster = gpsFixTrack.getDistanceTraveled(timePoint, timePoint3);
+ assertTrue(distanceTraveledFaster.compareTo(distanceTraveled) > 0);
+ final Distance foilingDistanceFaster = bravoFixTrack.getDistanceSpentFoiling(timePoint, timePoint3);
+ assertEquals(distanceTraveledFaster.getMeters(), foilingDistanceFaster.getMeters(), 0.001);
}
@Test
@@ -771,7 +733,7 @@ public class SensorFixStoreAndLoadTest {
trackedRace.waitForLoadingToFinish();
// only the initial 3 fixes are available
testNumberOfRawFixes(trackedRace.getSensorTrack(comp, BravoFixTrack.TRACK_NAME), 3);
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test(timeout=10_000)
@@ -809,7 +771,7 @@ public class SensorFixStoreAndLoadTest {
};
}.start();
// When the bug is triggered, this call would hang until the test timeout is reached
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
}
@Test
@@ -824,7 +786,7 @@ public class SensorFixStoreAndLoadTest {
trackedRace.attachRaceLog(raceLog);
trackedRace.attachRegattaLog(regattaLog);
trackedRace.waitForLoadingToFinish();
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
statusTransitionListener.assertTransitions(TrackedRaceStatusEnum.PREPARED, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.LOADING, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.FINISHED);
}
@@ -840,7 +802,7 @@ public class SensorFixStoreAndLoadTest {
regattaLog.add(new RegattaLogDeviceCompetitorBravoMappingEventImpl(new MillisecondsTimePoint(3), author, comp,
device, new MillisecondsTimePoint(START_OF_TRACKING), new MillisecondsTimePoint(END_OF_TRACKING)));
trackedRace.waitForLoadingToFinish();
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
statusTransitionListener.assertTransitions(TrackedRaceStatusEnum.PREPARED, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.LOADING, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.FINISHED);
}
@@ -857,7 +819,7 @@ public class SensorFixStoreAndLoadTest {
trackedRace.attachRegattaLog(regattaLog);
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(START_OF_TRACKING));
trackedRace.waitForLoadingToFinish();
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
statusTransitionListener.assertTransitions(TrackedRaceStatusEnum.PREPARED, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.LOADING, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.FINISHED);
}
@@ -876,7 +838,7 @@ public class SensorFixStoreAndLoadTest {
trackedRace.waitForLoadingToFinish();
trackedRace.setStartOfTrackingReceived(new MillisecondsTimePoint(START_OF_TRACKING));
trackedRace.waitForLoadingToFinish();
- fixLoaderAndTracker.stop(true);
+ fixLoaderAndTracker.stop(true, /* willBeRemoved */ false);
statusTransitionListener.assertTransitions(TrackedRaceStatusEnum.PREPARED, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.LOADING, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.LOADING, TrackedRaceStatusEnum.TRACKING, TrackedRaceStatusEnum.FINISHED);
}
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreTest.java
index 50f0204d706..1b11a7f9f3f 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreTest.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/SensorFixStoreTest.java
@@ -14,6 +14,7 @@ import org.mockito.Mockito;
import com.mongodb.DB;
import com.mongodb.MongoException;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
@@ -30,7 +31,6 @@ import com.sap.sailing.domain.racelog.tracking.FixReceivedListener;
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.Timed;
import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -384,7 +384,7 @@ public class SensorFixStoreTest {
}
private DoubleVectorFix createBravoDoubleVectorFixWithRideHeight(long timestamp, double rideHeight) {
- double[] fixData = new double[BravoSensorDataMetadata.getTrackColumnCount()];
+ Double[] fixData = new Double[BravoSensorDataMetadata.getTrackColumnCount()];
fixData[BravoSensorDataMetadata.RIDE_HEIGHT_PORT_HULL.getColumnIndex()] = rideHeight;
fixData[BravoSensorDataMetadata.RIDE_HEIGHT_STBD_HULL.getColumnIndex()] = rideHeight;
return new DoubleVectorFixImpl(new MillisecondsTimePoint(timestamp), fixData);
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java
index f449b0dc1b0..56bc80be5bc 100755
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/TrackedRaceLoadsFixesTest.java
@@ -24,11 +24,11 @@ import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.impl.fixtracker.FixLoaderAndTracker;
import com.sap.sailing.domain.racelogtracking.test.AbstractGPSFixStoreTest;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiIdentifier.java b/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiIdentifier.java
index 9bfdebc3545..f0ec889b7ab 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiIdentifier.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiIdentifier.java
@@ -1,6 +1,6 @@
package com.sap.sailing.domain.racelog.tracking.test.mock;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
+import com.sap.sailing.domain.common.DeviceIdentifier;
public class SmartphoneImeiIdentifier implements DeviceIdentifier {
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiJsonHandler.java b/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiJsonHandler.java
index 3a770d9dfbb..71a6c7cfcc2 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiJsonHandler.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiJsonHandler.java
@@ -1,7 +1,7 @@
package com.sap.sailing.domain.racelog.tracking.test.mock;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
public class SmartphoneImeiJsonHandler extends SmartphoneImeiSerializationHandler
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiMongoHandler.java b/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiMongoHandler.java
index 1ac23ea7e8f..d102c5e0280 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiMongoHandler.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiMongoHandler.java
@@ -1,8 +1,8 @@
package com.sap.sailing.domain.racelog.tracking.test.mock;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
public class SmartphoneImeiMongoHandler extends SmartphoneImeiSerializationHandler
implements DeviceIdentifierMongoHandler {
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiSerializationHandler.java b/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiSerializationHandler.java
index eaa539c68f6..bddce674e82 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiSerializationHandler.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter.testsupport/src/com/sap/sailing/domain/racelog/tracking/test/mock/SmartphoneImeiSerializationHandler.java
@@ -1,7 +1,7 @@
package com.sap.sailing.domain.racelog.tracking.test.mock;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sse.common.Util;
public class SmartphoneImeiSerializationHandler {
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages_fr.properties b/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages_fr.properties
index 70b07c43666..00a58568345 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages_fr.properties
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/resources/stringmessages/TrackingStringMessages_fr.properties
@@ -2,10 +2,10 @@ trackingInvitationFor=Invitation de suivi pour
scanQRCodeOrVisitUrlToRegisterAs=Si vous avez bien installé l''application {0}, scannez le code QR suivant ou cliquez sur le lien sur votre smartphone pour vous enregistrer comme
welcomeTo=Bienvenue dans
iOSUsers=Lancer l''application iOS
-androidUsers=Lancer l’application Android
+androidUsers=Lancer l''application Android
alternativelyVisitThisLink=Si vous consultez ce mail sur l''appareil sur lequel l''application est déjà installée, cliquez simplement sur le bouton ci-dessous pour commencer :
buoyTender=Navire baliseur
-appStoreInstallText=Si vous n''avez pas encore l''application, installez-la :
+appStoreInstallText=Si vous n''avez pas encore l''application, voici les liens pour l''installer :
appIos=Installer l''application iOS
appAndroid=Installer l''application Android
buoyPingerAppName=SAP Sailing Buoy Pinger
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/PingDeviceIdentifier.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/PingDeviceIdentifier.java
index 9312eb9f762..2aa2d8778f5 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/PingDeviceIdentifier.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/PingDeviceIdentifier.java
@@ -2,6 +2,8 @@ package com.sap.sailing.domain.racelogtracking;
import java.util.UUID;
+import com.sap.sailing.domain.common.DeviceIdentifier;
+
/**
* A device identifier used to identify a non-existent, virtual device, which is used only once as an
* identifier to add a single fix to a track (i.e. pinging the location of that track's item).
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/PingDeviceIdentifierImpl.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/PingDeviceIdentifierImpl.java
index d08d7f72ff8..9c8f284f018 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/PingDeviceIdentifierImpl.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/PingDeviceIdentifierImpl.java
@@ -4,8 +4,6 @@ import java.util.UUID;
public class PingDeviceIdentifierImpl implements PingDeviceIdentifier {
private static final long serialVersionUID = -4049961972156611640L;
-
-
private final UUID id;
public PingDeviceIdentifierImpl() {
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java
index bacd7172c58..1d8c2160bfe 100755
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java
@@ -39,8 +39,6 @@ public interface RaceLogTrackingAdapter {
* Is a {@link RaceLogRaceTracker} already listening for this racelog? If not, add one.
* Is a {@link RaceLogStartTrackingEvent} present in the racelog? If not, add one
*
- * @param trackWind TODO
- * @param correctWindDirectionByMagneticDeclination TODO
*/
RaceHandle startTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, boolean trackWind, boolean correctWindDirectionByMagneticDeclination)
throws NotDenotedForRaceLogTrackingException, Exception;
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapterFactory.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapterFactory.java
index bcaf268825b..abda88a56e9 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapterFactory.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapterFactory.java
@@ -4,6 +4,11 @@ import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.racelogtracking.impl.RaceLogTrackingAdapterFactoryImpl;
public interface RaceLogTrackingAdapterFactory {
+ /**
+ * A singleton instance; to be used for testing purposes only; when the containing
+ * bundle has been activates, an instance can be found in the OSGi service registry.
+ */
RaceLogTrackingAdapterFactory INSTANCE = RaceLogTrackingAdapterFactoryImpl.INSTANCE;
+
RaceLogTrackingAdapter getAdapter(DomainFactory baseDomainFactory);
}
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/Activator.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/Activator.java
index c2b99f36dc3..8be4cc22076 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/Activator.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/Activator.java
@@ -88,6 +88,8 @@ public class Activator implements BundleActivator {
registrations.add(context.registerService(MasterDataImportClassLoaderService.class,
new MasterDataImportClassLoaderServiceImpl(), null));
registrations.add(context.registerService(SensorFixMapper.class, new BravoDataFixMapper(), null));
+ registrations.add(context.registerService(SensorFixMapper.class, new BravoExtendedDataFixMapper(), null));
+ registrations.add(context.registerService(SensorFixMapper.class, new ExpeditionExtendedDataFixMapper(), null));
sensorFixMapperTracker = createSensorFixMapperServiceTracker(context);
racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class);
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/BravoDataFixMapper.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/BravoDataFixMapper.java
index 4469caa01f8..3415d44f166 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/BravoDataFixMapper.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/BravoDataFixMapper.java
@@ -20,7 +20,8 @@ public class BravoDataFixMapper implements SensorFixMapper getTrack(DynamicTrackedRace race, Competitor key) {
return race.getOrCreateSensorTrack(key, BravoFixTrack.TRACK_NAME,
- () -> new BravoFixTrackImpl(key, BravoFixTrack.TRACK_NAME));
+ () -> new BravoFixTrackImpl(key, BravoFixTrack.TRACK_NAME, /* hasExtendedFixes */ false,
+ race.getTrack(key)));
}
@Override
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/BravoExtendedDataFixMapper.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/BravoExtendedDataFixMapper.java
new file mode 100644
index 00000000000..f35509b8ec3
--- /dev/null
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/BravoExtendedDataFixMapper.java
@@ -0,0 +1,37 @@
+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.RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl;
+import com.sap.sailing.domain.base.Competitor;
+import com.sap.sailing.domain.common.tracking.BravoExtendedFix;
+import com.sap.sailing.domain.common.tracking.BravoFix;
+import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
+import com.sap.sailing.domain.common.tracking.impl.BravoExtendedFixImpl;
+import com.sap.sailing.domain.racelog.tracking.SensorFixMapper;
+import com.sap.sailing.domain.tracking.BravoFixTrack;
+import com.sap.sailing.domain.tracking.DynamicSensorFixTrack;
+import com.sap.sailing.domain.tracking.DynamicTrackedRace;
+import com.sap.sailing.domain.tracking.impl.BravoFixTrackImpl;
+
+/**
+ * {@link SensorFixMapper} implementation to handle {@link BravoExtendedFix}es.
+ */
+public class BravoExtendedDataFixMapper implements SensorFixMapper, Competitor> {
+
+ @Override
+ public DynamicSensorFixTrack getTrack(DynamicTrackedRace race, Competitor key) {
+ return race.getOrCreateSensorTrack(key, BravoFixTrack.TRACK_NAME,
+ () -> new BravoFixTrackImpl(key, BravoFixTrack.TRACK_NAME, /* hasExtendedFixes */ true,
+ race.getTrack(key)));
+ }
+
+ @Override
+ public BravoExtendedFix map(DoubleVectorFix fix) {
+ return new BravoExtendedFixImpl(fix);
+ }
+
+ @Override
+ public boolean isResponsibleFor(Class extends RegattaLogDeviceMappingEvent>> eventType) {
+ return RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl.class.isAssignableFrom(eventType);
+ }
+}
\ No newline at end of file
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/ExpeditionExtendedDataFixMapper.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/ExpeditionExtendedDataFixMapper.java
new file mode 100755
index 00000000000..5dcf9db8119
--- /dev/null
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/ExpeditionExtendedDataFixMapper.java
@@ -0,0 +1,41 @@
+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.RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl;
+import com.sap.sailing.domain.base.Competitor;
+import com.sap.sailing.domain.common.tracking.BravoExtendedFix;
+import com.sap.sailing.domain.common.tracking.BravoFix;
+import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
+import com.sap.sailing.domain.common.tracking.impl.BravoExtendedFixImpl;
+import com.sap.sailing.domain.racelog.tracking.SensorFixMapper;
+import com.sap.sailing.domain.tracking.BravoFixTrack;
+import com.sap.sailing.domain.tracking.DynamicSensorFixTrack;
+import com.sap.sailing.domain.tracking.DynamicTrackedRace;
+import com.sap.sailing.domain.tracking.impl.BravoFixTrackImpl;
+
+/**
+ * {@link SensorFixMapper} implementation to product {@link BravoExtendedFix}es from {@link DoubleVectorFix}es
+ * interpreted as "Expedition" data. The data has significant overlap with what we typically receive from the
+ * "Bravo" devices. Ultimately, the naming may need to be adjusted, better reflecting that the "Bravo" extended
+ * tracks now assume general responsibility for a broader set of sensor values that may be assigned to a
+ * competitor, beyond just GPS tracking data.
+ */
+public class ExpeditionExtendedDataFixMapper implements SensorFixMapper, Competitor> {
+
+ @Override
+ public DynamicSensorFixTrack getTrack(DynamicTrackedRace race, Competitor key) {
+ return race.getOrCreateSensorTrack(key, BravoFixTrack.TRACK_NAME,
+ () -> new BravoFixTrackImpl(key, BravoFixTrack.TRACK_NAME, /* hasExtendedFixes */ true,
+ race.getTrack(key)));
+ }
+
+ @Override
+ public BravoExtendedFix map(DoubleVectorFix fix) {
+ return new BravoExtendedFixImpl(fix);
+ }
+
+ @Override
+ public boolean isResponsibleFor(Class extends RegattaLogDeviceMappingEvent>> eventType) {
+ return RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl.class.isAssignableFrom(eventType);
+ }
+}
\ No newline at end of file
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierJsonHandler.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierJsonHandler.java
index 60d1b57dfb7..072e91a1e4f 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierJsonHandler.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierJsonHandler.java
@@ -1,7 +1,7 @@
package com.sap.sailing.domain.racelogtracking.impl;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
public class PingDeviceIdentifierJsonHandler extends PingDeviceIdentifierSerializationHandler
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierMongoHandler.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierMongoHandler.java
index efb7ecb08dc..9a5a7d37764 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierMongoHandler.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierMongoHandler.java
@@ -1,8 +1,8 @@
package com.sap.sailing.domain.racelogtracking.impl;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
public class PingDeviceIdentifierMongoHandler extends PingDeviceIdentifierSerializationHandler
implements DeviceIdentifierMongoHandler {
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierSerializationHandler.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierSerializationHandler.java
index 415af995c85..2d1e5578407 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierSerializationHandler.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/PingDeviceIdentifierSerializationHandler.java
@@ -2,8 +2,8 @@ package com.sap.sailing.domain.racelogtracking.impl;
import java.util.UUID;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.PingDeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.PingDeviceIdentifierImpl;
import com.sap.sse.common.Util;
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java
index 7ed7c2c6c5d..dff27e3ab36 100755
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogRaceTracker.java
@@ -161,7 +161,7 @@ public class RaceLogRaceTracker extends AbstractRaceTrackerBaseImpl {
}
@Override
- protected void onStop(boolean preemptive) {
+ protected void onStop(boolean preemptive, boolean willBeRemoved) {
RaceLog raceLog = params.getRaceLog();
final Pair trackingTimes = new TrackingTimesFinder(raceLog).analyze();
if (!trackedRegatta.getRegatta().isControlTrackingFromStartAndFinishTimes() &&
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/SmartphoneUUIDMongoHandler.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/SmartphoneUUIDMongoHandler.java
index 8646b044541..e11f27f1d8e 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/SmartphoneUUIDMongoHandler.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/SmartphoneUUIDMongoHandler.java
@@ -1,8 +1,8 @@
package com.sap.sailing.domain.racelogtracking.impl;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.SmartphoneUUIDSerializationHandler;
public class SmartphoneUUIDMongoHandler extends SmartphoneUUIDSerializationHandler
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierJsonHandler.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierJsonHandler.java
index fcdb4f4876e..bff372f9a57 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierJsonHandler.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierJsonHandler.java
@@ -4,8 +4,8 @@ import java.util.UUID;
import org.json.simple.JSONObject;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler;
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierMongoHandler.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierMongoHandler.java
index a9b1e2cd8b5..1218089453f 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierMongoHandler.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierMongoHandler.java
@@ -4,9 +4,9 @@ import java.util.UUID;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
import com.sap.sse.common.TimePoint;
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierStringSerializationHandler.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierStringSerializationHandler.java
index e121abd0502..9f66f61d8e1 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierStringSerializationHandler.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/TrackFileImportDeviceIdentifierStringSerializationHandler.java
@@ -2,8 +2,8 @@ package com.sap.sailing.domain.racelogtracking.impl;
import java.util.UUID;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifierStringSerializationHandler;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier;
import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifierImpl;
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/FixLoaderAndTracker.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/FixLoaderAndTracker.java
index 7776003a4d6..d83e9517bb5 100755
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/FixLoaderAndTracker.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/FixLoaderAndTracker.java
@@ -23,6 +23,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMap
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark;
import com.sap.sailing.domain.base.Regatta;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.DoubleVectorFix;
@@ -33,7 +34,6 @@ import com.sap.sailing.domain.racelog.tracking.FixReceivedListener;
import com.sap.sailing.domain.racelog.tracking.SensorFixMapper;
import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.racelogsensortracking.SensorFixMapperFactory;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sailing.domain.tracking.DynamicSensorFixTrack;
@@ -93,7 +93,7 @@ import com.sap.sse.util.ThreadPoolUtil;
*
*
*
- * There is a corner cases that is assumed to be acceptable for the specific semantic of a {@link Mark}'s fixes:
+ * There is a corner case that is assumed to be acceptable for the specific semantic of a {@link Mark}'s fixes:
* If a Marks is tracked and not pinged, any new fix transferred from the tracking device is treated as being better
* than the one before. So all fixes are being recorded starting at the time point when the operator starts tracking for
* a race and startOfTracking is in the future.
@@ -122,7 +122,20 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
*/
private final Set loadingJobs = ConcurrentHashMap.newKeySet();
private final SensorFixMapperFactory sensorFixMapperFactory;
+
+ /**
+ * This flag is used to tell the loaders/trackers whether preemptive stopping has been requested. If switched
+ * to {@code true}, running loaders will stop loading fixes and return immediately.
+ */
private AtomicBoolean preemptiveStopRequested = new AtomicBoolean(false);
+
+ /**
+ * When {@link #stop(boolean, boolean)} is called with {@code willBeStopped==true}, the fact will be recorded
+ * in this attribute. This is then evaluated when updating general progress so as to set the race status to
+ * {@link TrackedRaceStatusEnum#REMOVED} instead of {@link TrackedRaceStatusEnum#FINISHED}.
+ */
+ private AtomicBoolean willBeRemovedAfterStopping = new AtomicBoolean(false);
+
private AtomicBoolean stopRequested = new AtomicBoolean(false);
private final AbstractRaceChangeListener raceChangeListener = new AbstractRaceChangeListener() {
@Override
@@ -263,7 +276,6 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
this.sensorFixStore = sensorFixStore;
this.sensorFixMapperFactory = sensorFixMapperFactory;
this.trackedRace = trackedRace;
-
startTracking();
}
@@ -362,7 +374,7 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
*/
private void loadFixes(TimeRange timeRangeToLoad, RegattaLogDeviceMappingEvent extends WithID> mappingEvent,
final Consumer progressConsumer, final BooleanSupplier stopCallback) {
- if (timeRangeToLoad != null && !preemptiveStopRequested.get()) {
+ if (timeRangeToLoad != null && !stopCallback.getAsBoolean()) {
mappingEvent.accept(new MappingEventVisitor() {
@Override
public void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
@@ -496,15 +508,22 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
* TracTrac for archived races, loading is automatically stopped. Finishing already started loading jobs ensures,
* that e.g. bravo fixes are completely loaded even if loading from TracTrac is faster.
* If stopping preemptively, the call will block until all already started loading jobs are aborted or finished.
+ *
+ * @param willBeRemoved
+ * if {@code true} then not only will tracking for the race be stopped, but the race is expected to be
+ * removed shortly by the caller; therefore it does not make sense to resume cache calculations for
+ * the race. The race status will then be set to {@link TrackedRaceStatusEnum#REMOVED} instead of
+ * {@link TrackedRaceStatusEnum#FINISHED}.
*/
- public void stop(boolean preemptive) {
+ public void stop(boolean preemptive, boolean willBeRemoved) {
preemptiveStopRequested.set(preemptive);
+ willBeRemovedAfterStopping.set(willBeRemoved);
stopRequested.set(true);
trackedRace.removeListener(raceChangeListener);
deviceMappings.stop();
synchronized (loadingJobs) {
if (loadingJobs.isEmpty()) {
- setStatusAndProgress(TrackedRaceStatusEnum.FINISHED, 1.0);
+ setStatusAndProgress(willBeRemoved ? TrackedRaceStatusEnum.REMOVED : TrackedRaceStatusEnum.FINISHED, 1.0);
}
}
sensorFixStore.removeListener(listener);
@@ -544,7 +563,7 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
}
/**
- * Updates the {@link FixLoaderAndTracker}'s overall state on the {@link TrackedRace} based on the progresses of
+ * Updates the {@link FixLoaderAndTracker}'s overall status on the {@link TrackedRace} based on the progresses of
* {@link #loadingJobs}.
*/
private void updateStatusAndProgress() {
@@ -560,15 +579,14 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
}
if (allFinished) {
loadingJobs.clear();
- status = stopRequested.get() ? TrackedRaceStatusEnum.FINISHED : TrackedRaceStatusEnum.TRACKING;
+ status = stopRequested.get() ? willBeRemovedAfterStopping.get() ? TrackedRaceStatusEnum.REMOVED : TrackedRaceStatusEnum.FINISHED : TrackedRaceStatusEnum.TRACKING;
progress = 1.0;
} else {
progress = progressSum / loadingJobs.size();
status = TrackedRaceStatusEnum.LOADING;
}
-
} else {
- status = stopRequested.get() ? TrackedRaceStatusEnum.FINISHED : TrackedRaceStatusEnum.TRACKING;
+ status = stopRequested.get() ? willBeRemovedAfterStopping.get() ? TrackedRaceStatusEnum.REMOVED : TrackedRaceStatusEnum.FINISHED : TrackedRaceStatusEnum.TRACKING;
progress = 1.0;
}
setStatusAndProgress(status, progress);
@@ -629,9 +647,7 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
@Override
public final void run() {
-
updateStatusAndProgressWithErrorHandling();
-
try {
load(this::updateProgress, preemptiveStopRequested::get);
} finally {
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RaceLogFixTrackerManager.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RaceLogFixTrackerManager.java
index dfef30b0ae9..d8c29226b0e 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RaceLogFixTrackerManager.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RaceLogFixTrackerManager.java
@@ -88,7 +88,7 @@ public class RaceLogFixTrackerManager implements TrackingDataLoader {
if (isForTracking()) {
startTrackerIfNotAlreadyStarted();
} else {
- stopTrackerIfStillRunning(false);
+ stopTrackerIfStillRunning(/* preemptive */ false, /* willBeRemoved */ false);
}
}
@@ -116,8 +116,8 @@ public class RaceLogFixTrackerManager implements TrackingDataLoader {
knownRaceLogs.remove(raceLog);
}
- public void stop(boolean preemptive) {
- stopTrackerIfStillRunning(preemptive);
+ public void stop(boolean preemptive, boolean willBeRemoved) {
+ stopTrackerIfStillRunning(preemptive, willBeRemoved);
trackedRace.removeListener(raceChangeListener);
synchronized (knownRaceLogs) {
final Set tempSet = new HashSet<>(knownRaceLogs);
@@ -134,10 +134,10 @@ public class RaceLogFixTrackerManager implements TrackingDataLoader {
}
}
- private synchronized void stopTrackerIfStillRunning(boolean preemptive) {
+ private synchronized void stopTrackerIfStillRunning(boolean preemptive, boolean willBeRemoved) {
if (tracker != null) {
logger.fine("Stopping fix tracker for TrackedRace: " + trackedRace.getRaceIdentifier());
- tracker.stop(preemptive);
+ tracker.stop(preemptive, willBeRemoved);
tracker = null;
}
}
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RegattaLogDeviceMappings.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RegattaLogDeviceMappings.java
index 07cc2cefb8b..b837aa38419 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RegattaLogDeviceMappings.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RegattaLogDeviceMappings.java
@@ -22,8 +22,8 @@ import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMap
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogRevokeEvent;
import com.sap.sailing.domain.abstractlog.regatta.impl.BaseRegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMappingFinder;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.DoesNotHaveRegattaLogException;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
import com.sap.sailing.domain.tracking.DynamicTrack;
diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RegattaLogFixTrackerRegattaListener.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RegattaLogFixTrackerRegattaListener.java
index e48ea0c6a9b..8cbe6daaef9 100644
--- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RegattaLogFixTrackerRegattaListener.java
+++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/RegattaLogFixTrackerRegattaListener.java
@@ -74,9 +74,9 @@ public class RegattaLogFixTrackerRegattaListener extends AbstractTrackedRegattaA
if (raceTracker != null) {
boolean added = raceTracker.add(new RaceTracker.Listener() {
@Override
- public void onTrackerWillStop(boolean preemptive) {
+ public void onTrackerWillStop(boolean preemptive, boolean willBeRemoved) {
raceTracker.remove(this);
- removeRaceLogSensorDataTracker(raceIdentifier, preemptive);
+ removeRaceLogSensorDataTracker(raceIdentifier, preemptive, willBeRemoved);
}
});
// if !added, the RaceTracker is already stopped, so we are not allowed to start fix tracking
@@ -89,7 +89,7 @@ public class RegattaLogFixTrackerRegattaListener extends AbstractTrackedRegattaA
oldInstance = dataTrackers.put(raceIdentifier, trackerManager);
}
if (oldInstance != null) {
- oldInstance.stop(true);
+ oldInstance.stop(/* preemptive */ true, /* willBeRemoved */ false);
}
}
}
@@ -102,13 +102,13 @@ public class RegattaLogFixTrackerRegattaListener extends AbstractTrackedRegattaA
}
private void removeRaceLogSensorDataTracker(RegattaAndRaceIdentifier raceIdentifier) {
- removeRaceLogSensorDataTracker(raceIdentifier, false);
+ removeRaceLogSensorDataTracker(raceIdentifier, /* preemptive */ false, /* willBeRemoved */ false);
}
- private void removeRaceLogSensorDataTracker(RegattaAndRaceIdentifier raceIdentifier, boolean preemptive) {
+ private void removeRaceLogSensorDataTracker(RegattaAndRaceIdentifier raceIdentifier, boolean preemptive, boolean willBeRemoved) {
RaceLogFixTrackerManager currentActiveDataTracker = dataTrackers.get(raceIdentifier);
if (currentActiveDataTracker != null) {
- currentActiveDataTracker.stop(preemptive);
+ currentActiveDataTracker.stop(preemptive, willBeRemoved);
trackerStopped(raceIdentifier, currentActiveDataTracker);
}
}
diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ConfirmedFinishPositioningListFinderTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ConfirmedFinishPositioningListFinderTest.java
index bada0503c17..b818708212f 100644
--- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ConfirmedFinishPositioningListFinderTest.java
+++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/ConfirmedFinishPositioningListFinderTest.java
@@ -2,19 +2,26 @@ package com.sap.sailing.domain.racelog.analyzing.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
+import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
+import com.sap.sailing.domain.abstractlog.race.CompetitorResult.MergeState;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.ConfirmedFinishPositioningListFinder;
+import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultImpl;
+import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl;
+import com.sap.sailing.domain.common.MaxPointsReason;
+import com.sap.sse.common.Util;
public class ConfirmedFinishPositioningListFinderTest extends
PassAwareRaceLogAnalyzerTest {
@@ -27,9 +34,17 @@ public class ConfirmedFinishPositioningListFinderTest extends
@Override
protected TargetPair getTargetEventsAndResultForPassAwareTests(int passId, AbstractLogEventAuthor author) {
RaceLogFinishPositioningConfirmedEvent event = createEvent(RaceLogFinishPositioningConfirmedEvent.class, 1, passId, author);
- when(event.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(mock(CompetitorResults.class));
+ when(event.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(mockCompetitorResults());
return new TargetPair(Arrays.asList(event), event.getPositionedCompetitorsIDsNamesMaxPointsReasons());
}
+
+ private CompetitorResults mockCompetitorResults(CompetitorResult... results) {
+ final CompetitorResultsImpl result = new CompetitorResultsImpl();
+ for (final CompetitorResult r : results) {
+ result.add(r);
+ }
+ return result;
+ }
@Test
public void testNullForNone() {
@@ -42,11 +57,58 @@ public class ConfirmedFinishPositioningListFinderTest extends
public void testMostRecent() {
RaceLogFinishPositioningConfirmedEvent event1 = createEvent(RaceLogFinishPositioningConfirmedEvent.class, 1);
RaceLogFinishPositioningConfirmedEvent event2 = createEvent(RaceLogFinishPositioningConfirmedEvent.class, 2);
- when(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(mock(CompetitorResults.class));
-
+ final CompetitorResultImpl oldResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, MaxPointsReason.NONE, 1.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
+ final CompetitorResultImpl oldResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.NONE, 2.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
+ final CompetitorResults olderResults = mockCompetitorResults(oldResultC1, oldResultC2);
+ final CompetitorResultImpl newResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
+ final CompetitorResults newerResults = mockCompetitorResults(newResultC2);
+ when(event1.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(olderResults);
+ when(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(newerResults);
raceLog.add(event1);
raceLog.add(event2);
+ assertCompetitorResultsEquals(mockCompetitorResults(oldResultC1, newResultC2), analyzer.analyze());
+ }
+
+ @Test
+ public void testMixtureOfPartialResultsOfDifferentPriority() {
+ RaceLogFinishPositioningConfirmedEvent event1 = createEvent(/* priority */ 1, RaceLogFinishPositioningConfirmedEvent.class, 1);
+ RaceLogFinishPositioningConfirmedEvent event2 = createEvent(/* priority */ 1, RaceLogFinishPositioningConfirmedEvent.class, 2);
+ RaceLogFinishPositioningConfirmedEvent event3 = createEvent(/* priority */ 2, RaceLogFinishPositioningConfirmedEvent.class, 3);
+ RaceLogFinishPositioningConfirmedEvent event4 = createEvent(/* priority */ 1, RaceLogFinishPositioningConfirmedEvent.class, 4);
+ final CompetitorResultImpl e1ResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, MaxPointsReason.DNC, 6.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
+ final CompetitorResultImpl e1ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.NONE, 2.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
+ final CompetitorResults e1Results = mockCompetitorResults(e1ResultC1, e1ResultC2);
+ final CompetitorResultImpl e2ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
+ final CompetitorResults e2Results = mockCompetitorResults(e2ResultC2);
+ final CompetitorResultImpl e3ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DSQ, 6.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
+ final CompetitorResultImpl e3ResultC3 = new CompetitorResultImpl("Comp3", "Comp 3", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
+ final CompetitorResults e3Results = mockCompetitorResults(e3ResultC2, e3ResultC3);
+ final CompetitorResultImpl e4ResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, /* maxPointsReason */ null, /* score */ null, /* finishing time */ null, /* comment */ null, MergeState.OK);
+ final CompetitorResultImpl e4ResultC4 = new CompetitorResultImpl("Comp4", "Comp 4", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null, MergeState.OK);
+ final CompetitorResults e4Results = mockCompetitorResults(e4ResultC1, e4ResultC4);
+ when(event1.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(e1Results);
+ when(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(e2Results);
+ when(event3.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(e3Results);
+ when(event4.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(e4Results);
+ // insert in more or less random order
+ raceLog.add(event4);
+ raceLog.add(event2);
+ raceLog.add(event1);
+ raceLog.add(event3);
+ // e1ResultC1 is expected to be overruled by e4ResultC1 because the latter has the same priority and comes later
+ // e1ResultC2 is expected to be overruled by e2ResultC2 due to same priority but later time; and e3ResultC2 has less priority
+ // e3ResultC3 and e4ResultC4 stand by themselves; they are not overruled by anything
+ assertCompetitorResultsEquals(mockCompetitorResults(e4ResultC1, e2ResultC2, e3ResultC3, e4ResultC4), analyzer.analyze());
+ }
- assertEquals(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons(), analyzer.analyze());
+ /**
+ * Results are considered equal if they contain equal sets of {@link CompetitorResult}s.
+ */
+ private void assertCompetitorResultsEquals(CompetitorResults o1, CompetitorResults o2) {
+ Set o1Results = new HashSet<>();
+ Util.addAll(o1, o1Results);
+ Set o2Results = new HashSet<>();
+ Util.addAll(o2, o2Results);
+ assertEquals(o1Results, o2Results);
}
}
diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/RaceLogAnalyzerTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/RaceLogAnalyzerTest.java
index fea4c927df6..a40cda33219 100644
--- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/RaceLogAnalyzerTest.java
+++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/racelog/analyzing/test/RaceLogAnalyzerTest.java
@@ -9,6 +9,7 @@ import java.util.UUID;
import org.junit.Before;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
+import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogAnalyzer;
@@ -29,7 +30,11 @@ public abstract class RaceLogAnalyzerTest T createEvent(Class type, long milliseconds) {
- return createEvent(type, milliseconds, 0, UUID.randomUUID());
+ return createEvent(/* priority */ 0, type, milliseconds);
+ }
+
+ protected static T createEvent(int priority, Class type, long milliseconds) {
+ return createEvent(priority, type, milliseconds, 0, UUID.randomUUID());
}
protected static T createEvent(Class type, long milliseconds, Serializable id) {
@@ -41,7 +46,12 @@ public abstract class RaceLogAnalyzerTest T createEvent(Class type, long milliseconds, int passId, Serializable id) {
- return createEvent(type, milliseconds, passId, id, mock(AbstractLogEventAuthor.class));
+ return createEvent(/* priority */ 0, type, milliseconds, passId, id);
+ }
+
+ protected static T createEvent(int priority, Class type, long milliseconds, int passId, Serializable id) {
+ final AbstractLogEventAuthor author = new LogEventAuthorImpl("Author", priority);
+ return createEvent(type, milliseconds, passId, id, author);
}
protected static T createEvent(Class type, long milliseconds, int passId, AbstractLogEventAuthor author) {
diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/DeviceMappingFinderTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/DeviceMappingFinderTest.java
index e9b28c32396..e43e8cece89 100644
--- a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/DeviceMappingFinderTest.java
+++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/DeviceMappingFinderTest.java
@@ -17,9 +17,9 @@ import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCo
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceCompetitorMappingFinder;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.impl.CompetitorImpl;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
diff --git a/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF
index 73cbf568770..a0e1d5bcbb2 100644
--- a/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF
+++ b/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF
@@ -40,6 +40,7 @@ Export-Package: com.sap.sailing.domain.abstractlog,
com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl,
com.sap.sailing.domain.abstractlog.shared.analyzing,
com.sap.sailing.domain.abstractlog.shared.events,
+ com.sap.sailing.domain.anniversary,
com.sap.sailing.domain.base,
com.sap.sailing.domain.base.configuration,
com.sap.sailing.domain.base.configuration.impl,
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResult.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResult.java
index a1743691ef4..73e556c861e 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResult.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResult.java
@@ -14,6 +14,30 @@ import com.sap.sse.common.TimePoint;
*
*/
public interface CompetitorResult extends Serializable {
+ public static enum MergeState {
+ /**
+ * No merge was necessary at competitor level.
+ */
+ OK,
+
+ /**
+ * A field-wise merge was necessary because an update was received that affected this competitor result
+ * while locally this competitor result was in a "dirty" (modified) state. The merge was carried out
+ * automatically because the fields changed in the dirty state did not overlap with the fields changed
+ * in the version of the object received.
+ */
+ WARNING,
+
+ /**
+ * A field-wise merge was necessary because an update was received that affected this competitor result while
+ * locally this competitor result was in a "dirty" (modified) state. The fields changed in the dirty state
+ * overlap with the fields changed in the version of the object received. Field values from the local dirty state
+ * have been preferred or have been appended in case of {@link String}-typed fields and need manual
+ * intervention.
+ */
+ ERROR
+ };
+
Serializable getCompetitorId();
String getCompetitorDisplayName();
@@ -27,4 +51,9 @@ public interface CompetitorResult extends Serializable {
TimePoint getFinishingTime();
String getComment();
+
+ /**
+ * Always returns a valid, non-{@code null} result. See {@link MergeState} for details.
+ */
+ MergeState getMergeState();
}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResults.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResults.java
index 9abbcae0b33..b248d2bf176 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResults.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/CompetitorResults.java
@@ -7,4 +7,13 @@ package com.sap.sailing.domain.abstractlog.race;
*/
public interface CompetitorResults extends Iterable {
boolean add(CompetitorResult result);
+
+ /**
+ * @return {@code true} if there are more than one {@link CompetitorResult} contained with equal
+ * {@link CompetitorResult#getOneBasedRank() rank}. A client can take this as an indicator that
+ * there may be an inconsistency, caused, e.g., by merging results entered on different devices
+ * concurrently. The client shall use the {@link #iterator()} method to enumerate the
+ * {@link CompetitorResult} objects, finding the conflicting elements.
+ */
+ boolean hasConflicts();
}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/AbstractFinishPositioningListFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/AbstractFinishPositioningListFinder.java
new file mode 100755
index 00000000000..14ad1d00d2f
--- /dev/null
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/AbstractFinishPositioningListFinder.java
@@ -0,0 +1,60 @@
+package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
+import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
+import com.sap.sailing.domain.abstractlog.race.RaceLog;
+import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
+import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningEvent;
+import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl;
+
+/**
+ * Fetches competitor results from the current pass in a {@link RaceLog}. Results may be provided in multiple, partial
+ * race log events, all of potentially different priority, with time stamps and potential overlaps, providing different
+ * results for the same competitor at different times, with different priorities. This finder merges all these results
+ * from the current pass and prefers higher priorities (numerically less) over lower priorities (numerically greater),
+ * and later results over earlier results with equal priority. It can therefore rely on the order in which race log
+ * events are produced by {@link #getPassEventsDescending()}.
+ *
+ * The analyzer will return {@code null} if no result has been found at all.
+ *
+ * @author Axel Uhl (D043530)
+ *
+ */
+public class AbstractFinishPositioningListFinder extends RaceLogAnalyzer {
+ /**
+ * The type of event we're looking for in the log
+ */
+ private final Class extends RaceLogFinishPositioningEvent> clz;
+
+ public AbstractFinishPositioningListFinder(RaceLog raceLog, Class extends RaceLogFinishPositioningEvent> clz) {
+ super(raceLog);
+ this.clz = clz;
+ }
+
+ @Override
+ protected CompetitorResults performAnalysis() {
+ boolean resultFound = false;
+ final Map resultsByCompetitor = new HashMap<>();
+ for (RaceLogEvent event : getPassEventsDescending()) {
+ if (clz.isInstance(event)) {
+ RaceLogFinishPositioningEvent finishPositioningEvent = (RaceLogFinishPositioningEvent) event;
+ final CompetitorResults positionedCompetitorsIDsNamesMaxPointsReasons = finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons();
+ if (positionedCompetitorsIDsNamesMaxPointsReasons != null) {
+ resultFound = true;
+ for (final CompetitorResult r : positionedCompetitorsIDsNamesMaxPointsReasons) {
+ if (!resultsByCompetitor.containsKey(r.getCompetitorId())) {
+ resultsByCompetitor.put(r.getCompetitorId(), r);
+ }
+ }
+ }
+ }
+ }
+ final CompetitorResultsImpl result = new CompetitorResultsImpl();
+ result.addAll(resultsByCompetitor.values());
+ return resultFound ? result : null;
+ }
+}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ConfirmedFinishPositioningListFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ConfirmedFinishPositioningListFinder.java
index 381df5b1c36..5afc4304be9 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ConfirmedFinishPositioningListFinder.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/ConfirmedFinishPositioningListFinder.java
@@ -1,24 +1,10 @@
package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
-import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
-import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent;
-public class ConfirmedFinishPositioningListFinder extends RaceLogAnalyzer {
-
+public class ConfirmedFinishPositioningListFinder extends AbstractFinishPositioningListFinder {
public ConfirmedFinishPositioningListFinder(RaceLog raceLog) {
- super(raceLog);
- }
-
- @Override
- protected CompetitorResults performAnalysis() {
- for (RaceLogEvent event : getPassEventsDescending()) {
- if (event instanceof RaceLogFinishPositioningConfirmedEvent) {
- RaceLogFinishPositioningConfirmedEvent finishPositioningEvent = (RaceLogFinishPositioningConfirmedEvent) event;
- return finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons();
- }
- }
- return null;
+ super(raceLog, RaceLogFinishPositioningConfirmedEvent.class);
}
}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/FinishPositioningListFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/FinishPositioningListFinder.java
index 890748da8fa..5e51c98f0d0 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/FinishPositioningListFinder.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/analyzing/impl/FinishPositioningListFinder.java
@@ -1,25 +1,10 @@
package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
-import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
-import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningListChangedEvent;
-public class FinishPositioningListFinder extends RaceLogAnalyzer {
-
+public class FinishPositioningListFinder extends AbstractFinishPositioningListFinder {
public FinishPositioningListFinder(RaceLog raceLog) {
- super(raceLog);
- }
-
- @Override
- protected CompetitorResults performAnalysis() {
- for (RaceLogEvent event : getPassEventsDescending()) {
- if (event instanceof RaceLogFinishPositioningListChangedEvent) {
- RaceLogFinishPositioningListChangedEvent finishPositioningEvent = (RaceLogFinishPositioningListChangedEvent) event;
- return finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons();
- }
- }
-
- return null;
+ super(raceLog, RaceLogFinishPositioningListChangedEvent.class);
}
}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultImpl.java
index da8728f267b..d5221e451a4 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultImpl.java
@@ -23,8 +23,11 @@ public class CompetitorResultImpl implements CompetitorResult {
private final String comment;
+ private final MergeState mergeState;
+
public CompetitorResultImpl(Serializable competitorId, String competitorDisplayName, int oneBasedRank,
- MaxPointsReason maxPointsReason, Double score, TimePoint finishingTime, String comment) {
+ MaxPointsReason maxPointsReason, Double score, TimePoint finishingTime, String comment,
+ MergeState mergeState) {
super();
this.competitorId = competitorId;
this.competitorDisplayName = competitorDisplayName;
@@ -33,6 +36,7 @@ public class CompetitorResultImpl implements CompetitorResult {
this.score = score;
this.finishingTime = finishingTime;
this.comment = comment;
+ this.mergeState = mergeState;
}
@Override
@@ -70,6 +74,11 @@ public class CompetitorResultImpl implements CompetitorResult {
return comment;
}
+ @Override
+ public MergeState getMergeState() {
+ return mergeState == null ? MergeState.OK : mergeState; // default in case of having de-serialized an old version
+ }
+
@Override
public int hashCode() {
final int prime = 31;
@@ -81,6 +90,7 @@ public class CompetitorResultImpl implements CompetitorResult {
result = prime * result + ((maxPointsReason == null) ? 0 : maxPointsReason.hashCode());
result = prime * result + oneBasedRank;
result = prime * result + ((score == null) ? 0 : score.hashCode());
+ result = prime * result + ((mergeState == null) ? 0 : mergeState.hashCode());
return result;
}
@@ -122,6 +132,11 @@ public class CompetitorResultImpl implements CompetitorResult {
return false;
} else if (!score.equals(other.score))
return false;
+ if (mergeState == null) {
+ if (other.mergeState != null)
+ return false;
+ } else if (!mergeState.equals(other.mergeState))
+ return false;
return true;
}
@@ -129,7 +144,7 @@ public class CompetitorResultImpl implements CompetitorResult {
public String toString() {
return "CompetitorResultImpl [competitorId=" + competitorId + ", competitorName=" + competitorDisplayName + ", rank="
+ oneBasedRank + ", maxPointsReason=" + maxPointsReason + ", score=" + score + ", finishingTime="
- + finishingTime + ", comment=" + comment + "]";
+ + finishingTime + ", comment=" + comment + ", mergeState=" + mergeState + "]";
}
}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultsImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultsImpl.java
index 67b4e6cd896..0d60d044dec 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultsImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/CompetitorResultsImpl.java
@@ -1,10 +1,26 @@
package com.sap.sailing.domain.abstractlog.race.impl;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
public class CompetitorResultsImpl extends ArrayList implements CompetitorResults {
private static final long serialVersionUID = 4928351242700897387L;
+
+ @Override
+ public boolean hasConflicts() {
+ final Set oneBasedRanks = new HashSet<>();
+ for (final CompetitorResult r : this) {
+ final int oneBasedRank = r.getOneBasedRank();
+ if (oneBasedRank != 0) {
+ if (!oneBasedRanks.add(oneBasedRank)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/NoAddingRaceLogWrapper.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/NoAddingRaceLogWrapper.java
index 269d14b692d..5a2a9e2c7dc 100755
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/NoAddingRaceLogWrapper.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/impl/NoAddingRaceLogWrapper.java
@@ -15,6 +15,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor;
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
+import com.sap.sailing.domain.tracking.impl.TimeRangeCache;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Function;
@@ -263,4 +264,11 @@ public class NoAddingRaceLogWrapper implements RaceLog {
public int size() {
return innerRaceLog.size();
}
+
+ @Override
+ public T getValueSum(TimePoint from, TimePoint to, T nullElement,
+ com.sap.sailing.domain.tracking.Track.Adder adder, TimeRangeCache cache,
+ com.sap.sailing.domain.tracking.Track.TimeRangeValueCalculator valueCalculator) {
+ return innerRaceLog.getValueSum(from, to, nullElement, adder, cache, valueCalculator);
+ }
}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java
index 20501c69678..2fbd998177e 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/race/state/impl/RaceStateImpl.java
@@ -158,6 +158,7 @@ public class RaceStateImpl extends ReadonlyRaceStateImpl implements RaceState {
public void forceNewDependentStartTime(TimePoint now, final Duration startTimeDifference, final SimpleRaceLogIdentifier dependentOnRace) {
raceLog.add(new RaceLogDependentStartTimeEventImpl(now, author, raceLog.getCurrentPassId(), dependentOnRace, startTimeDifference));
}
+
@Override
public void setFinishingTime(TimePoint timePoint) {
@@ -166,7 +167,10 @@ public class RaceStateImpl extends ReadonlyRaceStateImpl implements RaceState {
@Override
public void setFinishedTime(TimePoint timePoint) {
- raceLog.add(new RaceLogRaceStatusEventImpl(timePoint, author, raceLog.getCurrentPassId(), RaceLogRaceStatus.FINISHED));
+ raceLog.add(new RaceLogRaceStatusEventImpl(timePoint, author, raceLog.getCurrentPassId(),
+ RaceLogRaceStatus.FINISHED));
+ // ensure caches are synched
+ forceUpdate();
}
@Override
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEvent.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEvent.java
index 8895db1fbea..7cac1817803 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEvent.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEvent.java
@@ -6,7 +6,7 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDefinedMarkAnalyzer;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TimeRange;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEventImpl.java
index 88b011916d1..08f4e08c1d9 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEventImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/RegattaLogDeviceMappingEventImpl.java
@@ -5,7 +5,7 @@ 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.racelogtracking.DeviceIdentifier;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.WithID;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl.java
new file mode 100644
index 00000000000..dbe9f1e80ac
--- /dev/null
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl.java
@@ -0,0 +1,47 @@
+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.RegattaLogDeviceCompetitorSensorDataMappingEvent;
+import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl;
+import com.sap.sailing.domain.base.Competitor;
+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 AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl extends RegattaLogDeviceMappingEventImpl
+ implements RegattaLogDeviceCompetitorSensorDataMappingEvent {
+ private static final long serialVersionUID = -1494030544804758753L;
+
+ public interface Factory {
+ 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) {
+ super(createdAt, logicalTimePoint, author, pId, mappedTo, device, from, to);
+ }
+
+ public AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
+ Competitor 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);
+ }
+}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl.java
new file mode 100644
index 00000000000..83fc2feb3e4
--- /dev/null
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl.java
@@ -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.Competitor;
+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 RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl extends AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl {
+ private static final long serialVersionUID = -1494030544804758753L;
+
+
+ public RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
+ AbstractLogEventAuthor author, Serializable pId, Competitor mappedTo, DeviceIdentifier device,
+ TimePoint from, TimePoint to) {
+ super(createdAt, logicalTimePoint, author, pId, mappedTo, device, from, to);
+ }
+
+ public RegattaLogDeviceCompetitorBravoExtendedMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
+ Competitor mappedTo, DeviceIdentifier device, TimePoint from, TimePoint to) {
+ super(logicalTimePoint, author, mappedTo, device, from, to);
+ }
+}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorBravoMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorBravoMappingEventImpl.java
index 8ece02e1ce8..831aa75a927 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorBravoMappingEventImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorBravoMappingEventImpl.java
@@ -3,19 +3,14 @@ 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.RegattaLogDeviceCompetitorSensorDataMappingEvent;
-import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl;
import com.sap.sailing.domain.base.Competitor;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
/**
* Mapping event for devices mapped for Bravo type fixes.
*/
-public class RegattaLogDeviceCompetitorBravoMappingEventImpl extends RegattaLogDeviceMappingEventImpl
- implements RegattaLogDeviceCompetitorSensorDataMappingEvent {
+public class RegattaLogDeviceCompetitorBravoMappingEventImpl extends AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl {
private static final long serialVersionUID = -1494030544804758753L;
@@ -29,14 +24,4 @@ public class RegattaLogDeviceCompetitorBravoMappingEventImpl extends RegattaLogD
Competitor 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);
- }
}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl.java
new file mode 100755
index 00000000000..eab4586d1f2
--- /dev/null
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl.java
@@ -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.Competitor;
+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 RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl extends AbstractRegattaLogDeviceCompetitorSensorDataMappingEventImpl {
+ private static final long serialVersionUID = -7865925670153838864L;
+
+ public RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl(TimePoint createdAt, TimePoint logicalTimePoint,
+ AbstractLogEventAuthor author, Serializable pId, Competitor mappedTo, DeviceIdentifier device,
+ TimePoint from, TimePoint to) {
+ super(createdAt, logicalTimePoint, author, pId, mappedTo, device, from, to);
+ }
+
+ public RegattaLogDeviceCompetitorExpeditionExtendedMappingEventImpl(TimePoint logicalTimePoint, AbstractLogEventAuthor author,
+ Competitor mappedTo, DeviceIdentifier device, TimePoint from, TimePoint to) {
+ super(logicalTimePoint, author, mappedTo, device, from, to);
+ }
+}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorMappingEventImpl.java
index ef7aea4c628..b9c8cbce426 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorMappingEventImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceCompetitorMappingEventImpl.java
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl;
import com.sap.sailing.domain.base.Competitor;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
public class RegattaLogDeviceCompetitorMappingEventImpl extends RegattaLogDeviceMappingEventImpl implements
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceMarkMappingEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceMarkMappingEventImpl.java
index e2da1cdca93..61312f84ba3 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceMarkMappingEventImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/events/impl/RegattaLogDeviceMarkMappingEventImpl.java
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEventImpl;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.base.Mark;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
public class RegattaLogDeviceMarkMappingEventImpl extends RegattaLogDeviceMappingEventImpl implements
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/BaseRegattaLogDeviceMappingFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/BaseRegattaLogDeviceMappingFinder.java
index 83cff11e8f6..62f138d79f5 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/BaseRegattaLogDeviceMappingFinder.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/BaseRegattaLogDeviceMappingFinder.java
@@ -10,8 +10,8 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogCloseOpenEndedDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.abstractlog.NotRevokableException;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TimeRange;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceCompetitorMappingFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceCompetitorMappingFinder.java
index 6226305b798..c357cc9e26e 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceCompetitorMappingFinder.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceCompetitorMappingFinder.java
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompeti
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceCompetitorMappingEventImpl;
import com.sap.sailing.domain.base.Competitor;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMappingFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMappingFinder.java
index 448947529dc..983684147c1 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMappingFinder.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMappingFinder.java
@@ -13,7 +13,7 @@ import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
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.RegattaLogDeviceMappingEvent;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
import com.sap.sailing.domain.racelogtracking.impl.DeviceMappingWithRegattaLogEventImpl;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMarkMappingFinder.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMarkMappingFinder.java
index b76ca947923..4e3d50a3cf8 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMarkMappingFinder.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/regatta/tracking/analyzing/impl/RegattaLogDeviceMarkMappingFinder.java
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMapping
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogDeviceMarkMappingEventImpl;
import com.sap.sailing.domain.base.Mark;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/anniversary/DetailedRaceInfo.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/anniversary/DetailedRaceInfo.java
new file mode 100644
index 00000000000..0a9608804c5
--- /dev/null
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/anniversary/DetailedRaceInfo.java
@@ -0,0 +1,70 @@
+package com.sap.sailing.domain.anniversary;
+
+import java.net.URL;
+import java.util.UUID;
+
+import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
+import com.sap.sailing.domain.common.dto.EventType;
+import com.sap.sse.common.TimePoint;
+
+/**
+ * Reference to an "anniversary" race, such that it can be used to obtain a link to the race on its hosting server. For
+ * this, the object hosts additional information about the leaderboard and the event.
+ * Object creation will fail with an exception if no leaderboardName and eventId is given. All other data is optional.
+ */
+public class DetailedRaceInfo extends SimpleRaceInfo {
+ private static final long serialVersionUID = 1L;
+ private final String eventName;
+ private final String leaderboardDisplayName;
+ private final String leaderboardName;
+ private final UUID eventID;
+ private EventType eventType;
+
+ public DetailedRaceInfo(RegattaAndRaceIdentifier identifier, String leaderboardName, String leaderboardDisplayName,
+ TimePoint timePoint, UUID eventId, String eventName, EventType eventType,
+ URL remoteUrl) {
+ super(identifier, timePoint, remoteUrl);
+ if (leaderboardName == null || eventId == null) {
+ throw new IllegalStateException("DetailedRaceInfo Data is not allowed to contain any null values!");
+ }
+ this.leaderboardName = leaderboardName;
+ this.leaderboardDisplayName = leaderboardDisplayName;
+ this.eventName = eventName;
+ this.eventID = eventId;
+ this.eventType = eventType;
+ }
+
+ /**
+ * Copy constructor to easily switch remoteUrl value
+ */
+ public DetailedRaceInfo(DetailedRaceInfo copy, URL remoteUrl) {
+ this(copy.getIdentifier(), copy.getLeaderboardName(), copy.getLeaderboardDisplayName(), copy.getStartOfRace(),
+ copy.getEventID(), copy.getEventName(), copy.getEventType(), remoteUrl);
+ }
+
+ public String getLeaderboardDisplayName() {
+ return leaderboardDisplayName;
+ }
+
+ public String getEventName() {
+ return eventName;
+ }
+
+ public String getLeaderboardName() {
+ return leaderboardName;
+ }
+
+ public UUID getEventID() {
+ return eventID;
+ }
+
+ @Override
+ public String toString() {
+ return "DetailedRaceInfo [identifier=" + getIdentifier() + ", leaderboardName=" + leaderboardName
+ + ", startOfRace=" + getStartOfRace() + ", eventID=" + eventID + "]";
+ }
+
+ public EventType getEventType() {
+ return eventType;
+ }
+}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/anniversary/SimpleRaceInfo.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/anniversary/SimpleRaceInfo.java
new file mode 100644
index 00000000000..15cf9422074
--- /dev/null
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/anniversary/SimpleRaceInfo.java
@@ -0,0 +1,85 @@
+package com.sap.sailing.domain.anniversary;
+
+import java.io.Serializable;
+import java.net.URL;
+
+import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
+import com.sap.sse.common.TimePoint;
+
+/**
+ * Used to capture information about a race for use in an "anniversary" feature that allows us to sort a set of races by
+ * their start time. Races are identified by a {@link RegattaAndRaceIdentifier}. Their start time is recorded in the
+ * {@link #startOfRace} field which must not be {@code null}, and the {@link URL} of the remote server reference is
+ * stored in {@link #remoteUrl}. Using clients shall make sure that the same {@link URL} object is used for larger sets
+ * of objects of this type in order not to waste memory on a massive replication of those equal {@link URL} objects
+ * identifying the same remote server.
+ */
+public class SimpleRaceInfo implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final RegattaAndRaceIdentifier identifier;
+ private final TimePoint startOfRace;
+ private final URL remoteUrl;
+
+ /**
+ * @param remoteUrl
+ * use {@code null} to mean "local"; a local server does not necessarily know under which URL it is being
+ * reached and therefore cannot provide this
+ */
+ public SimpleRaceInfo(RegattaAndRaceIdentifier identifier, TimePoint startOfRace, URL remoteUrl) {
+ if (identifier == null || startOfRace == null) {
+ throw new IllegalStateException("SimpleRaceInfo Data is not allowed to contain any null values!");
+ }
+ this.identifier = identifier;
+ this.startOfRace = startOfRace;
+ this.remoteUrl = remoteUrl;
+ }
+
+ public RegattaAndRaceIdentifier getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * The URL used in a remote server reference through which the record was obtained; or {@code null} in case the race
+ * identified by this object resides on the local server responding to a request.
+ */
+ public URL getRemoteUrl() {
+ return remoteUrl;
+ }
+
+ public TimePoint getStartOfRace() {
+ return startOfRace;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
+ result = prime * result + ((startOfRace == null) ? 0 : startOfRace.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;
+ SimpleRaceInfo other = (SimpleRaceInfo) obj;
+ if (identifier == null) {
+ if (other.identifier != null)
+ return false;
+ } else if (!identifier.equals(other.identifier))
+ return false;
+ if (startOfRace == null) {
+ if (other.startOfRace != null)
+ return false;
+ } else if (!startOfRace.equals(other.startOfRace))
+ return false;
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/CompetitorStore.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/CompetitorStore.java
index 029c3f50793..9aa1019ed12 100755
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/CompetitorStore.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/CompetitorStore.java
@@ -19,6 +19,7 @@ import com.sap.sse.common.Duration;
public interface CompetitorStore extends CompetitorFactory {
public interface CompetitorUpdateListener {
void competitorUpdated(Competitor competitor);
+ void competitorCreated(Competitor competitor);
}
/**
@@ -68,7 +69,7 @@ public interface CompetitorStore extends CompetitorFactory {
String newSailId, Nationality newNationality, URI newTeamImageUri, URI newFlagImageUri,
Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag);
- void addCompetitors(Iterable competitors);
+ void addNewCompetitors(Iterable competitors);
CompetitorDTO convertToCompetitorDTO(Competitor c);
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/TransientCompetitorStoreImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/TransientCompetitorStoreImpl.java
index 831bfdfb761..06abdb83f51 100755
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/TransientCompetitorStoreImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/TransientCompetitorStoreImpl.java
@@ -74,7 +74,7 @@ public class TransientCompetitorStoreImpl implements CompetitorStore, Serializab
DynamicTeam team, DynamicBoat boat, Double timeOnTimeFactor, Duration timeOnDistanceAllowancePerNauticalMile, String searchTag) {
Competitor result = new CompetitorImpl(id, name, displayColor, email, flagImage, team, boat,
timeOnTimeFactor, timeOnDistanceAllowancePerNauticalMile, searchTag);
- addNewCompetitor(id, result);
+ addNewCompetitor(result);
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "Created competitor "+name+" with ID "+id, new Exception("Here is where it happened"));
}
@@ -86,14 +86,19 @@ public class TransientCompetitorStoreImpl implements CompetitorStore, Serializab
* {@link #getExistingCompetitorById(Serializable)}. Subclasses may override in case they need to take additional
* measures such as durably storing the competitor. Overriding implementations must call this implementation.
*/
- protected void addNewCompetitor(Serializable id, Competitor competitor) {
+ protected void addNewCompetitor(Competitor competitor) {
LockUtil.lockForWrite(lock);
try {
- competitorCache.put(id, competitor);
- competitorsByIdAsString.put(id.toString(), competitor);
+ competitorCache.put(competitor.getId(), competitor);
+ competitorsByIdAsString.put(competitor.getId().toString(), competitor);
} finally {
LockUtil.unlockAfterWrite(lock);
}
+ synchronized (listeners) {
+ for (final CompetitorUpdateListener listener : listeners) {
+ listener.competitorCreated(competitor);
+ }
+ }
}
@Override
@@ -277,15 +282,9 @@ public class TransientCompetitorStoreImpl implements CompetitorStore, Serializab
}
@Override
- public void addCompetitors(Iterable competitors) {
- LockUtil.lockForWrite(lock);
- try {
- for (Competitor competitor: competitors) {
- competitorCache.put(competitor.getId(), competitor);
- competitorsByIdAsString.put(competitor.getId().toString(), competitor);
- }
- } finally {
- LockUtil.unlockAfterWrite(lock);
+ public void addNewCompetitors(Iterable competitors) {
+ for (Competitor competitor: competitors) {
+ addNewCompetitor(competitor);
}
}
}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceIdentifierSerializationHandler.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceIdentifierSerializationHandler.java
index 57327658980..e3bc1a64e60 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceIdentifierSerializationHandler.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceIdentifierSerializationHandler.java
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.racelogtracking;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sse.common.Util;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceMapping.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceMapping.java
index 19fd46a3fed..afd702b188d 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceMapping.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/DeviceMapping.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import java.util.List;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceMappingFinder;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.Timed;
import com.sap.sse.common.WithID;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/PlaceHolderDeviceIdentifier.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/PlaceHolderDeviceIdentifier.java
index 6adb0e30b79..1c4d9c2b16c 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/PlaceHolderDeviceIdentifier.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/PlaceHolderDeviceIdentifier.java
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.racelogtracking;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
+import com.sap.sailing.domain.common.DeviceIdentifier;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/SmartphoneUUIDIdentifier.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/SmartphoneUUIDIdentifier.java
index 05d6e8e3671..2b5655a8c58 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/SmartphoneUUIDIdentifier.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/SmartphoneUUIDIdentifier.java
@@ -2,6 +2,8 @@ package com.sap.sailing.domain.racelogtracking;
import java.util.UUID;
+import com.sap.sailing.domain.common.DeviceIdentifier;
+
public interface SmartphoneUUIDIdentifier extends DeviceIdentifier {
String TYPE = "smartphoneUUID";
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/SmartphoneUUIDSerializationHandler.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/SmartphoneUUIDSerializationHandler.java
index 8a284d26c53..2661f799f5a 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/SmartphoneUUIDSerializationHandler.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/SmartphoneUUIDSerializationHandler.java
@@ -2,6 +2,7 @@ package com.sap.sailing.domain.racelogtracking;
import java.util.UUID;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.racelogtracking.impl.SmartphoneUUIDIdentifierImpl;
import com.sap.sse.common.Util;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingImpl.java
index 125b7c6a8b3..1a7bebc997f 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingImpl.java
@@ -5,7 +5,7 @@ import java.util.ArrayList;
import java.util.List;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TimeRange;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingWithRegattaLogEventImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingWithRegattaLogEventImpl.java
index 21096c83a03..454d2055597 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingWithRegattaLogEventImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/DeviceMappingWithRegattaLogEventImpl.java
@@ -4,7 +4,7 @@ import java.io.Serializable;
import java.util.List;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMappingEvent;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMappingWithRegattaLogEvent;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.WithID;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/PlaceHolderDeviceIdentifierSerializationHandler.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/PlaceHolderDeviceIdentifierSerializationHandler.java
index 383c40a7e5c..182fa4d18a5 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/PlaceHolderDeviceIdentifierSerializationHandler.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/racelogtracking/impl/PlaceHolderDeviceIdentifierSerializationHandler.java
@@ -1,7 +1,7 @@
package com.sap.sailing.domain.racelogtracking.impl;
+import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
-import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.PlaceHolderDeviceIdentifier;
import com.sap.sse.common.Util;
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/FixAcceptancePredicate.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/FixAcceptancePredicate.java
new file mode 100755
index 00000000000..6788fc98915
--- /dev/null
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/FixAcceptancePredicate.java
@@ -0,0 +1,14 @@
+package com.sap.sailing.domain.tracking;
+
+/**
+ * A predicate for a fix, for use in
+ * {@link Track#getInterpolatedValue(com.sap.sse.common.TimePoint, com.sap.sse.common.Util.Function)}, used, e.g., to
+ * provide a rule for when a fix shall be accepted during the search for surrounding fixes.
+ *
+ * @author Axel Uhl (d043530)
+ *
+ * @param
+ */
+public interface FixAcceptancePredicate {
+ boolean isAcceptFix(FixType fix);
+}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java
index adada1b8209..7bffcbefe56 100755
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/Track.java
@@ -5,6 +5,7 @@ import java.util.Iterator;
import java.util.concurrent.locks.ReadWriteLock;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
+import com.sap.sailing.domain.tracking.impl.TimeRangeCache;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Timed;
@@ -31,6 +32,29 @@ import com.sap.sse.common.scalablevalue.ScalableValue;
* @author Axel Uhl (d043530)
*/
public interface Track extends Serializable {
+ /**
+ * An adding function to be used together with {@link Track#getValueSum(TimePoint, TimePoint, Object, Adder, TimeRangeCache, TimeRangeValueCalculator)}.
+ *
+ * @author Axel Uhl (D043530)
+ *
+ * @param
+ */
+ static interface Adder {
+ /**
+ * Adds two elements of type {@code T}. Neither argument must be {@code null}.
+ */
+ T add(T t1, T t2);
+ }
+
+ static interface TimeRangeValueCalculator {
+ /**
+ * Calculates a value for fixes across a time range. When the method is called,
+ * a read lock will previously have been {@link Track#lockForRead obtained} before,
+ * so an implementing class does not need to worry about acquiring the lock.
+ */
+ T calculate(TimePoint from, TimePoint to);
+ }
+
/**
* Locks this track for reading by the calling thread. If the thread already holds the lock for this track,
* the hold count will be incremented. Make sure to call {@link #unlockAfterRead()} in a finally
@@ -209,6 +233,8 @@ public interface Track extends Serializable {
*/
Duration getAverageIntervalBetweenRawFixes();
+ T getValueSum(TimePoint from, TimePoint to, T nullElement, Adder adder, TimeRangeCache cache, TimeRangeValueCalculator valueCalculator);
+
/**
* @return the number of raw fixes contained in the Track.
*/
@@ -218,4 +244,5 @@ public interface Track extends Serializable {
* Tells whether the collection of {@link #getRawFixes() raw fixes} (no outliers removed) is empty
*/
boolean isEmpty();
+
}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TimeRangeCache.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TimeRangeCache.java
new file mode 100755
index 00000000000..de43e8d22f7
--- /dev/null
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TimeRangeCache.java
@@ -0,0 +1,221 @@
+package com.sap.sailing.domain.tracking.impl;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+import java.util.NavigableSet;
+
+import com.sap.sse.common.TimePoint;
+import com.sap.sse.common.Util;
+import com.sap.sse.common.Util.Pair;
+import com.sap.sse.concurrent.LockUtil;
+import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
+import com.sap.sse.util.impl.ArrayListNavigableSet;
+
+/**
+ * This cache looks "backwards." It contains pairs whose first component represents a to parameter used in
+ * a calculation for a time range. It is ordered by this component. The second component is a navigable, ordered set of
+ * pairs where the first pair component represents a from parameter used in the calculation's time range
+ * and the second pair component represents the result of the calculation for this parameter combination.
+ *
+ *
+ * For implementation efficiency in combination with using an {@link ArrayListNavigableSet} for the values and in order
+ * to be able to efficiently extend a cache entry for a single to fix, the navigable sets containing the
+ * from fixes and results are ordered such that earlier fixes come later in the set. This way, extending
+ * the cache entry for a to fix to an earlier from fix only requires appending to the set.
+ *
+ *
+ * Invalidation: When a new fix is added to the track, all cache entries for fixes at or later than the new fix's
+ * time point are removed from this cache. Additionally, the fix insertion may have an impact on the
+ * {@link #getEarliestFromAndResultAtOrAfterFrom(TimePoint, TimePoint) previous fix's} validity (track smoothing) and
+ * therefore on its selection for result aggregation. Therefore, if fix addition turned the previous fix invalid, the
+ * cache entries for the time points at or after the previous fix also need to be removed.
+ *
+ *
+ * Cache use: When a result across a time range is to be computed the calculating method should first look for a
+ * cache entry for the to parameter. If one is found, the earliest entry in the navigable set for the
+ * navigable set of from and result values that is at or after the requested from time point
+ * is determined. If such an entry exists, the result is remembered and the algorithm is repeated recursively, using the
+ * from value found in the cache as the new to value, and the from value
+ * originally passed to the calculating method as from again. If no entry is found in the cache entry for
+ * to that is at or after the requested from time, the result has to be computed "from
+ * scratch."
+ *
+ *
+ * If a cache entry for to is not found, the latest cache entry before it is looked up. If one is found,
+ * the result for the time range between the to time point requested and the to time point
+ * found in the cache is computed by iterating the smoothened fixes for this interval. If none is found, the result is
+ * computed by iterating backwards all the way to from.
+ *
+ *
+ * Once the calculating method has computed its value, it should {@link #cache(TimePoint, TimePoint, Object) add} the
+ * result to the cache.
+ *
+ * @author Axel Uhl (D043530)
+ */
+public class TimeRangeCache {
+ public static final int MAX_SIZE = 100;
+
+ private final NavigableSet>>> timeRangeCache;
+
+ /**
+ * The cache is to have limited size. Eviction shall happen based on a least-recently-used strategy. Usage is
+ * defined as having been returned by {@link #getEarliestFromAndResultAtOrAfterFrom(TimePoint, TimePoint)} or
+ * having been added by {@link #cache(TimePoint, TimePoint, Object)}.
+ *
+ *
+ * When an eldest entry is asked to be expunged from this map and the map has more than {@link #MAX_SIZE} elements,
+ * the expunging will be admitted, and the entry is removed from the {@link #timeRangeCache} core structure. Reading
+ * and writing this structure must happen under the {@link #lock write lock} because also reading the linked hash
+ * map that counts access as "use" has a modifying effect on its internal structures.
+ *
+ *
+ * The key pairs are from/to pairs. Note that this is in some sense "the opposite direction" compared to the
+ * alignment of the {@link #timeRangeCache} structure which has as its outer keys the "to" time point.
+ *
+ * Read access is to be synchronized using this field's mutex; write access only happens under the
+ * {@link #lock write lock} and therefore will have no contenders.
+ */
+ private final LinkedHashMap, Void> lruCache;
+
+ private final NamedReentrantReadWriteLock lock;
+
+ private static final Comparator> timePointInPairComparator = new Comparator>() {
+ @Override
+ public int compare(Util.Pair o1, Util.Pair o2) {
+ return o1.getA().compareTo(o2.getA());
+ }
+ };
+
+ public TimeRangeCache(String nameForLockLogging) {
+ lock = new NamedReentrantReadWriteLock("lock for TimeRangeCache for "+nameForLockLogging, /* fair */ true);
+ this.timeRangeCache = new ArrayListNavigableSet>>>(timePointInPairComparator);
+ this.lruCache = new LinkedHashMap, Void>(/* initial capacity */ 10, /* load factor */ 0.75f,
+ /* access-based ordering */ true) {
+ private static final long serialVersionUID = -6568235517111733193L;
+
+ @Override
+ protected boolean removeEldestEntry(Entry, Void> eldest) {
+ final boolean expunge = size() > MAX_SIZE;
+ if (expunge) {
+ removeCacheEntry(eldest.getKey().getA(), eldest.getKey().getB());
+ }
+ return expunge;
+ }
+ };
+ }
+
+ public int size() {
+ return lruCache.size();
+ }
+
+ private void removeCacheEntry(TimePoint from, TimePoint to) {
+ assert lock.getWriteHoldCount() == 1; // we can be sure we are alone here; this only happens when adding a new entry, holding the write lock
+ Util.Pair>> entryForTo = timeRangeCache.floor(createDummy(to));
+ if (entryForTo.getA().equals(to)) {
+ Pair entryForFrom = entryForTo.getB().ceiling(new Util.Pair(from, null));
+ if (entryForFrom.getA().equals(from)) {
+ entryForTo.getB().remove(entryForFrom);
+ if (entryForTo.getB().isEmpty()) {
+ timeRangeCache.remove(entryForTo);
+ }
+ }
+ }
+ }
+
+ /**
+ * Looks up the entry closest to but no later than to. If not found, null is returned. If
+ * found, the earliest pair of from/result that is at or after from will be returned, together with
+ * the to value of the entry. If there is no entry that is at or after from,
+ * null is returned.
+ */
+ public Util.Pair> getEarliestFromAndResultAtOrAfterFrom(TimePoint from, TimePoint to) {
+ LockUtil.lockForRead(lock);
+ try {
+ Util.Pair> result = null;
+ Util.Pair>> entryForTo = timeRangeCache.floor(createDummy(to));
+ if (entryForTo != null) {
+ final Util.Pair fromCeiling = entryForTo.getB().ceiling(new Util.Pair(from, null));
+ if (fromCeiling != null) {
+ result = new Util.Pair>(entryForTo.getA(), fromCeiling);
+ }
+ }
+ // no writer can be active because we're holding the read lock; read access on the lruCache is synchronized using
+ // the lruCache's mutex; this is necessary because we're using access-based LRU pinging where even getting an entry
+ // modifies the internal parts of the data structure which is not thread safe.
+ synchronized (lruCache) {
+ lruCache.get(new Util.Pair(from, to));
+ }
+ return result;
+ } finally {
+ LockUtil.unlockAfterRead(lock);
+ }
+ }
+
+ /**
+ * Removes all cache entries that have a to time point that is at or after timePoint.
+ */
+ public void invalidateAllAtOrLaterThan(TimePoint timePoint) {
+ LockUtil.lockForWrite(lock);
+ try {
+ Util.Pair>> dummy = createDummy(timePoint);
+ NavigableSet>>> toRemove = timeRangeCache.tailSet(dummy, /* inclusive */ true);
+ for (Iterator>>> i=toRemove.iterator(); i.hasNext(); ) {
+ Util.Pair>> entryToRemove = i.next();
+ assert entryToRemove.getA().compareTo(timePoint) >= 0;
+ for (Pair fromAndResult : entryToRemove.getB()) {
+ lruCache.remove(new Util.Pair<>(fromAndResult.getA(), entryToRemove.getA()));
+ }
+ i.remove();
+ }
+ } finally {
+ LockUtil.unlockAfterWrite(lock);
+ }
+ }
+
+ private NavigableSet> getEntryForTo(TimePoint to) {
+ NavigableSet> result = null;
+ Util.Pair>> dummyForTo = createDummy(to);
+ Util.Pair>> entryForTo = timeRangeCache.floor(dummyForTo);
+ if (entryForTo != null && entryForTo.getA().equals(to)) {
+ result = entryForTo.getB();
+ }
+ return result;
+ }
+
+ public void cache(TimePoint from, TimePoint to, T result) {
+ LockUtil.lockForWrite(lock);
+ try {
+ NavigableSet> entryForTo = getEntryForTo(to);
+ if (entryForTo == null) {
+ entryForTo = new ArrayListNavigableSet>(timePointInPairComparator);
+ Util.Pair>> pairForTo = new Util.Pair>>(
+ to, entryForTo);
+ timeRangeCache.add(pairForTo);
+ }
+ entryForTo.add(new Util.Pair(from, result));
+ lruCache.put(new Util.Pair(from, to), null);
+ } finally {
+ LockUtil.unlockAfterWrite(lock);
+ }
+ }
+
+ private Util.Pair>> createDummy(TimePoint to) {
+ return new Util.Pair>>(to, null);
+ }
+
+ /**
+ * Removes all contents from this cache
+ */
+ public void clear() {
+ LockUtil.lockForWrite(lock);
+ try {
+ timeRangeCache.clear();
+ lruCache.clear();
+ } finally {
+ LockUtil.unlockAfterWrite(lock);
+ }
+
+ }
+}
diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java
index 0685e176249..4f6a752bbcc 100644
--- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java
+++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java
@@ -6,10 +6,12 @@ import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NavigableSet;
+import com.sap.sailing.domain.tracking.FixAcceptancePredicate;
import com.sap.sailing.domain.tracking.Track;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Timed;
+import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Function;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.scalablevalue.ScalableValue;
@@ -148,14 +150,25 @@ public class TrackImpl implements Track {
@Override
public FixType getLastFixAtOrBefore(TimePoint timePoint) {
+ return getLastFixAtOrBefore(timePoint, /* fixAcceptancePredicate == null means accept all */ null);
+ }
+
+ private FixType getLastFixAtOrBefore(TimePoint timePoint, FixAcceptancePredicate fixAcceptancePredicate) {
lockForRead();
try {
- return (FixType) getInternalFixes().floor(getDummyFix(timePoint));
+ final NavigableSet headSet = getInternalFixes().headSet(getDummyFix(timePoint), /* inclusive */ true);
+ for (final Iterator i=headSet.descendingIterator(); i.hasNext(); ) {
+ final FixType next = i.next();
+ if (fixAcceptancePredicate == null || fixAcceptancePredicate.isAcceptFix(next)) {
+ return next;
+ }
+ }
+ return null;
} finally {
unlockAfterRead();
}
}
-
+
@Override
public FixType getLastFixBefore(TimePoint timePoint) {
lockForRead();
@@ -188,9 +201,20 @@ public class TrackImpl implements Track {
@Override
public FixType getFirstFixAtOrAfter(TimePoint timePoint) {
+ return getFirstFixAtOrAfter(timePoint, /* fixAcceptancePredicate==null means accept all fixes */ null);
+ }
+
+ private FixType getFirstFixAtOrAfter(TimePoint timePoint, FixAcceptancePredicate fixAcceptancePredicate) {
lockForRead();
try {
- return (FixType) getInternalFixes().ceiling(getDummyFix(timePoint));
+ final NavigableSet tailSet = getInternalFixes().tailSet(getDummyFix(timePoint), /* inclusive */ true);
+ for (final Iterator i=tailSet.iterator(); i.hasNext(); ) {
+ final FixType next = i.next();
+ if (fixAcceptancePredicate == null || fixAcceptancePredicate.isAcceptFix(next)) {
+ return next;
+ }
+ }
+ return null;
} finally {
unlockAfterRead();
}
@@ -254,9 +278,16 @@ public class TrackImpl