java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java
... ...
@@ -1418,8 +1418,4 @@ public class MockedTrackedRace implements DynamicTrackedRace {
1418 1418
WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
1419 1419
return null;
1420 1420
}
1421
-
1422
- @Override
1423
- public void updateManeuvers(Competitor competitor, Iterable<Maneuver> maneuvers) {
1424
- }
1425 1421
}
... ...
\ No newline at end of file
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/ManeuverRaceFingerprint.java
... ...
@@ -1,24 +1,12 @@
1 1
package com.sap.sailing.domain.maneuverhash;
2 2
3
-
4
-import org.json.simple.JSONObject;
5
-
6
-import com.sap.sailing.domain.tracking.TrackedRace;
7
-
8
-public interface ManeuverRaceFingerprint {
9
-
10
- /**
11
- * Returns a {@link JSONObject} of the hash values.
12
- */
13
- JSONObject toJson();
14
-
15
- /**
16
- * Incrementally computes the composite fingerprint of the {@code trackedRace} and compares to this fingerprint
17
- * component by component. The fingerprint components are computed in ascending order of computational complexity,
18
- * trying to fail early / fast.<p>
19
- *
20
- * @return {@code true} if the {@code trackedRace} produces a fingerprint equal to this one if passed to
21
- * {@link ManeuverRaceFingerprintFactory#createFingerprint(TrackedRace)}
22
- */
23
- boolean matches(TrackedRace trackedRace);
3
+import com.sap.sailing.domain.base.Competitor;
4
+import com.sap.sailing.domain.tracking.Maneuver;
5
+import com.sap.sailing.domain.tracking.RaceFingerprint;
6
+
7
+/**
8
+ * Contains fingerprint data that encodes the state of the race relevant for computing all {@link Maneuver}s
9
+ * for all {@link Competitor}s.
10
+ */
11
+public interface ManeuverRaceFingerprint extends RaceFingerprint {
24 12
}
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/ManeuverRaceFingerprintFactory.java
... ...
@@ -1,13 +1,8 @@
1 1
package com.sap.sailing.domain.maneuverhash;
2 2
3
-import com.sap.sailing.domain.tracking.TrackedRace;
4 3
import com.sap.sailing.domain.maneuverhash.impl.ManeuverRaceFingerprintFactoryImpl;
5
-import org.json.simple.JSONObject;
4
+import com.sap.sailing.domain.tracking.RaceFingerprintFactory;
6 5
7
-public interface ManeuverRaceFingerprintFactory {
6
+public interface ManeuverRaceFingerprintFactory extends RaceFingerprintFactory<ManeuverRaceFingerprint> {
8 7
ManeuverRaceFingerprintFactory INSTANCE = new ManeuverRaceFingerprintFactoryImpl();
9
-
10
- ManeuverRaceFingerprint createFingerprint (TrackedRace TrackedRace);
11
-
12
- ManeuverRaceFingerprint fromJson (JSONObject json);
13 8
}
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuverRaceFingerprintImpl.java
... ...
@@ -4,228 +4,56 @@ import java.util.Set;
4 4
5 5
import org.json.simple.JSONObject;
6 6
7
-import com.sap.sailing.domain.abstractlog.race.RaceLog;
8
-import com.sap.sailing.domain.abstractlog.race.analyzing.impl.MarkPassingDataFinder;
9
-import com.sap.sailing.domain.base.Competitor;
10
-import com.sap.sailing.domain.base.Mark;
11
-import com.sap.sailing.domain.base.Waypoint;
12 7
import com.sap.sailing.domain.common.Wind;
13 8
import com.sap.sailing.domain.common.WindSource;
14
-import com.sap.sailing.domain.common.tracking.GPSFix;
15
-import com.sap.sailing.domain.common.tracking.GPSFixMoving;
16 9
import com.sap.sailing.domain.maneuverdetection.impl.ManeuverDetectorImpl;
17 10
import com.sap.sailing.domain.maneuverhash.ManeuverRaceFingerprint;
18
-import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
19
-import com.sap.sailing.domain.tracking.GPSFixTrack;
11
+import com.sap.sailing.domain.markpassinghash.impl.MarkPassingRaceFingerprintImpl;
20 12
import com.sap.sailing.domain.tracking.TrackedRace;
21 13
import com.sap.sailing.domain.tracking.WindTrack;
22
-import com.sap.sse.common.TimePoint;
23 14
import com.sap.sse.common.Util;
24
-import com.sap.sse.common.Util.Pair;
25
-import com.sap.sse.common.Util.Triple;
26 15
27
-public class ManeuverRaceFingerprintImpl implements ManeuverRaceFingerprint {
28
- private final int calculatorVersion;
29
- private final int competitorHash;
30
- private final TimePoint startOfTracking;
31
- private final TimePoint startTimeReceived;
32
- private final TimePoint endOfTracking;
33
- private final TimePoint startTimeFromRaceLog;
34
- private final TimePoint finishTimeFromRaceLog;
35
- private final int fixedAndSuppressedMarkPassingsFromRaceLogHash;
36
- private final int waypointsHash;
37
- private final int numberOfGPSFixes;
38
- private final int gpsFixesHash;
16
+public class ManeuverRaceFingerprintImpl extends MarkPassingRaceFingerprintImpl implements ManeuverRaceFingerprint {
39 17
private final int windHash;
40 18
private final int detectorVersion;
41 19
42 20
private static enum JSON_FIELDS {
43
- COMPETITOR_HASH, START_OF_TRACKING_AS_MILLIS, END_OF_TRACKING_AS_MILLIS, START_TIME_RECEIVED_AS_MILLIS,
44
- START_TIME_FROM_RACE_LOG_AS_MILLIS, FINISH_TIME_FROM_RACE_LOG_AS_MILLIS, WAYPOINTS_HASH, NUMBEROFGPSFIXES,
45
- GPSFIXES_HASH, RACE_ID, CALCULATOR_VERSION, FIXED_AND_SUPPRESSED_MARK_PASSINGS_FROM_RACE_LOG_HASH, WIND_HASH, DETECTOR_VERSION
21
+ WIND_HASH, DETECTOR_VERSION
46 22
};
47 23
48 24
public ManeuverRaceFingerprintImpl(TrackedRace trackedRace) {
25
+ super(trackedRace);
49 26
this.detectorVersion = ManeuverDetectorImpl.DETECTOR_VERSION;
50
- this.calculatorVersion = MarkPassingCalculator.CALCULATOR_VERSION;
51
- this.competitorHash = calculateHashForCompetitors(trackedRace);
52
- this.startOfTracking = trackedRace.getStartOfTracking();
53
- this.endOfTracking = trackedRace.getEndOfTracking();
54
- this.startTimeReceived = trackedRace.getStartTimeReceived();
55
- final Pair<TimePoint, TimePoint> startAndFinishedTimeFromRaceLogs = trackedRace
56
- .getStartAndFinishedTimeFromRaceLogs();
57
- this.startTimeFromRaceLog = startAndFinishedTimeFromRaceLogs == null ? null
58
- : startAndFinishedTimeFromRaceLogs.getA();
59
- this.finishTimeFromRaceLog = startAndFinishedTimeFromRaceLogs == null ? null
60
- : startAndFinishedTimeFromRaceLogs.getB();
61
- this.waypointsHash = calculateHashForWaypoints(trackedRace);
62
- this.numberOfGPSFixes = calculateHashForNumberOfGPSFixes(trackedRace);
63
- this.gpsFixesHash = calculateHashForGPSFixes(trackedRace);
64
- this.fixedAndSuppressedMarkPassingsFromRaceLogHash = calculateFixedAndSuppressedMarkPassingsFromRaceLogHash(trackedRace);
65 27
this.windHash = calculateWindHash(trackedRace);
66 28
}
67 29
68
- private int calculateFixedAndSuppressedMarkPassingsFromRaceLogHash(TrackedRace trackedRace) {
69
- int result = 1023;
70
- for (final RaceLog raceLog : trackedRace.getAttachedRaceLogs()) {
71
- for (final Triple<Competitor, Integer, TimePoint> triple : new MarkPassingDataFinder(raceLog).analyze()) {
72
- result ^= triple.getA().getId().hashCode();
73
- result ^= triple.getB();
74
- if (triple.getC() != null) {
75
- result ^= triple.getC().hashCode();
76
- }
77
- }
78
- }
79
- return result;
80
- }
81
-
82 30
public ManeuverRaceFingerprintImpl(JSONObject json) {
31
+ super(json);
83 32
this.detectorVersion = ((Number) json.get(JSON_FIELDS.DETECTOR_VERSION.name())).intValue();
84
- this.calculatorVersion = ((Number) json.get(JSON_FIELDS.CALCULATOR_VERSION.name())).intValue();
85
- this.competitorHash = ((Number) json.get(JSON_FIELDS.COMPETITOR_HASH.name())).intValue();
86
- this.startOfTracking = TimePoint.of((Long) json.get(JSON_FIELDS.START_OF_TRACKING_AS_MILLIS.name()));
87
- this.endOfTracking = TimePoint.of((Long) json.get(JSON_FIELDS.END_OF_TRACKING_AS_MILLIS.name()));
88
- this.startTimeReceived = TimePoint.of((Long) json.get(JSON_FIELDS.START_TIME_RECEIVED_AS_MILLIS.name()));
89
- this.startTimeFromRaceLog = TimePoint
90
- .of((Long) json.get(JSON_FIELDS.START_TIME_FROM_RACE_LOG_AS_MILLIS.name()));
91
- this.finishTimeFromRaceLog = TimePoint
92
- .of((Long) json.get(JSON_FIELDS.FINISH_TIME_FROM_RACE_LOG_AS_MILLIS.name()));
93
- this.waypointsHash = ((Number) json.get(JSON_FIELDS.WAYPOINTS_HASH.name())).intValue();
94
- this.numberOfGPSFixes = ((Number) json.get(JSON_FIELDS.NUMBEROFGPSFIXES.name())).intValue();
95
- this.gpsFixesHash = ((Number) json.get(JSON_FIELDS.GPSFIXES_HASH.name())).intValue();
96
- this.fixedAndSuppressedMarkPassingsFromRaceLogHash = ((Number) json.get(JSON_FIELDS.FIXED_AND_SUPPRESSED_MARK_PASSINGS_FROM_RACE_LOG_HASH.name())).intValue();
97 33
this.windHash = ((Number) json.get(JSON_FIELDS.WIND_HASH.name())).intValue();
98 34
}
99 35
100 36
@Override
101 37
public JSONObject toJson() {
102
- JSONObject result = new JSONObject();
38
+ final JSONObject result = super.toJson();
103 39
result.put(JSON_FIELDS.DETECTOR_VERSION.name(), detectorVersion);
104
- result.put(JSON_FIELDS.CALCULATOR_VERSION.name(), calculatorVersion);
105
- result.put(JSON_FIELDS.COMPETITOR_HASH.name(), competitorHash);
106
- result.put(JSON_FIELDS.START_OF_TRACKING_AS_MILLIS.name(),
107
- startOfTracking == null ? null : startOfTracking.asMillis());
108
- result.put(JSON_FIELDS.END_OF_TRACKING_AS_MILLIS.name(),
109
- endOfTracking == null ? null : endOfTracking.asMillis());
110
- result.put(JSON_FIELDS.START_TIME_RECEIVED_AS_MILLIS.name(),
111
- startTimeReceived == null ? null : startTimeReceived.asMillis());
112
- result.put(JSON_FIELDS.START_TIME_FROM_RACE_LOG_AS_MILLIS.name(),
113
- startTimeFromRaceLog == null ? null : startTimeFromRaceLog.asMillis());
114
- result.put(JSON_FIELDS.FINISH_TIME_FROM_RACE_LOG_AS_MILLIS.name(),
115
- finishTimeFromRaceLog == null ? null : finishTimeFromRaceLog.asMillis());
116
- result.put(JSON_FIELDS.WAYPOINTS_HASH.name(), waypointsHash);
117
- result.put(JSON_FIELDS.NUMBEROFGPSFIXES.name(), numberOfGPSFixes);
118
- result.put(JSON_FIELDS.GPSFIXES_HASH.name(), gpsFixesHash);
119
- result.put(JSON_FIELDS.FIXED_AND_SUPPRESSED_MARK_PASSINGS_FROM_RACE_LOG_HASH.name(), fixedAndSuppressedMarkPassingsFromRaceLogHash);
120 40
result.put(JSON_FIELDS.WIND_HASH.name(), windHash);
121 41
return result;
122 42
}
123 43
124 44
@Override
125 45
public boolean matches(TrackedRace trackedRace) {
126
- final boolean result;
127
- if (!Util.equalsWithNull(calculatorVersion, MarkPassingCalculator.CALCULATOR_VERSION)) {
128
- result = false;
129
- }else if (!Util.equalsWithNull(detectorVersion, ManeuverDetectorImpl.DETECTOR_VERSION)) {
130
- result = false;
131
- } else if (!Util.equalsWithNull(startOfTracking, trackedRace.getStartOfTracking())) {
132
- result = false;
133
- } else if (!Util.equalsWithNull(endOfTracking, trackedRace.getEndOfTracking())) {
134
- result = false;
135
- } else if (!Util.equalsWithNull(startTimeReceived, trackedRace.getStartTimeReceived())) {
136
- result = false;
137
- } else {
138
- final Pair<TimePoint, TimePoint> startAndFinishedTimeFromRaceLogs = trackedRace
139
- .getStartAndFinishedTimeFromRaceLogs();
140
- if (!Util.equalsWithNull(startTimeFromRaceLog,
141
- startAndFinishedTimeFromRaceLogs == null ? null : startAndFinishedTimeFromRaceLogs.getA())) {
142
- result = false;
143
- } else if (!Util.equalsWithNull(finishTimeFromRaceLog,
144
- startAndFinishedTimeFromRaceLogs == null ? null : startAndFinishedTimeFromRaceLogs.getB())) {
145
- result = false;
146
- } else if (waypointsHash != calculateHashForWaypoints(trackedRace)) {
147
- result = false;
148
- } else if (competitorHash != calculateHashForCompetitors(trackedRace)) {
149
- result = false;
150
- } else if (numberOfGPSFixes != calculateHashForNumberOfGPSFixes(trackedRace)) {
151
- result = false;
152
- } else if (fixedAndSuppressedMarkPassingsFromRaceLogHash != calculateFixedAndSuppressedMarkPassingsFromRaceLogHash(trackedRace)) {
153
- result = false;
154
- } else if (gpsFixesHash != calculateHashForGPSFixes(trackedRace)) {
46
+ boolean result = super.matches(trackedRace);
47
+ if (result) {
48
+ if (!Util.equalsWithNull(detectorVersion, ManeuverDetectorImpl.DETECTOR_VERSION)) {
155 49
result = false;
156 50
} else if (windHash != calculateWindHash(trackedRace)) {
157 51
result = false;
158
- }else {
159
- result = true;
160 52
}
161 53
}
162 54
return result;
163 55
}
164 56
165
- private int calculateHashForCompetitors(TrackedRace trackedRace) {
166
- int hashForCompetitors = 1023;
167
- for (Competitor c : trackedRace.getRace().getCompetitors()) {
168
- hashForCompetitors = hashForCompetitors ^ c.getId().hashCode();
169
- }
170
- return hashForCompetitors;
171
- }
172
-
173
- private int calculateHashForNumberOfGPSFixes(TrackedRace trackedRace) {
174
- int count = 0;
175
- for (Mark m : trackedRace.getMarks()) {
176
- count += trackedRace.getTrack(m).size();
177
- }
178
- for (final Competitor competitor : trackedRace.getRace().getCompetitors()) {
179
- count += trackedRace.getTrack(competitor).size();
180
- }
181
- return count;
182
- }
183
-
184
- private int calculateHashForGPSFixes(TrackedRace trackedRace) {
185
- int res = 511;
186
- for (Mark m : trackedRace.getMarks()) {
187
- final GPSFixTrack<Mark, GPSFix> markTrack = trackedRace.getTrack(m);
188
- markTrack.lockForRead();
189
- try {
190
- for (GPSFix gf : markTrack.getRawFixes()) {
191
- res = res ^ gf.getTimePoint().hashCode();
192
- res = res ^ gf.getPosition().hashCode();
193
- }
194
- } finally {
195
- markTrack.unlockAfterRead();
196
- }
197
- }
198
- for (final Competitor competitor : trackedRace.getRace().getCompetitors()) {
199
- final GPSFixTrack<Competitor, GPSFixMoving> competitorTrack = trackedRace.getTrack(competitor);
200
- competitorTrack.lockForRead();
201
- try {
202
- for (GPSFixMoving gfm : competitorTrack.getRawFixes()) {
203
- res = res ^ gfm.getTimePoint().hashCode();
204
- res = res ^ gfm.getPosition().hashCode();
205
- res = res ^ gfm.getSpeed().getBearing().hashCode();
206
- res = res ^ Double.hashCode(gfm.getSpeed().getKnots());
207
- }
208
- } finally {
209
- competitorTrack.unlockAfterRead();
210
- }
211
- }
212
- return res;
213
- }
214
-
215
- private int calculateHashForWaypoints(TrackedRace trackedRace) {
216
- Iterable<Waypoint> waypoints = trackedRace.getRace().getCourse().getWaypoints();
217
- int res = 0;
218
- for (Waypoint p : waypoints) {
219
- Iterable<Mark> marks = p.getMarks();
220
- for (Mark m : marks) {
221
- res = res ^ m.getId().hashCode();
222
- }
223
- res = res ^ p.getPassingInstructions().name().hashCode();
224
- res = (res << 5) - res; // we want to detect changes in order
225
- }
226
- return res;
227
- }
228
-
229 57
private int calculateWindHash(TrackedRace trackedRace) {
230 58
Set<WindSource> windSoures = trackedRace.getWindSources();
231 59
int res = 0;
... ...
@@ -254,19 +82,8 @@ public class ManeuverRaceFingerprintImpl implements ManeuverRaceFingerprint {
254 82
@Override
255 83
public int hashCode() {
256 84
final int prime = 31;
257
- int result = 1;
258
- result = prime * result + calculatorVersion;
85
+ int result = super.hashCode();
259 86
result = prime * result + detectorVersion;
260
- result = prime * result + competitorHash;
261
- result = prime * result + ((endOfTracking == null) ? 0 : endOfTracking.hashCode());
262
- result = prime * result + ((finishTimeFromRaceLog == null) ? 0 : finishTimeFromRaceLog.hashCode());
263
- result = prime * result + gpsFixesHash;
264
- result = prime * result + numberOfGPSFixes;
265
- result = prime * result + ((startOfTracking == null) ? 0 : startOfTracking.hashCode());
266
- result = prime * result + ((startTimeFromRaceLog == null) ? 0 : startTimeFromRaceLog.hashCode());
267
- result = prime * result + ((startTimeReceived == null) ? 0 : startTimeReceived.hashCode());
268
- result = prime * result + waypointsHash;
269
- result = prime * result + fixedAndSuppressedMarkPassingsFromRaceLogHash;
270 87
result = prime * result + windHash;
271 88
return result;
272 89
}
... ...
@@ -279,46 +96,11 @@ public class ManeuverRaceFingerprintImpl implements ManeuverRaceFingerprint {
279 96
return false;
280 97
if (getClass() != obj.getClass())
281 98
return false;
282
- ManeuverRaceFingerprintImpl other = (ManeuverRaceFingerprintImpl) obj;
283
- if (calculatorVersion != other.calculatorVersion)
99
+ if (!super.equals(obj))
284 100
return false;
101
+ ManeuverRaceFingerprintImpl other = (ManeuverRaceFingerprintImpl) obj;
285 102
if (detectorVersion != other.detectorVersion)
286 103
return false;
287
- if (competitorHash != other.competitorHash)
288
- return false;
289
- if (endOfTracking == null) {
290
- if (other.endOfTracking != null)
291
- return false;
292
- } else if (!endOfTracking.equals(other.endOfTracking))
293
- return false;
294
- if (finishTimeFromRaceLog == null) {
295
- if (other.finishTimeFromRaceLog != null)
296
- return false;
297
- } else if (!finishTimeFromRaceLog.equals(other.finishTimeFromRaceLog))
298
- return false;
299
- if (gpsFixesHash != other.gpsFixesHash)
300
- return false;
301
- if (numberOfGPSFixes != other.numberOfGPSFixes)
302
- return false;
303
- if (startOfTracking == null) {
304
- if (other.startOfTracking != null)
305
- return false;
306
- } else if (!startOfTracking.equals(other.startOfTracking))
307
- return false;
308
- if (startTimeFromRaceLog == null) {
309
- if (other.startTimeFromRaceLog != null)
310
- return false;
311
- } else if (!startTimeFromRaceLog.equals(other.startTimeFromRaceLog))
312
- return false;
313
- if (startTimeReceived == null) {
314
- if (other.startTimeReceived != null)
315
- return false;
316
- } else if (!startTimeReceived.equals(other.startTimeReceived))
317
- return false;
318
- if (waypointsHash != other.waypointsHash)
319
- return false;
320
- if (fixedAndSuppressedMarkPassingsFromRaceLogHash != other.fixedAndSuppressedMarkPassingsFromRaceLogHash)
321
- return false;
322 104
if (windHash != other.windHash)
323 105
return false;
324 106
return true;
java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverhash/impl/ManeuversFromDatabase.java
... ...
@@ -8,20 +8,28 @@ import java.util.logging.Logger;
8 8
import com.sap.sailing.domain.base.Competitor;
9 9
import com.sap.sailing.domain.maneuverhash.ManeuverCache;
10 10
import com.sap.sailing.domain.tracking.Maneuver;
11
+import com.sap.sailing.domain.tracking.TrackedRace;
11 12
import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
12 13
14
+/**
15
+ * Stores a {@link TrackedRace}'s {@link Maneuver}s after they were loaded successfully from the persistent store.
16
+ * This happens when a race was considered equal regarding its "fingerprint" to a version loaded previously with
17
+ * all maneuvers computed and stored persistently. This saves the computational effort to compute the maneuvers
18
+ * again (persistent caching).<p>
19
+ *
20
+ * This class collaborates with {@link ManeuverCacheDelegate}.
21
+ */
13 22
public class ManeuversFromDatabase implements ManeuverCache<Competitor, List<Maneuver>, EmptyUpdateInterval> {
14
-
23
+ boolean suspended;
24
+ private static final Logger logger = Logger.getLogger(ManeuversFromDatabase.class.getName());
25
+ private final Map<Competitor, List<Maneuver>> maneuvers;
26
+
15 27
public ManeuversFromDatabase(
16 28
Map<Competitor, List<Maneuver>> maneuvers) {
17 29
super();
18 30
this.maneuvers = maneuvers;
19 31
}
20 32
21
- boolean suspended;
22
- private static final Logger logger = Logger.getLogger(ManeuversFromDatabase.class.getName());
23
- private final Map<Competitor, List<Maneuver>> maneuvers;
24
-
25 33
public void resume() {
26 34
logger.log(Level.WARNING, "Method should never be called");
27 35
}
java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingCalculator.java
... ...
@@ -461,8 +461,7 @@ public class MarkPassingCalculator {
461 461
fixesForCompetitor.addAll(competitorEntry.getValue());
462 462
}
463 463
if (!newMarkFixes.isEmpty()) {
464
- // FIXME bug 2745 use new mark fixes to invalidate chooser's mark position and mutual mark/waypoint
465
- // distance cache
464
+ // FIXME bug 2745 use new mark fixes to invalidate chooser's mark position and mutual mark/waypoint distance cache
466 465
for (Entry<Competitor, List<GPSFixMoving>> fixesAffectedByNewMarkFixes : finder
467 466
.calculateFixesAffectedByNewMarkFixes(newMarkFixes).entrySet()) {
468 467
Collection<GPSFixMoving> fixes = combinedCompetitorFixesFinderConsidersAffected
... ...
@@ -614,7 +613,7 @@ public class MarkPassingCalculator {
614 613
try {
615 614
latchForRunningListenRun.await();
616 615
final Map<Competitor, Map<Waypoint, MarkPassing>> markPassings = race.getMarkPassings(/* waitForLatestUpdates */ true);
617
- // Bei Live-Rennen Speicherung unnötig
616
+ // TODO bug6182: do we need to store when we can assume that the race is still live? How to find out reliably?
618 617
markPassingRaceFingerprintRegistry.storeMarkPassings(race.getRaceIdentifier(),
619 618
MarkPassingRaceFingerprintFactory.INSTANCE.createFingerprint(race),
620 619
markPassings, race.getRace().getCourse());
java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassinghash/MarkPassingRaceFingerprint.java
... ...
@@ -5,24 +5,28 @@ import org.json.simple.JSONObject;
5 5
import com.sap.sailing.domain.base.Course;
6 6
import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
7 7
import com.sap.sailing.domain.tracking.MarkPassing;
8
+import com.sap.sailing.domain.tracking.RaceFingerprint;
8 9
import com.sap.sailing.domain.tracking.TrackedRace;
9 10
10 11
/**
11 12
* An instance of this class represents a composite fingerprint of those components of a {@link TrackedRace} that are
12
- * relevant for computing the
13
+ * relevant for computing
13 14
* {@link TrackedRace#getMarkPassing(com.sap.sailing.domain.base.Competitor, com.sap.sailing.domain.base.Waypoint) mark
14
- * passings} in the {@link MarkPassingCalculator}. It can be {@link #matches(TrackedRace) matched} against a {@link TrackedRace}
15
- * instance to see whether the {@link TrackedRace} will produce a set of {@link MarkPassing}s equal to that of the {@link TrackedRace}
16
- * from which this fingerprint was produced.<p>
15
+ * passings} in the {@link MarkPassingCalculator}. It can be {@link #matches(TrackedRace) matched} against a
16
+ * {@link TrackedRace} instance to see whether the {@link TrackedRace} will produce a set of {@link MarkPassing}s equal
17
+ * to that of the {@link TrackedRace} from which this fingerprint was produced.
18
+ * <p>
17 19
*
18
- * To produce a fingerprint from a {@link TrackedRace} or from a JSON representation use {@link MarkPassingRaceFingerprintFactory}.<p>
20
+ * To produce a fingerprint from a {@link TrackedRace} or from a JSON representation use
21
+ * {@link MarkPassingRaceFingerprintFactory}.
22
+ * <p>
19 23
*
20 24
* The {@link #equals(Object)} and {@link #hashCode()} methods are defined based on the contents of this fingerprint.
21 25
*
22 26
* @author Fabian Kallenbach (i550803)
23 27
* @author Axel Uhl (d043530)
24 28
*/
25
-public interface MarkPassingRaceFingerprint {
29
+public interface MarkPassingRaceFingerprint extends RaceFingerprint {
26 30
/**
27 31
* Returns a {@link JSONObject} of the hash values.
28 32
*/
java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassinghash/MarkPassingRaceFingerprintFactory.java
... ...
@@ -1,26 +1,13 @@
1 1
package com.sap.sailing.domain.markpassinghash;
2 2
3
-import org.json.simple.JSONObject;
4
-
5 3
import com.sap.sailing.domain.markpassinghash.impl.MarkPassingRaceFingerprintFactoryImpl;
6
-import com.sap.sailing.domain.tracking.TrackedRace;
4
+import com.sap.sailing.domain.tracking.RaceFingerprintFactory;
7 5
8 6
/**
9 7
* Factory for the creation of a {@link MarkPassingRaceFingerprint}.
10 8
*
11 9
* @author Fabian Kallenbach (i550803)
12 10
*/
13
-public interface MarkPassingRaceFingerprintFactory {
11
+public interface MarkPassingRaceFingerprintFactory extends RaceFingerprintFactory<MarkPassingRaceFingerprint> {
14 12
MarkPassingRaceFingerprintFactory INSTANCE = new MarkPassingRaceFingerprintFactoryImpl();
15
-
16
- /**
17
- * Creates a {@link MarkPassingRaceFingerprint} out of a given {@link TrackedRace}.
18
- */
19
- MarkPassingRaceFingerprint createFingerprint(TrackedRace trackedRace);
20
-
21
- /**
22
- * Creates a {@link MarkPassingRaceFingerprint} out of a given {@link JSONObject}, as produced by
23
- * {@link MarkPassingRaceFingerprint#toJson()}.
24
- */
25
- MarkPassingRaceFingerprint fromJson(JSONObject json);
26 13
}
... ...
\ No newline at end of file
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicTrackedRace.java
... ...
@@ -131,7 +131,7 @@ public interface DynamicTrackedRace extends TrackedRace {
131 131
* for the finish line that are affected will be {@link #updateMarkPassings(Competitor, Iterable) updated}.
132 132
*/
133 133
void updateMarkPassingsAfterRaceLogChanges();
134
-
134
+
135 135
/**
136 136
* Sets the start time as received from the tracking infrastructure. This isn't necessarily
137 137
* what {@link #getStart()} will deliver which assumes that the time announced here may be
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceFingerprint.java
... ...
@@ -0,0 +1,47 @@
1
+package com.sap.sailing.domain.tracking;
2
+
3
+import org.json.simple.JSONObject;
4
+
5
+import com.sap.sailing.domain.base.Course;
6
+import com.sap.sailing.domain.markpassingcalculation.MarkPassingCalculator;
7
+import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprintFactory;
8
+
9
+/**
10
+ * An instance of this class represents a composite fingerprint of those components of a {@link TrackedRace} that are
11
+ * relevant for computing some metric or value that causes significant computational effort and hence lends itself well
12
+ * for persistent caching, such as mark passings or maneuvers. It can be {@link #matches(TrackedRace) matched} against a
13
+ * {@link TrackedRace} instance to see whether the {@link TrackedRace} will produce a metric or value equal to that of
14
+ * the {@link TrackedRace} from which this fingerprint was produced.
15
+ * <p>
16
+ *
17
+ * To produce a fingerprint from a {@link TrackedRace} or from a JSON representation use a
18
+ * {@link RaceFingerprintFactory}.
19
+ * <p>
20
+ *
21
+ * The {@link #equals(Object)} and {@link #hashCode()} methods are defined based on the contents of this fingerprint.
22
+ *
23
+ * @author Fabian Kallenbach (i550803)
24
+ * @author Axel Uhl (d043530)
25
+ */
26
+public interface RaceFingerprint {
27
+ /**
28
+ * Returns a {@link JSONObject} of the hash values.
29
+ */
30
+ JSONObject toJson();
31
+
32
+ /**
33
+ * Incrementally computes the composite fingerprint of the {@code trackedRace} and compares to this fingerprint
34
+ * component by component. The fingerprint components are computed in ascending order of computational complexity,
35
+ * trying to fail early / fast.<p>
36
+ *
37
+ * The implementation may require to obtain the race's {@link Course#lockForRead() read lock}. Note that conversely
38
+ * updates to the course that happen under the course's write lock will trigger listeners which may synchronize
39
+ * on certain objects, such as the {@link MarkPassingCalculator}. Therefore, should this method be called
40
+ * while holding an object monitor ("synchronized") that a course update listener may also require, make
41
+ * sure to first obtain at least the course read lock before invoking this method. See also bug 5803.
42
+ *
43
+ * @return {@code true} if the {@code trackedRace} produces a fingerprint equal to this one if passed to
44
+ * {@link MarkPassingRaceFingerprintFactory#createFingerprint(TrackedRace)}
45
+ */
46
+ boolean matches(TrackedRace trackedRace);
47
+}
... ...
\ No newline at end of file
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceFingerprintFactory.java
... ...
@@ -0,0 +1,23 @@
1
+package com.sap.sailing.domain.tracking;
2
+
3
+import org.json.simple.JSONObject;
4
+
5
+import com.sap.sailing.domain.markpassinghash.MarkPassingRaceFingerprint;
6
+
7
+/**
8
+ * Factory for the creation of a {@link MarkPassingRaceFingerprint}.
9
+ *
10
+ * @author Fabian Kallenbach (i550803)
11
+ */
12
+public interface RaceFingerprintFactory<RFP extends RaceFingerprint> {
13
+ /**
14
+ * Creates a {@link RaceFingerprint} out of a given {@link TrackedRace}.
15
+ */
16
+ RFP createFingerprint(TrackedRace trackedRace);
17
+
18
+ /**
19
+ * Creates a {@link RaceFingerprint} out of a given {@link JSONObject}, as produced by
20
+ * {@link RaceFingerprint#toJson()}.
21
+ */
22
+ RFP fromJson(JSONObject json);
23
+}
... ...
\ No newline at end of file
java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/RaceTrackingConnectivityParameters.java
... ...
@@ -43,9 +43,11 @@ public interface RaceTrackingConnectivityParameters extends Serializable {
43 43
* tracker.
44 44
*/
45 45
RaceTracker createRaceTracker(TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
46
- RaceLogAndTrackedRaceResolver raceLogResolver, LeaderboardGroupResolver leaderboardGroupResolver, long timeoutInMilliseconds,
47
- RaceTrackingHandler raceTrackingHandler, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) throws Exception;
48
-
46
+ RaceLogAndTrackedRaceResolver raceLogResolver, LeaderboardGroupResolver leaderboardGroupResolver,
47
+ long timeoutInMilliseconds, RaceTrackingHandler raceTrackingHandler,
48
+ MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry,
49
+ ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) throws Exception;
50
+
49 51
/**
50 52
* Starts a {@link RaceTracker}, associating the resulting races with the {@link Regatta} passed as argument instead
51 53
* of using the tracker's domain factory to obtain a default {@link Regatta} object for the tracking parameters.
... ...
@@ -58,9 +60,11 @@ public interface RaceTrackingConnectivityParameters extends Serializable {
58 60
* {@link TrackedRegattaRegistry#removeRace(Regatta, com.sap.sailing.domain.base.RaceDefinition)}.
59 61
*/
60 62
RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry, WindStore windStore,
61
- RaceLogAndTrackedRaceResolver raceLogResolver, LeaderboardGroupResolver leaderboardGroupResolver, long timeoutInMilliseconds,
62
- RaceTrackingHandler raceTrackingHandler, MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry, ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) throws Exception;
63
-
63
+ RaceLogAndTrackedRaceResolver raceLogResolver, LeaderboardGroupResolver leaderboardGroupResolver,
64
+ long timeoutInMilliseconds, RaceTrackingHandler raceTrackingHandler,
65
+ MarkPassingRaceFingerprintRegistry markPassingRaceFingerprintRegistry,
66
+ ManeuverRaceFingerprintRegistry maneuverRaceFingerprintRegistry) throws Exception;
67
+
64 68
/**
65 69
* Deliver an ID object equal to that of the {@link RaceTracker#getID()} delivered by the {@link RaceTracker}
66 70
* that will be created from these parameters by calling {@link #createRaceTracker(TrackedRegattaRegistry)}.