From b9d8b4827a119bb8b4b4d064c95be7f594c72640 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 21 Nov 2017 11:10:40 +0100 Subject: [PATCH 1/4] bug 3742: don't assign a competitor points in a MetaLeaderboard if it has no score in the underlying column leaderboard Change-Id: I1e16044e0fd3196a187edd48a23e424deaa1d428 --- .../sap/sailing/domain/leaderboard/Leaderboard.java | 8 +++++++- .../impl/AbstractLeaderboardWithCache.java | 9 +++++++++ .../impl/AbstractSimpleLeaderboardImpl.java | 4 ++-- ...RegattaLeaderboardWithCompetitorElimination.java | 2 +- .../leaderboard/meta/AbstractMetaLeaderboard.java | 13 ++++++++++--- 5 files changed, 29 insertions(+), 7 deletions(-) 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 b039debafb7..cb83409832d 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 @@ -269,7 +269,7 @@ public interface Leaderboard extends LeaderboardBase, HasRaceColumns { * competitor doesn't appear in any of the race column's attached tracked races. A 0.0 score is returned * if the competitor's result for race is discarded. */ - Double getNetPoints(Competitor competitor, RaceColumn race, TimePoint timePoint) throws NoWindException; + Double getNetPoints(Competitor competitor, RaceColumn race, TimePoint timePoint); /** * Tells whether the contribution of raceColumn is discarded in the current leaderboard's standings for @@ -568,4 +568,10 @@ public interface Leaderboard extends LeaderboardBase, HasRaceColumns { BoatClass getBoatClass(); LeaderboardType getLeaderboardType(); + + /** + * Tells if there is at least one non-{@code null} score for the given {@code competitor} in the + * leaderboard. + */ + boolean hasScores(Competitor competitor, TimePoint timePoint); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java index 490ba407f71..33e3cdb0018 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractLeaderboardWithCache.java @@ -1118,4 +1118,13 @@ public abstract class AbstractLeaderboardWithCache implements Leaderboard { } } + @Override + public boolean hasScores(Competitor competitor, TimePoint timePoint) { + for (final RaceColumn raceColumn : getRaceColumns()) { + if (getTotalPoints(competitor, raceColumn, timePoint) != null) { + return true; + } + } + return false; + } } 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 037eb50f3be..63649e7db1b 100644 --- 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 @@ -425,13 +425,13 @@ public abstract class AbstractSimpleLeaderboardImpl extends AbstractLeaderboardW } @Override - public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) throws NoWindException { + public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) { return getNetPoints(competitor, raceColumn, getRaceColumns(), timePoint); } @Override public Double getNetPoints(Competitor competitor, RaceColumn raceColumn, - Iterable raceColumnsToConsider, TimePoint timePoint) throws NoWindException { + Iterable raceColumnsToConsider, TimePoint timePoint) { final Set discardedRaceColumns = getResultDiscardingRule() .getDiscardedRaceColumns(competitor, this, raceColumnsToConsider, timePoint); return getNetPoints(competitor, raceColumn, timePoint, discardedRaceColumns); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java index da4d65a6790..f4da263926c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/DelegatingRegattaLeaderboardWithCompetitorElimination.java @@ -280,7 +280,7 @@ public class DelegatingRegattaLeaderboardWithCompetitorElimination extends Abstr return getFullLeaderboard().getMaxPointsReason(competitor, race, timePoint); } - public Double getNetPoints(Competitor competitor, RaceColumn race, TimePoint timePoint) throws NoWindException { + public Double getNetPoints(Competitor competitor, RaceColumn race, TimePoint timePoint) { return getFullLeaderboard().getNetPoints(competitor, race, timePoint); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java index 293176a8147..1609478961c 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java @@ -171,9 +171,16 @@ public abstract class AbstractMetaLeaderboard extends AbstractSimpleLeaderboardI @Override public int getTrackedRank(Competitor competitor, RaceColumn race, TimePoint timePoint) { - final List competitorsFromBestToWorst = ((MetaLeaderboardColumn) race).getLeaderboard().getCompetitorsFromBestToWorst(timePoint); - Util.removeAll(getSuppressedCompetitors(), competitorsFromBestToWorst); - return competitorsFromBestToWorst.indexOf(competitor)+1; + final Leaderboard leaderboard = ((MetaLeaderboardColumn) race).getLeaderboard(); + final int result; + if (leaderboard.hasScores(competitor, timePoint)) { + final List competitorsFromBestToWorst = leaderboard.getCompetitorsFromBestToWorst(timePoint); + Util.removeAll(getSuppressedCompetitors(), competitorsFromBestToWorst); + result = competitorsFromBestToWorst.indexOf(competitor)+1; + } else { + result = 0; + } + return result; } @Override From 1dedaae406a364345623dfd2a2ab7b0d9e7d8253 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Tue, 21 Nov 2017 18:03:22 +0100 Subject: [PATCH 2/4] Allow user to enable/disable downsampler in sensordata upload dialog --- .../AbstractFileImportWidget.java | 7 +++++ .../AbstractFileImportWidget.ui.xml | 1 + .../adminconsole/SensorDataImportWidget.java | 1 + .../adminconsole/TrackFileImportWidget.java | 1 + .../impl/SensorDataImportServlet.java | 27 +++++++++++-------- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.java index d462a8ddd9a..12cd4d44eb3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.java @@ -12,6 +12,7 @@ import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FileUpload; import com.google.gwt.user.client.ui.FormPanel; @@ -35,6 +36,8 @@ public abstract class AbstractFileImportWidget extends Composite { @UiField FileUpload fileUploadUi; @UiField ListBox preferredImporterUi; @UiField Button importButtonUi; + @UiField + CheckBox downsampleUi; @UiField Image loadingImageUi; @UiField FormPanel formPanelUi; private final TrackFileImportDeviceIdentifierTableWrapper table; @@ -72,6 +75,10 @@ public abstract class AbstractFileImportWidget extends Composite { formPanelUi.submit(); } + protected void setDownsampleOptionVisible(boolean visible) { + downsampleUi.setVisible(visible); + } + @UiHandler("formPanelUi") void onFileImportComplete(SubmitCompleteEvent event) { if (shouldClearListOnNewUploadComplete) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.ui.xml index d8a0830654f..4893b5161d0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractFileImportWidget.ui.xml @@ -22,6 +22,7 @@ + Downsample diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SensorDataImportWidget.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SensorDataImportWidget.java index 20ec0834486..5cb8f4aee30 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SensorDataImportWidget.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SensorDataImportWidget.java @@ -15,6 +15,7 @@ public class SensorDataImportWidget extends AbstractFileImportWidget implements super("/sailingserver/sensordata/import", stringMessages, table, sailingService, errorReporter); setMultipleFileUploadEnabled(true); setShouldClearListOnNewUploadComplete(false); + setDownsampleOptionVisible(true); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackFileImportWidget.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackFileImportWidget.java index 385413b1ecd..ac869b5c4c6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackFileImportWidget.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackFileImportWidget.java @@ -14,6 +14,7 @@ public class TrackFileImportWidget extends AbstractFileImportWidget implements I public TrackFileImportWidget(TrackFileImportDeviceIdentifierTableWrapper table, StringMessages stringMessages, final SailingServiceAsync sailingService, final ErrorReporter errorReporter) { super("/sailingserver/trackfiles/import", stringMessages, table, sailingService, errorReporter); + setDownsampleOptionVisible(false); } @Override diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/SensorDataImportServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/SensorDataImportServlet.java index e23a004ea38..d5fde01a52d 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/SensorDataImportServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/SensorDataImportServlet.java @@ -52,14 +52,14 @@ public class SensorDataImportServlet extends AbstractFileUploadServlet { * * @param files * the file items together with the names of the importer to use for importing the respective file's - * contents; the importer names are matched against {@link DoubleVectorFixImporter#getType()} for - * all importers found registered in the OSGi registry. The first matching importer is used for the - * file. The importer is selected on a per-file basis. + * contents; the importer names are matched against {@link DoubleVectorFixImporter#getType()} for all + * importers found registered in the OSGi registry. The first matching importer is used for the file. The + * importer is selected on a per-file basis. * * @throws IOException */ - private Iterable importFiles(Iterable> files) - throws IOException { + private Iterable importFiles(boolean enableDownsampler, + Iterable> files) throws IOException { final Set deviceIds = new HashSet<>(); final Map from = new HashMap<>(); final Map to = new HashMap<>(); @@ -102,7 +102,7 @@ public class SensorDataImportServlet extends AbstractFileUploadServlet { } } } - }, fi.getName(), requestedImporterName, /* downsample */ true); + }, fi.getName(), requestedImporterName, enableDownsampler); logger.log(Level.INFO, "Successfully imported file " + requestedImporterName); } catch (FormatNotSupportedException e) { logger.log(Level.INFO, "Failed to import file " + requestedImporterName); @@ -119,10 +119,14 @@ public class SensorDataImportServlet extends AbstractFileUploadServlet { protected void process(List fileItems, HttpServletRequest req, HttpServletResponse resp) throws IOException { String importerName = null; - searchForPreferredImporter: for (FileItem fi : fileItems) { - if ("preferredImporter".equalsIgnoreCase(fi.getFieldName())) { - importerName = fi.getString(); - break searchForPreferredImporter; + boolean enableDownsampler = false; + for (FileItem fi : fileItems) { + if (fi.isFormField()) { + if ("preferredImporter".equalsIgnoreCase(fi.getFieldName())) { + importerName = fi.getString(); + } else if ("downsample".equalsIgnoreCase(fi.getFieldName())) { + enableDownsampler = "on".equalsIgnoreCase(fi.getString()); + } } } if (importerName == null) { @@ -134,7 +138,8 @@ public class SensorDataImportServlet extends AbstractFileUploadServlet { filesAndImporterNames.add(new Pair<>(importerName, fi)); } } - final Iterable mappingList = importFiles(filesAndImporterNames); + final Iterable mappingList = importFiles(enableDownsampler, + filesAndImporterNames); resp.setContentType("text/html"); for (TrackFileImportDeviceIdentifier mapping : mappingList) { String stringRep = mapping.getId().toString(); From 5f55a2ebefd82c87c73cd4fb31ce4fe213ddcd52 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 22 Nov 2017 09:43:54 +0100 Subject: [PATCH 3/4] fixed bug in chart data resolution calculation Change-Id: Idd840b537efa222e809b546535ecdf366e516b96 --- .../java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 51b58553984..d29a62d478c 100644 --- 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 @@ -473,7 +473,6 @@ import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; import com.sap.sse.common.Util.Triple; import com.sap.sse.common.WithID; -import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.TimeRangeImpl; import com.sap.sse.common.mail.MailException; @@ -3097,7 +3096,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S TimePoint newestEvent = trackedRace.getTimePointOfNewestEvent(); final TimePoint startTime = from == null ? trackedRace.getStartOfTracking() : new MillisecondsTimePoint(from); final TimePoint endTime = (to == null || to.after(newestEvent.asDate())) ? newestEvent : new MillisecondsTimePoint(to); - final long adjustedStepSizeInMillis = (long) Math.max((double) stepSizeInMillis, startTime.until(endTime).divide(new MillisecondsDurationImpl(stepSizeInMillis))); + final long adjustedStepSizeInMillis = (long) Math.max((double) stepSizeInMillis, startTime.until(endTime).divide(SailingServiceConstants.MAX_NUMBER_OF_FIXES_TO_QUERY).asMillis()); result = new CompetitorsRaceDataDTO(detailType, startTime==null?null:startTime.asDate(), endTime==null?null:endTime.asDate()); final int MAX_CACHE_SIZE = SailingServiceConstants.MAX_NUMBER_OF_FIXES_TO_QUERY; final ConcurrentHashMap cachesByTimePoint = new ConcurrentHashMap<>(); From 6e38297e9563ea694abd4bf07df580cae4cb7579 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 22 Nov 2017 09:49:53 +0100 Subject: [PATCH 4/4] updated release notes for bug 3742 Change-Id: Ia0ff31e91b0f70a18776e56cbadb474f857199b4 --- .../places/whatsnew/resources/SailingAnalyticsNotes.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html index 131d8e75975..a931629d8fb 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html @@ -18,6 +18,12 @@ figures which are so important for any foiling boat class. Note, that this feature is also available on overall leaderboards, providing foiling stats across an entire season or event series. +
  • When a leaderboard belongs to a leaderboard group with an overall (series) leaderboard and the + leaderboard has no scores at all yet for a competitor, that competitor won't be assigned a score + in the overall (series) leaderboard either. This way, when an act or event has its leaderboard already + linked to the series leaderboard group, no scores will show in the series leaderboard before the + act/event starts producing scores for the competitors. +
  • October 2017