From b0b01401fbe5d0589362335bc16ca80db94695ea Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 5 Oct 2016 11:05:13 +0200 Subject: [PATCH 01/11] Added conditions to prevent notification mails to be sent for old events --- .../sailing/server/impl/RacingEventServiceImpl.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) 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 2605ac6ddb2..7e30c0936a3 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 @@ -1775,10 +1775,12 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes // no action required; the update signaled by this call is implicit; the race log // updates that led to this change are replicated separately - scheduler.execute(()-> - // Notify interested users: - notificationService.notifyUserOnBoatClassRaceChangesStateToFinished(trackedRace.getRace().getBoatClass(), trackedRace, - getMostAppropriateLeaderboard(), getMostAppropriateRaceColumn(), getMostAppropriateFleet())); + if(newFinishedTime.after(MillisecondsTimePoint.now().minus(Duration.ONE_HOUR))) { + scheduler.execute(()-> + // Notify interested users: + notificationService.notifyUserOnBoatClassRaceChangesStateToFinished(trackedRace.getRace().getBoatClass(), trackedRace, + getMostAppropriateLeaderboard(), getMostAppropriateRaceColumn(), getMostAppropriateFleet())); + } } @Override @@ -1838,7 +1840,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes replicate(new UpdateMarkPassings(getRaceIdentifier(), competitor, markPassings)); final MarkPassing last = Util.last(markPassings); if (last != null && last.getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint() && - trackedRace.getStatus().getStatus() != TrackedRaceStatusEnum.LOADING) { + trackedRace.getStatus().getStatus() != TrackedRaceStatusEnum.LOADING && + last.getTimePoint().after(MillisecondsTimePoint.now().minus(Duration.ONE_HOUR))) { scheduler.execute(() -> // Notify interested users: notificationService.notifyUserOnCompetitorPassesFinish(competitor, trackedRace, From a708adbe3a42f4211b38188ba833faed5a906bec Mon Sep 17 00:00:00 2001 From: Kai Boernert Date: Thu, 13 Oct 2016 16:19:22 +0200 Subject: [PATCH 02/11] added locking, to prevent caching eventdata of already deleted servers if removal and querying data overlaps --- .../server/impl/RemoteSailingServerSet.java | 140 +++++++++++++----- 1 file changed, 102 insertions(+), 38 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RemoteSailingServerSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RemoteSailingServerSet.java index f9993be852e..915554f9f8e 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RemoteSailingServerSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RemoteSailingServerSet.java @@ -33,6 +33,8 @@ import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardGroupBaseJ import com.sap.sailing.server.gateway.deserialization.impl.VenueJsonDeserializer; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; +import com.sap.sse.concurrent.LockUtil; +import com.sap.sse.concurrent.NamedReentrantReadWriteLock; import com.sap.sse.util.HttpUrlConnectionHelper; /** @@ -44,15 +46,16 @@ import com.sap.sse.util.HttpUrlConnectionHelper; */ public class RemoteSailingServerSet { private static final int POLLING_INTERVAL_IN_SECONDS = 60; + private NamedReentrantReadWriteLock lock = new NamedReentrantReadWriteLock("lock for RemoteSailingServerSet", true); private static final Logger logger = Logger.getLogger(RemoteSailingServerSet.class.getName()); - + /** * Holds the remote server references managed by this set. Keys are the * {@link RemoteSailingServerReference#getName() names} of the server references. */ private final ConcurrentMap remoteSailingServers; - + private final ConcurrentMap, Exception>> cachedEventsForRemoteSailingServers; /** @@ -62,53 +65,79 @@ public class RemoteSailingServerSet { public RemoteSailingServerSet(ScheduledExecutorService scheduler) { remoteSailingServers = new ConcurrentHashMap<>(); cachedEventsForRemoteSailingServers = new ConcurrentHashMap<>(); - scheduler.scheduleAtFixedRate(new Runnable() { @Override public void run() { updateRemoteSailingServerReferenceEventCaches(); } }, - /* initialDelay */ 0, POLLING_INTERVAL_IN_SECONDS, TimeUnit.SECONDS); + scheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + updateRemoteSailingServerReferenceEventCaches(); + } + }, /* initialDelay */ 0, POLLING_INTERVAL_IN_SECONDS, TimeUnit.SECONDS); } public void clear() { - remoteSailingServers.clear(); - cachedEventsForRemoteSailingServers.clear(); + LockUtil.executeWithWriteLock(lock, new Runnable() { + @Override + public void run() { + remoteSailingServers.clear(); + cachedEventsForRemoteSailingServers.clear(); + } + }); } public void add(RemoteSailingServerReference remoteSailingServerReference) { - remoteSailingServers.put(remoteSailingServerReference.getName(), remoteSailingServerReference); - triggerAsynchronousEventCacheUpdate(remoteSailingServerReference); + LockUtil.executeWithWriteLock(lock, new Runnable() { + + @Override + public void run() { + remoteSailingServers.put(remoteSailingServerReference.getName(), remoteSailingServerReference); + triggerAsynchronousEventCacheUpdate(remoteSailingServerReference); + } + }); } - + private void updateRemoteSailingServerReferenceEventCaches() { - for (RemoteSailingServerReference ref : remoteSailingServers.values()) { - triggerAsynchronousEventCacheUpdate(ref); - } + LockUtil.executeWithReadLock(lock, new Runnable() { + + @Override + public void run() { + for (RemoteSailingServerReference ref : remoteSailingServers.values()) { + triggerAsynchronousEventCacheUpdate(ref); + } + } + }); } - + /** - * If this set has a {@link RemoteSailingServerReference} whose {@link RemoteSailingServerReference#getName() name} equals - * name, it is returned. Otherwise, null is returned. + * If this set has a {@link RemoteSailingServerReference} whose {@link RemoteSailingServerReference#getName() name} + * equals name, it is returned. Otherwise, null is returned. */ public RemoteSailingServerReference getServerReferenceByName(String name) { return remoteSailingServers.get(name); } private void triggerAsynchronousEventCacheUpdate(final RemoteSailingServerReference ref) { - new Thread("Event Cache Updater for remote server "+ref) { - @Override public void run() { updateRemoteServerEventCacheSynchronously(ref); } + new Thread("Event Cache Updater for remote server " + ref) { + @Override + public void run() { + updateRemoteServerEventCacheSynchronously(ref); + } }.start(); } - private Util.Pair, Exception> updateRemoteServerEventCacheSynchronously(RemoteSailingServerReference ref) { + private Util.Pair, Exception> updateRemoteServerEventCacheSynchronously( + RemoteSailingServerReference ref) { BufferedReader bufferedReader = null; Util.Pair, Exception> result; try { try { final URL eventsURL = getEventsURL(ref.getURL()); - logger.fine("Updating events for remote server "+ref+" from URL "+eventsURL); + logger.fine("Updating events for remote server " + ref + " from URL " + eventsURL); URLConnection urlConnection = HttpUrlConnectionHelper.redirectConnection(eventsURL); bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8")); JSONParser parser = new JSONParser(); Object eventsAsObject = parser.parse(bufferedReader); - EventBaseJsonDeserializer deserializer = new EventBaseJsonDeserializer(new VenueJsonDeserializer( - new CourseAreaJsonDeserializer(DomainFactory.INSTANCE)), new LeaderboardGroupBaseJsonDeserializer()); + EventBaseJsonDeserializer deserializer = new EventBaseJsonDeserializer( + new VenueJsonDeserializer(new CourseAreaJsonDeserializer(DomainFactory.INSTANCE)), + new LeaderboardGroupBaseJsonDeserializer()); JSONArray eventsAsJsonArray = (JSONArray) eventsAsObject; final Set events = new HashSet<>(); for (Object eventAsObject : eventsAsJsonArray) { @@ -123,13 +152,28 @@ public class RemoteSailingServerSet { } } } catch (IOException | ParseException e) { - logger.log(Level.INFO, "Exception trying to fetch events from remote server "+ref+": "+e.getMessage(), e); + logger.log(Level.INFO, "Exception trying to fetch events from remote server " + ref + ": " + e.getMessage(), + e); result = new Util.Pair, Exception>(/* events */ null, e); } - cachedEventsForRemoteSailingServers.put(ref, result); + + final Pair, Exception> finalResult = result; + + LockUtil.executeWithWriteLock(lock, new Runnable() { + + @Override + public void run() { + // check that the server was not removed while no lock was held + if (remoteSailingServers.containsValue(ref)) { + cachedEventsForRemoteSailingServers.put(ref, finalResult); + }else{ + logger.fine("Omitted update for " + ref + " as it was removed"); + } + } + }); return result; } - + private URL getEventsURL(URL remoteServerBaseURL) throws MalformedURLException { String getEventsUrl = remoteServerBaseURL.toExternalForm(); if (!getEventsUrl.endsWith("/")) { @@ -140,36 +184,56 @@ public class RemoteSailingServerSet { } public Map, Exception>> getCachedEventsForRemoteSailingServers() { - return Collections.unmodifiableMap(cachedEventsForRemoteSailingServers); + LockUtil.lockForRead(lock); + try { + return Collections.unmodifiableMap(cachedEventsForRemoteSailingServers); + } finally { + LockUtil.unlockAfterRead(lock); + } } public RemoteSailingServerReference remove(String name) { - RemoteSailingServerReference ref = remoteSailingServers.remove(name); - if (ref != null) { - cachedEventsForRemoteSailingServers.remove(ref); + LockUtil.lockForWrite(lock); + try{ + RemoteSailingServerReference ref = remoteSailingServers.remove(name); + if (ref != null) { + cachedEventsForRemoteSailingServers.remove(ref); + } + return ref; + }finally{ + LockUtil.unlockAfterWrite(lock); } - return ref; } /** - * Synchronously fetches the latest events list for the remote server reference specified. The - * result is cached. If ref was not yet part of this remote sailing server reference set, - * it is automatically added. + * Synchronously fetches the latest events list for the remote server reference specified. The result is cached. If + * ref was not yet part of this remote sailing server reference set, it is automatically added. */ public Util.Pair, Exception> getEventsOrException(RemoteSailingServerReference ref) { - if (!remoteSailingServers.containsKey(ref.getName())) { - remoteSailingServers.put(ref.getName(), ref); + LockUtil.lockForWrite(lock); + try { + if (!remoteSailingServers.containsKey(ref.getName())) { + remoteSailingServers.put(ref.getName(), ref); + } + } finally { + LockUtil.unlockAfterWrite(lock); } return updateRemoteServerEventCacheSynchronously(ref); } public Iterable getLiveRemoteServerReferences() { List result = new ArrayList<>(); - for (Map.Entry, Exception>> e : cachedEventsForRemoteSailingServers.entrySet()) { - if (e.getValue().getB() == null) { - // no exception; reference considered live - result.add(e.getKey()); + LockUtil.lockForRead(lock); + try { + for (Map.Entry, Exception>> e : cachedEventsForRemoteSailingServers + .entrySet()) { + if (e.getValue().getB() == null) { + // no exception; reference considered live + result.add(e.getKey()); + } } + } finally { + LockUtil.unlockAfterRead(lock); } return result; } From 04bf64c11aef12749da44b1e7ac30593faaa13b2 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 13 Oct 2016 17:16:44 +0200 Subject: [PATCH 03/11] formatting change only Change-Id: Ic666fcfd0180bdd663cd829a2c99d05b5bcfdcce --- .../com/sap/sailing/server/impl/RacingEventServiceImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 7e30c0936a3..bf20b0cc984 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 @@ -1774,8 +1774,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes public void finishedTimeChanged(TimePoint oldFinishedTime, TimePoint newFinishedTime) { // no action required; the update signaled by this call is implicit; the race log // updates that led to this change are replicated separately - - if(newFinishedTime.after(MillisecondsTimePoint.now().minus(Duration.ONE_HOUR))) { + if (newFinishedTime.after(MillisecondsTimePoint.now().minus(Duration.ONE_HOUR))) { scheduler.execute(()-> // Notify interested users: notificationService.notifyUserOnBoatClassRaceChangesStateToFinished(trackedRace.getRace().getBoatClass(), trackedRace, From d3e84161f0a5fe3362b88f2def4d990ab03ac67f Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 14 Oct 2016 12:45:20 +0200 Subject: [PATCH 04/11] added a failing test case for bug 3955 Change-Id: I86302f6b3a6a2adb14687cfcd4a769d3330cc48e --- .../test/ApplyScoresFromRaceLogTest.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java index 8267c1c0f3d..a5c20e7e880 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java @@ -107,5 +107,84 @@ public class ApplyScoresFromRaceLogTest extends LeaderboardScoringAndRankingTest assertEquals(expectedNewOrder, rankedCompetitorsAfterApplying); } + /** + * See also bug 3955: when for a competitor no score is explicitly provided but a {@link MaxPointsReason} has been set, don't + * correct the score in the leaderboard's score correction but only set the {@link MaxPointsReason}. This will let the scoring + * scheme select the score, as it used to be before the fix for bug 3794, commit 830e64842a39fb137446887c5177f7de34bd5b5a. + */ + @Test + public void testScoresFromRaceLogOnlyAppliedIfExplicitOrNoMaxPointsReason() throws NoWindException { + final RacingEventService service = new RacingEventServiceImpl(); + final List competitors = new ArrayList<>(); + for (int i=0; i<8; i++) { + final String competitorName = "C"+i; + competitors.add(service.getBaseDomainFactory().getCompetitorStore().getOrCreateCompetitor(UUID.randomUUID(), + competitorName, /* displayColor */ Color.RED, /* email */ null, /* flagImageURI */ null, + new TeamImpl("STG", Collections.singleton( + new PersonImpl(competitorName, new NationalityImpl("GER"), + /* dateOfBirth */ null, "This is famous "+competitorName)), + new PersonImpl("Rigo van Maas", new NationalityImpl("NED"), + /* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl(competitorName + "'s boat", + new BoatClassImpl("505", /* typicallyStartsUpwind */ true), /* sailID */ null), + /* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null)); + } + final Regatta regatta = createRegatta(/* qualifying */0, new String[] { "Default" }, /* final */1, + new String[] { "Default" }, + /* medal */false, /* medal */ 0, "testOneStartedRaceWithDifferentScores", + DomainFactory.INSTANCE.getOrCreateBoatClass("49er", /* typicallyStartsUpwind */true), DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.HIGH_POINT_FIRST_GETS_TEN_OR_EIGHT)); + TimePoint now = MillisecondsTimePoint.now(); + TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000); + TrackedRace f1 = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors); + RaceColumn f1Column = series.get(1).getRaceColumnByName("F1"); + f1Column.setTrackedRace(f1Column.getFleets().iterator().next(), f1); + final Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[0]); + + service.addLeaderboard(leaderboard); // should add a RaceLogScoringReplicator as listener to the leaderboard + service.addRegattaWithoutReplication(regatta); + int oneBasedRank = 1; + final CompetitorResults results = new CompetitorResultsImpl(); + + setResultForCompetitor(competitors.get(0), oneBasedRank++, results, MaxPointsReason.DNF, /* explicit score */ null); + setResultForCompetitor(competitors.get(1), oneBasedRank++, results, MaxPointsReason.OCS, /* explicit score */ null); + setResultForCompetitor(competitors.get(2), oneBasedRank++, results, MaxPointsReason.DNF, /* explicit score */ 0.1); + setResultForCompetitor(competitors.get(3), oneBasedRank++, results, MaxPointsReason.OCS, /* explicit score */ 0.2); + setResultForCompetitor(competitors.get(4), oneBasedRank++, results, /* maxPointsReason */ null, /* explicit score */ null); + setResultForCompetitor(competitors.get(5), oneBasedRank++, results, /* maxPointsReason */ null, /* explicit score */ 2.4); + setResultForCompetitor(competitors.get(6), oneBasedRank++, results, MaxPointsReason.NONE, /* explicit score */ null); + setResultForCompetitor(competitors.get(7), oneBasedRank++, results, MaxPointsReason.NONE, /* explicit score */ 3.3); + + final RaceLog f1RaceLog = f1Column.getRaceLog(f1Column.getFleets().iterator().next()); + final LogEventAuthorImpl author = new LogEventAuthorImpl("Axel", 0); + final RaceState f1RaceState = new RaceStateImpl(service, f1RaceLog, author, + new RacingProcedureFactoryImpl(author, new EmptyRegattaConfiguration())); + f1RaceState.setFinishPositioningListChanged(now, results); + final List rankedCompetitorsBeforeApplying = leaderboard.getCompetitorsFromBestToWorst(later); + assertEquals(competitors, rankedCompetitorsBeforeApplying); // no effects of preliminary results list yet + f1RaceState.setFinishPositioningConfirmed(now); + + assertScoreCorrections(leaderboard, f1Column, competitors.get(0), MaxPointsReason.DNF, 0, /* score is corrected */ false, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(1), MaxPointsReason.OCS, 0, /* score is corrected */ false, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(2), MaxPointsReason.DNF, 0.1, /* score is corrected */ true, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(3), MaxPointsReason.OCS, 0.2, /* score is corrected */ true, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(4), null, 6, /* score is corrected */ false, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(5), null, 2.4, /* score is corrected */ true, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(6), MaxPointsReason.NONE, 4, /* score is corrected */ false, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(7), MaxPointsReason.NONE, 3.3, /* score is corrected */ true, later); + } + + private void assertScoreCorrections(Leaderboard leaderboard, RaceColumn raceColumn, Competitor competitor, + MaxPointsReason expectedMaxPointsReason, double expectedScore, boolean expectedIsScoreCorrected, + TimePoint timePoint) { + assertEquals(expectedIsScoreCorrected, leaderboard.getScoreCorrection().getExplicitScoreCorrection(competitor, raceColumn) != null); + assertEquals(expectedMaxPointsReason, leaderboard.getScoreCorrection().getMaxPointsReason(competitor, raceColumn, timePoint)); + assertEquals(expectedScore, leaderboard.getTotalPoints(competitor, raceColumn, timePoint), 0.000001); + } + + private void setResultForCompetitor(final Competitor competitor, int oneBasedRank, + final CompetitorResults results, MaxPointsReason maxPointsReason, Double explicitScore) { + results.add(new CompetitorResultImpl(competitor.getId(), competitor.getName(), oneBasedRank++, maxPointsReason, explicitScore, /* finishingTime */ null, /* comment */ null)); + } + + } From aeeb3cedbedd6881d023a63e9fb76304308a9bdd Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 14 Oct 2016 12:55:04 +0200 Subject: [PATCH 05/11] fix for bug 3955: apply scores from RaceLog only if explicit or no MaxPointsReason is set; adjusted test; formerly failing test passes now Change-Id: Idf2085e122eb0b30c86be0c254f360407c1819f9 --- .../test/ApplyScoresFromRaceLogTest.java | 22 +++++++++---------- .../server/impl/RaceLogScoringReplicator.java | 14 +++++++++--- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java index a5c20e7e880..907301a3d26 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java @@ -97,12 +97,12 @@ public class ApplyScoresFromRaceLogTest extends LeaderboardScoringAndRankingTest assertEquals(competitors, rankedCompetitorsBeforeApplying); // no effects of preliminary results list yet f1RaceState.setFinishPositioningConfirmed(now); for (final Competitor c : competitors) { - assertEquals(scores.get(c)==null?competitors.indexOf(c)+1:scores.get(c), leaderboard.getTotalPoints(c, f1Column, now), 0.00000001); + assertEquals(scores.get(c)==null?(mprs.get(c) == null || mprs.get(c) == MaxPointsReason.NONE ? competitors.indexOf(c)+1 : competitors.size()+1):scores.get(c), leaderboard.getTotalPoints(c, f1Column, now), 0.00000001); } final List expectedNewOrder = new ArrayList<>(competitors); expectedNewOrder.sort((c1, c2)-> - new Double(scores.get(c1)==null?competitors.indexOf(c1)+1:scores.get(c1)).compareTo( - new Double(scores.get(c2)==null?competitors.indexOf(c2)+1:scores.get(c2)))); + new Double(scores.get(c1)==null?(mprs.get(c1) == null || mprs.get(c1) == MaxPointsReason.NONE ? competitors.indexOf(c1)+1 : competitors.size()+1):scores.get(c1)).compareTo( + new Double(scores.get(c2)==null?(mprs.get(c2) == null || mprs.get(c2) == MaxPointsReason.NONE ? competitors.indexOf(c2)+1 : competitors.size()+1):scores.get(c2)))); final List rankedCompetitorsAfterApplying = leaderboard.getCompetitorsFromBestToWorst(later); assertEquals(expectedNewOrder, rankedCompetitorsAfterApplying); } @@ -162,14 +162,14 @@ public class ApplyScoresFromRaceLogTest extends LeaderboardScoringAndRankingTest assertEquals(competitors, rankedCompetitorsBeforeApplying); // no effects of preliminary results list yet f1RaceState.setFinishPositioningConfirmed(now); - assertScoreCorrections(leaderboard, f1Column, competitors.get(0), MaxPointsReason.DNF, 0, /* score is corrected */ false, later); - assertScoreCorrections(leaderboard, f1Column, competitors.get(1), MaxPointsReason.OCS, 0, /* score is corrected */ false, later); - assertScoreCorrections(leaderboard, f1Column, competitors.get(2), MaxPointsReason.DNF, 0.1, /* score is corrected */ true, later); - assertScoreCorrections(leaderboard, f1Column, competitors.get(3), MaxPointsReason.OCS, 0.2, /* score is corrected */ true, later); - assertScoreCorrections(leaderboard, f1Column, competitors.get(4), null, 6, /* score is corrected */ false, later); - assertScoreCorrections(leaderboard, f1Column, competitors.get(5), null, 2.4, /* score is corrected */ true, later); - assertScoreCorrections(leaderboard, f1Column, competitors.get(6), MaxPointsReason.NONE, 4, /* score is corrected */ false, later); - assertScoreCorrections(leaderboard, f1Column, competitors.get(7), MaxPointsReason.NONE, 3.3, /* score is corrected */ true, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(0), MaxPointsReason.DNF, 0, /* score is corrected */ false, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(1), MaxPointsReason.OCS, 0, /* score is corrected */ false, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(2), MaxPointsReason.DNF, 0.1, /* score is corrected */ true, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(3), MaxPointsReason.OCS, 0.2, /* score is corrected */ true, later); + assertScoreCorrections(leaderboard, f1Column, competitors.get(4), MaxPointsReason.NONE, 6, /* score is corrected */ true, later); // score corrected based on rank because no MaxPointsReason set + assertScoreCorrections(leaderboard, f1Column, competitors.get(5), MaxPointsReason.NONE, 2.4, /* score is corrected */ true, later); // score corrected based on explicit score + assertScoreCorrections(leaderboard, f1Column, competitors.get(6), MaxPointsReason.NONE, 4, /* score is corrected */ true, later); // score corrected based on rank because MaxPointsReason.NONE set + assertScoreCorrections(leaderboard, f1Column, competitors.get(7), MaxPointsReason.NONE, 3.3, /* score is corrected */ true, later); // score corrected based on explicit score } private void assertScoreCorrections(Leaderboard leaderboard, RaceColumn raceColumn, Competitor competitor, diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java index dc88222e500..cd71012d9e0 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogScoringReplicator.java @@ -143,9 +143,17 @@ public class RaceLogScoringReplicator implements RaceColumnListener { if (positioningList != null) { for (CompetitorResult positionedCompetitor : positioningList) { Competitor competitor = service.getBaseDomainFactory().getExistingCompetitorById(positionedCompetitor.getCompetitorId()); - int rankByRaceCommittee = getRankInPositioningListByRaceCommittee(positionedCompetitor); - correctScoreInLeaderboard(leaderboard, raceColumn, timePoint, numberOfCompetitorsInRace, - competitor, rankByRaceCommittee, positionedCompetitor.getScore()); + // The score is updated when explicitly provided or when no penalty was set; + // in turn, this means that when a penalty is set and no score is explicitly provided, + // it is up to the scoring scheme to infer a penalty score for the MaxPointsReason. + // See also bug 3955. + if (positionedCompetitor.getScore() != null + || positionedCompetitor.getMaxPointsReason() == null + || positionedCompetitor.getMaxPointsReason().equals(MaxPointsReason.NONE)) { + int rankByRaceCommittee = getRankInPositioningListByRaceCommittee(positionedCompetitor); + correctScoreInLeaderboard(leaderboard, raceColumn, timePoint, numberOfCompetitorsInRace, competitor, + rankByRaceCommittee, positionedCompetitor.getScore()); + } setMaxPointsReasonInLeaderboardIfNecessary(leaderboard, raceColumn, timePoint, positionedCompetitor.getMaxPointsReason(), competitor); } // Since the metadata update is used by the Sailing suite to determine the final state of a race, it has to From bc5663217ebc2646bd171016364b564edaac90ec Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Sat, 15 Oct 2016 14:53:11 +0200 Subject: [PATCH 06/11] fixed test case based on the observation that now multiple competitors may have equal max points, leading to non-predictable sort order Change-Id: I09222833ccfe700a73049a02e01821c834d1f8da --- .../server/test/ApplyScoresFromRaceLogTest.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java index 907301a3d26..96e8418a984 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/ApplyScoresFromRaceLogTest.java @@ -1,6 +1,7 @@ package com.sap.sailing.server.test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Collections; @@ -8,6 +9,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.function.Function; import org.junit.Test; @@ -96,15 +98,19 @@ public class ApplyScoresFromRaceLogTest extends LeaderboardScoringAndRankingTest final List rankedCompetitorsBeforeApplying = leaderboard.getCompetitorsFromBestToWorst(later); assertEquals(competitors, rankedCompetitorsBeforeApplying); // no effects of preliminary results list yet f1RaceState.setFinishPositioningConfirmed(now); + final Function expectedPoints = (c)->scores.get(c)==null?(mprs.get(c) == null || mprs.get(c) == MaxPointsReason.NONE ? competitors.indexOf(c)+1 : competitors.size()+1):scores.get(c); for (final Competitor c : competitors) { - assertEquals(scores.get(c)==null?(mprs.get(c) == null || mprs.get(c) == MaxPointsReason.NONE ? competitors.indexOf(c)+1 : competitors.size()+1):scores.get(c), leaderboard.getTotalPoints(c, f1Column, now), 0.00000001); + assertEquals(expectedPoints.apply(c), leaderboard.getTotalPoints(c, f1Column, now), 0.00000001); } final List expectedNewOrder = new ArrayList<>(competitors); - expectedNewOrder.sort((c1, c2)-> - new Double(scores.get(c1)==null?(mprs.get(c1) == null || mprs.get(c1) == MaxPointsReason.NONE ? competitors.indexOf(c1)+1 : competitors.size()+1):scores.get(c1)).compareTo( - new Double(scores.get(c2)==null?(mprs.get(c2) == null || mprs.get(c2) == MaxPointsReason.NONE ? competitors.indexOf(c2)+1 : competitors.size()+1):scores.get(c2)))); + expectedNewOrder.sort((c1, c2)->new Double(expectedPoints.apply(c1)).compareTo(new Double(expectedPoints.apply(c1)))); final List rankedCompetitorsAfterApplying = leaderboard.getCompetitorsFromBestToWorst(later); - assertEquals(expectedNewOrder, rankedCompetitorsAfterApplying); + double lastScore = 0; + for (final Competitor c : rankedCompetitorsAfterApplying) { + assertEquals(expectedPoints.apply(c), leaderboard.getTotalPoints(c, f1Column, later)); + assertTrue(leaderboard.getTotalPoints(c, f1Column, later) >= lastScore); + lastScore = leaderboard.getTotalPoints(c, f1Column, later); + } } /** From af482370d5f282f035ebd858c0766c501ffa86ce Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 15 Oct 2016 14:12:06 +0200 Subject: [PATCH 07/11] Implemented a statistic for the absolute rank of a competitor for a race (getLeaderboard().getTotalRankOfCompetitor()) --- .../stringmessages/Sailing_StringMessages.properties | 1 + .../stringmessages/Sailing_StringMessages_de.properties | 1 + .../data/HasRaceResultOfCompetitorContext.java | 7 +++++-- .../impl/data/RaceResultOfCompetitorWithContext.java | 9 +++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties index 4dbc578b18f..efd17444d39 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties @@ -44,6 +44,7 @@ Bft10=Storm Bft11=Violent storm Bft12=Hurricane RelativeScoreInRace=Relative score in race (0 best; 1 worst) +AbsoluteRank=Absolute Rank WindSpeedInBeaufort=Wind speed in Bft DistanceAtStart=Distance to start at start SpeedWhenStarting=Speed when starting diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties index e8ec0210da2..7144f76f7aa 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties @@ -44,6 +44,7 @@ Bft10=schwerer Sturm Bft11=orkanartiger Sturm Bft12=Orkan RelativeScoreInRace=Relative Wertung im Rennen (0 am besten; 1 am schlechtesten) +AbsoluteRank=Absolute Platzierung WindSpeedInBeaufort=Windgeschwindigkeit in Bft. DistanceAtStart=Distanz zur Startlinie zum Startzeitpunkt SpeedWhenStarting=Geschwindigkeit beim Überqueren der Startlinie diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java index 36e5292a1ba..c1b5b248c48 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java @@ -18,6 +18,9 @@ public interface HasRaceResultOfCompetitorContext { */ @Statistic(messageKey="RelativeScoreInRace", ordinal=1, resultDecimals=2) public double getRelativeRank(); + + @Statistic(messageKey="AbsoluteRank", ordinal=2, resultDecimals=2) + public double getAbsoluteRank(); @Dimension(messageKey="WindSpeedInBeaufort") int getAverageWindSpeedInRoundedBeaufort(); @@ -25,9 +28,9 @@ public interface HasRaceResultOfCompetitorContext { @Dimension(messageKey="Regatta") String getRegattaName(); - @Statistic(messageKey="NumberOfPodiumFinish", ordinal=2) + @Statistic(messageKey="NumberOfPodiumFinish", ordinal=3) public Boolean isPodiumFinish(); - @Statistic(messageKey="NumberOfWins", ordinal=3) + @Statistic(messageKey="NumberOfWins", ordinal=4) public Boolean isWin(); } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceResultOfCompetitorWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceResultOfCompetitorWithContext.java index 964b04bdfce..a099ba12d7d 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceResultOfCompetitorWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceResultOfCompetitorWithContext.java @@ -72,6 +72,15 @@ public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompeti final double result = relativeLowPoints / competitorCount; return result; } + + @Override + public double getAbsoluteRank() { + try { + return getLeaderboard().getTotalRankOfCompetitor(competitor, MillisecondsTimePoint.now()); + } catch (NoWindException e) { + throw new IllegalStateException("No wind calculating the absoulte rank", e); + } + } @Override public int getAverageWindSpeedInRoundedBeaufort() { From d56f4e850cde2187900676c64b4991d89c1eb47c Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 15 Oct 2016 15:19:00 +0200 Subject: [PATCH 08/11] Implemented a (cherry-pickable) dimension for a competitors search tag --- .../stringmessages/Sailing_StringMessages.properties | 1 + .../stringmessages/Sailing_StringMessages_de.properties | 1 + .../sap/sailing/datamining/data/HasMarkPassingContext.java | 3 +++ .../sailing/datamining/data/HasRaceOfCompetitorContext.java | 4 ++++ .../datamining/data/HasRaceResultOfCompetitorContext.java | 3 +++ .../datamining/data/HasTrackedLegOfCompetitorContext.java | 4 ++++ .../sailing/datamining/impl/data/MarkPassingWithContext.java | 5 +++++ .../datamining/impl/data/RaceOfCompetitorWithContext.java | 5 +++++ .../impl/data/RaceResultOfCompetitorWithContext.java | 5 +++++ .../impl/data/TrackedLegOfCompetitorWithContext.java | 5 +++++ 10 files changed, 36 insertions(+) diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties index efd17444d39..b9051747ef9 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties @@ -16,6 +16,7 @@ Race=Race Competitor=Competitor Boat=Boat Team=Team +CompetitorSearchTag=Competitor Search Tag LeaderboardSailingDomainRetrieverChain=Leaderboards RaceSailingDomainRetrieverChain=Races LegSailingDomainRetrieverChain=Legs diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties index 7144f76f7aa..d94720dd689 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties @@ -3,6 +3,7 @@ DistanceTraveled=zur Boat=Boot Team=Team Name=Name +CompetitorSearchTag=Teilnehmer Such-Tag Nationality=Nationalitäts Acronym=Abkürzung SailID=Segelnummer diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasMarkPassingContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasMarkPassingContext.java index 78a88fadba0..5e2f50e6986 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasMarkPassingContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasMarkPassingContext.java @@ -26,4 +26,7 @@ public interface HasMarkPassingContext { @Dimension(messageKey="LegType", ordinal=6) String getPreviousLegTypeSignifier() throws NoWindException; + + @Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible + public String getCompetitorSearchTag(); } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceOfCompetitorContext.java index 8c6334b84e2..096ea5bdb74 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceOfCompetitorContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceOfCompetitorContext.java @@ -4,6 +4,7 @@ import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.common.Speed; import com.sap.sse.datamining.annotations.Connector; +import com.sap.sse.datamining.annotations.Dimension; import com.sap.sse.datamining.annotations.Statistic; public interface HasRaceOfCompetitorContext { @@ -14,6 +15,9 @@ public interface HasRaceOfCompetitorContext { @Connector(messageKey="Competitor") public Competitor getCompetitor(); + @Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible + public String getCompetitorSearchTag(); + @Statistic(messageKey="DistanceAtStart", resultDecimals=2, ordinal=0) public Distance getDistanceToStartLineAtStart(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java index c1b5b248c48..e5e0e4c9fcd 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java @@ -13,6 +13,9 @@ public interface HasRaceResultOfCompetitorContext { @Connector(messageKey="Competitor") public Competitor getCompetitor(); + @Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible + public String getCompetitorSearchTag(); + /** * 0 means the competitor won the race, 1 means the competitor ranked last */ diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java index c863c6bb2f7..fc095c71e24 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java @@ -4,6 +4,7 @@ import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sse.datamining.annotations.Connector; +import com.sap.sse.datamining.annotations.Dimension; import com.sap.sse.datamining.annotations.Statistic; public interface HasTrackedLegOfCompetitorContext { @@ -12,6 +13,9 @@ public interface HasTrackedLegOfCompetitorContext { public HasTrackedLegContext getTrackedLegContext(); public TrackedLegOfCompetitor getTrackedLegOfCompetitor(); + + @Dimension(messageKey="CompetitorSearchTag", ordinal=11) // TODO Clean me: Move Dimension to Competitor when possible + public String getCompetitorSearchTag(); @Connector(messageKey="Competitor") public Competitor getCompetitor(); 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 45fb928efee..6c33ea7afb8 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 @@ -35,6 +35,11 @@ public class MarkPassingWithContext implements HasMarkPassingContext { return markPassing.getCompetitor(); } + @Override + public String getCompetitorSearchTag() { + return getCompetitor().getSearchTag(); + } + @Override public Speed getSpeed() { return getTrackedRace().getTrack(getCompetitor()).getEstimatedSpeed(getMarkPassing().getTimePoint()); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceOfCompetitorWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceOfCompetitorWithContext.java index b9d8ca50086..dfcc72ff9a1 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceOfCompetitorWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceOfCompetitorWithContext.java @@ -38,6 +38,11 @@ public class RaceOfCompetitorWithContext implements HasRaceOfCompetitorContext { public Competitor getCompetitor() { return competitor; } + + @Override + public String getCompetitorSearchTag() { + return getCompetitor().getSearchTag(); + } @Override public Distance getDistanceToStartLineAtStart() { diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceResultOfCompetitorWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceResultOfCompetitorWithContext.java index a099ba12d7d..ea72cebd1f2 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceResultOfCompetitorWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/RaceResultOfCompetitorWithContext.java @@ -61,6 +61,11 @@ public class RaceResultOfCompetitorWithContext implements HasRaceResultOfCompeti return competitor; } + @Override + public String getCompetitorSearchTag() { + return getCompetitor().getSearchTag(); + } + @Override public double getRelativeRank() { Leaderboard leaderboard = getLeaderboard(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java index 5df1a9c689b..228ffe31440 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java @@ -35,6 +35,11 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti public Competitor getCompetitor() { return competitor; } + + @Override + public String getCompetitorSearchTag() { + return getCompetitor().getSearchTag(); + } @Override public Distance getDistanceTraveled() { From 65379ea089ad1647a550557682a4b498508fcdbe Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 15 Oct 2016 15:43:03 +0200 Subject: [PATCH 09/11] Implemented statistics for the absolute/relative rank at the end of legs (of competitor) --- .../Sailing_StringMessages.properties | 2 +- .../Sailing_StringMessages_de.properties | 2 +- .../HasRaceResultOfCompetitorContext.java | 2 +- .../HasTrackedLegOfCompetitorContext.java | 6 +++ .../TrackedLegOfCompetitorWithContext.java | 38 +++++++++++++++++-- 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties index b9051747ef9..15a5bcc7e3b 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages.properties @@ -44,7 +44,7 @@ Bft9=Strong gale Bft10=Storm Bft11=Violent storm Bft12=Hurricane -RelativeScoreInRace=Relative score in race (0 best; 1 worst) +RelativeScore=Relative Score (0 best; 1 worst) AbsoluteRank=Absolute Rank WindSpeedInBeaufort=Wind speed in Bft DistanceAtStart=Distance to start at start diff --git a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties index d94720dd689..06683cd4cfe 100644 --- a/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties +++ b/java/com.sap.sailing.datamining/resources/stringmessages/Sailing_StringMessages_de.properties @@ -44,7 +44,7 @@ Bft9=Sturm Bft10=schwerer Sturm Bft11=orkanartiger Sturm Bft12=Orkan -RelativeScoreInRace=Relative Wertung im Rennen (0 am besten; 1 am schlechtesten) +RelativeScore=Relative Wertung (0 am besten; 1 am schlechtesten) AbsoluteRank=Absolute Platzierung WindSpeedInBeaufort=Windgeschwindigkeit in Bft. DistanceAtStart=Distanz zur Startlinie zum Startzeitpunkt diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java index e5e0e4c9fcd..44ce04baa24 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasRaceResultOfCompetitorContext.java @@ -19,7 +19,7 @@ public interface HasRaceResultOfCompetitorContext { /** * 0 means the competitor won the race, 1 means the competitor ranked last */ - @Statistic(messageKey="RelativeScoreInRace", ordinal=1, resultDecimals=2) + @Statistic(messageKey="RelativeScore", ordinal=1, resultDecimals=2) public double getRelativeRank(); @Statistic(messageKey="AbsoluteRank", ordinal=2, resultDecimals=2) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java index fc095c71e24..16dc536da6d 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java @@ -25,5 +25,11 @@ public interface HasTrackedLegOfCompetitorContext { @Statistic(messageKey="RankGainsOrLosses", resultDecimals=2, ordinal=1) public Double getRankGainsOrLosses(); + + @Statistic(messageKey="RelativeScore", resultDecimals=2, ordinal=2) + public Double getRelativeRank(); + + @Statistic(messageKey="AbsoluteRank", resultDecimals=2, ordinal=3) + public Double getAbsoluteRank(); } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java index 228ffe31440..da55d62d031 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java @@ -4,9 +4,11 @@ import com.sap.sailing.datamining.data.HasTrackedLegContext; 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.leaderboard.Leaderboard; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util; public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompetitorContext { @@ -15,6 +17,9 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti private final TrackedLegOfCompetitor trackedLegOfCompetitor; private final Competitor competitor; + private Double rankAtStart; + private Double rankAtFinish; + public TrackedLegOfCompetitorWithContext(HasTrackedLegContext trackedLegContext, TrackedLegOfCompetitor trackedLegOfCompetitor) { this.trackedLegContext = trackedLegContext; this.trackedLegOfCompetitor = trackedLegOfCompetitor; @@ -49,10 +54,35 @@ public class TrackedLegOfCompetitorWithContext implements HasTrackedLegOfCompeti @Override public Double getRankGainsOrLosses() { - TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace(); - Double rankAtStart = Double.valueOf(trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getStartTime())); - Double rankAtFinish = Double.valueOf(trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getFinishTime())); - return rankAtStart - rankAtFinish; + return getRankAtStart() - getRankAtFinish(); + } + + private Double getRankAtStart() { + if (rankAtStart == null) { + TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace(); + rankAtStart = Double.valueOf(trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getStartTime())); + } + return rankAtStart; } + @Override + public Double getRelativeRank() { + Leaderboard leaderboard = getTrackedLegContext().getTrackedRaceContext().getLeaderboardContext().getLeaderboard(); + double competitorCount = Util.size(leaderboard.getCompetitors()); + return getRankAtFinish() / competitorCount; + } + + @Override + public Double getAbsoluteRank() { + return getRankAtFinish(); + } + + private Double getRankAtFinish() { + if (rankAtStart == null) { + TrackedRace trackedRace = getTrackedLegContext().getTrackedRaceContext().getTrackedRace(); + rankAtFinish = Double.valueOf(trackedRace.getRank(getCompetitor(), getTrackedLegOfCompetitor().getFinishTime())); + } + return rankAtFinish; + } + } From 36e18d771ffe469ecc63fa72e5e562811c662190 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 17 Oct 2016 10:28:48 +0200 Subject: [PATCH 10/11] added new TracTrac Javadoc files Change-Id: I3f5aeae42f831b7b97c2d87c2963c3cd1f46b066 --- .../api/event/RaceCompetitorStatusType.html | 439 +++++++++++++++ .../lib/api/event/RaceVisibilityType.html | 523 ++++++++++++++++++ .../javadoc/index-files/index-17.html | 238 ++++++++ .../javadoc/index-files/index-18.html | 188 +++++++ .../javadoc/script.js | 30 + 5 files changed, 1418 insertions(+) create mode 100755 java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/RaceCompetitorStatusType.html create mode 100755 java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/RaceVisibilityType.html create mode 100755 java/com.tractrac.clientmodule/javadoc/index-files/index-17.html create mode 100755 java/com.tractrac.clientmodule/javadoc/index-files/index-18.html create mode 100755 java/com.tractrac.clientmodule/javadoc/script.js diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/RaceCompetitorStatusType.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/RaceCompetitorStatusType.html new file mode 100755 index 00000000000..e906c147cae --- /dev/null +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/RaceCompetitorStatusType.html @@ -0,0 +1,439 @@ + + + + + +RaceCompetitorStatusType + + + + + + + + + + + + +
+
com.tractrac.model.lib.api.event
+

Enum RaceCompetitorStatusType

+
+
+
    +
  • java.lang.Object
  • +
  • + +
  • +
+
+
    +
  • +
    +
    All Implemented Interfaces:
    +
    java.io.Serializable, java.lang.Comparable<RaceCompetitorStatusType>
    +
    +
    +
    +
    public enum RaceCompetitorStatusType
    +extends java.lang.Enum<RaceCompetitorStatusType>
    +
    Enumeration representing all the possible values for the competitor status.
    +
  • +
+
+
+ +
+
+
    +
  • + + + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        values

        +
        public static RaceCompetitorStatusType[] values()
        +
        Returns an array containing the constants of this enum type, in +the order they are declared. This method may be used to iterate +over the constants as follows: +
        +for (RaceCompetitorStatusType c : RaceCompetitorStatusType.values())
        +    System.out.println(c);
        +
        +
        +
        Returns:
        +
        an array containing the constants of this enum type, in the order they are declared
        +
        +
      • +
      + + + +
        +
      • +

        valueOf

        +
        public static RaceCompetitorStatusType valueOf(java.lang.String name)
        +
        Returns the enum constant of this type with the specified name. +The string must match exactly an identifier used to declare an +enum constant in this type. (Extraneous whitespace characters are +not permitted.)
        +
        +
        Parameters:
        +
        name - the name of the enum constant to be returned.
        +
        Returns:
        +
        the enum constant with the specified name
        +
        Throws:
        +
        java.lang.IllegalArgumentException - if this enum type has no constant with the specified name
        +
        java.lang.NullPointerException - if the argument is null
        +
        +
      • +
      + + + +
        +
      • +

        getValue

        +
        public int getValue()
        +
      • +
      + + + + + + + + +
    • +
    +
  • +
+
+
+ + + + + + + diff --git a/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/RaceVisibilityType.html b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/RaceVisibilityType.html new file mode 100755 index 00000000000..c6a263652b9 --- /dev/null +++ b/java/com.tractrac.clientmodule/javadoc/com/tractrac/model/lib/api/event/RaceVisibilityType.html @@ -0,0 +1,523 @@ + + + + + +RaceVisibilityType + + + + + + + + + + + + +
+
com.tractrac.model.lib.api.event
+

Enum RaceVisibilityType

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • java.lang.Enum<RaceVisibilityType>
    • +
    • +
        +
      • com.tractrac.model.lib.api.event.RaceVisibilityType
      • +
      +
    • +
    +
  • +
+
+
    +
  • +
    +
    All Implemented Interfaces:
    +
    java.io.Serializable, java.lang.Comparable<RaceVisibilityType>
    +
    +
    +
    +
    public enum RaceVisibilityType
    +extends java.lang.Enum<RaceVisibilityType>
    +
    Values for race visitility.
    +
  • +
+
+
+ +
+
+
    +
  • + + + + + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        values

        +
        public static RaceVisibilityType[] values()
        +
        Returns an array containing the constants of this enum type, in +the order they are declared. This method may be used to iterate +over the constants as follows: +
        +for (RaceVisibilityType c : RaceVisibilityType.values())
        +    System.out.println(c);
        +
        +
        +
        Returns:
        +
        an array containing the constants of this enum type, in the order they are declared
        +
        +
      • +
      + + + +
        +
      • +

        valueOf

        +
        public static RaceVisibilityType valueOf(java.lang.String name)
        +
        Returns the enum constant of this type with the specified name. +The string must match exactly an identifier used to declare an +enum constant in this type. (Extraneous whitespace characters are +not permitted.)
        +
        +
        Parameters:
        +
        name - the name of the enum constant to be returned.
        +
        Returns:
        +
        the enum constant with the specified name
        +
        Throws:
        +
        java.lang.IllegalArgumentException - if this enum type has no constant with the specified name
        +
        java.lang.NullPointerException - if the argument is null
        +
        +
      • +
      + + + +
        +
      • +

        getValue

        +
        public int getValue()
        +
      • +
      + + + + + + + +
        +
      • +

        fromString

        +
        public static RaceVisibilityType fromString(java.lang.String status)
        +
      • +
      +
    • +
    +
  • +
+
+
+ + + + + + + diff --git a/java/com.tractrac.clientmodule/javadoc/index-files/index-17.html b/java/com.tractrac.clientmodule/javadoc/index-files/index-17.html new file mode 100755 index 00000000000..d312d292644 --- /dev/null +++ b/java/com.tractrac.clientmodule/javadoc/index-files/index-17.html @@ -0,0 +1,238 @@ + + + + + +U-Index + + + + + + + + +
+ + + + + + + +
+ + +
A B C D E F G H I L M N O R S T U V  + + +

U

+
+
unsubscribeCompetitors(ICompetitorsListener) - Method in interface com.tractrac.subscription.lib.api.IEventSubscriber
+
+
+ Unsubscribes the competitors subscribers +
+
+
unsubscribeConnectionStatus(IConnectionStatusListener) - Method in interface com.tractrac.subscription.lib.api.ISubscriber
+
+
Unsubscribes for connection status
+
+
unsubscribeControlPassings(IControlPassingsListener) - Method in interface com.tractrac.subscription.lib.api.IRaceSubscriber
+
+
Unsubscribes to control passing data for the specified race.
+
+
unsubscribeControlPositions(IControlPointPositionListener) - Method in interface com.tractrac.subscription.lib.api.IRaceSubscriber
+
+
Unsubscribes to control positions.
+
+
unsubscribeControls(IControlsListener) - Method in interface com.tractrac.subscription.lib.api.IEventSubscriber
+
+
+ Unsubscribes the controls subscribers +
+
+
unsubscribeEventMessages(IEventMessageListener) - Method in interface com.tractrac.subscription.lib.api.IEventSubscriber
+
+
Unsubscribes to event messages.
+
+
unsubscribeEventTimesChanges(IStartStopTimesChangeListener) - Method in interface com.tractrac.subscription.lib.api.IEventSubscriber
+
+
Unsubscribes to changes in event start and stop times.
+
+
unsubscribePositions(IPositionListener) - Method in interface com.tractrac.subscription.lib.api.IRaceSubscriber
+
+
Unsubscribes to competitor positions for a given Race.
+
+
unsubscribePositionsOffset(IPositionOffsetListener) - Method in interface com.tractrac.subscription.lib.api.IRaceSubscriber
+
+
Unsubscribes to competitor positions for a given Race.
+
+
unsubscribePositionsSnapped(IPositionSnappedListener) - Method in interface com.tractrac.subscription.lib.api.IRaceSubscriber
+
+
Unsubscribes to competitor positions for a given Race.
+
+
unsubscribeRaceCompetitor(IRaceCompetitorListener) - Method in interface com.tractrac.subscription.lib.api.IRaceSubscriber
+
+
Unsubscribes to race competitor
+
+
unsubscribeRaceMessages(IRaceMessageListener) - Method in interface com.tractrac.subscription.lib.api.IRaceSubscriber
+
+
Unsubscribes to race messages
+
+
unsubscribeRaces(IRacesListener) - Method in interface com.tractrac.subscription.lib.api.IEventSubscriber
+
+
+ Unsubscribes the races subscribers +
+
+
unsubscribeRaceTimesChanges(IRaceStartStopTimesChangeListener) - Method in interface com.tractrac.subscription.lib.api.IRaceSubscriber
+
+
Unsubscribes to changes in race start and stop times.
+
+
unsubscribeRouteChanges(IControlRouteChangeListener) - Method in interface com.tractrac.subscription.lib.api.IRaceSubscriber
+
+
Unsubscribes to route changes for a given Race.
+
+
unsubscribeRoutes(IRoutesListener) - Method in interface com.tractrac.subscription.lib.api.IRaceSubscriber
+
+
+ Unsubscribes to route changes for a given Race.
+
+
unsubscribeServerTime(IServerTimeListener) - Method in interface com.tractrac.subscription.lib.api.IEventSubscriber
+
+
Unsubscribes to messages for the server time.
+
+
UPCOMING_STR - Static variable in enum com.tractrac.model.lib.api.event.RaceVisibilityType
+
 
+
updateCompetitor(ICompetitor) - Method in interface com.tractrac.model.lib.api.event.IEvent
+
+
Update a competitor
+
+
updateCompetitor(ICompetitor) - Method in interface com.tractrac.subscription.lib.api.competitor.ICompetitorsListener
+
+
This event is thrown when a competitor is updated.
+
+
updateControl(IControl) - Method in interface com.tractrac.model.lib.api.event.IEvent
+
+
Update a control
+
+
updateControl(IControl) - Method in interface com.tractrac.subscription.lib.api.control.IControlsListener
+
+
This event is thrown when a control is updated.
+
+
updateRace(IRace) - Method in interface com.tractrac.model.lib.api.event.IEvent
+
+
Update a race
+
+
updateRace(IRace) - Method in interface com.tractrac.subscription.lib.api.race.IRacesListener
+
+
This event is thrown when a race is updated.
+
+
updateRaceCompetitor(IRaceCompetitor) - Method in interface com.tractrac.model.lib.api.event.IRace
+
+
Updates a race competitor
+
+
updateRaceCompetitor(IRaceCompetitor) - Method in interface com.tractrac.subscription.lib.api.race.IRaceCompetitorListener
+
+
This event is thrown when a race competitor is updated
+
+
updateRoute(IRoute) - Method in interface com.tractrac.subscription.lib.api.route.IRoutesListener
+
+
This event is thrown when a route is updated.
+
+
+A B C D E F G H I L M N O R S T U V 
+ +
+ + + + + + + +
+ + + + diff --git a/java/com.tractrac.clientmodule/javadoc/index-files/index-18.html b/java/com.tractrac.clientmodule/javadoc/index-files/index-18.html new file mode 100755 index 00000000000..ecf8f983fbd --- /dev/null +++ b/java/com.tractrac.clientmodule/javadoc/index-files/index-18.html @@ -0,0 +1,188 @@ + + + + + +V-Index + + + + + + + + +
+ + + + + + + +
+ + +
A B C D E F G H I L M N O R S T U V  + + +

V

+
+
valueOf(String) - Static method in enum com.tractrac.model.lib.api.event.EventType
+
+
Returns the enum constant of this type with the specified name.
+
+
valueOf(String) - Static method in enum com.tractrac.model.lib.api.event.RaceCompetitorStatusType
+
+
Returns the enum constant of this type with the specified name.
+
+
valueOf(String) - Static method in enum com.tractrac.model.lib.api.event.RaceStatusType
+
+
Returns the enum constant of this type with the specified name.
+
+
valueOf(String) - Static method in enum com.tractrac.model.lib.api.event.RaceVisibilityType
+
+
Returns the enum constant of this type with the specified name.
+
+
valueOf(String) - Static method in enum com.tractrac.model.lib.api.event.StartTimeType
+
+
Returns the enum constant of this type with the specified name.
+
+
valueOf(String) - Static method in enum com.tractrac.subscription.lib.api.event.ILiveDataEvent.StatusType
+
+
Returns the enum constant of this type with the specified name.
+
+
valueOf(String) - Static method in enum com.tractrac.subscription.lib.api.event.IStoredDataEvent.Type
+
+
Returns the enum constant of this type with the specified name.
+
+
values() - Static method in enum com.tractrac.model.lib.api.event.EventType
+
+
Returns an array containing the constants of this enum type, in +the order they are declared.
+
+
values() - Static method in enum com.tractrac.model.lib.api.event.RaceCompetitorStatusType
+
+
Returns an array containing the constants of this enum type, in +the order they are declared.
+
+
values() - Static method in enum com.tractrac.model.lib.api.event.RaceStatusType
+
+
Returns an array containing the constants of this enum type, in +the order they are declared.
+
+
values() - Static method in enum com.tractrac.model.lib.api.event.RaceVisibilityType
+
+
Returns an array containing the constants of this enum type, in +the order they are declared.
+
+
values() - Static method in enum com.tractrac.model.lib.api.event.StartTimeType
+
+
Returns an array containing the constants of this enum type, in +the order they are declared.
+
+
values() - Static method in enum com.tractrac.subscription.lib.api.event.ILiveDataEvent.StatusType
+
+
Returns an array containing the constants of this enum type, in +the order they are declared.
+
+
values() - Static method in enum com.tractrac.subscription.lib.api.event.IStoredDataEvent.Type
+
+
Returns an array containing the constants of this enum type, in +the order they are declared.
+
+
+A B C D E F G H I L M N O R S T U V 
+ +
+ + + + + + + +
+ + + + diff --git a/java/com.tractrac.clientmodule/javadoc/script.js b/java/com.tractrac.clientmodule/javadoc/script.js new file mode 100755 index 00000000000..b3463569314 --- /dev/null +++ b/java/com.tractrac.clientmodule/javadoc/script.js @@ -0,0 +1,30 @@ +function show(type) +{ + count = 0; + for (var key in methods) { + var row = document.getElementById(key); + if ((methods[key] & type) != 0) { + row.style.display = ''; + row.className = (count++ % 2) ? rowColor : altColor; + } + else + row.style.display = 'none'; + } + updateTabs(type); +} + +function updateTabs(type) +{ + for (var value in tabs) { + var sNode = document.getElementById(tabs[value][0]); + var spanNode = sNode.firstChild; + if (value == type) { + sNode.className = activeTableTab; + spanNode.innerHTML = tabs[value][1]; + } + else { + sNode.className = tableTab; + spanNode.innerHTML = "" + tabs[value][1] + ""; + } + } +} From 315043bca11e0dcce99235f578da8c06a3ce4c93 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Mon, 17 Oct 2016 11:40:04 +0200 Subject: [PATCH 11/11] using Lambdas for more compact code; some formatting adjustments Change-Id: I2666f1797ab71e72b81188dc2103fe19265fa2c8 --- .../server/impl/RemoteSailingServerSet.java | 57 ++++++------------- 1 file changed, 17 insertions(+), 40 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RemoteSailingServerSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RemoteSailingServerSet.java index 915554f9f8e..13275a35242 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RemoteSailingServerSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RemoteSailingServerSet.java @@ -74,34 +74,23 @@ public class RemoteSailingServerSet { } public void clear() { - LockUtil.executeWithWriteLock(lock, new Runnable() { - @Override - public void run() { - remoteSailingServers.clear(); - cachedEventsForRemoteSailingServers.clear(); - } + LockUtil.executeWithWriteLock(lock, () -> { + remoteSailingServers.clear(); + cachedEventsForRemoteSailingServers.clear(); }); } public void add(RemoteSailingServerReference remoteSailingServerReference) { - LockUtil.executeWithWriteLock(lock, new Runnable() { - - @Override - public void run() { - remoteSailingServers.put(remoteSailingServerReference.getName(), remoteSailingServerReference); - triggerAsynchronousEventCacheUpdate(remoteSailingServerReference); - } + LockUtil.executeWithWriteLock(lock, () -> { + remoteSailingServers.put(remoteSailingServerReference.getName(), remoteSailingServerReference); + triggerAsynchronousEventCacheUpdate(remoteSailingServerReference); }); } private void updateRemoteSailingServerReferenceEventCaches() { - LockUtil.executeWithReadLock(lock, new Runnable() { - - @Override - public void run() { - for (RemoteSailingServerReference ref : remoteSailingServers.values()) { - triggerAsynchronousEventCacheUpdate(ref); - } + LockUtil.executeWithReadLock(lock, () -> { + for (RemoteSailingServerReference ref : remoteSailingServers.values()) { + triggerAsynchronousEventCacheUpdate(ref); } }); } @@ -115,12 +104,7 @@ public class RemoteSailingServerSet { } private void triggerAsynchronousEventCacheUpdate(final RemoteSailingServerReference ref) { - new Thread("Event Cache Updater for remote server " + ref) { - @Override - public void run() { - updateRemoteServerEventCacheSynchronously(ref); - } - }.start(); + new Thread(() -> updateRemoteServerEventCacheSynchronously(ref), "Event Cache Updater for remote server " + ref).start(); } private Util.Pair, Exception> updateRemoteServerEventCacheSynchronously( @@ -156,19 +140,13 @@ public class RemoteSailingServerSet { e); result = new Util.Pair, Exception>(/* events */ null, e); } - final Pair, Exception> finalResult = result; - - LockUtil.executeWithWriteLock(lock, new Runnable() { - - @Override - public void run() { - // check that the server was not removed while no lock was held - if (remoteSailingServers.containsValue(ref)) { - cachedEventsForRemoteSailingServers.put(ref, finalResult); - }else{ - logger.fine("Omitted update for " + ref + " as it was removed"); - } + LockUtil.executeWithWriteLock(lock, () -> { + // check that the server was not removed while no lock was held + if (remoteSailingServers.containsValue(ref)) { + cachedEventsForRemoteSailingServers.put(ref, finalResult); + } else { + logger.fine("Omitted update for " + ref + " as it was removed"); } }); return result; @@ -225,8 +203,7 @@ public class RemoteSailingServerSet { List result = new ArrayList<>(); LockUtil.lockForRead(lock); try { - for (Map.Entry, Exception>> e : cachedEventsForRemoteSailingServers - .entrySet()) { + for (Map.Entry, Exception>> e : cachedEventsForRemoteSailingServers.entrySet()) { if (e.getValue().getB() == null) { // no exception; reference considered live result.add(e.getKey());