From e19209a61cba29341e4dc1790991b1a28fac2920 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 24 Apr 2014 19:13:05 +0200 Subject: [PATCH] in addition to the race column names for which to load details, added a parameter addOverallDetails that controls whether a leaderboardDTO shall have overall details; the leaderboard cache and the LiveLeaderboardUpdater consider this parameter in how they cache their DTOs. --- .../domain/test/LeaderboardOfflineTest.java | 12 ++-- .../domain/leaderboard/Leaderboard.java | 8 ++- .../caching/LeaderboardDTOCache.java | 33 ++++++---- .../caching/LiveLeaderboardUpdater.java | 64 ++++++++++++++----- .../impl/AbstractSimpleLeaderboardImpl.java | 23 ++++--- .../ui/test/GwtTestCaseColumnToggling.java | 2 +- .../gwt/ui/test/TestColumnSwapping.java | 4 +- .../actions/GetLeaderboardByNameAction.java | 13 ++-- .../sailing/gwt/ui/client/SailingService.java | 3 +- .../gwt/ui/client/SailingServiceAsync.java | 2 +- .../gwt/ui/leaderboard/LeaderboardPanel.java | 13 ++-- .../gwt/ui/server/SailingServiceImpl.java | 10 +-- .../jaxrs/api/LeaderboardsResource.java | 2 +- 13 files changed, 118 insertions(+), 71 deletions(-) diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardOfflineTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardOfflineTest.java index 4df7ca3ee3b..dc4dfba57e4 100755 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardOfflineTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardOfflineTest.java @@ -148,17 +148,17 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest { InterruptedException { } }; - LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO(now, emptySet, trackedRegattaRegistry, DomainFactory.INSTANCE); + LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO(now, emptySet, /* addOverallDetails */ true, trackedRegattaRegistry, DomainFactory.INSTANCE); assertNotNull(leaderboardDTO); - assertSame(leaderboardDTO, leaderboard.getLeaderboardDTO(now, emptySet, trackedRegattaRegistry, DomainFactory.INSTANCE)); // assert it's cached + assertSame(leaderboardDTO, leaderboard.getLeaderboardDTO(now, emptySet, /* addOverallDetails */ true, trackedRegattaRegistry, DomainFactory.INSTANCE)); // assert it's cached leaderboard.getRaceColumnByName(columnName).releaseTrackedRace(defaultFleet); // this should clear the cache - LeaderboardDTO leaderboardDTO2 = leaderboard.getLeaderboardDTO(now, emptySet, trackedRegattaRegistry, DomainFactory.INSTANCE); + LeaderboardDTO leaderboardDTO2 = leaderboard.getLeaderboardDTO(now, emptySet, /* addOverallDetails */ true, trackedRegattaRegistry, DomainFactory.INSTANCE); assertNotSame(leaderboardDTO, leaderboardDTO2); - assertSame(leaderboardDTO2, leaderboard.getLeaderboardDTO(now, emptySet, trackedRegattaRegistry, DomainFactory.INSTANCE)); // and cached again + assertSame(leaderboardDTO2, leaderboard.getLeaderboardDTO(now, emptySet, /* addOverallDetails */ true, trackedRegattaRegistry, DomainFactory.INSTANCE)); // and cached again leaderboard.getRaceColumnByName(columnName).setTrackedRace(defaultFleet, testRaces.iterator().next()); // clear cache again; requires listener(s) to still be attached - LeaderboardDTO leaderboardDTO3 = leaderboard.getLeaderboardDTO(now, emptySet, trackedRegattaRegistry, DomainFactory.INSTANCE); + LeaderboardDTO leaderboardDTO3 = leaderboard.getLeaderboardDTO(now, emptySet, /* addOverallDetails */ true, trackedRegattaRegistry, DomainFactory.INSTANCE); assertNotSame(leaderboardDTO2, leaderboardDTO3); - assertSame(leaderboardDTO3, leaderboard.getLeaderboardDTO(now, emptySet, trackedRegattaRegistry, DomainFactory.INSTANCE)); // and cached again + assertSame(leaderboardDTO3, leaderboard.getLeaderboardDTO(now, emptySet, /* addOverallDetails */ true, trackedRegattaRegistry, DomainFactory.INSTANCE)); // and cached again } @Test diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java index bb5a741eefc..9e968758d4c 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java @@ -71,8 +71,9 @@ public interface Leaderboard extends Named { } LeaderboardDTO computeDTO(final TimePoint timePoint, - final Collection namesOfRaceColumnsForWhichToLoadLegDetails, final boolean waitForLatestAnalyses, TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) - throws NoWindException; + final Collection namesOfRaceColumnsForWhichToLoadLegDetails, boolean addOverallDetails, + final boolean waitForLatestAnalyses, TrackedRegattaRegistry trackedRegattaRegistry, + DomainFactory baseDomainFactory) throws NoWindException; /** * Obtains the unique set of {@link Competitor} objects from all {@link TrackedRace}s currently linked to this @@ -452,6 +453,7 @@ public interface Leaderboard extends Named { * point at which to evaluate the leaderboard status * @param namesOfRaceColumnsForWhichToLoadLegDetails * the names of the race columns of which to expand the details in the result + * @param addOverallDetails TODO * @param trackedRegattaRegistry * used to determine which of the races are still being tracked and which ones are not * @param baseDomainFactory @@ -459,7 +461,7 @@ public interface Leaderboard extends Named { */ LeaderboardDTO getLeaderboardDTO(TimePoint timePoint, Collection namesOfRaceColumnsForWhichToLoadLegDetails, - TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) throws NoWindException, + boolean addOverallDetails, TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) throws NoWindException, InterruptedException, ExecutionException; NumberOfCompetitorsInLeaderboardFetcher getNumberOfCompetitorsInLeaderboardFetcher(); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCache.java index af722f75216..3190c45bf84 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCache.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCache.java @@ -19,8 +19,7 @@ import com.sap.sailing.domain.base.RaceColumnListener; import com.sap.sailing.domain.common.NoWindException; import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.dto.LeaderboardDTO; -import com.sap.sailing.domain.common.impl.Util; -import com.sap.sailing.domain.common.impl.Util.Pair; +import com.sap.sailing.domain.common.impl.Util.Triple; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardCacheManager; import com.sap.sailing.domain.leaderboard.ScoreCorrection; @@ -47,13 +46,15 @@ public class LeaderboardDTOCache implements LeaderboardCache { private static final Logger logger = Logger.getLogger(LeaderboardDTOCache.class.getName()); /** - * In live operations, {@link #getLeaderboardByName(Date, Collection, DomainFactory, TrackedRegattaRegistry)} is the application's + * In live operations, {@link #getLeaderboardByName(Date, Collection, boolean, DomainFactory, TrackedRegattaRegistry)} is the application's * bottleneck. When two clients ask the same data for the same leaderboard with their * waitForLatestAnalyses parameters set to false, expansion state and (quantized) time * stamp, no two computations should be spawned for the two clients. Instead, if the computation is still running, - * all clients asking the same wait for the single result. Results are cached in this LRU-based evicting cache. + * all clients asking the same wait for the single result. Results are cached in this LRU-based evicting cache. The key is + * the time point for the query, the names of the races for which details are requested and the flag telling + * whether overall details for the leaderboard are requested. */ - private final Map>, FutureTask> leaderboardCache; + private final Map, Boolean>, FutureTask> leaderboardCache; private final NamedReentrantReadWriteLock leaderboardCacheLock; private int leaderboardByNameCacheHitCount; private int leaderboardByNameCacheMissCount; @@ -83,10 +84,10 @@ public class LeaderboardDTOCache implements LeaderboardCache { this.leaderboard = leaderboard; this.waitForLatestAnalyses = waitForLatestAnalyses; // Note: don't use access-based ordering as it turns the get(...) call into a "write" access - this.leaderboardCache = new LinkedHashMap>, FutureTask>(16, 0.75f) { + this.leaderboardCache = new LinkedHashMap, Boolean>, FutureTask>(16, 0.75f) { private static final long serialVersionUID = 7287916997229815039L; @Override - protected boolean removeEldestEntry(Map.Entry>, FutureTask> e) { + protected boolean removeEldestEntry(Map.Entry, Boolean>, FutureTask> e) { return size() > 10; // remember 10 LeaderboardDTOs per leaderborad } }; @@ -118,10 +119,14 @@ public class LeaderboardDTOCache implements LeaderboardCache { * The {@link #waitForLatestAnalyses} field is passed on to * {@link SailingServiceImpl#computeLeaderboardByName(Leaderboard, TimePoint, Collection, boolean)} if a new cache * entry needs to be computed. Caching distinguished between + * + * @param addOverallDetails + * tells whether the columns containing the overall details shall be added */ - public LeaderboardDTO getLeaderboardByName(final TimePoint timePoint, final Collection namesOfRaceColumnsForWhichToLoadLegDetails, - final DomainFactory baseDomainFactory, final TrackedRegattaRegistry trackedRegattaRegistry) throws NoWindException, InterruptedException, - ExecutionException { + public LeaderboardDTO getLeaderboardByName(final TimePoint timePoint, + final Collection namesOfRaceColumnsForWhichToLoadLegDetails, final boolean addOverallDetails, + final DomainFactory baseDomainFactory, final TrackedRegattaRegistry trackedRegattaRegistry) + throws NoWindException, InterruptedException, ExecutionException { long startOfRequestHandling = System.currentTimeMillis(); final TimePoint adjustedTimePoint; TimePoint timePointOfLastModification = leaderboard.getTimePointOfLatestModification(); @@ -131,8 +136,8 @@ public class LeaderboardDTOCache implements LeaderboardCache { } else { adjustedTimePoint = timePoint; } - Util.Pair> key = new Util.Pair>(adjustedTimePoint, - namesOfRaceColumnsForWhichToLoadLegDetails); + Triple, Boolean> key = new Triple, Boolean>(adjustedTimePoint, + namesOfRaceColumnsForWhichToLoadLegDetails, addOverallDetails); FutureTask future = null; boolean cacheHit = false; /* @@ -161,8 +166,8 @@ public class LeaderboardDTOCache implements LeaderboardCache { LockUtil.propagateLockSetFrom(callerThread); try { LeaderboardDTO result = leaderboard.computeDTO(adjustedTimePoint, - namesOfRaceColumnsForWhichToLoadLegDetails, waitForLatestAnalyses, - trackedRegattaRegistry, baseDomainFactory); + namesOfRaceColumnsForWhichToLoadLegDetails, addOverallDetails, + waitForLatestAnalyses, trackedRegattaRegistry, baseDomainFactory); return result; } finally { LockUtil.unpropagateLockSetFrom(callerThread); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java index 266aa1093a7..a2daad31a2b 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LiveLeaderboardUpdater.java @@ -71,11 +71,13 @@ public class LiveLeaderboardUpdater implements Runnable { */ private final Set columnNamesForWhichCurrentLiveLeaderboardHasTheDetails; + private boolean currentLiveLeaderboardHasOverallDetails; + private boolean running; /** * For each String from namesOfRaceColumnsForWhichToLoadLegDetails passed to - * {@link #getLiveLeaderboard(Collection)}, records the validity time point of the last request here when the + * {@link #getLiveLeaderboard(Collection, boolean)}, records the validity time point of the last request here when the * {@link #currentLiveLeaderboard} has been updated with results containing this column details. This updater will * stop computing the details for that column if the validity time for the update calculation is more than * {@link #UPDATE_TIMEOUT_IN_MILLIS} milliseconds after the time point recorded here. @@ -84,7 +86,12 @@ public class LiveLeaderboardUpdater implements Runnable { private final Map timePointOfLastRequestForColumnDetails; /** - * As soon as the first {@link #getLiveLeaderboard(Collection)} request has been received, this field tells the + * Tells when {@link #updateRequestTimes(Collection, boolean)} was last called with the request for overall details + */ + private TimePoint timePointOfLastRequestForOverallDetails; + + /** + * As soon as the first {@link #getLiveLeaderboard(Collection, boolean)} request has been received, this field tells the * "validity time point" (as opposed to the request time point; so not when the request was received but for which * time point the request was asking the data) for which the last general request asked the leaderboard contents, * regardless the combination of column details requested. This is used to decide when to stop a thread running this @@ -117,14 +124,15 @@ public class LiveLeaderboardUpdater implements Runnable { return leaderboard; } - public LeaderboardDTO getLiveLeaderboard(Collection namesOfRaceColumnsForWhichToLoadLegDetails) throws NoWindException { + public LeaderboardDTO getLiveLeaderboard(Collection namesOfRaceColumnsForWhichToLoadLegDetails, boolean addOverallDetails) throws NoWindException { LeaderboardDTO result = null; - updateRequestTimes(namesOfRaceColumnsForWhichToLoadLegDetails); + updateRequestTimes(namesOfRaceColumnsForWhichToLoadLegDetails, addOverallDetails); ensureRunning(); synchronized (this) { if (running && columnNamesForWhichCurrentLiveLeaderboardHasTheDetails - .containsAll(namesOfRaceColumnsForWhichToLoadLegDetails)) { + .containsAll(namesOfRaceColumnsForWhichToLoadLegDetails) + && (!addOverallDetails || currentLiveLeaderboardHasOverallDetails)) { result = currentLiveLeaderboard; if (result != null) { cacheHitCount++; @@ -140,12 +148,13 @@ public class LiveLeaderboardUpdater implements Runnable { cacheMissCount++; synchronized (this) { while (result == null) { - if (columnNamesForWhichCurrentLiveLeaderboardHasTheDetails.containsAll(namesOfRaceColumnsForWhichToLoadLegDetails)) { + if (columnNamesForWhichCurrentLiveLeaderboardHasTheDetails.containsAll(namesOfRaceColumnsForWhichToLoadLegDetails) && + (!addOverallDetails || currentLiveLeaderboardHasOverallDetails)) { result = currentLiveLeaderboard; } if (result == null) { if (logger.isLoggable(Level.FINEST)) { - logger.finest("waiting for leaderboard for "+namesOfRaceColumnsForWhichToLoadLegDetails); + logger.finest("waiting for leaderboard for "+namesOfRaceColumnsForWhichToLoadLegDetails+" and addOverallDetails="+addOverallDetails); } ensureRunning(); try { @@ -153,26 +162,27 @@ public class LiveLeaderboardUpdater implements Runnable { } catch (InterruptedException e) { logger.log(Level.INFO, "interrupted while waiting for LiveLeaderboardCache update", e); } - if (columnNamesForWhichCurrentLiveLeaderboardHasTheDetails.containsAll(namesOfRaceColumnsForWhichToLoadLegDetails)) { + if (columnNamesForWhichCurrentLiveLeaderboardHasTheDetails.containsAll(namesOfRaceColumnsForWhichToLoadLegDetails) && + (!addOverallDetails || currentLiveLeaderboardHasOverallDetails)) { result = currentLiveLeaderboard; if (logger.isLoggable(Level.FINEST)) { - logger.finest("successfully waited for leaderboard for "+namesOfRaceColumnsForWhichToLoadLegDetails); + logger.finest("successfully waited for leaderboard for "+namesOfRaceColumnsForWhichToLoadLegDetails+" and addOverallDetails="+addOverallDetails); } } else { if (logger.isLoggable(Level.FINEST)) { - logger.finest("waiting for leaderboard for "+namesOfRaceColumnsForWhichToLoadLegDetails+" unsuccessful. Need to try again..."); + logger.finest("waiting for leaderboard for "+namesOfRaceColumnsForWhichToLoadLegDetails+" and addOverallDetails="+addOverallDetails+" unsuccessful. Need to try again..."); } } } else { if (logger.isLoggable(Level.FINEST)) { - logger.finest("leaderboard for "+namesOfRaceColumnsForWhichToLoadLegDetails+" was provided in the meantime"); + logger.finest("leaderboard for "+namesOfRaceColumnsForWhichToLoadLegDetails+" and addOverallDetails="+addOverallDetails+" was provided in the meantime"); } } // now we either have a result (good, we're done), or the thread stopped running (then we need to renew the request) // or the thread still runs but the result may have expired and therefore be null (renew the request) if (result == null) { // need to renew the request - updateRequestTimes(namesOfRaceColumnsForWhichToLoadLegDetails); + updateRequestTimes(namesOfRaceColumnsForWhichToLoadLegDetails, addOverallDetails); ensureRunning(); } } @@ -205,8 +215,11 @@ public class LiveLeaderboardUpdater implements Runnable { * * This method assumes that namesOfRaceColumnsForWhichToLoadLegDetails tells the column names for which * result has the details. + * + * @param addOverallDetails tells whether overall details are requested for the resulting leaderboard; see also + * {@link Leaderboard#computeDTO(TimePoint, Collection, boolean, boolean, TrackedRegattaRegistry, DomainFactory)}. */ - private synchronized void updateRequestTimes(Collection namesOfRaceColumnsForWhichToLoadLegDetails) { + private synchronized void updateRequestTimes(Collection namesOfRaceColumnsForWhichToLoadLegDetails, boolean addOverallDetails) { lastRequest = getLeaderboard().getNowMinusDelay(); for (String nameOfRaceColumn : namesOfRaceColumnsForWhichToLoadLegDetails) { if (!timePointOfLastRequestForColumnDetails.containsKey(nameOfRaceColumn) || @@ -214,6 +227,9 @@ public class LiveLeaderboardUpdater implements Runnable { timePointOfLastRequestForColumnDetails.put(nameOfRaceColumn, lastRequest); } } + if (addOverallDetails && timePointOfLastRequestForOverallDetails != null && lastRequest.after(timePointOfLastRequestForOverallDetails)) { + timePointOfLastRequestForOverallDetails = lastRequest; + } } /** @@ -228,8 +244,10 @@ public class LiveLeaderboardUpdater implements Runnable { } /** - * Keeps computing the leaderboard for the column names that appear as key in {@link #timePointOfLastRequestForColumnDetails} - * until no request has happened + * Keeps computing the leaderboard for the column names that appear as key in + * {@link #timePointOfLastRequestForColumnDetails} and for the overall details as noted in + * {@link #timePointOfLastRequestForOverallDetails} until no request has happened during the + * {@link #UPDATE_TIMEOUT_IN_MILLIS timeout period}. */ @Override public void run() { @@ -253,9 +271,10 @@ public class LiveLeaderboardUpdater implements Runnable { TimePoint timeLastUpdateWasStarted = now; try { final Set namesOfRaceColumnsForWhichToLoadLegDetails = getColumnNamesForWhichToFetchDetails(timePoint); + final boolean addOverallDetails = getOverallDetails(timePoint); LeaderboardDTO newCacheValue = leaderboard.computeDTO(timePoint, - namesOfRaceColumnsForWhichToLoadLegDetails, /* waitForLatestAnalyses */false, - trackedRegattaRegistry, baseDomainFactory); + namesOfRaceColumnsForWhichToLoadLegDetails, addOverallDetails, + /* waitForLatestAnalyses */false, trackedRegattaRegistry, baseDomainFactory); updateCacheContents(namesOfRaceColumnsForWhichToLoadLegDetails, newCacheValue); } catch (NoWindException e) { logger.info("Unable to update cached leaderboard results for leaderboard " + leaderboard.getName() + ": " @@ -290,6 +309,17 @@ public class LiveLeaderboardUpdater implements Runnable { } } + /** + * Determines based on {@link #timePointOfLastRequestForOverallDetails} and the timePoint parameter + * if the duration between then is less than {@link #UPDATE_TIMEOUT_IN_MILLIS} in which case overall details are to + * be loaded. If {@link #timePointOfLastRequestForOverallDetails} is null, meaning that overall details + * have never been requested for the leaderboard before, false is returned immediately. + */ + private boolean getOverallDetails(TimePoint timePoint) { + return timePointOfLastRequestForOverallDetails != null && + !timePoint.after(timePointOfLastRequestForOverallDetails.plus(UPDATE_TIMEOUT_IN_MILLIS)); + } + /** * Determines those column names from {@link #timePointOfLastRequestForColumnDetails}'s keys for which the last * request is less then {@link #UPDATE_TIMEOUT_IN_MILLIS} milliseconds before timePoint diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java index a4d7f958c30..f81cead3a64 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java @@ -1103,8 +1103,8 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race @Override public LeaderboardDTO computeDTO(final TimePoint timePoint, - final Collection namesOfRaceColumnsForWhichToLoadLegDetails, final boolean waitForLatestAnalyses, - TrackedRegattaRegistry trackedRegattaRegistry, final DomainFactory baseDomainFactory) + final Collection namesOfRaceColumnsForWhichToLoadLegDetails, boolean addOverallDetails, + final boolean waitForLatestAnalyses, TrackedRegattaRegistry trackedRegattaRegistry, final DomainFactory baseDomainFactory) throws NoWindException { long startOfRequestHandling = System.currentTimeMillis(); LeaderboardDTO result = null; @@ -1241,8 +1241,9 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race result.competitorDisplayNames.put(competitorDTO, displayName); } } - logger.info("computeLeaderboardByName("+this.getName()+", "+timePoint+", "+namesOfRaceColumnsForWhichToLoadLegDetails+") took "+ - (System.currentTimeMillis()-startOfRequestHandling)+"ms"); + logger.info("computeLeaderboardByName(" + this.getName() + ", " + timePoint + ", " + + namesOfRaceColumnsForWhichToLoadLegDetails + ", addOverallDetails=" + addOverallDetails + ") took " + + (System.currentTimeMillis() - startOfRequestHandling) + "ms"); return result; } @@ -1637,10 +1638,10 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race } private LeaderboardDTO getLiveLeaderboard(Collection namesOfRaceColumnsForWhichToLoadLegDetails, - TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) throws NoWindException { + boolean addOverallDetails, TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) throws NoWindException { LiveLeaderboardUpdater liveLeaderboardUpdater = getLiveLeaderboardUpdater(trackedRegattaRegistry, baseDomainFactory); - return liveLeaderboardUpdater.getLiveLeaderboard(namesOfRaceColumnsForWhichToLoadLegDetails); + return liveLeaderboardUpdater.getLiveLeaderboard(namesOfRaceColumnsForWhichToLoadLegDetails, addOverallDetails); } private LiveLeaderboardUpdater getLiveLeaderboardUpdater(TrackedRegattaRegistry trackedRegattaRegistry, @@ -1677,8 +1678,10 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race } @Override - public LeaderboardDTO getLeaderboardDTO(TimePoint timePoint, Collection namesOfRaceColumnsForWhichToLoadLegDetails, - TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) throws NoWindException, InterruptedException, ExecutionException { + public LeaderboardDTO getLeaderboardDTO(TimePoint timePoint, + Collection namesOfRaceColumnsForWhichToLoadLegDetails, boolean addOverallDetails, + TrackedRegattaRegistry trackedRegattaRegistry, DomainFactory baseDomainFactory) throws NoWindException, + InterruptedException, ExecutionException { LeaderboardDTO result = null; if (timePoint == null) { // date==null means live mode; however, if we're after the end of all races and after all score @@ -1694,7 +1697,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race } else { // don't use the regular leaderboard cache; the race still seems to be on; use the live leaderboard updater instead: timePoint = null; - result = this.getLiveLeaderboard(namesOfRaceColumnsForWhichToLoadLegDetails, trackedRegattaRegistry, baseDomainFactory); + result = this.getLiveLeaderboard(namesOfRaceColumnsForWhichToLoadLegDetails, addOverallDetails, trackedRegattaRegistry, baseDomainFactory); } } if (timePoint != null) { @@ -1702,7 +1705,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race // which is OK because the cache is invalidated whenever any of the tracked races attached to the // leaderboard changes. result = getLeaderboardDTOCache().getLeaderboardByName(timePoint, namesOfRaceColumnsForWhichToLoadLegDetails, - baseDomainFactory, trackedRegattaRegistry); + addOverallDetails, baseDomainFactory, trackedRegattaRegistry); } return result; } diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/GwtTestCaseColumnToggling.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/GwtTestCaseColumnToggling.java index 697c347bc3e..1009a7a4ff2 100644 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/GwtTestCaseColumnToggling.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/GwtTestCaseColumnToggling.java @@ -178,7 +178,7 @@ public class GwtTestCaseColumnToggling extends GWTTestCase { private void getLeaderboardByNameAndDeleteColumn(){ ArrayList al = new ArrayList(); al.add(COLUMN1_NAME); - service.getLeaderboardByName(LEADERBOARD_NAME, new Date(), al, /* previousLeaderboardId */ null, new AsyncCallback() { + service.getLeaderboardByName(LEADERBOARD_NAME, new Date(), al, /* addOverallDetails */ false, /* previousLeaderboardId */ null, new AsyncCallback() { @Override public void onFailure(Throwable caught) { fail("Failed to get leaderboard."); diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/TestColumnSwapping.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/TestColumnSwapping.java index 0294a67fd0b..e82d972522b 100755 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/TestColumnSwapping.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/TestColumnSwapping.java @@ -98,7 +98,7 @@ public class TestColumnSwapping { sailingService.moveLeaderboardColumnUp(TEST_LEADERBOARD_NAME, races[2]); sailingService.updateIsMedalRace(TEST_LEADERBOARD_NAME, races[0], true); sailingService.updateIsMedalRace(TEST_LEADERBOARD_NAME, races[2], false); - lb = sailingService.getLeaderboardByName(TEST_LEADERBOARD_NAME, new Date(), /* races to load */ null, /* previous leaderboard ID */ null).getLeaderboardDTO(/* previousVersion */ null); + lb = sailingService.getLeaderboardByName(TEST_LEADERBOARD_NAME, new Date(), /* races to load */ null, /* addOverallDetails */ true, /* previous leaderboard ID */ null).getLeaderboardDTO(/* previousVersion */ null); } catch (Exception e) { // e.printStackTrace(); fail(e.getLocalizedMessage()); @@ -139,7 +139,7 @@ public class TestColumnSwapping { public void testColumnSwappingFabian() { service.moveLeaderboardColumnUp(LEADERBOARDNAME, "Race3"); try { - leaderboardDTO = service.getLeaderboardByName(LEADERBOARDNAME, leaderboardCreationDate, leglist, /* previous leaderboard ID */ null).getLeaderboardDTO(/* previousVersion */ null); + leaderboardDTO = service.getLeaderboardByName(LEADERBOARDNAME, leaderboardCreationDate, leglist, /* addOverallDetails */ true, /* previous leaderboard ID */ null).getLeaderboardDTO(/* previousVersion */ null); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetLeaderboardByNameAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetLeaderboardByNameAction.java index a7e989f3fd3..4d6b53f6121 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetLeaderboardByNameAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/actions/GetLeaderboardByNameAction.java @@ -17,7 +17,7 @@ import com.sap.sse.gwt.client.player.Timer; * the logic how differential, incremental leaderboard fetching and transmission works. This helps guarantee the * requirement of {@link IncrementalOrFullLeaderboardDTO#getLeaderboardDTO(LeaderboardDTO)} (only pass null * as the previous leaderboard if null was passed as identifier of the previous leaderboard to - * {@link SailingServiceAsync#getLeaderboardByName(String, Date, Collection, String, AsyncCallback)} too. + * {@link SailingServiceAsync#getLeaderboardByName(String, Date, Collection, boolean, String, AsyncCallback)} too. *

* * When a valid {@link IncrementalOrFullLeaderboardDTO} object is received, the @@ -32,20 +32,22 @@ public class GetLeaderboardByNameAction implements AsyncAction { private final String leaderboardName; private final Date date; private final Collection namesOfRacesForWhichToLoadLegDetails; + private final boolean addOverallDetails; private final LeaderboardDTO previousLeaderboard; private final StringMessages stringMessages; private final ErrorReporter errorReporter; private final Timer timerToAdjustOffetIn; public GetLeaderboardByNameAction(SailingServiceAsync sailingService, String leaderboardName, Date date, - final Collection namesOfRacesForWhichToLoadLegDetails, LeaderboardDTO previousLeaderboard, - Timer timerToAdjustOffsetIn, ErrorReporter errorReporter, StringMessages stringMessages) { + final Collection namesOfRacesForWhichToLoadLegDetails, boolean addOverallDetails, + LeaderboardDTO previousLeaderboard, Timer timerToAdjustOffsetIn, ErrorReporter errorReporter, StringMessages stringMessages) { this.sailingService = sailingService; this.errorReporter = errorReporter; this.stringMessages = stringMessages; this.leaderboardName = leaderboardName; this.date = date; this.namesOfRacesForWhichToLoadLegDetails = namesOfRacesForWhichToLoadLegDetails; + this.addOverallDetails = addOverallDetails; this.previousLeaderboard = previousLeaderboard; this.timerToAdjustOffetIn = timerToAdjustOffsetIn; } @@ -53,9 +55,8 @@ public class GetLeaderboardByNameAction implements AsyncAction { @Override public void execute(final AsyncCallback callback) { final long clientTimeWhenRequestWasSent = System.currentTimeMillis(); - sailingService.getLeaderboardByName(leaderboardName, date, namesOfRacesForWhichToLoadLegDetails, - previousLeaderboard==null?null:previousLeaderboard.getId(), - new AsyncCallback() { + sailingService.getLeaderboardByName(leaderboardName, date, namesOfRacesForWhichToLoadLegDetails, addOverallDetails, + previousLeaderboard==null?null:previousLeaderboard.getId(), new AsyncCallback() { @Override public void onFailure(Throwable caught) { callback.onFailure(caught); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 189a7b876bb..689d0c6382f 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -125,7 +125,8 @@ public interface SailingService extends RemoteService { public List getLeaderboardNames(); IncrementalOrFullLeaderboardDTO getLeaderboardByName(String leaderboardName, Date date, - Collection namesOfRaceColumnsForWhichToLoadLegDetails, String previousLeaderboardId) throws Exception; + Collection namesOfRaceColumnsForWhichToLoadLegDetails, boolean addOverallDetails, + String previousLeaderboardId) throws Exception; List getLeaderboards(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index c4ae433c7c7..a5529fba2cc 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -172,7 +172,7 @@ public interface SailingServiceAsync { void getLeaderboardByName(String leaderboardName, Date date, Collection namesOfRaceColumnsForWhichToLoadLegDetails, - String previousLeaderboardId, AsyncCallback callback); + boolean addOverallDetails, String previousLeaderboardId, AsyncCallback callback); void getLeaderboardNames(AsyncCallback> callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java index 05c489c9a40..74dbed95408 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java @@ -135,7 +135,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS /** * The leaderboard name is used to - * {@link SailingServiceAsync#getLeaderboardByName(String, java.util.Date, String[], String, com.google.gwt.user.client.rpc.AsyncCallback) + * {@link SailingServiceAsync#getLeaderboardByName(String, java.util.Date, String[], boolean, String, com.google.gwt.user.client.rpc.AsyncCallback) * obtain the leaderboard contents} from the server. It may change in case the leaderboard is renamed. */ private String leaderboardName; @@ -791,7 +791,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS getSailingService().getLeaderboardByName(getLeaderboardName(), timer.getPlayMode() == PlayModes.Live ? null : getLeaderboardDisplayDate(), /* namesOfRacesForWhichToLoadLegDetails */getNamesOfExpandedRaces(), - previousLeaderboard.getId(), new MarkedAsyncCallback( + shallAddOverallDetails(), previousLeaderboard.getId(), new MarkedAsyncCallback( new AsyncCallback() { @Override public void onSuccess(IncrementalOrFullLeaderboardDTO result) { @@ -1767,7 +1767,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS GetLeaderboardByNameAction getLeaderboardByNameAction = new GetLeaderboardByNameAction(sailingService, getLeaderboardName(), useNullAsTimePoint() ? null : date, /* namesOfRacesForWhichToLoadLegDetails */getNamesOfExpandedRaces(), - /* previousLeaderboard */ getLeaderboard(), timer, errorReporter, stringMessages); + shallAddOverallDetails(), /* previousLeaderboard */ getLeaderboard(), timer, errorReporter, stringMessages); this.asyncActionsExecutor.execute(getLeaderboardByNameAction, LOAD_LEADERBOARD_DATA_CATEGORY, new AsyncCallback() { @Override @@ -1820,6 +1820,11 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS return namesOfExpandedRaces; } + private boolean shallAddOverallDetails() { + // TODO Auto-generated method stub + return true; + } + /** * Assigns leaderboard to {@link #leaderboard} and updates the UI accordingly. Also updates the min/max * values on the columns. @@ -2519,7 +2524,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS public boolean hasBusyIndicator() { return true; } - + private Iterable getSelectedRows() { ArrayList selectedRows = new ArrayList(); for (LeaderboardRowDTO row : getData().getList()) { 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 6946d37e95c..35a054f91ed 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 @@ -556,7 +556,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S *

* * Otherwise, the leaderboard is computed synchronously on the fly. - * * @param previousLeaderboardId * if null or no leaderboard with that {@link LeaderboardDTO#getId() ID} is known, a * {@link FullLeaderboardDTO} will be computed; otherwise, an {@link IncrementalLeaderboardDTO} will be @@ -564,8 +563,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S */ @Override public IncrementalOrFullLeaderboardDTO getLeaderboardByName(final String leaderboardName, final Date date, - final Collection namesOfRaceColumnsForWhichToLoadLegDetails, String previousLeaderboardId) - throws NoWindException, InterruptedException, ExecutionException, IllegalArgumentException { + final Collection namesOfRaceColumnsForWhichToLoadLegDetails, boolean addOverallDetails, + String previousLeaderboardId) throws NoWindException, InterruptedException, ExecutionException, + IllegalArgumentException { try { long startOfRequestHandling = System.currentTimeMillis(); IncrementalOrFullLeaderboardDTO result = null; @@ -578,7 +578,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S timePoint = new MillisecondsTimePoint(date); } LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO(timePoint, - namesOfRaceColumnsForWhichToLoadLegDetails, getService(), baseDomainFactory); + namesOfRaceColumnsForWhichToLoadLegDetails, addOverallDetails, getService(), baseDomainFactory); LeaderboardDTO previousLeaderboardDTO = null; synchronized (leaderboardByNameResultsCacheById) { leaderboardByNameResultsCacheById.put(leaderboardDTO.getId(), leaderboardDTO); @@ -2486,7 +2486,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S switch (detailType) { case REGATTA_TOTAL_POINTS: LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO(timePoint, Collections. emptyList(), - getService(), baseDomainFactory); + /* addOverallDetails */ false, getService(), baseDomainFactory); for (RaceColumnDTO raceColumnDTO : leaderboardDTO.getRaceList()) { result.add(getTotalPointsForRaceColumn(leaderboardDTO, raceColumnDTO)); } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java index 8b434f9e61d..9436c1077bd 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java @@ -104,7 +104,7 @@ public class LeaderboardsResource extends AbstractSailingServerResource { private JSONObject getLeaderboardJson(Leaderboard leaderboard, Triple timePointAndResultStateAndMaxCompetitorsCount) throws NoWindException, InterruptedException, ExecutionException { LeaderboardDTO leaderboardDTO = leaderboard.getLeaderboardDTO(timePointAndResultStateAndMaxCompetitorsCount.getA(), - Collections. emptyList(), getService(), getService().getBaseDomainFactory()); + Collections. emptyList(), /* addOverallDetails */ false, getService(), getService().getBaseDomainFactory()); TimePoint resultTimePoint = timePointAndResultStateAndMaxCompetitorsCount.getA(); ResultStates resultState = timePointAndResultStateAndMaxCompetitorsCount.getB();