diff --git a/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/CompetitorDeregistrationTest.java b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/CompetitorDeregistrationTest.java new file mode 100755 index 00000000000..693e7df1e24 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android.test/src/com/sap/sailing/domain/regattalog/tracking/analyzing/test/CompetitorDeregistrationTest.java @@ -0,0 +1,37 @@ +package com.sap.sailing.domain.regattalog.tracking.analyzing.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +import java.util.Collections; +import java.util.Set; + +import org.junit.Test; + +import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; +import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent; +import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor; +import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl; +import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorDeregistrator; +import com.sap.sailing.domain.abstractlog.shared.analyzing.CompetitorsInLogAnalyzer; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.impl.CompetitorImpl; +import com.sap.sse.common.impl.MillisecondsTimePoint; + +public class CompetitorDeregistrationTest extends AbstractRegattaLogTrackingTest { + private final Competitor competitor = new CompetitorImpl("comp", "Comp", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null); + private final Competitor competitor2 = new CompetitorImpl("comp2", "Comp2", null, null, null, null, null, /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null); + + @Test + public void testCompetitorDeregistration() { + log.add(new RegattaLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), author, competitor)); + log.add(new RegattaLogRegisterCompetitorEventImpl(MillisecondsTimePoint.now(), author, competitor2)); + final CompetitorDeregistrator deregistrator = new CompetitorDeregistrator<>(log, + Collections.singleton(competitor2), author); + final Set events = deregistrator.analyze(); + deregistrator.deregister(events); + final Set competitors = new CompetitorsInLogAnalyzer<>(log).analyze(); + assertEquals(1, competitors.size()); + assertSame(competitor, competitors.iterator().next()); + } +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/CompetitorDeregistrator.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/CompetitorDeregistrator.java index f1316b292b4..06c05304b64 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/CompetitorDeregistrator.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/abstractlog/shared/analyzing/CompetitorDeregistrator.java @@ -1,6 +1,7 @@ package com.sap.sailing.domain.abstractlog.shared.analyzing; import java.util.HashSet; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -14,14 +15,21 @@ import com.sap.sailing.domain.common.abstractlog.NotRevokableException; import com.sap.sse.common.Util; /** - * Generates events that close the events that are responsible for the {@link #mapping} that is passed to the - * constructor. + * Finds the competitor registration events for a given set of {@link Competitor competitors} that must be + * {@link AbstractLog#revokeEvent(AbstractLogEventAuthor, AbstractLogEvent) revoked} in order to deregister the + * competitors. Note that the de-registration cannot be performed during analysis because + * {@link BaseLogAnalyzer#analyze()} obtains a read lock on the log whereas + * {@link AbstractLog#revokeEvent(AbstractLogEventAuthor, AbstractLogEvent)} requires a write lock, and upgrading from a + * read to a write lock is not possible.

+ * + * Clients must call {@link #deregister} with the result of {@link #analyze()} in order to actually perform the + * deregistration. * * @author Jan Bross * */ public class CompetitorDeregistrator, EventT extends AbstractLogEvent, VisitorT> -extends BaseLogAnalyzer { +extends BaseLogAnalyzer> { private static final Logger logger = Logger.getLogger(CompetitorDeregistrator.class.getName()); protected final Iterable competitorsToDeregister; @@ -34,24 +42,29 @@ extends BaseLogAnalyzer { } @Override - protected Void performAnalysis() { - HashSet competitorSet = new HashSet(); + protected Set performAnalysis() { + final Set result = new HashSet<>(); + final HashSet competitorSet = new HashSet(); Util.addAll(competitorsToDeregister, competitorSet); - for (EventT event : log.getUnrevokedEventsDescending()) { if (event instanceof RegisterCompetitorEvent) { RegisterCompetitorEvent registerEvent = (RegisterCompetitorEvent) event; if (competitorSet.contains(registerEvent.getCompetitor())) { - try { - log.revokeEvent(eventAuthor, event, - "unregistering competitor because no longer selected for registration"); - } catch (NotRevokableException e) { - logger.log(Level.WARNING, "could not unregister competitor by adding RevokeEvent", e); - } + result.add(event); } } } - - return null; + return result; + } + + public void deregister(final Set competitorRegistrationEvents) { + for (final EventT event : competitorRegistrationEvents) { + try { + log.revokeEvent(eventAuthor, event, + "unregistering competitor because no longer selected for registration"); + } catch (NotRevokableException e) { + logger.log(Level.WARNING, "could not unregister competitor by adding RevokeEvent", e); + } + } } } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java index f45ead7b68d..de350e75ac7 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/tracking/impl/TrackImpl.java @@ -313,19 +313,36 @@ public class TrackImpl implements Track { } protected boolean add(FixType fix) { + return add(fix, /* replace */ false); + } + + protected boolean add(FixType fix, boolean replace) { lockForWrite(); try { - return addWithoutLocking(fix); + return addWithoutLocking(fix, replace); } finally { unlockAfterWrite(); } } /** - * The caller must ensure to hold the write lock for this track when calling this methos + * The caller must ensure to hold the write lock for this track when calling this method. + * + * @param replace + * whether or not to replace an existing fix in the track that is equal to {@link #fix} as defined by the + * comparator used for the {@link #fixes} set. By default this is a comparator only comparing the + * fixes' time stamps. Subclasses may use different comparator implementations. */ - protected boolean addWithoutLocking(FixType fix) { - return getInternalRawFixes().add(fix); + protected boolean addWithoutLocking(FixType fix, boolean replace) { + final boolean result; + final boolean added = getInternalRawFixes().add(fix); + if (!added && replace) { + getInternalRawFixes().remove(fix); + result = getInternalFixes().add(fix); + } else { + result = added; + } + return result; } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java index 75982559fa0..6c39ac72caa 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/RegattaImpl.java @@ -792,6 +792,6 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene public void deregisterCompetitors(Iterable competitors) { RegattaLog regattaLog = getRegattaLike().getRegattaLog(); CompetitorDeregistrator deregisterer = new CompetitorDeregistrator<>(regattaLog, competitors, regattaLogEventAuthorForRegatta); - deregisterer.analyze(); + deregisterer.deregister(deregisterer.analyze()); } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java index 4c3ef7f9c9f..be0e19e182e 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardImpl.java @@ -224,6 +224,6 @@ public abstract class AbstractLeaderboardImpl extends AbstractSimpleLeaderboardI public void deregisterCompetitors(Iterable competitors) { RegattaLog regattaLog = getRegattaLike().getRegattaLog(); CompetitorDeregistrator deregisterer = new CompetitorDeregistrator<>(regattaLog, competitors, regattaLogEventAuthorForAbstractLeaderboard); - deregisterer.analyze(); + deregisterer.deregister(deregisterer.analyze()); } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicTrack.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicTrack.java index e1e728cf9c6..970e9fbf522 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicTrack.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/DynamicTrack.java @@ -4,7 +4,25 @@ import com.sap.sse.common.Timed; public interface DynamicTrack extends Track { /** + * Tries to add {@code fix} to this track. If an {@link #equals(Object) equal} fix already exists + * in this track, the track remains unchanged and {@code false} will be returned. + * * @return true if the element was added, false otherwise. */ boolean add(FixType fix); + + /** + * Tries to add {@code fix} to this track. If an {@link #equals(Object) equal} fix already exists + * in this track and {@code replace} is {@code false}, the track remains unchanged and {@code false} will be returned. + * If {@code replace} is {@code true}, an equal (by definition of the comparator used for the fixes set) fix will + * replace the fix contained in this track. + * + * @param replace + * whether or not to replace an existing fix in the track that is equal to {@link #fix} as defined by the + * comparator used for the {@link #fixes} set. By default this is a comparator only comparing the fixes' + * time stamps. Subclasses may use different comparator implementations. + * + * @return true if the element was added, false otherwise. + */ + boolean add(FixType fix, boolean replace); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java index 474da3db2e6..77064a32927 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/DynamicGPSFixMovingTrackImpl.java @@ -47,7 +47,7 @@ public class DynamicGPSFixMovingTrackImpl extends GPSFixTrackImpl extends GPSFixTrackImpl extends GPSFixTrackImpl extends TrackImpl public boolean add(FixType fix) { return super.add(fix); } + + @Override + public boolean add(FixType fix, boolean replace) { + return super.add(fix, replace); + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java index 1259e536ac1..208b4059cd4 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/GPSFixTrackImpl.java @@ -1106,7 +1106,7 @@ public class GPSFixTrackImpl extends TrackImpl lockForWrite(); try { firstFixInTrack = getRawFixes().isEmpty(); - result = addWithoutLocking(fix); + result = addWithoutLocking(fix, /* replace */ false); if (!validityCachingSuspended) { invalidateValidityAndEstimatedSpeedAndDistanceCaches(fix); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/WindTrackImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/WindTrackImpl.java index 796f25602a5..8ce0c7194ed 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/WindTrackImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/impl/WindTrackImpl.java @@ -108,9 +108,14 @@ public class WindTrackImpl extends TrackImpl implements WindTrack { } @Override - public boolean add(Wind wind) { + public boolean add(Wind fix) { + return super.add(fix); + } + + @Override + public boolean add(Wind wind, boolean replace) { final CompactWindImpl compactWind = new CompactWindImpl(wind); - final boolean result = super.add(compactWind); + final boolean result = super.add(compactWind, replace); notifyListenersAboutReceive(compactWind); return result; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.java index 45104e186c4..69e1aad771f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.java @@ -139,7 +139,6 @@ public interface TextMessages extends Messages { String latestRaceResultsHeadline(); String latestRaceResultsIsNew(); String latestRaceResultsIsUpdated(); - String latestRaceResultsRaceCountLabel(); String latestRaceResultsRaceCountUnit(); String latestRaceResultsRefresh(); String leaderboardQuickAccessLabel(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.properties index 7365690323b..68759ed7726 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.properties @@ -128,7 +128,6 @@ headerSponsoring=Sponsoring latestRaceResultsHeadline=Latest Official Race Results latestRaceResultsIsNew=New latestRaceResultsIsUpdated=Updated -latestRaceResultsRaceCountLabel=Result after latestRaceResultsRaceCountUnit=races latestRaceResultsRefresh=refresh leaderboardQuickAccessLabel=Leaderboard Quick Access diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_de.properties index 66836911be6..9076a2dfd83 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_de.properties @@ -128,7 +128,6 @@ headerSponsoring=Sponsoren latestRaceResultsHeadline=Letzten ofiziellen Ergebnisse latestRaceResultsIsNew=Neu latestRaceResultsIsUpdated=Aktualisiert -latestRaceResultsRaceCountLabel=Ergebnis nach latestRaceResultsRaceCountUnit=Rennen latestRaceResultsRefresh=aktualisieren leaderboardQuickAccessLabel=Ergebnisliste Schnellzugang diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_ru.properties index 672db2ce8f1..46a2645ad4b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_ru.properties @@ -128,7 +128,6 @@ headerSponsoring=Sponsoring latestRaceResultsHeadline=Latest Official Race Results latestRaceResultsIsNew=New latestRaceResultsIsUpdated=Updated -latestRaceResultsRaceCountLabel=Result after latestRaceResultsRaceCountUnit=races latestRaceResultsRefresh=refresh leaderboardQuickAccessLabel=Leaderboard Quick Access diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_zh.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_zh.properties index 09b2d649884..28c706f9abe 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_zh.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_zh.properties @@ -159,7 +159,6 @@ headerSponsoring=Sponsoring latestRaceResultsHeadline=Latest Official Race Results latestRaceResultsIsNew=New latestRaceResultsIsUpdated=Updated -latestRaceResultsRaceCountLabel=Result after latestRaceResultsRaceCountUnit=races latestRaceResultsRefresh=refresh leaderboardQuickAccessLabel=Leaderboard Quick Access