From 9e8a35cb28a045a2902abf12da5d8059ca79b76b Mon Sep 17 00:00:00 2001 From: Vladislav Chumak Date: Fri, 16 Mar 2018 17:43:45 +0100 Subject: [PATCH 01/11] Removed "Mark Passing" maneuver type and refactored it into separate flag of maneuver interface --- .../MarkPassingRetrievalProcessor.java | 6 +- .../impl/data/MarkPassingWithContext.java | 12 +- .../sailing/domain/common/ManeuverType.java | 2 +- .../impl/AbstractLeaderboardWithCache.java | 16 +- .../impl/ManeuverDetectorImpl.java | 182 ++++++++++-------- .../sap/sailing/domain/tracking/Maneuver.java | 17 ++ .../domain/tracking/MarkPassingManeuver.java | 10 - .../domain/tracking/impl/ManeuverImpl.java | 21 +- .../ManeuverWithMainCurveBoundariesImpl.java | 5 +- ...ithStableSpeedAndCourseBoundariesImpl.java | 5 +- .../impl/MarkPassingManeuverImpl.java | 46 ----- .../gwt/ui/client/ManeuverTypeFormatter.java | 2 - .../gwt/ui/server/SailingServiceImpl.java | 6 +- 13 files changed, 161 insertions(+), 169 deletions(-) delete mode 100755 java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/MarkPassingManeuver.java delete mode 100755 java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/MarkPassingManeuverImpl.java diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/MarkPassingRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/MarkPassingRetrievalProcessor.java index 5f1b685ab4a..da98865c19c 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/MarkPassingRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/MarkPassingRetrievalProcessor.java @@ -7,10 +7,8 @@ import java.util.concurrent.ExecutorService; import com.sap.sailing.datamining.data.HasMarkPassingContext; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; import com.sap.sailing.datamining.impl.data.MarkPassingWithContext; -import com.sap.sailing.domain.common.ManeuverType; import com.sap.sailing.domain.common.NoWindException; import com.sap.sailing.domain.tracking.Maneuver; -import com.sap.sailing.domain.tracking.MarkPassingManeuver; import com.sap.sse.common.TimePoint; import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor; @@ -30,8 +28,8 @@ public class MarkPassingRetrievalProcessor extends AbstractRetrievalProcessor maneuvers = element.getTrackedLegOfCompetitor().getManeuvers(finishTime, false); for (Maneuver maneuver : maneuvers) { - if (maneuver.getType() == ManeuverType.MARK_PASSING) { - maneuversWithContext.add(new MarkPassingWithContext(element, (MarkPassingManeuver) maneuver)); + if (maneuver.isMarkPassing()) { + maneuversWithContext.add(new MarkPassingWithContext(element, maneuver)); } } } catch (NoWindException e) { diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/MarkPassingWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/MarkPassingWithContext.java index 76923fef37e..130d37a57d3 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/MarkPassingWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/MarkPassingWithContext.java @@ -7,22 +7,22 @@ import com.sap.sailing.domain.base.Waypoint; import com.sap.sailing.domain.common.NauticalSide; import com.sap.sailing.domain.common.Wind; import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.tracking.MarkPassingManeuver; +import com.sap.sailing.domain.tracking.Maneuver; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sse.common.Util; public class MarkPassingWithContext implements HasMarkPassingContext { private static final long serialVersionUID = -337042113749307686L; private final HasTrackedLegOfCompetitorContext trackedLegOfCompetitor; - private final MarkPassingManeuver maneuver; + private final Maneuver maneuver; private Double absoluteRank; private boolean rankHasBeenInitialized; private Wind wind; - public MarkPassingWithContext(HasTrackedLegOfCompetitorContext trackedLegOfCompetitor, MarkPassingManeuver maneuver) { + public MarkPassingWithContext(HasTrackedLegOfCompetitorContext trackedLegOfCompetitor, Maneuver markPassingManeuver) { this.trackedLegOfCompetitor = trackedLegOfCompetitor; - this.maneuver = maneuver; + this.maneuver = markPassingManeuver; } @Override @@ -31,13 +31,13 @@ public class MarkPassingWithContext implements HasMarkPassingContext { } @Override - public MarkPassingManeuver getManeuver() { + public Maneuver getManeuver() { return maneuver; } @Override public Waypoint getWaypoint() { - return getManeuver().getWaypointPassed(); + return getManeuver().getMarkPassing().getWaypoint(); } @Override diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ManeuverType.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ManeuverType.java index 6412b44b236..52eae29de56 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ManeuverType.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/ManeuverType.java @@ -1,5 +1,5 @@ package com.sap.sailing.domain.common; public enum ManeuverType { - HEAD_UP, BEAR_AWAY, TACK, JIBE, PENALTY_CIRCLE, MARK_PASSING, UNKNOWN; + HEAD_UP, BEAR_AWAY, TACK, JIBE, PENALTY_CIRCLE, UNKNOWN; } \ No newline at end of file diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java index ad2bbf6eb14..c9ec2114367 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java @@ -69,7 +69,6 @@ import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo; import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.Maneuver; import com.sap.sailing.domain.tracking.MarkPassing; -import com.sap.sailing.domain.tracking.MarkPassingManeuver; import com.sap.sailing.domain.tracking.RaceChangeListener; import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; @@ -950,19 +949,18 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard { } } break; - case MARK_PASSING: - // analyze all mark passings, not only those after this leg's start, to catch the mark passing - // maneuver starting this leg, even if its time point is slightly before the mark passing starting this leg - MarkPassingManeuver mpm = (MarkPassingManeuver) maneuver; - if (mpm.getWaypointPassed() == trackedLeg.getLeg().getFrom()) { - result.sideToWhichMarkAtLegStartWasRounded = mpm.getSide(); - } - break; default: /* Do nothing here. * Throwing an exception destroys the toggling (and maybe other behaviour) of the leaderboard. */ } + if(maneuver.isMarkPassing()) { + // analyze all mark passings, not only those after this leg's start, to catch the mark passing + // maneuver starting this leg, even if its time point is slightly before the mark passing starting this leg + if (maneuver.getMarkPassing().getWaypoint() == trackedLeg.getLeg().getFrom()) { + result.sideToWhichMarkAtLegStartWasRounded = maneuver.getSide(); + } + } } result.averageManeuverLossInMeters = new HashMap(); for (ManeuverType maneuverType : new ManeuverType[] { ManeuverType.TACK, ManeuverType.JIBE, diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java index ce1ba3c2410..9d4b0e29306 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java @@ -35,7 +35,6 @@ import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.impl.ManeuverWithMainCurveBoundariesImpl; import com.sap.sailing.domain.tracking.impl.ManeuverWithStableSpeedAndCourseBoundariesImpl; -import com.sap.sailing.domain.tracking.impl.MarkPassingManeuverImpl; import com.sap.sailing.domain.tracking.impl.SpeedWithBearingStepImpl; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; @@ -416,30 +415,15 @@ public class ManeuverDetectorImpl implements ManeuverDetector { maneuverMainCurveDetails.getTimePointBefore()); TrackedLegOfCompetitor legAfterManeuver = trackedRace.getTrackedLeg(competitor, maneuverMainCurveDetails.getTimePointAfter()); - Waypoint waypointPassed = null; // set for MARK_PASSING maneuvers only - NauticalSide sideToWhichWaypointWasPassed = null; // set for MARK_PASSING maneuvers only - // check for mask passing first; a tacking / jibe-setting mark rounding thus takes precedence over being - // detected as a penalty circle - final TimePoint markPassingTimePoint; + MarkPassing markPassing = null; // will remain null if no mark passing has been recorded within maneuver + // boundaries + // check whether a waypoint has been passed within maneuver if (legBeforeManeuver != legAfterManeuver // a maneuver at the start line is not to be considered a MARK_PASSING maneuver; show a tack as a tack && legAfterManeuver != null && legAfterManeuver.getLeg().getFrom() != trackedRace.getRace().getCourse().getFirstWaypoint()) { - waypointPassed = legAfterManeuver.getLeg().getFrom(); - MarkPassing markPassing = trackedRace.getMarkPassing(competitor, waypointPassed); - markPassingTimePoint = markPassing != null ? markPassing.getTimePoint() : maneuverDetails.getTimePoint(); - Position markPassingPosition = markPassing != null - ? competitorTrack.getEstimatedPosition(markPassingTimePoint, /* extrapolate */false) - : maneuverPosition; - sideToWhichWaypointWasPassed = maneuverDirection; - // produce an additional mark passing maneuver; continue to analyze to catch jibe sets and kiwi drops - maneuvers.add(new MarkPassingManeuverImpl(ManeuverType.MARK_PASSING, tackAfterManeuver, markPassingPosition, - maneuverLoss, markPassingTimePoint, maneuverMainCurveDetails.extractCurveBoundariesOnly(), - maneuverDetails.extractCurveBoundariesOnly(), - maneuverMainCurveDetails.getMaxAngularVelocityInDegreesPerSecond(), waypointPassed, - sideToWhichWaypointWasPassed)); - } else { - markPassingTimePoint = null; + Waypoint waypointPassed = legAfterManeuver.getLeg().getFrom(); + markPassing = trackedRace.getMarkPassing(competitor, waypointPassed); } BearingChangeAnalyzer bearingChangeAnalyzer = BearingChangeAnalyzer.INSTANCE; final Bearing courseBeforeManeuver = maneuverMainCurveDetails.getSpeedWithBearingBefore().getBearing(); @@ -451,26 +435,40 @@ public class ManeuverDetectorImpl implements ManeuverDetector { int numberOfTacks = wind == null ? 0 : bearingChangeAnalyzer.didPass(courseBeforeManeuver, mainCurveTotalCourseChangeInDegrees, courseAfterManeuver, wind.getFrom()); - if (markPassingTimePoint != null && (numberOfTacks + numberOfJibes > 0)) { - // In case of a mark passing we need to split the maneuver analysis into the phase before and after - // the mark passing. First of all, this is important to identify the correct maneuver time point for - // each tack and jibe, second it is essential to call a penalty which is only the case if the tack and - // the jibe are on the same side of the mark passing; otherwise this may have been a jibe set or a - // kiwi drop. - // Therefore, we recursively detect the maneuvers for the segment before and the segment after the - // mark passing and add the results to our result. - List maneuverSpots = detectManeuvers(maneuverDetails.getTimePointBefore(), - markPassingTimePoint.minus(1)); - maneuverSpots.addAll(detectManeuvers(markPassingTimePoint.plus(1), maneuverDetails.getTimePointAfter())); - maneuvers.addAll(getAllManeuversFromManeuverSpots(maneuverSpots)); - } else { - // Either there was no mark passing, or the mark passing was not accompanied by a tack or a jibe. - // For the first tack/jibe combination (they must alternate because the course changes in the same direction - // and - // the wind is considered sufficiently stable to not allow for two successive tacks or two successive jibes) - // we create a PENALTY_CIRCLE maneuver and recurse for the time interval after the first penalty circle has - // completed. - if (numberOfTacks > 0 && numberOfJibes > 0 && markPassingTimePoint == null) { + if (numberOfTacks > 0 && numberOfJibes > 0) { + boolean performPenaltyCircleAnalysis = true; + if (markPassing != null) { + // In case of a mark passing we need to split the maneuver analysis into the phase before and after + // the mark passing to catch kiwi drops. First of all, this is important to identify the correct + // maneuver time point for + // each tack and jibe, second it is essential to call a penalty which is only the case if the tack and + // the jibe are on the same side of the mark passing; otherwise this may have been a + // kiwi drop. + // Therefore, we recursively detect the maneuvers for the segment before and the segment after the + // mark passing and add the results to our result. + List maneuverSpotsBeforeMarkPassing = detectManeuvers( + maneuverDetails.getTimePointBefore(), markPassing.getTimePoint().minus(1)); + List maneuverSpotsAfterMarkPassing = detectManeuvers(markPassing.getTimePoint().plus(1), + maneuverDetails.getTimePointAfter()); + // split the penalty circle maneuver only by mark passing time point if tacks or jibes are present on + // both legs + if (getNumberOfTacksAndJibesFromManeuverSpots(maneuverSpotsAfterMarkPassing) != 0 + && getNumberOfTacksAndJibesFromManeuverSpots(maneuverSpotsAfterMarkPassing) != 0) { + performPenaltyCircleAnalysis = false; + maneuverSpotsBeforeMarkPassing.addAll(maneuverSpotsAfterMarkPassing); + maneuvers.addAll(getAllManeuversFromManeuverSpots(maneuverSpotsBeforeMarkPassing)); + } + } + if (performPenaltyCircleAnalysis) { + // Either there was no mark passing, or the mark passing was not accompanied by a tack or a jibe. + // For the first tack/jibe combination (they must alternate because the course changes in the same + // direction + // and + // the wind is considered sufficiently stable to not allow for two successive tacks or two successive + // jibes) + // we create a PENALTY_CIRCLE maneuver and recurse for the time interval after the first penalty circle + // has + // completed. TimePoint firstPenaltyCircleCompletedAt = getTimePointOfCompletionOfFirstPenaltyCircle( maneuverMainCurveDetails.getTimePointBefore(), courseBeforeManeuver, maneuverMainCurveDetails.getSpeedWithBearingSteps(), wind); @@ -511,7 +509,7 @@ public class ManeuverDetectorImpl implements ManeuverDetector { tackAfterManeuver, penaltyPosition, maneuverLoss, refinedPenaltyDetails.getTimePoint(), refinedPenaltyMainCurveDetails.extractCurveBoundariesOnly(), refinedPenaltyDetails.extractCurveBoundariesOnly(), - refinedPenaltyMainCurveDetails.getMaxAngularVelocityInDegreesPerSecond()); + refinedPenaltyMainCurveDetails.getMaxAngularVelocityInDegreesPerSecond(), markPassing); maneuvers.add(maneuver); // after we've "consumed" one tack and one jibe, recursively find more maneuvers if tacks and/or jibes // remain @@ -520,52 +518,74 @@ public class ManeuverDetectorImpl implements ManeuverDetector { maneuverDetails.getTimePointAfter()); maneuvers.addAll(getAllManeuversFromManeuverSpots(maneuverSpots)); } - } else { - final Maneuver maneuver; - if (numberOfTacks > 0 || numberOfJibes > 0) { - maneuverType = numberOfTacks > 0 ? ManeuverType.TACK : ManeuverType.JIBE; - maneuverLoss = getManeuverLoss(maneuverDetails.getTimePointBefore(), maneuverDetails.getTimePoint(), - maneuverDetails.getTimePointAfter()); - maneuver = new ManeuverWithStableSpeedAndCourseBoundariesImpl(maneuverType, tackAfterManeuver, - maneuverPosition, maneuverLoss, maneuverDetails.getTimePoint(), - maneuverMainCurveDetails.extractCurveBoundariesOnly(), - maneuverDetails.extractCurveBoundariesOnly(), - maneuverMainCurveDetails.getMaxAngularVelocityInDegreesPerSecond()); - } else if (wind != null) { - // heading up or bearing away - Bearing windBearing = wind.getBearing(); - Bearing toWindBeforeManeuver = windBearing - .getDifferenceTo(maneuverMainCurveDetails.getSpeedWithBearingBefore().getBearing()); - Bearing toWindAfterManeuver = windBearing - .getDifferenceTo(maneuverMainCurveDetails.getSpeedWithBearingAfter().getBearing()); - maneuverType = Math.abs(toWindBeforeManeuver.getDegrees()) < Math - .abs(toWindAfterManeuver.getDegrees()) ? ManeuverType.HEAD_UP : ManeuverType.BEAR_AWAY; - // treat maneuver main curve details as main maneuver details, because the detected maneuver is - // either HEAD_UP or BEAR_AWAY - maneuver = new ManeuverWithMainCurveBoundariesImpl(maneuverType, tackAfterManeuver, - maneuverPosition, maneuverLoss, maneuverDetails.getTimePoint(), - maneuverMainCurveDetails.extractCurveBoundariesOnly(), - maneuverDetails.extractCurveBoundariesOnly(), - maneuverMainCurveDetails.getMaxAngularVelocityInDegreesPerSecond()); - } else { - // no wind information; marking as UNKNOWN - maneuverType = ManeuverType.UNKNOWN; - maneuverLoss = getManeuverLoss(maneuverDetails.getTimePointBefore(), maneuverDetails.getTimePoint(), - maneuverDetails.getTimePointAfter()); - maneuver = new ManeuverWithStableSpeedAndCourseBoundariesImpl(maneuverType, tackAfterManeuver, - maneuverPosition, maneuverLoss, maneuverDetails.getTimePoint(), - maneuverMainCurveDetails.extractCurveBoundariesOnly(), - maneuverDetails.extractCurveBoundariesOnly(), - maneuverMainCurveDetails.getMaxAngularVelocityInDegreesPerSecond()); - } - maneuvers.add(maneuver); } + } else { + final Maneuver maneuver; + if (numberOfTacks > 0 || numberOfJibes > 0) { + maneuverType = numberOfTacks > 0 ? ManeuverType.TACK : ManeuverType.JIBE; + maneuverLoss = getManeuverLoss(maneuverDetails.getTimePointBefore(), maneuverDetails.getTimePoint(), + maneuverDetails.getTimePointAfter()); + maneuver = new ManeuverWithStableSpeedAndCourseBoundariesImpl(maneuverType, tackAfterManeuver, + maneuverPosition, maneuverLoss, maneuverDetails.getTimePoint(), + maneuverMainCurveDetails.extractCurveBoundariesOnly(), + maneuverDetails.extractCurveBoundariesOnly(), + maneuverMainCurveDetails.getMaxAngularVelocityInDegreesPerSecond(), markPassing); + } else if (wind != null) { + // heading up or bearing away + Bearing windBearing = wind.getBearing(); + Bearing toWindBeforeManeuver = windBearing + .getDifferenceTo(maneuverMainCurveDetails.getSpeedWithBearingBefore().getBearing()); + Bearing toWindAfterManeuver = windBearing + .getDifferenceTo(maneuverMainCurveDetails.getSpeedWithBearingAfter().getBearing()); + maneuverType = Math.abs(toWindBeforeManeuver.getDegrees()) < Math.abs(toWindAfterManeuver.getDegrees()) + ? ManeuverType.HEAD_UP : ManeuverType.BEAR_AWAY; + // treat maneuver main curve details as main maneuver details, because the detected maneuver is + // either HEAD_UP or BEAR_AWAY + maneuver = new ManeuverWithMainCurveBoundariesImpl(maneuverType, tackAfterManeuver, maneuverPosition, + maneuverLoss, maneuverDetails.getTimePoint(), + maneuverMainCurveDetails.extractCurveBoundariesOnly(), + maneuverDetails.extractCurveBoundariesOnly(), + maneuverMainCurveDetails.getMaxAngularVelocityInDegreesPerSecond(), markPassing); + } else { + // no wind information; marking as UNKNOWN + maneuverType = ManeuverType.UNKNOWN; + maneuverLoss = getManeuverLoss(maneuverDetails.getTimePointBefore(), maneuverDetails.getTimePoint(), + maneuverDetails.getTimePointAfter()); + maneuver = new ManeuverWithStableSpeedAndCourseBoundariesImpl(maneuverType, tackAfterManeuver, + maneuverPosition, maneuverLoss, maneuverDetails.getTimePoint(), + maneuverMainCurveDetails.extractCurveBoundariesOnly(), + maneuverDetails.extractCurveBoundariesOnly(), + maneuverMainCurveDetails.getMaxAngularVelocityInDegreesPerSecond(), markPassing); + } + maneuvers.add(maneuver); } return new ManeuverSpot(new ArrayList<>(douglasPeuckerFixesGroup), maneuverDirection, maneuvers, new WindMeasurement(maneuverDetails.getTimePoint(), maneuverPosition, wind == null ? null : wind.getBearing())); } + private int getNumberOfTacksAndJibesFromManeuverSpots(List maneuverSpots) { + int tackAndJibeCount = 0; + for (ManeuverSpot maneuverSpot : maneuverSpots) { + for (Maneuver maneuver : maneuverSpot.getManeuvers()) { + switch (maneuver.getType()) { + case JIBE: + case TACK: + ++tackAndJibeCount; + break; + case PENALTY_CIRCLE: + tackAndJibeCount += 2; + break; + case BEAR_AWAY: + case HEAD_UP: + case UNKNOWN: + break; + } + } + } + return tackAndJibeCount; + } + /** * Computes the maneuver loss as the distance projected onto the average course between entering and exiting the * maneuver that the boat lost compared to not having maneuvered. With this distance measure, the competitors speed diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/Maneuver.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/Maneuver.java index 9ab81f3dfae..b30061f143e 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/Maneuver.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/Maneuver.java @@ -2,6 +2,7 @@ package com.sap.sailing.domain.tracking; import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.ManeuverType; +import com.sap.sailing.domain.common.NauticalSide; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.Tack; @@ -141,4 +142,20 @@ public interface Maneuver extends GPSFix { */ Speed getLowestSpeed(); + /** + * Gets the mark passing which is contained within maneuver. In case if no mark passing was passed, {@code null} is + * returned. + */ + MarkPassing getMarkPassing(); + + /** + * Determines whether the maneuver is mark passing maneuver. + */ + boolean isMarkPassing(); + + /** + * Gets the direction of the maneuver. It corresponds to the direction of mark passing side. + */ + NauticalSide getSide(); + } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/MarkPassingManeuver.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/MarkPassingManeuver.java deleted file mode 100755 index e12ae4e7218..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/MarkPassingManeuver.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.sap.sailing.domain.tracking; - -import com.sap.sailing.domain.base.Waypoint; -import com.sap.sailing.domain.common.NauticalSide; - -public interface MarkPassingManeuver extends Maneuver { - Waypoint getWaypointPassed(); - - NauticalSide getSide(); -} diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverImpl.java index 6ad3b871da7..653285bc44a 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverImpl.java @@ -2,6 +2,7 @@ package com.sap.sailing.domain.tracking.impl; import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.ManeuverType; +import com.sap.sailing.domain.common.NauticalSide; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Speed; import com.sap.sailing.domain.common.SpeedWithBearing; @@ -9,6 +10,7 @@ import com.sap.sailing.domain.common.Tack; import com.sap.sailing.domain.common.tracking.impl.AbstractGPSFixImpl; import com.sap.sailing.domain.tracking.Maneuver; import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries; +import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sse.common.TimePoint; /** @@ -25,11 +27,12 @@ public abstract class ManeuverImpl extends AbstractGPSFixImpl implements Maneuve private final double maxAngularVelocityInDegreesPerSecond; private final ManeuverCurveBoundaries mainCurveBoundaries; private final ManeuverCurveBoundaries maneuverCurveWithStableSpeedAndCourseBoundaries; + private final MarkPassing markPassing; public ManeuverImpl(ManeuverType type, Tack newTack, Position position, Distance maneuverLoss, TimePoint timePoint, ManeuverCurveBoundaries mainCurveBoundaries, ManeuverCurveBoundaries maneuverCurveWithStableSpeedAndCourseBoundaries, - double maxAngularVelocityInDegreesPerSecond) { + double maxAngularVelocityInDegreesPerSecond, MarkPassing markPassing) { this.type = type; this.newTack = newTack; this.position = position; @@ -38,6 +41,7 @@ public abstract class ManeuverImpl extends AbstractGPSFixImpl implements Maneuve this.mainCurveBoundaries = mainCurveBoundaries; this.maneuverCurveWithStableSpeedAndCourseBoundaries = maneuverCurveWithStableSpeedAndCourseBoundaries; this.maxAngularVelocityInDegreesPerSecond = maxAngularVelocityInDegreesPerSecond; + this.markPassing = markPassing; } @Override @@ -100,7 +104,8 @@ public abstract class ManeuverImpl extends AbstractGPSFixImpl implements Maneuve return super.toString() + " " + type + " on new tack " + newTack + " on position " + position + " at time point " + timePoint + ", " + getManeuverBoundaries() + ", max. angular velocity: " + maxAngularVelocityInDegreesPerSecond - + (getManeuverLoss() == null ? "" : " Lost approximately " + getManeuverLoss()); + + (getManeuverLoss() == null ? "" : ", Lost approximately " + getManeuverLoss()) + ", Mark passing: " + + markPassing; } @Override @@ -108,4 +113,16 @@ public abstract class ManeuverImpl extends AbstractGPSFixImpl implements Maneuve return maxAngularVelocityInDegreesPerSecond; } + public MarkPassing getMarkPassing() { + return markPassing; + } + + public boolean isMarkPassing() { + return markPassing != null; + } + + public NauticalSide getSide() { + return getMainCurveBoundaries().getDirectionChangeInDegrees() < 0 ? NauticalSide.PORT : NauticalSide.STARBOARD; + } + } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverWithMainCurveBoundariesImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverWithMainCurveBoundariesImpl.java index bc72c7ea9c9..3872f48d81e 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverWithMainCurveBoundariesImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverWithMainCurveBoundariesImpl.java @@ -6,6 +6,7 @@ import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Tack; import com.sap.sailing.domain.tracking.Maneuver; import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries; +import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sse.common.TimePoint; /** @@ -21,9 +22,9 @@ public class ManeuverWithMainCurveBoundariesImpl extends ManeuverImpl { public ManeuverWithMainCurveBoundariesImpl(ManeuverType type, Tack newTack, Position position, Distance maneuverLoss, TimePoint timePoint, ManeuverCurveBoundaries mainCurveBoundaries, ManeuverCurveBoundaries maneuverCurveWithStableSpeedAndCourseBoundaries, - double maxAngularVelocityInDegreesPerSecond) { + double maxAngularVelocityInDegreesPerSecond, MarkPassing markPassing) { super(type, newTack, position, maneuverLoss, timePoint, mainCurveBoundaries, - maneuverCurveWithStableSpeedAndCourseBoundaries, maxAngularVelocityInDegreesPerSecond); + maneuverCurveWithStableSpeedAndCourseBoundaries, maxAngularVelocityInDegreesPerSecond, markPassing); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverWithStableSpeedAndCourseBoundariesImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverWithStableSpeedAndCourseBoundariesImpl.java index ec97c52b344..091a76f425a 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverWithStableSpeedAndCourseBoundariesImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverWithStableSpeedAndCourseBoundariesImpl.java @@ -6,6 +6,7 @@ import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.Tack; import com.sap.sailing.domain.tracking.Maneuver; import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries; +import com.sap.sailing.domain.tracking.MarkPassing; import com.sap.sse.common.TimePoint; /** @@ -22,9 +23,9 @@ public class ManeuverWithStableSpeedAndCourseBoundariesImpl extends ManeuverImpl public ManeuverWithStableSpeedAndCourseBoundariesImpl(ManeuverType type, Tack newTack, Position position, Distance maneuverLoss, TimePoint timePoint, ManeuverCurveBoundaries mainCurveBoundaries, ManeuverCurveBoundaries maneuverCurveWithStableSpeedAndCourseBoundaries, - double maxAngularVelocityInDegreesPerSecond) { + double maxAngularVelocityInDegreesPerSecond, MarkPassing markPassing) { super(type, newTack, position, maneuverLoss, timePoint, mainCurveBoundaries, - maneuverCurveWithStableSpeedAndCourseBoundaries, maxAngularVelocityInDegreesPerSecond); + maneuverCurveWithStableSpeedAndCourseBoundaries, maxAngularVelocityInDegreesPerSecond, markPassing); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/MarkPassingManeuverImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/MarkPassingManeuverImpl.java deleted file mode 100755 index 02dab346f74..00000000000 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/MarkPassingManeuverImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.sap.sailing.domain.tracking.impl; - -import com.sap.sailing.domain.base.Waypoint; -import com.sap.sailing.domain.common.Distance; -import com.sap.sailing.domain.common.ManeuverType; -import com.sap.sailing.domain.common.NauticalSide; -import com.sap.sailing.domain.common.Position; -import com.sap.sailing.domain.common.Tack; -import com.sap.sailing.domain.tracking.ManeuverCurveBoundaries; -import com.sap.sailing.domain.tracking.MarkPassingManeuver; -import com.sap.sse.common.TimePoint; - -public class MarkPassingManeuverImpl extends ManeuverWithStableSpeedAndCourseBoundariesImpl - implements MarkPassingManeuver { - private static final long serialVersionUID = 8935348908557191614L; - private final Waypoint waypointPassed; - private final NauticalSide side; - - public MarkPassingManeuverImpl(ManeuverType type, Tack newTack, Position position, Distance maneuverLoss, - TimePoint timePoint, ManeuverCurveBoundaries mainCurveBoundaries, - ManeuverCurveBoundaries maneuverCurveWithStableSpeedAndCourseBoundaries, - double maxAngularVelocityInDegreesPerSecond, Waypoint waypointPassed, NauticalSide side) { - super(type, newTack, position, maneuverLoss, timePoint, mainCurveBoundaries, - maneuverCurveWithStableSpeedAndCourseBoundaries, maxAngularVelocityInDegreesPerSecond); - this.waypointPassed = waypointPassed; - this.side = side; - } - - @Override - public Waypoint getWaypointPassed() { - return waypointPassed; - } - - @Override - public NauticalSide getSide() { - return side; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(super.toString()); - result.append(", passed waypoint " + getWaypointPassed() + " to " + getSide().name()); - return result.toString(); - } - -} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/ManeuverTypeFormatter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/ManeuverTypeFormatter.java index d6dd1df4c21..240e60b0e68 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/ManeuverTypeFormatter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/ManeuverTypeFormatter.java @@ -11,8 +11,6 @@ public class ManeuverTypeFormatter { return stringMessages.headUp(); case JIBE: return stringMessages.jibe(); - case MARK_PASSING: - return stringMessages.markPassing(); case PENALTY_CIRCLE: return stringMessages.penaltyCircle(); case TACK: diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 4e2883ead2f..31d78833c5c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -199,7 +199,6 @@ import com.sap.sailing.domain.common.LeaderboardNameConstants; import com.sap.sailing.domain.common.LeaderboardType; import com.sap.sailing.domain.common.LegIdentifier; import com.sap.sailing.domain.common.LegType; -import com.sap.sailing.domain.common.ManeuverType; import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.NoWindException; import com.sap.sailing.domain.common.NotFoundException; @@ -334,7 +333,6 @@ import com.sap.sailing.domain.tracking.GPSFixTrack; import com.sap.sailing.domain.tracking.LineDetails; import com.sap.sailing.domain.tracking.Maneuver; import com.sap.sailing.domain.tracking.MarkPassing; -import com.sap.sailing.domain.tracking.MarkPassingManeuver; import com.sap.sailing.domain.tracking.RaceHandle; import com.sap.sailing.domain.tracking.RaceTracker; import com.sap.sailing.domain.tracking.Track; @@ -3419,14 +3417,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S List result = new ArrayList(); for (Maneuver maneuver : maneuvers) { final ManeuverDTO maneuverDTO; - if (maneuver.getType() == ManeuverType.MARK_PASSING) { + if (maneuver.isMarkPassing()) { maneuverDTO = new MarkpassingManeuverDTO(maneuver.getType(), maneuver.getNewTack(), maneuver.getPosition(), maneuver.getTimePoint().asDate(), createSpeedWithBearingDTO(maneuver.getSpeedWithBearingBefore()), createSpeedWithBearingDTO(maneuver.getSpeedWithBearingAfter()), maneuver.getDirectionChangeInDegrees(), maneuver.getManeuverLoss()==null?null:maneuver.getManeuverLoss().getMeters(), - ((MarkPassingManeuver) maneuver).getSide()); + maneuver.getSide()); } else { maneuverDTO = new ManeuverDTO(maneuver.getType(), maneuver.getNewTack(), maneuver.getPosition(), From 431aad65b57ea6b401204cb2ad0878d662ecc207 Mon Sep 17 00:00:00 2001 From: Vladislav Chumak Date: Fri, 16 Mar 2018 17:54:33 +0100 Subject: [PATCH 02/11] Included mark passing flag into REST-API --- .../gateway/serialization/impl/ManeuverJsonSerializer.java | 2 ++ .../impl/ManeuverWithEstimationDataJsonSerializer.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ManeuverJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ManeuverJsonSerializer.java index be7c627a5f3..b3bb7108931 100755 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ManeuverJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ManeuverJsonSerializer.java @@ -17,6 +17,7 @@ public class ManeuverJsonSerializer implements JsonSerializer { public static final String POSITION_AND_TIME = "positionAndTime"; public static final String MAX_ANGULAR_VELOCITY_IN_DEGREES_PER_SECOND = "maxAngularVelocityInDegreesPerSecond"; public static final String LOWEST_SPEED_IN_KNOTS = "lowestSpeedInKnots"; + public static final String MARK_PASSING = "markPassing"; private final GPSFixJsonSerializer gpsFixSerializer; private final DistanceJsonSerializer distanceSerializer; @@ -46,6 +47,7 @@ public class ManeuverJsonSerializer implements JsonSerializer { result.put(POSITION_AND_TIME, gpsFixSerializer.serialize(maneuver)); result.put(MAX_ANGULAR_VELOCITY_IN_DEGREES_PER_SECOND, maneuver.getMaxAngularVelocityInDegreesPerSecond()); result.put(LOWEST_SPEED_IN_KNOTS, maneuver.getLowestSpeed().getKnots()); + result.put(MARK_PASSING, maneuver.isMarkPassing()); return result; } } diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ManeuverWithEstimationDataJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ManeuverWithEstimationDataJsonSerializer.java index 6d993cff554..ae4a6e3739e 100644 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ManeuverWithEstimationDataJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/ManeuverWithEstimationDataJsonSerializer.java @@ -17,6 +17,7 @@ public class ManeuverWithEstimationDataJsonSerializer implements JsonSerializer< public static final String NEW_TACK = "newTack"; public static final String POSITION_AND_TIME = "positionAndTime"; public static final String MAX_ANGULAR_VELOCITY_IN_DEGREES_PER_SECOND = "maxAngularVelocityInDegreesPerSecond"; + public final static String MARK_PASSING = "markPassing"; public static final String MANEUVER_LOSS_IN_METERS = "maneuverLossInMeters"; public static final String MAIN_CURVE_BOUNDARIES = "mainCurveBoundaries"; public static final String MANEUVER_BOUNDARIES = "maneuverBoundaries"; @@ -51,6 +52,7 @@ public class ManeuverWithEstimationDataJsonSerializer implements JsonSerializer< result.put(MANEUVER_TYPE, maneuver.getType() == null ? null : maneuver.getType().name()); result.put(NEW_TACK, maneuver.getNewTack() == null ? null : maneuver.getNewTack().name()); result.put(MAX_ANGULAR_VELOCITY_IN_DEGREES_PER_SECOND, maneuver.getMaxAngularVelocityInDegreesPerSecond()); + result.put(MARK_PASSING, maneuver.isMarkPassing()); result.put(MANEUVER_LOSS_IN_METERS, maneuver.getManeuverLoss() == null ? null : maneuver.getManeuverLoss().getMeters()); result.put(POSITION_AND_TIME, gpsFixSerializer.serialize(maneuver)); From b5a4331e52325b7522c08a18f4bcb829a85113df Mon Sep 17 00:00:00 2001 From: Vladislav Chumak Date: Fri, 16 Mar 2018 18:02:34 +0100 Subject: [PATCH 03/11] Adapted boolean dimension for mark passing maneuver filtering --- .../sailing/datamining/data/HasManeuverContext.java | 8 -------- .../datamining/impl/data/ManeuverWithContext.java | 12 ------------ .../datamining/impl/data/MarkPassingWithContext.java | 2 +- .../impl/AbstractLeaderboardWithCache.java | 2 +- .../com/sap/sailing/domain/tracking/Maneuver.java | 7 +++++-- .../sailing/domain/tracking/impl/ManeuverImpl.java | 2 +- 6 files changed, 8 insertions(+), 25 deletions(-) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasManeuverContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasManeuverContext.java index ee6d4b05031..0fc3f4459ca 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasManeuverContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasManeuverContext.java @@ -1,8 +1,6 @@ package com.sap.sailing.datamining.data; import com.sap.sailing.domain.common.Distance; -import com.sap.sailing.domain.common.ManeuverType; -import com.sap.sailing.domain.common.NauticalSide; import com.sap.sailing.domain.common.Tack; import com.sap.sse.common.TimePoint; import com.sap.sse.datamining.annotations.Connector; @@ -13,12 +11,6 @@ public interface HasManeuverContext extends HasWindOnTrackedLeg, HasManeuver, Ha @Connector(scanForStatistics = false) HasTrackedLegOfCompetitorContext getTrackedLegOfCompetitorContext(); - @Dimension(messageKey = "ManeuverType", ordinal = 12) - ManeuverType getManeuverType(); - - @Dimension(messageKey = "ToSide", ordinal = 16) - NauticalSide getToSide(); - @Dimension(messageKey = "TackBeforeManeuver") Tack getTackBeforeManeuver(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/ManeuverWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/ManeuverWithContext.java index 8183cb8c7f3..c037496623b 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/ManeuverWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/ManeuverWithContext.java @@ -4,8 +4,6 @@ import com.sap.sailing.datamining.data.HasManeuverContext; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.common.Distance; -import com.sap.sailing.domain.common.ManeuverType; -import com.sap.sailing.domain.common.NauticalSide; import com.sap.sailing.domain.common.SpeedWithBearing; import com.sap.sailing.domain.common.Tack; import com.sap.sailing.domain.common.Wind; @@ -88,16 +86,6 @@ public class ManeuverWithContext implements HasManeuverContext { return maneuver; } - @Override - public ManeuverType getManeuverType() { - return getManeuver().getType(); - } - - @Override - public NauticalSide getToSide() { - return getDirectionChangeInDegreesForAnalysis() >= 0 ? NauticalSide.STARBOARD : NauticalSide.PORT; - } - @Override public Double getAbsoluteDirectionChangeInDegrees() { return Math.abs(getDirectionChangeInDegreesForAnalysis()); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/MarkPassingWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/MarkPassingWithContext.java index 130d37a57d3..ad8aecd22f4 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/MarkPassingWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/MarkPassingWithContext.java @@ -42,7 +42,7 @@ public class MarkPassingWithContext implements HasMarkPassingContext { @Override public NauticalSide getPassingSide() { - return getManeuver().getSide(); + return getManeuver().getToSide(); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java index c9ec2114367..36d5fc3012e 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java @@ -958,7 +958,7 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard { // analyze all mark passings, not only those after this leg's start, to catch the mark passing // maneuver starting this leg, even if its time point is slightly before the mark passing starting this leg if (maneuver.getMarkPassing().getWaypoint() == trackedLeg.getLeg().getFrom()) { - result.sideToWhichMarkAtLegStartWasRounded = maneuver.getSide(); + result.sideToWhichMarkAtLegStartWasRounded = maneuver.getToSide(); } } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/Maneuver.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/Maneuver.java index b30061f143e..481d95885f4 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/Maneuver.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/Maneuver.java @@ -43,6 +43,7 @@ public interface Maneuver extends GPSFix { * * @return The type of maneuver */ + @Dimension(messageKey = "ManeuverType", ordinal = 12) ManeuverType getType(); /** @@ -51,7 +52,7 @@ public interface Maneuver extends GPSFix { * * @return The new tack after the performed maneuver */ - @Dimension(messageKey = "Tack", ordinal = 13) + @Dimension(messageKey = "Tack", ordinal = 14) Tack getNewTack(); /** @@ -151,11 +152,13 @@ public interface Maneuver extends GPSFix { /** * Determines whether the maneuver is mark passing maneuver. */ + @Dimension(messageKey = "MarkPassing", ordinal = 13) boolean isMarkPassing(); /** * Gets the direction of the maneuver. It corresponds to the direction of mark passing side. */ - NauticalSide getSide(); + @Dimension(messageKey = "ToSide", ordinal = 16) + NauticalSide getToSide(); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverImpl.java index 653285bc44a..534ca3ed32b 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/ManeuverImpl.java @@ -121,7 +121,7 @@ public abstract class ManeuverImpl extends AbstractGPSFixImpl implements Maneuve return markPassing != null; } - public NauticalSide getSide() { + public NauticalSide getToSide() { return getMainCurveBoundaries().getDirectionChangeInDegrees() < 0 ? NauticalSide.PORT : NauticalSide.STARBOARD; } From 1e41ef9b3da1eeaf706259ed41bb3f31c4bd0399 Mon Sep 17 00:00:00 2001 From: Vladislav Chumak Date: Fri, 16 Mar 2018 18:08:16 +0100 Subject: [PATCH 04/11] Fixed overlooked compile errors produced by last commit --- .../impl/data/ManeuverSpeedDetailsWithContext.java | 8 ++++---- .../com/sap/sailing/gwt/ui/server/SailingServiceImpl.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/ManeuverSpeedDetailsWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/ManeuverSpeedDetailsWithContext.java index c7a19d422fb..483c8c55080 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/ManeuverSpeedDetailsWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/ManeuverSpeedDetailsWithContext.java @@ -36,7 +36,7 @@ public class ManeuverSpeedDetailsWithContext implements HasManeuverSpeedDetailsC @Override public NauticalSide getToSide() { - return maneuverContext.getToSide(); + return maneuverContext.getManeuver().getToSide(); } @Override @@ -45,7 +45,7 @@ public class ManeuverSpeedDetailsWithContext implements HasManeuverSpeedDetailsC double lastSpeedValue = 0; Function twaIterationFunction = ManeuverSpeedDetailsUtils - .getTWAIterationFunctionForManeuverDirection(maneuverContext.getToSide()); + .getTWAIterationFunctionForManeuverDirection(getToSide()); for (int twa = maneuverEnteringTWA, i = 0; i < 360; ++i, twa = twaIterationFunction.apply(twa)) { if (maneuverSpeedPerTWA[twa] == 0 || lastSpeedValue == 0) { @@ -64,7 +64,7 @@ public class ManeuverSpeedDetailsWithContext implements HasManeuverSpeedDetailsC double firstSpeedValue = maneuverContext.getManeuverEnteringSpeed(); Function twaIterationFunction = ManeuverSpeedDetailsUtils - .getTWAIterationFunctionForManeuverDirection(maneuverContext.getToSide()); + .getTWAIterationFunctionForManeuverDirection(getToSide()); for (int twa = maneuverEnteringTWA, i = 0; i < 360; ++i, twa = twaIterationFunction.apply(twa)) { if (firstSpeedValue == 0) { @@ -85,7 +85,7 @@ public class ManeuverSpeedDetailsWithContext implements HasManeuverSpeedDetailsC double lastSpeedValue = 0; Function twaIterationFunction = ManeuverSpeedDetailsUtils - .getTWAIterationFunctionForManeuverDirection(maneuverContext.getToSide()); + .getTWAIterationFunctionForManeuverDirection(getToSide()); for (int twa = maneuverEnteringTWA, i = 0; i < 360; ++i, twa = twaIterationFunction.apply(twa)) { if (maneuverSpeedPerTWA[twa] == 0 || lastSpeedValue == 0) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 31d78833c5c..39b51a32e7c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -3424,7 +3424,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S createSpeedWithBearingDTO(maneuver.getSpeedWithBearingBefore()), createSpeedWithBearingDTO(maneuver.getSpeedWithBearingAfter()), maneuver.getDirectionChangeInDegrees(), maneuver.getManeuverLoss()==null?null:maneuver.getManeuverLoss().getMeters(), - maneuver.getSide()); + maneuver.getToSide()); } else { maneuverDTO = new ManeuverDTO(maneuver.getType(), maneuver.getNewTack(), maneuver.getPosition(), From c5a794ecae438183017ac14248d597bfeb02a2e9 Mon Sep 17 00:00:00 2001 From: Vladislav Chumak Date: Fri, 16 Mar 2018 18:33:20 +0100 Subject: [PATCH 05/11] Added release notes for the new mark passing treatment --- .../com.sap.sailing.www/release_notes_admin.html | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html index c34c904bc85..4de8d96ba78 100755 --- a/java/com.sap.sailing.www/release_notes_admin.html +++ b/java/com.sap.sailing.www/release_notes_admin.html @@ -22,21 +22,9 @@

Release Notes - Administration Console

-

February 2018

+

March 2018

    -
  • There is an integration with WindFinder (https://www.windfinder.com) now. - In the Event edit dialog there is a new tab "WindFinder" where so-called "spot collection ID" can be entered. - Such spot collection IDs are negotiated and manually selected by the WindFinder team upon request. Talk to - the SAP Sailing Analytics team or to WindFinder directly to obtain one for your area.

    - When such spot collections are provided for an event, a "Weather Data" button will appear on the event - landing page. Races whose tracking is started with wind tracking included will obtain wind information - from the wind finder spots of the spot collections configured. When the wind arrows for those readings - appear on the map, the bubble displayed when clicking them also contains a link to the respective - WindFinder web page.

    - The links to the WindFinder page are sensitive to the event time. If it's a few days before the event, - a forecast link will be used. During the event the actual report page is shown. Outside of these dates - a general weather statistics page is shown for the venue. -

  • +
  • Further improvements of maneuver detection algorithm were introduced. Mark Passing is no longer regarded as a separate maneuver type. Instead, it is regarded as a supplementary information which gets appended to a maneuver instance. Therefore, a new filtering dimension was added for maneuver data mining, which is boolean and is named as "Mark Passing".

January 2018

From 3a3a81c4ab2ccb2d4aa4e3409ba65443ebbd08d4 Mon Sep 17 00:00:00 2001 From: Vladislav Chumak Date: Mon, 19 Mar 2018 15:18:53 +0100 Subject: [PATCH 06/11] Improved penalty circle maneuver derivation --- .../impl/ManeuverDetectorImpl.java | 89 ++++++++++--------- 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java index 9d4b0e29306..0377eacd779 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/maneuverdetection/impl/ManeuverDetectorImpl.java @@ -469,54 +469,59 @@ public class ManeuverDetectorImpl implements ManeuverDetector { // we create a PENALTY_CIRCLE maneuver and recurse for the time interval after the first penalty circle // has // completed. - TimePoint firstPenaltyCircleCompletedAt = getTimePointOfCompletionOfFirstPenaltyCircle( - maneuverMainCurveDetails.getTimePointBefore(), courseBeforeManeuver, - maneuverMainCurveDetails.getSpeedWithBearingSteps(), wind); - if (firstPenaltyCircleCompletedAt == null) { - // This should really not happen! - logger.warning( - "Maneuver detection has failed to process penalty circle maneuver correctly, because getTimePointOfCompletionOfFirstPenaltyCircle() returned null. Race-Id: " - + trackedRace.getRace().getId() + ", Competitor: " + competitor.getName() - + ", Time point before maneuver: " + maneuverDetails.getTimePointBefore()); - // Use already detected maneuver details as fallback data to prevent Nullpointer - firstPenaltyCircleCompletedAt = maneuverDetails.getTimePointAfter(); + List additionalManeuversAfterFirstPenaltyCircle = null; + if (numberOfTacks > 1 || numberOfJibes > 1) { + TimePoint firstPenaltyCircleCompletedAt = getTimePointOfCompletionOfFirstPenaltyCircle( + maneuverMainCurveDetails.getTimePointBefore(), courseBeforeManeuver, + maneuverMainCurveDetails.getSpeedWithBearingSteps(), wind); + final ManeuverCurveDetailsWithBearingSteps refinedPenaltyMainCurveDetails; + final ManeuverCurveDetails refinedPenaltyDetails; + if (firstPenaltyCircleCompletedAt == null) { + // This should really not happen! + logger.warning( + "Maneuver detection has failed to process penalty circle maneuver correctly, because getTimePointOfCompletionOfFirstPenaltyCircle() returned null. Race-Id: " + + trackedRace.getRace().getId() + ", Competitor: " + competitor.getName() + + ", Time point before maneuver: " + maneuverDetails.getTimePointBefore()); + // Use already detected maneuver details as fallback data to prevent Nullpointer + } else { + refinedPenaltyMainCurveDetails = computeManeuverMainCurveDetails( + maneuverMainCurveDetails.getTimePointBefore(), firstPenaltyCircleCompletedAt, + maneuverDirection); + if (refinedPenaltyMainCurveDetails == null) { + // This should really not happen! + logger.warning( + "Maneuver detection has failed to process penalty circle maneuver correctly, because refinedPenaltyMainCurveDetails computation returned null. Race-Id: " + + trackedRace.getRace().getId() + ", Competitor: " + competitor.getName() + + ", Time point before maneuver: " + maneuverDetails.getTimePointBefore()); + // Use already detected maneuver main curve as fallback data to prevent Nullpointer + } else { + refinedPenaltyDetails = computeManeuverDetails(refinedPenaltyMainCurveDetails, + maneuverDetails.getTimePointBefore(), firstPenaltyCircleCompletedAt); + // after we've "consumed" one tack and one jibe, recursively find more maneuvers if tacks + // and/or jibes + // remain + List maneuverSpots = detectManeuvers(firstPenaltyCircleCompletedAt, + maneuverDetails.getTimePointAfter()); + additionalManeuversAfterFirstPenaltyCircle = getAllManeuversFromManeuverSpots( + maneuverSpots); + maneuverMainCurveDetails = refinedPenaltyMainCurveDetails; + maneuverDetails = refinedPenaltyDetails; + } + } } maneuverType = ManeuverType.PENALTY_CIRCLE; - ManeuverCurveDetailsWithBearingSteps refinedPenaltyMainCurveDetails = computeManeuverMainCurveDetails( - maneuverMainCurveDetails.getTimePointBefore(), firstPenaltyCircleCompletedAt, - maneuverDirection); - - ManeuverCurveDetails refinedPenaltyDetails; - if (refinedPenaltyMainCurveDetails == null) { - // This should really not happen! - logger.warning( - "Maneuver detection has failed to process penalty circle maneuver correctly, because refinedPenaltyMainCurveDetails computation returned null. Race-Id: " - + trackedRace.getRace().getId() + ", Competitor: " + competitor.getName() - + ", Time point before maneuver: " + maneuverDetails.getTimePointBefore()); - // Use already detected maneuver main curve as fallback data to prevent Nullpointer - refinedPenaltyMainCurveDetails = maneuverMainCurveDetails; - refinedPenaltyDetails = maneuverDetails; - firstPenaltyCircleCompletedAt = maneuverDetails.getTimePointAfter(); - } else { - refinedPenaltyDetails = computeManeuverDetails(refinedPenaltyMainCurveDetails, - maneuverDetails.getTimePointBefore(), firstPenaltyCircleCompletedAt); - } maneuverLoss = getManeuverLoss(maneuverDetails.getTimePointBefore(), maneuverDetails.getTimePoint(), - firstPenaltyCircleCompletedAt); - Position penaltyPosition = competitorTrack.getEstimatedPosition(refinedPenaltyDetails.getTimePoint(), + maneuverDetails.getTimePointAfter()); + Position penaltyPosition = competitorTrack.getEstimatedPosition(maneuverDetails.getTimePoint(), /* extrapolate */ false); final Maneuver maneuver = new ManeuverWithStableSpeedAndCourseBoundariesImpl(maneuverType, - tackAfterManeuver, penaltyPosition, maneuverLoss, refinedPenaltyDetails.getTimePoint(), - refinedPenaltyMainCurveDetails.extractCurveBoundariesOnly(), - refinedPenaltyDetails.extractCurveBoundariesOnly(), - refinedPenaltyMainCurveDetails.getMaxAngularVelocityInDegreesPerSecond(), markPassing); + tackAfterManeuver, penaltyPosition, maneuverLoss, maneuverDetails.getTimePoint(), + maneuverMainCurveDetails.extractCurveBoundariesOnly(), + maneuverDetails.extractCurveBoundariesOnly(), + maneuverMainCurveDetails.getMaxAngularVelocityInDegreesPerSecond(), markPassing); maneuvers.add(maneuver); - // after we've "consumed" one tack and one jibe, recursively find more maneuvers if tacks and/or jibes - // remain - if (numberOfTacks > 1 || numberOfJibes > 1) { - List maneuverSpots = detectManeuvers(firstPenaltyCircleCompletedAt, - maneuverDetails.getTimePointAfter()); - maneuvers.addAll(getAllManeuversFromManeuverSpots(maneuverSpots)); + if (additionalManeuversAfterFirstPenaltyCircle != null) { + maneuvers.addAll(additionalManeuversAfterFirstPenaltyCircle); } } } else { From 400317fe09a723d8b38d7992ec6394f3b616e311 Mon Sep 17 00:00:00 2001 From: Vladislav Chumak Date: Mon, 19 Mar 2018 15:25:58 +0100 Subject: [PATCH 07/11] Adjusted test case to the new mark passing maneuver strategy --- .../src/com/sap/sailing/xmlexport/test/XMLExportTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.xmlexport.test/src/com/sap/sailing/xmlexport/test/XMLExportTest.java b/java/com.sap.sailing.xmlexport.test/src/com/sap/sailing/xmlexport/test/XMLExportTest.java index 7036a876740..9ea495d1fba 100644 --- a/java/com.sap.sailing.xmlexport.test/src/com/sap/sailing/xmlexport/test/XMLExportTest.java +++ b/java/com.sap.sailing.xmlexport.test/src/com/sap/sailing/xmlexport/test/XMLExportTest.java @@ -70,7 +70,7 @@ public class XMLExportTest extends OnlineTracTracBasedTest { String resultData = leaderboardData.getResultXML(); assertNotNull(resultData); int resultDataLength = resultData.length(); - assertTrue("resultData length was " + resultDataLength + ", but expected to be > 261000", resultDataLength > 261000); + assertTrue("resultData length was " + resultDataLength + ", but expected to be > 254000", resultDataLength > 254000); } } From 75226b5a0abe4510ef442b83df24eb6e4b1a2333 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 21 Mar 2018 15:01:42 +0100 Subject: [PATCH 08/11] bug 4478: introduced MasterDataImportClassLoaderService in expeditionconnector.persistence to fix serialization problems Change-Id: I9604cfbf5a7256ae54aa223b7ae5c1e42b2b0f8d --- .../domain/racelogtracking/impl/Activator.java | 2 +- .../impl/MasterDataImportClassLoaderServiceImpl.java | 2 +- .../META-INF/MANIFEST.MF | 3 ++- .../persistence/impl/Activator.java | 2 ++ .../impl/MasterDataImportClassLoaderServiceImpl.java | 12 ++++++++++++ .../src/com/sap/sailing/server/impl/Activator.java | 2 +- .../sailing/server/impl/RacingEventServiceImpl.java | 2 +- .../sap/sse}/MasterDataImportClassLoaderService.java | 4 +--- 8 files changed, 21 insertions(+), 8 deletions(-) create mode 100755 java/com.sap.sailing.expeditionconnector.persistence/src/com/sap/sailing/expeditionconnector/persistence/impl/MasterDataImportClassLoaderServiceImpl.java rename java/{com.sap.sailing.server/src/com/sap/sailing/server => com.sap.sse/src/com/sap/sse}/MasterDataImportClassLoaderService.java (93%) 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 8be4cc22076..8bfcbfdde1c 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 @@ -24,7 +24,6 @@ import com.sap.sailing.domain.racelogtracking.impl.fixtracker.RegattaLogFixTrack import com.sap.sailing.domain.trackfiles.TrackFileImportDeviceIdentifier; import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParametersHandler; import com.sap.sailing.domain.tracking.TrackedRegattaListener; -import com.sap.sailing.server.MasterDataImportClassLoaderService; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; import com.sap.sailing.server.gateway.deserialization.impl.GPSFixJsonDeserializer; @@ -36,6 +35,7 @@ import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdent import com.sap.sailing.server.gateway.serialization.racelog.tracking.GPSFixJsonHandler; import com.sap.sailing.server.gateway.serialization.racelog.tracking.impl.GPSFixJsonHandlerImpl; import com.sap.sailing.server.gateway.serialization.racelog.tracking.impl.SmartphoneUUIDJsonHandler; +import com.sap.sse.MasterDataImportClassLoaderService; import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.replication.Replicable; import com.sap.sse.util.ServiceTrackerFactory; diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/MasterDataImportClassLoaderServiceImpl.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/MasterDataImportClassLoaderServiceImpl.java index 9a670c0ab5c..1c964a665b9 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/MasterDataImportClassLoaderServiceImpl.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/MasterDataImportClassLoaderServiceImpl.java @@ -1,6 +1,6 @@ package com.sap.sailing.domain.racelogtracking.impl; -import com.sap.sailing.server.MasterDataImportClassLoaderService; +import com.sap.sse.MasterDataImportClassLoaderService; public class MasterDataImportClassLoaderServiceImpl implements MasterDataImportClassLoaderService { diff --git a/java/com.sap.sailing.expeditionconnector.persistence/META-INF/MANIFEST.MF b/java/com.sap.sailing.expeditionconnector.persistence/META-INF/MANIFEST.MF index 2d660db1059..8180f29087d 100755 --- a/java/com.sap.sailing.expeditionconnector.persistence/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.expeditionconnector.persistence/META-INF/MANIFEST.MF @@ -14,5 +14,6 @@ Require-Bundle: com.sap.sailing.domain.persistence, com.sap.sse.mongodb, org.mongodb.mongo-java-driver;bundle-version="2.13.0", com.sap.sailing.expeditionconnector.common, - com.sap.sailing.server.gateway.serialization.shared.android + com.sap.sailing.server.gateway.serialization.shared.android, + com.sap.sse Export-Package: com.sap.sailing.expeditionconnector.persistence diff --git a/java/com.sap.sailing.expeditionconnector.persistence/src/com/sap/sailing/expeditionconnector/persistence/impl/Activator.java b/java/com.sap.sailing.expeditionconnector.persistence/src/com/sap/sailing/expeditionconnector/persistence/impl/Activator.java index 4e988439924..14318a1cd6f 100755 --- a/java/com.sap.sailing.expeditionconnector.persistence/src/com/sap/sailing/expeditionconnector/persistence/impl/Activator.java +++ b/java/com.sap.sailing.expeditionconnector.persistence/src/com/sap/sailing/expeditionconnector/persistence/impl/Activator.java @@ -12,6 +12,7 @@ import org.osgi.framework.ServiceRegistration; import com.sap.sailing.domain.persistence.racelog.tracking.DeviceIdentifierMongoHandler; import com.sap.sailing.expeditionconnector.ExpeditionSensorDeviceIdentifier; import com.sap.sailing.expeditionconnector.persistence.ExpeditionGpsDeviceIdentifier; +import com.sap.sse.MasterDataImportClassLoaderService; import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.mongodb.MongoDBService; @@ -37,6 +38,7 @@ public class Activator implements BundleActivator { Activator.context = bundleContext; registrations.add(context.registerService(DeviceIdentifierMongoHandler.class, new ExpeditionGpsDeviceIdentifierMongoHandler(), getDict(ExpeditionGpsDeviceIdentifier.TYPE))); registrations.add(context.registerService(DeviceIdentifierMongoHandler.class, new ExpeditionSensorDeviceIdentifierMongoHandler(), getDict(ExpeditionSensorDeviceIdentifier.TYPE))); + registrations.add(context.registerService(MasterDataImportClassLoaderService.class, new MasterDataImportClassLoaderServiceImpl(), null)); for (CollectionNames name : CollectionNames.values()) { MongoDBService.INSTANCE.registerExclusively(CollectionNames.class, name.name()); } diff --git a/java/com.sap.sailing.expeditionconnector.persistence/src/com/sap/sailing/expeditionconnector/persistence/impl/MasterDataImportClassLoaderServiceImpl.java b/java/com.sap.sailing.expeditionconnector.persistence/src/com/sap/sailing/expeditionconnector/persistence/impl/MasterDataImportClassLoaderServiceImpl.java new file mode 100755 index 00000000000..fabf75395f7 --- /dev/null +++ b/java/com.sap.sailing.expeditionconnector.persistence/src/com/sap/sailing/expeditionconnector/persistence/impl/MasterDataImportClassLoaderServiceImpl.java @@ -0,0 +1,12 @@ +package com.sap.sailing.expeditionconnector.persistence.impl; + +import com.sap.sse.MasterDataImportClassLoaderService; + +public class MasterDataImportClassLoaderServiceImpl implements MasterDataImportClassLoaderService { + + @Override + public ClassLoader getClassLoader() { + return this.getClass().getClassLoader(); + } + +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index 5296fd28d91..db69d72e47d 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -35,7 +35,6 @@ import com.sap.sailing.domain.persistence.racelog.tracking.impl.GPSFixMovingMong import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.domain.racelog.tracking.SensorFixStoreSupplier; import com.sap.sailing.domain.tracking.TrackedRegattaListener; -import com.sap.sailing.server.MasterDataImportClassLoaderService; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.RacingEventServiceMXBean; import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreferences; @@ -43,6 +42,7 @@ import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPrefe import com.sap.sailing.server.notification.impl.SailingNotificationServiceImpl; import com.sap.sailing.server.statistics.TrackedRaceStatisticsCache; import com.sap.sailing.server.statistics.TrackedRaceStatisticsCacheImpl; +import com.sap.sse.MasterDataImportClassLoaderService; import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.common.Util; import com.sap.sse.mail.MailService; diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 284ea401e52..0b4f662b634 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -1802,7 +1802,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes linkRaceToConfiguredLeaderboardColumns(trackedRace); TrackedRaceReplicatorAndNotifier trackedRaceReplicator = new TrackedRaceReplicatorAndNotifier(trackedRace); trackedRaceReplicators.put(trackedRace, trackedRaceReplicator); - trackedRace.addListener(trackedRaceReplicator, /* fire wind already loaded */true, true); + trackedRace.addListener(trackedRaceReplicator, /* fire wind already loaded */true, /* notifyAboutGPSFixesAlreadyLoaded */ true); PolarFixCacheUpdater polarFixCacheUpdater = new PolarFixCacheUpdater(trackedRace); polarFixCacheUpdaters.put(trackedRace, polarFixCacheUpdater); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/MasterDataImportClassLoaderService.java b/java/com.sap.sse/src/com/sap/sse/MasterDataImportClassLoaderService.java similarity index 93% rename from java/com.sap.sailing.server/src/com/sap/sailing/server/MasterDataImportClassLoaderService.java rename to java/com.sap.sse/src/com/sap/sse/MasterDataImportClassLoaderService.java index 01b4fe666d7..21f90b2c3d6 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/MasterDataImportClassLoaderService.java +++ b/java/com.sap.sse/src/com/sap/sse/MasterDataImportClassLoaderService.java @@ -1,4 +1,4 @@ -package com.sap.sailing.server; +package com.sap.sse; /** * Bundles which com.sap.sailing.server has no dependency to can use this service to let the master data importer @@ -13,7 +13,5 @@ package com.sap.sailing.server; * */ public interface MasterDataImportClassLoaderService { - ClassLoader getClassLoader(); - } From 8fb4c00f0fa4c3a5dbcdc63337237ce00411f2da Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 21 Mar 2018 16:25:43 +0100 Subject: [PATCH 09/11] added ThreadLocalTransporter Change-Id: I387a8355da12f8b0994ca6771e6fd77c2057c310 --- .../com/sap/sse/replication/Replicable.java | 24 ++++++++++++++ .../sap/sse/util/ThreadLocalTransporter.java | 31 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100755 java/com.sap.sse/src/com/sap/sse/util/ThreadLocalTransporter.java diff --git a/java/com.sap.sse.replication/src/com/sap/sse/replication/Replicable.java b/java/com.sap.sse.replication/src/com/sap/sse/replication/Replicable.java index ffd538d7e33..cedaccf1e60 100755 --- a/java/com.sap.sse.replication/src/com/sap/sse/replication/Replicable.java +++ b/java/com.sap.sse.replication/src/com/sap/sse/replication/Replicable.java @@ -15,6 +15,7 @@ import com.sap.sse.operationaltransformation.Operation; import com.sap.sse.operationaltransformation.OperationWithTransformationSupport; import com.sap.sse.replication.impl.OperationWithResultWithIdWrapper; import com.sap.sse.util.ObjectInputStreamResolvingAgainstCache; +import com.sap.sse.util.ThreadLocalTransporter; /** * Represents a replicable part of an application. Such a replicable part is usually holder of application state and a @@ -199,6 +200,29 @@ public interface Replicable> extends Repl */ void setCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster(boolean b); + default ThreadLocalTransporter getThreadLocalTransporterForCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster() { + return new ThreadLocalTransporter() { + private boolean currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster; + private boolean currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMasterAtBeginningOfTask; + + @Override + public void rememberThreadLocalStates() { + currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster = isCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster(); + } + + @Override + public void pushThreadLocalStates() { + currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMasterAtBeginningOfTask = isCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster(); + setCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster(currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster); + } + + @Override + public void popThreadLocalStates() { + setCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster(currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMasterAtBeginningOfTask); + } + }; + } + /** * If an operation equal to operationWithResultWithIdWrapper has previously been passed to a call to * {@link #addOperationSentToMasterForReplication(OperationWithResultWithIdWrapper)}, the call returns true diff --git a/java/com.sap.sse/src/com/sap/sse/util/ThreadLocalTransporter.java b/java/com.sap.sse/src/com/sap/sse/util/ThreadLocalTransporter.java new file mode 100755 index 00000000000..423efb401dd --- /dev/null +++ b/java/com.sap.sse/src/com/sap/sse/util/ThreadLocalTransporter.java @@ -0,0 +1,31 @@ +package com.sap.sse.util; + +/** + * When a task is to be pushed out to another thread, {@link ThreadLocal} state may need + * to be preserved and re-established so that the task, when executed by another thread + * will see the {@link ThreadLocal}s' state just as it was when the task was created. + * + * @author Axel Uhl (d043530) + * + */ +public interface ThreadLocalTransporter { + /** + * Call this method when your task is created and to be submitted to an executor. + * This will store the state of all relevant {@link ThreadLocal}s in this object. + */ + void rememberThreadLocalStates(); + + /** + * Call this at the beginning of the task that is executed on another thread. This method + * will save the states of the relevant {@link ThreadLocal}s and will then establish their + * state as remembered earlier by the {@link #rememberThreadLocalStates()} method. + */ + void pushThreadLocalStates(); + + /** + * Call this in a {@code finally} block at the end of your task. This will restore the + * relevant {@link ThreadLocal} states as they were remembered when {@link #pushThreadLocalStates()} + * was invoked. + */ + void popThreadLocalStates(); +} From 0601becf8185982a48f39358758a5cd9542fa3ae Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 21 Mar 2018 16:50:37 +0100 Subject: [PATCH 10/11] Bug 4489: Initial implementation to ensure replication state for out of thread event processing in TrackedRegattaImpl --- .../impl/CreateAndTrackWithRaceLogTest.java | 3 +- .../impl/RaceLogRaceTracker.java | 4 +- .../impl/SwissTimingRaceTrackerImpl.java | 4 +- .../SwissTimingReplayToDomainAdapter.java | 4 +- .../test/FetchTracksAndStoreLocallyTest.java | 3 +- .../domain/test/ReceiveTrackingDataTest.java | 3 +- .../test/TestDeadlockInRegattaListener.java | 11 ++-- .../domain/test/mock/MockedTrackedRace.java | 10 ++-- .../tracking/impl/TrackedRegattaTest.java | 7 ++- .../impl/DomainFactoryImpl.java | 3 +- .../impl/RaceCourseReceiver.java | 4 +- .../tractracadapter/impl/Simulator.java | 3 +- ...AbstractTrackedRegattaAndRaceObserver.java | 3 +- .../domain/tracking/TrackedRegatta.java | 11 ++-- .../impl/DynamicTrackedRegattaImpl.java | 8 ++- .../domain/tracking/impl/TrackedRaceImpl.java | 2 +- .../tracking/impl/TrackedRegattaImpl.java | 56 ++++++++++++------- .../gwt/ui/test/MockedTrackedRace.java | 10 ++-- ...estStoringAndRetrievingWindTracksTest.java | 4 +- .../server/statistics/StatisticsTest.java | 5 +- .../server/test/RaceTrackerStartStopTest.java | 10 +++- .../sailing/server/test/RaceTrackerTest.java | 3 +- .../server/test/RemoveLeaderboardTest.java | 4 +- .../server/impl/RacingEventServiceImpl.java | 10 +++- .../ImportMasterDataOperation.java | 4 +- .../simulation/SimulationServiceImpl.java | 3 +- 26 files changed, 128 insertions(+), 64 deletions(-) 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 0e20c9b4525..21a9059b81e 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 @@ -11,6 +11,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.util.Collections; +import java.util.Optional; import java.util.UUID; import org.junit.After; @@ -228,7 +229,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper { public void raceAdded(TrackedRace trackedRace) { } }; - raceHandle.getTrackedRegatta().addRaceListener(raceListener); + raceHandle.getTrackedRegatta().addRaceListener(raceListener, Optional.empty()); raceHandle.getTrackedRegatta().removeRaceListener(raceListener).get(); } 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 395d6a2e21a..e354df7ba7e 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 @@ -7,6 +7,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; @@ -304,7 +305,8 @@ public class RaceLogRaceTracker extends AbstractRaceTrackerBaseImpl { raceColumn.setRaceIdentifier(fleet, trackedRegatta.getRegatta().getRaceIdentifier(raceDef)); trackedRace = trackedRegatta.createTrackedRace(raceDef, sidelines, windStore, params.getDelayToLiveInMillis(), WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, - boatClass.getApproximateManeuverDurationInMilliseconds(), null, /*useMarkPassingCalculator*/ true, raceLogResolver); + boatClass.getApproximateManeuverDurationInMilliseconds(), null, /*useMarkPassingCalculator*/ true, raceLogResolver, + /* Not needed because the RaceTracker is not active on a replica */ Optional.empty()); notifyRaceCreationListeners(); logger.info(String.format("Started tracking race-log race (%s)", raceLog)); // this wakes up all waiting race handles diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java index 18bd0aee11a..87881b9e7b1 100644 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SwissTimingRaceTrackerImpl.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NavigableSet; +import java.util.Optional; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -487,7 +488,8 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl // we already know our single RaceDefinition assert SwissTimingRaceTrackerImpl.this.race == race; } - }, useInternalMarkPassingAlgorithm, raceLogResolver); + }, useInternalMarkPassingAlgorithm, raceLogResolver, + /* Not needed because the RaceTracker is not active on a replica */ Optional.empty()); notifyRaceCreationListeners(); logger.info("Created SwissTiming RaceDefinition and TrackedRace for "+race.getName()); } diff --git a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java index aa3489242a9..dee036575db 100755 --- a/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java +++ b/java/com.sap.sailing.domain.swisstimingreplayadapter/src/com/sap/sailing/domain/swisstimingreplayadapter/impl/SwissTimingReplayToDomainAdapter.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.NavigableSet; +import java.util.Optional; import java.util.Set; import java.util.TimeZone; import java.util.logging.Logger; @@ -400,7 +401,8 @@ public class SwissTimingReplayToDomainAdapter extends SwissTimingReplayAdapter i TrackedRace.DEFAULT_LIVE_DELAY_IN_MILLISECONDS, WindTrack.DEFAULT_MILLISECONDS_OVER_WHICH_TO_AVERAGE_WIND, /* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(), - /* raceDefinitionSetToUpdate */ null, useInternalMarkPassingAlgorithm, raceLogResolver); + /* raceDefinitionSetToUpdate */ null, useInternalMarkPassingAlgorithm, raceLogResolver, + /* Not needed because the RaceTracker is not active on a replica */ Optional.empty()); trackedRace.onStatusChanged(this, new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, 0)); TimePoint bestStartTimeKnownSoFar = bestStartTimePerRaceID.get(currentRaceID); if (bestStartTimeKnownSoFar != null) { diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/FetchTracksAndStoreLocallyTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/FetchTracksAndStoreLocallyTest.java index d965b5fcc1a..7b8fa85d92c 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/FetchTracksAndStoreLocallyTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/FetchTracksAndStoreLocallyTest.java @@ -6,6 +6,7 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import org.junit.Ignore; import org.junit.Test; @@ -74,7 +75,7 @@ public class FetchTracksAndStoreLocallyTest extends OnlineTracTracBasedTest { @Override public void raceRemoved(TrackedRace trackedRace) { } - }); + }, Optional.empty()); super.completeSetupLaunchingControllerAndWaitForRaceDefinition(ReceiverType.RACECOURSE, ReceiverType.RACESTARTFINISH, ReceiverType.RAWPOSITIONS); } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java index 11d389f28a1..855b29f764a 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/ReceiveTrackingDataTest.java @@ -5,6 +5,7 @@ import static org.mockito.Mockito.mock; import java.net.MalformedURLException; import java.net.URISyntaxException; +import java.util.Optional; import org.junit.Before; import org.junit.Test; @@ -77,7 +78,7 @@ public class ReceiveTrackingDataTest extends AbstractTracTracLiveTest { @Override public void raceRemoved(TrackedRace trackedRace) { } - }); + }, Optional.empty()); for (Receiver receiver : domainFactory .getUpdateReceivers(trackedRegatta, /* delayToLiveInMillis */0l, /* simulator */null, EmptyWindStore.INSTANCE, new DynamicRaceDefinitionSet() { diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TestDeadlockInRegattaListener.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TestDeadlockInRegattaListener.java index 54b0889169d..c7020e2d91e 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TestDeadlockInRegattaListener.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TestDeadlockInRegattaListener.java @@ -5,6 +5,7 @@ import static org.mockito.Mockito.when; import java.io.IOException; import java.net.MalformedURLException; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; @@ -33,6 +34,7 @@ import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl; import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.impl.RacingEventServiceImpl; +import com.sap.sse.util.ThreadLocalTransporter; public class TestDeadlockInRegattaListener { @Rule @@ -56,13 +58,14 @@ public class TestDeadlockInRegattaListener { private static final long serialVersionUID = -3599667964201700780L; @Override - protected void notifyListenersAboutTrackedRaceRemoved(TrackedRace trackedRace) { + protected void notifyListenersAboutTrackedRaceRemoved(TrackedRace trackedRace, + Optional threadLocalTransporter) { try { latch.await(); } catch (InterruptedException | BrokenBarrierException e) { throw new RuntimeException(e); } - super.notifyListenersAboutTrackedRaceRemoved(trackedRace); + super.notifyListenersAboutTrackedRaceRemoved(trackedRace, Optional.empty()); } }; RacingEventServiceImpl racingEventService = new RacingEventServiceImpl() { @@ -125,10 +128,10 @@ public class TestDeadlockInRegattaListener { throw new RuntimeException(e); } }).start(); - trackedRegatta.addTrackedRace(trackedRace1); + trackedRegatta.addTrackedRace(trackedRace1, Optional.empty()); // the following runs into RacingEventService.getRaceTrackerByRegattaAndRaceIdentifier // which waits for the latch based on the override above while in synchronized RegattaListener.raceAdded - new Thread(()->trackedRegatta.addTrackedRace(trackedRace2)).start(); + new Thread(()->trackedRegatta.addTrackedRace(trackedRace2, Optional.empty())).start(); monitorOnRegattaListenerLatch.await(); // the following awaits the latch in TrackedRegattaImpl.notifyListenersAboutTrackedRaceRemoved // after the write lock has been obtained but before the synchronized RegattaListener.raceRemoved method diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java index e4a45f5d83b..578c9aec53a 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/mock/MockedTrackedRace.java @@ -4,6 +4,7 @@ import java.io.Serializable; import java.util.Collections; import java.util.List; import java.util.NavigableSet; +import java.util.Optional; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.Future; @@ -89,6 +90,7 @@ import com.sap.sse.common.IsManagedByCache; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; +import com.sap.sse.util.ThreadLocalTransporter; public class MockedTrackedRace implements DynamicTrackedRace { private static final long serialVersionUID = 5827912985564121181L; @@ -565,15 +567,15 @@ public class MockedTrackedRace implements DynamicTrackedRace { } @Override - public void addTrackedRace(TrackedRace trackedRace) { + public void addTrackedRace(TrackedRace trackedRace, Optional threadLocalTransporter) { } @Override - public void removeTrackedRace(TrackedRace trackedRace) { + public void removeTrackedRace(TrackedRace trackedRace, Optional threadLocalTransporter) { } @Override - public void addRaceListener(RaceListener listener) { + public void addRaceListener(RaceListener listener, Optional threadLocalTransporter) { } @Override @@ -596,7 +598,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingcalculator, - RaceLogResolver raceLogResolver) { + RaceLogResolver raceLogResolver, Optional threadLocalTransporter) { return null; } diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaTest.java index 0c18176671a..3980819bac9 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaTest.java @@ -4,6 +4,7 @@ import static org.mockito.Mockito.mock; import java.util.Arrays; import java.util.Collections; +import java.util.Optional; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; @@ -74,11 +75,11 @@ public class TrackedRegattaTest { throw new RuntimeException(e); } } - }); + }, Optional.empty()); DynamicTrackedRace race1 = createRace("R1"); Thread thread1 = new Thread(() -> { - regatta.addTrackedRace(race1); + regatta.addTrackedRace(race1, Optional.empty()); }); thread1.start(); // This ensures, that the add event is being processed but is not finished because @@ -88,7 +89,7 @@ public class TrackedRegattaTest { addPhaser.arriveAndAwaitAdvance(); Thread thread2 = new Thread(() -> { - regatta.removeTrackedRace(race1); + regatta.removeTrackedRace(race1, Optional.empty()); }); thread2.start(); // If the implementation ensures that the events are fired in order, diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java index c65b8bd83cd..a2cc640340e 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java @@ -13,6 +13,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Map.Entry; import java.util.Set; import java.util.UUID; @@ -616,7 +617,7 @@ public class DomainFactoryImpl implements DomainFactory { return trackedRegatta.createTrackedRace(race, sidelines, windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, /* time over which to average speed: */ race.getBoatClass().getApproximateManeuverDurationInMilliseconds(), - raceDefinitionSetToUpdate, useMarkPassingCalculator, raceLogResolver); + raceDefinitionSetToUpdate, useMarkPassingCalculator, raceLogResolver, Optional.empty()); } @Override diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java index 8487db75d19..1ae14c249a3 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; @@ -241,7 +242,8 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue sidelines, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, - DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver); + DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver, + Optional beforeAndAfterNotificationHandler); /** * Obtains the tracked race for race. Blocks until the tracked race has been created @@ -79,16 +82,16 @@ public interface TrackedRegatta extends Serializable { */ TrackedRace getExistingTrackedRace(RaceDefinition race); - void addTrackedRace(TrackedRace trackedRace); + void addTrackedRace(TrackedRace trackedRace, Optional beforeAndAfterNotificationHandler); - void removeTrackedRace(TrackedRace trackedRace); + void removeTrackedRace(TrackedRace trackedRace, Optional beforeAndAfterNotificationHandler); /** * Listener will be notified when {@link #addTrackedRace(TrackedRace)} is called and * upon registration for each tracked race already known. Therefore, the listener * won't miss any tracked race. */ - void addRaceListener(RaceListener listener); + void addRaceListener(RaceListener listener, Optional beforeAndAfterNotificationHandler); /** * Removes the given listener and returns a {@link Future} that will be completed diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRegattaImpl.java index fdc820b7904..990fa8cb327 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicTrackedRegattaImpl.java @@ -1,5 +1,7 @@ package com.sap.sailing.domain.tracking.impl; +import java.util.Optional; + import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; @@ -8,6 +10,7 @@ import com.sap.sailing.domain.tracking.DynamicRaceDefinitionSet; import com.sap.sailing.domain.tracking.DynamicTrackedRace; import com.sap.sailing.domain.tracking.DynamicTrackedRegatta; import com.sap.sailing.domain.tracking.WindStore; +import com.sap.sse.util.ThreadLocalTransporter; public class DynamicTrackedRegattaImpl extends TrackedRegattaImpl implements DynamicTrackedRegatta { private static final long serialVersionUID = -90155868534737120L; @@ -35,9 +38,10 @@ public class DynamicTrackedRegattaImpl extends TrackedRegattaImpl implements Dyn @Override public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable sidelines, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, - DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingCalculator, RaceLogResolver raceLogResolver) { + DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useMarkPassingCalculator, RaceLogResolver raceLogResolver, + Optional threadLocalTransporter) { return (DynamicTrackedRace) super.createTrackedRace(raceDefinition, sidelines, windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, - millisecondsOverWhichToAverageSpeed, raceDefinitionSetToUpdate, useMarkPassingCalculator, raceLogResolver); + millisecondsOverWhichToAverageSpeed, raceDefinitionSetToUpdate, useMarkPassingCalculator, raceLogResolver, threadLocalTransporter); } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java index 38ffed188a4..d82fc8e09d1 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRaceImpl.java @@ -548,7 +548,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl markPassingCalculator.stop(); } } - }); + }, /* Not relevant For replication */ Optional.empty()); } else { markPassingCalculator = null; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java index e1185b9adfc..8585cdad67f 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java @@ -9,6 +9,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; @@ -34,6 +35,7 @@ import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; import com.sap.sse.concurrent.LockUtil; import com.sap.sse.concurrent.NamedReentrantReadWriteLock; +import com.sap.sse.util.ThreadLocalTransporter; public class TrackedRegattaImpl implements TrackedRegatta { private static final long serialVersionUID = 6480508193567014285L; @@ -128,7 +130,7 @@ public class TrackedRegattaImpl implements TrackedRegatta { } @Override - public void addTrackedRace(TrackedRace trackedRace) { + public void addTrackedRace(TrackedRace trackedRace, Optional threadLocalTransporter) { final TrackedRace oldTrackedRace; lockTrackedRacesForWrite(); try { @@ -136,39 +138,51 @@ public class TrackedRegattaImpl implements TrackedRegatta { " with regatta hash code "+getRegatta().hashCode()); oldTrackedRace = trackedRaces.put(trackedRace.getRace(), trackedRace); if (oldTrackedRace != trackedRace) { - notifyListenersAboutTrackedRaceAdded(trackedRace); + notifyListenersAboutTrackedRaceAdded(trackedRace, threadLocalTransporter); } } finally { unlockTrackedRacesAfterWrite(); } } - protected void notifyListenersAboutTrackedRaceAdded(TrackedRace trackedRace) { - enqueEvent(listener -> listener.raceAdded(trackedRace)); + protected void notifyListenersAboutTrackedRaceAdded(TrackedRace trackedRace, Optional threadLocalTransporter) { + enqueEvent(listener -> listener.raceAdded(trackedRace), threadLocalTransporter); } - protected void enqueEvent(Consumer fireEventCallback) { + protected void enqueEvent(Consumer fireEventCallback, Optional threadLocalTransporter) { final Set listenersToInform = new HashSet<>(raceListeners.keySet()); + threadLocalTransporter.ifPresent(ThreadLocalTransporter::rememberThreadLocalStates); eventQueue.addWork(() -> { - for (RaceListener listener : listenersToInform) { - fireEventCallback.accept(listener); - } + withBeforeAndAfterHandling(threadLocalTransporter, () -> { + for (RaceListener listener : listenersToInform) { + fireEventCallback.accept(listener); + } + }); }); } + private void withBeforeAndAfterHandling(Optional threadLocalTransporter, Runnable action) { + threadLocalTransporter.ifPresent(ThreadLocalTransporter::pushThreadLocalStates); + try { + action.run(); + } finally { + threadLocalTransporter.ifPresent(ThreadLocalTransporter::popThreadLocalStates); + } + } + @Override - public void removeTrackedRace(TrackedRace trackedRace) { + public void removeTrackedRace(TrackedRace trackedRace, Optional threadLocalTransporter) { lockTrackedRacesForWrite(); try { trackedRaces.remove(trackedRace.getRace()); - notifyListenersAboutTrackedRaceRemoved(trackedRace); + notifyListenersAboutTrackedRaceRemoved(trackedRace, threadLocalTransporter); } finally { unlockTrackedRacesAfterWrite(); } } - protected void notifyListenersAboutTrackedRaceRemoved(TrackedRace trackedRace) { - enqueEvent(listener -> listener.raceRemoved(trackedRace)); + protected void notifyListenersAboutTrackedRaceRemoved(TrackedRace trackedRace, Optional threadLocalTransporter) { + enqueEvent(listener -> listener.raceRemoved(trackedRace), threadLocalTransporter); } @Override @@ -201,7 +215,7 @@ public class TrackedRegattaImpl implements TrackedRegatta { } } }; - addRaceListener(listener); + addRaceListener(listener, Optional.empty()); try { synchronized (mutex) { result = getExistingTrackedRace(race); @@ -232,16 +246,19 @@ public class TrackedRegattaImpl implements TrackedRegatta { } @Override - public void addRaceListener(RaceListener listener) { + public void addRaceListener(RaceListener listener, Optional threadLocalTransporter) { lockTrackedRacesForRead(); try { raceListeners.put(listener, listener); final List trackedRacesCopy = new ArrayList<>(); Util.addAll(getTrackedRaces(), trackedRacesCopy); + threadLocalTransporter.ifPresent(ThreadLocalTransporter::rememberThreadLocalStates); eventQueue.addWork(() -> { - for (TrackedRace trackedRace : trackedRacesCopy) { - listener.raceAdded(trackedRace); - } + withBeforeAndAfterHandling(threadLocalTransporter, () -> { + for (TrackedRace trackedRace : trackedRacesCopy) { + listener.raceAdded(trackedRace); + } + }); }); } finally { unlockTrackedRacesAfterRead(); @@ -284,7 +301,8 @@ public class TrackedRegattaImpl implements TrackedRegatta { public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable sidelines, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, - DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver) { + DynamicRaceDefinitionSet raceDefinitionSetToUpdate, boolean useInternalMarkPassingAlgorithm, RaceLogResolver raceLogResolver, + Optional threadLocalTransporter) { logger.log(Level.INFO, "Creating DynamicTrackedRaceImpl for RaceDefinition " + raceDefinition.getName()); DynamicTrackedRaceImpl result = new DynamicTrackedRaceImpl(this, raceDefinition, sidelines, windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, @@ -295,7 +313,7 @@ public class TrackedRegattaImpl implements TrackedRegatta { if (raceDefinitionSetToUpdate != null) { raceDefinitionSetToUpdate.addRaceDefinition(raceDefinition, result); } - addTrackedRace(result); + addTrackedRace(result, threadLocalTransporter); return result; } } diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java index 201f21b1cc5..d0b893acc81 100644 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/MockedTrackedRace.java @@ -7,6 +7,7 @@ import java.io.Serializable; import java.util.Collections; import java.util.List; import java.util.NavigableSet; +import java.util.Optional; import java.util.Set; import java.util.concurrent.Future; @@ -76,6 +77,7 @@ import com.sap.sse.common.Duration; import com.sap.sse.common.IsManagedByCache; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; +import com.sap.sse.util.ThreadLocalTransporter; public class MockedTrackedRace implements DynamicTrackedRace { private static final long serialVersionUID = 5827912985564121181L; @@ -295,15 +297,15 @@ public class MockedTrackedRace implements DynamicTrackedRace { } @Override - public void addTrackedRace(TrackedRace trackedRace) { + public void addTrackedRace(TrackedRace trackedRace, Optional threadLocalTransporter) { } @Override - public void removeTrackedRace(TrackedRace trackedRace) { + public void removeTrackedRace(TrackedRace trackedRace, Optional threadLocalTransporter) { } @Override - public void addRaceListener(RaceListener listener) { + public void addRaceListener(RaceListener listener, Optional threadLocalTransporter) { } @Override @@ -325,7 +327,7 @@ public class MockedTrackedRace implements DynamicTrackedRace { public DynamicTrackedRace createTrackedRace(RaceDefinition raceDefinition, Iterable sidelines, WindStore windStore, long delayToLiveInMillis, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, DynamicRaceDefinitionSet raceDefinitionSetToUpdate, - boolean useMarkPassingCalculator, RaceLogResolver raceLogResolver) { + boolean useMarkPassingCalculator, RaceLogResolver raceLogResolver, Optional threadLocalTransporter) { return null; } diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingWindTracksTest.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingWindTracksTest.java index f78772ff244..e53c92b45da 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingWindTracksTest.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndRetrievingWindTracksTest.java @@ -9,6 +9,7 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.Collections; +import java.util.Optional; import org.junit.Before; import org.junit.Test; @@ -103,7 +104,8 @@ public class TestStoringAndRetrievingWindTracksTest extends AbstractTracTracLive @Override public void addRaceDefinition(RaceDefinition race, DynamicTrackedRace trackedRace) { } - }, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class)); + }, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class), + Optional.empty()); WindSource windSource = new WindSourceImpl(WindSourceType.WEB); Mongo myFirstMongo = newMongo(); DB firstDatabase = myFirstMongo.getDB(dbConfiguration.getDatabaseName()); diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/statistics/StatisticsTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/statistics/StatisticsTest.java index 46bbae978ea..17e91a94394 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/statistics/StatisticsTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/statistics/StatisticsTest.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Optional; import org.junit.Before; import org.junit.Test; @@ -81,7 +82,7 @@ public class StatisticsTest { trackedRace.setEndOfTrackingReceived(new MillisecondsTimePoint(END_OF_TRACKING)); trackedRace.setStartTimeReceived(new MillisecondsTimePoint(START_OF_RACE)); - regatta.addTrackedRace(trackedRace); + regatta.addTrackedRace(trackedRace, Optional.empty()); } private TrackedRaceStatisticsCacheImpl getStatisticsCacheWithRegattaAdded() throws Exception { @@ -98,7 +99,7 @@ public class StatisticsTest { public void raceAdded(TrackedRace trackedRace) { } }; - regatta.addRaceListener(raceListener); + regatta.addRaceListener(raceListener, Optional.empty()); regatta.removeRaceListener(raceListener).get(); return trackedRaceStatisticsCache; diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java index 16f1d062661..8685d9ca7a5 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerStartStopTest.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -83,17 +84,20 @@ public class RaceTrackerStartStopTest { trackedRegatta1.createTrackedRace(raceDef1, Collections. emptyList(), /* windStore */ EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l, - /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class)); + /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class), + Optional.empty()); regatta.addRace(raceDef2); trackedRegatta1.createTrackedRace(raceDef2, Collections. emptyList(), /* windStore */ EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l, - /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class)); + /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class), + Optional.empty()); regatta.addRace(raceDef3); trackedRegatta1.createTrackedRace(raceDef3, Collections. emptyList(), /* windStore */ EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l, - /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class)); + /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class), + Optional.empty()); Long trackerID1 = new Long(1); Long trackerID2 = new Long(2); Long trackerID3 = new Long(3); diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerTest.java index b94b3655167..96509d108d4 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RaceTrackerTest.java @@ -10,6 +10,7 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.util.Optional; import java.util.logging.Logger; import org.junit.After; @@ -102,7 +103,7 @@ public class RaceTrackerTest { @Override public void raceRemoved(TrackedRace trackedRace) { } - }); + }, Optional.empty()); synchronized (trackedRaces) { if (trackedRaces[0] == null) { trackedRaces.wait(); diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardTest.java index 8a7d341470a..39a522db57f 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardTest.java @@ -10,6 +10,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.UUID; import org.junit.Before; @@ -101,7 +102,8 @@ public class RemoveLeaderboardTest { trackedRace = trackedRegatta1.createTrackedRace(raceDef1, Collections. emptyList(), /* windStore */ EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 0l, /* millisecondsOverWhichToAverageWind */ 0l, - /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class)); + /* millisecondsOverWhichToAverageSpeed */ 0l, /* raceDefinitionSetToUpdate */ null, /*useMarkPassingCalculator*/ false, mock(RaceLogResolver.class), + Optional.empty()); } @Test diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 284ea401e52..bb8a96c70e6 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -1740,13 +1741,15 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes RaceDefinition race = getRace(raceIdentifier); return trackedRegatta.createTrackedRace(race, Collections. emptyList(), windStore, delayToLiveInMillis, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, - /* raceDefinitionSetToUpdate */null, useMarkPassingCalculator, /* raceLogResolver */ this); + /* raceDefinitionSetToUpdate */null, useMarkPassingCalculator, /* raceLogResolver */ this, + Optional.of(this.getThreadLocalTransporterForCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster())); } private void ensureRegattaIsObservedForDefaultLeaderboardAndAutoLeaderboardLinking( DynamicTrackedRegatta trackedRegatta) { if (regattasObservedForDefaultLeaderboard.add(trackedRegatta)) { - trackedRegatta.addRaceListener(new RaceAdditionListener()); + trackedRegatta.addRaceListener(new RaceAdditionListener(), + Optional.of(this.getThreadLocalTransporterForCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster())); } } @@ -2436,7 +2439,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes final int newSizeOfTrackedRaces; oldSizeOfTrackedRaces = Util.size(trackedRegatta.getTrackedRaces()); try { - trackedRegatta.removeTrackedRace(trackedRace); + trackedRegatta.removeTrackedRace(trackedRace, Optional.of( + getThreadLocalTransporterForCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster())); newSizeOfTrackedRaces = Util.size(trackedRegatta.getTrackedRaces()); isTrackedRacesBecameEmpty = (oldSizeOfTrackedRaces > 0 && newSizeOfTrackedRaces == 0); } finally { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java index 7c24ea62cc0..a1983633ad7 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/ImportMasterDataOperation.java @@ -7,6 +7,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.logging.Level; @@ -477,7 +478,8 @@ public class ImportMasterDataOperation extends trackedRegatta.unlockTrackedRacesAfterRead(); } for (TrackedRace raceToRemove : toRemove) { - trackedRegatta.removeTrackedRace(raceToRemove); + trackedRegatta.removeTrackedRace(raceToRemove, Optional.of(toState + .getThreadLocalTransporterForCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster())); RaceDefinition race = existingRegatta.getRaceByName(raceToRemove .getRaceIdentifier().getRaceName()); if (race != null) { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java index f7ebb1eca4a..9252bbb57c4 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/simulation/SimulationServiceImpl.java @@ -6,6 +6,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.TreeMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -283,7 +284,7 @@ public class SimulationServiceImpl implements SimulationService { DynamicTrackedRegatta trackedRegatta = racingEventService.getTrackedRegatta(regatta); SimulationRaceListener raceListener = new SimulationRaceListener(); raceListeners.put(legIdentifier.getRegattaName(), raceListener); - trackedRegatta.addRaceListener(raceListener); + trackedRegatta.addRaceListener(raceListener, /* Not replicated */ Optional.empty()); } if (!legListeners.containsKey(legIdentifier.getRaceIdentifier())) { TrackedRace trackedRace = racingEventService.getTrackedRace(legIdentifier); From 20206e20100f4317a8d639a0cdfda6137c7d3c4a Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 21 Mar 2018 16:56:35 +0100 Subject: [PATCH 11/11] Bug 4489: Added JavaDocs --- .../sailing/domain/tracking/impl/TrackedRegattaImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java index 8585cdad67f..138fb07c656 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/TrackedRegattaImpl.java @@ -149,6 +149,12 @@ public class TrackedRegattaImpl implements TrackedRegatta { enqueEvent(listener -> listener.raceAdded(trackedRace), threadLocalTransporter); } + /** + * Firing events is handled through {@link #eventQueue} to ensure that events are fired in order. This method + * enqueues an event while ensuring that the set of listeners is freezed to prevent events to be fired twice to a + * specific listener. Any Listener attached after will receive a consistent set of already added {@link TrackedRace + * TrackedRaces}. Firing events may not be done directly but only by using this method. + */ protected void enqueEvent(Consumer fireEventCallback, Optional threadLocalTransporter) { final Set listenersToInform = new HashSet<>(raceListeners.keySet()); threadLocalTransporter.ifPresent(ThreadLocalTransporter::rememberThreadLocalStates);